feat: REINS can steer anywhere in 40-49, one block at a time

The influence probe measured the stack as heavily back-loaded — blocks
48 and 49 alone carry about a third of all residual movement, and the
busiest twelve are almost all in the 40s — while REINS defaults to block
25 and the picker stopped at 40, so it could not reach where the model
does most of its work.

CANDIDATE_BLOCKS now covers 40-49 individually (the quiet early half
stays on the coarse grid). Capture has to cover them too: direction()
reads descriptors at the exact block being steered, so a picker entry
outside the capture set would say "not enough data yet" forever. A test
pins that the two sets cannot drift apart — the same silent-substitution
class as the rating combo that discarded every digit.

Node and Editor choice lists verified byte-identical: a mismatch there
makes ComfyUI's widget validation quietly swap in the default.
This commit is contained in:
digital-garbage
2026-09-04 18:23:58 +03:00
parent 8a670fdf60
commit 24f7cec8dd
4 changed files with 27 additions and 4 deletions
+6 -1
View File
@@ -43,7 +43,12 @@ import torch
# of guessed from someone else's percentage. Only DEFAULT_BLOCK ever STEERS; the rest of
# CANDIDATE_BLOCKS are captured read-only alongside it so block_sweep() has something to rank.
DEFAULT_BLOCK = 25
CANDIDATE_BLOCKS = sorted({1, 5, 10, 15, 20, 25, 30, 35, 40, 45, DEFAULT_BLOCK})
# 41-49 individually, not on the coarse grid: the block-influence probe measured the stack as
# heavily BACK-LOADED (blocks 48+49 alone carrying ~a third of all residual movement), so the
# tail is where a steering push has the most to act on and is worth resolving one block at a
# time. Everything below 40 stays coarse -- it is the quiet end.
CANDIDATE_BLOCKS = sorted({1, 5, 10, 15, 20, 25, 30, 35, DEFAULT_BLOCK,
*range(40, 50)})
MIN_PER_GROUP = 2 # need 2+ POSITIVE-weight and 2+ NEGATIVE-weight rows. Was 3 (parity with
# absolute/taste steering's floor, not derived from anything specific to this mechanism).
+2 -2
View File
@@ -322,8 +322,8 @@
hint: "EXPERIMENTAL, unvalidated, H3 only. Reaches inside the model instead of around it: captures one block's video-row hidden state each generation, and once you have 3+ liked and 3+ disliked runs on this refinement key, adds their mean difference back into that block's output on every later run. No architectural ceiling like the attention-bias mechanisms have — push the strength too far and coherence can break with no warning." },
{ name: "h3_repr_steering_strength", label: "Representation steering strength", kind: "float", default: 0.05, min: 0.0, max: 2.0, step: 0.01, dependsOn: "h3_repr_steering",
hint: "Fraction of the block's own hidden-state norm added along the learned direction. Start low and push it deliberately high on a same-seed test to confirm it moves the video at all before trusting a small value." },
{ name: "h3_repr_steering_block", label: "Steer at block", kind: "combo", choices: ["1", "5", "10", "15", "20", "25", "30", "35", "40"], default: "25", dependsOn: "h3_repr_steering",
hint: "TEST-ONLY: which of the block-sweep's candidate blocks actually gets steered, instead of always block 25. Blocks 1-15 are deep-end territory (the anchor/reference rows haven't been read by the network yet at that depth) -- expect this to behave differently, not just 'weaker', than 20-40. The other candidate blocks are still captured read-only either way." },
{ name: "h3_repr_steering_block", label: "Steer at block", kind: "combo", choices: ["1", "5", "10", "15", "20", "25", "30", "35", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49"], default: "25", dependsOn: "h3_repr_steering",
hint: "TEST-ONLY: which of the block-sweep's candidate blocks actually gets steered, instead of always block 25. Blocks 40-49 are listed one at a time because that is where the stack does most of its work (48 and 49 alone carry about a third of all movement). Blocks 1-15 are deep-end territory (the anchor/reference rows haven't been read by the network yet at that depth) -- expect this to behave differently, not just 'weaker', than 20-40. The other candidate blocks are still captured read-only either way." },
{ name: "identity_transfer_enabled", label: "Best-FaceID compatibility", kind: "bool", default: false,
hint: "Feeds the identity pin image the way Best-FaceID identity LoRAs expect it. Needs an Identity pin set.",
detail: "Replaces Continuity's identity-pin guide with separate, non-rendered reference tokens plus an optional ArcFace projector below. Load the LoRA itself in Models. No effect without an identity pin." },
+1 -1
View File
@@ -2966,7 +2966,7 @@ class FunPackLTXAVSceneChainSampler:
# workflow (builder.py), silently corrupting anything the user hadn't
# explicitly overridden in sampler_inputs. Fixed 2026-09-03; do not move this
# back up next to its sibling widgets.
"h3_repr_steering_block": (["1", "5", "10", "15", "20", "25", "30", "35", "40"], {
"h3_repr_steering_block": (["1", "5", "10", "15", "20", "25", "30", "35", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49"], {
"default": "25",
"tooltip": "TEST-ONLY: which block actually gets steered (the rest of the sweep's candidate blocks are still captured read-only, same as always). direction() is recomputed for whichever block you pick here -- this does not change what block_sweep ranks, only which block's learned direction gets injected into this run.",
}),
+18
View File
@@ -223,3 +223,21 @@ def test_block_sweep_drops_neutral_weight_rows():
rs.commit("k", 0.0) # exactly neutral -- must not count toward either side
sweep = rs.block_sweep("k", trials=200)
assert sweep[rs.DEFAULT_BLOCK]["n"] == 2 * rs.MIN_PER_GROUP
def test_every_steerable_block_is_also_captured():
"""A block can only be STEERED if it is also in CANDIDATE_BLOCKS -- direction() reads
descriptors captured at that exact block, so a picker entry outside the capture set would
report "not enough data yet" forever no matter how many runs were rated."""
import re
src = open("samplers.py").read()
choices = re.search(r'"h3_repr_steering_block": \(\[([^]]*)\]', src).group(1)
offered = {int(c.strip().strip('"')) for c in choices.split(",")}
assert offered <= set(rs.CANDIDATE_BLOCKS), offered - set(rs.CANDIDATE_BLOCKS)
def test_the_back_loaded_tail_is_resolved_one_block_at_a_time():
"""The influence probe measured blocks 48-49 carrying ~a third of all residual movement,
so the tail is where a push has the most to act on -- it is covered individually rather
than on the coarse grid the quiet early half uses."""
assert set(range(40, 50)) <= set(rs.CANDIDATE_BLOCKS)