2026/07/13 15.6k words

Transformer System #numinens#transformer#output-head#lm-head#logits#log-softmax#softmax#vocabulary#weight-tying#decoding-policy#temperature#top-k#top-p#beam-search#sampling#tensor-shapes

M3.8 — Output Head and Decoding Policy

M3.8 — Output Head and Decoding Policy

0x00 Overview And Background

M3.7 ended with final normalized state rows:

H_final: [B, S, d_model]

Each row is a learned continuous representation. It is not yet:

a token ID
a vocabulary score vector
a probability distribution
a selected next token

The output head, also called the language-model head, generator, vocabulary projection, or unembedding, changes the final axis:

hidden width d_model
    -> output vocabulary width V_out

For all sequence rows:

[B, S, d_model] -> [B, S, V_out]

For one selected inference row:

[B, d_model] -> [B, V_out]

M3.8 owns both the projection and the local decoding policy that consumes its vocabulary scores. M3.10 owns the surrounding autoregressive state machine: appending IDs, updating cache state, stopping, and invoking the next model step.

Owner question

How does one final hidden row become a typed vocabulary distribution, and how do greedy, stochastic, truncated, and beam policies transform that distribution into a token decision without confusing model scores with generation state?

M3.8 owns:

final hidden rows -> output projection -> logits
logits -> processors -> warpers -> normalization -> selection
vocabulary identity and optional input/output weight tying
training loss compatibility at the logit boundary
local token or beam candidate metadata

It defers shifted targets and optimizer execution to M3.9, the prefix/cache loop to M3.10, serving scheduling to M5, and verified multi-token acceleration to M7.


Background knowledge: language modeling ends with an unembedding

Input embeddings map vocabulary addresses into model-width vectors. The output head performs the reverse type of interface: it compares a final hidden row with one learned direction per vocabulary item and produces one scalar score for each item.

hidden representation:
    [B,S,d_model]

vocabulary projection:
    [d_model] -> [V]

logits:
    unnormalized scores used by the loss or decoding policy

weight tying:
    optional reuse of the input embedding parameters as output directions

The head does not choose a token and softmax is not always part of the module itself. Training losses, generation APIs, and fused kernels may consume logits under different conventions, so naming the exact output object is part of correctness.

The source article's full local path runs from one decoder row through vocabulary projection, normalization, policy selection, and token-ID lookup

Why this interface became its own system

The oldest useful abstraction is multiclass classification at every target position. A recurrent or Transformer decoder produces a context-dependent state; a learned affine map assigns one energy to every output symbol; a normalized likelihood trains those energies against the observed next symbol. That view is still correct, but modern language models made each part large enough to become an engineering boundary:

learned representation:
    one model-width row summarizes the visible prefix

learned classifier:
    one output direction and optional bias per vocabulary address

training normalization:
    log-sum-exp over a vocabulary that may be sharded or fused with loss

generation policy:
    a stateful transformation of one score row before a token is selected

The vocabulary axis can contain tens or hundreds of thousands of rows. Its matrix may be tied to the input embedding, sharded across ranks, quantized differently from the trunk, or replaced by a hierarchical or clustered head. At inference time, the same learned logits can drive greedy selection, truncated sampling, adaptive feedback, constrained decoding, or search. The model checkpoint therefore does not define a complete generation behavior by itself.

This is also why the common phrase “the softmax layer generates the next token” is too compressed. Three different contracts are hidden inside it:

ContractLearned or configured?Output
vocabulary projectionlearned checkpoint stateraw logits
normalization/lossmathematical and runtime contractprobabilities, log-probabilities, or scalar loss
decoding policyconfigured algorithm plus local state/RNGtoken or candidate metadata

The original Transformer made the pre-softmax projection explicit and shared compatible embedding/projection weights. Later work studied weight tying as an architecture and optimization choice, while large-vocabulary work introduced sampled, hierarchical, and adaptive alternatives. Open-ended neural generation then exposed a second problem: maximizing likelihood during training does not imply that local likelihood maximization is the best generation policy. Nucleus, typical, eta, feedback-controlled, and contrastive policies are different responses to that inference problem, not different definitions of the learned head.

From residual coordinates to vocabulary evidence

The unembedding does more than resize a tensor. Each vocabulary row defines a direction against which the final residual state is scored:

Consequently, every residual update can change the final logit row through the same output directions. This observation motivates output-embedding analyses and logit-lens diagnostics, but it does not make logits calibrated probabilities or prove that an intermediate residual row has the same geometry as the final normalized state.

A15's source figure writes the final residual row through an unembedding matrix before normalization; M3.8 uses it as a projection contract, not as proof that every intermediate state is directly decodable

The historical progression is therefore best read as a set of contracts:

fixed-vocabulary classifier
    -> optional input/output storage tying
        -> large-vocabulary training and sharding alternatives
            -> local generation policies over one score row
                -> runtime integration, evaluation, and rollback

M3.8 follows that progression. It does not turn the output article into the outer autoregressive loop, a serving scheduler, or a survey of speculative execution.

Immutable head-to-policy manifest

Shape compatibility is necessary but insufficient. Two artifacts can both produce a tensor shaped [B,S,V] while assigning different meanings to its rows, normalizing it differently, or consuming randomness in a different order. A reproducible experiment and a releasable runtime therefore pin an identity manifest before logits are compared.

Identity groupFields that must be pinnedFailure if omitted
headmodel width, output width, storage orientation, bias, parameter dtype, accumulation dtypetransposed or numerically different scores
vocabularytokenizer artifact hash, ordered ID-to-token table hash, special IDs, added-token ordercorrect numbers attached to wrong symbols
tyingtied/untied flag, source parameter path, alias/storage identity, tie restoration policyduplicate parameters or silently broken sharing
lossscore type, target type, ignore index, label smoothing, reduction, vocabulary shardingdouble normalization or wrong gradients
policyordered processors, ordered warpers, support fallback, selector, stop-token viewsame logits produce different decisions
randomnessgenerator algorithm, seed, per-row stream/counter, draw schedule, distributed ownerirreproducible or batch-order-dependent samples
checkpoint/runtimeformat/version, parameter keys, shard ranges, framework/engine version, kernel pathloader accepts an incompatible artifact

One compact manifest can be written as:

{
  "head": {
    "weight_key": "lm_head.weight",
    "stored_shape": ["V", "d_model"],
    "bias": false,
    "parameter_dtype": "bf16",
    "accumulation_dtype": "fp32"
  },
  "vocabulary": {
    "size": "V",
    "ordered_table_sha256": "...",
    "special_ids": {"bos": 1, "eos": 2, "pad": 0}
  },
  "tying": {
    "enabled": true,
    "embedding_key": "model.embed_tokens.weight",
    "checkpoint_alias_required": true
  },
  "loss": {
    "input": "raw_logits",
    "target": "class_index",
    "ignore_index": -100,
    "label_smoothing": 0.0,
    "reduction": "token_mean",
    "vocab_parallel": false
  },
  "policy": {
    "processors": ["repetition_penalty", "constraint_mask"],
    "warpers": ["temperature", "top_p"],
    "selector": "multinomial",
    "empty_support": "raise"
  },
  "rng": {
    "algorithm": "framework_generator",
    "seed": 1234,
    "stream_owner": "request",
    "draw_contract": "one categorical draw per active row"
  }
}

This is not a universal schema. It is a declaration of invariants. A production format may encode hashes, enums, and runtime keys differently, but it must answer the same questions.

Compatibility gates

Before loading or comparing two artifacts:

  1. Compare ordered vocabulary identities, not vocabulary sizes alone.
  2. Reconstruct parameter aliases and prove pointer/storage identity when tying is required.
  3. Confirm whether the caller supplies raw logits, probabilities, or log-probabilities.
  4. Compare processor and warper order, because most transforms do not commute.
  5. Confirm the sampling generator and per-request draw schedule before calling two outputs deterministic equivalents.
  6. For a vocabulary shard, verify global row offsets and the rank that owns each target row.
  7. Refuse release when a checkpoint migration lacks a reversible vocabulary and optimizer-state mapping.

The manifest separates architecture identity from an experiment’s tunable policy parameters. Sweeping temperature or top-p does not change the checkpoint head. Reordering a constraint mask and top-p, changing token IDs, or breaking a tied alias changes the executable contract.

0x01 The local object: final normalized hidden rows

The output head begins after the final normalization expected by the checkpoint:

Transformer blocks
    -> final LayerNorm or RMSNorm
        -> H_final
            -> output head

For a decoder-only model:

H_final: [B, S, d_model]

For an encoder-decoder model, the generative head consumes decoder-owned target rows:

decoder H_final: [B, T, d_model]
encoder memory:  [B, S, d_model]

The encoder memory informs the decoder through cross-attention, but the target-vocabulary head is applied to decoder rows, not directly to encoder memory.

The local row equation is:

where:

h_i: [d_model]
W_U: [d_model, V_out] in row-vector algebra
b_U: [V_out] optional
z_i: [V_out]

The vector z_i contains logits, one score for every output-vocabulary row.


0x02 Linear projection and storage orientation

A minimal raw-logit head is:

class LMHead(nn.Module):
    def __init__(self, d_model, vocab_size, bias=False):
        super().__init__()
        self.proj = nn.Linear(d_model, vocab_size, bias=bias)

    def forward(self, hidden_states):
        return self.proj(hidden_states)

Shape trace:

hidden_states: [B, S, d_model]
logits:        [B, S, V_out]

nn.Linear acts on the last dimension and preserves all leading dimensions. The same head can therefore process:

[d_model]       -> [V_out]
[B,d_model]     -> [B,V_out]
[B,S,d_model]   -> [B,S,V_out]

Algebra versus PyTorch weight shape

Row-vector algebra often writes:

W_U: [d_model, V_out]
z = h @ W_U + b

PyTorch stores:

nn.Linear(d_model, V_out).weight: [V_out, d_model]

and computes:

z = h @ weight.T + bias

This orientation matters for checkpoint conversion and weight tying. The PyTorch output weight has the same stored shape as a token embedding table:

embedding.weight: [V_out, d_model]
lm_head.weight:   [V_out, d_model]

It is not necessary to manually transpose the parameter before calling nn.Linear.

Logits are learned compatibility energies

Let denote output row in PyTorch storage. With no bias,

The score grows when the final hidden direction aligns with the token’s output direction and with their magnitudes. This is a dot product, not necessarily cosine similarity because neither vector must be unit-normalized.

Softmax is translation invariant:

Only relative logits determine probabilities. Their pairwise difference is a multiclass log-probability ratio:

That statement is more precise than calling each individual logit a binary log-odds value.

Cross-entropy gradient at the head

For a one-hot target and probability row ,

Differentiate through log-softmax:

For a batch of flattened supervised rows and output storage with :

Every vocabulary row receives a gradient proportional to its predicted probability, while the target row receives the additional -1 term. This is why training does not need argmax and why the full vocabulary participates even though labels contain one integer per row.

With label smoothing target distribution , the same result becomes

Deriving the complete affine-head backward

Flatten only the supervised row axes and retain vocabulary as the class axis:

The stored-weight forward equation is

Let . A differential exposes every parameter path:

Collecting the coefficient of each differential gives:

In matrix form:

dH = G @ E             [R,d]
dE = G.T @ H           [V,d]
db = sum_rows(G)        [V]

For ordinary one-hot cross-entropy, G = P - Y. The target row receives the negative correction, while every non-target row receives probability-weighted pressure. A vocabulary projection is therefore dense in output-gradient space even when the input lookup that produced the hidden states touched only a small set of token addresses.

What the bias can represent

The bias adds one context-independent scalar per output address:

If , the distribution is ; thus can encode a global token preference. But calling it “the unigram prior” is too strong: training jointly changes , the trunk, and , while softmax translation invariance leaves one common-offset degree of freedom. Bias-free heads force all context-independent preference to emerge through the hidden state and output directions.

Norm and angle are separate score mechanisms

Write the dot product as

A large score can come from angular alignment, output-row norm, hidden-state norm, or all three. Weight tying does not turn this into nearest-neighbor cosine search. Final normalization constrains the hidden-state scale according to its own contract, but output-row norms remain learned unless an architecture normalizes or parameterizes them explicitly.

Parameter and logical-work ledger

For an untied affine head:

For projected rows, the matrix product performs multiply-accumulates, and the logical logit tensor contains elements. A tied head removes the additional output parameter allocation; it does not remove the matrix product or guarantee that a runtime stores only one physical copy after conversion.

M3.9 derives how shifted labels and masks create those target rows; M3.8 owns the typed gradient boundary at the output head.


0x03 The A15 Harvard Generator

A15 imports the Annotated Transformer style, where the generator combines the linear projection with log_softmax:

import torch.nn.functional as F

class Generator(nn.Module):
    def __init__(self, d_model, vocab):
        super(Generator, self).__init__()
        self.proj = nn.Linear(d_model, vocab)

    def forward(self, x):
        return F.log_softmax(self.proj(x), dim=-1)

The shape path is:

x:            [B,T,d_model] or [B,d_model]
self.proj(x): [B,T,V_tgt]   or [B,V_tgt]     raw logits
generator(x):[B,T,V_tgt]   or [B,V_tgt]     log-probabilities

The final shape does not identify the score type. Both logits and log-probabilities use the same vocabulary-width tensor.

Source-audit corrections

The A15 local code is useful, but several surrounding explanations should not be imported as technical claims.

A15 wording or implicationCorrect contract
Final decoder state is a probability vector.It is a hidden representation in d_model space.
Each logit is a probability or ordinary binary log-odds.Multiclass logits are unnormalized real scores.
Softmax selects the highest-scoring token.Softmax normalizes scores; a separate policy selects a token.
Training finds an argmax token at every row.Training normally computes a differentiable loss against known labels; argmax is not in that gradient path.
The toy tensor named prob contains probabilities.This Generator returns log-probabilities.
generator.lut.weight is the output projection parameter.In the shown class it is generator.proj.weight.

The source snippet also imports torch.nn.functional as F but prints a bare log_softmax(...) call. The executable form is F.log_softmax(...) unless log_softmax was separately imported.


0x04 Logits, probabilities, and log-probabilities

Let one output row be:

logits z: [V_out]

Raw logits

logits = lm_head(hidden)

Logits are unconstrained real scores:

they can be positive or negative
they do not need to sum to one
they are not yet sampling weights

For multiclass output, calling each logit a binary log-odds value is generally misleading. The distribution depends on all vocabulary scores through the normalization denominator.

Probabilities

probs = torch.softmax(logits, dim=-1)

Now:

probs[c] >= 0
sum_c probs[c] = 1

Log-probabilities

log_probs = F.log_softmax(logits, dim=-1)

PyTorch 2.13 documents F.log_softmax as mathematically equivalent to log(softmax(x)) but implemented with a numerically stable formulation. Do not compute the two operations separately merely to obtain log-probabilities.

One denominator derives softmax, log-softmax, and cross-entropy

The naive normalizer

can overflow even when the final probabilities are ordinary. Let . Multiplying numerator and denominator by does not change softmax:

The largest shifted logit is zero, so every exponential lies in . The stable log-normalizer is:

That one scalar derives both normalized forms:

For class target , negative log-likelihood cancels every irrelevant intermediate:

An implementation can therefore compute loss without materializing a persistent probability tensor. A fused implementation may keep only the row maximum, denominator, target score, and whichever state its backward needs.

def stable_cross_entropy_row(logits, target):
    # Accumulate the reduction in the declared stable dtype.
    maximum = logits.max()
    shifted = logits - maximum
    log_denom = maximum + log(exp(shifted).sum())
    return log_denom - logits[target]

Why the gradient is probability minus target

Differentiate the normalizer:

The target term contributes only at :

The Hessian is:

It is positive semidefinite and has a zero direction along the all-ones vector. That zero mode is the differential form of translation invariance: adding the same constant to every logit changes neither probabilities nor cross-entropy.

Label smoothing is a target-distribution contract

For the convention that mixes the one-hot target with a uniform distribution over all V classes:

and:

Another legitimate convention distributes all smoothing mass over the V-1 non-target classes. The same epsilon then produces a different target distribution and gradient. A manifest must pin the convention, not only the number.

Dtype and degenerate-row policy

Stable algebra does not choose an accumulation dtype. A runtime may project in bf16/fp16, promote row maximum and exponential reductions to fp32, and cast the loss or gradient according to its mixed-precision contract. Merely subtracting the maximum does not prevent underflow in tiny tail probabilities; underflowed tail mass can be acceptable for a loss kernel only if the target and reduction remain valid.

Special rows require explicit behavior:

Input rowMathematical resultRuntime policy
one finite maximum, other very negative logitsconcentrated valid distributionstable max subtraction
several equal maximamass divided across tied maximatie order matters only to discrete selection
all logits negative infinityundefined zero-over-zero normalizationreject or provide declared legal fallback
any NaNNaN contaminates comparisons/reductionfail telemetry; do not silently sample
masked targetloss is invalid for that rowM3.9 excludes it through the declared ignore/mask contract

Temperature belongs before the denominator:

If a training loss deliberately uses this transformed row, its logit gradient contains a factor . Ordinary next-token training uses the checkpoint’s declared objective, usually at ; inference temperature is a policy and does not retroactively change the trained loss.

Transform relationships

probs = log_probs.exp()
probs = torch.softmax(log_probs, dim=-1)

Both recover the probability distribution mathematically because normalized log-probabilities have logsumexp(log_probs) = 0. Applying softmax to log-probabilities is therefore redundant, not a distribution-changing second softmax.

In contrast:

torch.softmax(probs, dim=-1)

does change an already normalized probability distribution and is usually a type error.

Argmax invariance

Because softmax, log_softmax, and exp are monotone in each score while sharing one row-wise denominator:

argmax(logits) == argmax(probs) == argmax(log_probs)

That equivalence is useful for greedy selection, but it does not make the tensor types interchangeable for loss functions, cumulative-probability filtering, or multinomial sampling.

Example probability distribution after vocabulary softmax


0x05 The training interface: all supervised rows

Under teacher forcing, one model pass can produce one hidden row for every target input position:

H_final: [B, T, d_model]

The output head can project all rows in parallel:

scores: [B, T, V_tgt]

The label path supplies one target token ID per supervised position:

labels: [B, T]

M3.9 owns target shifting, padding-label exclusion, flattening, label smoothing, and loss normalization. M3.8 owns the score-type interface between the head and criterion.

Harvard path: log-probabilities into KL divergence

log_probs = generator(hidden_states)       # [B,T,V]

flat_log_probs = log_probs.reshape(B * T, V)
flat_targets = target_distribution.reshape(B * T, V)

loss = F.kl_div(
    flat_log_probs,
    flat_targets,
    reduction="sum",
)

The Annotated Transformer label-smoothing path constructs a target distribution and expects generator log-probabilities.

Modern path: raw logits into cross entropy

logits = lm_head(hidden_states)             # [B,T,V]

flat_logits = logits.reshape(B * T, V)
flat_labels = labels.reshape(B * T)

loss = F.cross_entropy(
    flat_logits,
    flat_labels,
    ignore_index=pad_or_ignore_id,
)

PyTorch 2.13 CrossEntropyLoss expects unnormalized logits. It incorporates the log-softmax/NLL-style calculation for class-index targets.

The implementation rule is:

Generator returns log-probs:
    pair with an NLL/KL-style criterion expecting log-probs

LM head returns raw logits:
    pair with cross entropy or explicitly convert as required

Training does not need to select an argmax token before computing the loss. The known label indexes the appropriate class term while gradients flow through the entire vocabulary score row.

Source-to-tensor training trace

M3.9 supplies an immutable row map:

row r
    -> batch index
    -> sequence position
    -> target token ID or ignore

M3.8 consumes only supervised rows:

H_valid: [R,d]
E:       [V,d]
b:       [V] optional

Z = H_valid @ E.T + b             [R,V]
m = row_max(Z)                    [R]
s = sum_v exp(Z - m)              [R]
t = gather_target_logit(Z, y)     [R]
loss_row = m + log(s) - t         [R]

The reduction then receives the declared valid-row count from M3.9. A token mean is:

where is the supervised-row set. Averaging each local chunk or rank independently and then averaging those means is wrong when valid counts differ.

Materialized, chunked, and fused execution

The same mathematical objective admits several schedules:

SchedulePersistent logical score stateExact objective?Main tradeoff
materializedfull [R,V] logits, possibly probabilitiesyessimple APIs, largest live score tensor
row-chunked[C,V] for chunk size Cyesrepeated launches, bounded live score state
fused linear plus cross-entropytiled logits/reduction stateyes when contract matchesspecialized backward and kernel constraints
sampled/clustered objectivesubset or hierarchygenerally a different estimator/headchanges training contract

Let be bytes per stored logit. Full materialization requires:

Row chunking bounds this object by:

These are logical tensor sizes, not hardware peak claims. M4 combines them with allocator behavior, kernel workspaces, recomputation, and the rest of the model.

An exact row-chunked loss must accumulate a sum and count:

loss_sum = 0.0
valid_count = 0

for hidden_chunk, labels_chunk in valid_row_chunks:
    logits = linear(hidden_chunk, output_weight, output_bias)
    losses = cross_entropy(logits, labels_chunk, reduction="none")
    loss_sum += losses.sum()
    valid_count += labels_chunk.numel()

loss = loss_sum / valid_count

Do not call mean inside each differently sized chunk and average chunk means.

Backward state and recomputation

The exact backward needs the local quantity:

scaled by the outer loss reduction. A schedule can obtain it by saving probabilities, saving enough row-normalizer state and recomputing exponentials, or recomputing the projection and loss tile. It then accumulates:

dH += G_Z @ E
dE += G_Z.T @ H
db += row_sum(G_Z)
StrategySaved stateRecomputed stateContract risk
ordinary eager autogradframework-selected inputs/intermediatesimplementation-dependentaccidental full-logit liveness
checkpointed headhidden or upstream recompute inputs, labelsprojection and normalizationreplay must preserve dtype and row map
fused losshidden tile, weight, target, reduction/normalizer metadataprobability-like tile in backwardkernel convention must match reference
chunked losschunk inputs or replay source, targetseach score chunksum/count and gradient accumulation order

Recomputation is valid only if it recreates the same hidden rows, weights, targets, masking, and numerical policy. If upstream dropout is replayed, its RNG state belongs to the M3.9 training-execution contract. Inference sampling RNG is a different state and must never be consumed by the training loss.

Exact conformance checks

A candidate implementation should be tested against a small materialized reference for:

  1. per-row loss before reduction;
  2. valid-row sum, count, and final reduction;
  3. gradients for hidden rows, output weight, and optional bias;
  4. tied-weight accumulation when the embedding path is present;
  5. extreme logits, ignored rows, label smoothing, and uneven chunks;
  6. forward and backward dtypes within declared tolerances.

Matching only the scalar mean loss can hide row swaps, wrong valid counts, and compensating errors in gradients.


0x06 The inference interface: project the decision row

At one generation step, the policy needs one vocabulary score row per active sequence:

decision hidden state: [B,d_model]
decision logits:       [B,V_out]

In a simple unpadded full-prefix example:

last_hidden = hidden_states[:, -1, :]  # [B,d_model]
logits = lm_head(last_hidden)          # [B,V]

But hidden_states[:, -1, :] means the last rectangular column, not necessarily the last semantic token. With right padding, use the row selected by the inference contract:

lengths = attention_mask.sum(dim=-1)               # [B]
last_idx = lengths - 1                              # [B]
batch_idx = torch.arange(B, device=hidden_states.device)
last_hidden = hidden_states[batch_idx, last_idx, :] # [B,d_model]
logits = lm_head(last_hidden)                       # [B,V]

M3.10 owns the padding-side and last-valid-row logic. M3.8 requires that the head receive the correct row.

During cached one-token decode, the model may already return:

hidden_states: [B,1,d_model]

Then:

logits = lm_head(hidden_states)  # [B,1,V]
step_logits = logits[:, -1, :]   # [B,V]

The output head does not append the selected token, update the cache, stop completed rows, or choose a decoding policy.


0x07 A versioned raw-logit path: LlamaForCausalLM

Hugging Face Transformers v5.13.1 LlamaForCausalLM separates the base model from a bias-free vocabulary projection:

self.model = LlamaModel(config)
self.vocab_size = config.vocab_size
self.lm_head = nn.Linear(
    config.hidden_size,
    config.vocab_size,
    bias=False,
)

Its forward path obtains final normalized hidden states from LlamaModel, selects the requested sequence rows, and returns raw logits:

hidden_states = outputs.last_hidden_state

slice_indices = (
    slice(-logits_to_keep, None)
    if isinstance(logits_to_keep, int)
    else logits_to_keep
)

logits = self.lm_head(hidden_states[:, slice_indices, :])

Shape examples:

logits_to_keep = 0:
    selected hidden: [B,S,d_model]
    logits:          [B,S,V]

logits_to_keep = 1:
    selected hidden: [B,1,d_model]
    logits:          [B,1,V]

Here -0 is 0, so slice(-0, None) means all sequence positions. The option changes how many rows receive the vocabulary projection; it does not change vocabulary size or the meaning of each output column.

This modern interface returns logits because training loss, generation processors, temperature, and selection code can consume raw scores without forcing one normalization policy inside the model head.


0x08 The vocabulary-axis identity contract

The last axis is not an anonymous class dimension. Output column c must correspond to the checkpoint’s token ID c:

logits[..., c]
    -> score for output token ID c
    -> tokenizer/model vocabulary entry for ID c

The minimum contract is:

0 <= emitted tokenizer ID < V_out
output row ordering matches checkpoint token-ID ordering
special token IDs agree with model configuration
added token rows exist and were initialized/adapted as intended

tokenizer.vocab_size, len(tokenizer), embedding rows, and output rows are not guaranteed to be reported identically in every library because added and reserved tokens can be handled separately. The robust audit prints all of them:

print(tokenizer.vocab_size)
print(len(tokenizer))
print(model.get_input_embeddings().weight.shape)
print(model.get_output_embeddings().weight.shape)
print(model.config.vocab_size)

For encoder-decoder models:

source IDs address V_src
target decoder IDs address V_tgt
output logits usually use V_tgt

Equal row counts do not prove equal vocabulary semantics. Swapping two tokenizer IDs preserves every shape and assigns scores to the wrong tokens.

Vocabulary migration is a row-address transaction

A safe migration starts with an explicit partial bijection:

where is the set of retained old token IDs. For every retained token:

Untied models apply the same semantic mapping independently to input embedding rows and output-head rows. Tied models migrate one shared table and restore one alias after loading. Optimizer moments and any row-shaped master weights must follow the same address transform:

New rows need declared initialization. Common choices include random checkpoint-style initialization, an average of source-subtoken rows, copying a semantically related row, or a separately trained initialization. These are design choices, not equivalent migrations. Adam-like moments for genuinely new rows are usually initialized to zero under the chosen optimizer contract.

def migrate_vocab_rows(old_rows, old_to_new, new_size, init_new):
    new_rows = init_new(new_size, old_rows.shape[1])
    copied = zeros(new_size, dtype=bool)

    for old_id, new_id in old_to_new.items():
        new_rows[new_id] = old_rows[old_id]
        copied[new_id] = True

    return new_rows, copied

Append-only growth is safer, not free

Appending tokens while preserving every old ID avoids row permutation:

old IDs: 0 ... V_old-1
new IDs: V_old ... V_new-1

The old raw logits can remain identical for a fixed hidden row if old weights and biases are unchanged. The old probabilities do not necessarily remain identical because new rows enter the softmax denominator:

Badly initialized new rows can therefore steal probability mass before they have useful semantics. Append-only compatibility tests must compare mapped raw logits and separately measure distribution and generation drift.

Tied alias and optimizer restoration order

One safe construction order is:

  1. Load and hash the old tokenizer, ordered table, config, checkpoint, and optimizer manifest.
  2. Build the new ordered vocabulary and immutable old-to-new mapping.
  3. Allocate resized embedding/head/bias/master/moment tensors.
  4. Transform every row-addressed object with the same mapping.
  5. Load module state and restore the required tied Parameter alias.
  6. Restore or create exactly one optimizer state for each shared Parameter.
  7. Assert shapes, token hashes, special IDs, pointer identity, and shard ranges.
  8. Run old-token raw-logit, new-token, loss, and generation conformance tests.
  9. Release tokenizer, model, optimizer, policy, and mapping manifests as one versioned bundle.

Creating the optimizer before replacing parameters can leave stale objects in its parameter groups. Re-tying after optimizer restore can leave duplicate moment slots. The loader must prove both model alias identity and optimizer state ownership.

Release and rollback ledger

ArtifactRelease gateRollback requirement
tokenizer and ordered tabledeterministic ID table hashprevious immutable tokenizer
model rows and biasmapped raw-logit oracle, new-row initialization auditprevious checkpoint
tied aliasesstorage/pointer identity assertionprevious architecture config
optimizer/master statemapped old rows, zero/declared new rows, one state per shared parameterprevious optimizer checkpoint
shardscontiguous global row ranges and owner mapprevious shard manifest
local policyspecial IDs and legal-token masks match new vocabularyprevious policy manifest

Rollback after further training is not “apply the inverse permutation”: new rows may have influenced normalization and all model gradients. Reliable rollback restores the complete previous release bundle.


0x09 Weight tying: shared storage, not similar shape

An input embedding table and PyTorch output head can have the same stored shape:

embed_tokens.weight: [V,d_model]
lm_head.weight:      [V,d_model]

Untied model:

two separate Parameter objects
independent values and gradients

Tied model:

one shared Parameter object
used for input lookup and output projection

Conceptually:

hidden = embed_tokens(input_ids)       # row lookup from E
logits = F.linear(hidden, E)           # hidden @ E.T

An explicit PyTorch tie is:

lm_head.weight = embed_tokens.weight

assert lm_head.weight is embed_tokens.weight
assert lm_head.weight.data_ptr() == embed_tokens.weight.data_ptr()

Copying values is not tying:

lm_head.weight.data.copy_(embed_tokens.weight.data)

After the next optimizer update, two copied Parameters can diverge.

Input embedding and output projection sharing one transposed parameter matrix

What tying does and does not imply

The original Transformer shared compatible source embeddings, target embeddings, and the pre-softmax matrix under its vocabulary setup. Press and Wolf studied the output matrix as an embedding and reported reduced perplexity in their evaluated language models plus substantial parameter reduction in translation models.

Those results support weight tying as a real architecture choice, not a universal requirement:

same vocabulary semantics and dimensions:
    tying may be valid

different source and target vocabularies:
    blind three-way tying is invalid

same shapes but checkpoint trained untied:
    tying changes the model

The Transformers v5.13.1 LlamaConfig default sets tie_word_embeddings=False, even though the framework exposes tied-weight metadata for configurations/checkpoints that request tying. Read the checkpoint configuration and verify actual parameter identity rather than inferring from class names.

If the output head has a bias, tying the weight does not automatically tie or remove that separate [V] parameter.

Tied parameters receive two semantic gradient contributions

If one parameter is used for both input lookup and output projection, autograd accumulates both uses:

The input contribution is sparse in token addresses for an ordinary embedding lookup before optimizer effects; the output contribution is generally dense across vocabulary rows because softmax assigns probability to all candidates. Tying is therefore not only parameter-count reduction. It couples how token rows are learned as inputs and as output directions.

For token-ID matrix and upstream gradient at the embedding output, the input-use contribution for row is a scatter-add:

The output-use contribution from flattened hidden rows is:

Autograd must add those expressions into one gradient buffer before one optimizer state is updated:

shared row E[v]
    <- sparse scatter from every input occurrence of token v
    +  dense classifier contribution for output candidate v

This also explains a migration hazard. If a loader materializes two Parameter objects, loads equal values, and creates separate optimizer slots, the next training step implements two independent equations rather than the tied one.

A15 reuses Press and Wolf's historical input/output embedding comparison; its empirical conclusions are paper-reported, while storage aliasing and gradient addition are the implementation contract derived here

Tying variants are different architectures

VariantShared storageExtra transformCompatibility condition
untiednoneoptional biasinput and output widths may differ
direct tyinginput table equals output weightnonesame ordered vocabulary and model width
projected tyingshared table plus learned projectionmaps hidden/output spacesprojection and checkpoint keys must be pinned
source-target-output tyingthree uses share one tabletask-dependentsource and target token identities must truly match
copied initializationequal initial values onlynonenot weight tying after optimization

Press and Wolf and Inan et al. motivate direct tying from related but distinct analyses. Their reported empirical results do not imply that every tokenizer, translation pair, or checkpoint should be tied. The architecture choice must be declared before training and reconstructed during load.

Distributed and sharded optimizers must preserve that identity. Registering two independently sharded parameters that happen to begin with equal values does not reproduce one shared parameter with one accumulated gradient and one optimizer state.


0x0A Output-row scope is an interface and cost boundary

The linear head can project any number of selected rows:

training all rows:
    [B,T,d_model] -> [B,T,V]

prefill last-valid rows only:
    [B,d_model] -> [B,V]

cached decode row:
    [B,1,d_model] -> [B,1,V]

Projecting all prompt rows during inference is mathematically valid if those rows are available, but often unnecessary when only the final row drives the next decision. Selecting hidden rows before the large vocabulary projection can avoid producing unused [B,S,V] tensors.

Let R be the number of hidden rows actually projected. The local ledger is:

plus V parameters if a bias exists, and:

The produced score tensor contains R*V elements. Therefore selecting rows before the projection reduces both projection work and output materialization in direct proportion to the number of omitted rows.

Worked example:

B       = 8
S       = 2048
d_model = 4096
V       = 32000
dtype   = bf16/fp16 for stored weights/logits
output-head weights:
    32000 * 4096
    = 131,072,000 parameters
    = 250 MiB at 2 bytes/parameter

all prompt-row logits:
    8 * 2048 * 32000
    = 524,288,000 elements
    = 1000 MiB at 2 bytes/element

last-row logits only:
    8 * 32000
    = 256,000 elements
    ~= 0.488 MiB

all-row projection:
    2,147,483,648,000 MACs

last-row projection:
    1,048,576,000 MACs

The ratio is exactly S=2048 for this row-selection comparison. Training needs all supervised rows, so it cannot apply the same shortcut blindly. Cached generation normally needs only the current decision row. M4.1 owns the whole-model and hardware traffic model, but this local derivation belongs here because it explains why the output-row interface is operationally important.

The [B,S,V] tensor is the logical training interface, not proof that an optimized loss kernel writes the entire tensor to HBM. A fused linear plus cross-entropy implementation can tile vocabulary work and combine projection, normalization, and loss reduction. That changes physical materialization, not the output-head class domain or the B*S*V*d_model projection arithmetic being audited here.

Vocabulary-parallel projection and loss

When is large, tensor parallelism can shard output rows. Rank owns

E_r: [V_r, d_model]
Z_r = H @ E_r.T: [R, V_r]

The global softmax denominator still spans all vocabulary shards. A numerically stable distributed log-sum-exp uses a global row maximum:

This requires a max reduction followed by a sum reduction unless the backend fuses or restructures them. The target logit is local on exactly one vocabulary shard and must be selected and reduced consistently:

owner rank:
    contributes z_target

non-owner ranks:
    contribute neutral value under the chosen reduction

The per-row cross entropy is then

A vocabulary-parallel fused cross-entropy can compute this without all-gathering [R,V] logits. It still computes each local shard’s projection and participates in the global reductions. “Logits were not materialized globally” does not mean the vocabulary normalization disappeared.

Exact forward trace over vocabulary shards

Assume contiguous shard owns global IDs:

For each supervised row:

  1. Compute local logits Z_r = H E_r^T in the declared projection dtype.
  2. Compute local maximum and all-reduce MAX to obtain .
  3. Form local exponentials .
  4. Sum each row locally and all-reduce SUM to obtain .
  5. Determine owner mask and local target index .
  6. The owner contributes its target logit; non-owners contribute zero. An all-reduce SUM yields the global target score.
  7. Return before the declared outer reduction.
local_logits = linear(hidden, local_vocab_weight)

global_max = all_reduce_max(local_logits.max(dim=-1))
local_exp = exp(local_logits - global_max[:, None])
global_denom = all_reduce_sum(local_exp.sum(dim=-1))

owns_target = (shard_start <= target) & (target < shard_end)
# Non-owners gather a safe in-range index; where() discards that value.
local_target = where(owns_target, target - shard_start, 0)
target_contribution = where(
    owns_target,
    gather(local_logits, local_target),
    0.0,
)
global_target = all_reduce_sum(target_contribution)

loss_row = global_max + log(global_denom) - global_target

Using negative infinity as the non-owner value would be correct for a maximum reduction, but not for the SUM shown above. Neutral values belong to the chosen collective.

Exact backward and ownership

Each rank can normalize its local shard with the global denominator:

For one-hot class targets:

No rank subtracts the target outside its own shard. Local parameter gradients need no vocabulary all-gather:

Every shard contributes to the hidden-state gradient:

When is replicated across tensor-parallel ranks, that sum is a collective reduction. Other layouts can use reduce-scatter or fused collectives, but they must implement the same global derivative.

Label smoothing adds a distributed target value for every local class. For the all-class convention:

and G_Zr = P_r - Q_r. A non-target-only convention uses a different formula. Mixing the convention across ranks breaks both the loss and gradient.

Collective and failure ledger

ObjectLocal shapeGlobal operationSilent failure
local maximum[R]MAXnormalization differs by shard
exponential sum[R]SUMlocal probabilities sum to more than one globally
target contribution[R]SUM with zero non-ownerwrong or missing target score
hidden gradient contribution[R,d]SUM/reduce-scatter by layouttrunk sees only one vocabulary shard
weight gradient[V_r,d]local until optimizer/sharding contractrow owners or optimizer shards disagree

Telemetry should include target-owner count, target IDs outside all shard ranges, non-finite local maxima, global denominator validity, and per-rank collective participation. One rank skipping an ignored row while others enter its collectives can deadlock; ignored-row compaction or masking must preserve a common distributed schedule.

Distributed inference selection

Greedy selection over vocabulary shards needs the global maximum and its global token ID. Each rank can propose (local_max, local_id); a collective maximum with deterministic tie semantics chooses the winner.

Top-k can similarly merge local candidate lists:

each rank:
    local top-k over V_r

collective or coordinator:
    top-k over at most TP*k candidates

Top-p is harder to distribute exactly because cumulative mass depends on global ordering and the global softmax denominator. Implementations may gather scores, use distributed sort/selection, overselect local candidates with an exact correction, or impose approximations. A local top-p on each shard is not equal to global top-p.

For exact global top-k, each shard’s local top-k is sufficient: a candidate ranked below k inside its own shard cannot enter the global top-k because at least k same-shard candidates already outrank it. Merge candidates using global token IDs, and pin a deterministic secondary key for equal scores.

Global multinomial sampling also needs one declared owner. Gathering the full row is simple but expensive; distributed categorical algorithms can avoid that gather by sampling from shard masses and then a local conditional distribution. They must consume randomness according to the same manifest contract and return the same global token-address semantics.

Output-head quantization and tying boundary

The head can be quantized independently, but several constraints interact:

tied input/output weight:
    one physical parameter may serve lookup and GEMM paths with different kernel needs

vocabulary rows:
    per-row scales align naturally with output classes but not every embedding lookup kernel

rare or added tokens:
    outlier rows can be disproportionately affected by shared-group quantization

fused loss:
    dequantization and projection must match the loss kernel's accepted layout

M8 owns the compression decision. M3.8 records why the output head is not just another anonymous linear layer: its row identity is externally observable through token IDs, and weight tying can couple it to input lookup.


0x0B The decoding-policy pipeline

The output head produces scores. A policy composes transformations in a declared order:

raw logits
    -> processors
       hard constraints, history penalties, token biases
    -> warpers
       temperature, top-k, top-p, typical/min-p filters
    -> normalization when needed
       softmax or log_softmax
    -> selector
       argmax, multinomial draw, beam candidate top-k

Names differ across libraries, but ordering is semantic. Temperature preserves rank for positive , yet changes top-p cumulative mass. A repetition penalty can change rank, so applying it before versus after top-k can change support. A probability-space multiplier is not equal to an additive logit bias.

def local_policy(
    logits,
    *,
    prefix_ids,
    processors=(),
    do_sample=False,
    temperature=1.0,
    top_k=None,
    top_p=None,
    generator=None,
):
    scores = logits
    for processor in processors:
        scores = processor(prefix_ids, scores)

    if not do_sample:
        return scores.argmax(dim=-1)

    if temperature <= 0:
        raise ValueError("sampling temperature must be positive")

    scores = scores / temperature
    if top_k is not None:
        scores = top_k_filter(scores, top_k)

    probs = torch.softmax(scores, dim=-1)
    if top_p is not None:
        return sample_top_p(probs, top_p, generator)

    return torch.multinomial(probs, 1, generator=generator)

This is a coherent teaching pipeline, not a universal API order. A release contract should record:

score type before every transform
processor order
normalization point
support and tie rules
selector and beam scoring
random generator and seed ownership

Policy state is typed and partly mutable

The outer request owns the generated prefix and invokes the next model step. The local policy reads a snapshot of that prefix and can own additional state:

StateExamplesMutation owner
immutable policy configprocessor order, temperature bounds, k/p thresholds, fallback, tie rulerelease/configuration
read-only request viewprefix IDs, active/finished flag, current step, special IDsM3.10 outer loop
constraint stategrammar/FSM state, legal token set, stop-sequence prefixpolicy transition returned to M3.10
adaptive controllertarget entropy/surprisal, running error, current temperature or klocal policy
randomnessalgorithm, request stream/key, counter/draw indexlocal selector
beam metadataparent IDs, cumulative scores, finished candidateslocal search policy; outer loop reorders all model state

A processor transforms scores using model-independent or prefix-dependent rules. A warper changes the sampling distribution or support. Libraries draw that naming boundary differently; the executable contract is the ordered composition and score type at every edge.

PolicyInput:
    raw logits [B,V]
    read-only prefix/step/special-ID view
    constraint/controller/RNG state

PolicyOutput:
    selected global token IDs or ranked candidates
    selected score/log-probability metadata
    updated constraint/controller/RNG state
    diagnostic and fallback events

Most policy transforms do not commute

An additive bias and temperature give:

Applying top-k before a repetition penalty can permanently remove a token that the penalty would have promoted relative to others. Applying top-p before a hard grammar mask can select a nucleus containing no legal token. A safe grammar-oriented ordering is commonly:

raw scores
    -> mandatory token suppression / vocabulary legality
    -> prefix-dependent penalties and biases
    -> adaptive or fixed score warping
    -> support truncation
    -> final legal-support assertion
    -> normalization
    -> selection

That ordering is a design, not a universal law. Some algorithms define their thresholds in probability space and require an earlier normalization. The manifest must pin the exact graph rather than relying on the words “processor” and “warper.”

Hard constraints define a conditional support

Let be the legal token set in constraint state . A logit-space mask is:

The resulting distribution is the model policy conditioned on that legal set, after any other declared transforms. It is not the original full-softmax distribution. The state transition must use the emitted token:

Before normalization:

if not any(isfinite(score) for score in constrained_scores):
    if empty_support_policy == "raise":
        raise EmptySupportError(constraint_state, step)
    constrained_scores = declared_fallback(...)

Silently restoring every raw logit defeats the constraint. Silently forcing EOS is also wrong unless EOS is legal and the fallback contract declares it.

Request-owned randomness and replay

A global generator consumed in rectangular batch order couples samples to batch composition. Removing a finished row or changing scheduler order can shift every later draw. Request-owned streams instead key randomness to a stable request identity and explicit draw schedule:

rng identity:
    algorithm/version
    base seed or key
    request/beam owner
    decoding step
    draw counter

draw contract:
    how many draws a selector consumes
    whether rejected or fallback paths consume draws
    how beam forks derive child streams

The strongest replay artifact records the processed support and selected draw metadata in addition to the seed. Floating-point or kernel changes can alter probabilities enough that the same uniform variate crosses a different cumulative boundary.

Local policy trace and assertions

def policy_step(raw_logits, request_view, state, config):
    scores = assert_finite_or_declared(raw_logits)
    trace = [summary("raw", scores)]

    for transform in config.ordered_transforms:
        scores = transform(scores, request_view, state)
        trace.append(summary(transform.name, scores))

    assert scores.shape == raw_logits.shape
    assert at_least_one_finite_score_per_active_row(scores)

    distribution = normalize_if_required(scores, config.selector)
    decision, rng_state = config.selector(distribution, state.rng)
    next_constraint = transition(state.constraint, decision)

    return decision, state.replace(
        rng=rng_state,
        constraint=next_constraint,
    ), trace

Useful trace fields are top-score margin, entropy, finite support size, legal support size, removed target/special IDs, selected raw and processed score, selected log-probability, RNG counter, and fallback reason. These are policy observations, not claims that the selected token is semantically correct.


0x0C Greedy decoding and temperature

Greedy is a local argmax

Greedy decoding selects

Softmax is unnecessary because it preserves order:

Greedy decoding maximizes one conditional step, not the full sequence objective

The sequence objective is

Choosing the best token at each step need not maximize that sum over completed sequences. This is search myopia, not an implementation bug in argmax.

Temperature rescales logit gaps

For ,

Pairwise log-probability ratios become

Thus magnifies every gap and contracts it. Positive temperature does not change ranking, but it changes stochastic mass and any probability-dependent support filter.

Temperature also gives an exact entropy result. Let

Writing inverse temperature gives

Differentiate using :

Entropy increases monotonically with positive temperature unless all supported logits are equal under the distribution. This derives “higher temperature is flatter” rather than leaving it as a slogan.

T=0 is not valid division. A user API may interpret it as greedy, but the implementation must branch to argmax.

Dynamic temperature is another policy

A policy may choose from entropy, divergence, or generated history. That can adapt exploration to the current score row, but it defines a history-dependent distribution and requires its own calibration, bounds, and reproducibility tests.

One source method adjusts temperature from divergence rather than using one global constant

The figure is a source-reported method design, not evidence that divergence-guided temperature universally improves generation.


0x0D Multinomial, top-k, and nucleus sampling

Multinomial needs nonnegative mass

probs = torch.softmax(scores, dim=-1)
token_ids = torch.multinomial(probs, num_samples=1, generator=generator)

Raw logits may be negative and are invalid as the weight argument to torch.multinomial. A categorical API explicitly parameterized by logits performs its own normalization; that is a different interface.

An explicit torch.Generator controls this draw. End-to-end reproducibility additionally requires stable upstream logits, processor order, batch/RNG assignment, kernels, and model state.

Top-k: fixed cardinality

Top-k retains the k highest scores and removes the rest:

def top_k_filter(logits, k):
    if not 0 < k <= logits.size(-1):
        raise ValueError("k must be in [1, V]")

    values, indices = torch.topk(logits, k, dim=-1)
    filtered = torch.full_like(logits, -torch.inf)
    return filtered.scatter(-1, indices, values)

After filtering, softmax renormalizes over retained finite entries. Threshold-based implementations can retain more than k entries under ties; torch.topk itself does not promise stable tied indices. Exact reproducibility must define tie behavior.

Top-k retains a fixed number of highest-scoring candidates before renormalization and sampling

Top-p: dynamic probability mass

Nucleus sampling sorts probabilities and retains the smallest prefix whose cumulative mass reaches .

def sample_top_p(probs, p, generator=None):
    if not 0.0 < p <= 1.0:
        raise ValueError("p must be in (0, 1]")

    sorted_p, sorted_ids = probs.sort(dim=-1, descending=True)
    cumulative = sorted_p.cumsum(dim=-1)

    # Keep the item that crosses p.
    remove = cumulative - sorted_p >= p
    sorted_p = sorted_p.masked_fill(remove, 0.0)

    z = sorted_p.sum(dim=-1, keepdim=True)
    if torch.any(z <= 0):
        raise RuntimeError("empty nucleus")
    sorted_p = sorted_p / z

    sampled_sorted = torch.multinomial(sorted_p, 1, generator=generator)
    return sorted_ids.gather(-1, sampled_sorted)

For sorted probabilities [0.52, 0.25, 0.13, 0.06, 0.04] and p=0.80, the retained prefix contains three tokens because 0.52+0.25=0.77 is below the threshold and adding 0.13 crosses it.

Top-p adapts support size to cumulative probability mass

The nucleus paper contrasts flat and peaked distributions: one fixed k may be too small in a flat context and too permissive in a peaked context.

Flat and peaked distributions motivate adapting support to mass rather than one fixed candidate count

Active temperature, top-k, and top-p generally change the model’s full-softmax distribution. They are policy choices, not distribution-preserving acceleration.

One row through the full sampling pipeline

Take vocabulary rows [A,B,C,D,E] and raw logits

z = [3.0, 2.0, 1.0, 0.0, -1.0]

Suppose C is forbidden, T=2, k=3, and p=0.80.

  1. Constraint processing:

    [3.0, 2.0, -inf, 0.0, -1.0]
    
  2. Temperature:

    [1.5, 1.0, -inf, 0.0, -0.5]
    
  3. Top-k retains A,B,D:

    [1.5, 1.0, -inf, 0.0, -inf]
    
  4. Softmax over retained support is approximately:

    A: 0.547
    B: 0.331
    D: 0.122
    
  5. Top-p with p=0.80 keeps A and B because their cumulative mass is 0.878, then renormalizes:

    A: 0.623
    B: 0.377
    

