From 77cf37e18dadbabc43eeb728c64ea661a35924bb Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Tue, 22 Sep 2026 14:43:33 +0300 Subject: [PATCH] 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 --- conditioning.py | 32 ++++++++++++++++++++------------ samplers.py | 13 +++++++------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/conditioning.py b/conditioning.py index a5c559ae..d8e6d05e 100644 --- a/conditioning.py +++ b/conditioning.py @@ -10198,10 +10198,17 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner): # value_guidance only controls APPLICATION (ascent below) - a user who runs with it # off still builds the VF, so enabling guidance later works immediately. # - # NOT on H3: nothing there reads either value function (value_guidance is forced - # off above; output_guidance is a sampler-side toggle forced off the same way), so - # training them is pure waste that only helps a mechanism this session found does - # not help — h3_repr_steering has its own commit below, unconditional. + # The conditioning-payload value function (below) is NOT trained on H3: it only + # feeds embed_guidance/value_guidance/taste_nearest_prompt, all forced off there + # (see self._is_h3 override in the sampler) because they were built and calibrated + # 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") and self._v2_reward_admissible(learning_profile)): if not _is_h3: @@ -10212,14 +10219,15 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner): ) if n is not None: print(f"[FunPackRefiner] Value function updated — {n} samples") - # output_guidance's value function, trained on the sampler's x0_snapshot from - # the run this rating scores (whole-run granularity — see - # _v2_train_output_value_function for why this sits at the single - # overall-reward call site, not the per-scene ones). - with self._v2_stage("output value function"): - n_out = self._v2_train_output_value_function(refinement_key, float(learning_profile.get("reward", 0.0))) - if n_out is not None: - print(f"[FunPackRefiner] Output value function updated — {n_out} samples") + # output_guidance's value function, trained on the sampler's x0_snapshot from + # the run this rating scores (whole-run granularity — see + # _v2_train_output_value_function for why this sits at the single + # overall-reward call site, not the per-scene ones). Trained on every family + # (see the comment above this block) -- explore_first_step needs it on H3 too. + with self._v2_stage("output value function"): + n_out = self._v2_train_output_value_function(refinement_key, float(learning_profile.get("reward", 0.0))) + if n_out is not None: + print(f"[FunPackRefiner] Output value function updated — {n_out} samples") if _is_h3: try: from . import h3_repr_steering as _rs diff --git a/samplers.py b/samplers.py index 56a41ffa..d925ed24 100644 --- a/samplers.py +++ b/samplers.py @@ -10224,18 +10224,19 @@ class FunPackLTXAVSceneChainSampler: # 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), # 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): _snap = output.get("samples") if self._is_nested(_snap): _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 if isinstance(_snap, torch.Tensor): - if not self._is_h3: - # 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) + self._save_output_value_snapshot(refinement_key_input, _snap, None) # DynaShift pending candidate: same run/rating pairing as the snapshot, but # the RAW video latent (fp16) — the rating decides whether it becomes a # negative-bank entry, a positive-bank entry, or is discarded