Revert i2v anchor (DynamicConditioning): no-op on packed AV, not worth keeping
DynamicConditioning is an unpacked-video technique; on LTXAV (packed AV latent, 3D mask) it can only no-op (comfy's process_timestep patchifies expecting 5D). Rather than keep dead knobs in the Chain Sampler UI, remove i2v_anchor_power / i2v_anchor_first_frame_only, the install block, and _install_i2v_anchor entirely. The packed-safe path for cross-cut appearance carry (strengthen the Chain Sampler's own carry/guide masks pre-pack) remains available as a future native feature. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
04d00fcecd
commit
cf3f0b64a5
-83
@@ -2070,14 +2070,6 @@ class FunPackLTXAVSceneChainSampler:
|
||||
"default": 0.05, "min": 0.0, "max": 1.0, "step": 0.001,
|
||||
"tooltip": "Decode timestep fed to the VAE decoder when decode_noise_scale > 0. ~0.05 adds subtle detail; higher gives the decoder more freedom (more deviation from the latent).",
|
||||
}),
|
||||
"i2v_anchor_power": ("FLOAT", {
|
||||
"default": 1.0, "min": 1.0, "max": 2.0, "step": 0.01,
|
||||
"tooltip": "Progressively strengthen i2v adherence to the conditioning frame as denoising proceeds (port of LTXV DynamicConditioning): the denoise mask is raised to power**step. 1.0 = off. NOTE: only works on UNPACKED 5D video masks; on PACKED audio+video (LTXAV) it safely no-ops (the mask is 3D and comfy's per-token-timestep patchify needs 5D). ~zero overhead.",
|
||||
}),
|
||||
"i2v_anchor_first_frame_only": ("BOOLEAN", {
|
||||
"default": True,
|
||||
"tooltip": "When i2v_anchor_power > 1.0: apply the ramp only to the first (conditioning) frame, leaving the rest free. Off ramps the whole mask.",
|
||||
}),
|
||||
"embed_guidance_source": (["relative", "absolute"], {
|
||||
"default": "relative",
|
||||
"tooltip": "Which learned direction embed_guidance steers toward. Relative: this prompt's liked direction (needs refinement_key_input). Absolute: the global, prompt-agnostic taste direction the Refiner accumulates across all prompts — works with no key.",
|
||||
@@ -2785,75 +2777,6 @@ class FunPackLTXAVSceneChainSampler:
|
||||
result.seed = seed
|
||||
return result
|
||||
|
||||
def _install_i2v_anchor(self, model, power, first_frame_only):
|
||||
"""Port of LTXV DynamicConditioning: progressively strengthen i2v adherence to the
|
||||
conditioning frame as denoising proceeds, by raising the denoise mask to power**step.
|
||||
Uses the stock comfy ModelPatcher API (set_model_denoise_mask_function) — no modified
|
||||
model, no extra forward pass. Fully defensive: any missing mask / unexpected shape / error
|
||||
falls through to the unmodified mask, so it's a safe no-op when it can't apply."""
|
||||
p = float(power)
|
||||
|
||||
def _find_step(sigma, step_sigmas):
|
||||
try:
|
||||
for idx, s in enumerate(step_sigmas):
|
||||
if s <= sigma:
|
||||
return idx
|
||||
return len(step_sigmas) - 1
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
def _denoise_mask_fn(sigma, denoise_mask, extra_options):
|
||||
try:
|
||||
step_sigmas = extra_options.get("sigmas")
|
||||
inner = extra_options.get("model")
|
||||
if denoise_mask is None or step_sigmas is None or inner is None:
|
||||
return denoise_mask
|
||||
exp = p ** _find_step(sigma, step_sigmas)
|
||||
if abs(exp - 1.0) < 1e-6:
|
||||
return denoise_mask
|
||||
# This technique (LTXV DynamicConditioning) assumes an UNPACKED 5D video mask
|
||||
# [B,C,F,H,W]: comfy's LTXAV process_timestep patchifies the mask expecting 5D.
|
||||
# LTXAV PACKS the AV latent, so its denoise mask is 3D [B,C,N] — touching or
|
||||
# propagating that crashes patchify (expected 5, got 3). So operate ONLY on genuine
|
||||
# 5D masks; on packed AV (or anything else) this is a clean no-op.
|
||||
if denoise_mask.dim() != 5:
|
||||
if not getattr(self, "_i2v_anchor_packed_warned", False):
|
||||
self._i2v_anchor_packed_warned = True
|
||||
print("[FunPackSceneChain] i2v anchor: packed/non-5D denoise mask "
|
||||
f"(ndim={denoise_mask.dim()}) -> no-op (technique needs unpacked video).")
|
||||
return denoise_mask
|
||||
mask = denoise_mask.clone()
|
||||
if first_frame_only:
|
||||
try:
|
||||
num_channels = inner.model_patcher.model.diffusion_model.in_channels
|
||||
except Exception:
|
||||
num_channels = mask.shape[1]
|
||||
mask[:, :num_channels, :1] = mask[:, :num_channels, :1] ** exp
|
||||
else:
|
||||
mask = mask ** exp
|
||||
# Propagate to the conds so per-token timestep values stay consistent.
|
||||
try:
|
||||
for ck in inner.conds:
|
||||
if "positive" in ck or "negative" in ck:
|
||||
for cond in inner.conds[ck]:
|
||||
mc = cond.get("model_conds") if isinstance(cond, dict) else None
|
||||
if mc and "denoise_mask" in mc:
|
||||
mc["denoise_mask"].cond = mask
|
||||
except Exception:
|
||||
pass
|
||||
return mask
|
||||
except Exception:
|
||||
return denoise_mask
|
||||
|
||||
try:
|
||||
patched = model.clone()
|
||||
patched.set_model_denoise_mask_function(_denoise_mask_fn)
|
||||
print(f"[FunPackSceneChain] i2v anchor ramp on (power={p}, first_frame_only={first_frame_only})")
|
||||
return patched
|
||||
except Exception as e:
|
||||
print(f"[FunPackSceneChain] i2v anchor install failed ({e}); continuing without it.")
|
||||
return model
|
||||
|
||||
def sample(self, model, vae, positive, negative, sampler, sigmas, seed, latent_template,
|
||||
num_frames_per_scene, frame_overlap, cfg, max_scenes, use_same_seed=False,
|
||||
carry_i2v_guides=False,
|
||||
@@ -2862,7 +2785,6 @@ class FunPackLTXAVSceneChainSampler:
|
||||
embed_guidance_source="relative",
|
||||
transition_duration=16, decode_tile_size=0,
|
||||
decode_noise_scale=0.0, decode_timestep=0.05,
|
||||
i2v_anchor_power=1.0, i2v_anchor_first_frame_only=True,
|
||||
refinement_key_input="", unique_id=None, prompt=None):
|
||||
if not isinstance(positive, list) or not positive:
|
||||
raise ValueError("positive conditioning must contain at least one scene entry.")
|
||||
@@ -2875,11 +2797,6 @@ class FunPackLTXAVSceneChainSampler:
|
||||
if decode_noise_scale and decode_noise_scale > 0:
|
||||
vae = self._vae_with_decode_noise(vae, decode_timestep, decode_noise_scale, seed)
|
||||
|
||||
# i2v anchor ramp (LTXV DynamicConditioning): patch the model BEFORE the batch/main split
|
||||
# so both paths inherit it. power<=1.0 = off.
|
||||
if i2v_anchor_power and i2v_anchor_power > 1.0:
|
||||
model = self._install_i2v_anchor(model, i2v_anchor_power, bool(i2v_anchor_first_frame_only))
|
||||
|
||||
# Batch Training: Studio (the hub) packs N conditionings into positive, each scene entry
|
||||
# tagged 'funpack_batch_variant'. That marker is the only trigger — the sampler has no
|
||||
# batch-count input. Sample one chain per packed entry, persist each for rating in Studio.
|
||||
|
||||
Reference in New Issue
Block a user