Skip to content

Add from scratch pretrain converter#1506

Open
Cacapice wants to merge 1 commit into
TransformerLensOrg:devfrom
Cacapice:add-from-scratch-pretrain-converter
Open

Add from scratch pretrain converter#1506
Cacapice wants to merge 1 commit into
TransformerLensOrg:devfrom
Cacapice:add-from-scratch-pretrain-converter

Conversation

@Cacapice

Copy link
Copy Markdown

Description

Adds a weight converter and loader that bring checkpoints from an external
from-scratch pretraining framework into HookedTransformer, so a
foundation model trained outside the HuggingFace ecosystem can be analysed with
the standard TransformerLens hook API (run_with_cache, resid_post, etc.).

The source architecture is a decoder-only transformer with RoPE (adjacent-pair
rotation), RMSNorm, SwiGLU MLPs, and optional dropless top-k Mixture-of-Experts.
Its checkpoints are not loadable through from_pretrained because they are not
a HuggingFace model; this PR follows the same pattern as the existing
nanogpt / mixtral converters to support them.

Motivation: this is the base-model half of an interpretability project — the
model whose residual stream downstream linear probes read. Loading it into
TransformerLens means the probing side can use the library's tooling directly
instead of a bespoke activation-extraction path.

Fixes # (no issue — new-feature contribution)

Type of change

New feature (non-breaking change which adds functionality)
This change requires a documentation update (docstrings included; happy
to add a docs/ loading example if the maintainers would like one)

What's included

weight_conversions/maritime_pretrain.py — convert_maritime_pretrain_weights.
Splits the fused QKV projection into per-head W_Q/W_K/W_V, maps SwiGLU
gate/up/down onto TransformerLens's W_gate/W_in/W_out, and (for MoE) emits
the router plus every expert under the names MoE/MoEGatedMLP expect. No
Q/K reordering is needed because RoPE is applied inside attention, not baked
into the weights.
pretrained/maritime_pretrain_loader.py — build_config and
load_maritime_pretrain. Builds the matching HookedTransformerConfig
(positional_embedding_type="rotary", rotary_adjacent_pairs=True,
normalization_type="RMS", final_rms=True, gated_mlp=True, and
num_experts/experts_per_token/norm_topk_prob for MoE), merges
tensor-parallel weight shards, and returns a ready HookedTransformer.
weight_conversions/init.py — export the new converter (alphabetical).
Tests — tests/unit/pretrained_weight_conversions/test_maritime_pretrain.py.

Key correctness detail

The source rotates adjacent RoPE pairs ([x0, x1] -> [-x1, x0]), which maps to
rotary_adjacent_pairs=True (the GPT-NeoX-style d -> (d 2) frequency layout),
not the default half-split convention. Getting this wrong still loads without
error but silently corrupts every activation, so the equivalence tests below are
the real guardrail.

Checklist

I have commented my code, particularly in hard-to-understand areas
I have made corresponding changes to the documentation (module + function docstrings)
My changes generate no new warnings
I have added tests that prove my feature works
New and existing unit tests pass locally with my changes
I have not rewritten tests relating to key interfaces which would affect backward compatibility

Test evidence

test_maritime_pretrain.py asserts bit-exact logit equivalence between the
source model and its converted HookedTransformer, parametrised across the axes
a future change is most likely to break, plus structural, failure-path and
tensor-parallel coverage (13 tests):

dense and MoE MLPs
tied and untied embeddings
four (d_model, n_heads) combinations
converter key/shape correctness for the MoE branch
a config/checkpoint shape mismatch raises a clear ValueError (not an opaque
reshape error)
tensor-parallel shard merge reconstructs the original weights for
N ∈ {1, 2, 4} shards

$ python -m pytest tests/unit/pretrained_weight_conversions/test_maritime_pretrain.py -q
13 passed

Observed max|Δlogit| between source and converted model ≈ 1e-5
(floating-point noise) across every parametrisation. Converter validates each
source weight's shape before reshaping, so a mismatched config fails with an
actionable message. Files formatted with the repo's pinned black==23.3.0 /
isort==5.8.0; pylint 10.00/10 and pyright clean on the new modules.

Notes / open questions for reviewers

Naming. I've used the project-specific name maritime_pretrain to mirror
nanogpt. If you'd prefer a generic name (e.g. swiglu_moe_gpt) since the
converter isn't domain-specific, I'm glad to rename.
Loader placement. The loader lives at pretrained/maritime_pretrain_loader.py
rather than being wired into loading_from_pretrained.py, because these
checkpoints load from a local run directory, not a hub ID. If you'd rather
register it as an official model source, point me at the preferred hook.
Targeting dev per the contribution guidelines (this is a feature, not a
fix against the released version).

@Cacapice Cacapice force-pushed the add-from-scratch-pretrain-converter branch 2 times, most recently from 4768b46 to 63ed83c Compare July 11, 2026 07:32
Adds a converter and loader that bring checkpoints from an external
decoder-only pretraining framework (RoPE with adjacent-pair rotation,
RMSNorm, SwiGLU, optional dropless top-k MoE) into HookedTransformer so
their residual streams can be read with the standard hook API.

- convert_maritime_pretrain_weights: splits the fused QKV projection into
  per-head W_Q/W_K/W_V, maps SwiGLU gate/up/down onto W_gate/W_in/W_out,
  and emits router + per-expert weights under the MoE component's names.
- maritime_pretrain_loader: builds the matching HookedTransformerConfig
  (rotary_adjacent_pairs=True, normalization_type=RMS, gated_mlp=True,
  norm_topk_prob=True for MoE), merges tensor-parallel shards, returns a
  ready HookedTransformer.
- Tests assert bit-exact logit equivalence (max|delta| < 1e-4) for both
  dense and MoE configs plus converter key/shape correctness.
@Cacapice Cacapice force-pushed the add-from-scratch-pretrain-converter branch from 63ed83c to 1616b7d Compare July 11, 2026 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant