2026/09/04 19.6k words

Transformer System #numinens#transformer#encoder#representation#pooling#task-head#classification#token-classification#question-answering#sentence-embedding#retrieval#cross-encoder#bi-encoder#late-interaction

M3.11 — Representation Readout and Task-Head Inference

M3.11 — Representation Readout and Task-Head Inference

0x00 Contextual Rows Are Not Yet A Task Result

M3.10 closed one autoregressive request: a selected vocabulary token is appended, model state advances, and the loop repeats until a stopping contract closes the output. That is only one way to consume Transformer state.

An encoder-style call can expose all valid contextual rows at once:

input IDs and metadata
    -> embeddings and positional state
        -> full-visibility Transformer blocks
            -> contextual rows H [B,S,D]

This is an explicit input contract. Tokenization is complete, M2.2 has already constructed the initial rows, and M3.1-M3.7 have already contextualized them. M3.11 receives H plus row/task metadata; it does not reopen token-ID lookup, input-table initialization, positional composition, or block internals.

The tensor is useful, but it is not yet any of these objects:

a sequence label
a real-valued prediction
one label per source token
an extractive answer span
a fixed-width search vector
a query-document relevance score

Those outputs require a readout contract. The contract states which rows are valid, which rows are selected or pooled, which learned map consumes them, which score type is produced, and which decision or similarity rule follows. Changing any one of those objects can preserve tensor rank while changing the meaning of the model.

Owner question

How do complete contextual rows become pooled vectors, sequence or token predictions, extractive spans, and retrieval scores without confusing the readout architecture with its training objective or serving system?

This article follows the path:

contextual rows H [B,S,D] + valid-row/task metadata
    -> row selection or pooling
        -> task projection or representation normalization
            -> typed logits, spans, vectors, or pairwise scores
                -> task decision and release artifact

It does not assume that “use the [CLS] token” is a universal algorithm. It does not call a cosine score a probability. It does not treat a dual encoder as a cheaper cross encoder with unchanged semantics. It derives the object that each method changes.

Why the generative endpoint was not enough

M3.8 owns the learned map from hidden width to an ordered vocabulary axis:

That head is tied to token identity. A sequence classifier instead maps one readout vector to a task label axis of width :

A token classifier preserves the row axis:

An embedding system may produce no class logits at all:

The final scalar is a similarity or relevance score under a declared geometry, not automatically a calibrated probability. These paths share a contextual backbone while defining different output axes, persistent state, training objectives, and reusable runtime artifacts.

A contextual tensor with batch, row, and channel axes branches into pooled sequence heads, row-preserving token and span heads, and representation or retrieval readouts.

Reconstructed owner map. Every branch consumes contextual state, but the branch chooses a different row transformation and output identity. A shared backbone does not make the heads interchangeable.

Historical pressure: representations made task heads small, not trivial

Earlier task systems often trained a task-specific encoder and output module together. The pretraining-and-fine-tuning program changed that allocation: learn a contextual encoder from broad text, then adapt it with a comparatively small output layer for a downstream task. BERT is a primary example. Its paper describes a deep bidirectional encoder representation and reports adaptation to classification and extractive question answering with little task-specific architecture beyond output layers. This is an externally verified statement about that system, not a claim that every task needs only one linear layer. (Devlin et al., 2018)

The change exposed a new interface:

pretrained contextual state
    -> task-specific readout
        -> task-specific loss and decision

The interface later split again. Sentence-BERT uses siamese or triplet structures so sentence representations can be computed separately and compared with cosine similarity. DPR independently encodes queries and passages so document vectors can be precomputed. ColBERT also encodes the two sides independently but retains multiple contextual vectors and delays fine-grained interaction until a lightweight scoring stage. These systems do not differ only in speed; they move the interaction boundary. (Reimers and Gurevych, 2019, Karpukhin et al., 2020, Khattab and Zaharia, 2020)

Reading the inherited architecture figure precisely

A4 source figure comparing encoder-only, decoder-only, and encoder-decoder Transformer families

Source-local figure from A4. The left branch is the important starting point here: an encoder returns contextual rows together. The box labeled Output (l tokens) does not specify a pooling rule, task head, score type, or training objective. The decoder labels describe incremental generation and belong to M3.10, not to this article’s readout path.

The missing specification can be written as a typed function:

where:

H   contextual rows from a declared layer or layer mixture
M   valid-row mask in the readout's polarity
mu  task metadata: offsets, segments, special rows, label map, prompts
phi learned or configured readout state
Y   a typed result, not an anonymous tensor

The codomain of is the method. For example:

ReadoutRow transformationOutput object
sequence classificationselect or pool valid rowslogits [B,C]
regressionselect or pool valid rowsvalues [B,R]
token classificationpreserve aligned valid rowslogits [B,S,C] plus offset map
extractive QApreserve rows, project two score channelsstart/end logits [B,S]
single-vector embeddingpool, optionally project and normalizevectors [B,D_e]
cross encoderencode a joint pair, read one scorepair scores [B] or [B,C]
bi-encoderencode sides independentlyreusable vectors plus similarity
late interactionretain multiple vectors per sidetoken-level similarity reduction

Architecture, objective, score, and decision are separate contracts

Four layers of terminology are frequently collapsed:

LayerQuestionExample
backbone architectureWhich rows and parameters produce H?full-visibility encoder
readout architectureWhich rows become the task representation?masked mean plus projection
training objectiveWhich target relation shapes the representation?cross-entropy or contrastive loss
inference decisionHow is the score consumed?argmax, threshold, nearest neighbor

An encoder-only architecture does not imply [CLS] pooling. Mean pooling does not imply contrastive training. L2 normalization does not imply cosine is the only admissible score. A binary sigmoid threshold does not imply that 0.5 is calibrated for the release population.

Claim status

StatusMeaning in this article
Source-localPreserved from A2/A4/A5 or a neighboring Transformer System owner; provenance is not independent verification.
Externally verifiedSupported by a primary paper or pinned official implementation for the scoped claim.
Source-reportedA paper’s benchmark or systems number; not reproduced and not assumed portable.
Rewrite interpretationA boundary, name, or pedagogical synthesis introduced here.
Synthetic contract testChecked by a deterministic fixture/oracle; not a benchmark.
UncertainPlausible but not sufficiently verified for a settled claim.

Owner boundary

M3.11 consumes:

M2.1: sequence validity, segment, and offset metadata
M2.2: ID-addressed initial state and the lookup/contextual/readout terminology handoff
M3.1-M3.7: contextual row computation
M3.9: supervision/update transaction when training a readout

M3.11 owns:

contextual-output and valid-row readout contract
pooling and row-selection formulas
sequence, token, span, regression, and multilabel heads
representation normalization, contrastive objectives, similarity, and decision typing
cross-, bi-, and late-interaction retrieval readouts
readout runtime, evaluation, migration, release, and rollback

M3.11 defers:

vocabulary projection and token policy                  -> M3.8
general labels/loss/backward/optimizer transaction      -> M3.9
autoregressive feedback, cache, stopping, and streaming -> M3.10
physical operation and traffic accounting              -> M4
multi-request scheduling and service policy             -> M5
fleet evaluation, canarying, production rollback        -> M8.10
modality-specific encoders, fusion, and readout          -> X1
ANN index construction, sharding, and search internals   -> retrieval systems

The forbidden duplication is equally important. This article will not re-derive input lookup or self-attention, repeat the complete training loop, teach sampling, or turn approximate-nearest-neighbor implementation into an M3 subtopic.

Article map

The remaining sections build the contract in dependency order:

immutable contextual/readout manifest
    -> valid rows, offsets, segments, and special-row identity
        -> pooling derivations and backward paths
            -> sequence/token/span task heads
                -> representation geometry and decisions
                    -> cross/bi/late interaction
                        -> concrete representation-family transformations
                            -> training and runtime reconciliation
                                -> evaluation, migration, release, rollback

The durable rule is:

Name the row set, write the readout function, type the output score, and identify which state can be reused before comparing methods or runtimes.

0x01 The Readout Is An Immutable Artifact Contract

A backbone checkpoint is insufficient to reproduce a task result. Two systems can load identical encoder weights and return different vectors or labels because they select another layer, use another valid-row mask, include prompt or special rows in a mean, apply a different projection, normalize at another point, or attach a label map in another order.

The release identity is therefore a tuple:

with:

A  backbone and task-head artifacts
T  tokenizer, special IDs, prompt/template, and truncation policy
X  sequence, segment, validity, content, and offset contract
H  contextual-state layer, axes, final norm, and dtype
R  row selection, pooling, projection, activation, and dropout
L  task type, ordered labels, null label, and span/tag policy
S  score type, normalization, threshold, and tie rule
U  runtime implementation, backend, export, and release identity

Changing one field creates a new semantic artifact even if every parameter shape remains loadable.

An immutable readout manifest binds backbone and tokenizer identity to contextual-state selection, valid-row semantics, pooling and projection, output labels or score geometry, and runtime release identity.

The manifest follows meaning rather than file layout. A model file, tokenizer folder, pooling configuration, and label map can be stored separately while still forming one indivisible release contract.

Manifest fields and their failure boundary

RecordMinimum fieldsShape-correct failure it prevents
artifactbackbone/head hashes, architecture, revision, adapter statebase encoder silently paired with another fine-tuned head
inputtokenizer hash, max length, truncation side, padding side, special IDs, prompt/templatefirst/last row points to a different semantic unit
row metadataattention/content masks, polarity, segment IDs, offsets, word IDspadding or special rows enter pooling; token labels lose source alignment
contextual statelayer or layer mixture, final norm, logical axes, parameter/compute/accumulation dtypelast layer is substituted for a trained layer mixture
readoutfamily, pooling mode, included rows, denominator, projection, activation, dropoutmasked mean becomes padded mean or [CLS] selection
output identitytask type, ordered label map, null/no-answer ID, output dimensionlabel IDs are swapped under the same classifier shape
scorelogit/probability/similarity type, vector normalization, temperature, threshold, tie rulecosine threshold is applied to an inner-product model
runtimeframework and source revision, backend, export format, device/dtypesexported graph omits mask or normalization behavior
releaseschema, content ID, tests, parent release, migration and rollback compatibilitymutable files are promoted under an old model name

The manifest should carry both declared and observed runtime state. A requested backend or dtype is configuration; the backend and accumulation mode observed during a measured run are evidence.

Canonical manifest sketch

{
  "schema": "numinens.readout.v1",
  "artifact": {
    "backbone_sha256": "...",
    "head_sha256": "...",
    "architecture": "encoder",
    "task_revision": "..."
  },
  "input": {
    "tokenizer_sha256": "...",
    "max_length": 512,
    "padding_side": "right",
    "truncation": "longest_first",
    "special_token_ids": {"cls": 101, "sep": 102, "pad": 0},
    "prompt": null,
    "offset_mapping_required": true
  },
  "contextual_state": {
    "layer": -1,
    "axes": ["batch", "row", "channel"],
    "width": 768,
    "final_norm_applied": true,
    "compute_dtype": "float32",
    "accumulation_dtype": "float32"
  },
  "readout": {
    "family": "single_vector",
    "pooling": "masked_mean",
    "mask_source": "content_mask",
    "include_prompt": false,
    "include_special_tokens": false,
    "projection": null,
    "normalize": {"kind": "l2", "epsilon": 1e-12}
  },
  "output": {
    "kind": "embedding",
    "dimension": 768,
    "score_type": "cosine",
    "threshold": null
  },
  "runtime": {
    "framework_revision": "...",
    "observed_backend": "eager",
    "export_format": "safetensors+json"
  }
}

This is a semantic sketch, not a required universal serialization format. Official libraries may split the same identity among model config, tokenizer config, pooling modules, task-head files, and runtime arguments.

Derived invariants should not be typed twice

Some fields are consequences of others and should be derived by admission code:

contextual state width D
    -> pooling output width unless modes are concatenated
        -> projection input width
            -> projection output width
                -> embedding dimension or head input width

ordered label map
    -> class count C
        -> classifier output width

selected valid/content rows
    -> pooling denominator
        -> zero-row admission or fallback decision

For concatenated pooling modes, if mode emits width , the projection input width is:

It must not be copied from a stale configuration after one mode is removed.

Admission pseudocode

def validate_readout_manifest(m):
    require(m.contextual_state.axes == ["batch", "row", "channel"])
    require(m.contextual_state.width > 0)
    require(m.input.padding_side in {"left", "right"})
    require(m.readout.mask_source in {"attention_mask", "content_mask"})

    if m.readout.pooling in {"masked_mean", "max", "weighted_mean"}:
        require(m.readout.mask_source is not None)

    derived_width = pooling_output_width(m.readout, m.contextual_state.width)
    if m.readout.projection is not None:
        require(m.readout.projection.in_features == derived_width)
        derived_width = m.readout.projection.out_features

    require(m.output.dimension == derived_width)

    if m.output.kind in {"classification", "token_classification"}:
        require(is_bijection(m.output.label2id, m.output.id2label))
        require(m.output.dimension == len(m.output.label2id))

    if m.output.score_type == "cosine":
        require(m.readout.normalize.kind == "l2" or
                m.output.cosine_normalizes_operands)

    require(m.runtime.framework_revision)
    require(m.release.content_id)

The executable fixture uses a five-row contextual tensor. Only two content rows enter the mean; [CLS], [SEP], and padding are excluded. Its expected normalized vector is derived from the selected rows, not copied into the manifest validator. Admission also fails closed when the content mask selects padding, because a content row must first be valid model input.

Manifest changes are migrations

Some changes preserve the backbone but still require a new readout release:

mean -> CLS pooling
include prompt -> exclude prompt
last layer -> learned layer mixture
dot product -> cosine with normalization
label order [negative, positive] -> [positive, negative]
max length 512 -> 256 with a different truncation policy

Migration must declare whether stored embeddings, cached document vectors, thresholds, calibration parameters, and evaluation baselines remain valid. For a bi-encoder, changing document pooling invalidates the document index even if query-side code is untouched. M3.11 owns that semantic invalidation; retrieval infrastructure owns rebuilding and serving the index.

0x02 A Contextual Row Has Several Identities

The encoder returns one vector per model row, but downstream code often asks about another unit: a source word, a character span, one member of an input pair, or ordinary content rather than inserted control state. These identities cannot be reconstructed from H.shape.

The source tokenizer article shows the broad path from text through normalization, pre-tokenization, subword modeling, post-processing, IDs, and embeddings:

Source-local A6 overview from text through tokenization, special-token insertion, IDs, and embedding rows

Source-local A6 figure. It correctly exposes normalization, subword splitting, [CLS]/[SEP] insertion, integer IDs, and embedding lookup. For task readout, the pipeline must preserve additional row metadata: validity, special-row identity, source sequence, source offsets, and word ownership. M2.1 owns how that metadata is produced; M3.11 owns how a readout consumes it.

One row table, not one universal mask

Consider a paired input whose first source contains playing in Rome and whose second source contains who. A WordPiece-style trace may be:

row stokenattention mspecial ksequence qtype IDword IDoffset [a,b)
0[CLS]11none0nonenone
1play10000[0,4)
2##ing10000[4,7)
3in10001[8,10)
4rome10002[11,15)
5[SEP]11none0nonenone
6who10110[0,3)
7[SEP]11none1nonenone
8[PAD]01none0nonenone

The table distinguishes five predicates:

m_policy can exclude a visible prompt, instruction, title, or metadata field from final pooling while still allowing those rows to influence content through attention. This is why attention_mask cannot be renamed pooling_mask.

A row-alignment diagram showing visible special rows, source content rows, paired sequence ownership, shared word IDs for subword pieces, half-open offsets, and excluded padding.

One contextual row can be model-valid but not poolable, source-mapped, or label-bearing. The diagram’s masks answer different questions and therefore must remain separate tensors or reproducibly derived views.

token_type_ids and sequence_ids are not synonyms

For BERT, token-type IDs index a learned segment embedding that is added before the encoder. They are model input. Tokenizer sequence_ids, by contrast, are alignment metadata that identify which source of a pair produced a row and normally use None for inserted special rows. Some model families omit learned token-type embeddings while fast tokenizers can still expose pair ownership.

Therefore this inference is invalid:

# Wrong as a general row-identity rule.
context_rows = token_type_ids == 1

A checkpoint may use all-zero type IDs, may not accept them, or may assign a type ID to [SEP] even though that row has no source offset. Use the tokenizer’s declared sequence map for source ownership; use token_type_ids only according to the checkpoint’s input contract. The official Tokenizers Encoding API separately exposes type_ids, sequence_ids, special_tokens_mask, word_ids, and offsets, which externally verifies this distinction.

Half-open offsets connect model rows back to source text

For a source string x, row s with offset