The final draw is not from the original model distribution, nor from temperature alone, nor from top-k alone. It is from the composition in the declared order.


Sampling-family contracts beyond top-k and top-p

Most truncation methods create a support set and then sample from the renormalized distribution:

They differ in how is constructed. Once active, none preserves the original full-softmax policy.

MethodControlled quantitySupport rulePersistent state
top-kcardinalityk highest scoresnone
top-pcumulative probability masssmallest probability-ranked prefix reaching pnone
locally typicaldistance from expected surprisalprobability mass ranked by surprisal deviationnone
eta samplingentropy-dependent probability floorprobability above adaptive eta thresholdnone
min-pprobability relative to current maximumprobability at least alpha times maximumnone
top-n-sigmadistance below maximum in logit standard deviationslogit at least max minus n sigmanone
Mirostatobserved token surprisal/perplexitycontroller-adjusted truncationrunning controller value
dynamic temperatureentropy/divergence/task signalfull or subsequently truncated support after T_tcontroller inputs/state

Locally typical support

For model distribution , token surprisal and row entropy are:

Locally typical sampling ranks tokens by:

and retains a probability-mass-limited prefix in that ranking. Unlike top-p, the maximum-probability token need not rank first: its surprisal can be farther from the expected information content than a moderately probable token.

Eta sampling

The desmoothing interpretation treats low-probability mass as partly induced by a smoothing distribution. In the notation used by Hewitt et al., an entropy-sensitive threshold can be written:

Candidates below the threshold are removed. In a high-entropy row, is small and the rule relaxes the absolute floor; in a low-entropy row it behaves more like a fixed epsilon cutoff. The epsilon definition and strict/equality convention remain policy fields.

Min-p and relative logit gaps

Min-p retains:

Because the softmax denominator cancels, this is equivalent to:

After temperature scaling, the equivalent raw-logit condition is:

Thus increasing temperature widens the admissible raw-logit gap for fixed alpha. The method has an intuitive implementation and a primary proposal with reported evaluations, but a later critical analysis disputes superiority claims from that evidence. M3.8 therefore treats min-p as a mechanism, not an established winner.

Top-n-sigma and affine invariance

Top-n-sigma, reconstructed from A15 and its primary paper, keeps:

Under a positive affine score transformation :

The support is therefore invariant to positive temperature scaling when the standard deviation is measured on the same transformed score row. It is not invariant to arbitrary token-wise biases or penalties.

A15's source figure shows the paper-reported peaked tail and broad background of one evaluated model/task; this motivates the threshold but does not prove Gaussian noise for every checkpoint or prompt

The source method retains logits within n standard deviations of the maximum before sampling; threshold equality, transform order, and fallback remain runtime contracts

Feedback-controlled surprise and temperature

Mirostat targets a chosen surprisal rather than one fixed support parameter. A schematic controller observes emitted-token surprise and updates:

The controller then maps to the next truncation parameter. The exact Mirostat version, Zipf estimate, units (bits or nats), gain, initialization, clamps, and update timing are part of the policy state. Resetting at every token reduces the method to a misnamed stateless heuristic.

Dynamic-temperature methods instead set . A15 surveys KL-guided, rule-based code, and entropy-based variants. They use different signals and costs: one may require a second model distribution, another token-type rules, and another the current row entropy.

A15's EDT figure computes row entropy, maps it to a temperature, renormalizes, and samples; its quality claims remain source-reported and task-dependent

Sensitivity and evaluation contract

Sampler comparisons must sweep controls rather than compare arbitrary defaults:

fixed checkpoint and tokenizer
fixed prompt/evaluation manifest
fixed processor and constraint order
request-owned seeds and enough repeated draws
matched output-length and stopping policy
quality, diversity, repetition, calibration, and latency reported separately
support size / entropy / fallback telemetry

Failure geometry differs by method:

FailureLikely cause
support collapses to one tokenaggressive k/p/epsilon/alpha/n or concentrated row
incoherent tail enterspermissive truncation or high temperature
controller oscillatesexcessive gain, delayed observation, missing clamp
adaptive state leaks across requestscontroller stored globally
no legal token remainstruncation composed incorrectly with hard constraint
paper result does not reproducetokenizer, model, prompt, metric, or implementation mismatch

No one scalar ranks policies universally. A policy that improves creative diversity can be inappropriate for exact extraction, constrained code, or target-policy verification in M7.

0x0E Score processors, repetition, and hard constraints

Processors can depend on read-only prefix state even though M3.10 owns advancing that prefix.

Additive token bias

For bias vector ,

In probability space this multiplies unnormalized mass by :

Setting forbids a token. At least one finite score must remain.

Sign-sensitive repetition penalty

One common implementation applies penalty to previously generated token rows as

Both branches reduce the penalized token’s relative score: positive values shrink; negative values become more negative. Dividing every logit regardless of sign can increase a negative score toward zero and accidentally reward it.

seen_scores = scores.gather(-1, prefix_ids)
seen_scores = torch.where(
    seen_scores < 0,
    seen_scores * penalty,
    seen_scores / penalty,
)
scores = scores.scatter(-1, prefix_ids, seen_scores)

Repetition penalties modify already generated token rows before normalization

This particular rule is a library/paper convention, not the only repetition control. Frequency penalties, presence penalties, no-repeat n-gram constraints, and contrastive penalties define different functions.

Hard constraints and finite-state policy

Minimum length may forbid EOS until a step threshold. Bad-word or grammar constraints may mask tokens based on a finite-state machine. Forced-prefix decoding can leave exactly one legal token at a step.

constraint state + prefix
    -> legal vocabulary mask [V]
    -> processed scores [V]

The local policy consumes the state; the outer loop owns updating and checkpointing it. Beam search requires one constraint state per beam and must reorder it with parent IDs.


0x0F Beam search: joint parent/token candidates

For K active beams:

local logits:   [B,K,V]
beam scores:    [B,K]
candidate grid: [B,K,V]

Using log probabilities,

Flatten the parent and vocabulary axes and retain K candidates:

def beam_step(logits, beam_scores, beam_width):
    B, K, V = logits.shape
    log_probs = torch.log_softmax(logits, dim=-1)
    candidates = beam_scores[..., None] + log_probs
    next_scores, flat_ids = candidates.reshape(B, K * V).topk(
        beam_width, dim=-1
    )
    parent_ids = flat_ids // V
    token_ids = flat_ids % V
    return next_scores, parent_ids, token_ids

The quotient/remainder derivation follows the parent-major flattened index:

Parent IDs are mandatory metadata. Prefix tokens, attention masks, position state, constraint state, and every K/V cache layer must follow the same reorder.

Beam search retains a bounded frontier rather than exploring the full sequence tree

First-step and finished-set contracts

If all initial beams represent the same prefix, activate only one:

beam_scores = torch.full((B, K), -torch.inf, device=logits.device)
beam_scores[:, 0] = 0.0

Otherwise the first expansion can duplicate candidates from identical parents. EOS candidates usually move to a finished set while additional live candidates fill the beam frontier. Stopping when the first EOS appears is not generally safe.

Length penalty

Raw log-probability sums favor shorter sequences because each additional term is non-positive. One generic normalized score is

where may be or a smoothed function such as

The exact formula, when it is applied, and how it enters early-stopping bounds are framework contracts. A length penalty changes ranking; a no-repeat n-gram rule changes legal continuations.

Finite K remains approximate. Even K=V is not exhaustive after multiple steps because the number of prefixes grows as .


0x10 Search policies and alternative output architectures

Sampling changes one local conditional distribution. Search instead retains or revisits multiple prefixes, and alternative output architectures change how the vocabulary distribution is parameterized or trained. These are separate design axes.

Search policies are objectives over prefixes

For prefix , the unnormalized sequence score is:

SearchFrontier/orderExtra model stateObjective caveat
greedyone live prefixone cachelocal argmax, not sequence optimum
beamtop K prefixes per depthK caches and metadatafinite-width pruning and length bias
diverse beamgrouped beams plus diversity penaltygroup/frontier statemodified ranking objective
best-first beampriority queue across depthsbounded queue plus cachespriority and stopping rule must be pinned
A*-style searchpath score plus heuristicqueue, heuristic stateguarantees require heuristic assumptions
best-of-N/verifiercomplete rollouts ranked by verifierN rollouts and verifiernot model-likelihood beam search

Encoder-decoder search can add source coverage. The GNMT-style family combines log-likelihood, length normalization, and an attention-coverage term:

The exact length exponent, coverage clipping, attention tensor, and stopping bound are one search contract. Coverage has no direct analogue when the model does not expose encoder-decoder attention.

A15's GNMT source figure combines model score, length normalization, and encoder-attention coverage; it is a translation-search contract rather than a universal decoder-only score

Best-first beam changes expansion order. Instead of synchronously expanding all live prefixes at depth t, it pops the highest-priority item from a bounded queue, expands it, and reinserts candidates. Priority can use path score, length normalization, or a heuristic:

Calling a search “A*” does not establish optimality; the heuristic and stopping conditions must satisfy the paper’s assumptions.

A15 reuses the Best-First Beam Search paper's replaceable queue/score/stopping algorithm; concrete guarantees depend on the selected components

Policies that request more than one finished logit row

Contrastive search combines model confidence with a representation-degeneration penalty:

Evaluating candidate hidden state for several tokens requires additional model work or a specialized batched path. It is not merely a function of the already finished score row.

DoLa contrasts a mature-layer distribution with one selected premature-layer distribution. A schematic contrast is:

Layer selection, candidate restriction, normalization, and fallback are part of the method. This reaches into intermediate states and must not be confused with ordinary final-layer temperature.

Self-evaluation decoding methods detect uncertain or “chaotic” positions, construct alternatives, and ask the model or another evaluator to score them. They add candidate-generation and evaluation calls, their own prompt/template, and extra cache state.

