fix: decisiveness declares a schedule it cannot act on and stops learning there; new features' logs colour by state
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
81d8a9b094
commit
aa352de959
@@ -28,6 +28,8 @@
|
||||
guidance no longer edit the last step.** On few-step schedules the last step is the video,
|
||||
and edits there showed as grain. Each edit now goes into the next step's input.
|
||||
|
||||
- Decisiveness says when a schedule leaves it too little to act on (simple at 4 steps) and then
|
||||
does not learn from that run's rating. New features' log lines now colour by state.
|
||||
- The harmless `set_mempolicy: Operation not permitted` line from ffmpeg is hidden (said once).
|
||||
|
||||
## [4.0.0] "Blinding Blackout" - 2026-08-27
|
||||
|
||||
@@ -231,9 +231,9 @@ _ERROR = _re.compile(r"\b(fail(s|ed|ing|ures?)?|\w*errors?|\w*exceptions?|traceb
|
||||
r"refused|out of memory|nan|critical|fatal)\b", _re.I)
|
||||
_WARN = _re.compile(r"\b(warn(s|ing|ings)?|skip(s|ped|ping)?|inactive|disabled|not ready|could not|"
|
||||
r"cannot|can't|missing|ignor(ed|ing)|fallback|falling back|stripped|leaked|"
|
||||
r"deprecated|no module named)\b", _re.I)
|
||||
r"deprecated|no module named|inert|barely|nothing (will )?steer(ed)?)\b", _re.I)
|
||||
_OK = _re.compile(r"\b(active|done|saved|recorded|updated|loaded|finished|completed?|success(ful|fully)?|"
|
||||
r"succeeded|prompt executed|installed|applied)\b", _re.I)
|
||||
r"succeeded|prompt executed|installed|applied|upscaled)\b", _re.I)
|
||||
# White (info) is the terminal's own colour, so it gets no code.
|
||||
_TERM = {"error": "\x1b[91m", "warn": "\x1b[38;5;208m", "ok": "\x1b[92m"}
|
||||
|
||||
|
||||
@@ -266,3 +266,38 @@ def test_a_traceback_is_red_through_its_closing_line():
|
||||
lines = ["[FunPack][movie] x failed:", "Traceback (most recent call last):",
|
||||
' File "a.py", line 1, in f', "KeyboardInterrupt", "next unrelated line"]
|
||||
assert bridge.log_levels(lines) == ["error", "error", "error", "error", "info"]
|
||||
|
||||
|
||||
def test_the_new_features_lines_carry_their_state_colour():
|
||||
"""Green = it is acting, orange = it cannot or barely does, red = it failed."""
|
||||
P = "[FunPackSceneChain] "
|
||||
green = (
|
||||
"STAS: Active | alpha 2.00 at block 15: steered 12 call(s), channels 3 and 41",
|
||||
"STAS: Active | alpha learned 2.00 from 4 rating(s), trying 2.10",
|
||||
"late-branch guidance: Active | strength 0.50, a copy with block 43 left out, sharing "
|
||||
"blocks 0-42 (~14% extra per step, none on the last), edits the picture (the sound can react).",
|
||||
"late-branch guidance: Active | guided 3 step call(s)",
|
||||
"decisiveness: Active | learned k 1.020 from 7 rating(s), trying 1.050, push up to 9% of a step's noise",
|
||||
"shot memory: Active | reusing a liked shot of 5 (reuse 0.71 > fresh 0.40), amount 0.70",
|
||||
"shot memory: Active | fresh (reuse 0.30 < fresh 0.55)",
|
||||
"steering window: Active | 1 of 4 steps (peak gate 0.50)",
|
||||
"[FunPack] upscaled a.mp4 with 4x.safetensors: 96 frames -> funpack_upscaled/a_4x.mp4",
|
||||
)
|
||||
orange = (
|
||||
"STAS: Inactive | no channel at block 15 is over 50x the mean, nothing steered -- try another block",
|
||||
"STAS: Inactive | H3 only",
|
||||
"late-branch guidance: Inactive | no step call reached it, nothing guided",
|
||||
"late-branch guidance: Inactive | did not apply this run, so this run's rating will not teach its learned strength",
|
||||
"decisiveness: barely acts on this schedule (its push is at most 1.9% of a step's noise, the "
|
||||
"last step is never edited), so this run's rating will not teach k | learned k 0.900",
|
||||
"decisiveness: Inactive | a 1-step schedule has no step before the output to carry an edit into",
|
||||
"shot memory: Inactive | left 1 sampling pass(es) alone, their latent already held a picture",
|
||||
"steering window: Inactive | nothing will steer on this schedule, every rating-driven mechanism is gated off",
|
||||
)
|
||||
for line in green:
|
||||
text = line if line.startswith("[") else P + line
|
||||
assert bridge.log_level(text) == "ok", text
|
||||
for line in orange:
|
||||
text = line if line.startswith("[") else P + line
|
||||
assert bridge.log_level(text) == "warn", text
|
||||
assert bridge.log_level(P + "decisiveness failed (boom), passing through") == "error"
|
||||
|
||||
+38
-24
@@ -941,8 +941,8 @@ class _InputSteer:
|
||||
where = self._where(args)
|
||||
if where is not None and where[1] <= 1:
|
||||
_log.note_once("FunPackSceneChain",
|
||||
f"{self.what}: a 1-step schedule has no step before the output "
|
||||
f"to carry an edit into, so it does nothing this run",
|
||||
f"{self.what}: Inactive | a 1-step schedule has no step before the "
|
||||
f"output to carry an edit into, so it does nothing this run",
|
||||
key=f"input steer 1 step:{self.what}")
|
||||
return where is not None and where[0] >= where[1] - 1
|
||||
|
||||
@@ -4297,12 +4297,12 @@ class FunPackLTXAVSceneChainSampler:
|
||||
if _stas_report is not None:
|
||||
_line, _n = _stas_report()
|
||||
self._stas_ran = getattr(self, "_stas_ran", 0) + _n
|
||||
print(f"[FunPackSceneChain] STAS: {_line}")
|
||||
print(f"[FunPackSceneChain] STAS: {'Active' if _n else 'Inactive'} | {_line}")
|
||||
if _late_stats is not None:
|
||||
self._late_ran = getattr(self, "_late_ran", 0) + _late_stats["guided"]
|
||||
print("[FunPackSceneChain] late-branch guidance: " + (
|
||||
f"guided {_late_stats['guided']} step call(s)" if _late_stats["guided"]
|
||||
else (_late_stats["why"] or "no step call reached it, nothing guided")))
|
||||
f"Active | guided {_late_stats['guided']} step call(s)" if _late_stats["guided"]
|
||||
else "Inactive | " + (_late_stats["why"] or "no step call reached it, nothing guided")))
|
||||
if _phrase_probe is not None:
|
||||
self._report_phrase_probe(_phrase_probe[1])
|
||||
# The masked probe passes ran through every capture hook too, so this
|
||||
@@ -8688,7 +8688,7 @@ class FunPackLTXAVSceneChainSampler:
|
||||
return (stats["why"] or f"no channel at block {block} is over "
|
||||
f"{_stas.MA_RATIO:.0f}x the mean, nothing steered -- try another block"), 0
|
||||
|
||||
print(f"[FunPackSceneChain] STAS: alpha {_alpha:.2f} at block {block}, first "
|
||||
print(f"[FunPackSceneChain] STAS: Active | alpha {_alpha:.2f} at block {block}, first "
|
||||
f"{_stas.EARLY_FRACTION:.0%} of steps, frame 0 + frame edges, picture rows (the sound can react).")
|
||||
return patched, _report
|
||||
except Exception as _e: # noqa: BLE001
|
||||
@@ -8808,8 +8808,8 @@ class FunPackLTXAVSceneChainSampler:
|
||||
|
||||
patched.model_options["model_function_wrapper"] = _tag_scene_wrapper(
|
||||
_late_wrapper, old_wrapper)
|
||||
print(f"[FunPackSceneChain] late-branch guidance: strength {_w:.2f}, weak copy "
|
||||
f"skips block {branch} and shares 0-{branch - 1} "
|
||||
print(f"[FunPackSceneChain] late-branch guidance: Active | strength {_w:.2f}, "
|
||||
f"a copy with block {branch} left out, sharing blocks 0-{branch - 1} "
|
||||
f"(~{100.0 * (len(dit) - branch) / len(dit):.0f}% extra per step, none on the last), "
|
||||
f"edits the picture (the sound can react).")
|
||||
return patched, stats
|
||||
@@ -9736,36 +9736,49 @@ class FunPackLTXAVSceneChainSampler:
|
||||
self._late_w, self._late_block = 0.0, int(late_guidance_block)
|
||||
self._stas_alpha, self._stas_block = None, int(stas_block)
|
||||
self._late_ran, self._stas_ran = 0, 0 # calls the features actually changed
|
||||
self._tsr_acts = True # False: too weak on this schedule to be rated
|
||||
if (shot_memory != "off" or tsr == "learned" or late_guidance == "learned"
|
||||
or stas == "learned"):
|
||||
if not refinement_key_input:
|
||||
print("[FunPackSceneChain] shot memory / learned decisiveness / learned "
|
||||
"late-branch guidance / learned STAS: needs refinement_key_input -- "
|
||||
"off this run")
|
||||
"late-branch guidance / learned STAS: Inactive | needs refinement_key_input")
|
||||
if shot_memory != "off" and refinement_key_input:
|
||||
self._shot_memory = _shot_memory.ShotMemory(
|
||||
refinement_key_input, shot_memory, shot_memory_amount)
|
||||
if tsr != "off":
|
||||
self._tsr_k, _tsr_note = _tsr.choose_k(refinement_key_input, tsr, tsr_k)
|
||||
if _tsr_note:
|
||||
print(f"[FunPackSceneChain] decisiveness: {_tsr_note}")
|
||||
_reach = None
|
||||
if self._is_h3 and self._tsr_k != 1.0:
|
||||
try:
|
||||
_reach = _tsr.reach(sigmas.flatten().tolist(), self._tsr_k)
|
||||
except Exception: # noqa: BLE001
|
||||
_reach = None
|
||||
if _reach is not None and _reach < _tsr.INERT_SHARE:
|
||||
self._tsr_acts = False
|
||||
print(f"[FunPackSceneChain] decisiveness: barely acts on this schedule (its "
|
||||
f"push is at most {_reach:.1%} of a step's noise, the last step is never "
|
||||
f"edited), so this run's rating will not teach k | {_tsr_note}")
|
||||
else:
|
||||
print(f"[FunPackSceneChain] decisiveness: Active | {_tsr_note}"
|
||||
+ (f", push up to {_reach:.0%} of a step's noise" if _reach is not None else ""))
|
||||
if late_guidance != "off":
|
||||
if not self._is_h3:
|
||||
print("[FunPackSceneChain] late-branch guidance: H3 only -- off this run")
|
||||
print("[FunPackSceneChain] late-branch guidance: Inactive | H3 only")
|
||||
else:
|
||||
_w, _late_note = _late.DIAL.choose(
|
||||
refinement_key_input, late_guidance, late_guidance_strength)
|
||||
self._late_w = max(0.0, _w or 0.0)
|
||||
if _late_note:
|
||||
print(f"[FunPackSceneChain] late-branch guidance: {_late_note}")
|
||||
print(f"[FunPackSceneChain] late-branch guidance: Active | {_late_note}")
|
||||
if stas != "off":
|
||||
if not self._is_h3:
|
||||
print("[FunPackSceneChain] STAS: H3 only -- off this run")
|
||||
print("[FunPackSceneChain] STAS: Inactive | H3 only")
|
||||
else:
|
||||
self._stas_alpha, _stas_note = _stas.DIAL.choose(
|
||||
refinement_key_input, stas, stas_alpha)
|
||||
if _stas_note:
|
||||
print(f"[FunPackSceneChain] STAS alpha: {_stas_note}")
|
||||
print(f"[FunPackSceneChain] STAS: Active | alpha {_stas_note}")
|
||||
|
||||
# Per-bucket value functions for trajectory_guidance. Separate from the one above
|
||||
# because they answer a different question: that one asks "is this a good finish",
|
||||
@@ -9808,13 +9821,13 @@ class FunPackLTXAVSceneChainSampler:
|
||||
_cov = _steer_ramp_coverage(_steer_ramp, sigmas)
|
||||
if _cov is not None:
|
||||
_gated, _total, _peak = _cov
|
||||
print(f"[FunPackSceneChain] steering window: {_gated} of {_total} steps "
|
||||
f"(peak gate {_peak:.2f})"
|
||||
print(f"[FunPackSceneChain] steering window: {'Active' if _gated else 'Inactive'} | "
|
||||
f"{_gated} of {_total} steps (peak gate {_peak:.2f})"
|
||||
+ (" — read off the schedule's base grid; each edit goes into the next "
|
||||
"step's input, the last step is the model's own" if self._is_h3 else ""))
|
||||
if _gated == 0:
|
||||
print("[FunPackSceneChain] steering window: NOTHING will steer on this "
|
||||
"schedule — every rating-driven mechanism is gated off")
|
||||
print("[FunPackSceneChain] steering window: Inactive | nothing will steer on "
|
||||
"this schedule, every rating-driven mechanism is gated off")
|
||||
|
||||
# Trajectory probe (FUNPACK_TRAJECTORY_PROBE=1): record the predicted x0 per
|
||||
# schedule bucket so a later analysis can say whether ratings separate EARLY, in the
|
||||
@@ -11008,16 +11021,17 @@ class FunPackLTXAVSceneChainSampler:
|
||||
# of THIS run would score the shots / k of an older, unrated one.
|
||||
if self._shot_memory is not None:
|
||||
for _note in self._shot_memory.notes:
|
||||
print(f"[FunPackSceneChain] shot memory: {_note}")
|
||||
print(f"[FunPackSceneChain] shot memory: "
|
||||
f"{'Inactive' if 'left alone' in _note else 'Active'} | {_note}")
|
||||
if self._shot_memory.skipped:
|
||||
print(f"[FunPackSceneChain] shot memory: left {self._shot_memory.skipped} "
|
||||
f"sampling pass(es) alone -- their latent already held a picture "
|
||||
print(f"[FunPackSceneChain] shot memory: Inactive | left {self._shot_memory.skipped} "
|
||||
f"sampling pass(es) alone, their latent already held a picture "
|
||||
f"(second pass, latent anchor or carried overlap), so the noise "
|
||||
f"does not decide the shot there")
|
||||
self._shot_memory.save_pending()
|
||||
else:
|
||||
_shot_memory.clear_pending(refinement_key_input)
|
||||
if tsr == "learned":
|
||||
if tsr == "learned" and getattr(self, "_tsr_acts", True):
|
||||
_tsr.save_pending(refinement_key_input, self._tsr_k)
|
||||
else:
|
||||
_tsr.clear_pending(refinement_key_input)
|
||||
@@ -11032,7 +11046,7 @@ class FunPackLTXAVSceneChainSampler:
|
||||
continue
|
||||
_dial.clear_pending(refinement_key_input)
|
||||
if _on and self._is_h3:
|
||||
print(f"[FunPackSceneChain] {_name}: did not apply this run, so this "
|
||||
print(f"[FunPackSceneChain] {_name}: Inactive | did not apply this run, so this "
|
||||
f"run's rating will not teach its learned strength")
|
||||
|
||||
# Trajectory probe: same run/rating pairing as the two above — the rating that scores
|
||||
|
||||
@@ -201,3 +201,12 @@ def test_h3_a_one_step_schedule_says_it_does_nothing(capsys):
|
||||
_euler(model.model_options["model_function_wrapper"], torch.randn(1, 2, 3, 4, 4),
|
||||
schedule=torch.tensor([1.0, 0.0]))
|
||||
assert "1-step schedule" in capsys.readouterr().out
|
||||
|
||||
|
||||
def test_decisiveness_reach_tells_a_weak_schedule_from_a_strong_one():
|
||||
simple4 = [1.0, 0.973, 0.923, 0.8, 0.0]
|
||||
beta57_8 = [1.0, 0.99, 0.969, 0.933, 0.872, 0.764, 0.563, 0.235, 0.0]
|
||||
assert tsr.reach(simple4, 0.9) < tsr.INERT_SHARE # ~2%: can't be felt
|
||||
assert tsr.reach(beta57_8, 0.95) > tsr.INERT_SHARE * 3 # a real push
|
||||
assert tsr.reach([1.0, 0.0], 0.9) == 0.0 # one step: nothing to carry into
|
||||
assert tsr.reach(simple4, 1.0) == 0.0 # k = 1 is exactly off
|
||||
|
||||
@@ -44,6 +44,26 @@ def rescale_x0(x, x0, sigma, k):
|
||||
return (x - float(sigma) * r * eps) / a
|
||||
|
||||
|
||||
# Below this share of a step's input noise, a push cannot be felt (simple@4, k 0.9 is ~2%).
|
||||
# ponytail: judged by eye on one schedule, not measured; tune it if a rental says otherwise.
|
||||
INERT_SHARE = 0.03
|
||||
|
||||
|
||||
def reach(sigmas, k, s=S):
|
||||
"""The largest share of a step's input noise that decisiveness's push makes up when each
|
||||
push rides into the NEXT step's input (H3): sigma*|1-r|/(1-sigma), scaled by the landing
|
||||
step's (1 - sigma) and set against its noise sigma. The last step is never edited."""
|
||||
vals = [float(v) for v in sigmas]
|
||||
best = 0.0
|
||||
for i in range(len(vals) - 2):
|
||||
s0, s1 = vals[i], vals[i + 1]
|
||||
if s0 < 1e-4 or s1 < 1e-4 or 1.0 - s0 < 1e-3:
|
||||
continue
|
||||
push = s0 * abs(1.0 - factor(s0, k, s)) / (1.0 - s0) * (1.0 - s1)
|
||||
best = max(best, push / s1)
|
||||
return best
|
||||
|
||||
|
||||
def _path(refinement_key):
|
||||
try:
|
||||
from .conditioning import refinement_state_path
|
||||
|
||||
Reference in New Issue
Block a user