feat: disable every rating-driven mechanism on H3 except phrase emphasis and REINS

H3's only validated (or being-validated) rating consumers are
h3_phrase_emphasis and h3_repr_steering. Everything else --
value_guidance/absolute taste steering, output_guidance,
trajectory_guidance, dynashift, embed_guidance, score_slider,
taste_nearest_prompt, and the path planner -- was built and
calibrated for LTXAV or for a value function nothing on H3 reads.
None of it helps REINS; it only trains value functions that are
never consumed and prints status lines for mechanisms that can
never fire, which is what actually produced the "80% of the log is
useless" bug report this responds to.

Forced off at two chokepoints (top of sample() in samplers.py once
self._is_h3 is known; top of refine_v2 in conditioning.py once the
clip's family is known), not just hidden in Engine Settings, so a
project saved before this still behaves correctly. Value-function
and Absolute-taste TRAINING (not just application) is skipped too --
per-scene, per-key, and the main path -- since nothing on H3 will
ever read what they'd produce.
This commit is contained in:
digital-garbage
2026-09-03 18:46:30 +03:00
parent c8993891c6
commit 6a942ae3a9
3 changed files with 69 additions and 8 deletions
+21 -8
View File
@@ -4791,10 +4791,14 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
return seed_memory_status
def _v2_learn_scene_into_keys(self, scene_keys, project_key, scene_run, profile, iter_num,
axis_feedback, seed_output_connected):
axis_feedback, seed_output_connected, is_h3=False):
"""Train every non-default key that participated in a scene. Each key's own state file
gets the full learning suite + its value-function update, then is saved. The project
key is skipped here (it already learns into the run's main global_state)."""
key is skipped here (it already learns into the run's main global_state).
`is_h3` skips the value-function update: nothing on H3 reads it (see refine_v2's
is_h3 override) -- the rest of the learning suite still runs, it is only this
mechanism-specific training that has nowhere to go on H3."""
trained = []
for key in scene_keys or []:
key = str(key or "").strip()
@@ -4806,7 +4810,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
self._v2_learn_scene_into_state(
key_global, scene_run, profile, iter_num, axis_feedback, seed_output_connected,
)
if not profile.get("skip_learning") and self._v2_reward_admissible(profile):
if not is_h3 and not profile.get("skip_learning") and self._v2_reward_admissible(profile):
self._v2_train_value_function(
refinement_state_path(key, "value_fn", prefix="refine_v2", extension="pt"),
scene_run.get("conditioning"),
@@ -4834,6 +4838,11 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
"""Apply Refiner V2 learning once per rated scene (Movie Editor multi-scene chains)."""
if not isinstance(previous_run, dict) or not scene_ratings:
return "Movie Editor ratings: none.", None
try:
from . import minimax_h3 as _h3fam
except ImportError:
import minimax_h3 as _h3fam
is_h3 = _h3fam.is_h3_clip(clip)
scene_count = int(previous_run.get("scene_count") or len(previous_run.get("scene_texts") or []) or 1)
if scene_count <= 1:
return "Movie Editor ratings: previous run was single-scene.", None
@@ -4873,9 +4882,10 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
# so a clip's key never trains the default (and vice versa).
trained_keys = self._v2_learn_scene_into_keys(
scene_keys, refinement_key, scene_run, profile, iter_num,
axis_feedback, seed_output_connected,
axis_feedback, seed_output_connected, is_h3=is_h3,
)
self._v2_learn_absolute(scene_run, profile)
if not is_h3:
self._v2_learn_absolute(scene_run, profile)
profiles.append(profile)
lines.append(
f"Scene {scene_index + 1} ({label}): trained custom key(s) [{', '.join(trained_keys)}], default skipped"
@@ -4886,7 +4896,7 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
seed_memory_status = self._v2_learn_scene_into_state(
global_state, scene_run, profile, iter_num, axis_feedback, seed_output_connected,
)
if refinement_key and self._v2_reward_admissible(profile):
if not is_h3 and refinement_key and self._v2_reward_admissible(profile):
with self._v2_stage("value function"):
n = self._v2_train_value_function(
refinement_state_path(refinement_key, "value_fn", prefix="refine_v2", extension="pt"),
@@ -4895,7 +4905,8 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
)
if n is not None:
print(f"[FunPackRefiner] Scene {scene_index + 1} value function updated — {n} samples")
self._v2_learn_absolute(scene_run, profile)
if not is_h3:
self._v2_learn_absolute(scene_run, profile)
profiles.append(profile)
lines.append(
f"Scene {scene_index + 1} ({label}): {seed_memory_status.split(': ', 1)[-1]}"
@@ -10207,7 +10218,9 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
# Runs even with no refinement_key (Absolute is global), so standalone runs still build it.
# Skipped for Wrong-* repair ratings (skip_value_function): Absolute reads reward as pure
# quality, so a 0.0/low repair reward on a good gen would push it into the global bad_dir.
if has_previous_run:
# NOT on H3 -- nothing reads it (steer_mode/absolute_strength are Studio-side, gated by
# the same value_guidance override above), so training it is pure waste.
if has_previous_run and not _is_h3:
with self._v2_stage("absolute taste"):
self._v2_learn_absolute(previous_run, learning_profile)
if has_previous_run and not learning_profile.get("skip_learning"):
+14
View File
@@ -6909,6 +6909,20 @@ class FunPackLTXAVSceneChainSampler:
# happened last run is reported again rather than deduped away forever.
_log.begin_run()
self._is_h3 = self._set_stream_axes(model)
if self._is_h3:
# H3's rating-driven mechanisms are h3_phrase_emphasis (Studio) and
# h3_repr_steering (this file) ONLY -- see project_reward_model_rework.md and the
# 2026-09-03 dev session. Every other rating-driven latent/conditioning steerer
# was built and validated for LTXAV; none of them has been shown to do anything
# useful on H3 (output_guidance/trajectory_guidance/dynashift/score_slider ride
# the same last-half gate that was calibrated there, and embed_guidance/
# taste_nearest_prompt read the same relative value function that phrase
# emphasis's own manipulation check showed produces near-invisible pushes at H3's
# real calibration). Forced off HERE, not just hidden in Engine Settings, so a
# project saved before this still behaves correctly instead of silently doing
# six things nobody asked for.
output_guidance = trajectory_guidance = dynashift = False
embed_guidance = score_slider = taste_nearest_prompt = False
# Read once per run, consumed by _install_h3_final_layer at each scene's sample call.
self._h3_video_detail = max(0.0, min(2.0, float(h3_video_detail)))
# The gate every rating-driven wrapper shares. On H3 it is read off the schedule's
+34
View File
@@ -457,6 +457,40 @@ def test_me_scene_ratings_custom_key_skips_default(monkeypatch):
assert calls["default_vf"] == 1 # default VF trained ONLY scene 2
def test_h3_scene_ratings_skip_value_function_and_absolute(monkeypatch):
"""H3's only rating-driven mechanisms are h3_phrase_emphasis and h3_repr_steering --
nothing reads the per-key value function or the Absolute taste store on H3, so training
them per rated scene is pure waste (see the 2026-09-03 dev session)."""
import minimax_h3
monkeypatch.setattr(minimax_h3, "is_h3_clip", lambda c: True)
studio = conditioning.FunPackVideoRefinerV2()
calls = {"vf": 0, "absolute": 0, "custom_is_h3": []}
monkeypatch.setattr(studio, "_v2_build_scene_learning_run",
lambda run, idx, *a, **k: {"conditioning": {"x": 1}, "scene_index": idx})
monkeypatch.setattr(studio, "_v2_axis_feedback",
lambda *a, **k: {"missing_axes": [], "satisfied_axes": []})
monkeypatch.setattr(studio, "_v2_learn_scene_into_state", lambda *a, **k: "seed: ok")
monkeypatch.setattr(studio, "_v2_train_value_function",
lambda *a, **k: (calls.__setitem__("vf", calls["vf"] + 1), 1)[1])
monkeypatch.setattr(studio, "_v2_learn_absolute",
lambda *a, **k: calls.__setitem__("absolute", calls["absolute"] + 1))
def _fake_learn_into_keys(keys, *a, is_h3=False, **k):
calls["custom_is_h3"].append(is_h3)
return list(keys)
monkeypatch.setattr(studio, "_v2_learn_scene_into_keys", _fake_learn_into_keys)
prev = {"scene_count": 2, "scene_texts": ["s1", "s2"],
"scene_refinement_keys": [["mykey"], []]} # scene1 custom, scene2 default
ratings = [{"index": 0, "rating": "Perfect"}, {"index": 1, "rating": "Perfect"}]
studio._v2_apply_movie_editor_scene_ratings(
{}, prev, ratings, 1, refinement_key="default", clip=object())
assert calls["vf"] == 0 # scene 2 (default key) never trains its VF on H3
assert calls["absolute"] == 0 # neither scene feeds Absolute on H3
assert calls["custom_is_h3"] == [True] # scene 1's custom-key path was told it's H3 too
def test_wrong_ratings_skip_value_function():
"""Wrong-* are prompt-repair signals, not quality rewards: they must NOT train the value
function (a 0.0/low reward on a visually-good gen poisons the learned quality landscape).