Skip to content

vllm

vllm

The base envoys of a vLLM family: the same values as nnterp.components, read where vLLM keeps them.

vLLM runs a family through its own implementation, which differs from transformers' in three ways a value has to absorb:

  • No batch axis. A request's activations are [tokens, hidden_size]: every prompt token on the prefill, one row on each decode step. The values keep nnterp's layouts, so they are served as [1, tokens, hidden_size] and code written against [:, -1] runs on both engines.
  • Live buffers. A served tensor is the model's own, and the next fused kernel rewrites it after the block has read it, so a saved reference comes back holding later data. Every value here is a private copy, handed back to the model when the block moves on; in-place edits to the copy and assignment both reach the model.
  • The residual stream in two halves. Most blocks fuse the residual add into the next norm and are called with, and return, (hidden_states, residual): the stream is their sum. FusedLayer is that block, Layer one that is called with the stream (alone, or after the positions) and returns it (alone, or with something beside it).

The attention module hands its queries, keys and values to vLLM's attention layer (its attn child) and gets the per-head outputs back, each [tokens, num_heads * head_dim]; they are that child's inputs and output, served in nnterp's layouts with the heads split out. What the layer computes between them (the scores, the pattern) is inside its kernel, not Python on this engine, so those two are recomputed from the queries and keys: read-only, and there on the prefill only, where a step holds every key.

A family vLLM runs through its transformers backend (transformers' own modules inside the engine) builds on nnterp.components.vllm.transformers_backend instead, where the batch axis is already there and the engine's attention layer is mounted as the attention module's attn child.

DECODE_STEP module-attribute

DECODE_STEP = "recomputed from this step's queries and keys, and on a decode step the earlier tokens' keys are in vLLM's cache, which only its kernel reads; read it on the prefill"

__all__ module-attribute

__all__ = ['Attention', 'DECODE_STEP', 'Flat', 'FusedLayer', 'Layer', 'Mlp', 'argument', 'batched', 'on_decode_step', 'on_transformers_backend', 'project', 'summed', 'unbatched', 'with_argument']

Attention

Attention(*args: Any, **kwargs: Any)

Bases: Attention

A vLLM attention module: its contribution, what goes into and comes out of the engine's attention layer, and the pattern.

The module projects (and, on a rotary family, rotates) its queries, keys and values and calls vLLM's attention layer on them, self.attn(q, k, v), which returns the per-head outputs the output projection then mixes. Those four are the attn child's inputs and output, each [tokens, num_heads * head_dim], served with the heads split out by the module's own head_dim. A family whose attention module names that child, or its head width, another way points the values at it.

They are this step's rows: on a decode step the keys and values are the new token's alone, and the earlier ones are in the engine's cache, which the kernel reads for itself.

The scores and the pattern are computed inside the kernel, which serves nothing between its inputs and its output, so here they are recomputed from the queries and keys, with the layer's own scale, softcap and window. That makes them read-only (the kernel never takes a pattern: edit the queries or keys to change what a head attends to, or its head outputs to change what it wrote) and there on the prefill only, where a step holds every key; a decode step raises Unavailable (on_decode_step).

attention_scores class-attribute instance-attribute

attention_scores = DerivedEProperty(scores, description='The scores entering the softmax, [1, num_heads, query, key], recomputed from the queries and keys; prefill only, read-only', unavailable=on_decode_step)

attention_probabilities class-attribute instance-attribute

attention_probabilities = DerivedEProperty(probabilities, description='The attention pattern, [1, num_heads, query, key], recomputed from the queries and keys; prefill only, read-only', unavailable=on_decode_step)

attention_queries

attention_queries(value: Tensor) -> Queries

The queries the attention layer receives, after the projection, any query norm and the rotary embedding.

attention_keys

attention_keys(value: Tensor) -> Keys

This step's keys as the attention layer receives them; num_kv_heads wide under grouped-query attention.

attention_values

attention_values(value: Tensor) -> Values

This step's values as the attention layer receives them; num_kv_heads wide under grouped-query attention.

attention_head_outputs

attention_head_outputs(value: Tensor) -> HeadOutputs

Each head's output as the attention layer returns it, before the output projection mixes them.

attention_premix

attention_premix(value: Tensor) -> HeadOutputs

The output projection's input split by head, after any gate the attention applies; the head outputs where there is none.

attention_output

attention_output(value: Tensor) -> Residual

Flat

Flat(*args: Any, heads: str | None = None, batch: bool | Callable[[Envoy], bool] = False, factor: Callable[[Envoy], float] | None = None, **kwargs: Any)

Bases: EProperty

An EProperty over a [tokens, ...] tensor, served as a private [1, tokens, ...] copy.

Takes what EProperty takes (a path for a key, select for one argument of a call). The decorated function receives the batched copy and returns the value; its annotation is the layout. In-place edits are handed back to the model when the block moves on, and an assignment is checked against the rows this request has before it is swapped in. An output that is a tuple serves its first element unless select says another: a norm vLLM calls with the residual beside the stream returns (normed, residual), and the same norm called alone returns the tensor.

PARAMETER DESCRIPTION
heads

For a [tokens, num_heads * head_dim] tensor, where the head axis goes: "first" serves [1, num_heads, tokens, head_dim] (the queries, keys and values), "last" [1, tokens, heads, head_dim] (the head outputs). The width of a head is the head_size of the module the key names, vLLM's attention layer, or, for a module that has none (the output projection), the host's head_dim.

TYPE: str | None DEFAULT: None

batch

Whether the tensor already carries the batch axis, [1, tokens, ...], as it does inside the transformers model vLLM's transformers backend runs: its rows are then tensor[0], served and handed back the same way. A function of the host for a value whose model decides (the root's token_embeddings).