A15's SED process adds a self-evaluation branch after uncertainty detection; its reported gains are method-specific and the extra model work must be counted

Test-time best-of-N, verifier-guided rollouts, filler/pause tokens, and latent reasoning likewise change the number or type of model steps. They cross from a single local policy into M3.10 execution or M7 proposal/verification and are kept as boundaries here.

Alternative output heads change training and inference

Architecture/objectiveTraining pathFull-vocabulary inferenceContract change
full affine softmaxscore and normalize all V rowsdirect full distributionbaseline used above
hierarchical softmaxtarget path through a class/tree hierarchytraverse or score hierarchytoken probability is product of path decisions
adaptive softmaxfrequent shortlist plus rare-token clustersevaluate head and required tailslearned cluster assignment and dimensions
sampled/importance softmaxestimate objective from target plus sampled negativesusually still needs full or specialized headestimator, proposal, and correction
shortlist/importance NMTtrain against a selected vocabulary subsetselected or full vocabulary by deploymentsubset construction is part of objective
mixture of softmaxesmix several normalized componentsseveral projections/softmaxesincreases expressivity and compute

In a hierarchical head, a word probability is a product over decisions on its root-to-leaf path:

This can replace an O(V) normalization with path work, but tree construction affects both computation and learned confusion structure.

Adaptive softmax uses token-frequency imbalance. A frequent word can be scored in a short head path; a rare word uses a cluster probability and conditional tail probability:

Cutoffs, cluster ownership, tail dimensions, and weight tying are checkpoint architecture. This is not a drop-in inference warper over full-softmax logits.

Sampled and importance objectives avoid evaluating every negative class during training. Unless the estimator and correction recover the declared full objective, they optimize an approximation. At inference, the system still needs a way to rank the intended output vocabulary.

Why a single softmax has an expressivity bottleneck

For context matrix and output matrix , unnormalized scores are:

The log-probability matrix subtracts one row normalizer:

Therefore:

The softmax-bottleneck analysis asks whether the target family of conditional log distributions requires higher rank. Mixture of Softmaxes combines several component distributions:

The logarithm of that mixture is not one low-rank affine score matrix minus one normalizer, so it can represent a richer family at the cost of multiple heads, normalizations, and mixture state. It is an architecture/training choice, not a sampling method.

Paper-by-contract comparison

MethodChanges weights/training?Needs extra forward work?Preserves base local distribution?Primary audit question
beam / best-firstnomultiple live prefixesranks sequence likelihood unless penalties modify itare queue, score, stop, and cache reorder exact?
contrastive searchpossibly contrastive training; decode rule changescandidate hidden statesnois degeneration score computed for the intended candidates?
DoLano base retraining required by methodintermediate-layer projectionsnoare mature/premature layers and candidate mask pinned?
SEDno base retraining required by methodself-evaluation callsnois extra work and evaluator prompt included?
adaptive/hierarchical softmaxyes, head architecturespecialized head pathdefines a different normalized modelcan checkpoint/token probabilities be reconstructed?
sampled objectiveyes, training estimatorfewer training classesestimator-dependentare proposal and correction unbiased/declared?
mixture of softmaxesyesmultiple component headsdefines a different modelare mixture gates and component normalizers correct?

Logit diagnostics are observations, not decoding rules

A score row exposes several useful diagnostics:

top-1 margin:
    z_(1) - z_(2)

entropy:
    -sum_v p_v log p_v

effective support / perplexity of the row:
    exp(H(p))

normalizer:
    logsumexp(z)

energy-style score:
    -T * logsumexp(z / T)

The top-1 margin is invariant to adding a constant to all logits but changes under temperature scaling. Entropy depends on the full distribution. A large margin or low entropy means the policy is concentrated; it does not establish semantic correctness or calibrated confidence.

Calibration asks whether confidence frequencies match empirical outcomes under a declared task and grouping. Token-level calibration is complicated by multiple valid continuations and sequence dependence. Temperature scaling fitted on held-out data can improve one calibration metric while changing generation diversity; the fitted temperature is a deployment policy artifact, not a new base-model weight.

Logit lens and intermediate unembedding

Because every residual row has width d_model, one can apply the final norm/head approximately or directly to an intermediate layer:

This logit lens asks which vocabulary directions are already visible. It is an analysis intervention:

intermediate row
    -> final-normalization convention
    -> shared output head
    -> diagnostic logits

The actual model still sends through later attention, MLP, residual, and normalization operations. Intermediate top tokens are not promises about the final prediction.

Tuned lenses learn a translator for each layer before unembedding. Better predictive agreement may mean the translator compensates for representation mismatch; it does not prove that the unmodified intermediate state was literally using the final vocabulary basis.

Vocabulary bias and score preprocessing

Frequent-token priors, tokenizer segmentation, output bias, and embedding norms can all influence raw scores. Subtracting an empirical prior or calibrating logits defines a modified policy:

where is a reference token frequency. This can be useful in a studied setting, but it is not a universally correct “debiasing” operation. The reference corpus, zero-frequency smoothing, tokenizer, and become part of the policy contract.

Likewise, a source article may visualize compressed information in logits or propose preprocessing based on a secondary distribution. Such a transformation must be evaluated as an explicit processor with baseline, ablation, and task-specific metrics rather than imported as an assumed improvement.

Hidden reasoning and filler tokens cross the local boundary

Pause tokens, chain-of-thought tokens, and latent-reasoning methods spend additional model steps before the final answer. They can change the hidden state that reaches the output head:

ordinary policy:
    one state -> one output decision

filler / visible reasoning:
    select extra tokens -> run additional model steps -> later decision

latent reasoning:
    evolve hidden state under an architecture-specific recurrence -> later head

These methods are not equivalent to lowering entropy on the same fixed score row. Their evaluation must account for additional tokens/compute, training distribution, answer extraction, and whether intermediate reasoning is visible or latent.


0x11 Shape and type ledger

ObjectShapeType / meaning
final hidden matrix[B,S,d_model]Continuous states after final norm.
one decision row[B,d_model]Last valid or otherwise selected row.
algebraic output matrix W_U[d_model,V]Row-vector notation.
PyTorch lm_head.weight[V,d_model]Stored nn.Linear orientation.
optional output bias[V]Added to every output row.
all-row logits[B,S,V]Raw unnormalized scores.
one-step logits[B,V] or [B,1,V]Raw scores for decision rows.
probabilitiessame as logitssoftmax(logits, dim=-1).
log-probabilitiessame as logitslog_softmax(logits, dim=-1).
class-index labels[B,S] or flattened [B*S]Integer target IDs.
distribution labels[B,S,V] or flattened [B*S,V]Label-smoothed/soft targets.
selected token IDs[B] or [B,1]Local policy output; M3.10 appends and advances state.
beam candidate scores[B,K,V]Parent sequence score plus local log-probability.
flattened beam candidates[B,K*V]Joint parent/token candidate axis.
parent beam IDs[B,K]Prefix/cache reorder metadata.
next beam token IDs[B,K]Retained vocabulary IDs.

Score-type contract

TensorValid direct consumers
raw logitscross entropy, argmax, temperature, score processors, softmax/log-softmax
log-probabilitiesNLL/KL-style losses, argmax, sequence log-score sums, exp
probabilitiesmultinomial sampling, cumulative top-p mass, probability reporting

Official implementation reconciliation

The mathematics above is implementation-independent; runtime behavior is not. This reconstruction pins three official source snapshots:

Runtime evidenceRevisionContract observed
Hugging Face Transformersv5.13.1, commit 4626421LLaMA bias-free head, tied-weight metadata, row slicing, ordered generation processors
NVIDIA Megatron-LMmain snapshot 5adbee2global MAX/SUM vocabulary-parallel cross-entropy and saved softmax shard
vLLMmain snapshot 7b50d2cfloat32 sampler path with explicit legality, processor, penalty, temperature, min-p, top-k/top-p, and selector order

The Transformers snapshot appends sampling transforms in an explicit sequence that includes temperature, top-h, top-k, top-p, min-p, typical, and epsilon cutoffs after its earlier processors. It explicitly places min-p after temperature. The vLLM snapshot uses a different staged pipeline: whitelist and bad-word suppression, non-argmax-invariant processors, penalties, greedy candidate, temperature, min-p, top-k/top-p, then random/greedy selection.

Neither order is the universal mathematical definition. They demonstrate why framework, version, and ordered transforms belong in the release manifest.

The pinned Megatron snapshot implements:

local logits -> global MAX
target owner/masked local target
target-score SUM
denominator SUM
loss and local normalized shard
saved normalized shard + target mask/index
owner-only subtraction in backward

Its label-smoothing path uses implementation-specific algebra. A release that enables smoothing must compare per-row loss and local shard gradients with the declared global-V convention rather than assuming the same parameter name implies the same target distribution.

Evaluation ladder

LayerRequired testMain invariant
head unittiny affine oracle and finite differenceslogits and dH/dE/db
normalizationextreme logits, translation, smoothingstable loss and P minus Q
training schedulematerialized versus chunked/fusedper-row loss, valid sum/count, gradients
vocabulary migrationpermutation/append/tied aliasmapped raw logits and one optimizer owner
distributed lossfull versus sharded oracleloss, local gradients, target owner
processor pipelineorder, masks, fallbacknonempty legal support and declared score types
stochastic policyrepeated seeded draws and distribution testrequest-owned replay plus statistical agreement
searchtoy exhaustive tree for small V/Tparent/token IDs, score, stopping, state reorder
end to endfixed prompts and policy manifestoutput IDs/log-probs within declared determinism tier

Statistical policies need more than one golden string. For a fixed processed row, draw many samples and compare empirical frequencies or a categorical goodness-of-fit statistic under a predeclared tolerance. End-to-end generation then adds prompt, stopping, length, batch, and scheduler dimensions.

Release, canary, and rollback

A releasable output-policy bundle contains:

