GizStack
View .mdOpen in ChatGPTOpen in Claude

gizml:npullm

Gemma 4 E2B's forward pass on an AMD NPU (XDNA 2), with the AIE kernels of FastFlowLM (the layer and lm_head xclbins, MIT runtime, binaries free to use unmodified). gizml:llm loads such a folder as a model like any other (its chat, sampling and serving); this module gives it the logits of the tokens it reads (Model.read). A token runs the 35 decoder layers as 35 runs of the layer kernel and then one run of the lm_head kernel; this module writes each run's control code (an AIE transaction) for the current context length, and the CPU does the embeddings and the rotary tables. The model folder holds config.json, tokenizer.json, model.q4nx (a safetensors file of 4.125-bit Q41 blocks, bf16 and q8_0 tensors) and xclbins/.

gizlang
import * as Npullm from "gizml:npullm";

Types

Shape

gizlang
type Shape = { d: i64; layers: i64; ffn: i64; pli: i64; heads: i64; kvHeads: i64; dh: i64; swaDh: i64; window: i64; period: i64; shared: i64; vocab: i64; padded: i64; softcap: f64; wide: bool; maxL: i64; }

The sizes of the model (config.json). A layer is global (full attention, head size dh) when (i + 1) is a multiple of period, else sliding-window (head size swaDh, the last window positions); the last shared layers reuse the cache of the last layer of their kind before them.

  • d: i64
  • layers: i64
  • ffn: i64
  • pli: i64
  • heads: i64
  • kvHeads: i64
  • dh: i64
  • swaDh: i64
  • window: i64
  • period: i64
  • shared: i64
  • vocab: i64
  • padded: i64
  • softcap: f64
  • wide: bool
  • maxL: i64

Model

gizlang
type Model = { shape: Shape; npu: Session; layer: Vec<Program>; head: Program; commands: Vec<Command>; x: Buffer; proj: Vec<Buffer>; rms: Vec<Buffer>; rope: Vec<Buffer>; kv: Vec<Buffer>; lmHead: Buffer; logits: Buffer; prompt: Pass; embed: Vec<Stored>; tokenizer: Tokenizer.Tokenizer; stops: Vec<i64>; length: i64; }

A loaded model: the NPU session, the programs of the two kernels (layer holds one for each of the four layer kinds), the buffers, the prompt pass, the embedding tensors (read from the file a row at a time), the tokenizer, and the context length so far.

  • shape: M28.Shape
  • npu: M14.Session
  • layer: Vec<M1.Program>
  • head: M1.Program
  • commands: Vec<M1.Command>
  • x: M1.Bo
  • proj: Vec<M1.Bo>
  • rms: Vec<M1.Bo>
  • rope: Vec<M1.Bo>
  • kv: Vec<M1.Bo>
  • lmHead: M1.Bo
  • logits: M1.Bo
  • prompt: M28.Pass
  • embed: Vec<gizlang_safetensors.Stored>
  • tokenizer: M34.Tokenizer
  • stops: Vec<i64>
  • length: i64

Mm

gizlang
type Mm = { m: i64; k: i64; n: i64; args: Vec<i64>; clamp: bool; }

A bf16 matrix-multiply kernel: C (M by N, row-major) = A (M by K, row-major) times B, whose columns come in groups of n, each group n by K, row-major. m, k and n are a core's tile; args are the kernel arguments of A, B and C; clamp says that the run-time parameters end with an output clamp.

  • m: i64
  • k: i64
  • n: i64
  • args: Vec<i64>
  • clamp: bool

Pass

gizlang
type Pass = { mm: Vec<Program>; dequant: Vec<Program>; attention: Vec<Program>; rows: i64; start: i64; stop: i64; hidden: Buffer; q: Buffer; k: Buffer; v: Buffer; y: Buffer; gate: Buffer; up: Buffer; hid: Buffer; pliDown: Buffer; pliGate: Buffer; pliHid: Buffer; w: Vec<Vec<Buffer>>; cache: Vec<Buffer>; pliDownW: Buffer; pliW: Vec<Buffer>; norms: Vec<bytes>; scales: Vec<f64>; pliNorm: bytes; }

The programs and buffers of the prompt pass. rows, start and stop are the geometry the row and attention codes have now. The buffers: the rows of the pass (hidden state, q, k, v, attention output, gate, up, their product, PLI down, gate and product), the bf16 projections of the current layer (q, k and v; o; gate; up; down), the prompt caches of a sliding-window and a global layer, and the bf16 PLI projections. The host copies of each layer's norms: input, post attention, pre and post MLP, q, k, post PLI; and its output scale.

  • mm: Vec<M1.Program>
  • dequant: Vec<M1.Program>
  • attention: Vec<M1.Program>
  • rows: i64
  • start: i64
  • stop: i64
  • hidden: M1.Bo
  • q: M1.Bo
  • k: M1.Bo
  • v: M1.Bo
  • y: M1.Bo
  • gate: M1.Bo
  • up: M1.Bo
  • hid: M1.Bo
  • pliDown: M1.Bo
  • pliGate: M1.Bo
  • pliHid: M1.Bo
  • w: Vec<Vec<M1.Bo>>
  • cache: Vec<M1.Bo>
  • pliDownW: M1.Bo
  • pliW: Vec<M1.Bo>
  • norms: Vec<bytes>
  • scales: Vec<f64>
  • pliNorm: bytes

