Repository navigation
0.2.0: t0 and Timestral, a shared forecaster interface, and batching - #2
Merged
Merged
Conversation
Port The Forecasting Company's t0 family from tfc-t0 0.6.0 as Tsfm.Forecasting.T0 (Apache-2.0): causal scaler, patch encoder, alternating time/group transformer with xPos rotary embedding, residual decoder and monotone quantile head. Each checkpoint's scaler convention is read from its config; t0-beta's differs from alpha's. T0Forecaster takes the TimesFM shape (ForecastJoint with known-future flags, Forecast over OHLCVA). Both now implement a shared IQuantileForecaster in the core package, so one call site drives either. Unlike TimesFM, any context length is accepted and up to 1024 steps are decoded in one pass. Verified stage by stage against the reference on both checkpoints, including the quickstart notebook's electricity-price and M4 examples. Weights are fetched at pinned, checksummed revisions; both exceed the nuget.org size limit, so neither is packaged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F1dTUhvq2UnFWdBmH7AA8G
IQuantileForecaster gains ForecastJointBatch and ForecastBatch over JointSeries / ReadOnlyMemory entries sharing a horizon, written [entry][step][quantile] into a caller-sized span. - t0 batches any entries in one pass, each its own attention group, shorter contexts left-padded and masked, cut into passes by MaxRowsPerPass. Checked against the reference in the parity harness. - TimesFM stacks same-shape entries on the model's batch axis. Single calls now run as a batch of one, bit-identical to 0.1.3. - KronosForecaster.InferBatch forecasts the final window of many series; Infer/InferPath share the generalised loop, bit-identical to 0.1.3. Also: clearer t0 weight installation (pinned, checksummed download commands; Load names them when files are missing), corrected wording on covariate-to-target information flow, and all packages move to 0.2.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F1dTUhvq2UnFWdBmH7AA8G
KronosForecaster.Seed decides each window's sampling stream from its anchor bar and a series key (KronosSeries.SeriesKey, or seriesKey: on Infer/InferPath). SamplingSeeds.AnchorTime, the default, keeps the current behaviour: series anchored on one bar share draws. PerSeries gives each key an independent stream; Salted derives a fresh, reproducible run from any policy. Batch invariance holds under all of them, and the default is bit-identical to before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F1dTUhvq2UnFWdBmH7AA8G
…mbedded Port mistralai/timestral 1.0.0 as Tsfm.Forecasting.Timestral (Apache-2.0): causal per-patch scaler, gated time/variate transformer with partial RoPE, Decoupled Horizon Forecasting decoder tokens and the monotone 21-quantile head. TimestralForecaster implements IQuantileForecaster, batches included, and applies the reference forecaster's defaults (symmetric averaging, non-negative clipping, advancing refine frame, quantile cap); the mirrored input rides in the same forward pass. Verified stage by stage against the reference on all four sizes, with and without the defaults, including the covariate path and the shared notebook examples. Timestral-5M and -28M ship in Tsfm.Forecasting.Timestral.Weights.*, embedded at pinned revisions whose SHA-256 the build checks. The weights are under Mistral's revenue-restricted Modified MIT licence, carried verbatim as the package licence file with acceptance required; 123M and 209M are fetched by script. Core gains IModelWeights for tokenizer-free checkpoints. Also updates the README byline as requested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F1dTUhvq2UnFWdBmH7AA8G
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F1dTUhvq2UnFWdBmH7AA8G
Mistral's Modified MIT licence is not MIT-compatible, so each Timestral weights package now declares <PackageLicenseFile>LICENSE.txt</> and packs its own LICENSE.txt at the package root: the Mistral licence verbatim with that package's pinned revision, then the MIT notice for the small loader class. The repository's MIT LICENSE is no longer packed into those two packages (PackRepositoryLicense=false), so they carry one licence, the right one. Every other package is unchanged. verify-packages.sh now checks the weights packages declare LICENSE.txt, carry no stray MIT LICENSE, and require licence acceptance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F1dTUhvq2UnFWdBmH7AA8G
Fetches the checkpoints the weights packages embed, packs every package into one directory (artifacts/ by default) after clearing stale packages, runs verify-packages.sh, and prints the upload order by dependency tier. Fails if a package is produced that the upload list does not name. Nothing is pushed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F1dTUhvq2UnFWdBmH7AA8G
Updated changelog to reflect version 0.2.0 release.
The batch tests asserted batched forecasts equal single ones bit for bit (TimesFM) or after rounding to fixed decimals (t0, Timestral). Neither holds across runners: a matmul over more rows need not reproduce one over fewer, and the macOS and some Linux runners take BLAS kernels whose last bit differs. Rounding to decimals made it worse — values 2e-6 apart failed whenever they straddled a rounding boundary, so the same commit passed in one run and failed in the next. Compare to a relative 1e-5 instead (~80 float32 ulps), and correct the README, which claimed batching was exact for TimesFM and Kronos. The CI failures were 6e-8 to 4e-6 apart; a stacking bug is orders larger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F1dTUhvq2UnFWdBmH7AA8G
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds two model families, a quantile-forecaster interface shared with TimesFM, batch forecasting for every model, and a host-chosen Kronos seeding policy. All packages move to 0.2.0.
Changes
t0 —
Tsfm.Forecasting.T0(new, Apache-2.0). t0-alpha and t0-beta, ported fromtfc-t00.6.0. Same call shape as TimesFM (ForecastJointwith known-future flags,Forecastover OHLCVA). Accepts any context length (left-padded and masked) and decodes up to 1024 steps per pass. Each checkpoint's scaler convention is read from itsconfig.json. No weights are packaged, because both checkpoints exceed nuget.org's 250 MB limit; the README has pinned, checksummed download commands.Timestral —
Tsfm.Forecasting.Timestral(new, Apache-2.0). Timestral 5M/28M/123M/209M, ported frommistralai/timestral1.0.0. Applies the reference forecaster's defaults (symmetric averaging, non-negative clipping, refine frame, quantile cap) so published numbers reproduce. The averaging's negated input runs in the same forward pass as the original rather than a second call, which makes the port faster than Python on CPU at every size (5M: 11 vs 19 ms; 209M: 138 vs 191 ms).Timestral weights —
.Weights.5M,.Weights.28M(new). Embedded at pinned revisions; the build checks each payload's SHA-256. They are under Mistral's Modified MIT licence, which is revenue-restricted (USD 20M/month), not open source:LICENSE.txt, set viaPackageLicenseFile, and must be accepted on install;LICENSEis not packed into these two packages.Shared interface and batching.
IQuantileForecaster(core) is implemented by TimesFM, t0 and Timestral.ForecastJointBatch/ForecastBatchtakeReadOnlyMemoryentries and write[entry][step][quantile]into a caller-sized span.KronosForecaster.InferBatchforecasts the final window of many instruments in one pass.IModelWeightsfor tokenizer-free checkpoints.Kronos seeding policy.
KronosForecaster.Seeddecides each window's random draws from its anchor bar and a series key. The defaultAnchorTimekeeps the 0.1.x behaviour;PerSeriesgives eachSeriesKeyits own stream;Saltedderives a fresh, reproducible run from either.Tooling.
scripts/pack.sh: fetches the weights, packs, verifies, and prints the upload order.Compatibility
KronosForecaster.Infer/InferPathgain a trailing optionalseriesKey. Callers' source is unchanged, but code compiled against 0.1.3 must be recompiled.Verification
tests/Tsfm.Forecasting.T0.Parity), both checkpoints: scaling and masks match exactly; layers within 6e-7 relative; forecasts within 5e-7. Includes the quickstart notebook's electricity-price and M4 examples.tests/Tsfm.Forecasting.Timestral.Parity), all four sizes, defaults on and off: every stage within 1.5e-6 relative, forecasts within 9e-7, including the covariate path and a mixed batch.dotnet pack+verify-packages.shpass for all 9 packages. Each package's licence was checked in its packed.nuspec.