Refine initialization, objectives, and evaluation - #1001
Merged
Merged
Conversation
danbraunai-goodfire
approved these changes
Sep 4, 2026
Antovigo
added a commit
to Antovigo/spd
that referenced
this pull request
Sep 5, 2026
…ite kind Upstream 964d8ba "Refine initialization, objectives, and evaluation" (goodfire-ai#1001) into feature/dual_obj_jax. 38 conflicts; the local dual objective, tPD delta pinning, AB grid, two-stream eval namespace and frozen-stack split all survive. Resolutions worth naming: * INITS. goodfire-ai#1001 introduced `ComponentInitializer`, a target-aware V/U seeding seam, and its own data-free `neuron_aligned` init. This branch's `pd.weight_init` enum is retired wholesale: `default`/`coupled`/`zero_u` are gone (none beat the alternatives) and `neuron_aligned_targeted` is re-expressed as a `ComponentInitializer`. The config surface moves from `pd.weight_init` to `decomposition.sites.initialization` + `.neuron_ranks`, so the arms live where the sites they seed are authored. * NEURON-ALIGNED TARGETED now aligns EVERY decomposed site, attention included — no `zero_u` fallback, so `validate_neuron_alignment` demands an entry per site. The harvest produces five rankings per block instead of one: mlp neurons by write energy, q and k channels by their own projection-output energy (attention mixes across positions, never across channels, so q_j and k_j meet only inside their head's dot product and rank independently), o channels by E[z^2]*||W_o[:,j]||^2, and v channels by that summed over the GQA group — v channel (g,d) IS attention channel (h,d) for every h in group g. Statistic renamed `unit_energy`; the read side refuses the old `write_energy` artifacts rather than misaligning silently. The per-coordinate factorization is now `glu_transformer.selected_unit_factors`, shared with the data-free init. * IMP-MIN. goodfire-ai#1001 deleted the L_p penalty and gave its NAME to smooth-L0, so `SmoothL0ImportanceMinimalityLoss` -> `ImportanceMinimalityLoss` everywhere. The local `normalize_at_one` rescale survives as a defaulted keyword. The tPD TMS goldens are re-recorded: that fixture's `pnorm=1.0` became `gamma=1.0`, a different per-value penalty, and the merged step now reproduces upstream's own goldens to 12 significant digits under this branch's non-target key spelling. * EVAL. Upstream's shared per-batch context (one clean forward + CI envelope per batch, folded by `BatchedOperation`) replaces per-operation forwards, and this branch's per-stream/per-role fan-out rides on top: `LMBatchContext` carries its `Stream`, holds the whole `AnyCI` envelope, and each operation folds only the stream it measures and reads its own head via `ci_for(role)`. Delta pinning (SPEC T4) is preserved on all three non-target recon families and now has a BINDING-level guard, not only kernel-level ones — an unpinned non-target probe measures a delta->0 attack no component-side training can defend, which reads as a decomposition failure that is really a measurement bug. * Also adopted: GQA-aware nonlinearity locality (QueryHeads/KVHeads, soft USE counts), the padded-CI attention API, and the whole-tree test relocation. Dropped with upstream: `hidden_acts_eval.py` and both hidden-acts eval metrics. 1317 tests pass. The one failure, `test_no_checkpointing::test_sigterm_exits_ without_saving`, is its own 300s deadline expiring under 16-way xdist contention; it passes in 41s alone. ruff + basedpyright clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Antovigo
added a commit
to Antovigo/spd
that referenced
this pull request
Sep 6, 2026
Replaces p-222d379b (addsub-L18-18, pre-goodfire-ai#1001 pd.weight_init schema) with p-6540dfdd (addsub-L18-23, post-goodfire-ai#1001), which is the current aligned init and covers every site kind including attention. - general text: aligned is ~22% easier to attack at 100 steps (0.0127 vs 0.0104), more than twice either run's own adversary-start spread - the older run read 12% - task distribution: aligned is ~10% HARDER to attack (0.0047 vs 0.0052), a new direction the older pairing could not resolve (its spread reached 24%) - both inits still saturate by ~40 steps, so the nonlinearity penalty's runaway remains specific to that penalty The two runs straddle goodfire-ai#1001 and no single build opens both; verified before comparing that the probe computation is identical across the merge (core recon/ adversary/masking/recon byte-identical, eval-side change a pure refactor) and that probe inputs match, so the curves are comparable. Recorded in the caveats. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011EqWYtK2A5PugNTcQx2iAE
Antovigo
added a commit
to Antovigo/spd
that referenced
this pull request
Sep 11, 2026
Antoine wants to test `zero_u` again on the merged branch. The arm was retired with `pd.weight_init` in the goodfire-ai#1001 merge (8b38226); this brings it back in the shape goodfire-ai#1001 introduced — a plain `ComponentInitializer`, the same seam `random` and the two aligned inits already use — rather than reviving the enum branch in `run_state`. `zero_u` is the target-coupled seed's `V` with `U` zeroed: the component sum is exactly zero at init and the delta carries all of `W`, so a subcomponent acquires norm only as the reconstruction losses demand it instead of starting with `W`-scale weight a mask adversary could switch on. `V` still feeds the CI nets a live signal, and `U` has a nonzero gradient from step 0 (`V`'s is zero until `U` moves off zero). THE PROPERTY THAT MAKES THE TEST WORTH RUNNING, and the one most likely to rot silently: the per-site keys are split exactly as the retired arm split them — `split(key, len(sites))` indexed by site position — and `V` is `_coupled_site_vu`'s `V`. So a run here reproduces the pre-goodfire-ai#1001 zero_u `V` bit for bit at one seed, which is what makes p-88665048 a control rather than a different experiment. `test_v_is_the_coupled_seed_with_the_pre_1001_key_discipline` pins it. Shape of the port: - core/components.py restores `zero_component_stacks` and `_coupled_site_vu` (both deleted by the merge) and adds `init_component_stacks_zero_u`. `coupled` itself is NOT restored: zero_u is built directly as coupled-V-plus-zero-U, so there is no dead public API for an arm nobody can select. - core/init_placed.py adds `zero_u_component_initializer` plus `_site_weights_in_graph`, which reads each site's frozen `W` INSIDE the init graph through the zero-stacks `weight_deltas` identity, so no full-precision copy crosses the jit. - Domain-neutral by construction: `W` is reached only via `weight_deltas`, which every `DecomposedModel` implements, so the toys can select it as readily as the LM. - Config: `zero_u` joins `ComponentInitialization`, dispatches in `load_run.component_initializer_for`, and the capacity validator short-circuits on `random | zero_u` — the aligned arms' `C <= coordinate count` bound does not apply. 1007 tests pass (9 new); ruff and basedpyright clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
ImportanceMinimalityLossand updates canonical configs and guidance.Related Issue
N/A.
Motivation and Context
These changes keep initialization, minimality, and evaluation behavior consistent as the library grows, while making the supported configuration and test surfaces easier to follow.
How Has This Been Tested?
uv lock --checkuv run ruff format --checkuv run ruff checkuv run basedpyrightDoes this PR introduce a breaking change?
Yes. Legacy Lp importance-minimality configuration is replaced by the smooth-L0
ImportanceMinimalityLossfields, and the standalone hidden-activation evaluator is removed in favor of shared evaluation context. Existing callers using those retired paths must migrate.Diff breakdown