Inference for small transformer models over sequences of frames, in float32 on the standard library alone, with no cgo. It runs any model a trainer writes in its weight file; RipModel, which hears recordings for Stapes, is one.
- Convolutions, windowed attention with ALiBi, and towers of named output heads
- Runs over a sequence of any length
- A versioned, checksummed weight file, checked whole on load, that a trainer in any language can write
- Deterministic on a platform, and one model runs on any number of goroutines at once
The forward pass
A model reads a sequence of frames and writes one output vector per frame. It runs models and does not train them: any trainer that writes the weight file can produce one, and a PyTorch copy of the model in Stapes does.
Frames
channels planes of inputs features, any length of sequenceInput
- Convolutionsoptional the frames as an image, frames by features: odd kernels, GELU, a max-pool over features
- Input layer linear, from a frame’s features to the width
Stack
- Block× layers
pre-norm, each half added back to its input
- Attention per head, the frames within the window, ALiBi-biased by distance
- Feed-forward to the FFN width and back, exact GELU
- Norm, output layer or towers: stacks of their own over the one input layer, each computing the next heads
Out
- One vector a frame
its named heads end to end:
Slice(out, "pitch") - Raw scores no activation: the caller applies its own
- Attention
- Each frame attends to the frames within a window on either side. Head a of h, counted from 0, subtracts s·|i − j| from each score, with s = 2−8(a+1)/h (ALiBi), in place of position embeddings, so a model runs over a sequence of any length.
- Shape
- Optional convolutions over the frames as an image, then the input layer, then one stack of blocks for every head, or towers, stacks of their own over the one input layer, each computing the next heads.
- Numerics
- float32 throughout, but for a norm's mean and variance, the GELU and the softmax's exponential, taken in float64 and rounded. It matches PyTorch to float32 rounding, within 10−5 on real recordings.
- Concurrency
- A loaded model is read-only: one serves any number of goroutines at once.
How far three of eight heads reach around a frame, by their ALiBi bias alone, over a window of 64: the first stays within a few frames, the last weighs the whole window nearly evenly. Nothing past the window counts.
The weight file
One file is one model: the magic VIFT, the format’s version, the shape, every
tensor by name with its dimensions and float32 data, and an FNV-1a checksum
over all of it. Load reads the whole file and refuses it if the checksum,
the version, the shape or any tensor’s name or size disagree. The format’s
document states the computation exactly, enough for a trainer in any language
to write a model that means the same here.
m, err := transformer.Load(f)
out := m.Forward(frames) // one vector per frame
pitch := m.Slice(out[t], "pitch") // a named head's scores