TYPE: bool | Callable[[Envoy], bool] DEFAULT: False

factor

For a value that is the tensor times a scalar of the model (Granite's residual_multiplier), a function of the host giving that scalar. The value is served multiplied and is a computed copy: a write goes back divided by the factor, and a read that edits nothing hands the model's tensor back untouched, so dividing never rounds a clean forward.

TYPE: Callable[[Envoy], float] | None DEFAULT: None

heads instance-attribute

heads = heads

batch instance-attribute

batch = batch

factor instance-attribute

factor = factor

__call__

__call__(preprocess: Callable) -> 'Flat'

__set__

__set__(obj: Envoy, value: Tensor) -> None

FusedLayer

FusedLayer(*args: Any, **kwargs: Any)

Bases: Layer

A vLLM block with the residual add fused into the next norm (Llama, Qwen, Gemma, most families).

It is called forward(positions, hidden_states, residual) and returns (hidden_states, residual): hidden_states is what the last sublayer produced and residual the stream before it, so the stream is their sum, entering and leaving. The first block is called with residual None and the embeddings as hidden_states.

The sum is computed for the read, so it is nobody's buffer. An edit goes back as a change to hidden_states (the next norm adds the two), and a read that edits nothing changes nothing: the difference it hands back is exactly zero.

attention_norm_output class-attribute instance-attribute

attention_norm_output = Layer.attention_norm_output

mlp_norm_output class-attribute instance-attribute

mlp_norm_output = Layer.mlp_norm_output

mlp_input class-attribute instance-attribute

mlp_input = Layer.mlp_input

layer_mid class-attribute instance-attribute

layer_mid = summed('post_attention_layernorm.inputs', description='The residual stream after the attention add: hidden_states + residual, [1, tokens, hidden_size]')

HIDDEN class-attribute instance-attribute

HIDDEN = (1, 'hidden_states')

RESIDUAL class-attribute instance-attribute

RESIDUAL = (2, 'residual')

skip_with

skip_with(hidden: Tensor) -> None

Skip this block, handing hidden ([1, tokens, hidden_size]) on as its residual stream.

Safe on a request that runs alone. The engine batches whatever is in flight into one step, and a skipped block has to answer for all of it; see nnsight's vLLM guide before skipping on a shared engine.

layer_input

layer_input(view: Tensor, raw: tuple) -> tuple

layer_output

layer_output(view: Tensor, raw: tuple) -> tuple

Layer

Layer(*args: Any, **kwargs: Any)

Bases: Layer

A vLLM block that is called with the residual stream and returns it.

Two things vary between the blocks that work this way, and a family states them: STREAM, where the stream sits in the block's call (GPT-2's block takes it alone, most take the positions first), and the base's returns_tuple, for a block that returns the stream with something beside it (Exaone4's and Cohere's return (hidden_states, residual) with the whole stream first, where a FusedLayer returns its two halves).

