199 lines
19 KiB
Markdown
199 lines
19 KiB
Markdown
# 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)
|
||
``` |