Files
CavinHuang-comfyui-nodes-docs/docs/easy fullkSampler.md
2024-05-26 20:35:16 +08:00

199 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Documentation
- Class name: samplerFull
- Category: EasyUse/Sampler
- Output node: True
- Repo Ref: https://github.com/yolain/ComfyUI-Easy-Use.git
节点类'samplerFull'旨在提供一个全面的采样框架,用于生成高质量的图像。它利用先进的采样技术的力量,创造视觉连贯和多样化的输出。该节点的主要功能是促进生成与输入条件和约束相一致的图像,确保丰富的结果多样性。通过抽象采样过程,此节点强调生成既美观又技术准确的图像,为系统的创造性和研究导向目标做出重要贡献。
# Input types
## Required
- pipe
- ‘pipe’参数是‘samplerFull’节点的主要输入,为采样过程提供必要的数据和设置。它包括模型信息、条件数据和配置参数,指导最终图像的生成。此参数至关重要,因为它直接影响输出图像的质量和特性。
- Comfy dtype: PIPE_LINE
- Python dtype: Dict
- steps
- ‘s steps’参数定义了采样过程将经历的迭代次数。它是决定生成图像的精炼级别的关键因素。通常,步数越多,生成的图像就越详细、越精炼,因为模型有更多机会调整和提高图像质量。
- Comfy dtype: INT
- Python dtype: int
- cfg
- ‘cfg’参数调整采样过程的配置设置,影响诸如噪声水平和模型行为等多种方面。它在调整输出以满足特定要求或期望结果方面发挥着重要作用,允许对图像生成采取定制化的方法。
- Comfy dtype: FLOAT
- Python dtype: float
# Output types
- pipe
- ‘samplerFull’节点的‘pipe’输出包含了在采样过程中更新和精炼的全面数据和设置。它包括最终图像、模型信息以及进一步处理或分析所必需的任何其他相关细节。
- Comfy dtype: PIPE_LINE
- Python dtype: Dict
- image
- ‘image’输出代表了采样过程生成的最终图像。这些图像是输入参数和设置的直接体现,展示了‘samplerFull’节点在创建视觉上吸引人和情境相关的输出方面的能力。
- Comfy dtype: IMAGE
- Python dtype: List[torch.Tensor]
# Usage tips
- Infra type: GPU
# Source code
```
class samplerFull(LayerDiffuse):
def __init__(self):
super().__init__()
@classmethod
def INPUT_TYPES(cls):
return {'required': {'pipe': ('PIPE_LINE',), 'steps': ('INT', {'default': 20, 'min': 1, 'max': 10000}), 'cfg': ('FLOAT', {'default': 8.0, 'min': 0.0, 'max': 100.0}), 'sampler_name': (comfy.samplers.KSampler.SAMPLERS,), 'scheduler': (comfy.samplers.KSampler.SCHEDULERS,), 'denoise': ('FLOAT', {'default': 1.0, 'min': 0.0, 'max': 1.0, 'step': 0.01}), 'image_output': (['Hide', 'Preview', 'Save', 'Hide/Save', 'Sender', 'Sender/Save'],), 'link_id': ('INT', {'default': 0, 'min': 0, 'max': sys.maxsize, 'step': 1}), 'save_prefix': ('STRING', {'default': 'ComfyUI'})}, 'optional': {'seed': ('INT', {'default': 0, 'min': 0, 'max': MAX_SEED_NUM}), 'model': ('MODEL',), 'positive': ('CONDITIONING',), 'negative': ('CONDITIONING',), 'latent': ('LATENT',), 'vae': ('VAE',), 'clip': ('CLIP',), 'xyPlot': ('XYPLOT',), 'image': ('IMAGE',)}, 'hidden': {'tile_size': 'INT', 'prompt': 'PROMPT', 'extra_pnginfo': 'EXTRA_PNGINFO', 'my_unique_id': 'UNIQUE_ID', 'embeddingsList': (folder_paths.get_filename_list('embeddings'),)}}
RETURN_TYPES = ('PIPE_LINE', 'IMAGE', 'MODEL', 'CONDITIONING', 'CONDITIONING', 'LATENT', 'VAE', 'CLIP', 'INT')
RETURN_NAMES = ('pipe', 'image', 'model', 'positive', 'negative', 'latent', 'vae', 'clip', 'seed')
OUTPUT_NODE = True
FUNCTION = 'run'
CATEGORY = 'EasyUse/Sampler'
def run(self, pipe, steps, cfg, sampler_name, scheduler, denoise, image_output, link_id, save_prefix, seed=None, model=None, positive=None, negative=None, latent=None, vae=None, clip=None, xyPlot=None, tile_size=None, prompt=None, extra_pnginfo=None, my_unique_id=None, force_full_denoise=False, disable_noise=False, downscale_options=None):
easyCache.update_loaded_objects(prompt)
samp_model = model if model is not None else pipe['model']
samp_positive = positive if positive is not None else pipe['positive']
samp_negative = negative if negative is not None else pipe['negative']
samp_samples = latent if latent is not None else pipe['samples']
samp_vae = vae if vae is not None else pipe['vae']
samp_clip = clip if clip is not None else pipe['clip']
samp_seed = seed if seed is not None else pipe['seed']
steps = steps if steps is not None else pipe['loader_settings']['steps']
start_step = pipe['loader_settings']['start_step'] if 'start_step' in pipe['loader_settings'] else 0
last_step = pipe['loader_settings']['last_step'] if 'last_step' in pipe['loader_settings'] else 10000
cfg = cfg if cfg is not None else pipe['loader_settings']['cfg']
sampler_name = sampler_name if sampler_name is not None else pipe['loader_settings']['sampler_name']
scheduler = scheduler if scheduler is not None else pipe['loader_settings']['scheduler']
denoise = denoise if denoise is not None else pipe['loader_settings']['denoise']
add_noise = pipe['loader_settings']['add_noise'] if 'add_noise' in pipe['loader_settings'] else 'enabled'
force_full_denoise = pipe['loader_settings']['force_full_denoise'] if 'force_full_denoise' in pipe['loader_settings'] else True
disable_noise = False
if add_noise == 'disable':
disable_noise = True
def downscale_model_unet(samp_model):
if downscale_options is None:
return samp_model
elif 'PatchModelAddDownscale' in ALL_NODE_CLASS_MAPPINGS:
cls = ALL_NODE_CLASS_MAPPINGS['PatchModelAddDownscale']
if downscale_options['downscale_factor'] is None:
unet_config = samp_model.model.model_config.unet_config
if unet_config is not None and 'samples' in samp_samples:
height = samp_samples['samples'].shape[2] * 8
width = samp_samples['samples'].shape[3] * 8
context_dim = unet_config.get('context_dim')
longer_side = width if width > height else height
if context_dim is not None and longer_side > context_dim:
width_downscale_factor = float(width / context_dim)
height_downscale_factor = float(height / context_dim)
if width_downscale_factor > 1.75:
log_node_warn('正在收缩模型Unet...')
log_node_warn('收缩系数:' + str(width_downscale_factor))
(samp_model,) = cls().patch(samp_model, downscale_options['block_number'], width_downscale_factor, 0, 0.35, True, 'bicubic', 'bicubic')
elif height_downscale_factor > 1.25:
log_node_warn('正在收缩模型Unet...')
log_node_warn('收缩系数:' + str(height_downscale_factor))
(samp_model,) = cls().patch(samp_model, downscale_options['block_number'], height_downscale_factor, 0, 0.35, True, 'bicubic', 'bicubic')
else:
cls = ALL_NODE_CLASS_MAPPINGS['PatchModelAddDownscale']
log_node_warn('正在收缩模型Unet...')
log_node_warn('收缩系数:' + str(downscale_options['downscale_factor']))
(samp_model,) = cls().patch(samp_model, downscale_options['block_number'], downscale_options['downscale_factor'], downscale_options['start_percent'], downscale_options['end_percent'], downscale_options['downscale_after_skip'], downscale_options['downscale_method'], downscale_options['upscale_method'])
return samp_model
def process_sample_state(pipe, samp_model, samp_clip, samp_samples, samp_vae, samp_seed, samp_positive, samp_negative, steps, start_step, last_step, cfg, sampler_name, scheduler, denoise, image_output, link_id, save_prefix, tile_size, prompt, extra_pnginfo, my_unique_id, preview_latent, force_full_denoise=force_full_denoise, disable_noise=disable_noise):
if 'layer_diffusion_method' in pipe['loader_settings']:
samp_blend_samples = pipe['blend_samples'] if 'blend_samples' in pipe else None
additional_cond = pipe['loader_settings']['layer_diffusion_cond'] if 'layer_diffusion_cond' in pipe['loader_settings'] else (None, None, None)
method = self.get_layer_diffusion_method(pipe['loader_settings']['layer_diffusion_method'], samp_blend_samples is not None)
images = pipe['images'].movedim(-1, 1) if 'images' in pipe else None
weight = pipe['loader_settings']['layer_diffusion_weight'] if 'layer_diffusion_weight' in pipe['loader_settings'] else 1.0
(samp_model, samp_positive, samp_negative) = self.apply_layer_diffusion(samp_model, method, weight, samp_samples, samp_blend_samples, samp_positive, samp_negative, images, additional_cond)
blend_samples = pipe['blend_samples'] if 'blend_samples' in pipe else None
layer_diffusion_method = pipe['loader_settings']['layer_diffusion_method'] if 'layer_diffusion_method' in pipe['loader_settings'] else None
empty_samples = pipe['loader_settings']['empty_samples'] if 'empty_samples' in pipe['loader_settings'] else None
samples = empty_samples if layer_diffusion_method is not None and empty_samples is not None else samp_samples
if samp_model is not None:
samp_model = downscale_model_unet(samp_model)
start_time = int(time.time() * 1000)
samp_samples = sampler.common_ksampler(samp_model, samp_seed, steps, cfg, sampler_name, scheduler, samp_positive, samp_negative, samples, denoise=denoise, preview_latent=preview_latent, start_step=start_step, last_step=last_step, force_full_denoise=force_full_denoise, disable_noise=disable_noise)
end_time = int(time.time() * 1000)
latent = samp_samples['samples']
if tile_size is not None:
samp_images = samp_vae.decode_tiled(latent, tile_x=tile_size // 8, tile_y=tile_size // 8)
else:
samp_images = samp_vae.decode(latent).cpu()
(new_images, samp_images, alpha) = self.layer_diffusion_decode(layer_diffusion_method, latent, blend_samples, samp_images, samp_model)
end_decode_time = int(time.time() * 1000)
spent_time = '扩散:' + str((end_time - start_time) / 1000) + '秒, 解码:' + str((end_decode_time - end_time) / 1000) + '秒'
results = easySave(new_images, save_prefix, image_output, prompt, extra_pnginfo)
sampler.update_value_by_id('results', my_unique_id, results)
easyCache.update_loaded_objects(prompt)
new_pipe = {'model': samp_model, 'positive': samp_positive, 'negative': samp_negative, 'vae': samp_vae, 'clip': samp_clip, 'samples': samp_samples, 'blend_samples': blend_samples, 'images': new_images, 'samp_images': samp_images, 'alpha': alpha, 'seed': samp_seed, 'loader_settings': {**pipe['loader_settings'], 'spent_time': spent_time}}
sampler.update_value_by_id('pipe_line', my_unique_id, new_pipe)
del pipe
if image_output in ('Hide', 'Hide/Save'):
return {'ui': {}, 'result': sampler.get_output(new_pipe)}
if image_output in ('Sender', 'Sender/Save'):
PromptServer.instance.send_sync('img-send', {'link_id': link_id, 'images': results})
return {'ui': {'images': results}, 'result': sampler.get_output(new_pipe)}
def process_xyPlot(pipe, samp_model, samp_clip, samp_samples, samp_vae, samp_seed, samp_positive, samp_negative, steps, cfg, sampler_name, scheduler, denoise, image_output, link_id, save_prefix, tile_size, prompt, extra_pnginfo, my_unique_id, preview_latent, xyPlot, force_full_denoise, disable_noise):
sampleXYplot = easyXYPlot(xyPlot, save_prefix, image_output, prompt, extra_pnginfo, my_unique_id, sampler, easyCache)
if not sampleXYplot.validate_xy_plot():
return process_sample_state(pipe, samp_model, samp_clip, samp_samples, samp_vae, samp_seed, samp_positive, samp_negative, steps, 0, 10000, cfg, sampler_name, scheduler, denoise, image_output, link_id, save_prefix, tile_size, prompt, extra_pnginfo, my_unique_id, preview_latent)
if samp_model is not None:
samp_model = downscale_model_unet(samp_model)
alpha = None
blend_samples = pipe['blend_samples'] if 'blend_samples' in pipe else None
layer_diffusion_method = pipe['loader_settings']['layer_diffusion_method'] if 'layer_diffusion_method' in pipe['loader_settings'] else None
plot_image_vars = {'x_node_type': sampleXYplot.x_node_type, 'y_node_type': sampleXYplot.y_node_type, 'lora_name': pipe['loader_settings']['lora_name'] if 'lora_name' in pipe['loader_settings'] else None, 'lora_model_strength': pipe['loader_settings']['lora_model_strength'] if 'model_strength' in pipe['loader_settings'] else None, 'lora_clip_strength': pipe['loader_settings']['lora_clip_strength'] if 'clip_strength' in pipe['loader_settings'] else None, 'lora_stack': pipe['loader_settings']['lora_stack'] if 'lora_stack' in pipe['loader_settings'] else None, 'steps': steps, 'cfg': cfg, 'sampler_name': sampler_name, 'scheduler': scheduler, 'denoise': denoise, 'seed': samp_seed, 'images': pipe['images'], 'model': samp_model, 'vae': samp_vae, 'clip': samp_clip, 'positive_cond': samp_positive, 'negative_cond': samp_negative, 'ckpt_name': pipe['loader_settings']['ckpt_name'] if 'ckpt_name' in pipe['loader_settings'] else None, 'vae_name': pipe['loader_settings']['vae_name'] if 'vae_name' in pipe['loader_settings'] else None, 'clip_skip': pipe['loader_settings']['clip_skip'] if 'clip_skip' in pipe['loader_settings'] else None, 'positive': pipe['loader_settings']['positive'] if 'positive' in pipe['loader_settings'] else None, 'positive_token_normalization': pipe['loader_settings']['positive_token_normalization'] if 'positive_token_normalization' in pipe['loader_settings'] else None, 'positive_weight_interpretation': pipe['loader_settings']['positive_weight_interpretation'] if 'positive_weight_interpretation' in pipe['loader_settings'] else None, 'negative': pipe['loader_settings']['negative'] if 'negative' in pipe['loader_settings'] else None, 'negative_token_normalization': pipe['loader_settings']['negative_token_normalization'] if 'negative_token_normalization' in pipe['loader_settings'] else None, 'negative_weight_interpretation': pipe['loader_settings']['negative_weight_interpretation'] if 'negative_weight_interpretation' in pipe['loader_settings'] else None}
if 'models' in pipe['loader_settings']:
plot_image_vars['models'] = pipe['loader_settings']['models']
if 'vae_use' in pipe['loader_settings']:
plot_image_vars['vae_use'] = pipe['loader_settings']['vae_use']
if 'a1111_prompt_style' in pipe['loader_settings']:
plot_image_vars['a1111_prompt_style'] = pipe['loader_settings']['a1111_prompt_style']
if 'cnet_stack' in pipe['loader_settings']:
plot_image_vars['cnet'] = pipe['loader_settings']['cnet_stack']
if 'positive_cond_stack' in pipe['loader_settings']:
plot_image_vars['positive_cond_stack'] = pipe['loader_settings']['positive_cond_stack']
if 'negative_cond_stack' in pipe['loader_settings']:
plot_image_vars['negative_cond_stack'] = pipe['loader_settings']['negative_cond_stack']
if layer_diffusion_method:
plot_image_vars['layer_diffusion_method'] = layer_diffusion_method
if 'layer_diffusion_weight' in pipe['loader_settings']:
plot_image_vars['layer_diffusion_weight'] = pipe['loader_settings']['layer_diffusion_weight']
if 'layer_diffusion_cond' in pipe['loader_settings']:
plot_image_vars['layer_diffusion_cond'] = pipe['loader_settings']['layer_diffusion_cond']
if 'empty_samples' in pipe['loader_settings']:
plot_image_vars['empty_samples'] = pipe['loader_settings']['empty_samples']
latent_image = sampleXYplot.get_latent(pipe['samples'])
latents_plot = sampleXYplot.get_labels_and_sample(plot_image_vars, latent_image, preview_latent, start_step, last_step, force_full_denoise, disable_noise)
samp_samples = {'samples': latents_plot}
(images, image_list) = sampleXYplot.plot_images_and_labels()
output_images = torch.stack([tensor.squeeze() for tensor in image_list])
(new_images, samp_images, alpha) = self.layer_diffusion_decode(layer_diffusion_method, latents_plot, blend_samples, output_images, samp_model)
results = easySave(images, save_prefix, image_output, prompt, extra_pnginfo)
sampler.update_value_by_id('results', my_unique_id, results)
easyCache.update_loaded_objects(prompt)
new_pipe = {'model': samp_model, 'positive': samp_positive, 'negative': samp_negative, 'vae': samp_vae, 'clip': samp_clip, 'samples': samp_samples, 'blend_samples': blend_samples, 'samp_images': samp_images, 'images': new_images, 'seed': samp_seed, 'alpha': alpha, 'loader_settings': pipe['loader_settings']}
sampler.update_value_by_id('pipe_line', my_unique_id, new_pipe)
del pipe
if image_output in ('Hide', 'Hide/Save'):
return sampler.get_output(new_pipe)
return {'ui': {'images': results}, 'result': sampler.get_output(new_pipe)}
preview_latent = True
if image_output in ('Hide', 'Hide/Save'):
preview_latent = False
xyplot_id = next((x for x in prompt if 'XYPlot' in str(prompt[x]['class_type'])), None)
if xyplot_id is None:
xyPlot = None
else:
xyPlot = pipe['loader_settings']['xyplot'] if 'xyplot' in pipe['loader_settings'] else xyPlot
if xyPlot is not None:
return process_xyPlot(pipe, samp_model, samp_clip, samp_samples, samp_vae, samp_seed, samp_positive, samp_negative, steps, cfg, sampler_name, scheduler, denoise, image_output, link_id, save_prefix, tile_size, prompt, extra_pnginfo, my_unique_id, preview_latent, xyPlot, force_full_denoise, disable_noise)
else:
return process_sample_state(pipe, samp_model, samp_clip, samp_samples, samp_vae, samp_seed, samp_positive, samp_negative, steps, start_step, last_step, cfg, sampler_name, scheduler, denoise, image_output, link_id, save_prefix, tile_size, prompt, extra_pnginfo, my_unique_id, preview_latent, force_full_denoise, disable_noise)
```