STREAM class-attribute instance-attribute

STREAM = 0

skip_with

skip_with(hidden: Tensor) -> None

Skip this block, handing hidden ([1, tokens, hidden_size]) on as its residual stream.

Safe on a request that runs alone. The engine batches whatever is in flight into one step, and a skipped block has to answer for all of it; see nnsight's vLLM guide before skipping on a shared engine.

layer_input

layer_input(value: Tensor) -> Residual

layer_output

layer_output(value: Tensor) -> Residual

attention_norm_output

attention_norm_output(value: Tensor) -> Residual

layer_mid

layer_mid(value: Tensor) -> Residual

mlp_norm_output

mlp_norm_output(value: Tensor) -> Residual

mlp_input

mlp_input(value: Tensor) -> Residual

Mlp

Mlp(*args: Any, **kwargs: Any)

Bases: Mlp

A vLLM feed-forward module: its contribution is its output.

The neurons are the down projection's input, as on transformers. On a plain MLP (GPT-2's GELU) that is also the activation's output, and it is read there for both: vLLM builds an activation by name once and shares the one module between every block, so act_fn's own output cannot say which block called it. A gated MLP is different on vLLM: its gate and up projections are one gate_up_proj and its act_fn (SiluAndMul, GeluAndMul) computes act(gate) * up in one kernel, so what it returns is already the neurons and act(gate) alone is never a tensor. There mlp_activation is unavailable (GATED) and mlp_neurons is act_fn's output. A mixture of experts has neither (ROUTED).

mlp_activation

mlp_activation(value: Tensor) -> Neurons

act(up_proj(x)) on a plain MLP, [1, tokens, intermediate_size]: read as the down projection's input, which it is.

mlp_neurons

mlp_neurons(value: Tensor) -> Neurons

The neurons' values the down projection sums, [1, tokens, intermediate_size]: act(gate) * up, which is act_fn's output on vLLM's fused gate, or the activation itself on a plain MLP.

mlp_output

mlp_output(value: Tensor) -> Residual

on_decode_step

on_decode_step(envoy: Envoy) -> str | None

DECODE_STEP when a read made now would be served a decode step of the request, else None.

A request's first visit to its attention layer is the prefill, every prompt token at once, and each later one a decode step of one token. The worker knows which visit a read would ask for before anything is read, so the value refuses there, by name. Outside a trace there is no step to ask about and the answer is the prefill's: support lists it available.

batched

batched(rows: Tensor, head_dim: int | None = None, heads_first: bool = False) -> Tensor

[tokens, ...] as a private [1, tokens, ...] copy; with head_dim, the last axis split into heads.

[tokens, num_heads * head_dim] (or [tokens, num_heads, head_dim], where a module keeps its heads apart) becomes [1, tokens, num_heads, head_dim], or [1, num_heads, tokens, head_dim] with heads_first.

on_transformers_backend

on_transformers_backend(envoy: Envoy) -> bool

Whether envoy's model runs on vLLM's transformers backend, where every activation carries the batch axis.

unbatched

unbatched(value: Tensor, rows: Tensor, name: str, head_dim: int | None = None, heads_first: bool = False) -> Tensor

What batched served, back as the [tokens, ...] the model holds, refusing another shape.

A written value is spliced into the step the engine is running, among other requests' rows. One of the wrong height would reach the next kernel as it is, where the mismatch can end the engine and every request in it, so it is refused here, in the block that wrote it.

argument

argument(inputs: tuple, index: int, name: str) -> Any

One argument of a call served as (args, kwargs), however the caller passed it; None when absent.

summed

summed(key: str, hidden: tuple = (0, 'x'), residual: tuple = (1, 'residual'), description: str | None = None) -> EProperty

The stream at a call that takes it in two halves, hidden + residual, [1, tokens, hidden_size].

A fused block hands its stream to the next norm as norm(hidden_states, residual), and the norm adds the two before it normalizes (in place): the stream is their sum, computed for the read. key is the call's inputs, hidden and residual where the halves sit in it, as (index, name). An edit goes back as a change to the hidden half, and a read that edits nothing hands the difference back as exactly zero; a call without the residual (a block's first norm) is its stream alone.

with_argument

with_argument(inputs: tuple, index: int, name: str, value: Any) -> tuple

inputs with that argument replaced, where the caller passed it.

Submodules