maxact-fast
Train a model to generate text that maximally activates an arbitrary linear direction in its own residual stream, conditioned activation-oracle style (direction injected at layer 1, maximized at layer L). The bet: if we pretrain on a huge, diverse set of directions — not just SAE features — the model learns a general residual-direction→text inverter that transfers to SAE features for free (cross-uplift).
The direction firehose (why this beats SAE-only conditioning)
SAE conditioning caps you at ~65k features and inherits the SAE's blind spots. Instead we mint an effectively unlimited, diverse supply of concept directions straight from a corpus:
- Embed a large corpus (UltraFineWeb, streamed) with a fast embedding model (BGE) — cheap.
- Cluster the embeddings into K≈10k clusters (faiss k-means, GPU). Each cluster ≈ a concept.
- For a training example, sample cluster A vs cluster B, train a quick linear probe on the
policy model's layer-L residuals to separate A from B. The probe weight vector
wis the conditioning direction — same space as an SAE encoder column, so it drops straight into the existing inject@1 / read@L machinery. - SFT target = the few real corpus texts closest to cluster A's centroid. "Given direction
w, write text like this." - Pretrain on millions of these (shuffled). Then RL (Dr. GRPO, no KL) on cluster-probes and/or SAE features, and measure whether cluster-pretraining lifts SAE-feature performance.
Probe residuals are cached once per cluster (the only expensive Qwen3 pass), so step 3-4 mint millions of (direction, targets) examples cheaply.
Objective & injection (unchanged from the activation-oracle line)
- Inject
unit(w) * ‖resid‖ * coeffinto the layer-1 residual at a?marker (norm-matched add). - Reward = max over token positions of
(x_L − μ)·unit(w), measured on the STANDALONE re-tokenized generation through the clean base model (no adapter, no injection). Same fair protocol as before.
RL = Dr. GRPO, done right, no KL
- advantage =
r − group_mean— no/std(the removed Dr. GRPO difficulty bias). - loss =
Σ_tokens(−min(ratio·A, clip(ratio)·A) · mask) / total_tokens_in_batch(global constant normalizer, no per-response length bias). - No KL term. Stability comes from lr + grad-clip + fluency/distinct gates (optional), not a leash.
- Rollouts via vllm-lens (
SteeringVector(norm_match=True)== our injection), ~5× vs HF generate. - Reuse vLLM generation logprobs as
old_logps(one on-policy update/batch → ratio≈1, no extra fwd).
Pipeline stages (each a CLI in scripts/)
embed_cluster— stream corpus → BGE embeddings → faiss k-means K clusters → cluster assignments.cache_resids— per cluster, run M member texts through Qwen3, cache layer-L mean residuals.build_data— sample cluster pairs, train probes on cached resids, pick centroid targets → (direction, target_text) shards. Millions.pretrain— SFT the generator (AO/LoRA) on the direction→text firehose. Massive.finetune— final polish on per-feature MAX-activating CORPUS examples (cleanest targets).rl— Dr. GRPO (no KL), vllm-lens rollouts, on cluster-probes and/or SAE features.eval— beat-corpus / normalized-activation on held-out SAE features (cross-uplift test).interface— tiny gradio app: type/pick a direction, watch generations + live activation.
Speed principles
bf16 + flash-attn everywhere; faiss-GPU k-means; HF streaming (never materialize the corpus); cache the one expensive Qwen3 residual pass; vLLM-lens rollouts; batchmax forwards on H200; torch.compile the training step. Target: pretraining data mine + pretrain in a day, not a week.