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:
+6
-1
@@ -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).
|
||||
|
||||
@@ -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
@@ -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.",
|
||||
}),
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user