transformer_lens.tools.analysis.logit_lens module¶
Logit lens and vocabulary readout.
The logit lens
reads every intermediate residual-stream state through the model’s own final
norm and unembedding, so each layer can be asked “what would the model predict
if it stopped here?”. logit_lens() does that in one call over a cache’s
accumulated residual stream; logit_readout() is the kernel underneath it
and reads any d_model vector (a head output, a steering direction, a
sparse-coder decoder column) through the same path.
Both go through the real ln_final module, W_U, b_U and the
adapter’s post-unembedding transform (Gemma-style softcap, Cohere logit scale),
so the final stack entry reproduces the model’s own logits on a raw bridge and
the model’s log-probabilities in compatibility mode (center_unembed shifts
raw logits by a per-position constant). Logits are produced chunk by chunk, so
[layers, batch, pos, d_vocab] is never materialized unless the full
vocabulary is explicitly requested.
Example:
from transformer_lens.model_bridge import TransformerBridge
from transformer_lens.tools.analysis import logit_lens
model = TransformerBridge.boot_transformers("gpt2", device="cpu")
result = logit_lens(model, "The Eiffel Tower is in the city of", targets=" Paris")
for label, rank in zip(result.labels, result.rank_trajectory(" Paris").tolist()):
print(f"{label:>12}: rank {rank}")
# Rank of the actual next token at every position and layer: a per-row target.
tokens = model.to_tokens("The Eiffel Tower is in the city of Paris")
nxt = logit_lens(model, tokens[:, :-1], positions=None, targets=tokens[:, 1:])
nxt.rank_trajectory() # [layers, batch, pos]
- class transformer_lens.tools.analysis.logit_lens.LogitLensResult(readout: LogitReadout, labels: List[str], has_batch_dim: bool, target_names: List[str | None] | None = None)¶
Bases:
objectResult of
logit_lens().- readout¶
The
LogitReadoutover the accumulated stack. Its leading axis is the stack entry, aligned withlabels; the remaining leading dims are[batch, pos]after the requestedpositions/batch_slice(an integer selection drops its axis).
- labels¶
Stack entry labels from
accumulated_resid("0_pre","3_mid","final_post").- Type:
List[str]
- has_batch_dim¶
Whether a batch axis follows the stack axis.
- Type:
bool
- target_names¶
For shared targets, the string passed for each target (
Nonewhere an id was passed), sorank_trajectory()accepts the strings again.- Type:
List[str | None] | None
- has_batch_dim: bool¶
- labels: List[str]¶
- rank_trajectory(target: str | int | None = None) Tensor¶
Full-vocabulary rank of one target at every stack entry,
[layer, ...].targetis the string passed totargetsor a token id;Noneselects the only target when exactly one was requested, and is the only form for per-row targets.
- readout: LogitReadout¶
- target_names: List[str | None] | None = None¶
- to_dataframe(tokenizer: Any | None = None, top_k: int | None = None) Any¶
One row per (stack entry, batch, position, token) as a pandas DataFrame.
Rows within a (layer, batch, pos) group are sorted by descending value and
top_kkeeps the leading ones. Full-vocabulary"logits"readouts go throughtransformer_lens.utilities.logits_utils.logits_to_df()(columnslogit,log_prob,probability); every other readout carriestoken_index, optionaltoken_stringand one value column named likelogits_to_dfnames it (logit/log_prob/probability).
- top_tokens(tokenizer: Any) Dict[str, Any]¶
Decoded top-k tokens per stack entry,
{label: nested lists}.
- property values: Tensor¶
Shortcut for
readout.values.
- class transformer_lens.tools.analysis.logit_lens.LogitReadout(values: Float[Tensor, '... selected'], return_type: str, entropy: Float[Tensor, '...'], top_ids: Int[Tensor, '... k'] | None = None, vocab_ids: Int[Tensor, 'v'] | None = None, target_ids: Tensor | None = None, target_ranks: Int[Tensor, '... t'] | None = None, per_row_targets: bool = False, applied_ln: bool = True, applied_output_transform: bool = True)¶
Bases:
objectResult of
logit_readout().Exactly one of the three selectors expands the trailing axis of
values:targetsgives[..., n_targets]([..., 1]for per-row targets),top_kgives[..., k]withtop_ids,vocabgives[..., len(vocab)]; with none of them the trailing axis is the full vocabulary.entropyandtarget_ranksare always computed over the full vocabulary, whatever was selected.- values¶
The requested quantity (see
return_type) with the leading dims of the input vectors and the selected trailing axis.- Type:
jaxtyping.Float[Tensor, ‘… selected’]
- return_type¶
"logits","log_probs"or"probs".- Type:
str
- entropy¶
Full-vocabulary entropy of the softmax, in nats,
[...].- Type:
jaxtyping.Float[Tensor, ‘…’]
- top_ids¶
Token ids aligned with
valueswhentop_kwas used.- Type:
jaxtyping.Int[Tensor, ‘… k’] | None
- vocab_ids¶
The requested subset ids when
vocabwas used.- Type:
jaxtyping.Int[Tensor, ‘v’] | None
- target_ids¶
Shared targets as
[n_targets]; per-row targets as a tensor with the leading dims of the vectors (one id per row).- Type:
torch.Tensor | None
- target_ranks¶
Zero-based full-vocabulary rank of each target (0 is the argmax; ties count only strictly larger logits), aligned with
values.- Type:
jaxtyping.Int[Tensor, ‘… t’] | None
- per_row_targets¶
Whether
targetswas given per row (a tensor).- Type:
bool
- applied_ln¶
Whether the model’s final norm was applied to the vectors.
- Type:
bool
- applied_output_transform¶
Whether the adapter’s post-unembedding transform was invoked (it is the identity for most architectures).
- Type:
bool
- applied_ln: bool = True¶
- applied_output_transform: bool = True¶
- decode(tokenizer: Any) Any¶
Decode the trailing-axis token ids to strings, keeping the leading structure.
top_kand per-row readouts decode per row; sharedtargets/vocabreadouts decode the id list once. Full-vocabulary readouts have no id list to decode.
- entropy: Float[Tensor, '...']¶
- per_row_targets: bool = False¶
- return_type: str¶
- row_ids(index: Tuple[int, ...]) Tensor | None¶
Trailing-axis token ids for one row of
values(None= full vocabulary).
- property selected_ids: Tensor | None¶
Token ids along the trailing axis of
valueswhen it is not the full vocabulary.
- target_ids: Tensor | None = None¶
- target_ranks: Int[Tensor, '... t'] | None = None¶
- top_ids: Int[Tensor, '... k'] | None = None¶
- values: Float[Tensor, '... selected']¶
- vocab_ids: Int[Tensor, 'v'] | None = None¶
- transformer_lens.tools.analysis.logit_lens.logit_lens(model: Any | ActivationCache, input: str | List[str] | Tensor | None = None, *, cache: ActivationCache | None = None, layers: Sequence[int] | None = None, incl_mid: bool = False, positions: int | integer | Tuple[int] | Tuple[int, int] | Tuple[int, int, int] | List[int] | Tensor | ndarray | None = -1, batch_slice: int | integer | Tuple[int] | Tuple[int, int] | Tuple[int, int, int] | List[int] | Tensor | ndarray | None = None, lens: Callable[[Tensor, int], Tensor] | None = None, apply_ln: bool = True, vocab: Sequence[int] | Tensor | None = None, targets: str | int | Sequence[str | int] | Tensor | None = None, return_type: str = 'logits', top_k: int | None = None, chunk_size: int = 64, enable_grad: bool = False) LogitLensResult¶
Read the accumulated residual stream through the final norm and unembedding.
Builds the stack with
accumulated_resid(), optionally applies a per-entrylenstranslator, applies the final norm throughapply_ln_to_stack()with recomputed statistics, and hands the result tologit_readout(). The final stack entry reproduces the model’s logits (raw bridge) or log-probabilities (compatibility mode).- Parameters:
model – A
TransformerBridge, or anActivationCache(theninputmust be omitted).input – Prompt(s) or token tensor to run when no
cacheis given. Only the residual-stream hooks are cached. A batch of strings is padded by the tokenizer, so with the defaultpositions=-1the shorter prompts are read at a pad position; pass a token tensor (or per-prompt positions) when prompts differ in length.cache – An existing cache to read instead of running the model.
layers – Indices into the accumulated stack (negative allowed);
Nonekeeps every entry.incl_mid – Include
resid_midentries. Raises on hybrid stacks whose SSM blocks have noresid_mid.positions – Position selection (
Slicesemantics); default last token.batch_slice – Batch selection (
Slicesemantics).lens – Optional
f(entry, index) -> entryapplied to each stack entry before the norm, e.g. a tuned-lens translator. Combine withenable_grad=Trueto fit or attribute through it.targets – As in
logit_readout(); a per-row tensor is aligned with the stack’s[batch, pos]dims afterpositionsandbatch_sliceare applied ([batch, pos]next-token ids withpositions=None,[batch]with the default last position).apply_ln – As in
logit_readout().vocab – As in
logit_readout().return_type – As in
logit_readout().top_k – As in
logit_readout().chunk_size – As in
logit_readout().enable_grad – As in
logit_readout().
- Returns:
- transformer_lens.tools.analysis.logit_lens.logit_readout(model: Any, vectors: Float[Tensor, '... d_model'], *, apply_ln: bool = True, vocab: Sequence[int] | Tensor | None = None, targets: str | int | Sequence[str | int] | Tensor | None = None, return_type: str = 'logits', top_k: int | None = None, chunk_size: int = 64, enable_grad: bool = False) LogitReadout¶
Read
d_modelvectors through the model’s final norm and unembedding.Computes
transform(ln_final(x) @ W_U + b_U)for every vector, wheretransformis the adapter’s post-unembedding transform, in chunks ofchunk_sizerows so at mostchunk_size × d_vocablogits exist at once. Everything derived from the full vocabulary (the softmax normalizer,entropy,target_ranks) is computed per chunk and discarded; only the selected columns are kept.- Parameters:
model – A
TransformerBridgein eval mode.vectors – Residual-stream-shaped vectors, any leading dims.
apply_ln – Apply the model’s
ln_finalmodule first (recomputed statistics per vector).Falsereads the raw vectors and does not reproduce the model.vocab – Token ids to keep along the trailing axis.
targets – Tokens whose values and full-vocabulary ranks to report. Strings (single tokens) or ints, or a sequence of them, are shared across every row. A tensor is per row: it is right-aligned and broadcast to the vectors’ leading dims (for
[batch, pos, d_model]vectors pass[batch, pos]next-token ids, or[batch, 1]for one id per example) and the trailing axis ofvalueshas length 1. Note the convention differs fromActivationCache.logit_attrs, which reads a 1-D tensor as per-example first; here alignment is purely right-to-left.return_type –
"logits","log_probs"or"probs".top_k – Keep the
klargest-logit tokens per vector, with their ids.chunk_size – Rows of
vectorsprocessed per unembedding matmul.enable_grad – Keep autograd on (for trainable lenses and attribution); default runs under
torch.no_grad().
- Returns:
A
LogitReadout.- Raises:
ValueError – On a bad
return_type, more than one selector, achunk_sizebelow 1, a wrong trailing dimension, empty vectors, per-row targets that do not broadcast, or a model whose final norm cannot be applied exactly.NotImplementedError – For encoder-decoder and encoder-only bridges.