From e254cbed4966aa72a9d569affe7b870498e2c6ad Mon Sep 17 00:00:00 2001 From: "Dr.Lt.Data" Date: Thu, 20 Jun 2024 23:53:14 +0900 Subject: [PATCH] feat: support GITSScheduler --- README.md | 1 + __init__.py | 4 +- modules/impact/animatediff_nodes.py | 14 ++++--- modules/impact/config.py | 2 +- modules/impact/core.py | 16 ++++---- modules/impact/impact_pack.py | 64 ++++++++++++++++------------- modules/impact/impact_sampling.py | 43 +++++++++++-------- modules/impact/segs_nodes.py | 21 ++++++---- modules/impact/segs_upscaler.py | 4 +- modules/impact/special_samplers.py | 63 ++++++++++++++++++++++------ pyproject.toml | 2 +- 11 files changed, 150 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index d5fc82f..4254876 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,7 @@ This custom node helps to conveniently enhance images through Detector, Detailer * `KSampler (pipe)` - pipe version of KSampler * `KSampler (advanced/pipe)` - pipe version of KSamplerAdvacned * When converting the scheduler widget to input, refer to the `Impact Scheduler Adapter` node to resolve compatibility issues. + * `GITSScheduler Func Provider` - provider scheduler function for GITSScheduler ### Batch/List Util diff --git a/__init__.py b/__init__.py index bde026b..8d95b5b 100644 --- a/__init__.py +++ b/__init__.py @@ -298,7 +298,8 @@ NODE_CLASS_MAPPINGS = { "ImpactHFTransformersClassifierProvider": HF_TransformersClassifierProvider, "ImpactSEGSClassify": SEGS_Classify, - "ImpactSchedulerAdapter": ImpactSchedulerAdapter + "ImpactSchedulerAdapter": ImpactSchedulerAdapter, + "GITSSchedulerFuncProvider": GITSSchedulerFuncProvider } @@ -431,6 +432,7 @@ NODE_DISPLAY_NAME_MAPPINGS = { "SEGSPreviewCNet": "SEGSPreview (CNET Image)", "ImpactSchedulerAdapter": "Impact Scheduler Adapter", + "GITSSchedulerFuncProvider": "GITSScheduler Func Provider", } if not impact.config.get_config()['mmdet_skip']: diff --git a/modules/impact/animatediff_nodes.py b/modules/impact/animatediff_nodes.py index 1314cf1..d5974cc 100644 --- a/modules/impact/animatediff_nodes.py +++ b/modules/impact/animatediff_nodes.py @@ -26,6 +26,7 @@ class SEGSDetailerForAnimateDiff: "optional": { "refiner_basic_pipe_opt": ("BASIC_PIPE",), "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -39,7 +40,7 @@ class SEGSDetailerForAnimateDiff: @staticmethod def do_detail(image_frames, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, - denoise, basic_pipe, refiner_ratio=None, refiner_basic_pipe_opt=None, noise_mask_feather=0): + denoise, basic_pipe, refiner_ratio=None, refiner_basic_pipe_opt=None, noise_mask_feather=0, scheduler_func_opt=None): model, clip, vae, positive, negative = basic_pipe if refiner_basic_pipe_opt is None: @@ -89,7 +90,7 @@ class SEGSDetailerForAnimateDiff: refiner_ratio=refiner_ratio, refiner_model=refiner_model, refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper, - noise_mask_feather=noise_mask_feather) + noise_mask_feather=noise_mask_feather, scheduler_func=scheduler_func_opt) if cnet_images is not None: cnet_image_list.extend(cnet_images) @@ -104,11 +105,11 @@ class SEGSDetailerForAnimateDiff: return (segs[0], new_segs), cnet_image_list def doit(self, image_frames, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, - denoise, basic_pipe, refiner_ratio=None, refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0): + denoise, basic_pipe, refiner_ratio=None, refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): segs, cnet_images = SEGSDetailerForAnimateDiff.do_detail(image_frames, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, denoise, basic_pipe, refiner_ratio, refiner_basic_pipe_opt, - noise_mask_feather=noise_mask_feather) + noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) if len(cnet_images) == 0: cnet_images = [empty_pil_tensor()] @@ -139,6 +140,7 @@ class DetailerForEachPipeForAnimateDiff: "detailer_hook": ("DETAILER_HOOK",), "refiner_basic_pipe_opt": ("BASIC_PIPE",), "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -152,7 +154,7 @@ class DetailerForEachPipeForAnimateDiff: @staticmethod def doit(image_frames, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, denoise, feather, basic_pipe, refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None, - noise_mask_feather=0): + noise_mask_feather=0, scheduler_func_opt=None): enhanced_segs = [] cnet_image_list = [] @@ -160,7 +162,7 @@ class DetailerForEachPipeForAnimateDiff: for sub_seg in segs[1]: single_seg = segs[0], [sub_seg] enhanced_seg, cnet_images = SEGSDetailerForAnimateDiff().do_detail(image_frames, single_seg, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, - denoise, basic_pipe, refiner_ratio, refiner_basic_pipe_opt, noise_mask_feather) + denoise, basic_pipe, refiner_ratio, refiner_basic_pipe_opt, noise_mask_feather, scheduler_func_opt=scheduler_func_opt) image_frames = SEGSPaste.doit(image_frames, enhanced_seg, feather, alpha=255)[0] diff --git a/modules/impact/config.py b/modules/impact/config.py index d9e42c1..51038f2 100644 --- a/modules/impact/config.py +++ b/modules/impact/config.py @@ -1,7 +1,7 @@ import configparser import os -version_code = [5, 14, 1] +version_code = [5, 15] version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '') dependency_version = 21 diff --git a/modules/impact/core.py b/modules/impact/core.py index 8076e80..8141b20 100644 --- a/modules/impact/core.py +++ b/modules/impact/core.py @@ -223,7 +223,7 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max detailer_hook=None, refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None, control_net_wrapper=None, cycle=1, - inpaint_model=False, noise_mask_feather=0): + inpaint_model=False, noise_mask_feather=0, scheduler_func=None): if noise_mask is not None: noise_mask = utils.tensor_gaussian_blur_mask(noise_mask, noise_mask_feather) @@ -331,7 +331,8 @@ def enhance_detail(image, model, clip, vae, guide_size, guide_size_for_bbox, max noise = None refined_latent = impact_sampling.ksampler_wrapper(model2, seed2, steps2, cfg2, sampler_name2, scheduler2, positive2, negative2, - refined_latent, denoise2, refiner_ratio, refiner_model, refiner_clip, refiner_positive, refiner_negative, noise=noise) + refined_latent, denoise2, refiner_ratio, refiner_model, refiner_clip, refiner_positive, refiner_negative, + noise=noise, scheduler_func=scheduler_func) if detailer_hook is not None: refined_latent = detailer_hook.pre_decode(refined_latent) @@ -364,7 +365,7 @@ def enhance_detail_for_animatediff(image_frames, model, clip, vae, guide_size, g wildcard_opt=None, wildcard_opt_concat_mode=None, detailer_hook=None, refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, - refiner_negative=None, control_net_wrapper=None, noise_mask_feather=0): + refiner_negative=None, control_net_wrapper=None, noise_mask_feather=0, scheduler_func=None): if noise_mask is not None: noise_mask = utils.tensor_gaussian_blur_mask(noise_mask, noise_mask_feather) noise_mask = noise_mask.squeeze(3) @@ -478,7 +479,7 @@ def enhance_detail_for_animatediff(image_frames, model, clip, vae, guide_size, g latent = detailer_hook.post_encode(latent) refined_latent = impact_sampling.ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, - latent, denoise, refiner_ratio, refiner_model, refiner_clip, refiner_positive, refiner_negative) + latent, denoise, refiner_ratio, refiner_model, refiner_clip, refiner_positive, refiner_negative, scheduler_func=scheduler_func) if detailer_hook is not None: refined_latent = detailer_hook.pre_decode(refined_latent) @@ -1602,7 +1603,7 @@ class TwoSamplersForMaskUpscaler: class PixelKSampleUpscaler: def __init__(self, scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, - use_tiled_vae, upscale_model_opt=None, hook_opt=None, tile_size=512): + use_tiled_vae, upscale_model_opt=None, hook_opt=None, tile_size=512, scheduler_func=None): self.params = scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise self.upscale_model = upscale_model_opt self.hook = hook_opt @@ -1610,6 +1611,7 @@ class PixelKSampleUpscaler: self.tile_size = tile_size self.is_tiled = False self.vae = vae + self.scheduler_func = scheduler_func def upscale(self, step_info, samples, upscale_factor, save_temp_prefix=None): scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise = self.params @@ -1635,7 +1637,7 @@ class PixelKSampleUpscaler: upscaled_latent, denoise) refined_latent = impact_sampling.impact_sample(model, seed, steps, cfg, sampler_name, scheduler, - positive, negative, upscaled_latent, denoise) + positive, negative, upscaled_latent, denoise, scheduler_func_opt=self.scheduler_func) return refined_latent def upscale_shape(self, step_info, samples, w, h, save_temp_prefix=None): @@ -1663,7 +1665,7 @@ class PixelKSampleUpscaler: upscaled_latent, denoise) refined_latent = impact_sampling.impact_sample(model, seed, steps, cfg, sampler_name, scheduler, - positive, negative, upscaled_latent, denoise) + positive, negative, upscaled_latent, denoise, scheduler_func_opt=self.scheduler_func) return refined_latent diff --git a/modules/impact/impact_pack.py b/modules/impact/impact_pack.py index 1b07427..a342545 100644 --- a/modules/impact/impact_pack.py +++ b/modules/impact/impact_pack.py @@ -201,6 +201,7 @@ class DetailerForEach: "detailer_hook": ("DETAILER_HOOK",), "inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}), "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -213,7 +214,7 @@ class DetailerForEach: def do_detail(image, segs, model, clip, vae, guide_size, guide_size_for_bbox, max_size, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard_opt=None, detailer_hook=None, refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None, - cycle=1, inpaint_model=False, noise_mask_feather=0): + cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): if len(image) > 1: raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.') @@ -293,7 +294,8 @@ class DetailerForEach: refiner_ratio=refiner_ratio, refiner_model=refiner_model, refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, + scheduler_func=scheduler_func_opt) if cnet_pils is not None: cnet_pil_list.extend(cnet_pils) @@ -336,13 +338,13 @@ class DetailerForEach: def doit(self, image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard, cycle=1, - detailer_hook=None, inpaint_model=False, noise_mask_feather=0): + detailer_hook=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): enhanced_img, *_ = \ DetailerForEach.do_detail(image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard, detailer_hook, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) return (enhanced_img, ) @@ -372,11 +374,12 @@ class DetailerForEachPipe: "cycle": ("INT", {"default": 1, "min": 1, "max": 10, "step": 1}), }, "optional": { - "detailer_hook": ("DETAILER_HOOK",), - "refiner_basic_pipe_opt": ("BASIC_PIPE",), - "inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}), - "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), - } + "detailer_hook": ("DETAILER_HOOK",), + "refiner_basic_pipe_opt": ("BASIC_PIPE",), + "inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}), + "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), + "scheduler_func_opt": ("SCHEDULER_FUNC",), + } } RETURN_TYPES = ("IMAGE", "SEGS", "BASIC_PIPE", "IMAGE") @@ -389,7 +392,7 @@ class DetailerForEachPipe: def doit(self, image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, denoise, feather, noise_mask, force_inpaint, basic_pipe, wildcard, refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None, - cycle=1, inpaint_model=False, noise_mask_feather=0): + cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): if len(image) > 1: raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.') @@ -407,13 +410,13 @@ class DetailerForEachPipe: force_inpaint, wildcard, detailer_hook, refiner_ratio=refiner_ratio, refiner_model=refiner_model, refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) # set fallback image if len(cnet_pil_list) == 0: cnet_pil_list = [empty_pil_tensor()] - return (enhanced_img, new_segs, basic_pipe, cnet_pil_list) + return enhanced_img, new_segs, basic_pipe, cnet_pil_list class FaceDetailer: @@ -463,6 +466,7 @@ class FaceDetailer: "detailer_hook": ("DETAILER_HOOK",), "inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}), "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), + "scheduler_func_opt": ("SCHEDULER_FUNC",), }} RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "MASK", "DETAILER_PIPE", "IMAGE") @@ -480,7 +484,7 @@ class FaceDetailer: sam_mask_hint_use_negative, drop_size, bbox_detector, segm_detector=None, sam_model_opt=None, wildcard_opt=None, detailer_hook=None, refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None, cycle=1, - inpaint_model=False, noise_mask_feather=0): + inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): # make default prompt as 'face' if empty prompt for CLIPSeg bbox_detector.setAux('face') @@ -512,7 +516,7 @@ class FaceDetailer: refiner_ratio=refiner_ratio, refiner_model=refiner_model, refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) else: enhanced_img = image cropped_enhanced = [] @@ -538,7 +542,7 @@ class FaceDetailer: bbox_threshold, bbox_dilation, bbox_crop_factor, sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion, sam_mask_hint_threshold, sam_mask_hint_use_negative, drop_size, bbox_detector, wildcard, cycle=1, - sam_model_opt=None, segm_detector_opt=None, detailer_hook=None, inpaint_model=False, noise_mask_feather=0): + sam_model_opt=None, segm_detector_opt=None, detailer_hook=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): result_img = None result_mask = None @@ -556,7 +560,7 @@ class FaceDetailer: bbox_threshold, bbox_dilation, bbox_crop_factor, sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion, sam_mask_hint_threshold, sam_mask_hint_use_negative, drop_size, bbox_detector, segm_detector_opt, sam_model_opt, wildcard, detailer_hook, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) result_img = torch.cat((result_img, enhanced_img), dim=0) if result_img is not None else enhanced_img result_mask = torch.cat((result_mask, mask), dim=0) if result_mask is not None else mask @@ -1021,6 +1025,7 @@ class PixelKSampleUpscalerProvider: "optional": { "upscale_model_opt": ("UPSCALE_MODEL", ), "pk_hook_opt": ("PK_HOOK", ), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -1030,10 +1035,10 @@ class PixelKSampleUpscalerProvider: CATEGORY = "ImpactPack/Upscale" def doit(self, scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, - use_tiled_vae, upscale_model_opt=None, pk_hook_opt=None, tile_size=512): + use_tiled_vae, upscale_model_opt=None, pk_hook_opt=None, tile_size=512, scheduler_func_opt=None): upscaler = core.PixelKSampleUpscaler(scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, use_tiled_vae, upscale_model_opt, pk_hook_opt, - tile_size=tile_size) + tile_size=tile_size, scheduler_func=scheduler_func_opt) return (upscaler, ) @@ -1057,6 +1062,7 @@ class PixelKSampleUpscalerProviderPipe(PixelKSampleUpscalerProvider): "optional": { "upscale_model_opt": ("UPSCALE_MODEL", ), "pk_hook_opt": ("PK_HOOK", ), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -1066,11 +1072,11 @@ class PixelKSampleUpscalerProviderPipe(PixelKSampleUpscalerProvider): CATEGORY = "ImpactPack/Upscale" def doit_pipe(self, scale_method, seed, steps, cfg, sampler_name, scheduler, denoise, - use_tiled_vae, basic_pipe, upscale_model_opt=None, pk_hook_opt=None, tile_size=512): + use_tiled_vae, basic_pipe, upscale_model_opt=None, pk_hook_opt=None, tile_size=512, scheduler_func_opt=None): model, _, vae, positive, negative = basic_pipe upscaler = core.PixelKSampleUpscaler(scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, use_tiled_vae, upscale_model_opt, pk_hook_opt, - tile_size=tile_size) + tile_size=tile_size, scheduler_func=scheduler_func_opt) return (upscaler, ) @@ -1305,6 +1311,7 @@ class FaceDetailerPipe: "optional": { "inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}), "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -1319,7 +1326,7 @@ class FaceDetailerPipe: denoise, feather, noise_mask, force_inpaint, bbox_threshold, bbox_dilation, bbox_crop_factor, sam_detection_hint, sam_dilation, sam_threshold, sam_bbox_expansion, sam_mask_hint_threshold, sam_mask_hint_use_negative, drop_size, refiner_ratio=None, - cycle=1, inpaint_model=False, noise_mask_feather=0): + cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): result_img = None result_mask = None @@ -1342,7 +1349,7 @@ class FaceDetailerPipe: sam_mask_hint_use_negative, drop_size, bbox_detector, segm_detector, sam_model_opt, wildcard, detailer_hook, refiner_ratio=refiner_ratio, refiner_model=refiner_model, refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) result_img = torch.cat((result_img, enhanced_img), dim=0) if result_img is not None else enhanced_img result_mask = torch.cat((result_mask, mask), dim=0) if result_mask is not None else mask @@ -1395,6 +1402,7 @@ class MaskDetailerPipe: "detailer_hook": ("DETAILER_HOOK",), "inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}), "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -1408,7 +1416,7 @@ class MaskDetailerPipe: def doit(self, image, mask, basic_pipe, guide_size, guide_size_for, max_size, mask_mode, seed, steps, cfg, sampler_name, scheduler, denoise, feather, crop_factor, drop_size, refiner_ratio, batch_size, cycle=1, - refiner_basic_pipe_opt=None, detailer_hook=None, inpaint_model=False, noise_mask_feather=0): + refiner_basic_pipe_opt=None, detailer_hook=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): if len(image) > 1: raise Exception('[Impact Pack] ERROR: MaskDetailer does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.') @@ -1439,7 +1447,7 @@ class MaskDetailerPipe: force_inpaint=True, wildcard_opt=None, detailer_hook=detailer_hook, refiner_ratio=refiner_ratio, refiner_model=refiner_model, refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) else: enhanced_img, cropped_enhanced, cropped_enhanced_alpha = image, [], [] @@ -1472,7 +1480,7 @@ class DetailerForEachTest(DetailerForEach): def doit(self, image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard, detailer_hook=None, - cycle=1, inpaint_model=False, noise_mask_feather=0): + cycle=1, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): if len(image) > 1: raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.') @@ -1481,7 +1489,7 @@ class DetailerForEachTest(DetailerForEach): DetailerForEach.do_detail(image, segs, model, clip, vae, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, feather, noise_mask, force_inpaint, wildcard, detailer_hook, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) # set fallback image if len(cropped) == 0: @@ -1510,7 +1518,7 @@ class DetailerForEachTestPipe(DetailerForEachPipe): def doit(self, image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, denoise, feather, noise_mask, force_inpaint, basic_pipe, wildcard, cycle=1, - refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0): + refiner_ratio=None, detailer_hook=None, refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): if len(image) > 1: raise Exception('[Impact Pack] ERROR: DetailerForEach does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.') @@ -1529,7 +1537,7 @@ class DetailerForEachTestPipe(DetailerForEachPipe): refiner_ratio=refiner_ratio, refiner_model=refiner_model, refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative, - cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + cycle=cycle, inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) # set fallback image if len(cropped) == 0: diff --git a/modules/impact/impact_sampling.py b/modules/impact/impact_sampling.py index d33fd17..b107697 100644 --- a/modules/impact/impact_sampling.py +++ b/modules/impact/impact_sampling.py @@ -151,11 +151,15 @@ def sample_with_custom_noise(model, add_noise, noise_seed, cfg, positive, negati # When sampling one step at a time, it mitigates the problem. (especially for _sde series samplers) def separated_sample(model, add_noise, seed, steps, cfg, sampler_name, scheduler, positive, negative, - latent_image, start_at_step, end_at_step, return_with_leftover_noise, sigma_ratio=1.0, sampler_opt=None, noise=None, callback=None): - if sampler_opt is None: - total_sigmas = calculate_sigmas(model, sampler_name, scheduler, steps) + latent_image, start_at_step, end_at_step, return_with_leftover_noise, sigma_ratio=1.0, sampler_opt=None, noise=None, callback=None, scheduler_func=None): + + if scheduler_func is not None: + total_sigmas = scheduler_func(model, sampler_name, steps) else: - total_sigmas = calculate_sigmas(model, "", scheduler, steps) + if sampler_opt is None: + total_sigmas = calculate_sigmas(model, sampler_name, scheduler, steps) + else: + total_sigmas = calculate_sigmas(model, "", scheduler, steps) sigmas = total_sigmas @@ -189,15 +193,15 @@ def separated_sample(model, add_noise, seed, steps, cfg, sampler_name, scheduler return res[1] -def impact_sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=1.0, sigma_ratio=1.0, sampler_opt=None, noise=None): +def impact_sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=1.0, sigma_ratio=1.0, sampler_opt=None, noise=None, scheduler_func=None): advanced_steps = math.floor(steps / denoise) start_at_step = advanced_steps - steps end_at_step = start_at_step + steps - return separated_sample(model, True, seed, advanced_steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, False) + return separated_sample(model, True, seed, advanced_steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, False, scheduler_func=scheduler_func) def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, - refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None, sigma_factor=1.0, noise=None): + refiner_ratio=None, refiner_model=None, refiner_clip=None, refiner_positive=None, refiner_negative=None, sigma_factor=1.0, noise=None, scheduler_func=None): if refiner_ratio is None or refiner_model is None or refiner_clip is None or refiner_positive is None or refiner_negative is None: # Use separated_sample instead of KSampler for `AYS scheduler` @@ -207,7 +211,9 @@ def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, start_at_step = advanced_steps - steps end_at_step = start_at_step + steps - refined_latent = separated_sample(model, True, seed, advanced_steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, False, sigma_ratio=sigma_factor, noise=noise) + refined_latent = separated_sample(model, True, seed, advanced_steps, cfg, sampler_name, scheduler, + positive, negative, latent_image, start_at_step, end_at_step, False, + sigma_ratio=sigma_factor, noise=noise, scheduler_func=scheduler_func) else: advanced_steps = math.floor(steps / denoise) start_at_step = advanced_steps - steps @@ -215,7 +221,8 @@ def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, # print(f"pre: {start_at_step} .. {end_at_step} / {advanced_steps}") temp_latent = separated_sample(model, True, seed, advanced_steps, cfg, sampler_name, scheduler, - positive, negative, latent_image, start_at_step, end_at_step, True, sigma_ratio=sigma_factor, noise=noise) + positive, negative, latent_image, start_at_step, end_at_step, True, + sigma_ratio=sigma_factor, noise=noise, scheduler_func=scheduler_func) if 'noise_mask' in latent_image: # noise_latent = \ @@ -228,7 +235,8 @@ def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, # print(f"post: {end_at_step} .. {advanced_steps + 1} / {advanced_steps}") refined_latent = separated_sample(refiner_model, False, seed, advanced_steps, cfg, sampler_name, scheduler, - refiner_positive, refiner_negative, temp_latent, end_at_step, advanced_steps + 1, False, sigma_ratio=sigma_factor) + refiner_positive, refiner_negative, temp_latent, end_at_step, advanced_steps + 1, False, + sigma_ratio=sigma_factor, scheduler_func=scheduler_func) return refined_latent @@ -236,9 +244,10 @@ def ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, class KSamplerAdvancedWrapper: params = None - def __init__(self, model, cfg, sampler_name, scheduler, positive, negative, sampler_opt=None, sigma_factor=1.0): + def __init__(self, model, cfg, sampler_name, scheduler, positive, negative, sampler_opt=None, sigma_factor=1.0, scheduler_func=None): self.params = model, cfg, sampler_name, scheduler, positive, negative, sigma_factor self.sampler_opt = sampler_opt + self.scheduler_func = scheduler_func def clone_with_conditionings(self, positive, negative): model, cfg, sampler_name, scheduler, _, _, _ = self.params @@ -269,7 +278,8 @@ class KSamplerAdvancedWrapper: if sigma_ratio > 0: latent_image = separated_sample(model, add_noise, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, - return_with_leftover_noise, sigma_ratio=sigma_ratio * sigma_factor, sampler_opt=self.sampler_opt, noise=noise) + return_with_leftover_noise, sigma_ratio=sigma_ratio * sigma_factor, + sampler_opt=self.sampler_opt, noise=noise, scheduler_func=self.scheduler_func) except ValueError as e: if str(e) == 'sigma_min and sigma_max must not be 0': print(f"\nWARN: sampling skipped - sigma_min and sigma_max are 0") @@ -292,8 +302,8 @@ class KSamplerAdvancedWrapper: try: latent_image = separated_sample(model, add_noise, seed, steps, cfg, recovery_sampler, scheduler, - positive, negative, latent_image, start_at_step-compensate, end_at_step, - return_with_leftover_noise, sigma_ratio=recovery_sigma_ratio * sigma_factor, sampler_opt=self.sampler_opt) + positive, negative, latent_image, start_at_step-compensate, end_at_step, return_with_leftover_noise, + sigma_ratio=recovery_sigma_ratio * sigma_factor, sampler_opt=self.sampler_opt, scheduler_func=self.scheduler_func) except ValueError as e: if str(e) == 'sigma_min and sigma_max must not be 0': print(f"\nWARN: sampling skipped - sigma_min and sigma_max are 0") @@ -304,8 +314,9 @@ class KSamplerAdvancedWrapper: class KSamplerWrapper: params = None - def __init__(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise): + def __init__(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, scheduler_func=None): self.params = model, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise + self.scheduler_func = scheduler_func def sample(self, latent_image, hook=None): model, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise = self.params @@ -314,4 +325,4 @@ class KSamplerWrapper: model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise = \ hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise) - return nodes.common_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise=denoise)[0] + return impact_sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, scheduler_func=self.scheduler_func) diff --git a/modules/impact/segs_nodes.py b/modules/impact/segs_nodes.py index 6925be2..67c57f5 100644 --- a/modules/impact/segs_nodes.py +++ b/modules/impact/segs_nodes.py @@ -41,6 +41,7 @@ class SEGSDetailer: "refiner_basic_pipe_opt": ("BASIC_PIPE",), "inpaint_model": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}), "noise_mask_feather": ("INT", {"default": 20, "min": 0, "max": 100, "step": 1}), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -55,7 +56,7 @@ class SEGSDetailer: @staticmethod def do_detail(image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, denoise, noise_mask, force_inpaint, basic_pipe, refiner_ratio=None, batch_size=1, cycle=1, - refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0): + refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): model, clip, vae, positive, negative = basic_pipe if refiner_basic_pipe_opt is None: @@ -108,7 +109,7 @@ class SEGSDetailer: refiner_ratio=refiner_ratio, refiner_model=refiner_model, refiner_clip=refiner_clip, refiner_positive=refiner_positive, refiner_negative=refiner_negative, control_net_wrapper=seg.control_net_wrapper, cycle=cycle, - inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) if cnet_pils is not None: cnet_pil_list.extend(cnet_pils) @@ -125,7 +126,7 @@ class SEGSDetailer: def doit(self, image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, denoise, noise_mask, force_inpaint, basic_pipe, refiner_ratio=None, batch_size=1, cycle=1, - refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0): + refiner_basic_pipe_opt=None, inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): if len(image) > 1: raise Exception('[Impact Pack] ERROR: SEGSDetailer does not allow image batches.\nPlease refer to https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/batching-detailer.md for more information.') @@ -133,13 +134,13 @@ class SEGSDetailer: segs, cnet_pil_list = SEGSDetailer.do_detail(image, segs, guide_size, guide_size_for, max_size, seed, steps, cfg, sampler_name, scheduler, denoise, noise_mask, force_inpaint, basic_pipe, refiner_ratio, batch_size, cycle=cycle, refiner_basic_pipe_opt=refiner_basic_pipe_opt, - inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) # set fallback image if len(cnet_pil_list) == 0: cnet_pil_list = [empty_pil_tensor()] - return (segs, cnet_pil_list) + return segs, cnet_pil_list class SEGSPaste: @@ -1743,6 +1744,7 @@ class SEGSUpscaler: "optional": { "upscale_model_opt": ("UPSCALE_MODEL",), "upscaler_hook_opt": ("UPSCALER_HOOK",), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -1754,7 +1756,7 @@ class SEGSUpscaler: @staticmethod def doit(image, segs, model, clip, vae, rescale_factor, resampling_method, supersample, rounding_modulus, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, feather, inpaint_model, noise_mask_feather, - upscale_model_opt=None, upscaler_hook_opt=None): + upscale_model_opt=None, upscaler_hook_opt=None, scheduler_func_opt=None): new_image = segs_upscaler.upscaler(image, upscale_model_opt, rescale_factor, resampling_method, supersample, rounding_modulus) @@ -1780,7 +1782,7 @@ class SEGSUpscaler: enhanced_image = segs_upscaler.img2img_segs(cropped_image, model, clip, vae, seg_seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, noise_mask=cropped_mask, control_net_wrapper=seg.control_net_wrapper, - inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather) + inpaint_model=inpaint_model, noise_mask_feather=noise_mask_feather, scheduler_func_opt=scheduler_func_opt) if not (enhanced_image is None): new_image = new_image.cpu() enhanced_image = enhanced_image.cpu() @@ -1822,6 +1824,7 @@ class SEGSUpscalerPipe: "optional": { "upscale_model_opt": ("UPSCALE_MODEL",), "upscaler_hook_opt": ("UPSCALER_HOOK",), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -1833,10 +1836,10 @@ class SEGSUpscalerPipe: @staticmethod def doit(image, segs, basic_pipe, rescale_factor, resampling_method, supersample, rounding_modulus, seed, steps, cfg, sampler_name, scheduler, denoise, feather, inpaint_model, noise_mask_feather, - upscale_model_opt=None, upscaler_hook_opt=None): + upscale_model_opt=None, upscaler_hook_opt=None, scheduler_func_opt=None): model, clip, vae, positive, negative = basic_pipe return SEGSUpscaler.doit(image, segs, model, clip, vae, rescale_factor, resampling_method, supersample, rounding_modulus, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, feather, inpaint_model, noise_mask_feather, - upscale_model_opt=upscale_model_opt, upscaler_hook_opt=upscaler_hook_opt) + upscale_model_opt=upscale_model_opt, upscaler_hook_opt=upscaler_hook_opt, scheduler_func_opt=scheduler_func_opt) diff --git a/modules/impact/segs_upscaler.py b/modules/impact/segs_upscaler.py index ba09d2c..af33e32 100644 --- a/modules/impact/segs_upscaler.py +++ b/modules/impact/segs_upscaler.py @@ -83,7 +83,7 @@ def upscaler(image, upscale_model, rescale_factor, resampling_method, supersampl def img2img_segs(image, model, clip, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, noise_mask, control_net_wrapper=None, - inpaint_model=False, noise_mask_feather=0): + inpaint_model=False, noise_mask_feather=0, scheduler_func_opt=None): original_image_size = image.shape[1:3] @@ -115,7 +115,7 @@ def img2img_segs(image, model, clip, vae, seed, steps, cfg, sampler_name, schedu refined_latent = latent_image # ksampler - refined_latent = impact_sampling.ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, refined_latent, denoise) + refined_latent = impact_sampling.ksampler_wrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, refined_latent, denoise, scheduler_func=scheduler_func_opt) # non-latent downscale - latent downscale cause bad quality refined_image = vae.decode(refined_latent['samples']) diff --git a/modules/impact/special_samplers.py b/modules/impact/special_samplers.py index 23f41a5..7f9eca5 100644 --- a/modules/impact/special_samplers.py +++ b/modules/impact/special_samplers.py @@ -49,6 +49,9 @@ class KSamplerProvider: "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), "basic_pipe": ("BASIC_PIPE", ) }, + "optional": { + "scheduler_func_opt": ("SCHEDULER_FUNC",), + } } RETURN_TYPES = ("KSAMPLER",) @@ -57,9 +60,9 @@ class KSamplerProvider: CATEGORY = "ImpactPack/Sampler" @staticmethod - def doit(seed, steps, cfg, sampler_name, scheduler, denoise, basic_pipe): + def doit(seed, steps, cfg, sampler_name, scheduler, denoise, basic_pipe, scheduler_func_opt=None): model, _, _, positive, negative = basic_pipe - sampler = KSamplerWrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise) + sampler = KSamplerWrapper(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, scheduler_func=scheduler_func_opt) return (sampler, ) @@ -74,7 +77,8 @@ class KSamplerAdvancedProvider: "basic_pipe": ("BASIC_PIPE", ) }, "optional": { - "sampler_opt": ("SAMPLER", ) + "sampler_opt": ("SAMPLER", ), + "scheduler_func_opt": ("SCHEDULER_FUNC",), } } @@ -84,9 +88,9 @@ class KSamplerAdvancedProvider: CATEGORY = "ImpactPack/Sampler" @staticmethod - def doit(cfg, sampler_name, scheduler, basic_pipe, sigma_factor=1.0, sampler_opt=None): + def doit(cfg, sampler_name, scheduler, basic_pipe, sigma_factor=1.0, sampler_opt=None, scheduler_func_opt=None): model, _, _, positive, negative = basic_pipe - sampler = KSamplerAdvancedWrapper(model, cfg, sampler_name, scheduler, positive, negative, sampler_opt=sampler_opt, sigma_factor=sigma_factor) + sampler = KSamplerAdvancedWrapper(model, cfg, sampler_name, scheduler, positive, negative, sampler_opt=sampler_opt, sigma_factor=sigma_factor, scheduler_func=scheduler_func_opt) return (sampler, ) @@ -581,18 +585,22 @@ class KSamplerBasicPipe: "scheduler": (core.SCHEDULERS, ), "latent_image": ("LATENT", ), "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), - } + }, + "optional": + { + "scheduler_func_opt": ("SCHEDULER_FUNC", ), + } } RETURN_TYPES = ("BASIC_PIPE", "LATENT", "VAE") FUNCTION = "sample" - CATEGORY = "sampling" + CATEGORY = "ImpactPack/sampling" @staticmethod - def sample(basic_pipe, seed, steps, cfg, sampler_name, scheduler, latent_image, denoise=1.0): + def sample(basic_pipe, seed, steps, cfg, sampler_name, scheduler, latent_image, denoise=1.0, scheduler_func_opt=None): model, clip, vae, positive, negative = basic_pipe - latent = impact_sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise) + latent = impact_sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, scheduler_func=scheduler_func_opt) return basic_pipe, latent, vae @@ -611,18 +619,47 @@ class KSamplerAdvancedBasicPipe: "start_at_step": ("INT", {"default": 0, "min": 0, "max": 10000}), "end_at_step": ("INT", {"default": 10000, "min": 0, "max": 10000}), "return_with_leftover_noise": ("BOOLEAN", {"default": False, "label_on": "enable", "label_off": "disable"}), - } + }, + "optional": + { + "scheduler_func_opt": ("SCHEDULER_FUNC", ), + } } RETURN_TYPES = ("BASIC_PIPE", "LATENT", "VAE") FUNCTION = "sample" - CATEGORY = "sampling" + CATEGORY = "ImpactPack/sampling" @staticmethod - def sample(basic_pipe, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, latent_image, start_at_step, end_at_step, return_with_leftover_noise, denoise=1.0): + def sample(basic_pipe, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, latent_image, start_at_step, end_at_step, return_with_leftover_noise, denoise=1.0, scheduler_func_opt=None): model, clip, vae, positive, negative = basic_pipe - latent = separated_sample(model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, return_with_leftover_noise) + latent = separated_sample(model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, return_with_leftover_noise, scheduler_func=scheduler_func_opt) return basic_pipe, latent, vae + +class GITSSchedulerFuncProvider: + @classmethod + def INPUT_TYPES(s): + return {"required": { + "coeff": ("FLOAT", {"default": 1.20, "min": 0.80, "max": 1.50, "step": 0.05}), + "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), + } + } + + RETURN_TYPES = ("SCHEDULER_FUNC",) + CATEGORY = "ImpactPack/sampling" + + FUNCTION = "doit" + + def doit(self, coeff, denoise): + try: + import comfy_extras.nodes_gits as node_gits + except Exception: + raise Exception("[Impact Pack] ComfyUI is an outdated version.") + + def f(model, sampler, steps): + return node_gits.GITSScheduler().get_sigmas(coeff, steps, denoise)[0] + + return (f, ) diff --git a/pyproject.toml b/pyproject.toml index 0a82fb5..64b7315 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-impact-pack" description = "This extension offers various detector nodes and detailer nodes that allow you to configure a workflow that automatically enhances facial details. And provide iterative upscaler." -version = "5.14.1" +version = "5.15" license = "LICENSE" dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]