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

19 KiB
Raw Permalink Blame History

Documentation

节点类'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)