# Documentation - Class name: InstantIDAttentionPatch - Category: InstantID - Output node: False - Repo Ref: https://github.com/cubiq/ComfyUI_InstantID.git InstantIDAttentionPatch是一个旨在增强神经网络模型中注意力机制的类,特别为图像处理任务定制。它与InstantID模型集成,以提高模型对图像中相关特征的聚焦能力,从而提高输出嵌入的质量。该节点抽象了注意力补丁的复杂性,并强调了模型特征检测和表示能力的总体增强。 # Input types ## Required - instantid - instantid参数至关重要,因为它提供了注意力补丁操作所需的基础模型架构。它是应用注意力机制和特征增强的基础,直接影响节点在提炼模型输出方面的有效性。 - Comfy dtype: INSTANTID - Python dtype: dict - insightface - insightface参数对节点至关重要,因为它提供了面部分析组件,这对于图像数据处理至关重要。它使节点能够准确检测和分析面部特征,这是图像处理任务的关键方面。 - Comfy dtype: FACEANALYSIS - Python dtype: object - image - image参数对节点的运作至关重要,因为它引入了将被处理的原始图像数据。图像的质量和分辨率直接影响节点提取和利用相关特征的能力,从而影响图像处理任务的整体性能。 - Comfy dtype: IMAGE - Python dtype: PIL.Image - model - model参数是节点将通过应用注意力补丁来增强的神经网络模型。它是一个关键组件,因为它决定了节点构建其特征增强和注意力机制的基础。 - Comfy dtype: MODEL - Python dtype: torch.nn.Module - weight - weight参数是一个浮点值,用于调整注意力补丁对模型输出的影响。它很重要,因为它允许对模型对特定特征的关注进行微调,直接影响提取特征的质量和相关性。 - Comfy dtype: FLOAT - Python dtype: float - start_at - start_at参数定义了注意力补丁开始施加影响的初始点。它很重要,因为它设置了特征增强过程的起始条件,影响模型最初如何聚焦输入图像。 - Comfy dtype: FLOAT - Python dtype: float - end_at - end_at参数指定了注意力补丁结束其影响的最终点。它很重要,因为它决定了特征增强的结束条件,影响模型对输入图像的持续关注。 - Comfy dtype: FLOAT - Python dtype: float ## Optional - noise - noise参数在注意力补丁的操作中引入了一定程度的随机性,这有助于多样化模型的特征提取。它通过在特征表示中引入变异性,增强了模型的鲁棒性和创造力。 - Comfy dtype: FLOAT - Python dtype: float - mask - 当提供mask参数时,它允许有选择地将注意力补丁应用于图像的特定区域。它通过确定在特征增强过程中哪些图像区域被优先考虑或忽略,影响节点的操作。 - Comfy dtype: MASK - Python dtype: torch.Tensor # Output types - model - 输出模型是应用注意力补丁后增强的神经网络。它代表了节点努力提炼和集中模型特征提取能力的成果,提供了对输入图像更准确和细致的表示。 - Comfy dtype: MODEL - Python dtype: torch.nn.Module - FACE_EMBEDS - FACE_EMBEDS输出由输入图像中提取的面部嵌入组成,这些嵌入已通过注意力补丁得到增强。这些嵌入捕捉了面部数据的基本特征,提供了丰富而详细的表示,可用于进一步的分析或比较。 - Comfy dtype: FACE_EMBEDS - Python dtype: Dict[str, torch.Tensor] # Usage tips - Infra type: GPU # Source code ``` class InstantIDAttentionPatch: @classmethod def INPUT_TYPES(s): return {'required': {'instantid': ('INSTANTID',), 'insightface': ('FACEANALYSIS',), 'image': ('IMAGE',), 'model': ('MODEL',), 'weight': ('FLOAT', {'default': 1.0, 'min': -1.0, 'max': 3.0, 'step': 0.01}), 'start_at': ('FLOAT', {'default': 0.0, 'min': 0.0, 'max': 1.0, 'step': 0.001}), 'end_at': ('FLOAT', {'default': 1.0, 'min': 0.0, 'max': 1.0, 'step': 0.001}), 'noise': ('FLOAT', {'default': 0.0, 'min': 0.0, 'max': 1.0, 'step': 0.1})}, 'optional': {'mask': ('MASK',)}} RETURN_TYPES = ('MODEL', 'FACE_EMBEDS') FUNCTION = 'patch_attention' CATEGORY = 'InstantID' def patch_attention(self, instantid, insightface, image, model, weight, start_at, end_at, noise=0.0, mask=None): self.dtype = torch.float16 if comfy.model_management.should_use_fp16() else torch.float32 self.device = comfy.model_management.get_torch_device() output_cross_attention_dim = instantid['ip_adapter']['1.to_k_ip.weight'].shape[1] is_sdxl = output_cross_attention_dim == 2048 cross_attention_dim = 1280 clip_extra_context_tokens = 16 face_embed = extractFeatures(insightface, image) if face_embed is None: raise Exception('Reference Image: No face detected.') clip_embed = face_embed if clip_embed.shape[0] > 1: clip_embed = torch.mean(clip_embed, dim=0).unsqueeze(0) if noise > 0: seed = int(torch.sum(clip_embed).item()) % 1000000007 torch.manual_seed(seed) clip_embed_zeroed = noise * torch.rand_like(clip_embed) else: clip_embed_zeroed = torch.zeros_like(clip_embed) clip_embeddings_dim = face_embed.shape[-1] self.instantid = InstantID(instantid, cross_attention_dim=cross_attention_dim, output_cross_attention_dim=output_cross_attention_dim, clip_embeddings_dim=clip_embeddings_dim, clip_extra_context_tokens=clip_extra_context_tokens) self.instantid.to(self.device, dtype=self.dtype) (image_prompt_embeds, uncond_image_prompt_embeds) = self.instantid.get_image_embeds(clip_embed.to(self.device, dtype=self.dtype), clip_embed_zeroed.to(self.device, dtype=self.dtype)) image_prompt_embeds = image_prompt_embeds.to(self.device, dtype=self.dtype) uncond_image_prompt_embeds = uncond_image_prompt_embeds.to(self.device, dtype=self.dtype) if weight == 0: return (model, {'cond': image_prompt_embeds, 'uncond': uncond_image_prompt_embeds}) work_model = model.clone() sigma_start = work_model.model.model_sampling.percent_to_sigma(start_at) sigma_end = work_model.model.model_sampling.percent_to_sigma(end_at) if mask is not None: mask = mask.to(self.device) patch_kwargs = {'number': 0, 'weight': weight, 'ipadapter': self.instantid, 'cond': image_prompt_embeds, 'uncond': uncond_image_prompt_embeds, 'mask': mask, 'sigma_start': sigma_start, 'sigma_end': sigma_end, 'weight_type': 'original'} if not is_sdxl: for id in [1, 2, 4, 5, 7, 8]: _set_model_patch_replace(work_model, patch_kwargs, ('input', id)) patch_kwargs['number'] += 1 for id in [3, 4, 5, 6, 7, 8, 9, 10, 11]: _set_model_patch_replace(work_model, patch_kwargs, ('output', id)) patch_kwargs['number'] += 1 _set_model_patch_replace(work_model, patch_kwargs, ('middle', 0)) else: for id in [4, 5, 7, 8]: block_indices = range(2) if id in [4, 5] else range(10) for index in block_indices: _set_model_patch_replace(work_model, patch_kwargs, ('input', id, index)) patch_kwargs['number'] += 1 for id in range(6): block_indices = range(2) if id in [3, 4, 5] else range(10) for index in block_indices: _set_model_patch_replace(work_model, patch_kwargs, ('output', id, index)) patch_kwargs['number'] += 1 for index in range(10): _set_model_patch_replace(work_model, patch_kwargs, ('middle', 0, index)) patch_kwargs['number'] += 1 return (work_model, {'cond': image_prompt_embeds, 'uncond': uncond_image_prompt_embeds}) ```