FlowStateModel
FlowStateModel at 6 layers and hidden size 512. One published checkpoint has this shape.
Implementing it
One forward, written out, per checkpoint whose arithmetic actually differs. A shape groups checkpoints by class, depth, width and layer stack — none of which decides an activation, a rope base or a routing rule — so where the members of this shape disagree there is a block each, and each names the checkpoint it was generated from.
No forward was recorded for this shape, so there is no pass above to compare it against — this block is what the published configuration says the arithmetic is, not a transcript of a run. Where the configuration does not say, the line says that instead of guessing.
The names are the ones the published checkpoint uses where a name is published, and canonical otherwise. A checkpoint loader may store them differently — fusing a gate/up pair into one matrix, or splitting one published projection in two — and those are that loader's names, not the model's. Everything spelled here is what the download contains.
Generated from granite-timeseries-flowstate-r1.
# Continuous time, and the only model here whose state is complex.
# No patching anywhere in this file.
# 1. The normalisation is causal and it scales the value only.
# Running statistics per position: mu[k] is the mean of 0..k, and the
# deviation's k-th term uses the mean as of its own position. Reading
# it as a variance about one mean is the obvious misreading and gives
# a different normalisation at every position but the last.
v = last 2048 samples
mu, sd = running_mean_std(v) # per position, not per window
z = (v - mu) / sd
u = stack(z, missing_flag) # the flag is appended after
# scaling, not scaled with it
h = u @ W_in.T # Linear 2 -> 512
# 2. 6 S5 layers, each a scan and then a gated MLP.
for layer in layers:
L = -exp(layer.log_Lambda_real) + 1j * layer.Lambda_imag
Lbar = exp(L * exp(layer.log_Delta) * scale) # discretised per step
Bbar = (Lbar - 1) / L * layer.B_tilde # zero-order hold
x = 0
for k in 0 .. T-1:
x = Lbar * x + Bbar * h[k] # the scan is the
# reference's FFT
# convolution, exactly
y = C_r . Re(x) + C_i . (-Im(x)) + D * h
# ^ note the sign: the real part of a complex product written
# out, not a sum of two magnitudes.
y = selu(y)
y = y * sigmoid(y @ layer.gate.T) # self-gate
h = layernorm(h + y, layer.norm) # residual, then norm
# 3. Only the last hidden state reaches the decoder, and only the last
# layer may skip positions — the ones before it must produce the whole
# sequence because the next layer reads all of it.
c = h[-1] @ W_dec.T # -> 9 x 256 Legendre coefficients,
# one curve per quantile 0.1 .. 0.9
q = legendre_basis(256) @ c # evaluated at 24 points
q = q * sd[-1] + mu[-1] # denormalised first, with the
# last position's statistics
# The point forecast is derived from the nine, in three steps, and is
# not row 4. Reading the median directly is the same shape and a
# different number wherever the curves cross.
q = sort(q) # per horizon point, across the 9
q = resample(q, at=[0.1 .. 0.9]) # linear interpolation over the
# sorted sample; the identity
# when nothing crossed
w = normalise(0.5 - |0.5 - p|) # triangular over the levels,
# not uniform — a plain mean
# of the nine is a different
# number
point = sum(q * w)
forecast = [point, *q] # 10 rows out of 9 predicted
The decoder predicts 9 curves and the model returns 10 rows. decoder.lin is feat -> dec_dim * n_quantile and there is no tenth set of coefficients: the point forecast is built from the nine by sorting them at each horizon point, resampling at the same nine probabilities, and taking a triangular weighted sum (w = 0.5 - |0.5 - p|, normalised). The sort is not cosmetic — it is why the shipped model does this instead of indexing the median row, and it is the identity only while the curves stay ordered. A uniform average of the nine is a different number everywhere.
The denormalisation happens before the sort, so the curves are ordered in the output's units rather than the model's. With a single positive scale the two orders agree; the shipped code does it in this one.
The normalisation is causal and it scales the value only. Position k is scaled by the statistics of 0..k, the missing flag is appended after scaling, and the forecast is denormalised with the last position's statistics. A window-wide mean — what every other forecaster here uses — runs and is a different model.
The input is [value, missing] pairs, so the projection into the state is Linear(2, width). A port that feeds bare values has the wrong input width and, if it pads instead, tells the model every sample is present.
The diagonal scan is exactly the reference's FFT convolution, not an approximation: for a diagonal system the kernel after its flip is h[j] = Lbar^j, and a causal convolution with that kernel is the closed form of the recurrence. No FFT is needed to reproduce it.
Geometry
| layers | 6 |
| hidden size | 512 |
| context window | 2,048 samples |
| forecast horizon | 24 samples |
| state width | 512 |
| decoder width | 256 |
| quantile levels | 9 |
| largest checkpoint | 9.1M |
How this was checked
implemented, evidence grade class, per the assessment: the architecture class is implemented; nothing specific to this checkpoint was measured. The implementation meant here and below is an unpublished independent inference implementation by the author.
What stands behind the block above, beyond the published configuration it is read from:
- a checkpoint loader, which is where published tensor names are read
- an independent reference implementation of this architecture in Python, driving the published modelling code — an executable statement of what the model should compute, written against the publication rather than against any one implementation of it
Where an independent implementation and the published configuration disagree, the configuration is what this page reports and the disagreement is what it says.
Checkpoints with this architecture
| model | parameters | context |
|---|---|---|
granite-timeseries-flowstate-r1 | 9.1M | — |