tokenizer and ordered vocabulary hash
model/head/checkpoint and tying manifest
loss and sharding manifest
processor/warper/constraint graph
search or selector configuration
RNG algorithm and request-stream policy
runtime/framework/kernel revisions
evaluation corpus/split and acceptance thresholds
previous known-good bundle identifier

Release stages:

  1. Run all local numerical and migration oracles.
  2. Compare pinned reference and candidate runtimes on fixed hidden rows.
  3. Run deterministic prompt cases and statistical sampler cases.
  4. Canary by request class with old/new policy telemetry side by side.
  5. Gate on invalid-support, NaN, fallback, stop, latency, quality, diversity, and constraint-violation metrics.
  6. Promote the immutable bundle, retaining a one-action rollback target.

Rollback restores tokenizer, checkpoint, aliases, policy, RNG semantics, and runtime together. Rolling back only temperature while keeping a changed vocabulary or transform order does not restore the old behavior.

Claim and visual evidence contract

This article uses four evidence labels:

Source-local:
    reconstructed from A2/A15; may include a source correction

Externally verified:
    supported by a primary paper or pinned official implementation

Rewrite interpretation:
    derived synthesis, engineering rule, or audit recommendation

Uncertain / source-reported:
    empirical or implementation-sensitive claim kept within its source scope

Reused A15 figures are retained when they teach an owned mechanism. Captions state whether the figure is a generic tensor contract, a paper-specific algorithm, or one experiment. Figures about pause tokens, latent reasoning, and multi-step proposal systems are not promoted into M3.8’s local policy spine.

0x12 Failure lab

Hidden-state and projection bugs

  1. Treating final hidden states as logits. [B,S,d_model] is not vocabulary-indexed unless d_model == V by meaningless coincidence.

  2. Skipping the final norm expected by a Pre-LN checkpoint. The head receives same-shaped but wrong hidden states.

  3. Applying the target LM head directly to encoder memory. Encoder-decoder generation projects decoder-owned target rows.

  4. Transposing the PyTorch output weight manually. nn.Linear already uses stored [V,d_model] weights as weight.T in the forward calculation.

  5. Loading a bias-free checkpoint into a biased output head. An extra [V] parameter changes logits even though the main weight shape matches.

  6. Projecting an MLP intermediate. The head expects model-width final states, not [B,S,d_ff] branch activations.

Score-type bugs

  1. Calling logits probabilities. Raw scores can be negative and do not sum to one.

  2. Calling every multiclass logit binary log-odds. Vocabulary probabilities depend on the full row normalization.

  3. Softmax over the sequence axis. dim=-1 must normalize vocabulary candidates for each state row.

  4. Applying softmax to probabilities again. This changes the distribution.

  5. Claiming softmax over normalized log-probabilities changes the distribution. It recovers probabilities mathematically; the operation is merely redundant.

  6. Computing log(softmax(logits)) as separate low-precision operations. Use the numerically stable log_softmax implementation.

  7. Sampling raw logits with torch.multinomial. Multinomial weights must be non-negative; probability conversion belongs before sampling.

  8. Using A15’s bare log_softmax without importing that symbol. With import torch.nn.functional as F, call F.log_softmax.

Training-interface bugs

  1. Passing probabilities into CrossEntropyLoss. The official contract expects unnormalized logits.

  2. Passing raw logits into a KL/NLL path expecting log-probabilities. The head and criterion conventions disagree.

  3. Taking argmax before the training loss. Discrete selection breaks the intended differentiable vocabulary-score path.

  4. Flattening [B,T,V] as if T were the class axis. Preserve V as the final class dimension: [B*T,V].

  5. Shifting labels inside both the model and data pipeline. Output-head shape survives while supervision moves two positions.

  6. Training PAD or ignored rows as ordinary target IDs. M3.9’s label mask or ignore_index must agree with the loss.

Inference-row bugs

  1. Using hidden[:, -1] with right-padded unequal prompts. Shorter rows project a PAD-position state.

  2. Applying argmax over sequence length. The returned index is a time position, not a vocabulary ID.

  3. Computing all prompt logits and accidentally selecting the first row. Every tensor is valid, but the decision conditions on the wrong prefix position.

  4. Reading logits_to_keep=0 as zero logits. In the Transformers v5.13.1 LLaMA slice convention it selects all positions.

Vocabulary and tying bugs

  1. Tokenizer ID order differs from output-row order. Scores decode to the wrong strings while shapes remain valid.

  2. Adding tokenizer entries without resizing/adapting the output rows. New IDs are missing or use untrained vocabulary weights.

  3. Resizing only the input embedding in an untied model. Lookup accepts new IDs but the head cannot score the same output space.

  4. Copying embedding values and claiming the weights are tied. Separate Parameters diverge after optimization.

  5. Tying source, target, and output matrices with incompatible vocabularies. Equal shapes do not establish shared token identity.

  6. Assuming every LLaMA-style checkpoint ties embeddings. The architecture supports configuration-specific behavior; verify actual parameter identity.

  7. Creating the optimizer before replacing one Parameter with a tied reference. The optimizer can retain a stale parameter object or duplicate state.

  8. Treating tied output rows as cosine-nearest neighbors. The head computes learned dot products, optionally plus bias; vectors are not necessarily unit-normalized.

Boundary bugs

  1. Putting top-k, top-p, beam state, or EOS handling inside the learned LM-head module. M3.8 owns the adjacent policy interface, but the head itself remains a learned projection and the outer loop owns persistent state.

  2. Treating the local projection ledger as a complete runtime model. M3.8 counts output-head parameters, MACs, logical logits, and local policy objects. M4.1 combines those counts with the rest of the model and analyzes materialization and hardware traffic.

Policy and search bugs

  1. Passing raw logits to torch.multinomial. Convert to nonnegative probability weights or use an API explicitly accepting logits.

  2. Dividing by temperature=0. Greedy is a branch or a limit, not literal zero-temperature arithmetic.

  3. Assuming temperature can change top-k membership. Positive temperature preserves ranking unless another transform intervenes; it can still change top-p support.

  4. Dropping the top-p threshold-crossing token. The remaining support can have cumulative mass below p.

  5. Returning a top-p sorted position as the vocabulary ID. Gather through the sort permutation.

  6. Assuming threshold top-k retains exactly k tokens under ties. An equality policy can keep more than k, while selected tied indices can be unstable.

  7. Applying one repetition formula to positive and negative logits. Dividing a negative value moves it toward zero and can increase its relative score.

  8. Masking every token to negative infinity. No categorical distribution remains; raise or provide an explicit legal fallback.

  9. Ranking beam tokens without parent sequence scores. Search then chooses local tokens rather than scored continuations.

  10. Using % K to decode a flattened beam candidate token. The fast-changing axis has width V; token is flat_id % V.

  11. Reordering beam token IDs without all beam-owned state. Cache, positions, masks, constraints, RNG state, and prefix metadata must follow parent IDs.

  12. Initializing every duplicate first-step beam at zero. Identical parents can occupy the frontier with duplicate candidates.

  13. Stopping at the first EOS without a valid score bound. A live hypothesis may still outrank the finished one under the configured length score.

  14. Calling active top-k/top-p distribution-preserving. They intentionally truncate the original full-softmax policy.

  15. Treating a seeded local draw as complete reproducibility. Batch order, upstream numerics, processor order, and random-stream ownership also matter.

  16. Calling test-time best-of-N or verifier-guided rollout ordinary beam search. These methods add complete rollouts and an external or learned verifier objective.

Extended contract failures

  1. Averaging chunk means instead of accumulating loss sum and valid count. Uneven chunks or ignore masks receive the wrong weight.

  2. Saving only the scalar loss as a fused-kernel conformance check. Row permutations and wrong gradients can cancel in the mean.

  3. Using vocabulary size instead of ordered vocabulary identity. Equal shapes can attach every score to the wrong token.

  4. Appending rows and claiming old probabilities are unchanged. New rows enter the softmax denominator even when old raw logits match.

  5. Migrating model rows but not optimizer moments or master weights. The next update applies old state to the wrong token address.

  6. Restoring tied values without restoring one Parameter and optimizer owner. Subsequent gradients and moments diverge.

  7. Normalizing each vocabulary shard independently. Local shard probabilities do not form the global model distribution.

  8. Subtracting the target on every vocabulary rank. Only the rank that owns the global target row applies the one-hot term.

  9. Skipping a distributed loss collective only on ignored rows of one rank. Collective schedules diverge and can deadlock.

  10. Applying top-p separately on each vocabulary shard. Local cumulative supports are not the global probability-ranked nucleus.

  11. Sharing one adaptive controller across requests. Mirostat or dynamic temperature state leaks history between users.

  12. Treating min-p benchmark superiority as settled. The mechanism is valid, while published evaluation claims have been critically disputed and remain source-scoped.

  13. Calling sampled softmax an inference sampler. It is a training-objective approximation/family, not top-k-style decoding.

  14. Calling adaptive or hierarchical softmax a drop-in warper. They change checkpoint architecture and token-probability factorization.

  15. Assuming an A-named search is optimal without heuristic conditions.* Queue priority and stopping guarantees depend on the actual heuristic.

  16. Comparing two runtimes without pinning policy order and log-prob mode. The same named knobs can produce different transformed scores and metadata.


0x13 Handoff to training, inference, and acceleration

M3.8 contains the complete local learned-to-policy boundary:

hidden: [B,d_model]
    -> lm_head
logits: [B,V]

The policy can now return a token or beam decision:

logits: [B,V]
    -> optional score processors / temperature
    -> probability conversion when required
    -> greedy, top-k, top-p, or beam policy
selected token IDs: [B] or [B,1]

M3.9 consumes all supervised logit rows to train the model. M3.10 appends selected IDs, stops finished rows, calls the next model step, and maintains cache state. M7 owns speculative and multi-token acceleration while preserving its declared target policy.


0xFF References

Local source and neighboring contracts

Output geometry, objectives, and large vocabularies

Sampling and adaptive decoding policies

Search and multi-pass decoding

Pinned implementations and API contracts