Safe By Design AI

TSPulseForReconstruction

TSPulseForReconstruction at 8 layers and hidden size 24. One published checkpoint has this shape.

Implementing it

How to read this sheet: method.

No forward was recorded for this shape, so the block is read from the published configuration, the checkpoint's tensor names, and TSPulseForReconstruction in granite-tsfm v0.3.9 — not transcribed from a run.

Generated from granite-timeseries-tspulse-r1.

# Two views of one series in a single grid. The spectrum is an input
# here, not a post-processing step.

# 1. RevIN — and its affine is not the identity (`revin_affine: true`).
std = sqrt(max(variance, 1e-3))           # `minimum_scale: 0.001`, clamped,
                                          #   not added: the smallest scale
                                          #   is 0.0316, and above the clamp
                                          #   the constant does nothing.
                                          #   `sqrt(var + 1e-3)` would turn
                                          #   0.1000 into 0.1049 at var = 1e-2.
scaled = (series - mean) / std
scaled = scaled * affine_weight + affine_bias # learned scalars; the inverse
                                              # removes these before
                                              # undoing mean/std

# 2. The FFT is real and its halves are kept separately.
bins = rfft(scaled)                       # 512 samples -> 257 bins
bins = bins[:-1]                          # `fft_remove_component: last`
re, im_ = Re(bins), Im(bins)
re  /= (max(|re|)  + 1e-3)                # each half by its own max-abs;
im_ /= (max(|im_|) + 1e-3)                #   here the guard is added
spec = concat(re, im_)                    # end to end, not a magnitude

# 3. Two patchers. Time and spectrum do not share an embedding:
#    `time_encoding.patcher` and `fft_encoding.patcher` are distinct.
time = patch(scaled, 8) @ time_encoding.patcher.T   # 64 x 24
spec = patch(spec,   8) @ fft_encoding.patcher.T    # 64 x 24
grid = concat(time, spec, registers)      # 138 x 24; 10 registers,
                                          #   appended (TTM-R3 prepends)
grid = base_norm(flatten(grid))           # one LayerNorm over 138 * 24

h = encoder_mixers(grid)                  # 8 layers
h = decoder_mixers(h)                     # 2 layers

# 4. The forecast head reads the registers only.
y = register_mixers(h[-10:])              # 3 layers
y = layernorm(flatten(y))                 # 240
forecast = y @ forecast_mapping.W.T       # -> 16 samples
recon    = h[:64] @ time_head.W.T         # per patch 24 -> 8; 512 samples

forecast = invert_revin(forecast)

Sources, granite-tsfm v0.3.9: TSPulseLearnableMaskRevIN; get_fft, called with epsilon=minimum_scale from the backbone; the two encodings, register tokens and base_norm; the appended registers; the forecast mapping and head slicing.

Time and spectrum have separate trained patchers of the same shape, so reusing one for both still loads and still forecasts.

It does not consume magnitudes. The real and imaginary halves are normalised separately by their own maximum absolute value and laid end to end. A port that patches |rfft(x)| has thrown the phase away and halved the sequence.

The dropped bin is the last one, not DC (fft_remove_component: last). Dropping DC instead shifts every bin by one.

Two numerical guards, one constant, two different operations. RevIN clamps the variance — sqrt(max(var, 1e-3)) — and the spectrum normalisation adds to the maximum — re / (max|re| + 1e-3). Both matter exactly where a series is flat or nearly constant.

TSPulseForReconstruction.forward is stochastic. With mask_ratio: 0.7 the backbone builds a time masker, and this class calls the backbone without passing enable_masking, which defaults to true — so the input is masked at random in eval mode too, and two calls disagree.

Geometry

layers8
hidden size24
context window512 samples
forecast horizon16 samples
patch length8 samples
patch stride8 samples
patches128
decoder width24
feed-forward expansion2
input channels1
largest checkpoint1.1M

How this was checked

Status and evidence grade in the assessment (see what the grades mean):

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:

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

modelparameterscontext
granite-timeseries-tspulse-r11.1M—