Repository navigation
[AINode] Add TiRex-2 as a built-in forecasting model - #19273
Open
kotselidis wants to merge 1 commit into
Open
kotselidis wants to merge 1 commit into
kotselidis wants to merge 1 commit into
Conversation
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.
Description
This PR adds TiRex-2 (NXAI) to AINode's built-in forecasting models, next to
timer_xl,sundial,chronos2,moirai2,totoandmoment. TiRex-2 is an xLSTM time series foundation model with about 83M parameters. It forecasts nine quantiles (0.1 to 0.9), up to 320 steps ahead, for univariate and multivariate series, and it can use past-only and future-known covariates. The model is registered astirex2. AINode downloads its weights from the Hugging Face repositoryNX-AI/TiRex-2at startup, as it does for the other built-in models.Usage
Once the weights are downloaded,
SHOW MODELSliststirex2with model typetirex2, categorybuiltinand stateactive.Example: the input is 1024 points of
50 + 10·sin(2πt/24) + 0.01·t. The request is aTForecastReqwithoutputLength = 24, sent to AINode's inference manager on CPU with the published checkpoint. The response is 24 values (the median forecast). The first six:The mean absolute error is 0.112 over 24 steps and 0.126 over 96 steps. If
output_lengthis above the model's horizon, the request fails with a clear message:1599: TiRex-2 forecasts at most 320 steps, but output_length is 400.Model code
iotdb/ainode/core/model/tirex2/contains the inference model from NX-AI/tirex-2 0.5.0 (Apache License 2.0), in the same way aschronos2/contains the code from chronos-forecasting. The model code is unchanged except for these points:iotdb.ainode.core.model.tirex2package, and files carry the ASF header followed by NXAI's copyright notice.config.jsonmust be atorch.nnmodule, such astorch.nn.SiLU. Upstream imports any dotted path from the config.ForecastModelAPI, dataframe/GluonTS/fev adapters, plotting and the demo. Thenarwhalsdependency goes with them.TiRex-2's own loader replays the forward pass from CUDA graphs. This PR leaves CUDA graphs off (
use_cuda_graphs = False), so every forecast runs eagerly.As upstream does, TiRex-2 wraps its residual blocks, and FlexAttention where it is used, in
torch.compile. This PR keeps that. PyTorch compiles these blocks on the first forecast, so the first request after loading is slower. On CPU, compilation needs a C++ compiler on the AINode host. This was tested with PyTorch 2.14.1 on CPU, but not in the packaged AINode binary.AINode integration
modeling_tirex2.TiRex2ForPredictionis the model, loaded throughPyTorchModelHubMixin(hub_mixin_clsinModelInfo). AINode already supports this loading path. The transformersPreTrainedModelpath is not used, because the publishedmodel.safetensorsstores one weight per gate. TiRex-2'sload_state_dicthooks fuse those weights into the layout of its recurrent layers, and transformers' loader bypasses the hooks. The weights load withstrict=True, so a checkpoint with a missing or extra weight is rejected.pipeline_tirex2.TiRex2Pipelineturns each input into one TiRex-2 series. The targets of an input, shape(target_count, input_length), are forecast jointly. A covariate that appears only inpast_covariatesbecomes a past covariate. A covariate that also appears infuture_covariatesbecomes a known covariate, built from its past and future values. All inputs of a request run in one batch. The pipeline returns the 0.5 quantile.output_lengthmust be between 1 and 320. TiRex-2 has no autoregressive mode, so the pipeline rejects longer horizons instead of truncating them.Dependencies
There are no new dependencies. The model needs PyTorch, NumPy, safetensors and huggingface_hub, which AINode already pins. On Linux, the CUDA wheels of PyTorch include Triton. TiRex-2 0.5.0 replaced its earlier
flashrnnandmlstm_kernelsdependencies, and their CUDA toolkit requirement, with these Triton kernels.pyproject.toml,ainode.specandainode.xmlare unchanged.ainode.specalready collects every module underiotdb.ainode.core.Licences
TiRex-2's code and its published weights are both under the Apache License 2.0 (code licence, weights licence). The weights are downloaded at run time and are not part of the distribution. This PR adds TiRex-2 to
LICENSE,NOTICEand AINode'sNOTICE-binary, with the copyright line from TiRex-2's NOTICE file.NXAI's intended-use notice says the release is not intended for high-risk uses under the EU AI Act. The notice states that it does not change the licence.
Tests
tests/test_tirex2.py(unittest, CPU only, no downloads) uses a two-block TiRex-2 with random weights. The tests:TiRex2Pipeline, and check the output shapes for 1-D and 2-D targets and that the result is the model's median;output_lengthabove the horizon is rejected, and that the activation lookup is restricted.tirex2entry is added toAINodeTestUtils.BUILTIN_LTSM_MAP, soAINodeSharedClusterITlists, loads and forecasts with it on CPU and GPU, like the other built-in foundation models.This PR has:
for an unfamiliar reader.
for code coverage.
Key changed/added classes (or packages if there are too many classes) in this PR
iotdb/ainode/core/model/tirex2/(new): the TiRex-2 model,TiRex2ForPrediction,TiRex2Pipelineiotdb/ainode/core/model/model_info.py:tirex2entry inBUILTIN_HF_TRANSFORMERS_MODEL_MAPiotdb-core/ainode/tests/test_tirex2.py(new)integration-test/.../ainode/utils/AINodeTestUtils.java:tirex2inBUILTIN_LTSM_MAPLICENSE,NOTICE,iotdb-core/ainode/src/assembly/resources/NOTICE-binary