Skip to content
VipDataTool edited this page Jul 31, 2026 · 23 revisions

TAGM Documentation

Transformer Alignment Gradient Metrology

This document explains TAGM in full: what it measures, how each feature works, what every parameter does, and where the numbers on the screen come from. It is written against the current source; wherever the code documents its own reasoning (or its own arbitrary choices), that reasoning is quoted or summarized here rather than invented.

A short orientation for newcomers is first; reference material (parameters, endpoints, storage) is toward the end.


Table of contents

  1. What TAGM is
  2. Core concepts
  3. The basic workflow
  4. Model loading and the delta pipeline
  5. The Analyze panel: flags and what they compute
  6. Core metrics reference
  7. Advanced Parameters (engine config) reference
  8. Analysis modules
  9. The probe system
  10. Entropic Cascade Mitigation (ECM)
  11. Chat and the Roundtable LMA
  12. High-Efficiency Pipeline (HEP)
  13. Visualizations
  14. Storage, sessions, and export
  15. HTTP API reference
  16. Research tools (offline harnesses)
  17. Honesty notes and known rough edges

1. What TAGM is

TAGM is a mechanistic-interpretability instrument built around one idea: the difference between a base model's weights and its instruction-tuned sibling's weights is itself an object you can measure prompts against.

Alignment tuning (instruction tuning, RLHF, and similar) changes a model's weight matrices. Subtract the base weights from the instruct weights and you get the deltas — a set of matrices that encode, in aggregate, everything the tuning did. Those deltas define directions in the model's internal space. When a prompt's activations project strongly into those directions, the tuning is exerting force on that prompt; when they don't, the prompt passes through largely as the base model would have processed it.

TAGM loads a base/instruct pair, computes the deltas once, then runs prompts through the instruct model with hooks installed and measures — token by token, layer by layer — how each prompt interacts with the delta geometry. The output is a set of per-prompt signatures (stress, signed attribution, lateral tension, spectral density, rank displacement, and more) that can be compared across prompt categories with bootstrap statistics, explored in interactive 3D visualizations, and subjected to causal tests (direction ablation and steering).

Everything runs in a browser dashboard served by a FastAPI backend, with a SQLite database for persistence. The instrument is CPU-friendly by design and comfortable with sub-1B parameter model pairs on a 4-core / 16 GB machine.

