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:
digital-garbage
2026-07-01 17:02:13 +03:00
parent bcbc3670d5
commit 293dbd11d5
3 changed files with 24 additions and 3 deletions
+1
View File
@@ -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":
+5 -1
View File
@@ -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
View File
@@ -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)