Functions

shapeOf

gizlang
function shapeOf(config: Json.Json): Shape

The shape of the model whose config.json (the "text_config" part, or the whole) is config.

Effects: fail.

kindOf

gizlang
function kindOf(s: Shape, i: i64): i64

The kind of layer i: bit 0 global, bit 1 shared cache.

Effects: fail.

projOffsets

gizlang
function projOffsets(s: Shape, kind: i64): Vec<i64>

The byte offsets in the projection buffer of a layer of kind: q, k, v (none on a shared layer), o, up and gate, down, then the bf16 PLI down, gate and up projections; the last is the buffer's size.

Effects: fail.

ropeOffsets

gizlang
function ropeOffsets(s: Shape, kind: i64): Vec<i64>

The bf16 element offsets in the rope buffer of a layer of kind: cos and sin, q norm, k norm, PLI embedding, PLI norm, post-PLI norm, the layer scale; the last is the elements with the padding.

Effects: fail.

layerCode

gizlang
function layerCode(s: Shape, kind: i64, length: i64): bytes

The control code of a layer of kind that attends to length positions (the new one included).

Effects: fail.

headCode

gizlang
function headCode(s: Shape): bytes

The control code of the lm_head kernel: the final norm and the logit soft cap (softcap, as f32 bits) go to the 32 cores; each round the 8 shim tiles send the Q41 rows of 1024 tokens and take their logits back.

Effects: fail.

reordered

gizlang
function reordered(data: bytes, columns: i64, vertical: i64): bytes

The Q41 blocks of data (rows of blocks, columns / 256 blocks a row) in the order the kernels read them: each column of blocks of vertical rows of blocks together.

Effects: fail.

load

gizlang
function load(sys: System, folder: string): Model throws string

Loads the model in folder onto the first NPU of this host.

Effects: fail, io.

lmMm

gizlang
function lmMm(): Mm

The kernel of the language model's projections.

Effects: fail.

mmCode

gizlang
function mmCode(g: Mm, rows: i64, inputs: i64, outputs: i64, b: i64, act: i64): bytes

The control code of g over A of rows by inputs and an output of outputs columns, with B from element b of its buffer and activation act. The 8 shim tiles each take a group of B columns and their C; the even ones also take the rows of A, 4 by m at a time; each queue holds two descriptors (ping-pong).

Effects: fail.

dequantCode

gizlang
function dequantCode(offset: i64, inputs: i64, outputs: i64, band: i64): bytes

The control code of dequant.xclbin over the Q41 matrix at byte offset of the projection buffer (inputs columns, outputs rows): the bf16 matrix in groups of 128 rows, each 128 by inputs, row-major in pieces 512 wide (B of an Mm). band (0 none, 1 up, 2 gate) takes one matrix of the up and gate band, where they alternate every ROUND_ROWS rows. Each of the 8 shim tiles takes 128 rows a round.

Effects: fail.

attentionCode

gizlang
function attentionCode(s: Shape, global: bool, begin: i64, end: i64): bytes

The control code of an attention kernel (attn.xclbin for a global layer, swa.xclbin for a sliding-window one) for the query rows of positions begin to end (multiples of CHUNK_ROWS): y (argument 0) gets each head's output from q (argument 1, the rows of the pass), and the k and v of the positions before go in from the prompt cache (argument 2: k of maxL positions, then v). A global kernel works two heads at a time on 2 groups of 4 columns, a sliding one four heads on 4 groups of 2; each takes 128 query rows a round.

Effects: fail.

Methods

Model.step

gizlang
function Model.step(self: mut Model, sys: System, id: i64): Vec<f32> throws string

Runs token id at the next position and returns its logits, the vocabulary's.

Effects: fail, io.

Model.read

gizlang
function Model.read(self: mut Model, sys: System, at: i64, ids: Vec<i64>): Vec<f32> throws string

Reads ids from position at (the cache holds the tokens before it) and returns the logits after the last, the vocabulary's: passes of up to PASS_TOKENS tokens, then a rest of fewer than PASS_MIN tokens one at a time.

Effects: fail, io.

Model.pass

gizlang
function Model.pass(self: mut Model, sys: System, ids: Vec<i64>): Vec<f32> throws string

Runs the tokens ids (at most PASS_TOKENS) at the next positions in one pass and returns the logits of the last.

Effects: fail, io.