Lineage. TAGM grew out of an earlier instrument called TASM, and the TASM name survives throughout the source (TASMModule, "TASM-compatible", flat-result conventions). Metric definitions were kept bit-compatible with TASM where the code says so explicitly (the spectral profiling notes it matches TASM's outputs "bit-for-bit"; engine config defaults "reproduce TASM's original behavior").

A caution the codebase itself makes. None of TAGM's metrics is presented as a validated safety measure. They are instrument readings. The statistics module exists so you can test whether they separate your prompt categories, and two of the bundled offline tools exist specifically to attack the metrics' validity (see Research tools).


2. Core concepts

A short glossary. Each term gets a fuller treatment later.

Model pair. A base checkpoint and its instruction-tuned sibling — e.g. Qwen2.5-0.5B and Qwen2.5-0.5B-Instruct. TAGM's unit of study.

Delta (ΔW). For each weight matrix W, the difference W_instruct − W_base. Deltas are computed per layer, per role.

Role. Which projection a delta belongs to: q, k, v, o (the attention projections) or gate, up, down (the MLP projections). The DeltaStore is addressed by (layer, role).

Adapter. The model-family abstraction. All family-specific knowledge — module paths for hooks, projection key names in safetensors, unembedding access, GQA head geometry — lives in one ModelAdapter subclass per family. Shipped adapters: qwen2 (Qwen 2.x) and llama3 (Llama 3.x). Family detection is automatic via the HuggingFace config's model_type.

Signal layers. The middle third of the model's layers by default (controlled by signal_layer_fraction). Most extraction functions read only these layers, on the working assumption that early layers do tokenization-adjacent work and late layers collapse toward the unembedding. For a 24-layer model, the default signal region is layers 8–15.

Session. One experimental run. A new session is created every time a model pair is loaded. All analyzed prompts land in the current session; modules operate over the session's records.

Category. A free-text label attached to each prompt (benign, harmful, jailbreak, mild, …). Categories are how you tell the statistics and the direction-fitting modules which prompts belong to which class. The bundled prompts.csv uses benign / mild / harmful; several modules default their class definitions to harmful,jailbreak,unknown vs benign,mild.

Probe / probe set. Short texts arranged in a subject × subclass lattice, embedded through the model at fixed depths. Probes give the correction-signal metrics a semantic coordinate system — instead of "token 7 has high stress," you can say "tokens in this topic region attract correction." Three modules require an active probe set.

Counterfactuals. At every prompt position, the model has a ranked list of tokens it would have preferred. TAGM extracts the top-k alternatives (excluding the actual token) with full-vocabulary softmax probabilities — the code is explicit that probabilities are never renormalized over the top-k subset, so instruct-model and base-model masses are directly comparable.


3. The basic workflow

  1. Start the server (bash start.sh), open http://localhost:8000.
  2. Register a model pair — Configuration tab → model pairs, or POST /api/models with a name, base ID, and instruct ID (HuggingFace repo IDs).
  3. Load the pair. Loading downloads the instruct model, streams the base weights from disk to compute deltas, spectrally profiles each delta, and opens a fresh session. Progress streams to the sidebar over SSE.
  4. Analyze prompts. Type a prompt and pick a category in the Data tab, choose which measurements to compute (the flag checkboxes), and click Analyze — or upload a CSV of prompts for a batch run. Analysis is asynchronous; the dashboard updates when the analyze_done event fires.
  5. Inspect results. The dashboard table shows the indexed scalar metrics per prompt. Clicking a row loads the full record — per-token arrays, plots, counterfactual tables.
  6. Run modules. The Modules tab holds seventeen post-collection analysis modules — from cross-category statistics to causal ablation experiments to 3D terrain visualization. Each module has its own parameter card; Run executes it in a background thread over the session's data.
  7. Export. One zip containing the full session plus every module's report.

A useful mental model: collection is expensive, analysis is cheap. The forward passes and generation happen at steps 4 and (for some modules) 6; most modules re-read stored records, so you can iterate on their parameters freely without re-running inference. The ECM module makes this explicit — its v3 redesign exists precisely so detector settings apply at module-Run time instead of collection time.


4. Model loading and the delta pipeline

What happens on load

Pipeline.load() does the following, in order:

  1. Load the instruct model via AutoModelForCausalLM (default dtype bfloat16, device CPU).
  2. Auto-detect the adapter from the model config's model_type. If no registered adapter matches, loading fails with a message listing the registered families.
  3. Compute deltas from disk. This is the codebase's single largest memory-discipline decision, and its docstring says so: the base model is never instantiated just to diff weights. Instead, the base checkpoint's safetensors files are read one tensor at a time; for each projection key the adapter recognizes, the delta W_instruct − W_base is computed and stored, and the base tensor is freed. For a 7B pair, holding both models in memory just to subtract them would cost roughly double the model memory; streaming avoids that entirely.
  4. Spectral profiling. Each delta gets an SVD-derived profile: effective rank (exp of the Shannon entropy of the normalized singular values), stable rank, and top-k energy shares (k = delta_svd_k, default 64). Interpretation, per the source: a low effective rank means tuning made a surgical, few-direction correction to that matrix; a high effective rank means it reshaped the whole subspace.
  5. Open a fresh session in the database, tagged with the instruct model ID.

An optional layer_filter restricts delta computation to specific layers. The DeltaStore remembers the filter it was built under: a consumer asking for an excluded layer gets a descriptive LayerNotComputedError ("re-load with a wider filter") instead of a bare KeyError ("this layer doesn't exist").

The base model afterward

The base model is loaded lazily, only when something actually needs its forward pass: KL/top-k behavioral comparison, LTP base profiles, or base-model chat (POST /api/set_inference_model with inference_class="base" loads it at toggle time, not per message).

Delta backends

Deltas live in RAM by default (delta_backend: "memory"). The High-Efficiency Pipeline switches them to memory-mapped files on disk — see section 12.


5. The Analyze panel

Every analysis run — single prompt or batch CSV — is controlled by a set of flags. Each flag turns on a measurement; each measurement adds fields to the stored record. The single-prompt and batch paths share one implementation; the only difference is that trajectory capture defaults ON for single prompts and OFF for batches (batch volume).

Prompts are capped at 5000 characters. Batch CSVs need a prompt column and an optional category column.

Flag (form field) What it computes Cost profile
(always on) Tokens, stress score, signed attribution + proof-1 checks, delta scale, domain embeddings The baseline single forward pass
compute_trajectory Amplitude trajectory across all sublayers + the sublayer × token heatmap Hooks every layer instead of just the signal region
full_capture Everything trajectory does, plus per-token coherence, spectral rank, attn/MLP split, and the token-similarity matrix; also captures attention weights at all layers The heaviest per-prompt option; needed by the MI Instrumentation module (per_token_final_emb consumers)
compute_kl KL divergence between instruct and base next-token distributions Requires a base-model forward pass
capture_responses Top-k next-token predictions from both models Base-model forward pass
compute_ltp Lateral Tension Profile (per-token profiles, counterfactuals, tension trajectory) The most math-heavy extraction; also triggers the base pass for base profiles
ltp_k How many counterfactual alternatives per position (default 8) Larger k = wider profiles, more storage
ltp_layer_strategy signal (default — the signal layers) or late (final third of layers)
ltp_svd_rank If > 0, LTP uses an SVD-truncated ΔW_V retaining this many singular directions (cached per rank for the model's lifetime) First use per rank pays the SVD
compute_sfd Spectral Field Density + per-token spectral directions First use builds the per-layer SVD cache, then cheap
compute_ecm Replays the cascade detector over the record's traces and attaches the diagnostics Cheap; pure post-processing
harvest_responses Generate a response for the prompt while the instruct model is resident, and analyze it as its own record (category suffixed :response) Adds a generation per prompt
ecm_harvest_tokens Response length for harvests, in tokens; 0 = prompt-only
deconstruct Expand the prompt into its prefix ladder and analyze every rung as its own record Multiplies the run by the number of rungs

When compute_sfd or compute_ltp is on and LTP counterfactuals exist for both models, rank displacement is computed as well.

Deconstruction in detail

With Deconstruct on, I like cake. becomes an ordered ladder:

I
I like
I like cake
I like cake.

Each rung is a genuine prompt — its own forward pass, its own record — tagged with family_index (which original prompt) and rung_index (position in the ladder) so the dashboard and modules can regroup them. Two policy decisions are documented in the source:

  1. Punctuation runs earn their own rung. The period is rung 3, not glued to cake, because punctuation shapes how the model builds context; a run of punctuation (...) is one rung, not three.
  2. Rungs are literal prefixes — cut points at unit boundaries, text[:cut], never rebuilt from pieces. The final rung is byte-identical to the input, so you never measure a re-spacing or re-tokenization artifact instead of the real effect. Intra-word apostrophes and hyphens stay attached (don't, well-being), so noise rungs like don' never appear.

Asynchronous contract

POST /api/analyze and POST /api/analyze_batch both return {"ok": true, "started": true, "n_prompts": N} immediately. Completion is announced exactly once as an analyze_done event on the GET /api/events SSE stream, with payload {ok, n_results, n_prompts, n_errors, error}. Results are persisted individually as they are produced (add_result() is a single database INSERT); there is no separate save step, and a crash mid-batch keeps everything already analyzed.

Re-running

POST /api/session/rerun re-analyzes specific stored prompts with the current settings, replacing their records in place. Deconstruction identity (family_index/rung_index) is deliberately preserved from the old record so ladder membership survives a rerun.

Clone this wiki locally