Attention explorer: dislikes no longer grow the change size, learned size capped at 0.35

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnrTBt9b8CdJwub5roffF3
This commit is contained in:
Claude
2026-10-25 21:37:21 +00:00
parent f71407f98e
commit 089248ea10
2 changed files with 16 additions and 6 deletions
@@ -71,6 +71,7 @@ STAY_HEAD_START = 2.0 # extra likes "as is" starts with, so a new key is s
MAX_ROWS = 10 ** 9 # no cap: a rated run is under 1 KB
START_SPREAD = 0.2
SPREAD_MIN, SPREAD_MAX = 0.05, 0.5
LEARN_MAX = 0.35 # what ratings can grow the size to; 0.5x/1.5x on many blocks wrecked a picture on H3
LR = 0.5
EXPLORE = 0.05
@@ -121,8 +122,11 @@ def learned_spread(rows, signature):
continue
if all(int(a) == STAY for a in p["arms"].tolist()):
continue # nothing changed, so nothing to blame on the size
m += LR * _sign(r["reward"]) * (float(p["spread"]) - m)
m = min(max(m, SPREAD_MIN), SPREAD_MAX)
used = float(p["spread"])
# A like pulls toward the size it used. A dislike can only say "too much": it pushes the
# size down from a bigger one, never up from a smaller one (that would ratchet to the cap).
m += LR * (used - m) if r["reward"] > 0 else LR * min(0.0, m - used)
m = min(max(m, SPREAD_MIN), LEARN_MAX)
return m
@@ -197,7 +201,7 @@ def install(patcher, values, key):
rows = taste.rows(KIND)
picks = draw(counts(rows, signature, len(groups)))
spread = manual_spread if manual else min(max(
learned_spread(rows, signature) + random.gauss(0.0, EXPLORE), SPREAD_MIN), SPREAD_MAX)
learned_spread(rows, signature) + random.gauss(0.0, EXPLORE), SPREAD_MIN), LEARN_MAX)
live["scaled"] = live["calls"] = 0
live["temps"] = {b: 1.0 + spread * ARMS[a] for g, a in zip(groups, picks) for b in g}
captured.update({"arms": torch.tensor(picks), "sig": torch.tensor(signature),
@@ -54,15 +54,21 @@ def _srow(reward, arms, spread, sig=(2, 0, 9)):
def test_the_size_moves_toward_liked_and_away_from_disliked_and_ignores_unchanged_runs():
from modules.sampling.attention_bandit import SPREAD_MAX, SPREAD_MIN, START_SPREAD, learned_spread
from modules.sampling.attention_bandit import LEARN_MAX, SPREAD_MIN, START_SPREAD, learned_spread
sig = [2, 0, 9]
assert learned_spread([], sig) == START_SPREAD
assert learned_spread([_srow(1.0, [0, 1], 0.4)], sig) > START_SPREAD
assert learned_spread([_srow(-1.0, [0, 1], 0.4)], sig) < START_SPREAD
assert learned_spread([_srow(1.0, [1, 1], 0.4)], sig) == START_SPREAD # nothing changed
assert learned_spread([_srow(1.0, [0, 1], 0.4, sig=(3, 0, 9))], sig) == START_SPREAD # other layout
assert learned_spread([_srow(1.0, [0, 0], 0.5)] * 30, sig) == pytest.approx(0.5, abs=1e-3)
assert SPREAD_MIN <= learned_spread([_srow(-1.0, [0, 0], 0.5)] * 30, sig) <= SPREAD_MAX
assert learned_spread([_srow(1.0, [0, 0], 0.5)] * 30, sig) == pytest.approx(LEARN_MAX, abs=1e-3)
assert SPREAD_MIN <= learned_spread([_srow(-1.0, [0, 0], 0.5)] * 30, sig) <= LEARN_MAX
def test_dislikes_of_small_changes_never_grow_the_size():
from modules.sampling.attention_bandit import START_SPREAD, learned_spread
assert learned_spread([_srow(-1.0, [0, 1], 0.1)] * 20, [2, 0, 9]) == START_SPREAD
assert learned_spread([_srow(-1.0, [0, 1], 0.4)] * 20, [2, 0, 9]) < START_SPREAD
def test_the_log_names_exact_blocks_and_skips_the_unchanged():