| | import torch |
| | import gradio as gr |
| | from modules import scripts, script_callbacks, sd_samplers_cfg_denoiser, shared |
| |
|
| | |
| | |
| | |
| | def calc_nrs(x_orig, cond, uncond, sigma, skew, stretch, squash): |
| | |
| | is_v_pred = False |
| | if hasattr(shared.sd_model, 'parameterization'): |
| | is_v_pred = shared.sd_model.parameterization == "v" |
| | |
| | |
| | if isinstance(sigma, torch.Tensor): |
| | sig_tens = sigma[0] |
| | else: |
| | sig_tens = torch.tensor(sigma, device=cond.device, dtype=cond.dtype) |
| | |
| | if sig_tens.dtype != cond.dtype: |
| | sig_tens = sig_tens.to(dtype=cond.dtype) |
| |
|
| | sig_tens = sig_tens.view(1, 1, 1, 1) |
| | sig_root = (sig_tens ** 2 + 1).sqrt() |
| |
|
| | |
| | if is_v_pred: |
| | nrs_cond, nrs_uncond = cond, uncond |
| | x_div = None |
| | else: |
| | x_div = x_orig / (sig_tens ** 2 + 1) |
| | factor = sig_tens / sig_root |
| | nrs_cond = x_orig - (x_div - cond * factor) |
| | nrs_uncond = x_orig - (x_div - uncond * factor) |
| |
|
| | |
| | def _dot(a, b): return (a * b).sum(dim=1, keepdim=True) |
| | def _nrm2(v): return _dot(v, v) |
| |
|
| | eps_safe = 1e-6 |
| | |
| | |
| | c_dot_c = _nrm2(nrs_cond) + eps_safe |
| | u_dot_c = _dot(nrs_uncond, nrs_cond) |
| | u_on_c = (u_dot_c / c_dot_c) * nrs_cond |
| | |
| | |
| | proj_diff = nrs_cond - u_on_c |
| | stretched = nrs_cond + (stretch * proj_diff) |
| |
|
| | |
| | u_rej_c = nrs_uncond - u_on_c |
| | skewed = stretched - (skew * u_rej_c) |
| |
|
| | |
| | cond_len = nrs_cond.norm(dim=1, keepdim=True) |
| | nrs_len = skewed.norm(dim=1, keepdim=True) + eps_safe |
| | |
| | squash_scale = (1 - squash) + (squash * (cond_len / nrs_len)) |
| | x_final = skewed * squash_scale |
| |
|
| | |
| | if is_v_pred: |
| | return x_final |
| | else: |
| | return (x_div - (x_orig - x_final)) * (sig_root / sig_tens) |
| |
|
| |
|
| | |
| | |
| | |
| | def should_apply_at_step(current_step, total_steps, start_step, end_step, start_frac, end_frac, step_mode): |
| | """ |
| | Определяет, нужно ли применять эффект на текущем шаге |
| | |
| | Args: |
| | current_step: Текущий шаг сэмплера |
| | total_steps: Общее количество шагов |
| | start_step: Начальный абсолютный шаг |
| | end_step: Конечный абсолютный шаг |
| | start_frac: Начальная доля (0.0-1.0) |
| | end_frac: Конечная доля (0.0-1.0) |
| | step_mode: Режим ("Absolute Steps" или "Fraction of Steps") |
| | |
| | Returns: |
| | bool: True если эффект должен применяться |
| | """ |
| | if step_mode == "Absolute Steps": |
| | |
| | effective_start = max(0, start_step) |
| | effective_end = min(total_steps, end_step) if end_step > 0 else total_steps |
| | return effective_start <= current_step < effective_end |
| | else: |
| | |
| | effective_start = int(total_steps * max(0.0, min(1.0, start_frac))) |
| | effective_end = int(total_steps * max(0.0, min(1.0, end_frac))) |
| | if effective_end == 0: |
| | effective_end = total_steps |
| | return effective_start <= current_step < effective_end |
| |
|
| |
|
| | def get_param_value_at_step(base_value, current_step, total_steps, start_step, end_step, |
| | start_frac, end_frac, step_mode, enabled): |
| | """ |
| | Возвращает значение параметра для текущего шага |
| | Если шаг вне диапазона - возвращает 0.0 |
| | """ |
| | if not enabled: |
| | return base_value |
| | |
| | if should_apply_at_step(current_step, total_steps, start_step, end_step, |
| | start_frac, end_frac, step_mode): |
| | return base_value |
| | else: |
| | return 0.0 |
| |
|
| |
|
| | |
| | |
| | |
| |
|
| | |
| | def hook_cfg_denoiser_params(params): |
| | if hasattr(params.denoiser, 'p') and getattr(params.denoiser.p, '_nrs_enabled', False): |
| | params.denoiser.p._nrs_current_sigma = params.sigma |
| | params.denoiser.p._nrs_current_x_in = params.x |
| | |
| | |
| | if hasattr(params, 'sampling_step'): |
| | params.denoiser.p._nrs_current_step = params.sampling_step |
| | elif hasattr(params.denoiser, 'step'): |
| | params.denoiser.p._nrs_current_step = params.denoiser.step |
| | else: |
| | |
| | params.denoiser.p._nrs_current_step = getattr(params.denoiser.p, '_nrs_current_step', 0) |
| |
|
| | script_callbacks.on_cfg_denoiser(hook_cfg_denoiser_params) |
| |
|
| | |
| | if not hasattr(sd_samplers_cfg_denoiser.CFGDenoiser, 'original_combine_denoised_nrs_backup'): |
| | sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup = sd_samplers_cfg_denoiser.CFGDenoiser.combine_denoised |
| |
|
| | |
| | def hijacked_combine_denoised(self, x_out, conds_list, uncond, cond_scale): |
| | |
| | if not getattr(self, 'p', None) or not getattr(self.p, '_nrs_enabled', False): |
| | return sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup(self, x_out, conds_list, uncond, cond_scale) |
| |
|
| | if not hasattr(self.p, '_nrs_current_sigma') or not hasattr(self.p, '_nrs_current_x_in'): |
| | return sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup(self, x_out, conds_list, uncond, cond_scale) |
| |
|
| | try: |
| | |
| | base_skew, base_stretch, base_squash = self.p._nrs_params |
| | |
| | |
| | step_control_enabled = getattr(self.p, '_nrs_step_control_enabled', False) |
| | step_control_mode = getattr(self.p, '_nrs_step_control_mode', 'Global') |
| | |
| | |
| | current_step = getattr(self.p, '_nrs_current_step', 0) |
| | total_steps = getattr(self.p, 'steps', 20) |
| | |
| | |
| | if step_control_enabled: |
| | if step_control_mode == 'Global': |
| | |
| | global_settings = getattr(self.p, '_nrs_global_step_settings', {}) |
| | start_step = global_settings.get('start_step', 0) |
| | end_step = global_settings.get('end_step', total_steps) |
| | start_frac = global_settings.get('start_frac', 0.0) |
| | end_frac = global_settings.get('end_frac', 1.0) |
| | step_mode = global_settings.get('step_mode', 'Absolute Steps') |
| | |
| | |
| | if not should_apply_at_step(current_step, total_steps, start_step, end_step, |
| | start_frac, end_frac, step_mode): |
| | |
| | return sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup( |
| | self, x_out, conds_list, uncond, cond_scale) |
| | |
| | skew, stretch, squash = base_skew, base_stretch, base_squash |
| | else: |
| | |
| | individual_settings = getattr(self.p, '_nrs_individual_step_settings', {}) |
| | |
| | skew_settings = individual_settings.get('skew', {}) |
| | skew = get_param_value_at_step( |
| | base_skew, current_step, total_steps, |
| | skew_settings.get('start_step', 0), |
| | skew_settings.get('end_step', total_steps), |
| | skew_settings.get('start_frac', 0.0), |
| | skew_settings.get('end_frac', 1.0), |
| | skew_settings.get('step_mode', 'Absolute Steps'), |
| | skew_settings.get('enabled', True) |
| | ) |
| | |
| | stretch_settings = individual_settings.get('stretch', {}) |
| | stretch = get_param_value_at_step( |
| | base_stretch, current_step, total_steps, |
| | stretch_settings.get('start_step', 0), |
| | stretch_settings.get('end_step', total_steps), |
| | stretch_settings.get('start_frac', 0.0), |
| | stretch_settings.get('end_frac', 1.0), |
| | stretch_settings.get('step_mode', 'Absolute Steps'), |
| | stretch_settings.get('enabled', True) |
| | ) |
| | |
| | squash_settings = individual_settings.get('squash', {}) |
| | squash = get_param_value_at_step( |
| | base_squash, current_step, total_steps, |
| | squash_settings.get('start_step', 0), |
| | squash_settings.get('end_step', total_steps), |
| | squash_settings.get('start_frac', 0.0), |
| | squash_settings.get('end_frac', 1.0), |
| | squash_settings.get('step_mode', 'Absolute Steps'), |
| | squash_settings.get('enabled', True) |
| | ) |
| | else: |
| | |
| | skew, stretch, squash = base_skew, base_stretch, base_squash |
| | |
| | |
| | denoised_uncond = x_out[-uncond.shape[0]:] |
| | denoised = torch.clone(denoised_uncond) |
| | |
| | x_orig_all = self.p._nrs_current_x_in |
| | x_orig_uncond = x_orig_all[-uncond.shape[0]:] |
| |
|
| | for i, conds in enumerate(conds_list): |
| | for idx, (cond_index, weight) in enumerate(conds): |
| | current_cond = x_out[cond_index] |
| | |
| | |
| | if idx == 0: |
| | current_x_orig = x_orig_uncond[i].unsqueeze(0) |
| | c_in = current_cond.unsqueeze(0) |
| | u_in = denoised_uncond[i].unsqueeze(0) |
| | |
| | nrs_result = calc_nrs( |
| | current_x_orig, c_in, u_in, |
| | self.p._nrs_current_sigma, |
| | skew, stretch, squash |
| | ) |
| | |
| | if len(conds) == 1: |
| | denoised[i] = nrs_result.squeeze(0) |
| | else: |
| | delta = nrs_result.squeeze(0) - denoised_uncond[i] |
| | denoised[i] += delta * weight |
| | else: |
| | denoised[i] += (current_cond - denoised_uncond[i]) * (weight * cond_scale) |
| |
|
| | return denoised |
| |
|
| | except Exception as e: |
| | print(f"!!! NRS Error (Fallback): {e}") |
| | return sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup(self, x_out, conds_list, uncond, cond_scale) |
| |
|
| |
|
| | |
| | |
| | |
| | class NRSScript(scripts.Script): |
| | def title(self): |
| | return "Negative Rejection Steering (Enhanced)" |
| |
|
| | def show(self, is_img2img): |
| | return scripts.AlwaysVisible |
| |
|
| | def ui(self, is_img2img): |
| | with gr.Accordion("Negative Rejection Steering", open=False): |
| | with gr.Row(): |
| | enabled = gr.Checkbox(label="Включить NRS (Enable)", value=False) |
| | |
| | |
| | with gr.Accordion("❓ Как этим пользоваться (Инструкция)", open=False): |
| | gr.Markdown(""" |
| | ### Что это такое? |
| | **NRS** — это замена стандартному CFG Scale. Вместо простого усиления промпта, он дает вам 3 рычага управления для более точного контроля. |
| | |
| | ### Параметры: |
| | * **Skew (Сдвиг/Руление):** *Влияет на:* **Композицию и Геометрию**. |
| | Отклоняет генерацию *прочь* от того, что указано в Negative prompt. Если картинка "ломается" или лезут лишние объекты — крутите это. |
| | * **Stretch (Растяжение):** *Влияет на:* **Цвета и Текстуры**. |
| | Усиливает элементы, которые совпадают с вашим Positive prompt. Работает как "газ" для ваших идей. |
| | * **Squash (Сплющивание):** *Влияет на:* **Детализацию и Контраст**. |
| | Ограничитель скорости. При `0.0` эффект максимальный (может "пережарить" картинку). Увеличение добавляет микро-деталей и смягчает цвета. |
| | |
| | ### 🚀 С чего начать (Советы от автора): |
| | 1. **Skew** ≈ Половина вашего обычного CFG (например, **3.0** - **4.0**). |
| | 2. **Stretch** ≈ Ваш обычный CFG (например, **6.0** - **7.0**). |
| | 3. **Squash** ≈ Оставьте **0.0** для начала. |
| | |
| | ### ⏱️ Step Control (Управление шагами): |
| | Позволяет применять NRS только на определенных шагах генерации. |
| | - **Global Mode**: Одинаковые настройки для всех трех параметров |
| | - **Individual Mode**: Отдельные настройки для каждого параметра (Skew, Stretch, Squash) |
| | """) |
| |
|
| | |
| | gr.HTML("<div style='margin-bottom: 0.5em; opacity: 0.8; font-size: 0.9em; border-bottom: 1px solid #444;'>Основные настройки</div>") |
| | |
| | with gr.Row(): |
| | skew = gr.Slider( |
| | label="Skew (Композиция)", |
| | minimum=-30.0, maximum=30.0, step=0.05, value=4.0, |
| | info="Сила отклонения от Negative prompt. Аналог 'силы' CFG для структуры." |
| | ) |
| | stretch = gr.Slider( |
| | label="Stretch (Цвета/Текстура)", |
| | minimum=-30.0, maximum=30.0, step=0.05, value=2.0, |
| | info="Сила притяжения к Positive prompt. Усиливает цвета и стиль." |
| | ) |
| | |
| | squash = gr.Slider( |
| | label="Squash (Защита от пережарки)", |
| | minimum=0.0, maximum=1.0, step=0.01, value=0.0, |
| | info="0.0 = Макс. эффект. 1.0 = Ослабление (больше деталей, меньше контраста)." |
| | ) |
| | |
| | |
| | with gr.Accordion("⏱️ Step Control (Управление шагами)", open=False): |
| | with gr.Row(): |
| | step_control_enabled = gr.Checkbox( |
| | label="Включить Step Control", |
| | value=False, |
| | info="Применять NRS только на определенных шагах" |
| | ) |
| | step_control_mode = gr.Radio( |
| | label="Режим управления", |
| | choices=["Global", "Individual"], |
| | value="Global", |
| | info="Global: общие настройки | Individual: настройки для каждого параметра" |
| | ) |
| | |
| | |
| | with gr.Group(visible=True) as global_group: |
| | gr.HTML("<div style='margin: 0.5em 0; font-weight: bold;'>Глобальные настройки (для всех параметров)</div>") |
| | |
| | global_step_mode = gr.Radio( |
| | label="Режим шагов", |
| | choices=["Absolute Steps", "Fraction of Steps"], |
| | value="Absolute Steps", |
| | info="Absolute: номера шагов | Fraction: доли от общего числа" |
| | ) |
| | |
| | with gr.Row(): |
| | global_start_step = gr.Slider( |
| | label="Start Step (абсолютный)", |
| | minimum=0, maximum=150, step=1, value=0, |
| | visible=True |
| | ) |
| | global_end_step = gr.Slider( |
| | label="End Step (абсолютный, 0=конец)", |
| | minimum=0, maximum=150, step=1, value=0, |
| | visible=True |
| | ) |
| | |
| | with gr.Row(): |
| | global_start_frac = gr.Slider( |
| | label="Start (доля от общего числа)", |
| | minimum=0.0, maximum=1.0, step=0.01, value=0.0, |
| | visible=False |
| | ) |
| | global_end_frac = gr.Slider( |
| | label="End (доля от общего числа)", |
| | minimum=0.0, maximum=1.0, step=0.01, value=1.0, |
| | visible=False |
| | ) |
| | |
| | |
| | with gr.Group(visible=False) as individual_group: |
| | gr.HTML("<div style='margin: 0.5em 0; font-weight: bold;'>Индивидуальные настройки</div>") |
| | |
| | |
| | with gr.Accordion("Skew (Композиция) - Step Settings", open=False): |
| | skew_step_enabled = gr.Checkbox(label="Включить управление шагами для Skew", value=True) |
| | skew_step_mode = gr.Radio( |
| | label="Режим", |
| | choices=["Absolute Steps", "Fraction of Steps"], |
| | value="Absolute Steps" |
| | ) |
| | with gr.Row(): |
| | skew_start_step = gr.Slider(label="Start Step", minimum=0, maximum=150, step=1, value=0, visible=True) |
| | skew_end_step = gr.Slider(label="End Step (0=конец)", minimum=0, maximum=150, step=1, value=0, visible=True) |
| | with gr.Row(): |
| | skew_start_frac = gr.Slider(label="Start (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=0.0, visible=False) |
| | skew_end_frac = gr.Slider(label="End (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=1.0, visible=False) |
| | |
| | |
| | with gr.Accordion("Stretch (Цвета/Текстура) - Step Settings", open=False): |
| | stretch_step_enabled = gr.Checkbox(label="Включить управление шагами для Stretch", value=True) |
| | stretch_step_mode = gr.Radio( |
| | label="Режим", |
| | choices=["Absolute Steps", "Fraction of Steps"], |
| | value="Absolute Steps" |
| | ) |
| | with gr.Row(): |
| | stretch_start_step = gr.Slider(label="Start Step", minimum=0, maximum=150, step=1, value=0, visible=True) |
| | stretch_end_step = gr.Slider(label="End Step (0=конец)", minimum=0, maximum=150, step=1, value=0, visible=True) |
| | with gr.Row(): |
| | stretch_start_frac = gr.Slider(label="Start (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=0.0, visible=False) |
| | stretch_end_frac = gr.Slider(label="End (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=1.0, visible=False) |
| | |
| | |
| | with gr.Accordion("Squash (Защита от пережарки) - Step Settings", open=False): |
| | squash_step_enabled = gr.Checkbox(label="Включить управление шагами для Squash", value=True) |
| | squash_step_mode = gr.Radio( |
| | label="Режим", |
| | choices=["Absolute Steps", "Fraction of Steps"], |
| | value="Absolute Steps" |
| | ) |
| | with gr.Row(): |
| | squash_start_step = gr.Slider(label="Start Step", minimum=0, maximum=150, step=1, value=0, visible=True) |
| | squash_end_step = gr.Slider(label="End Step (0=конец)", minimum=0, maximum=150, step=1, value=0, visible=True) |
| | with gr.Row(): |
| | squash_start_frac = gr.Slider(label="Start (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=0.0, visible=False) |
| | squash_end_frac = gr.Slider(label="End (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=1.0, visible=False) |
| | |
| | |
| | def update_mode_visibility(mode): |
| | return { |
| | global_group: gr.update(visible=(mode == "Global")), |
| | individual_group: gr.update(visible=(mode == "Individual")) |
| | } |
| | |
| | step_control_mode.change( |
| | fn=update_mode_visibility, |
| | inputs=[step_control_mode], |
| | outputs=[global_group, individual_group] |
| | ) |
| | |
| | |
| | def update_global_step_inputs(mode): |
| | is_absolute = (mode == "Absolute Steps") |
| | return { |
| | global_start_step: gr.update(visible=is_absolute), |
| | global_end_step: gr.update(visible=is_absolute), |
| | global_start_frac: gr.update(visible=not is_absolute), |
| | global_end_frac: gr.update(visible=not is_absolute) |
| | } |
| | |
| | global_step_mode.change( |
| | fn=update_global_step_inputs, |
| | inputs=[global_step_mode], |
| | outputs=[global_start_step, global_end_step, global_start_frac, global_end_frac] |
| | ) |
| | |
| | |
| | def update_skew_step_inputs(mode): |
| | is_absolute = (mode == "Absolute Steps") |
| | return { |
| | skew_start_step: gr.update(visible=is_absolute), |
| | skew_end_step: gr.update(visible=is_absolute), |
| | skew_start_frac: gr.update(visible=not is_absolute), |
| | skew_end_frac: gr.update(visible=not is_absolute) |
| | } |
| | |
| | skew_step_mode.change( |
| | fn=update_skew_step_inputs, |
| | inputs=[skew_step_mode], |
| | outputs=[skew_start_step, skew_end_step, skew_start_frac, skew_end_frac] |
| | ) |
| | |
| | |
| | def update_stretch_step_inputs(mode): |
| | is_absolute = (mode == "Absolute Steps") |
| | return { |
| | stretch_start_step: gr.update(visible=is_absolute), |
| | stretch_end_step: gr.update(visible=is_absolute), |
| | stretch_start_frac: gr.update(visible=not is_absolute), |
| | stretch_end_frac: gr.update(visible=not is_absolute) |
| | } |
| | |
| | stretch_step_mode.change( |
| | fn=update_stretch_step_inputs, |
| | inputs=[stretch_step_mode], |
| | outputs=[stretch_start_step, stretch_end_step, stretch_start_frac, stretch_end_frac] |
| | ) |
| | |
| | |
| | def update_squash_step_inputs(mode): |
| | is_absolute = (mode == "Absolute Steps") |
| | return { |
| | squash_start_step: gr.update(visible=is_absolute), |
| | squash_end_step: gr.update(visible=is_absolute), |
| | squash_start_frac: gr.update(visible=not is_absolute), |
| | squash_end_frac: gr.update(visible=not is_absolute) |
| | } |
| | |
| | squash_step_mode.change( |
| | fn=update_squash_step_inputs, |
| | inputs=[squash_step_mode], |
| | outputs=[squash_start_step, squash_end_step, squash_start_frac, squash_end_frac] |
| | ) |
| | |
| | return [ |
| | enabled, skew, stretch, squash, |
| | step_control_enabled, step_control_mode, |
| | |
| | global_step_mode, global_start_step, global_end_step, global_start_frac, global_end_frac, |
| | |
| | skew_step_enabled, skew_step_mode, skew_start_step, skew_end_step, skew_start_frac, skew_end_frac, |
| | |
| | stretch_step_enabled, stretch_step_mode, stretch_start_step, stretch_end_step, stretch_start_frac, stretch_end_frac, |
| | |
| | squash_step_enabled, squash_step_mode, squash_start_step, squash_end_step, squash_start_frac, squash_end_frac |
| | ] |
| |
|
| | def process(self, p, enabled, skew, stretch, squash, |
| | step_control_enabled, step_control_mode, |
| | global_step_mode, global_start_step, global_end_step, global_start_frac, global_end_frac, |
| | skew_step_enabled, skew_step_mode, skew_start_step, skew_end_step, skew_start_frac, skew_end_frac, |
| | stretch_step_enabled, stretch_step_mode, stretch_start_step, stretch_end_step, stretch_start_frac, stretch_end_frac, |
| | squash_step_enabled, squash_step_mode, squash_start_step, squash_end_step, squash_start_frac, squash_end_frac): |
| | |
| | p._nrs_enabled = enabled |
| | p._nrs_params = (skew, stretch, squash) |
| | p._nrs_step_control_enabled = step_control_enabled |
| | p._nrs_step_control_mode = step_control_mode |
| | |
| | |
| | p._nrs_global_step_settings = { |
| | 'step_mode': global_step_mode, |
| | 'start_step': global_start_step, |
| | 'end_step': global_end_step, |
| | 'start_frac': global_start_frac, |
| | 'end_frac': global_end_frac |
| | } |
| | |
| | |
| | p._nrs_individual_step_settings = { |
| | 'skew': { |
| | 'enabled': skew_step_enabled, |
| | 'step_mode': skew_step_mode, |
| | 'start_step': skew_start_step, |
| | 'end_step': skew_end_step, |
| | 'start_frac': skew_start_frac, |
| | 'end_frac': skew_end_frac |
| | }, |
| | 'stretch': { |
| | 'enabled': stretch_step_enabled, |
| | 'step_mode': stretch_step_mode, |
| | 'start_step': stretch_start_step, |
| | 'end_step': stretch_end_step, |
| | 'start_frac': stretch_start_frac, |
| | 'end_frac': stretch_end_frac |
| | }, |
| | 'squash': { |
| | 'enabled': squash_step_enabled, |
| | 'step_mode': squash_step_mode, |
| | 'start_step': squash_start_step, |
| | 'end_step': squash_end_step, |
| | 'start_frac': squash_start_frac, |
| | 'end_frac': squash_end_frac |
| | } |
| | } |
| | |
| | if enabled: |
| | sd_samplers_cfg_denoiser.CFGDenoiser.combine_denoised = hijacked_combine_denoised |
| | |
| | |
| | p._nrs_current_step = 0 |
| |
|
| | def postprocess(self, p, processed, *args): |
| | pass |