Multi-key: stop training every refinement key on every clip
Per-scene key attribution diverged from the generation split whenever the advisor rewrote prompt_to_encode away from the raw prompt, so resolve_scene_refinement_keys hit its all-keys UNION fallback and assigned every key to every scene. That union got persisted into the run and read back at rating time, training every key on every clip (value_fn bloat). - prompt_scene_shortcut_keys now scans both expanded and original text (mirrors split_timeline_verbatim), so identical structure -> matching scene count -> precise attribution far more often. - Divergence fallback is now default-key only (empty sets), not the all-keys union; a diverged run under-trains instead of cross-training. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
5ed5fcd59a
commit
ab4f78695d
@@ -2,6 +2,17 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- Multi-key refinement: stop training every key on every clip. Per-scene key attribution
|
||||
(`prompt_scene_shortcut_keys`) now scans both the expanded and original prompt — matching the
|
||||
generation splitter `split_timeline_verbatim` — so structurally-identical prompts land on the
|
||||
same scene count and attribution stays precise. When the count still diverges (advisor/repair
|
||||
rewrote `prompt_to_encode` away from the raw prompt), `resolve_scene_refinement_keys` now falls
|
||||
back to the project **default key only** (empty sets) instead of the all-keys **union**. The
|
||||
union assigned every key to every scene, which both steered and — once persisted into the run
|
||||
and read back at rating time — trained every key on every clip (cross-contamination + value
|
||||
function bloat, e.g. an ~80 MB jump on a single 3-clip rating pass).
|
||||
|
||||
## [3.0.1] - 2026-06-14
|
||||
|
||||
### Added
|
||||
|
||||
+19
-5
@@ -857,6 +857,7 @@ def prompt_scene_shortcut_keys(prompt):
|
||||
split_pattern = re.compile(_GENERIC_SCENE_LABEL_PATTERN, re.IGNORECASE)
|
||||
|
||||
cuts = []
|
||||
# (1) Scan the EXPANDED text: catches a shortcut whose expansion resolves to a transition.
|
||||
for m in split_pattern.finditer(expanded):
|
||||
info = custom_map.get(re.sub(r"\s+", " ", m.group(0).strip().lower())) or {}
|
||||
if info.get("placement") == "start":
|
||||
@@ -864,6 +865,14 @@ def prompt_scene_shortcut_keys(prompt):
|
||||
else:
|
||||
orig = _project_offset(pieces, m.end(), "after")
|
||||
cuts.append(orig)
|
||||
# (2) Scan the ORIGINAL text too: a transition trigger that is ALSO a shortcut gets expanded
|
||||
# away in (1) before detection, so its split would be lost. Matching the verbatim text
|
||||
# catches it at its true offset. This mirrors split_timeline_verbatim so this attribution
|
||||
# split lands on the same scene count as the generation split (fewer divergence fallbacks).
|
||||
for m in split_pattern.finditer(text):
|
||||
info = custom_map.get(re.sub(r"\s+", " ", m.group(0).strip().lower())) or {}
|
||||
orig = m.start() if info.get("placement") == "start" else m.end()
|
||||
cuts.append(orig)
|
||||
seen, uniq = set(), []
|
||||
for off in sorted(cuts):
|
||||
if off <= 0 or off in seen:
|
||||
@@ -891,10 +900,12 @@ def resolve_scene_refinement_keys(raw_positive, scene_count):
|
||||
"""Per-scene non-default refinement keys, aligned to split_scene_texts.
|
||||
|
||||
A key participates in a scene when one of its bound shortcuts fired in that scene's
|
||||
text (anchor keys count for every scene). Falls back to the union across all scenes
|
||||
when attribution can't be trusted — the raw-prompt scene count diverges from the
|
||||
actual split (advisor/repair rewrote the prompt, unusual transition stacking, etc.).
|
||||
Returns a list of sets aligned to scenes; empty sets => default key (today's path).
|
||||
text (anchor keys count for every scene). Falls back to the project DEFAULT key only
|
||||
(empty sets) when attribution can't be trusted — the raw-prompt scene count diverges
|
||||
from the actual split (advisor/repair rewrote the prompt, unusual transition stacking,
|
||||
etc.). The old behaviour here was the all-keys UNION, which trained EVERY key on EVERY
|
||||
scene (cross-contamination + value-function bloat); under-training one diverged run is
|
||||
far safer. Returns a list of sets aligned to scenes; empty sets => default key.
|
||||
|
||||
This is the single source of truth shared by generation (FunPackStudio._v2_scene_refinement_keys)
|
||||
and the Movie Editor preview, so what the editor shows is exactly what will run."""
|
||||
@@ -908,7 +919,10 @@ def resolve_scene_refinement_keys(raw_positive, scene_count):
|
||||
return [set() for _ in range(scene_count)]
|
||||
if n == scene_count:
|
||||
return scene_sets
|
||||
return [set(all_keys) for _ in range(scene_count)]
|
||||
# Divergence: attribution cannot be trusted. Steer/train with the project default key only
|
||||
# (empty sets) instead of the all-keys union, so a diverged run never trains every key on
|
||||
# every scene. all_keys stays available to callers that need the full set (e.g. session reset).
|
||||
return [set() for _ in range(scene_count)]
|
||||
|
||||
|
||||
def parse_timeline_segments(prompt):
|
||||
|
||||
@@ -176,9 +176,10 @@ def test_studio_scene_refinement_keys_fallback(monkeypatch):
|
||||
raw = "wide shot scene 1 alpha here scene 2 beta here" # attribution finds 2 scenes
|
||||
# scene_count matches -> precise per-scene
|
||||
assert studio._v2_scene_refinement_keys(raw, 2) == [{"keyA"}, {"keyB"}]
|
||||
# scene_count diverges (advisor rewrote / stacking) -> safe union for every scene
|
||||
# scene_count diverges (advisor rewrote / stacking) -> default key only (empty sets), NOT the
|
||||
# all-keys union; a union here would train every key on every scene (cross-contamination).
|
||||
out = studio._v2_scene_refinement_keys(raw, 3)
|
||||
assert out == [{"keyA", "keyB"}, {"keyA", "keyB"}, {"keyA", "keyB"}]
|
||||
assert out == [set(), set(), set()]
|
||||
|
||||
|
||||
def test_studio_scene_refinement_keys_no_bindings(monkeypatch):
|
||||
|
||||
Reference in New Issue
Block a user