distilled flow: port quality_sharpness unsharp mask from Hybrid Euler 2S
The free video-only unsharp-on-x0 sharpening (temporal high-pass between consecutive denoised predictions, no extra model eval) only existed on Hybrid Euler 2S. Distilled Flow — the recommended sampler for this pipeline (deterministic, clean audio) — had no equivalent, so the "quality phase" of the actual production sampler had no sharpening path at all. Ports the same _apply_quality_sharpness call into sample_funpack_distilled_flow, gated to the existing final-correction (Heun) steps. Threaded through FunPackDistilledFlowSampler's INPUT_TYPES/get_sampler, Studio's _build_one_sampler, and the Editor's sampler_panel.js Distilled Flow section — verified live end-to-end (UI -> studio_settings JSON -> backend build call).
This commit is contained in:
@@ -14674,6 +14674,7 @@ class FunPackStudio:
|
||||
mg_strength=float(dc.get("mg_strength", 0.5)),
|
||||
mg_decay=float(dc.get("mg_decay", 0.5)),
|
||||
mg_sigma_threshold=float(dc.get("mg_sigma_threshold", 0.975)),
|
||||
quality_sharpness=float(dc.get("quality_sharpness", 0.0)),
|
||||
sigmas=sigmas_raw,
|
||||
)
|
||||
elif sampler_type == "KSampler":
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
function defaultDistilled() {
|
||||
return {
|
||||
order: 2, final_correction_steps: 1, ab2_ramp: false,
|
||||
order: 2, final_correction_steps: 1, ab2_ramp: false, quality_sharpness: 0.0,
|
||||
normalize_strength: 0.0, normalize_start_sigma: 0.9, s_noise: 0.0,
|
||||
velocity_bias_mode: "off", velocity_bias_strength: 0.0,
|
||||
velocity_bias_source: "mean", velocity_refinement_key: "default",
|
||||
@@ -251,6 +251,10 @@
|
||||
row(container, "final correction steps",
|
||||
intCtrl(dc.final_correction_steps, 0, 3, dk + "-dfcs",
|
||||
(v) => { dc.final_correction_steps = v; save(); }));
|
||||
row(container, "quality sharpness",
|
||||
numCtrl(dc.quality_sharpness, 0, 1, 0.01, dk + "-dqs",
|
||||
(v) => { dc.quality_sharpness = v; save(); }));
|
||||
hint(container, "Free unsharp mask on the final-correction steps only (needs final correction steps > 0). 0 = off, 0.2-0.4 typical.");
|
||||
row(container, "s_noise",
|
||||
numCtrl(dc.s_noise, 0, 0.5, 0.01, dk + "-dsn",
|
||||
(v) => { dc.s_noise = v; save(); }));
|
||||
|
||||
+18
-2
@@ -1695,7 +1695,8 @@ def sample_funpack_distilled_flow(model, x, sigmas, extra_args=None, callback=No
|
||||
rescue_prompt_sig=None,
|
||||
alg_enabled=False, alg_strength=2.0, alg_sigma_threshold=0.975,
|
||||
alg_guide_tail_frames=0,
|
||||
mg_enabled=False, mg_strength=0.5, mg_decay=0.5, mg_sigma_threshold=0.975):
|
||||
mg_enabled=False, mg_strength=0.5, mg_decay=0.5, mg_sigma_threshold=0.975,
|
||||
quality_sharpness=0.0):
|
||||
"""
|
||||
ODE sampler for distilled few-step video models (e.g. LTX2.3 distilled LoRA).
|
||||
|
||||
@@ -1729,6 +1730,9 @@ def sample_funpack_distilled_flow(model, x, sigmas, extra_args=None, callback=No
|
||||
the complementary window to ALG's blur, which only acts above its threshold. The EMA
|
||||
itself accumulates every step (free) so it has real history by the time it starts
|
||||
being applied; only the application is gated. Audio is never touched (video-only).
|
||||
- Optional quality_sharpness: temporal-average unsharp on the x0 prediction, applied only
|
||||
during the final Heun-correction steps (same mechanism as the Hybrid Euler 2S sampler's
|
||||
quality-phase sharpening, ported here). Free (no extra model eval), video-only.
|
||||
"""
|
||||
extra_args = {} if extra_args is None else extra_args
|
||||
seed = extra_args.get("seed", None)
|
||||
@@ -1837,6 +1841,11 @@ def sample_funpack_distilled_flow(model, x, sigmas, extra_args=None, callback=No
|
||||
source=velocity_bias_source,
|
||||
), denoised, video_mask)
|
||||
|
||||
# Restore high-frequency detail during the final Heun-correction steps (free,
|
||||
# video-only) — same unsharp mechanism as the Hybrid Euler 2S sampler.
|
||||
if i >= correction_start_idx:
|
||||
denoised = _video_only(_apply_quality_sharpness(denoised, prev_denoised, quality_sharpness), denoised, video_mask)
|
||||
|
||||
# Video-only latent normalization (opt-in, anti-overbake) — stacks on top of the ODE.
|
||||
denoised = _normalize_video_denoised(
|
||||
denoised, video_mask, sigma, ref_scale, normalize_strength, normalize_start_sigma,
|
||||
@@ -2013,6 +2022,11 @@ class FunPackDistilledFlowSampler:
|
||||
"default": 0.975, "min": 0.5, "max": 0.999, "step": 0.005,
|
||||
"tooltip": "Momentum guidance applies while sigma is BELOW this value (the opposite window from alg_sigma_threshold) — defaults to the same boundary as ALG for a clean handoff. Only used when mg_enabled.",
|
||||
}),
|
||||
# Appended last on purpose, same rule as ab2_ramp above.
|
||||
"quality_sharpness": ("FLOAT", {
|
||||
"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01,
|
||||
"tooltip": "Restores fine detail via temporal-average unsharp on the x0 prediction, applied only during the final Heun-correction steps (final_correction_steps > 0 required to have any effect). 0 disables. 0.2-0.4 typical. Free (no extra model eval), video-only.",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2036,7 +2050,8 @@ class FunPackDistilledFlowSampler:
|
||||
rescue_prompt_sig=None, sigmas=None, ab2_ramp=False,
|
||||
normalize_strength=0.0, normalize_start_sigma=0.9,
|
||||
alg_enabled=False, alg_strength=2.0, alg_sigma_threshold=0.975,
|
||||
mg_enabled=False, mg_strength=0.5, mg_decay=0.5, mg_sigma_threshold=0.975):
|
||||
mg_enabled=False, mg_strength=0.5, mg_decay=0.5, mg_sigma_threshold=0.975,
|
||||
quality_sharpness=0.0):
|
||||
prepared_sigmas = sigmas.detach().clone() if isinstance(sigmas, torch.Tensor) else sigmas
|
||||
sampler = comfy.samplers.KSAMPLER(
|
||||
sample_funpack_distilled_flow,
|
||||
@@ -2062,6 +2077,7 @@ class FunPackDistilledFlowSampler:
|
||||
"mg_strength": mg_strength,
|
||||
"mg_decay": mg_decay,
|
||||
"mg_sigma_threshold": mg_sigma_threshold,
|
||||
"quality_sharpness": quality_sharpness,
|
||||
}
|
||||
)
|
||||
return (sampler, prepared_sigmas)
|
||||
|
||||
Reference in New Issue
Block a user