fix: output value function -- train on H3 too, not just LTXAV
explore_first_step reads the same output-space value function output_guidance trains, but training/snapshotting was gated off for H3 entirely -- a decision made before explore_first_step existed, when output_guidance (still correctly forced off there) was its only consumer. Result: the value function could never reach MIN_SAMPLES on H3 no matter how many generations were rated, so explore_first_step printed "not ready yet" forever. Un-gate the snapshot save and the training call for H3; leave output_guidance's own application (and the separate conditioning-payload VF for embed_guidance/value_guidance) forced off as before -- that decision is unaffected. No new automated test: no existing fixture exercises this rating-commit code path (FunPackVideoRefiner.run's post-scene training block) cheaply enough to extend honestly; verified by full suite pass (1491/1491) and direct tracing that no other call site re-introduces the gate. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
68d1657a50
commit
77cf37e18d
+20
-12
@@ -10198,10 +10198,17 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
|
|||||||
# value_guidance only controls APPLICATION (ascent below) - a user who runs with it
|
# value_guidance only controls APPLICATION (ascent below) - a user who runs with it
|
||||||
# off still builds the VF, so enabling guidance later works immediately.
|
# off still builds the VF, so enabling guidance later works immediately.
|
||||||
#
|
#
|
||||||
# NOT on H3: nothing there reads either value function (value_guidance is forced
|
# The conditioning-payload value function (below) is NOT trained on H3: it only
|
||||||
# off above; output_guidance is a sampler-side toggle forced off the same way), so
|
# feeds embed_guidance/value_guidance/taste_nearest_prompt, all forced off there
|
||||||
# training them is pure waste that only helps a mechanism this session found does
|
# (see self._is_h3 override in the sampler) because they were built and calibrated
|
||||||
# not help — h3_repr_steering has its own commit below, unconditional.
|
# for LTXAV and have never been shown to do anything useful on H3 -- training it
|
||||||
|
# would be pure waste. The OUTPUT value function just below is a different story:
|
||||||
|
# explore_first_step reads it too (to select between candidate seeds), and that
|
||||||
|
# mechanism is not H3-excluded -- training it only for output_guidance's sake
|
||||||
|
# (also forced off on H3) silently starved explore_first_step of every sample it
|
||||||
|
# needed, permanently printing "not ready yet" no matter how much was rated. So
|
||||||
|
# only the conditioning-payload VF stays H3-gated; the output VF trains on every
|
||||||
|
# family. h3_repr_steering has its own commit below, unconditional either way.
|
||||||
if (has_previous_run and refinement_key and not learning_profile.get("skip_learning")
|
if (has_previous_run and refinement_key and not learning_profile.get("skip_learning")
|
||||||
and self._v2_reward_admissible(learning_profile)):
|
and self._v2_reward_admissible(learning_profile)):
|
||||||
if not _is_h3:
|
if not _is_h3:
|
||||||
@@ -10212,14 +10219,15 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
|
|||||||
)
|
)
|
||||||
if n is not None:
|
if n is not None:
|
||||||
print(f"[FunPackRefiner] Value function updated — {n} samples")
|
print(f"[FunPackRefiner] Value function updated — {n} samples")
|
||||||
# output_guidance's value function, trained on the sampler's x0_snapshot from
|
# output_guidance's value function, trained on the sampler's x0_snapshot from
|
||||||
# the run this rating scores (whole-run granularity — see
|
# the run this rating scores (whole-run granularity — see
|
||||||
# _v2_train_output_value_function for why this sits at the single
|
# _v2_train_output_value_function for why this sits at the single
|
||||||
# overall-reward call site, not the per-scene ones).
|
# overall-reward call site, not the per-scene ones). Trained on every family
|
||||||
with self._v2_stage("output value function"):
|
# (see the comment above this block) -- explore_first_step needs it on H3 too.
|
||||||
n_out = self._v2_train_output_value_function(refinement_key, float(learning_profile.get("reward", 0.0)))
|
with self._v2_stage("output value function"):
|
||||||
if n_out is not None:
|
n_out = self._v2_train_output_value_function(refinement_key, float(learning_profile.get("reward", 0.0)))
|
||||||
print(f"[FunPackRefiner] Output value function updated — {n_out} samples")
|
if n_out is not None:
|
||||||
|
print(f"[FunPackRefiner] Output value function updated — {n_out} samples")
|
||||||
if _is_h3:
|
if _is_h3:
|
||||||
try:
|
try:
|
||||||
from . import h3_repr_steering as _rs
|
from . import h3_repr_steering as _rs
|
||||||
|
|||||||
+7
-6
@@ -10224,18 +10224,19 @@ class FunPackLTXAVSceneChainSampler:
|
|||||||
# silently skipped it, so the output value function NEVER received a sample on AV
|
# silently skipped it, so the output value function NEVER received a sample on AV
|
||||||
# ("not ready yet (needs 10+)" forever). Snapshot the video stream (largest tensor),
|
# ("not ready yet (needs 10+)" forever). Snapshot the video stream (largest tensor),
|
||||||
# matching the video-only convention of the in-flight guidance path.
|
# matching the video-only convention of the in-flight guidance path.
|
||||||
|
# NOT gated on family any more: output_guidance's own APPLICATION is still forced off
|
||||||
|
# on H3 (self._is_h3 override above, untested/uncalibrated there), but explore_first_step
|
||||||
|
# reads this SAME value function to select between candidate seeds and is not
|
||||||
|
# H3-excluded -- skipping the snapshot here starved it permanently (0 samples, forever
|
||||||
|
# "not ready yet" regardless of rating count), the exact bug this comment used to cause
|
||||||
|
# for output_guidance on AV before the nested-tensor fix above.
|
||||||
if refinement_key_input and isinstance(output, dict):
|
if refinement_key_input and isinstance(output, dict):
|
||||||
_snap = output.get("samples")
|
_snap = output.get("samples")
|
||||||
if self._is_nested(_snap):
|
if self._is_nested(_snap):
|
||||||
_parts = [t for t in _snap.unbind() if isinstance(t, torch.Tensor) and t.numel() > 0]
|
_parts = [t for t in _snap.unbind() if isinstance(t, torch.Tensor) and t.numel() > 0]
|
||||||
_snap = max(_parts, key=lambda t: t.numel()) if _parts else None
|
_snap = max(_parts, key=lambda t: t.numel()) if _parts else None
|
||||||
if isinstance(_snap, torch.Tensor):
|
if isinstance(_snap, torch.Tensor):
|
||||||
if not self._is_h3:
|
self._save_output_value_snapshot(refinement_key_input, _snap, None)
|
||||||
# NOT on H3: this snapshot only feeds output_guidance's value function,
|
|
||||||
# forced off for H3 (see self._is_h3 override above) — capturing it here
|
|
||||||
# anyway would just be banking video latents nothing ever reads, the same
|
|
||||||
# waste the "disable everything unrelated to REINS" pass was for.
|
|
||||||
self._save_output_value_snapshot(refinement_key_input, _snap, None)
|
|
||||||
# DynaShift pending candidate: same run/rating pairing as the snapshot, but
|
# DynaShift pending candidate: same run/rating pairing as the snapshot, but
|
||||||
# the RAW video latent (fp16) — the rating decides whether it becomes a
|
# the RAW video latent (fp16) — the rating decides whether it becomes a
|
||||||
# negative-bank entry, a positive-bank entry, or is discarded
|
# negative-bank entry, a positive-bank entry, or is discarded
|
||||||
|
|||||||
Reference in New Issue
Block a user