8.0 KiB
8.0 KiB
Documentation
- Class name: StyleAlignedReferenceSampler
- Category: style_aligned
- Output node: False
- Repo Ref: https://github.com/brianfitzgerald/style_aligned_comfy
StyleAlignedReferenceSampler类旨在促进风格对齐的潜在空间采样,确保生成的内容遵循特定的风格参考。它整合了注意力机制和规范化技术来精炼输出,为生成模型中的风格对齐提供了细致的方法。
Input types
Required
- model
- 模型参数至关重要,因为它定义了用于风格对齐采样的生成模型的基础架构和参数。它是风格对齐和采样过程构建的基础。
- Comfy dtype: MODEL
- Python dtype: ModelPatcher
- share_norm
- share_norm参数决定模型中不同层或组之间的规范化层如何共享,这通过控制信息流对风格对齐过程产生重大影响。
- Comfy dtype: SHARE_NORM_OPTIONS
- Python dtype: str
- share_attn
- share_attn参数决定了模型中注意力机制的共享策略,这对于通过影响注意力权重使生成内容与期望风格对齐至关重要。
- Comfy dtype: SHARE_ATTN_OPTIONS
- Python dtype: str
- scale
- scale参数调整风格参考对生成样本的影响,允许微调风格对齐以实现期望的审美结果。
- Comfy dtype: FLOAT
- Python dtype: float
- batch_size
- batch_size决定了同时处理的样本数量,这影响了风格对齐采样过程的效率和速度。
- Comfy dtype: INT
- Python dtype: int
- noise_seed
- noise_seed用于生成采样过程中的噪声向量,确保风格对齐的样本可以一致地复现。
- Comfy dtype: INT
- Python dtype: int
- cfg
- cfg参数影响采样过程的配置,特别是模型如何响应条件输入,这对于实现准确风格对齐至关重要。
- Comfy dtype: FLOAT
- Python dtype: float
- positive
- 正面条件输入对于引导模型朝向期望的风格特征至关重要,作为风格对齐过程的参考。
- Comfy dtype: CONDITIONING
- Python dtype: T
- negative
- 负面条件输入通过指定要避免的不期望特征来帮助完善模型的输出,提高了风格对齐的精确度。
- Comfy dtype: CONDITIONING
- Python dtype: T
- ref_positive
- ref_positive条件输入提供了额外的风格参考层,进一步确保生成的样本与目标风格紧密匹配。
- Comfy dtype: CONDITIONING
- Python dtype: T
- sampler
- sampler参数定义了采样策略,这对于风格对齐输出的多样性和质量至关重要。
- Comfy dtype: SAMPLER
- Python dtype: T
- sigmas
- sigmas参数用于控制在采样过程中应用的噪声水平,直接影响风格对齐样本的平滑度和连贯性。
- Comfy dtype: SIGMAS
- Python dtype: T
- ref_latents
- ref_latents提供了一组作为风格对齐参考的潜在表示,确保输出样本遵循期望的风格细节。
- Comfy dtype: STEP_LATENTS
- Python dtype: T
Output types
- output
- 输出参数包含模型生成的风格对齐潜在样本,这是采样过程的主要结果,可以进一步处理或分析。
- Comfy dtype: LATENT
- Python dtype: dict
- denoised_output
- denoised_output参数提供了经过处理以减少噪声和增强清晰度的精炼潜在样本,提供了目标风格的更清晰表示。
- Comfy dtype: LATENT
- Python dtype: dict
Usage tips
- Infra type: GPU
Source code
class StyleAlignedReferenceSampler:
@classmethod
def INPUT_TYPES(cls):
return {'required': {'model': ('MODEL',), 'share_norm': (SHARE_NORM_OPTIONS,), 'share_attn': (SHARE_ATTN_OPTIONS,), 'scale': ('FLOAT', {'default': 1, 'min': 0, 'max': 2.0, 'step': 0.01}), 'batch_size': ('INT', {'default': 2, 'min': 1, 'max': 8, 'step': 1}), 'noise_seed': ('INT', {'default': 0, 'min': 0, 'max': 18446744073709551615}), 'cfg': ('FLOAT', {'default': 8.0, 'min': 0.0, 'max': 100.0, 'step': 0.1, 'round': 0.01}), 'positive': ('CONDITIONING',), 'negative': ('CONDITIONING',), 'ref_positive': ('CONDITIONING',), 'sampler': ('SAMPLER',), 'sigmas': ('SIGMAS',), 'ref_latents': ('STEP_LATENTS',)}}
RETURN_TYPES = ('LATENT', 'LATENT')
RETURN_NAMES = ('output', 'denoised_output')
FUNCTION = 'patch'
CATEGORY = 'style_aligned'
def patch(self, model: ModelPatcher, share_norm: str, share_attn: str, scale: float, batch_size: int, noise_seed: int, cfg: float, positive: T, negative: T, ref_positive: T, sampler: T, sigmas: T, ref_latents: T) -> 'tuple[dict, dict]':
m = model.clone()
args = StyleAlignedArgs(share_attn)
style_latent_tensor = ref_latents[0].unsqueeze(0)
(height, width) = style_latent_tensor.shape[-2:]
latent_t = torch.zeros([batch_size, 4, height, width], device=ref_latents.device)
latent = {'samples': latent_t}
noise = comfy.sample.prepare_noise(latent_t, noise_seed)
latent_t = torch.cat((style_latent_tensor, latent_t), dim=0)
ref_noise = torch.zeros_like(noise[0]).unsqueeze(0)
noise = torch.cat((ref_noise, noise), dim=0)
x0_output = {}
preview_callback = latent_preview.prepare_callback(m, sigmas.shape[-1] - 1, x0_output)
def callback(step: int, x0: T, x: T, steps: int):
preview_callback(step, x0, x, steps)
if step + 1 < steps:
x[0] = ref_latents[step + 1]
x0[0] = ref_latents[step + 1]
share_group_norm = share_norm in ['group', 'both']
share_layer_norm = share_norm in ['layer', 'both']
register_shared_norm(m, share_group_norm, share_layer_norm)
m.set_model_attn1_patch(SharedAttentionProcessor(args, scale))
batched_condition = []
for (i, condition) in enumerate(positive):
additional = condition[1].copy()
batch_with_reference = torch.cat([ref_positive[i][0], condition[0].repeat([batch_size] + [1] * len(condition[0].shape[1:]))], dim=0)
if 'pooled_output' in additional and 'pooled_output' in ref_positive[i][1]:
pooled_output = torch.cat([ref_positive[i][1]['pooled_output'], additional['pooled_output'].repeat([batch_size] + [1] * len(additional['pooled_output'].shape[1:]))], dim=0)
additional['pooled_output'] = pooled_output
if 'control' in additional:
if 'control' in ref_positive[i][1]:
control_hint = torch.cat([ref_positive[i][1]['control'].cond_hint_original, additional['control'].cond_hint_original.repeat([batch_size] + [1] * len(additional['control'].cond_hint_original.shape[1:]))], dim=0)
cloned_controlnet = additional['control'].copy()
cloned_controlnet.set_cond_hint(control_hint, strength=additional['control'].strength, timestep_percent_range=additional['control'].timestep_percent_range)
additional['control'] = cloned_controlnet
else:
control_hint = torch.cat([torch.zeros_like(additional['control'].cond_hint_original), additional['control'].cond_hint_original.repeat([batch_size] + [1] * len(additional['control'].cond_hint_original.shape[1:]))], dim=0)
cloned_controlnet = additional['control'].copy()
cloned_controlnet.set_cond_hint(control_hint, strength=additional['control'].strength, timestep_percent_range=additional['control'].timestep_percent_range)
additional['control'] = cloned_controlnet
batched_condition.append([batch_with_reference, additional])
disable_pbar = not comfy.utils.PROGRESS_BAR_ENABLED
samples = comfy.sample.sample_custom(m, noise, cfg, sampler, sigmas, batched_condition, negative, latent_t, callback=callback, disable_pbar=disable_pbar, seed=noise_seed)
samples = samples[1:]
out = latent.copy()
out['samples'] = samples
if 'x0' in x0_output:
out_denoised = latent.copy()
x0 = x0_output['x0'][1:]
out_denoised['samples'] = m.model.process_latent_out(x0.cpu())
else:
out_denoised = out
return (out, out_denoised)