跳至主要内容

效能與記憶體

TinyLoop 有多種 runtime 模式,不同模式的數字不能互相直接套用。本頁目的就是讓 benchmark 主張保持嚴謹。

Benchmark 形狀很重要

目前公開 benchmark 數字指的是:

  • seq_len=128
  • loops=8
  • 不物化 logits
  • H100 驗證環境

不要把這些數字泛化到:

  • 任意序列長度
  • tokenizer-backed 服務工作負載
  • batched decode 吞吐

目前 benchmark 狀態

路徑結果解讀
預設低位元 benchmark30.48 ms主低位元 runtime 路徑
FP16-body benchmark2.82 ms更快,但 VRAM 顯著更高
完整 prefill attention0.143 ms -> 0.087 ms較安全 tiled prefill kernel 對比參考路徑

FP16 body cache — 407M INT4 上 prefill 快 30-65×

2026-04-17 於 H100 / 407M INT4 / L=8 實測(開啟 TINYLOOP_EXPERIMENTAL_FP16_BODY=1):

phaseINT4 scalar(預設)FP16 body + cuBLAS TCspeedup
prefill seq=128183 ms2.8 ms65×
prefill seq=256357 ms5.2 ms69×
prefill seq=512712 ms13.8 ms51×
prefill seq=10241431 ms47.5 ms30×
128-token decode1241 ms514 ms2.4×

權重 VRAM 放大約 2.9×(407M:216 → 619 MB)。輸出在幾個 token 後與 INT4 scalar 路徑分歧,是 FP32 vs FP16 tensor-core 累加器 rounding 差異, 不是正確性 bug。

KV cache INT8 — 同 VRAM 下 2× context

2026-04-17 於 H100 / 407M INT4 / L=8 實測(開啟 TINYLOOP_KV_INT8=1)。 per-token per-head 對稱 INT8 量化,每 (token, head) 一個 FP16 scale:

指標FP16 KVINT8 KV差異
KV 記憶體(max_seq=2048, 10 layers)167.8 MB85.2 MB−49.2%
同 VRAM 下有效 context2048 tok4032 tok+97%
decode 時間 seq=2562652 ms2748 ms+3.6%
decode 時間 seq=102415262 ms16653 ms+9.1%
decode 時間 seq=204842668 ms48462 ms+13.6%

Greedy 輸出前 ~40 tokens 完全相同,之後會隨著 rounding 累積而分歧 — 兩邊都是量化模型的合法取樣。可與 TINYLOOP_EXPERIMENTAL_FP16_BODY=1 疊加。剩餘的 decode regression 來自 per-element int8→float 轉換,要 再進一步需要 Hopper 上的 INT8 tensor cores(目前未排期)。

Cross-iteration stochastic rounding — 在 L ≥ 16 贏過 naïve INT4

Looped transformer 每次 forward 都把同一個 weight 用 L 次,這是唯一 可以做 per-iteration stochastic rounding 抵銷 quantization bias 的 regime。§16.9 出三個操作點:

變種儲存成本slope407M PPL vs naïve INT4
naïve INT4(預設)4 bits/weight+1.00± 0(baseline)
INT4 + 1-bit sign-of-frac+25%+0.80+2.18 at L=16(gap 縮小 46%)
INT4 + 4-bit signed fracloop block +100%(整模型約 +15%)+0.50−0.32 at L=16, −0.67 at L=32

1-bit 便宜版只縮 gap 但沒贏 naïve。4-bit frac 版在 L=16 跟 L=32 實測 贏 naïve INT4,符合 paper §O.2 Bernoulli oracle simulation 的方向。

Runtime 開啟:先用 tools/tinyloop_add_sign_bit.py 升級 .tinyloop 檔,然後 TINYLOOP_CROSS_ITER_ROUND=1:

python3 tools/tinyloop_add_sign_bit.py \
model_int4.tinyloop model_int4_v5.tinyloop \
--from-pt model.pt --loop-only --frac-bits 4

--loop-only 只在 loop block 加 sign-bit / frac channel(pre-blocks、 embed、head 保持 plain INT4 — 每 iteration 加 noise 對這些只跑一次 的權重反而傷質)。

Prefix cache — 10-user 同 prefix 吞吐量 3.03×

2026-04-17 於 H100 / 407M INT4 / L=8 透過 tests/bench_prefix_cache.py 實測:

後端prefixNNO_CACHESHAREDspeedup
INT4 scalar(預設)500 tok1012 847 ms5 415 ms2.37×
INT4 scalar(預設)1024 tok1023 852 ms8 329 ms2.86×
INT4 scalar(預設)1024 tok50104 605 ms34 531 ms3.03×
FP16 body + TC1024 tok105 123 ms4 732 ms1.08×

論文主張(「prefix cache 得以乘上 L」)的前提是 prefill 為 compute-bound。 INT4-scalar body 下看到完整 2.4-3.0× 增益;tensor-core 路徑下 prefill 本身已經夠快,prefix 共享只貢獻 5-8%。

主要 runtime 開關

TINYLOOP_EXPERIMENTAL_FP16_BODY=1

作用:

  • 在載入時將 transformer-body 權重反量化為常駐 FP16 cache
  • body GEMM 走 FP16/cuBLAS

取捨:

  • 更快
  • 需要更多 VRAM

TINYLOOP_DISABLE_FLASH2_PREFILL=1

作用:

  • 停用較新的、較安全 tiled prefill attention 路徑
  • 強制回到參考 prefill kernel

適用於:

  • 與舊路徑做 parity 比較
  • 隔離 prefill attention 變更影響

TINYLOOP_DISABLE_KV_CACHE=1

作用:

  • 關閉 cached generation
  • 強制 uncached 參考生成路徑

適用於:

  • 執行 parity 檢查
  • 偵錯 decode 行為

TINYLOOP_CUDA_PROFILE=1

作用:

  • benchmark 期間輸出分段時間

適用於:

  • 找出主導耗時階段
  • 判斷加速來源是 prefill、MLP、attention 還是 logits

記憶體組成

TinyLoop runtime 記憶體占用大致為:

  1. 權重
  2. 常駐 buffer
  3. 可選 cache(如 FP16 body cache)
  4. 隨序列增長的 KV cache

目前重要記憶體控制桿:

  • max_seq_len
  • cache_window
  • 預設低位元路徑 vs FP16 body cache 模式

Sliding-Window Cache

cache_window 控制 decode 歷史在 KV cache 中保留多少。

語義:

  • 0:完整快取
  • >0:只保留最後 W 個快取 token

適用於:

  • 不需要長上下文保留
  • 有界 KV 記憶體比完整歷史更重要

Prefix Cache 重用

Prefix cache 是針對重複共享 prompt 的記憶體與延遲策略。

有幫助的情境:

  • 多請求共享共同前綴
  • 想攤提前綴 prefill 成本

它不能取代 batching 或 paged attention。

如何負責任地發布數字

發布 TinyLoop 數字時請附上:

  • GPU 型號
  • loop 次數
  • 序列長度
  • 是否物化 logits
  • 是否啟用 KV cache
  • 是否啟用 TINYLOOP_EXPERIMENTAL_FP16_BODY=1
  • 是否啟用較新的 tiled prefill attention 路徑

沒有這些上下文,數字很容易被誤讀。