# xtrain 演进总览 — 按维度记录每次变化

每个里程碑（**T# 基建 phase** 或 **v# 训练 run**）在四个维度上分别改了什么、结果如何。
这是活文档：**每次新 run 收尾时追加一行/一段**。细节见各 `docs/runs/0N-*.md`、各 phase 设计文档、`docs/known-issues.md`。

四个维度：**算法**（autograd/优化器/精度/反向数学）· **模型架构**（dim/层/头/算子）· **Infra**（构建/显存/并行/吞吐）· **数据集**（语料/token/epoch/tokenizer）。

---

## 一、基建 phase（T1–T12）—— 主要动「算法」与「Infra」

| Phase | 维度 | 变化 | 结果 / 验证 |
|---|---|---|---|
| T1 | Infra | Rust↔CUDA FFI 构建链（build.rs+nvcc, `no_cuda` cfg），gitea↔dash5 流 | vector-add 跑通 |
| T2 | Infra | Tensor 抽象（dtype/shape/Storage, H↔D 拷贝）+ elementwise kernel | roundtrip 保真 |
| T3 | 算法 | 手写 tiled GEMM fwd/bwd + finite-diff 梯度检查 harness | fwd vs cuBLAS 1e-7；bwd vs finite-diff |
| T4 | 算法 | tape autograd 引擎 + 11 算子 backward（含梯度扇出累加）；attention 由 matmul+softmax 组合 | 每算子 finite-diff ≤2e-2 |
| T5 | 模型架构 | 组装 tiny decoder（RoPE+RMSNorm+SwiGLU）+ embedding/reshape/transpose 算子 | overfit 27/27 + PyTorch 对拍 B>1 |
| T6 | 算法 + 数据集 | 手写 AdamW + 训练 loop + LR sched + grad clip + checkpoint；gpt2 BPE + TinyStories | 真训出连贯英文 |
| T7 | Infra | cuBLAS matmul + GPU 端 AdamW/grad-norm + 去 per-op sync | **~3×**：2.7K→8.5K tok/s，零回归 |
| T8 | Infra | NCCL DDP（单进程 thread-per-GPU）+ 梯度 all-reduce | 多卡（当时弱扩展 ~1.4×） |
| T9 | 算法/模型架构 + Infra | **加 per-head QK-norm**（Qwen3 兼容）；safetensors 导出 | xserv 闭环：贪心**逐 token 一致** |
| T10 | 算法/Infra | **batched 多序列 forward**（linears flatten `[B·S,dim]` + fused batched SDPA + 每序列 RoPE） | **单卡 15–24×**；MFU 0.4%→14%（修 KI-1） |
| T11 | Infra | **device caching/pool allocator**（复用 op 输出显存，消 per-step cudaMalloc） | 单卡 2.3×；**8卡 461K tok/s** 近线性（修 KI-5） |
| T12 | 算法/Infra | **bf16 混合精度**（fp32 master，cuBLAS GemmEx，norm/softmax/CE 保 fp32） | dim768 OOM 解除，−29% 显存/+13% tok/s（修 KI-2） |

---

## 二、Scaling runs（v0–v7）—— 主要动「模型架构」与「数据集」

架构始终是 **Qwen3-style**（RoPE + RMSNorm + QK-norm + SwiGLU，gpt2 50257 词表），只放大 dim/层；其余维度逐版变化如下：

| ver | 模型架构（dim/层/头·hd · 核心/总参） | 数据集（语料 · 实训 token · epoch） | 算法/精度 | Infra（GPU · 吞吐） | 结果（val · 备注） |
|---|---|---|---|---|---|
| v0 | dim32/4L/2h · 41K/3.26M | TinyStories 3MB 切片 · ~0.72M · — | fp32 单序列 | 1 GPU | val 3.80（toy，不可用） |
| v1 | dim256/8L/8h · 8.4M/34M | TinyStories 全量 · 5.1M · 0.01ep | fp32 单序列 | 1 GPU · 3.3K | val 2.58 |
| v2 | dim384/12L/12h · 28M/67M | TinyStories · 37M · 0.08ep | fp32 单序列 | 4 GPU DDP · 3.6K | val 1.71（暴露 KI-1/弱扩展） |
| v3 | dim512/16L/16h · 67M/119M | TinyStories · 246M · 0.53ep | fp32 **batched(T10)** | 1 GPU · 26K | val 1.30 |
| v4 | dim768/18L/24h · 127M/205M | TinyStories · 721M · 1.54ep | fp32 batched | **8 GPU(T11)** · 145K | val 1.17（仍欠拟合） |
| v5 | dim768/18L（**同 v4**） | TinyStories · 2.49B · **5.33ep** | **bf16(T12)** | 8 GPU · 217K | val **1.11**：⚠️**TinyStories 饱和**（3.5×数据仅↓5%） |
| v6 | dim768/18L（同 v4/v5） | **FineWeb-edu** 真实网页 · 2.29B · 1.02ep | bf16 | 8 GPU · 218K | val **3.07**：⚠️**FineWeb 留出集，与 v0–v5 不可比**（真实网页熵高，~3.0 是预期）；判据=采样质量+transfer。第一版脱离 TinyStories，**语言种类质变**（小故事→真实说明文）；transfer→TinyStories val 2.75(v5 native 1.11)，纯通用数据对窄分布有代价；val 末步仍单调降=未饱和 |
| v7 | dim768/18L（同 v4/v5/v6） | **同 v6 的 FineWeb-edu 子集**（非新数据）· 3.28B · **1.45ep** | bf16 | 8 GPU · 218K | val **3.01**（与 v6 可比）：⚠️**同子集多 epoch 近天花板**——唯一变量=epoch(1.02→1.45)，多喂 ~1B token val 仅 ↓0.05 且 ~step44000 后走平、采样无质变。与 v5 的 TinyStories 数据量饱和同类（重复老数据边际薄）；真·更多数据要**新 shards** |