corresponds to x[a_s:b_s]. Half-open intervals make the token width $b_s-a_sand let adjacent pieces meet at one boundary without overlap. An inserted special token has no source substring; representing that fact asNoneis safer than treating(0,0)` as ordinary source content.

Given a character answer span , a token row overlaps it when:

For extractive QA, overlap alone is not enough. The row must also belong to the declared context sequence. The official Transformers QA guide uses both offset mapping and sequence_ids for this reason. If truncation removes any part of the answer, the training policy must emit the declared no-answer/null target or drop the window; clipping the answer to the surviving edge creates a false label.

def rows_overlapping_span(offsets, sequence_ids, context_id, start, end):
    rows = []
    for s, (offset, sequence_id) in enumerate(zip(offsets, sequence_ids)):
        if sequence_id != context_id or offset is None:
            continue
        a, b = offset
        if b > start and a < end:       # [a,b) intersects [start,end)
            rows.append(s)
    return rows

A source word may own several model rows

In the trace, play and ##ing share word ID 0. A word-level label therefore needs an explicit expansion or reduction policy:

PolicyTraining labelsInference reductionConsequence
first piecesupervise row 1; ignore row 2read row 1one loss term per source word
all piecescopy or scheme-adjust label to rows 1 and 2first, vote, or constrained decodelonger words receive more token-level terms unless reweighted
aggregate piecespool rows 1 and 2 before the word headone word scoreadds a word-readout operation

For first-piece supervision, with word and sequence identities (q_s,w_s), the label-bearing predicate is:

Pair identity is included because each source sequence can restart word IDs at zero. The first content row in each sequence is also a first piece by definition. Loss-ignore values such as -100 are a supervision convention, not a substitute for preserving the mapping.

def first_piece_label_mask(attention, special, sequence_ids, word_ids):
    out = [False] * len(attention)
    previous = None
    for s in range(len(attention)):
        owner = (sequence_ids[s], word_ids[s])
        content = bool(attention[s]) and not bool(special[s])
        mapped = owner[0] is not None and owner[1] is not None
        out[s] = content and mapped and owner != previous
        if content and mapped:
            previous = owner
        else:
            previous = None
    return out

This reset-on-boundary implementation is deliberately explicit. A vectorized implementation is acceptable only if it preserves sequence boundaries, special rows, and left/right padding behavior.

First and last are semantic selectors, not physical columns

For row mask , define:

Then row selection is or . The shortcut

last = attention_mask.sum(-1) - 1

works only for a right-padded contiguous visible prefix beginning at physical row zero. It fails for left padding, packed layouts, holes, and any selector whose mask excludes a visible suffix prompt. The robust operation gathers the minimum or maximum physical index satisfying the readout’s mask.

def boundary_index(mask, side):
    selected = [s for s, keep in enumerate(mask) if keep]
    if not selected:
        raise ValueError("readout selected zero rows")
    return min(selected) if side == "first" else max(selected)

Layer selection is part of row identity

The same token row has one state per encoder depth. A release must declare whether it consumes one layer,

an average over a fixed layer set,

or a learned scalar mixture,

The learned logits and scale are task-head parameters and must travel with the readout checkpoint. Replacing a mixture with the last hidden state preserves [B,S,D] while changing every downstream row.

Source-to-tensor admission trace

encoding = tokenizer(
    first_text,
    second_text,
    return_offsets_mapping=True,
    return_special_tokens_mask=True,
    truncation="longest_first",
    padding="max_length",
)

row_contract = {
    "input_ids": encoding["input_ids"],
    "attention_mask": encoding["attention_mask"],
    "special_tokens_mask": encoding["special_tokens_mask"],
    "sequence_ids": encoding.sequence_ids(),
    "word_ids": encoding.word_ids(),
    "offsets": normalize_absent_offsets(encoding["offset_mapping"]),
}
validate_row_contract(row_contract)

H = model(**model_inputs(row_contract), output_hidden_states=True).hidden_states
contextual = select_declared_layer_or_mixture(H, manifest.contextual_state)
content_mask = derive_content_mask(row_contract, manifest.readout)

Fast-tokenizer alignment APIs are an implementation boundary, not a universal property of every tokenizer backend. If a runtime cannot emit the metadata a task requires, admission must fail or preprocessing must persist an equivalent mapping. It must not guess offsets from decoded token strings after normalization.

Zero-row and empty-source policy

Every reduction needs a declared empty-set behavior:

reject:
    safest when an empty content set means preprocessing drift

use a learned empty vector:
    valid only if that vector was trained and versioned

fall back to a declared special row:
    valid only if the training/readout contract used that rule

clamp denominator and return zero:
    numerically finite, but semantically dangerous if accidental

The default executable oracle rejects zero selected rows. Section 0x03 derives why a denominator clamp prevents NaN but does not decide the semantic policy.

0x03 Pooling Is A Reduction With A Backward Contract

Let one example expose contextual rows

and a declared readout mask . Write

Every pool below changes how information and gradient cross the row axis. The choice is therefore learned architecture or immutable configuration, not a cosmetic post-processing flag.

Pooling contract comparison showing selected-row gathers, masked mean and max reductions, fixed weighted means, learned attention weights, gradient routes, and output widths.

Selection routes state through one row. Fixed reductions distribute state by a declared rule. Learned pooling makes the weighting function part of the checkpoint. Concatenating modes preserves several summaries and widens the next projection.

First and last valid row: gather, do not reduce

With the semantic selectors from 0x02, first-row pooling is:

If , then:

Last-row pooling substitutes . No gradient reaches another output row through the gather itself, although contextualization may already have mixed information into the selected row inside the backbone.

This distinction matters for BERT terminology. The official BERT implementation does not return the raw first row as pooler_output; BertPooler computes:

The physical first row is appropriate only because the BERT input grammar puts [CLS] there. Raw [CLS], transformed BERT pooler output, and “first non-pad row” are three different readouts. A checkpoint trained with one cannot silently substitute another.

Masked mean: derive the denominator

The arithmetic mean over selected rows is:

The denominator is , not padded width . Padding one example from 8 to 512 physical rows must not shrink its representation by .

Because the binary mask is metadata rather than differentiable state, the local Jacobian is:

For upstream gradient :

Every selected row receives an equal direct share. That does not mean every source token has equal total influence: contextualization, subword expansion, layer selection, and later normalization still matter.

def masked_mean(hidden, mask):
    # hidden [B,S,D], mask [B,S], 1 means this readout includes the row
    x = hidden.float()                         # accumulator contract
    w = mask.to(dtype=x.dtype).unsqueeze(-1)  # [B,S,1]
    count = w.sum(dim=1)                       # [B,1]
    if torch.any(count == 0):
        raise ValueError("masked mean selected zero rows")
    return (x * w).sum(dim=1) / count          # [B,D]

Promoting the reduction to FP32 reduces long-sum error for lower-precision backbone outputs. Returning FP16/BF16 afterward is a separate output-dtype decision. The denominator and numerator should be accumulated under the same declared precision contract.

Mean divided by square-root length is not a mean

Some released pooling modules expose:

Its backward share is . If selected rows have a common mean , then ; representation magnitude can therefore grow with sequence length. Later L2 normalization removes global scale from cosine geometry but not from pre-normalization nonlinear projections, dot products, or gradient magnitudes. The name must not be shortened to “mean pooling.”

Masked max: zero is not a safe mask value

Channel-wise max pooling computes:

This implementation is wrong:

maximum = (hidden * mask.unsqueeze(-1)).max(dim=1).values

If every selected value in one channel is negative, a masked pad becomes zero and wins. Invalid rows must be replaced before the reduction by an identity sentinel such as in a supported accumulation dtype:

def masked_max(hidden, mask):
    if torch.any(mask.sum(dim=1) == 0):
        raise ValueError("masked max selected zero rows")
    masked = hidden.float().masked_fill(~mask.bool().unsqueeze(-1), -torch.inf)
    values, indices = masked.max(dim=1)
    return values, indices

When one row uniquely maximizes channel , direct gradient for that channel goes only to that row. At ties, max has a set-valued mathematical subgradient; libraries choose a concrete backward convention. Returning/storing argmax indices makes that convention auditable. Max can select different rows for different channels, so the output need not equal any one token vector.

Fixed weighted means expose position or policy bias

For declared nonnegative weights :

The direct hidden-state gradient is:

Weights can encode recency, position, confidence, or source-specific policy. They remain configuration only if they are deterministic functions recorded in the manifest. For example, position-weighted mean pooling is not the same as a learned importance model merely because both emit [B,D].

Negative weights are mathematically possible but change the denominator and can make zero through cancellation. A “weighted mean” contract should state whether weights are nonnegative, whether they are normalized, and what happens at zero total mass.

Learned scalar attention adds an indirect gradient path

A common learned pool scores every selected row:

masks invalid logits, normalizes over rows,

and returns:

For upstream vector , softmax coupling gives:

The hidden row receives a direct value path and an indirect score path:

The second term is precisely what a fixed weighted mean lacks. Changing W, v, mask polarity, score dtype, or softmax axis changes the learned readout.

def attention_pool(hidden, mask, scorer):
    score = scorer(hidden.float()).squeeze(-1)          # [B,S]
    score = score.masked_fill(~mask.bool(), -torch.inf)
    if torch.any(mask.sum(dim=-1) == 0):
        raise ValueError("attention pool selected zero rows")
    alpha = torch.softmax(score, dim=-1)                # row axis only
    pooled = torch.einsum("bs,bsd->bd", alpha, hidden.float())
    return pooled, alpha

Structured self-attentive pooling generalizes one scalar distribution to attention hops. With rows arranged as :

Lin et al. add a diversity penalty based on to discourage identical hops. This is an externally verified paper design, not a requirement for every attention pool. The method emits a matrix until a later flatten/reduction step; calling it a single vector hides an output-shape decision.

Combining pooling modes widens the artifact

Sentence Transformers exposes modular pooling and can concatenate enabled modes. For readouts :

If all preserve hidden width, the next layer sees , not . Concatenating raw first-row, mean, and max summaries therefore triples projection input width and parameter count. Averaging those summaries would keep width but define a different architecture.

Alternatives by contract

ReadoutTrainable stateDirect row gradientMain sensitivity
first/last gathernone, unless followed by poolerone selected rowgrammar, padding, suffix/prompt
BERT poolerW_p,b_pfirst row through tanhcheckpoint pooler training
masked meannoneequal selected-row sharesrow set and denominator
mean/sqrt-lengthnoneequal 1/sqrt(n) shareslength-dependent norm
channel maxnoneper-channel argmax rowsoutliers and tie convention
fixed weighted meanconfigured weightsnormalized weight sharesposition/policy bias
learned attentionscorer parametersvalue plus score pathscore saturation and collapse
multi-hop attentionscorer plus later reducermultiple distributionshop redundancy and output shape
concatenated modesconstituent stateunion of constituent pathswidened projection/interface

No row-only pooling universally repairs a backbone that was not trained for the target representation geometry. SBERT’s siamese/triplet training, SimCSE’s contrastive objective, and task-specific fine-tuning change what the rows encode; they are not merely better pooling formulas. Section 0x07 owns their representation-objective contracts and readout-local trainable-state schedules.

Numerical and semantic assertions

assert hidden.ndim == 3 and mask.ndim == 2
assert hidden.shape[:2] == mask.shape
assert mask.dtype == torch.bool
assert torch.all(mask.any(dim=1))
assert accumulation_dtype in {torch.float32, torch.float64}

pooled = pool(hidden, mask)
assert pooled.shape == (hidden.shape[0], declared_pool_width)
assert torch.isfinite(pooled).all()

clamp_min(epsilon) is useful inside a numerically defensive implementation, but assertions must run before the clamp if zero selected rows are forbidden. Otherwise an invalid example becomes a finite zero vector and can enter an ANN index or classifier without an obvious failure.

0x04 Task Heads Type The Output Axis

Pooling answers “which contextual state summarizes this input?” A task head answers another question: “which target axis is represented by each output coordinate?” A [B,3] tensor can mean three mutually exclusive classes, three independent attributes, three regression targets, or three candidate scores. Shape alone does not choose among them.

A task-head map showing pooled sequence representations feeding multiclass, regression, multilabel, and multiple-choice heads, while contextual rows feed token labels and extractive start-end span scores.

A pooled branch removes the row axis before prediction. Token and span branches preserve it. Each branch carries a distinct target identity, loss reduction, decision rule, and release state.

Single-label sequence classification

Let a readout produce and let the ordered label map have entries. A linear head computes:

The head adds parameters. For one mutually exclusive target :

The familiar softmax-cross-entropy gradient follows from the shared denominator:

The gradient handed to the readout is:

Thus changing label order while retaining shape silently permutes rows of W_c, probabilities, metrics, and decisions. label2id and id2label are checkpoint identity, not display metadata.

def sequence_classification(hidden, row_mask, pool, head, labels=None):
    r = pool(hidden, row_mask)        # [B,D_r]
    r_drop = dropout(r)               # active only in training mode
    logits = head(r_drop)             # [B,C]
    loss = None if labels is None else cross_entropy(logits, labels)
    return {"logits": logits, "loss": loss, "readout": r}

Dropout placement and probability are part of the trained head. Evaluation must switch dropout off; “same weights” in training mode is not deterministic inference.

Regression keeps coordinate meaning outside softmax

For real-valued targets:

With mean squared error over values:

No softmax couples regression coordinates. Target scaling therefore changes gradient scale. A release must preserve target units, normalization statistics, inverse transform, missing-target mask, and whether MSE, MAE, Huber, Gaussian negative log-likelihood, or another objective trained the head.

Huber loss is a useful alternative when large residuals should become linear:

The threshold is part of the objective contract, not an inference threshold.

Multilabel classification uses independent Bernoulli coordinates

For target vector , every coordinate can be positive:

For an unweighted sum, the logit gradient is:

This is not one softmax over the labels. Probabilities do not sum to one, and inference may emit zero, one, or many labels. Per-label thresholds, positive-class weights, focal terms, and calibration parameters must be versioned with the ordered label map. A universal 0.5 threshold is a policy choice, not a theorem.

Multiple choice moves the competition to the candidate axis

For answer candidates, each candidate is rendered as its own paired input:

input IDs       [B,K,S]
backbone rows   [B,K,S,D]
pooled states   [B,K,D_r]
scalar head     [B,K,1]
candidate logits [B,K]

Flattening B*K for the backbone is an implementation schedule; unflattening before candidate softmax restores the semantic axis:

Candidates must share one example identity and deterministic order. Treating all flattened rows as independent binary examples changes the objective.

Token classification preserves the model-row axis

For :

Let only for rows that bear a target under the first-piece, all-piece, or aggregate policy from 0x02. With :

The local logit gradient is:

Padding, special tokens, ignored subword pieces, and truncated source words must contribute zero. The predicted row labels still need offsets/word IDs to return source spans; decoding token strings and searching them in normalized text is not a reversible alignment algorithm.

logits = token_head(dropout(H))                    # [B,S,C]
flat_loss = cross_entropy(
    logits.reshape(-1, C),
    aligned_labels.reshape(-1),
    ignore_index=IGNORE,
    reduction="none",
).reshape(B, S)
loss = flat_loss[label_mask].mean()

A linear-chain CRF is an alternative when adjacent labels obey a learned transition model. It adds transition scores , normalizes over complete label sequences, and uses Viterbi or constrained decoding. BIO/BILOU legality can instead be imposed only at inference. These designs have different learned state and losses; “token classification” does not imply either one.

Extractive QA predicts boundaries over context rows

BERT-style extractive QA applies one linear map with two output channels:

This is equivalent to separate start/end vectors only at the linear map; the two channels still have distinct parameters. A common training objective is:

after masking rows that cannot be answers. Start and end are trained with separate normalized distributions, so the loss does not itself guarantee or a maximum answer length.

Inference must search the admissible span set:

For independent boundary logits, a standard score is:

The selected offsets map rows back to a source substring. This constrained joint search is not equivalent to independently taking argmax(start) and argmax(end), which can return an inverted or overlong span.

def best_valid_span(start, end, context_mask, max_answer_length):
    best = None
    for s in range(len(start)):
        if not context_mask[s]:
            continue
        stop = min(len(end), s + max_answer_length)
        for e in range(s, stop):
            if not context_mask[e]:
                continue
            candidate = (start[s] + end[e], s, e)
            if best is None or candidate > best:
                best = candidate
    if best is None:
        raise ValueError("no admissible answer span")
    return best[1], best[2], best[0]

No-answer support adds another contract. One design uses a declared null row such as [CLS] and compares its boundary score with the best non-null span; another adds a separate answerability classifier. The threshold is calibrated on a development distribution and must be released. SQuAD 1.1’s original task contains answer spans, while no-answer handling is associated with later task variants and model recipes; do not project one convention onto every extractive QA checkpoint.

Joint span scorers, biaffine boundary models, and span-enumeration classifiers can represent start/end interaction directly but cost more than two independent row channels. They are alternatives, not implementation details of the BERT head.

Head, objective, and decision ledger

TaskHead outputTraining couplingInference decision
multiclass[B,C] logitssoftmax across labelsargmax/top-k plus calibration policy
regression[B,R] values/parameterscoordinate loss or probabilistic NLLinverse transform and domain constraints
multilabel[B,C] logitsindependent/weighted sigmoid termsper-label thresholds
multiple choice[B,K] logitssoftmax across candidatescandidate argmax
token labels[B,S,C] logitsmasked row losses or structured sequence lossoffset-aware merge/constrained decode
extractive QAtwo [B,S] score fieldsindependent or joint boundary objectiveconstrained span plus no-answer policy

Fail-closed head admission

def validate_task_head(manifest, batch, output):
    require(output.shape == manifest.output.logical_shape(batch))
    require(manifest.output.dimension == manifest.head.out_features)
    require(manifest.output.ordered_labels_are_bijective())

    if manifest.output.kind == "token_classification":
        require(batch.label_mask.shape == batch.input_ids.shape)
        require(batch.offsets_available_for_emitted_rows())

    if manifest.output.kind == "extractive_qa":
        require(batch.context_mask.shape == batch.input_ids.shape)
        require(batch.context_offsets_are_present())
        require(manifest.output.max_answer_length > 0)

    if manifest.output.kind == "multilabel":
        require(len(manifest.output.thresholds) == manifest.output.dimension)

The executable oracle checks local losses and gradients, source-row masking, candidate-axis competition, and constrained span search. M3.9 remains the owner of optimizer state, accumulation, distributed reduction, and checkpoint timing.

0x05 A Score Is Not Yet A Decision

M2.2 ended at model-input state; this article therefore owns the downstream representation geometry. This section derives normalization and score meaning. Section 0x07 owns the objectives that train that geometry. Physical ANN realization remains a retrieval-system concern. The local endpoint here is a typed, calibrated, and releasable decision.

Normalize only under the trained geometry

For nonzero vector :

The local Jacobian is:

The projection removes radial gradient. Applying L2 normalization only at deployment is therefore not equivalent to training through it. Near-zero norms also amplify the Jacobian; an epsilon or zero-vector fallback changes the function and must be declared.

Three common pair scores are:

For unit vectors:

Thus maximum cosine, maximum inner product over consistently unit-normalized vectors, and minimum squared L2 have the same exact ranking. They do not emit the same numbers. A threshold cosine >= 0.8 cannot be copied to squared L2 as distance <= 0.8; under the identity it becomes distance <= 0.4.

Raw inner product is different when norms vary:

Norm can encode learned confidence, popularity, frequency, or accidental scale. Removing it is a model change, not automatically a correction.

Score types form a small type system

TypeRangeLarger wins?Sum constraintProbability claim
raw class logitrealonly relative within declared class headnoneno
softmax probability[0,1]yesone over class/candidate axisconditional model probability, not necessarily calibrated
sigmoid probability[0,1]yesnone across labelsmarginal model probability, not necessarily calibrated
dot/cosine similarityreal / [-1,1]yesnoneno
L2 distancenonnegativenononeno
calibrated probability[0,1]yesdepends on calibrator/taskempirical claim on a declared population

Calling every float score throws away exactly the information a decision needs. APIs and manifests should use names such as logits, probabilities, cosine_similarity, or squared_l2_distance.

A score decision pipeline separates vector normalization and metric, raw logits or similarities, optional calibration, cost-aware thresholds and abstention, and monitored release decisions.

Ranking, calibration, and action policy are separate stages. A monotone calibrator can preserve ranking while changing thresholds and probability meaning; a changed encoder can invalidate all three.

Temperature changes confidence even when argmax is fixed

Given class logits and temperature :

Positive scaling preserves argmax(z), but changes entropy, NLL, and any probability threshold. For target :

Training temperature in a contrastive loss controls optimization and negative competition; post-hoc classification temperature scaling fits on held-out logits to improve calibration. The two parameters may use the same equation but belong to different lifecycle stages.

Temperature scaling cannot repair class-conditional errors that require different transformations. Alternatives include vector/matrix scaling, Platt sigmoid calibration for a scalar score, isotonic regression, or a separate calibration model. Greater flexibility raises overfitting risk and expands release state.

Calibration is population-conditional

A predictor is calibrated on population when, informally:

Finite data requires estimates. Negative log-likelihood and Brier score are proper scoring rules; reliability diagrams and expected calibration error bin predictions and therefore depend on binning policy. Accuracy alone cannot detect a model that is systematically overconfident.

def fit_temperature(frozen_logits, labels, calibration_split):
    assert calibration_split.is_disjoint_from_train_and_test
    log_T = Parameter(0.0)
    optimize(lambda: cross_entropy(frozen_logits / exp(log_T), labels))
    return exp(log_T).detach()

The calibrator identity includes:

base checkpoint and readout release
calibration data revision and inclusion rules
label order and population slice
calibrator family, parameters, and fitting objective
software/dtype used to produce calibration logits

Domain, prevalence, class mix, and input-policy shifts can break calibration while preserving ranking or aggregate accuracy. Monitor calibration on the deployment population rather than treating it as a permanent model property.

Thresholds encode costs and capacity

For calibrated binary probability , false-positive cost , and false-negative cost :

predict positive: expected cost = (1-p) * C_FP
predict negative: expected cost = p * C_FN

Choose positive when:

The familiar 0.5 follows only when the two costs are equal. Capacity limits, review queues, prevalence shift, legal constraints, and fairness requirements can require another policy. For multilabel output, each label can have its own threshold and cost model.

Similarity thresholds need empirical relevance labels. A cosine value is not a probability, and its numeric scale can shift after changing pooling, prompts, normalization, quantization, or the document population. Top-k retrieval avoids one absolute cutoff but introduces a capacity choice and can still return irrelevant items when all scores are poor.

Abstention adds another decision region

One simple multiclass policy is:

Margin, entropy, conformal sets, retrieval-score gaps, or an explicit reject class are alternatives. They make different statistical promises. An abstention threshold must be evaluated with coverage and conditional risk, not accuracy on accepted examples alone.

Monotone transforms preserve rankings, not decisions

For strictly increasing :

Exact top-k order is preserved, but these objects can change:

absolute threshold crossings
score margins and gap alarms
probability calibration
weighted fusion with another score
floating-point tie behavior
approximate-index traversal

Platt scaling with positive slope can preserve one score’s order while giving a probability interpretation on calibration data. A negative fitted slope reverses the order and usually signals that score orientation was misdeclared or the relationship differs from expectation.

Readout decision admission

def decide(output, contract):
    require(output.score_type == contract.expected_score_type)

    if contract.metric == "cosine":
        require(output.query_normalized and output.document_normalized)
    if contract.calibrator is not None:
        require(contract.calibrator.parent_release == output.release_id)
        score = contract.calibrator(output.score)
    else:
        score = output.score

    require(contract.threshold_revision)
    require(contract.tie_rule)
    return apply_threshold_abstention_and_capacity(score, contract)

Changing the backbone, tokenizer, selected layer, pool, projection, normalization, score metric, or output dtype invalidates calibration and thresholds unless a frozen equivalence test proves otherwise. It may also invalidate every stored document vector. M3.11 owns that semantic invalidation declaration; the retrieval-system owner executes re-encoding and index rebuild, and M8.10 owns production transition.

0x06 Interaction Placement Determines Reusable State

Cross-encoders, bi-encoders, and late-interaction models all emit pairwise scores, but they do not compute the same intermediate object. The architectural question is:

At what point may query state and document state interact?

Moving that point changes representation semantics, offline artifacts, online work, and the gradients available during training. It is not merely a faster implementation of one equation.

Cross-encoder, bi-encoder, and late-interaction paths showing full joint token interaction, one reusable document vector, and reusable document token vectors with a MaxSim score matrix.

The reusable document artifact grows from none, to one vector, to many token vectors. In return, the interaction retained at query time grows from one global metric to token-level matching; only the cross-encoder permits full query-document attention inside every Transformer layer.

Cross-encoder: interaction before representation readout

A BERT-style pair grammar is:

[CLS] query [SEP] document [SEP]

The tokenizer emits one pair sequence . Full-visibility encoder layers allow every admitted query row to affect every admitted document row:

A pair readout and scalar or class head follow:

The output may be an uncalibrated logit, regression value, or class vector. Official Sentence Transformers documentation explicitly notes that cross-encoder checkpoints may return logits and that an optional sigmoid changes score scale without changing rank. The release must declare the actual type.

Document state cannot generally be precomputed independently because:

when document rows attend to query rows. Caching tokenized document text is possible; caching its joint contextual state for arbitrary future queries is not the same computation.

Pair rendering also creates a shared length budget. A max_length=512 contract must declare whether the query or document truncates first, the stride/window policy for long documents, and how chunk scores aggregate. Query-dependent truncation can change which evidence the scorer sees.

def cross_score(query, documents, tokenizer, model):
    pairs = [(query, document) for document in documents]
    batch = tokenizer(
        pairs,
        padding=True,
        truncation="only_second",
        max_length=PAIR_LIMIT,
    )
    logits = model(**batch).logits
    return type_scores(logits, SCORE_CONTRACT)

Bi-encoder: interaction after one-vector readout

A bi-encoder computes each side independently:

then applies a decomposable score:

or the declared cosine/L2 alternative. For query matrix and document matrix , exact inner-product scores are:

Because is query-independent, document vectors are reusable. That is the architectural property that permits an offline document artifact and exact or approximate vector search. M3.11 owns the vector and score semantics; retrieval systems own index construction and search execution.

The encoders may share all weights, start equal and later diverge, or be different architectures. DPR’s primary paper uses separate question and passage BERT encoders and an inner-product score. A shared-weight Sentence-BERT path is a different parameter-ownership contract even when both are called bi-encoders.

Asymmetric query/document templates are also state:

query:    "query: {text}"
document: "passage: {title} {body}"

Swapping templates or encoders can preserve vector width while moving the two sides into incompatible spaces.

Late interaction: retain one vector per selected row

ColBERT moves interaction later than a cross-encoder but earlier than a single-vector bi-encoder. Independent encoders and a projection produce:

with selected query/document rows and, in the paper contract, normalized token vectors. The pairwise token matrix is:

ColBERT’s late-interaction score is MaxSim followed by a query-token sum:

Each query token independently retrieves its strongest document-token match. The sum retains more local evidence than reducing the document to one vector, but document storage now retains up to projected vectors plus row metadata. Physical byte, compression, and kernel accounting belong to M4/M8.

Padding or excluded document rows must be masked with before each row-wise max. Multiplying an invalid dot product by zero repeats the masked-max failure from pooling.

def maxsim(query_tokens, document_tokens, query_mask, document_mask):
    # Q [B,m,d], D [B,n,d]
    similarity = query_tokens.float() @ document_tokens.float().transpose(-1, -2)
    similarity = similarity.masked_fill(~document_mask[:, None, :], -torch.inf)
    per_query_token, winner = similarity.max(dim=-1)   # [B,m]
    per_query_token = per_query_token.masked_fill(~query_mask, 0.0)
    return per_query_token.sum(dim=-1), winner

For a unique winning document row

the local score gradients are:

Several query rows can route gradient to one document row. At ties, the concrete argmax convention matters. Smooth alternatives such as log-sum-exp distribute mass across document rows but define a different scorer and temperature:

As it approaches max. For finite , it is not MaxSim and can change ranking.

Paper-by-contract comparison

ContractInteraction pointReusable document statePair score stateMain semantic loss if substituted
cross-encoderinside every joint Transformer layerno query-independent contextual statejoint rows plus task headremoves token-level cross-input attention
tied bi-encoderafter independent pooled readoutsone vectorshared encoder/pool plus metricforces one representation function on both sides
untied bi-encoder / DPR-styleafter independent pooled readoutsone vectorseparate query/document encoders plus metricswapping sides or checkpoints breaks space alignment
ColBERT-style late interactionafter independent token projectionsmany document row vectorsprojection, row masks, normalization, MaxSimone-vector pooling removes local matching

Cross-encoder source-reported quality advantages do not establish a universal ordering: candidate recall, pair truncation, training data, latency budget, and task distribution all matter. The architectures expose different feasible workflows rather than one Pareto ranking.

A two-stage system preserves both ceilings

A common design retrieves candidates with a reusable bi-encoder or late interaction artifact, then applies a cross-encoder to those pairs. The reranker cannot recover a relevant document absent from its input set:

M3.11 owns the semantic candidate/reranker interface. Retrieval systems own the index-specific serving manifest:

candidate stage output:
    stable document IDs + retrieval score type + candidate rank

reranker input:
    exact query/document rendering + parent candidate identity

reranker output:
    typed pair logit/probability + stable tie rule

Interaction-contract admission

def validate_interaction_release(m):
    if m.kind == "cross_encoder":
        require(not m.document_state_reusable)
        require(m.pair_template_hash and m.pair_truncation_policy)
    elif m.kind == "bi_encoder":
        require(m.document_vector_dimension == m.query_vector_dimension)
        require(m.query_release and m.document_release)
        require(m.metric_contract)
    elif m.kind == "late_interaction":
        require(m.query_row_policy and m.document_row_policy)
        require(m.projection_revision and m.maxsim_tie_rule)
        require(m.document_token_artifact_schema)
    else:
        raise ValueError("unsupported interaction contract")

All three paths still need task-specific training. Section 0x07 owns the local objective, contrastive denominator, and backward-state contract for these readouts.

Representation families change more than one pooling switch

The preceding sections deliberately define reusable primitives: visibility, row identity, selection, pooling, projection, normalization, interaction, and score type. A named embedding model composes several of them. Replacing only the pool while keeping the rest of the pipeline fixed usually does not reproduce the named method.

A useful model-side identity is:

(backbone checkpoint, visibility policy, rendered input, selected layer,
 selected rows, pool/projection, normalization, objective stages,
 positive/negative relation, added trainable state, exported state)

This subsection keeps the method comparison at M3.11’s owner boundary. It does not repeat the history of static and contextual word representations, and it stops before physical ANN construction or serving.

Reconstruction pretraining changes what the exported state must carry

Ordinary masked-language-model loss supervises selected token positions; it does not by itself require one sequence row to preserve enough evidence to reconstruct the input. RetroMAE creates that pressure with two differently corrupted views: a full encoder produces a sentence representation, while a shallow decoder reconstructs heavily masked tokens using that representation and its own masked input. The decoder and corruption sampler are training state. The encoder, selected sentence row, and normalization policy are the inference artifact.

RetroMAE v2 / DupMAE changes the exported object again. It trains one reconstruction route from the contextual [CLS] row and a second bag-of-words route from ordinary contextual rows. After dimension reduction and token aggregation, the two routes are concatenated:

Discarding the ordinary-token route after training does not produce a smaller equivalent DupMAE artifact; it removes one of the representation channels the objective trained and the paper exports.

C-Pack illustrates a different point: data, benchmark, model family, and training recipe are separate resources. Its BGE lineage composes embedding-oriented pretraining, general contrastive training, and task-specific tuning. A final checkpoint therefore identifies the result of an ordered training program, not every dataset revision, miner, instruction, or intermediate checkpoint that could be paired with the same architecture.

Causal rows begin with unequal information

For a causal backbone,

so an early row cannot contain later-token evidence while a final row can see the complete admitted prefix. A plain mean over all causal rows therefore mixes receptive fields. Published methods address this in different places:

MethodVisibility and rendered inputReadoutTraining/export consequence
E5-Mistralcausal; task instruction on the query, no instruction prefix on the document; append EOS to bothfinal-layer EOS rowcontrastive LoRA training; preserve side-specific templates, EOS locator, weights/adapter, and normalization
PromptEOLcausal; append an exact semantic-completion promptfinal prompt-token state before generationcan be training-free; the prompt bytes, tokenization, selected row, and layer become representation state
Echo embeddingscausal; render the source twice under a reconstruction/repetition promptpool only rows belonging to the second occurrencepreserves the causal model but spends more sequence length; retain the second-copy span map
LLM2Vecreplace causal visibility with bidirectional visibilitymean-pool declared content rowsadapt with masked next-token prediction, then unsupervised contrastive learning; preserve the changed mask behavior and resulting adapter/weights
NV-Embedremove the causal mask during contrastive training; instruction rows may influence content while remaining outside the final pooltoken queries attend to a trainable latent dictionary, pass through an MLP, then mean-poolretain latent-attention/MLP state, content mask, templates, normalization, and two-stage training lineage
MoEEuse the pretrained MoE model’s visibility and promptextract final hidden state plus routing-weight coordinatesconcatenation creates one wider vector; weighted score fusion retains two spaces and a fusion coefficient

The E5 contract is a selected-row solution:

The EOS row has the whole admitted prefix in its causal receptive field. This does not make the earlier rows bidirectional, and attention_mask.sum(-1)-1 locates EOS only under a compatible right-padded, contiguous-row contract.

Echo instead changes the rendered sequence. For source rows , prefix , and separator :

where selects content rows in the second occurrence. Pooling both copies restores the early incomplete-view rows that repetition was meant to avoid. Truncating the second occurrence can remove the only rows the readout is allowed to pool.

LLM2Vec changes the attention graph and then adapts it in two distinct stages:

causal checkpoint
    -> bidirectional visibility
        -> masked next-token prediction (token x_i from row h_(i-1))
            -> merge/retain the MNTP adaptation as declared
                -> new SimCSE adaptation over pooled sequence vectors

The previous-row target preserves the decoder’s next-token readout offset. An MLM-style target from the masked row is another objective. Likewise, removing the causal mask without recording the subsequent adaptation does not identify an LLM2Vec release.

NV-Embed learns a pooling block rather than treating a latent array as output queries. With decoder rows and trainable dictionary :

The sequence axis survives in ; an MLP and declared masked mean perform the later sequence reduction. Swapping token and latent roles may remain shape-compatible while producing a different object. The paper also changes negative admission between its retrieval-first and mixed-task stages, which is why training-stage identity belongs beside the pooling module.

MoEE exposes another type distinction. Let be a hidden-state vector and the ordered router-weight vector. Concatenation exports one vector,

whereas score fusion keeps two geometries:

The second equation cannot be reproduced by storing one ordinary concatenated vector unless the metric and scaling are transformed to an explicitly proved equivalent form. Layer order, expert-coordinate order, router normalization, selected row, score types, and are release state. M6.2 owns the router and expert-parallel mechanics; M3.11 owns only the extracted representation and score contract.

Shape-correct substitutions that still change the method

SubstitutionWhy it is not equivalent
serve RetroMAE’s training decoder as part of every embedding calltraining-only reconstruction state becomes an undeclared runtime dependency
export only DupMAE’s [CLS] routethe trained ordinary-token representation channel disappears
apply an E5 query instruction to stored documentsdocument vectors leave the trained asymmetric space and require re-encoding
select the final padded column instead of the declared EOS/prompt rowwidth is preserved but row identity changes
pool both Echo copiesrows without full-source causal visibility re-enter the vector
enable bidirectional attention but omit LLM2Vec’s adaptation lineagean information path is added without identifying weights trained to use it
use in-batch negatives indiscriminately in NV-Embed’s mixed-task stagesame-class examples can be admitted as false negatives
serialize MoEE score fusion as a concatenated-vector indextwo separately typed scores and their fusion coefficient disappear

These methods are examples, not a leaderboard. Their durable lesson is that visibility, rendering, row selection, pooling, objective sequence, and exported state move together. Section 0x07 now derives the local training relation; 0x08 reconciles the resulting artifact with batching and export. Physical ANN data structures, shard layout, and search algorithms remain retrieval-system work.

0x07 Training A Readout Means Declaring Gradient Reachability

The forward contracts above do not determine what training is allowed to change. The same classifier can sit on a frozen feature extractor, a trainable pooler over a frozen encoder, a fully fine-tuned encoder, or a parameter-efficient side path. Those programs can produce identically shaped logits while owning different gradients, optimizer slots, checkpoints, and rollback parents.

The original BERT work compared both feature-based use, where contextual states feed a separately trained task model, and fine-tuning, where task parameters and the pretrained parameters are updated jointly. BERT’s reported results are source-reported evidence for those recipes, not proof that full fine-tuning dominates on every dataset. Adapter tuning later inserted small task-specific modules while freezing the shared network, and BitFit studied the narrower choice of updating bias terms. These are different trainable-set contracts, not aliases for “fine-tuning.” (BERT, Houlsby et al., BitFit)

The source-local loss picture is one instance, not the owner contract

Source-local one-hot target and predicted vocabulary distributions

Source-local visual from A5 — Training and Reasoning. It usefully separates target and predicted distributions for one vocabulary classification example. M3.11 generalizes the path: the supervised axis may be class, independent label, candidate, token row, or span boundary; its validity mask and reduction denominator must therefore come from the declared task contract rather than from this picture.

Source-to-loss trace: preserve every address change

For one batch, the complete local path is:

source examples + stable example IDs
    -> tokenizer revision + truncation/window policy
        -> input_ids, row_valid, sequence_id, word_id, offsets
            -> backbone(H [B,S,D])
                -> readout R or row-preserving state
                    -> typed head logits Z
                        -> aligned labels Y + supervised mask W
                            -> per-example or per-valid-row losses
                                -> declared reduction numerator S and denominator D_loss
                                    -> scalar L passed to M3.9

The mask used in the loss is not inferred from attention_mask alone. A row can be visible to the encoder and intentionally unsupervised: a special row, the second subword of a word, a question row in extractive QA, or padding in a multiple-choice candidate. Conversely, a sequence-level label supervises one example even though many contextual rows contributed to its pooled readout.

Define a typed per-element loss , a non-negative supervision weight , and a declared denominator:

with . For ordinary binary masks, is the number of valid supervised elements. For class weighting or example weighting, it is the sum of weights if that is the chosen estimator. Dividing by padded tensor size, batch size, or sequence length defines a different estimator whenever valid counts vary.

Task addresses make the difference concrete:

task headloss element address supervision objectusual local denominator
sequence class/regression(example)one class or target vectorvalid examples or sum of example weights
multilabel(example, label)independent binary targetsvalid example-label cells under declared reduction
multiple choice(example) over candidate axiscorrect candidate IDvalid examples; candidate mask acts inside logits
token classification(example, model_row)aligned token/word labelsupervised model rows, not all visible rows
extractive QA(example, start/end channel)two row indices or null rulevalid examples per channel
embedding/retrieval(anchor, candidate relation)positive/negative relationobjective-specific admitted anchor or positive count, owned here

M3.11 owns how its head produces typed local losses, which rows reach that head, and which positive/candidate relations enter a contrastive denominator. M3.9 owns microbatch accumulation, distributed global normalization, loss scaling, gradient clipping, optimizer transition, and atomic training checkpoints.

Contrastive readout: the candidate set is part of the objective

A retrieval representation is not trained by pooling alone. Let a readout produce query vectors and document vectors , with the normalization and score contract from 0x05. Define:

For anchor , let be the admitted candidate set and its non-empty positive set. A multi-positive contrastive loss is:

This equation makes the ownership boundary explicit:

readout contract:
    which contextual rows become q_i and d_j
    whether projection and L2 normalization run
    which similarity creates s_ij

relation contract:
    stable anchor, candidate, and semantic-group IDs
    positive set P_i
    admitted denominator A_i
    hard-negative source and weighting

execution contract:
    batch/device gather order and gradient behavior
    score accumulation dtype and temperature
    local numerator/denominator passed to M3.9

For one positive column , define the admitted softmax:

Then:

Lower temperature sharpens candidate competition and scales score gradients by . It is part of training semantics, not display metadata. A document-to-query term may be added:

but the reverse relation is not automatically valid. One document may answer several queries, or one query may have several relevant documents. Treating another true positive as a negative creates a direct force to separate semantically compatible examples.

def contrastive_readout_loss(
    query,
    document,
    positive_mask,
    admitted_mask,
    temperature,
):
    require(query.ndim == document.ndim == 2)
    require(temperature > 0)
    require((positive_mask & ~admitted_mask).sum() == 0)
    require(positive_mask.any(dim=1).all())

    q = l2_normalize(query.float())
    d = l2_normalize(document.float())
    logits = (q @ d.T) / temperature

    denominator = torch.logsumexp(
        logits.masked_fill(~admitted_mask, -torch.inf),
        dim=1,
    )
    numerator = torch.logsumexp(
        logits.masked_fill(~positive_mask, -torch.inf),
        dim=1,
    )
    per_anchor = denominator - numerator
    return per_anchor.sum(), per_anchor.numel()  # numerator/count for M3.9

The positive need not remain on the diagonal after cross-device gathering, sorting, duplicate filtering, or uneven batches. The contract must carry global example IDs and derive positive columns after the final candidate layout. A detached remote candidate still affects the local query through the denominator but may not receive the reciprocal document-encoder gradient. Detached and gradient-preserving gathers are therefore different training programs even when their forward loss values match.

The major published families instantiate this contract differently:

FamilyPositive or target relationReadout/objective consequence
SBERT classificationlabeled sentence pairshared encoder plus declared pool; classifier consumes
SBERT regression or tripletsimilarity target or anchor/positive/negative relationmetric and margin scale are part of the objective
unsupervised SimCSEtwo dropout views of the same sentenceview identity and independent stochastic masks define positives
supervised SimCSEentailment positive with contradiction hard negativesNLI relation labels alter numerator and denominator membership
DPR-style dual encoderquestion with relevant passage and admitted negativesquery/document encoder identity and positive passage IDs define the space

These are not interchangeable recipes that happen to return [B,D]. Changing positive identity, duplicate masking, hard-negative mining, temperature, gather semantics, or normalization produces a new representation training contract.

Alignment and uniformity are diagnostics, not replacement labels

For unit-normalized representation function , a common alignment diagnostic measures the squared distance over the declared positive-pair distribution:

A complementary uniformity diagnostic measures how broadly independent samples occupy the hypersphere:

These quantities help describe a learned space; they do not decide whether a candidate is relevant. Alignment alone permits collapse, while uniformity alone does not encode the task’s positive relation. Both depend on the sampled positive and population distributions and therefore belong to evaluation evidence for a declared representation release, not to a universal post-processing recipe.

Shape-correct failureSemantic errorRequired evidence
diagonal positive assumed after gatherthe target column points to another examplestable global IDs and reconstructed positive map
duplicate positive remains in denominatora known match is pushed awaygroup-aware admitted/positive masks
hard-negative weight changes silentlytarget distribution and gradient scale changeminer and weight revision in the manifest
remote vectors detach unexpectedlydocument-side gradient ownership changesgather backward oracle
all-padding readout is normalizedzero has no valid unit directionnon-empty row admission before pooling/normalization
triplet margin reused under another metricthe margin has another numeric meaningmetric-specific objective fixture

M3.11 owns these semantic relations and local derivatives. M3.9 owns their placement inside accumulation, distributed reduction, optimization, and checkpoint transactions; M4 owns their physical communication and memory cost.

One scalar chain exposes four trainable-state schedules

Use a deliberately small chain so every derivative is visible:

Here is a backbone scalar, is an optional additive adaptation path, is a learned readout scalar, and is a task-head scalar. Let . By the chain rule:

The mathematical derivatives exist whether or not a parameter is trainable. Freezing changes which parameter gradients are retained and updated; it does not sever the input-gradient path needed to train a module earlier in the graph. With , , , , , and :

h = 6, r = 3, z = 12, L = 2, g = 2

dL/dw     =  6
dL/dphi   = 48
dL/dtheta =  8
dL/da     =  8

Finite differences in the executable training-state oracle verify all four values. The training schedule then admits only a subset:

scheduleretained trainable gradientsfrozen state still used in forward/backwardtask artifact
head-only probebackbone and fixed readouthead plus manifest
learned readout + headbackbonereadout and head
full fine-tuningnone of those threecomplete changed model plus head
adapter path + readout + headbase adapter, readout, head, base identity
Source-to-loss graph comparing head-only, learned-readout, full-fine-tuning, and adapter schedules by which backbone, adapter, readout, and head gradients are retained.

Gradient reachability is separate from update ownership. A frozen backbone still executes and may propagate input gradients through its operations. The diagram marks parameter gradients retained by each schedule; M3.9 owns the subsequent optimizer transaction and M6.3 owns the internal adapter map.

Frozen parameters and evaluation mode are independent switches

requires_grad=False prevents accumulation of a parameter gradient. It does not call eval(), disable dropout, freeze batch-dependent statistics in every possible architecture, or make repeated forwards deterministic. These are separate state axes:

def configure_readout_training(model, manifest):
    set_requires_grad(model.backbone, manifest.train_backbone)
    set_requires_grad(model.readout, manifest.train_readout)
    set_requires_grad(model.head, True)

    if manifest.adapter_kind is not None:
        activate_adapter(model, manifest.adapter_release)
        set_requires_grad(model.adapter, manifest.train_adapter)

    model.train(manifest.module_mode == "train")
    assert declared_trainable_names(model) == set(manifest.trainable_names)

A head-only probe can deliberately train with backbone dropout active, but that is a stochastic-feature recipe and must be recorded. If the intended artifact is a deterministic probe over frozen representations, run the backbone in evaluation mode while the new head remains in training mode. A single recursive model.train() may violate that mixed-mode contract.

Backward state follows reachability, not only trainable parameter count

Freezing a backbone removes its parameter gradients and optimizer state, but it does not always remove activation storage. If the first trainable object sits after the entire frozen backbone and no input gradient is needed, the backbone forward can run under a no-grad boundary and expose detached features:

with no_grad():
    H = backbone(batch_inputs)
H = H.detach()
R = learned_readout(H, row_contract)
Z = task_head(R)
L = local_task_loss(Z, labels, supervision_mask)

If a trainable adapter is inserted inside layer 7, backward must reach that layer and the runtime needs the activations or recomputation state required by the adapter path. “Only 1% of parameters are trainable” therefore does not imply “only 1% of training activations are live.” M4 owns the physical memory/FLOP ledger; M3.11 records the first and last trainable graph nodes so that ledger can be derived.

Multiple tasks require normalization before weighting

Suppose task produces a numerator and denominator . First form the task-local estimator, then apply an explicit task weight:

For a sequence task with two examples and losses summing to , and a token task with four supervised rows and losses summing to :

L_sequence = 4 / 2 = 2
L_token    = 4 / 4 = 1

with lambda_sequence = 1 and lambda_token = 0.5:
L_multi = 1*2 + 0.5*1 = 2.5

Summing all six raw losses and dividing by six would instead optimize an element-weighted mixture. That may be intentional, but it is not equivalent. The task sampler also changes effective weighting: a task selected twice as often contributes twice as many updates unless the schedule compensates.

Alternative adaptation schedules change the hypothesis

methodtrainable setwhere new computation appearskey tradeoff
frozen feature extraction / linear probetask head, optionally readoutafter backbonecheap isolation test; representation cannot adapt
full fine-tuningall declared backbone/readout/head parametersexisting pathbroadest local update surface; largest per-task state
gradual or selective unfreezingchanging subset of backbone layersexisting pathschedule and checkpoint phase become part of artifact
BitFitselected bias terms plus headexisting affine operationssmall update set, different hypothesis from low-rank adaptation
bottleneck adaptersinserted task modules plus headinside blocksextra nonlinear path; base remains shared
LoRAselected low-rank weight-update branches plus headbeside chosen linear mapstarget modules and rank define update surface

ULMFiT introduced discriminative fine-tuning and gradual unfreezing in a different recurrent-language-model setting; it is useful historical evidence that trainability can be a schedule rather than a fixed set. It is not evidence that the exact ULMFiT recipe transfers unchanged to every Transformer readout. (Howard and Ruder, 2018)

M3.11 compares these schedules by which readout behavior may change. M6.3 derives LoRA factors, initialization, target modules, backward, and adapter checkpoints. This article must not compress those mechanics into a generic “adapter” box.

The training manifest is a proof obligation

training contract:
    dataset revision + split hash + example-ID namespace
    tokenizer/readout/head manifests
    objective kind + label schema + ignored-row policy
    numerator definition + denominator definition
    task weights + task sampler
    trainable-name allowlist + frozen-name hash
    module train/eval modes + dropout/RNG policy
    first and last trainable graph nodes
    base / adapter / readout / head release identities
    parent checkpoint and optimizer-procedure reference -> M3.9

Admission should fail closed:

def validate_training_contract(c, model):
    require(c.objective_kind == model.head.objective_kind)
    require(c.denominator_kind in allowed_denominators(c.objective_kind))
    require(c.valid_supervised_count > 0)
    require(all(weight >= 0 for weight in c.task_weights.values()))

    actual = declared_trainable_names(model)
    require(actual == set(c.trainable_names))
    require(actual.isdisjoint(c.frozen_names))

    if c.schedule == "head_only":
        require(actual <= model.head_parameter_names())
    elif c.schedule == "adapter":
        require(c.adapter_release is not None)
        require(actual <= model.adapter_and_readout_head_names())
    elif c.schedule == "full":
        require(model.backbone_parameter_names() <= actual)
    else:
        require(c.schedule == "readout_head")

    require(c.module_modes_cover_all_stochastic_modules)

The function does not step an optimizer. It proves that the local graph and declared trainable-state policy agree before M3.9 begins the transaction.

Training failure lab

failureshape checksemantic consequencedetection
attention_mask reused as token-label maskoften passesspecial/subword/question rows receive unintended losscompare row-identity table with supervised-row table
loss divided by padded tensor sizepasseslong-padding batches shrink gradient scalereconcile numerator and declared denominator
frozen backbone left in stochastic train mode accidentallypassesprobe features and metrics vary with dropout RNGrecord module modes; replay identical batch
adapter schedule places base weights in optimizerpassesartifact ceases to be adapter-onlyexact trainable-name allowlist
trainable internal adapter executed under no_grad()passes forwardadapter receives no gradientfirst-trainable-node reachability assertion
raw task losses summed before task normalizationpassestasks with more labels/rows dominatereport each
checkpoint saves head without base/readout identityloads by shapehead is paired with incompatible representationparent release and manifest hashes
gradual unfreezing resumes at wrong phasepasseswrong layer subset changes after restartcheckpoint schedule phase and trainable-set hash

The contract closes at a scalar local objective plus typed reachable gradients. The exact update, distributed reduction, finite gate, optimizer state, and restart transaction remain M3.9 responsibilities.

0x08 Runtime Integration Must Preserve The Readout Algebra

A correct training artifact can still be deployed incorrectly. Runtime code adds padding, groups unrelated examples into rectangles, splits long sources into overlapping windows, exports a graph with named dynamic axes, casts tensors, caches representations, and may distribute encoding across workers. Each step can preserve tensor shapes while changing the representation or decision.

The runtime owner question is therefore:

What must remain invariant when one admitted readout artifact is evaluated with different batch shapes, windows, devices, or exported backends?

M3.11 owns the single-artifact answer. M5 owns request scheduling, queueing, continuous batching, and service-level admission. Retrieval systems own ANN index construction, shards, metric realization, and search execution. M4/M8 own physical kernel, precision, compression, and deployment costs.

Padding invariance is a conditional proof

For selected rows and binary readout mask , masked mean pooling is:

Append any number of rows with mask zero. If every original valid contextual row remains identical, then:

so . This is the readout proof. It is not yet a complete model proof, because the premise can fail when:

  • padding is visible inside attention;
  • left padding shifts absolute position IDs without compensating them;
  • the “first row” selector uses physical column zero rather than the first declared valid/special row;
  • token-type, sequence, or special-row metadata changes;
  • stochastic mode or backend numerics differ.

Official Transformers documentation exposes padding side, padding length, truncation strategy, maximum length, and padding-to-a-multiple as distinct runtime choices. They create rectangular tensors; they do not guarantee semantic equivalence by themselves. (Hugging Face padding and truncation)

For the pooling families in 0x03:

def padding_safe_readout(H, row_valid, kind):
    require((row_valid.sum(axis=1) > 0).all())
    if kind == "mean":
        return (H * row_valid[..., None]).sum(1) / row_valid.sum(1, keepdims=True)
    if kind == "max":
        return where(row_valid[..., None], H, -inf).max(1)
    if kind == "first_valid":
        index = first_true_index(row_valid, axis=1)
        return gather_rows(H, index)
    raise ValueError("unsupported readout")

Zero-filling invalid rows before max remains wrong when all valid values in a channel are negative. Selecting H[:, 0] remains wrong under left padding. The runtime oracle evaluates the same valid rows with left and right padding and proves that all three corrected readouts agree.

Dynamic batching changes allocation, not example identity

One request can move among batches of different width. Its output is admitted only if the runtime preserves:

example_id
source rendering and normalization
tokenizer revision
content token IDs and row identities
valid-row / readout masks
position and segment policy
readout/head/calibrator/decision releases
stochastic and dtype policy

Batch order is not example identity. Every output row must carry the stable example ID through sorting, bucketing, padding, model execution, and scatter back. A length-sorted batch that returns outputs in sorted order without the inverse permutation is numerically plausible and semantically wrong.

Long sources require an explicit window contract

Truncation is one policy, not a neutral preprocessing step. Official tokenizer APIs expose overflowing encodings, offsets, sequence IDs, special-token masks, and a stride that repeats content from the preceding piece. Those fields are enough to build an auditable window map; they do not choose how predictions from those windows should be reconciled. (Tokenizers Encoding, Transformers tokenizer API)

An immutable window record needs:

source_id, window_id, parent release
source character interval and source token identities
window-local row -> source token / character offset
left/right context and stride
special-row insertion
overlap multiplicity or one-owner assignment
task-specific aggregation policy

There are several non-equivalent design choices:

long-source policyretained evidencemain failure boundary
hard truncationone prefix/suffix/pair allocationomitted evidence is unrecoverable
overlapping windowslocal context around all covered spansduplicate source rows and inconsistent boundary context
hierarchical readoutone vector/logit per chunk, then document aggregatoraggregator is another trained or declared model
late interactionmany selected row vectorslarger persistent artifact; retrieval systems own index realization
long-context backboneone longer contextual graphdifferent model/position/runtime contract, not “no chunking” for free

Overlap correction fixes ownership, not context

Let occurrence in window map to source token . Let be the number of retained occurrences of source token . A de-duplicated mean over occurrence representations is:

For source values [2, 4, 10, 20] and windows [2,4,10] and [10,20], the naive mean of window means is:

((2 + 4 + 10) / 3 + (10 + 20) / 2) / 2 = 10.1667

The multiplicity-corrected occurrence mean is:

(2 + 4 + 10/2 + 10/2 + 20) / 4 = 9

which matches the unique-value mean. But contextual rows for the repeated token need not be equal across windows: each occurrence sees different neighbors and positions. Multiplicity correction averages those occurrence representations; it cannot reconstruct the representation from one unavailable full-context forward. Choosing a “maximum-context” owner, center-weighting, first owner, or learned hierarchy defines another contract.

Aggregate the object the model was trained to aggregate

For document classification, common policies include averaging logits, averaging probabilities, taking a maximum, or applying a trained second-stage aggregator. They are not interchangeable. With chunk logits :

Softmax is nonlinear, so generally . For chunk logits [4,0] and [0,0]:

softmax(mean logits)     ~= [0.8808, 0.1192]
mean(softmax(each logit))~= [0.7410, 0.2590]

Both predict class zero here, but their confidence and threshold behavior differ. Calibration must be fitted after the aggregation point used in deployment. A per-chunk temperature cannot be assumed valid for a document-level maximum or mean.

Task-specific reconciliation differs again:

outputwindow reconciliation
token labelsmap rows through offsets; resolve duplicate token ownership before metrics/output
QA spansmap local start/end to source offsets; reject cross-window spans; compare null and span scores under one declared rule
sequence logitsaggregate logits/probabilities with a trained or fixed policy before final decision
embedding vectoraggregate chunk vectors or token occurrences, then normalize at the trained stage
late-interaction rowsde-duplicate or retain versioned occurrences under the artifact schema

For normalized embeddings, “normalize each chunk then average” differs from “average unnormalized chunk vectors then normalize.” The runtime must match the training and evaluation geometry, not merely return unit length.

Export is an ABI, not a file conversion

An exported readout graph must name both its axes and semantics:

inputs:
    input_ids       int64 [batch, sequence]
    attention_mask  bool/int [batch, sequence]
    token_type_ids  optional, model-specific [batch, sequence]
    position_ids    optional, policy-specific [batch, sequence]

outputs, exactly one declared family:
    sequence_logits [batch, classes]
    regression      [batch, outputs]
    token_logits    [batch, sequence, classes]
    start_logits + end_logits [batch, sequence]
    embeddings      [batch, embedding_dim]
    token_vectors   [batch, sequence, projection_dim] + row mask

Batch and sequence may be dynamic axes. Class, output, embedding, and projection dimensions are release constants. Dynamic shape support can change backend optimization opportunities, so “dynamic” is both an ABI and performance choice. ONNX Runtime documentation explicitly notes graph input/output names, shapes, and dynamic axes as export-visible properties and warns that dynamic axes can constrain some Transformer optimizations. (ONNX Runtime PyTorch inference, Transformer optimization)

Do not export a bare output tensor and reconstruct semantics from its rank. [B,S,C] could be token classes, token vectors, or another hidden state. The release must carry output kind, score type, row mask, normalization stage, calibrator, threshold/tie policy, and label map.

Reusable state is keyed by the complete representation release

A cached embedding or token-vector artifact is valid only under a complete key:

Changing a calibrator may leave embeddings reusable but invalidate final decisions. Changing the readout or normalization invalidates vectors. Changing a K/V-targeting adapter can invalidate contextual rows. Cache identity should therefore be layered rather than one opaque “model version” string:

contextual-state release -> readout/vector release -> score release -> decision release

Cross-encoders have no query-independent document contextual state. Bi-encoders can cache one document vector. Late-interaction systems can cache selected document row vectors. The cacheability statement follows the interaction graph from 0x06, not a runtime optimization toggle.

Distributed encoding needs algebraic merge rules

Independent examples can be encoded on different workers and scattered back by stable ID. Splitting one example across workers is harder: only readouts with an associative sufficient state can merge exactly after contextual rows already exist. For masked mean, worker can return:

then:

For max, merge channel-wise maxima and retain deterministic argmax ownership if backward or provenance is needed. Learned attention cannot generally normalize each shard independently and average the outputs; it must merge the global softmax sufficient state or evaluate one global denominator. Attention inside the backbone also cannot be recreated by independently encoding arbitrary sequence shards unless the backbone architecture itself defines such a split.

M4 owns communication bytes and collective placement. M5 owns worker admission and scheduling. M3.11 only declares the mathematical merge object and stable output identity.

Runtime readout path showing dynamic padding with stable row identities, long-source windows with overlap ownership, typed exported outputs, and versioned reusable state.

The runtime may change rectangular allocation and physical placement. It may not silently change row identity, chunk ownership, output type, or the release key of reusable representations.

Runtime admission and failure lab

def admit_readout_request(request, release):
    require(request.release_id == release.id)
    require(request.tokenizer_revision == release.tokenizer_revision)
    require(request.output_kind == release.output_kind)
    require(request.padding_side in release.tested_padding_sides)
    require(request.max_length <= release.exported_max_length)

    if request.requires_overflow:
        require(release.window_policy is not None)
        require(release.window_aggregation is not None)
        require(request.offsets_available)

    if release.output_kind in {"embedding", "token_vectors"}:
        require(request.normalization_stage == release.normalization_stage)
    return True
failureshape checkconsequencedetection
left padding with unshifted absolute positionspassesvalid contextual rows changecompare unpadded/left/right outputs by stable row ID
H[:,0] used as first-row readoutpassesleft pad becomes representationfirst-valid/special-row identity assertion
overlapping windows counted twicepassesboundary evidence gets extra weightsource-token multiplicity ledger
chunk probabilities averaged after logit calibrationpassesconfidence contract changesaggregate-point identifier and calibration replay
QA span start/end taken from different windowspasses indicesimpossible source spanrequire shared source/window compatibility
export drops row mask for token vectorspasses tensor rankpadded rows enter late interactionoutput ABI requires companion row mask
cached vector reused after readout revisionpasses dimensionstale representation in new score spacelayered release key
worker averages local means equallypassesunequal shard lengths bias global meanmerge (sum,count), not local means
sorted batch is not inverse-permutedpassesoutputs assigned to wrong examplesstable-ID scatter reconciliation

The next section pins official implementations and reconciles these mathematical contracts with concrete source symbols. The runtime derivation above deliberately stops before framework-specific class names become claims.

0x09 Pinned Implementations Expose Hidden Policy

Paper equations describe a family of implementations. A moving documentation page or main branch cannot prove what one release did. This section therefore uses immutable source snapshots captured on 2026-08-05:

projectpinned revisionlocal evidence
Hugging Face Transformers0104732151118872214a2bcdc5badd32d938ab38hf_modeling_bert_0104732.py
Sentence Transformersf6d3a4030d6878b3d916971de4686cef46626683pooling, normalization, and cross-encoder snapshots

The files and SHA-256 digests live under docs/numinens-evidence/m3-11-representation-readout/sources/. They are evidence snapshots, not vendored dependencies. Statements below describe these commits. Earlier or later releases may choose another class layout, default, or edge-case policy.

BertPooler is a learned first-physical-row map

The pinned BertPooler performs:

first_token_tensor = hidden_states[:, 0]
pooled_output = self.dense(first_token_tensor)
pooled_output = self.activation(pooled_output)  # tanh

Its durable tensor contract is:

Three policies are bundled:

  1. the selected row is physical column zero;
  2. the map has learned weight and bias;
  3. the output is bounded by tanh.

That is not equivalent to raw [CLS], first-valid pooling, or masked mean. It is safe under the ordinary right-padded BERT convention because the special classification token occupies row zero. If a runtime left-pads without keeping that token at row zero, the pooler does not search the mask for it.

The sequence-classification wrapper owns more than a linear layer

At the pinned revision, BertForSequenceClassification instantiates a BertModel with the pooler, applies classifier dropout, and maps the pooled width to num_labels:

input rows
    -> BertModel
        -> pooler_output [B,D]
            -> classifier dropout
                -> Linear(D, num_labels)
                    -> logits [B,num_labels]

When config.problem_type is absent, the wrapper infers a local objective from label count and dtype:

num_labels == 1                   -> regression / MSE
num_labels > 1 and integer labels -> single-label / cross-entropy
otherwise                         -> multilabel / BCE-with-logits

This convenience is version-specific and can make dtype part of objective selection. A float tensor containing class IDs can therefore choose a different loss path than an integer tensor of the same shape. M3.11’s release manifest is stricter: problem_type, label schema, and output meaning are declared before the batch arrives rather than inferred from one batch dtype.

Token classification preserves rows but does not align source words

BertForTokenClassification constructs BertModel(..., add_pooling_layer=False), then applies dropout and one classifier to every model row:

Its loss flattens logits to [-1, num_labels] and labels to [-1] before cross-entropy. The wrapper does not derive word_ids, choose first-subword ownership, or map results to source offsets. Those remain preprocessing and release contracts. The common -100 ignore behavior comes from the loss implementation’s default; it does not make every attention-masked row ignored automatically.

This snapshot therefore agrees with the 0x04 tensor trace while reinforcing a boundary: a task-head class consumes aligned labels; it does not prove their alignment.

The QA wrapper creates two channels, then chooses an out-of-range sentinel

The pinned BertForQuestionAnswering disables the BERT pooler and applies one linear map to every contextual row. It splits the final channel into start and end logits:

H [B,S,D] -> Linear(D,2) -> [B,S,2]
                         -> start [B,S], end [B,S]

For training, it defines ignored_index = S, clamps supplied positions into [0,S], applies cross-entropy to each channel with that ignored index, then averages start and end losses. Row index is outside the score axis 0..S-1, so it acts as an ignore sentinel rather than a candidate span row.

The implementation does not enforce start <= end, context-segment ownership, maximum answer length, or a no-answer score rule. Those are decode and dataset contracts from 0x02/0x04. Reading only the class name would hide this separation.

Sentence Transformers pooling is a configurable concatenation

The pinned Pooling module accepts one or more modes:

cls, max, mean, mean_sqrt_len_tokens, weightedmean, lasttoken

Every selected mode emits a vector, and the module concatenates them on the last axis. Therefore two active width- modes emit width ; the output is not an average of modes.

The implementation reconciles with the derivations in 0x03 as follows:

modepinned implementationimportant edge policy
clsuses supplied cls_token_embeddings, else gathers first 1 in attention maskfallback supports left padding; it identifies first valid, not necessarily a semantic CLS row
maxfills masked entries with -inf, then channel-wise maxagrees with the negative-value counterexample
meanmasked sum divided by mask sumdenominator is clamped to 1e-9 rather than rejecting an empty row set
mean_sqrt_len_tokenssame sum divided by square root of clamped countdifferent length scaling, not ordinary mean
weightedmeanphysical weights 1..S times attention maskleft padding shifts content weights unless the intended policy accounts for it
lasttokenfinds last true mask entry by reversing the maskall-zero fallback returns a masked zero row instead of fail-closed rejection

The article’s zero-valid-row admission is deliberately stricter than these fallbacks. Returning a finite zero or clamped result can keep a batch running, but it also hides malformed row ownership. Whether to reject or tolerate that case belongs in the release contract.

The physical position weighting deserves emphasis. With right padding, content rows at columns 0,1,2 receive weights 1,2,3. Move the same content to columns 2,3,4 under left padding and the weights become 3,4,5. Masking removes pads but does not restore content-relative positions. Therefore the pinned weightedmean mode is not left/right padding invariant in general.

Normalization is a separate module and therefore a separate stage

The pinned Normalize module reads sentence_embedding and applies:

F.normalize(sentence_embedding, p=2, dim=1)

It does not normalize token embeddings before pooling, infer a score metric, or attach a threshold. Module order determines geometry:

Transformer -> Pooling -> Normalize

is generally different from:

Transformer -> normalize each token -> Pooling

and both differ from document-window aggregation followed by normalization. The serialized module graph, not the presence of a Normalize class anywhere in the repository, defines the release.

CrossEncoder prediction exposes score-policy and permutation contracts

At the pinned Sentence Transformers revision, CrossEncoder.predict:

  1. moves the model to the requested device and calls eval();
  2. sorts input pairs by estimated length;
  3. preprocesses each joint pair and runs the model;
  4. applies a configured activation;
  5. optionally applies softmax for multi-output scores;
  6. squeezes the single-label axis when applicable;
  7. inverse-permutes results to original input order.

The default activation is sigmoid when num_labels == 1 and identity otherwise; apply_softmax defaults to false. Consequently, the API can return a sigmoid-transformed scalar for one model and raw multi-class logits for another. “CrossEncoder score” is not one universal score type.

The inverse permutation mechanically supports 0x08’s batch-identity rule. It uses original list indices as the local identity; a larger service still needs stable request/example IDs around that call. Joint pair preprocessing also confirms the architecture boundary: document state depends on the query and is not independently reusable.

Pinned implementation reconciliation mapping BERT pooler and task heads plus Sentence Transformers pooling, normalization, and CrossEncoder prediction to their hidden semantic policies.

Pinned source symbols are evidence for one revision. The article extracts durable tensor and semantic contracts, then records where convenience defaults are weaker than release admission.

Executable source reconciliation

The pinned-source oracle does not import these frameworks. It instead:

verifies each pinned file SHA-256
checks exact semantic source markers
rejects HTML/404 bodies and unpinned revisions
reuses prior numeric pooling/head/runtime oracles
emits one source-symbol -> article-contract report

The checked markers include:

BertPooler: hidden_states[:, 0] -> dense -> tanh
sequence wrapper: pooled output -> dropout -> classifier
token wrapper: sequence output -> dropout -> classifier
QA wrapper: split start/end; ignore sentinel at sequence length
Pooling: -inf max; sum/count mean; first-valid fallback
Normalize: p=2 along sentence embedding dimension
CrossEncoder: eval; length sort; activation; optional softmax; inverse permutation

This is stronger than citing a documentation page and weaker than reproducing all upstream tests. It proves the narrow implementation claims made here while leaving kernel/runtime behavior to its owning modules.

0x0A Evaluation And Rollback Must Preserve The Semantic Tuple

An output tensor is not publishable because it has the expected shape, and a readout is not releasable because one aggregate score improved. Evaluation must exercise the exact tokenizer, contextual state, readout, head, score, calibrator, decision, runtime, and window policy that will be released. A rollback must restore that complete semantic tuple or explicitly migrate every dependent artifact.

This section owns readout-local semantic evidence. It does not duplicate M8.10, which owns fleet workloads, latency/goodput, resource and energy gates, shadow traffic, canary attribution, production monitoring, and operational rollback. M3.11 produces the semantic candidate and compatibility record consumed by that deployment process.

Freeze split roles before observing final outcomes

One immutable split manifest needs more than filenames:

dataset revision and license/provenance
stable source/group IDs and deduplication policy
train, development, calibration, promotion-test roles
window/chunk parent identities
label schema and scorer revision
slice definitions fixed before final evaluation
allowed tuning operations per split

The roles are distinct:

splitpermitted useforbidden use
trainfit backbone/readout/head/adaptersreport as held-out evidence
developmentchoose architectures and ordinary hyperparametersfinal promotion claim after repeated tuning
calibrationfit temperature, thresholds, abstention, or null-score rulesupdate backbone/head from those outcomes unless reclassified as train data
promotion testevaluate one frozen candidate and policytune the candidate, thresholds, slices, or margins after seeing results

All windows from one source document, conversation, user, patient, or other declared dependence group must stay in one role. Splitting overlapping windows at random creates nearly duplicated train/test evidence. M4.7-M4.9 own the general scaling-law split discipline; M3.11 applies the same immutable-identity principle to readout evaluation.

Match the metric to the output object

No one metric covers all heads:

output contractprimary semantic metricsrequired companion evidence
single-label classaccuracy; macro/micro precision, recall, F1confusion matrix, per-class support, calibration and cost-sensitive errors
multilabelper-label and macro/micro F1; average precision where appropriateprevalence, threshold vector, labels per example, empty-label policy
regressionMAE/MSE/RMSE; Pearson or Spearman when the task defines ittarget range, residual slices, clipping and missing-target rules
token/entity labelsexact entity-span precision/recall/F1token accuracy, illegal tag sequences, boundary/type error table, offset scorer revision
extractive QAnormalized exact match and token-overlap F1answerable/unanswerable slices, null-score rule, window coverage and truncation failures
sequence similaritytask-defined correlation or pair classificationnormalization/metric contract and score distribution
retrieval/rerankingrecall, MRR, nDCG, MAP under fixed candidates/corpusrepresentation and candidate semantics are local; index/search execution is owned by retrieval systems

GLUE’s value is its multi-task and diagnostic framing, not one universal aggregate. MTEB similarly exists because performance on one embedding task such as semantic textual similarity does not establish performance on clustering, classification, reranking, or retrieval; its original paper reports no single method dominating every evaluated task. These are externally verified reasons to preserve task buckets, not claims that either benchmark is a sufficient production gate. (GLUE, MTEB)

For exact entity evaluation, a predicted span is a true positive only when its source boundary and type match under the pinned scorer. If , , and count exact entities:

Token accuracy can remain high while entity F1 collapses on boundaries. CoNLL evaluation history also illustrates that scorer behavior for malformed tag sequences matters; record the exact scorer rather than reimplementing an informal “CoNLL F1.” (CoNLL-2003 shared task, NER scorer reproducibility analysis)

Macro and micro answer different weighting questions

For class , define and . Macro F1 gives every class equal weight:

Micro F1 first sums event counts:

For single-label multiclass classification, micro F1 equals accuracy; macro F1 can expose failure on rare classes. In the evaluation fixture, six examples yield:

class 0: F1 = 1.0
class 1: F1 = 0.5
class 2: F1 = 0.5

macro F1 = 2/3
micro F1 = accuracy = 4/6

The equality here is a property of the single-label counting scheme, not a universal identity for multilabel or token tasks.

Calibration and decisions need separate held-out evidence

Accuracy and ranking can remain fixed while confidence changes. A classification release should preserve at least:

raw logits
post-calibration probabilities
predicted class or thresholded labels
negative log-likelihood / Brier score
calibration summary with bin definition
coverage and risk under abstention
cost-weighted false positive/negative counts

Temperature, thresholds, per-label thresholds, and abstention regions are fit on the calibration split and frozen before promotion testing. If the threshold is changed after inspecting test errors, the old test set has become tuning data; a new untouched gate is required.

For a confidence partition into bins , expected calibration error is often reported as:

ECE depends on bin construction and can hide within-bin or slice errors. It is a diagnostic with a versioned estimator, not a universal proof of calibration. NLL, Brier score, reliability plots, and critical-slice calibration should accompany it when confidence drives actions.

Slices make failure mechanisms visible

Freeze slices from mechanism hypotheses before the final gate:

source length and truncation/window coverage
left/right padding and batch-width buckets
language, domain, time, and source system
class/label support and multi-label cardinality
entity type and span length
QA answerability, answer length, and answer position
special-token, subword, Unicode, and offset complexity
cross-encoder pair length and candidate rank
embedding norm, query/document length, and interaction family

Report support and uncertainty with every slice. A perfect score on three cases is not evidence of a robust subgroup. Global metrics must not average away a critical slice floor, and slices must not be invented post hoc until one makes the candidate look favorable.

Pair candidate and baseline on stable case identities

Evaluate the candidate and rollback parent on the same stable cases and retain per-case outputs:

Pairing removes variation from changing examples and supports direct error transition tables:

both correct
parent correct -> candidate wrong
parent wrong -> candidate correct
both wrong, same or different failure class

M8.10 owns formal promotion margins, paired uncertainty, non-inferiority, and deployment selection. M3.11 supplies stable semantic case IDs, outputs, and failure categories so those tests operate on the right objects.

Compatibility is a dependency graph, not one Boolean

Represent the artifact as layers:

source/tokenizer
    -> contextual state
        -> readout/vector
            -> head/raw score
                -> calibration
                    -> decision/label

A change invalidates its descendants unless an explicit migration proves compatibility:

changecontextual cachevector cacheraw scorescalibrated scoresdecisions
tokenizer/template/position policyinvalidateinvalidateinvalidateinvalidateinvalidate
backbone or active internal adapterinvalidateinvalidateinvalidateinvalidateinvalidate
selected layer/pooling/projection/normalizationmay reuse contextual rows if identity matchesinvalidateinvalidateinvalidateinvalidate
task head weights or ordered label mapreusablereusable if head consumes vectorsinvalidate semantic score artifactinvalidateinvalidate
calibrator onlyreusablereusablereusableinvalidateinvalidate
threshold/tie/abstention onlyreusablereusablereusablereusableinvalidate
backend/dtype/exportcompatibility unproven until parity testssamesamesamesame

“Reusable” means semantically eligible under the exact parent identities; it does not mean retaining the cache is operationally worthwhile. Backend/dtype changes are not automatically invalid, but they require parity evidence under the numerical contract before sharing a namespace.

Migration must be explicit and reversible

Examples:

  • adding a new label changes output width and normally requires a new head;
  • reordering labels with unchanged width changes coordinate meaning and must migrate both head rows and label maps together, or reject the artifact;
  • changing mean pooling to concatenated mean+max changes head input width;
  • changing calibration preserves raw logits but creates a new calibrated-score and decision release;
  • changing window stride changes which evidence reaches a document-level readout even when tensor shapes stay fixed.

A migration record needs source and target release IDs, transformed objects, preconditions, postconditions, parity tests, cache invalidation plan, and a rollback target. “Load succeeded” proves only structural compatibility.

Local lifecycle and deployment lifecycle meet at the candidate boundary

M3.11’s semantic artifact state machine is:

DRAFT
    -> RECONCILED       hashes, schemas, source markers, local oracles pass
        -> EVALUATED    frozen semantic suite and critical slices pass
            -> CANDIDATE complete package, compatibility and rollback records

M8.10 consumes CANDIDATE and owns shadow, canary, ramp, active production, monitoring, and fleet rollback. If a deployed readout fails, the M3.11 rollback record tells M8.10 which semantic tuple and cache namespaces constitute the known-good parent.

Readout evaluation and release pipeline from immutable split roles through task-specific metrics, calibration and critical slices, compatibility-directed invalidation, semantic candidate packaging, and rollback handoff to M8.10.

M3.11 proves the semantic candidate. M8.10 decides whether and how that candidate receives production traffic. Rollback joins both contracts: restore the known-good semantic tuple and execute the service transition safely.

Rollback restores a known-good tuple, not just old weights

The rollback parent must include:

tokenizer/template and source normalization
backbone, adapter, selected layer, and dtype policy
readout/pooling/projection/normalization
head, ordered label map, null label, score type
calibrator, thresholds, abstention, and tie rules
window/export/runtime schemas
compatible cache namespaces or explicit invalidation
evaluation evidence and known-good release ID

Restoring only the old checkpoint while leaving the new tokenizer, label order, pooling configuration, calibrator, or vector cache can reproduce the original failure under an old model filename. Rollback is a forward transition to a complete known-good identity.

Publication evidence bundle

manifest/
  semantic artifact and parent identities
  immutable split and scorer manifests
  trainable/runtime/export contracts

evaluation/
  per-case outputs for candidate and parent
  aggregate, per-class, per-label, span, QA, calibration metrics
  frozen slices, supports, failure taxonomy

implementation/
  pinned source revisions, snapshots, hashes, marker report
  numerical oracle and backend parity reports

lifecycle/
  migration and compatibility matrix
  invalidation plan and rollback target
  M8.10 deployment handoff

Final readout failure lab

layershape-correct failureevidence that catches it
inputtokenizer or template driftstable source-to-row trace and artifact hash
rowsspecial/padding/subword row enters wrong readout/lossrow identity and offset oracle
poolingzero-filled max or wrong denominatornegative-value and padding-invariance fixtures
headlabel order changes at same widthordered map plus semantic probes
spanlocal window indices treated as source offsetsoverflow/offset reconciliation and exact spans
scoresigmoid probability treated as raw logitscore-type and pinned CrossEncoder marker
contrastive objectivepositive mapping or admitted denominator changes silentlystable relation IDs, candidate masks, and gather-gradient oracle
calibrationthreshold tuned on testimmutable split-role audit
batchingsorted outputs assigned to wrong examplesstable-ID inverse-permutation check
chunkingoverlap counted twice or logits/probabilities swappedmultiplicity and nonlinear aggregation oracle
cacheold vector reused after readout changecompatibility dependency graph
migrationhead loads against incompatible pool widthderived width and migration preconditions
rollbackold weights restored with new label map/cachecomplete known-good tuple reconciliation

The article is publishable only when these failures are represented by executable checks, source evidence, or explicit release gates rather than by warnings alone.

0xFF References