wrhhh/NeoQuasar-Kronos-Tokenizer-base-NPU
模型介绍
文件和版本
Pull Requests
讨论
分析

NeoQuasar/Kronos-Tokenizer-base NPU

#NPU

Model Introduction

Model: NeoQuasar/Kronos-Tokenizer-base (https://huggingface.co/NeoQuasar/Kronos-Tokenizer-base)
Revision: local snapshot 2026-08-20, config d_in=6 d_model=256 n_heads=4 ff_dim=512 n_enc_layers=4 n_dec_layers=4 s1_bits=10 s2_bits=10 group_size=4
Type: Time-Series Tokenizer for financial K-line (OHLCV + amount) – hierarchical discrete tokenization via BSQuantizer (Binary Spherical Quantization) with Transformer encoder/decoder. Part of Kronos family (Kronos-small/base use this tokenizer, context 512).
Weight: model.safetensors 15.8 MB, FP32, no remote code required.
License: MIT
Original paper: https://arxiv.org/abs/2508.02739 Kronos: A Foundation Model for the Language of Financial Markets
Task routed: Tokenization self-supervised reconstruction (time-series). Tokenizer-only checkpoint is a component of Kronos forecasting pipeline; this adaptation demonstrates encode (6-dim continuous -> s1/s2 discrete tokens 2x10 bits) and decode (tokens -> 6-dim reconstruction) on Ascend NPU.
Architecture: embed(d_in->d_model) -> 3x TransformerBlock encoder -> quant_embed(256->20) -> BSQuantizer (20 dims -> s1 10 bits + s2 10 bits, vocab each 1024) -> post_quant_embed -> 3x TransformerBlock decoder -> head -> reconstruction (s1-only pre and full).

Data Contract

Input contract:

  • Shape: [batch, seq_len, 6] where 6 = [open, high, low, close, volume, amount] (volume/amount optional but filled if missing)
  • DType: float32
  • Range: normalized (mean/std per series) clipped to [-5, 5] (KronosPredictor clip=5)
  • Sequence: seq 32 in demo (max_context 512 for base), batch 2 in validation, batch 2 seq 128 in benchmark.
  • Columns fixed order: open, high, low, close, volume, amount
  • Missing values: not allowed (predictor raises if NaN)
  • No column shuffling; dtype preserved.

Synthetic demo data: seed 42, torch.randn *0.5, shape [2,32,6], mean 0.025 std 0.49, mimics normalized K-line after standardization. Real data would be loaded from CSV with columns open/high/low/close/volume/amount and timestamps for temporal embeddings (KronosPredictor.calc_time_stamps). This submission uses synthetic for CI but code supports df DataFrame path.

Output contract:

  • Encode: s1_ids, s2_ids each [batch, seq_len] int64 0..1023 (vocab 1024)
  • Decode: recon [batch, seq_len, 6] float32, finite, reconstructed K-line in normalized space.
  • Forward: (z_pre, z) both [B,T,6], bsq_loss scalar, quantized [B,T,20].

Preprocessing saved: no extra scaler file needed; predictor does per-series mean/std and clip. Example: x = (x - mean)/ (std+1e-5); x = clip(x, -5,5).

Environment

  • NPU: Ascend910_9362 x2, npu-smi 25.5.5, CANN 8.5.1 at /usr/local/Ascend/cann-8.5.1
  • Python 3.11.14, torch 2.9.0+cpu, torch_npu 2.9.0.post1, transformers 4.57.6, einops 0.8.2, numpy 1.26.4, pandas 3.0.2, safetensors 0.6.2, huggingface_hub 0.33.1
  • Device explicitly npu:0 via torch.device("npu:0") and .to(device) for model+tensor; no CPU fallback (fails if npu unavailable).
  • Model loaded from local snapshot /tmp/models/Kronos-Tokenizer-base else snapshot_download via HF_ENDPOINT https://hf-mirror.com.

Installation

pip install -r requirements.txt
# ensure CANN toolkit at /usr/local/Ascend/cann-8.5.1 is sourced
# weights: auto-downloaded on first run, or pre-download:
python -c "from huggingface_hub import snapshot_download; snapshot_download('NeoQuasar/Kronos-Tokenizer-base', local_dir='/tmp/models/Kronos-Tokenizer-base')"

NPU Inference

Default command (uses synthetic K-line, runs on npu:0):

python inference.py

What it does: loads tokenizer to npu:0, creates batch 2 seq 32 dim6 normalized input, encode to s1/s2 tokens (half=True), decode to reconstruction, forward full, prints device, shapes, sample tokens/recon, timings with torch.npu.synchronize(), CPU-NPU diff, and status.

Expected output snippet:

device: npu:0
model param device: npu:0
input shape: [2,32,6]
encode done: s1 shape [2, 32] s2 shape [2, 32] s1 sample [643,483,473,347,275]
decode done: reconstructed shape [2, 32, 6] reconstructed sample [1.0793,0.4287,0.6702,-0.6551,-0.3674,-0.3132]
forward done: z shape [2, 32, 6] bsq_loss -0.061378
CPU-NPU max_abs_error recon: 0.00000167 mean: 0.00000022
NPU inference SUCCESS

For real CSV:

import pandas as pd
df = pd.read_csv("your_klines.csv", parse_dates=["timestamps"])
# df must contain open,high,low,close,volume,amount
# see KronosPredictor.predict example in original README

Real Results

Run python inference.py on Ascend910_9362 npu:0:

  • Input: batch 2 seq 32 din 6, seed 42, normalized clipped
  • Encode: s1 batch0 first5 [643,483,473,347,275] s2 [704,450,963,995,994]
  • Decode recon batch0 t0 [1.0793, 0.4287, 0.6702, -0.6551, -0.3674, -0.3132] (FP32)
  • Forward z shape [2,32,6] bsq_loss -0.061378
  • Finite: True max 1.3992 min -1.4275
  • Timings: encode 3.45ms decode 6.37ms total 9.82ms forward 52.29ms (including quantize, after 2 warmups)
  • Device checks: param npu:0, input npu:0, output npu:0, quantized npu:0

Consistency

Same weights, same input, same dtype (float32), same half=True, eval mode.

python scripts/compare_outputs.py --cpu cpu_recon.npy --npu npu_recon.npy --task regression --atol 1e-4 --rtol 1e-3
  • Recon: cpu_shape [2,32,6] npu_shape [2,32,6] finite True max_abs_error 1.6689e-06 mean 2.24e-07 passed True
  • Forward z: same error 1.66e-06 passed True
  • Threshold: FP32 atol 1e-4 rtol 1e-3 justified (NPU bfloat16 accumulation would need looser, but this model stays FP32 and matches within 2e-06).
  • No CPU fallback: model and tensors explicitly on npu:0, verified via next(model.parameters()).device == npu:0 and output.device == npu:0.

Performance

Measured with torch.npu.synchronize() before/after, after 3 warmups, 10 timed runs, batch 2 seq 128 din 6 dtype float32 device npu:0:

  • First warmup (compile): 234.76ms (includes graph compile / RoPE cache)
  • Stable runs 2-3: 3.40ms 3.32ms (encode only 3.33ms)
  • 10-run encode+decode: avg 6.45ms min 6.03ms max 9.77ms p50 6.08ms p90 6.51ms p95 8.14ms
  • Throughput: windows/s 309.87 rows/s 39662.74 (batch*seq / avg time, preprocessing not counted)
  • Single forward (encode+decode pipeline) ~6ms; full forward (with BSQ loss) ~52ms.
  • Peak HBM: ~3107 MB idle -> no OOM; model 16 MB weights + activations.
  • Preprocessing (normalize/clip) not included in timing (as noted).

Evidence

Three xterm.js evidence PNGs generated from real logs via scripts/render_xterm_evidence.mjs --style raw (logs redacted of tokens/paths). They show workflow, device calls, and model result. Prompt is fixed atomgit@pod-a94f8701860f4700b161b00e290de466:~$ as display label only.

  • agent workflow
  • npu device call
  • model result

Images are rendered from logs/workflow.log, logs/device.log, logs/inference.log with UTC timestamps and exit_code 0, via xterm.js raw style (dark bg, white mono).

Limitations

  • Tokenizer-only checkpoint is not a full forecasting model; by itself it only does lossy compression/reconstruction, not future prediction. Full Kronos forecasting requires pairing with Kronos-small/base/large (24M-102M params) and autoregressive KronosPredictor (see original examples). This repo therefore demonstrates NPU tokenization correctly but does not claim standalone price forecasting.
  • Input must be normalized per-series; raw price scales need mean/std.
  • Max context 512 for base tokenizer; longer sequences truncated in predictor.
  • FP32 only; FP16/BF16 not validated here (would need larger atol).
  • Synthetic demo data, not live market data; smoke consistency on 2x32 window, not full benchmark (MAE/RMSE would need labeled forecast horizon).
  • Requires Ascend NPU with CANN 8.5.1 and torch_npu; CPU fallback fails.