> 实训 token = steps×batch×seq（非数据集大小）。val 同一 1M-token TinyStories 留出集（v0–v5 可比；v6 起换 FineWeb-edu 留出集，分布不同、与 v0–v5 不可比；v6 与 v7 同一 FineWeb 留出集、彼此可比）。

---

## 三、各维度的累积演进（轴向看一条线怎么走的）

- **算法**：手写 autograd(tape)+扇出累加 → AdamW/LR-sched/grad-clip → +QK-norm(Qwen3) → batched forward → bf16 混合精度(fp32 master)。
- **模型架构**：固定 Qwen3-style；dim **32→256→384→512→768**；核心参数 **41K→127M**（总 3.26M→205M）。
- **Infra**：单卡 fp32 → cuBLAS/GPU-optim(T7) → NCCL DDP(T8) → batched forward(T10) → caching allocator(T11) → bf16(T12)。吞吐 **3.3K→217K tok/s**，MFU **0.4%→17%**（每次提升都对应一块 perf 基建，详见 known-issues + MFU 分析）。
- **数据集**：TinyStories 3MB 切片 → 全量 TinyStories（epoch 0.01→5.33，**至饱和**）→ **v6 毕业到 FineWeb-edu 真实网页**（2.255B 语料，1.02ep）→ **v7 同子集多 epoch（1.45ep，近顶）**。tokenizer 全程 gpt2 BPE（复用 xserv-tokenizer；v6 刻意不换 tokenizer 以隔离「数据来源」变量，KI-4 留后续版本）。
  - **v5→v6 数据轴的质变**：v0–v5 都吃合成幼儿故事（TinyStories，低熵、词汇受控），v5 证明同尺寸模型在它上面已饱和；v6 第一版换成**真实教育类网页文本**（FineWeb-edu），语言种类发生质变——采样从「只会写小故事」变成「能写历史/科学/说明文」。
  - ⚠️ **同子集多 epoch 也有天花板（v6→v7）**：v6 的 FineWeb val 才训 1.02ep、末步仍单调降，曾被读作「还没喂够」；v7 把**同一 2.255B 子集**喂到 1.45ep（多 ~1B token），FineWeb val 仅 ↓0.05（3.07→3.01）且 ~step44000 后走平、采样无质变 ⇒ **该子集在 dim768 已近天花板**。这与 v5 的 TinyStories 数据量饱和是**同一类现象**：**「重复喂老数据」边际都薄，无论是 v5 的同语料多 epoch 还是 v7 的同子集多 epoch**。真正抬天花板的是 v6「换更广的新语料」那一步——**杠杆在「更多样的新 token」，不在「同数据多读几遍」**。后续要继续降 val，必须补**新 FineWeb shards**（更多样、不重复），不是同子集加 epoch。
  - ⚠️ **val 可比性**：v0–v5 的 val 是同一 TinyStories 1M 留出集（彼此可比）；**v6 起换 FineWeb-edu 留出集，分布不同、val 不能和 v0–v5（~1.1）比大小**——真实网页熵高，~3.0 是预期而非回退；**v6 与 v7 同一 FineWeb 留出集、彼此可比**（3.07→3.01）。v6 的判据还有采样质量 + **transfer eval**（v6→TinyStories val 2.75 vs v5 native 1.11，量化「纯通用数据对窄分布的代价」）。

## 四、perf 杠杆台账（详见 [known-issues.md](known-issues.md)）

- **已修**：KI-1 单序列 launch-bound（T10）· KI-5 per-op cudaMalloc 串行（T11）· KI-2 bf16/OOM（T12）。
- **待办**：KI-3 激活重计算（放大到 dim1024+ 时）· KI-4 大词表小 vocab · process-per-GPU（要更高多卡线性时）。
- 两次「先 profile 再动手」证伪了错误的拟修复（KI-1「加大batch」、KI-5「分桶all-reduce」），避免了无效大改——profile-first。
