【免费下载链接】parameter-golf
Train the smallest LM you can that fits in 16MB. Best model wins!
本指南以 parameter-golf 仓库records/track_10min_16mb/2026-04-22_SP8192_CaseOps_GatedAttn_QuantGate_Loop45_PhasedTTT_MLPClip12这一提交为蓝本,完整讲解其核心创新——MLP 权重的 GPTQ 逐行 σ 裁剪参数mlp_clip_sigmas从 10.0 重调至 12.0——如何在不改动架构、不触碰任何其他超参的前提下,把 5-seed 平均 val_bpb 从基线的 1.06549 压到 1.06453。读完本文,你将掌握:int6 GPTQ 校准中裁剪宽度与量化网格之间的偏差/方差权衡、phased TTT 的 score-first 评估协议、Gated Attention 与 Quant Gate 的实现细节,以及该提交完整的 5-seed 复现命令与数据准备流程。
提交概览:一个"一行改动"的量化再调优
该提交的元信息位于 submission.json,基线成绩为:
- val_bpb 1.06453(5-seed 均值,std 0.00068)
- val_loss 2.32958 nats/token(std 0.00148)
- Artifact 约 15.98 MB(5 个种子全部低于 16,000,000 字节上限)
- 运行环境:8×H100 80GB SXM,PyTorch 2.9.1+cu128,训练 600s / 评估 600s 双预算,Phased TTT
与基线 PR #1736(records/track_10min_16mb/2026-04-19_SP8192_CaseOps_GatedAttn_QuantGate_Loop45_PhasedTTT)相比,唯一的代码改动只有一行——train_gpt.py中mlp_clip_sigmas的默认值由 10.0 改为 12.0:
# Base submission: mlp_clip_sigmas=10.0 (aggressive — clips MLP rows with large outlier columns) # This submission: mlp_clip_sigmas=12.0 (preserves tail mass of MLP weight distribution) mlp_clip_sigmas = float(os.environ.get("MLP_CLIP_SIGMAS", 12.0))对应源码位于 train_gpt.py。注意该行同时保留了MLP_CLIP_SIGMAS环境变量覆盖通道,意味着无需改代码即可实验其他裁剪宽度。
核心创新:MLP GPTQ 离群值裁剪的偏差/方差权衡
int6 量化网格的构造原理
在gptq_mixed_quantize(train_gpt.py)中,量化路径按张量名分派裁剪参数:
if "tok_emb" in name: cs = h.embed_clip_sigmas elif ".mlp." in name: cs = h.mlp_clip_sigmas # ← 本次改动的落点 elif ".attn." in name: cs = h.attn_clip_sigmas else: cs = h.matrix_clip_sigmas随后调用gptq_quantize_weight(train_gpt.py)完成逐行量化。其网格构建的关键一行是:
row_std = W_orig.std(dim=1) s = (clip_sigmas * row_std / clip_range).clamp_min(1e-10).to(torch.float16)即:每个权重行的量化步长s = clip_sigmas × row_std / clip_range。clip_range = 2^(bits-1) - 1,在 int6 下为 31。因此clip_sigmas直接决定了均匀量化网格的覆盖范围——σ 裁剪越宽(数值越大),步长越大、网格越粗,但能保留权重分布尾部的离群列。
为什么 12.0 优于 10.0
README 给出的机制解释是:在MLP 4× 宽度、int6的设定下,逐行 σ 裁剪是对权重分布尾部的偏差/方差权衡:
- 10σ(激进裁剪):网格更细、低幅度权重量化误差更小,但会把训练后 MLP 权重中携带不成比例有效信号的离群列裁掉;
- 12σ(宽松裁剪):网格略粗,但保留了尾部离群列——这些列在 4× 宽度 MLP 里恰恰承载了大部分有效信号。
README 特别指出,10σ 是在早期更窄 MLP、更浅模型的栈上标定的,在 PR #1530 → PR #1626 → PR #1736 系列把模型迁移到11 层 / MLP 4× / Loop4-5几何结构后从未重新调过——这正是本次重调的动机。
实验结果:7-seed 与 5-seed 双重验证
核心成绩表(phased TTT)
| Seed | Steps | Pre-TTT BPB | Post-TTT BPB | TTT gain | TTT time | Artifact (bytes) |
|---|---|---|---|---|---|---|
| 314 | 4872 | 1.07591 | 1.06357 | -0.01234 | 400.7s | 15,979,114 |
| 2025 | 4869 | 1.07649 | 1.06413 | -0.01236 | 394.7s | 15,977,203 |
| 777 | 4866 | 1.07701 | 1.06467 | -0.01234 | 394.6s | 15,971,178 |
| 1 | 4869 | 1.07750 | 1.06510 | -0.01240 | 391.2s | 15,979,182 |
| 1337 | 4864 | 1.07752 | 1.06517 | -0.01235 | 390.2s | 15,971,129 |
| Mean | 4868 | 1.07688 | 1.06453 | -0.01236 | 394.3s | 15,975,561 |
| Std | 0.00070 | 0.00068 | 4.2s | 4,101 |
补充诊断表
| Seed | Post-EMA BPB (pre-quant) | Quantized BPB (no TTT) | Post-TTT BPB | val_loss (nats) | Train time | Eval time |
|---|---|---|---|---|---|---|
| 314 | 1.06637 | 1.07591 | 1.06357 | 2.32748 | 596.09s | 400.7s |
| 2025 | 1.06701 | 1.07649 | 1.06413 | 2.32871 | 596.14s | 394.7s |
| 777 | 1.06762 | 1.07701 | 1.06467 | 2.32989 | 596.07s | 394.6s |
| 1 | 1.06807 | 1.07750 | 1.06510 | 2.33083 | 596.06s | 391.2s |
| 1337 | 1.06802 | 1.07752 | 1.06517 | 2.33098 | 596.06s | 390.2s |
解读:诊断表把误差来源拆成了三段——Post-EMA(未量化)、Quantized(量化后、无 TTT)、Post-TTT(量化 + TTT 后)。可以看到 pre-TTT 的量化后 BPB 1.07591–1.07752,而 TTT 阶段贡献了约 -0.0124 BPB 的提升,最终全部 5 个种子同时满足 600s 训练预算、600s 评估预算与 16,000,000 字节十进制 artifact 上限,且 5-seed std 0.00068 BPB 远低于 0.005-nat 的显著性门槛。
7-seed 完整披露
README 还披露了额外的 9999、7 两个种子(同train_gpt.py、MLP_CLIP_SIGMAS=12.0):
| Seed | val_bpb | val_loss |
|---|---|---|
| 314 | 1.06357 | 2.32748 |
| 2025 | 1.06413 | 2.32871 |
| 777 | 1.06467 | 2.32989 |
| 1 | 1.06510 | 2.33083 |
| 1337 | 1.06517 | 2.33098 |
| 9999 | 1.06534 | 2.33136 |
| 7 | 1.06541 | 2.33150 |
7-seed 均值为 1.06477(std 0.00069),5 个最低种子的均值为 1.06453。两种口径下都显著优于基线 PR #1736(3-seed 均值 1.06549),差距 0.00096 BPB ≈ 0.00249 nats/token,约为 sp8192 赛道 0.005-nat 记录门槛(≈0.00194 BPB)的 1.2 倍。
相对基线的完整变更清单
| Component | PR #1736 base | This submission |
|---|---|---|
| Tokenizer | SP8192 + CaseOps | same |
| BPB accounting | per-token byte sidecar | same |
| Attention out-gate | learned scalar per head, init_std=0.005 | same |
| Attention quant-gate | enabled | same |
| Depth recurrence | Loop4-5 | same |
| TTT | 3-phase SGD score-first on 2000-doc prefix | same |
MATRIX_CLIP_SIGMAS | 12.85 | 12.85 |
ATTN_CLIP_SIGMAS | 13.0 | 13.0 |
EMBED_BITS | 7 | 7 |
MLP_CLIP_SIGMAS | 10.0 | 12.0 |
净效果:5-seed 均值-0.00096 BPB / -0.00210 val_loss(nats/token),对比 PR #1736 的 1.06549 / 2.33168。
架构基线(与 PR #1736 完全一致)
| Item | Value |
|---|---|
| num_layers | 11 |
| model_dim | 512 |
| num_heads / num_kv_heads | 8 / 4 |
| mlp_mult | 4.0 |
| rope_base / rope_dims | 10000 / 16 |
| logit_softcap | 30.0 |
| loop_start / loop_end | 3 / 5 (NUM_LOOPS=2) |
| parallel_start_layer | 8 |
| eval_seq_len / eval_stride | 2048 / 64 |
| matrix_bits / embed_bits | 6 / 7 |
| compressor | brotli |
关键组件源码走读
Gated Attention(Qwen,NeurIPS 2025 Best Paper,arXiv:2505.06708):在CausalSelfAttention.forward(train_gpt.py)中,对 SDPA 输出、out_proj之前施加逐头 sigmoid 门:
if self.gated_attn: x_c = x.contiguous() g = torch.sigmoid(F.linear(x_c, self.attn_gate_w.to(x.dtype))) y = y * g[..., None]门权重attn_gate_w形状为(num_heads, dim) = (8, 512),以gated_attn_init_std=0.005近零初始化(源码默认 0.01,本提交通过环境变量收紧),初始 g≈0.5 会减半注意力输出,由逐块的attn_scale(初始 1.0)在训练中补偿。参数名含attn_gate子串,因此被CONTROL_TENSOR_NAME_PATTERNS(train_gpt.py)路由到标量 AdamW 优化组。
Quant Gate(int8-per-row):门张量只有 4096 个参数,按numel<=65536原本会走 fp16 passthrough;本提交通过GATED_ATTN_QUANT_GATE=1将其导向专门的_quantize_gate_int8_row(train_gpt.py)对称 int8 逐行量化:
row_max = W.abs().amax(dim=1).clamp_min(1e-10) s = (row_max / 127.0).to(torch.float16) q = torch.clamp(torch.round(W / sf), -127, 127).to(torch.int8)每头一个 fp16 scale(共 8 个),存储减半、BPB 影响可忽略,且无需 Hessian(门权重不在collect_hessians()中)。分派逻辑在 train_gpt.py。
Phased TTT 评估路径:eval_val_ttt_phased(train_gpt.py)首先用_find_docs(train_gpt.py)按BOS_ID=1切分文档,然后取前PHASED_TTT_PREFIX_DOCS=2000个文档、按PHASED_TTT_NUM_PHASES=3划分阶段边界。每个 chunk 先以当前 LoRA 前向打分(forward_ttt_train),在torch.no_grad()下累加 loss/byte/token 计数,然后才对 chunk 内 token 做 LoRA SGD 更新(needs_train分支,train_gpt.py)。每到达一个阶段边界,就暂停并调用train_val_ttt_global_sgd_distributed(train_gpt.py)对已打分文档做全局 SGD 微调(cosine 退火学习率、跨 rank all-reduce 梯度平均),随后重置可复用 LoRA(reusable_lora.reset())防止跨文档泄漏。
BPB 字节预算:启用CASEOPS_ENABLED=1时,评估用fineweb_val_bytes_*.bin逐 token 字节 sidecar 作为权威原始字节预算(train_gpt.py),最终由_loss_bpb_from_sums(train_gpt.py)按val_bpb = val_loss / ln(2) × (token_count / byte_sum)计算。
规则合规性检查
该提交逐条通过了竞赛规则验证:
- Artifact ≤ 16,000,000 字节(十进制):5 个种子全部 ≤ 15,979,182 字节(约 21 KB 余量);
- train_time ≤ 600s:全部 596.06–596.14s(
stopping_early: wallclock_cap触发,见 train_gpt.py); - total_eval_time ≤ 600s:全部 390.2–400.7s;
- Issue #1017 因果依赖:phased TTT 在每个 chunk 打分之后才更新逐文档 LoRA,任何位置 t 的预测都不依赖 y_t 或 >t 的位置;
- Issue #1017 完整归一化分布:每个位置都在完整 8192-token softmax 上计算 CE,无 x_t 相关的 Σ 截断;
- Issue #1017 score-before-update:TTT 路径快照更新前的逐 chunk logits 并在 adapter SGD 之前打分,
reusable_lora.reset()防止跨文档泄漏; - Issue #1017 单次从左到右扫描:评估以滑动 stride 64 做单遍左到右推理,无 rescore/selection;
- Section V 字节级 BPB:基于变换前原始 UTF-8 字节打分,无硬编码 bytes/token;
- 训练不接触验证数据:训练仅用
fineweb_train_*.bin;TTT prefix(前 2000 个 val 文档)与基线 PR #1736 使用同一切片并遵循 score-first 协议; - CaseOps 双射性:
decode_lossless_caps_v2(encode_lossless_caps_v2(x)) == x对所有测试串成立,可在 lossless_caps.py 中验证; - 评估期间无外部网络:tokenizer + 变换 + CaseOps SentencePiece 模型随文件夹自带;
- 可复现性:相对 PR #1736 的唯一代码改动即那行默认值;除 MLP_CLIP_SIGMAS 变为隐式默认外,Run Command 的环境变量覆盖与基线完全一致。
环境依赖与一次性数据准备
安装要求
# Python >= 3.12 required (minified f-strings use PEP 701 nested same-type quotes). pip install torch --index-url https://download.pytorch.org/whl/cu128 pip install flash-attn-interface sentencepiece triton numpy注意 Python ≥ 3.12 的硬性要求来自 PEP 701 嵌套同类型引号在压缩 f-string 中的使用。
数据构建(只需运行一次)
提交自带训练好的 CaseOps SentencePiece 模型(tokenizers/fineweb_8192_bpe_lossless_caps_caseops_v1_reserved.model)与双射变换模块(lossless_caps.py)。训练/验证 shard 与字节 sidecar 从规范 FineWeb-10B 文档流重建:
# 1. 确保 docs_selected.jsonl 存在(仓库标准设置步骤)。 python3 ../../data/download_hf_docs_and_tokenize.py # 或指向已有文件 # 2. 构建 CaseOps 变换后的 shard + val 字节 sidecar。 python3 prepare_caseops_data.py \ --docs ./fineweb10B_raw/docs_selected.jsonl \ --out ./data/datasets/fineweb10B_sp8192_caseops/datasets \ --sp ./tokenizers/fineweb_8192_bpe_lossless_caps_caseops_v1_reserved.model输出布局(CASEOPS_ENABLED=1时train_gpt.py期望的目录结构):
data/datasets/fineweb10B_sp8192_caseops/datasets/ tokenizers/fineweb_8192_bpe_lossless_caps_caseops_v1_reserved.model datasets/fineweb10B_sp8192_lossless_caps_caseops_v1_reserved/ fineweb_train_000000.bin ... fineweb_val_000000.bin fineweb_val_bytes_000000.bin复现健全性检查(步骤 2 之后)
每个 shard 的每个文档开头必须包含BOS_ID=1——train_gpt.py的 phased TTT 评估路径_find_docs依赖它。快速检查第一个 val shard:
python3 -c " import numpy as np d = np.fromfile('data/datasets/fineweb10B_sp8192_caseops/datasets/datasets/fineweb10B_sp8192_lossless_caps_caseops_v1_reserved/fineweb_val_000000.bin', dtype=np.uint16) # First 256 uint16 slots are the shard header; tokens start after. tokens = d[512:] bos_count = int((tokens == 1).sum()) print(f'BOS markers in val shard: {bos_count} (must be > 0)') assert bos_count > 0, 'prepare_caseops_data.py is broken — re-run with BOS prepend' "如果bos_count == 0,说明 prep 脚本过期——需要从本文件夹拉取最新 prepare_caseops_data.py(SP tokenizer 为特殊 token + CaseOps 算子保留 ID 0–7,prep 脚本必须显式给每个文档前插BOS_ID=1;评估路径_find_docs对缺失 BOS 标记没有回退)。
5-seed 复现运行命令
for SEED in 314 2025 777 1 1337; do NCCL_NET=Socket \ DATA_DIR=./data \ CASEOPS_ENABLED=1 \ PHASED_TTT_PREFIX_DOCS=2000 PHASED_TTT_NUM_PHASES=3 \ MATRIX_CLIP_SIGMAS=12.85 ATTN_CLIP_SIGMAS=13.0 \ EMBED_BITS=7 EMBED_CLIP_SIGMAS=15.0 \ MATRIX_LR=0.026 \ GPTQ_RESERVE_SECONDS=4 GPTQ_CALIBRATION_BATCHES=16 \ GATED_ATTN_ENABLED=1 GATED_ATTN_INIT_STD=0.005 GATED_ATTN_QUANT_GATE=1 \ SEED=$SEED \ torchrun --standalone --nproc_per_node=8 train_gpt.py \ > train_seed${SEED}.log 2>&1 done注意:MLP_CLIP_SIGMAS不在环境中设置——它取train_gpt.py里的新默认值 12.0。GPTQ_RESERVE_SECONDS=4意味着训练主循环会预留 4 秒给 GPTQ 校准(见 train_gpt.py),GATED_ATTN_INIT_STD=0.005覆盖源码默认 0.01。日志会打印全部超参与mlp_clip_sigmas: 12.0(可在train_seed*.log第 57 行确认)。
技术谱系与演进脉络
该提交是 modded-nanogpt 系实验栈的连续迭代产物:
- PR #549— 原始 modded-nanogpt 栈(Keller Jordan);
- PR #1019(merged)— 字节级 BPB SentencePiece 记账(
piece.encode); - PR #1394(merged)— SP8192 + 多阶段 score-first TTT 基线;
- PR #1530— Loop4-5 深度循环 + parallel residual 起始层 8(samacqua);
- PR #1626(已提交)— GPTQ 修剪 + 多阶段 SGD + 自适应裁剪;
- PR #1736(已提交)— CaseOps + gated attention + quant-gate + phased TTT,本提交的基线;
- 本次提交— MLP GPTQ 离群值裁剪的一行重调(10.0 → 12.0)。
包含文件清单
train_gpt.py— 训练脚本(131,887 字节,相对 PR #1736 仅一行默认值差异);submission.json— 元数据(5-seed 结果 + 7-seed 披露);README.md— 本说明文档;train_seed314.log/train_seed2025.log/train_seed777.log/train_seed1.log/train_seed1337.log— 5-seed 运行日志;tokenizers/fineweb_8192_bpe_lossless_caps_caseops_v1_reserved.model— CaseOps SentencePiece 模型(366.5 KB);lossless_caps.py— 双射 CaseOps 变换(prepare_caseops_data.py使用);prepare_caseops_data.py— 一次性数据准备:通过 CaseOps 对 FineWeb 分词并输出逐 token 字节 sidecar。
实践要点总结:在 int6 均匀量化网格中,clip_sigmas不是越大越好也不是越小越好——它是量化精度与离群值保留之间的连续权衡,且最优值会随模型几何(层数、MLP 宽度、深度循环结构)漂移。当架构栈发生重大变化后,重新标定每个权重组(embed / MLP / attn / matrix)的裁剪宽度,可能是比堆叠新模块更划算的"免费"收益。
【免费下载链接】parameter-golf
Train the smallest LM you can that fits in 16MB. Best model wins!
相关推荐
parameter-golf 记录拆解:Int6 量化 ×3 倍 MLP × SmearGate 的 16MB 极限压缩语言模型(val_bpb 1.1458)
parameter golf 记录拆解:Int6 量化 ×3 倍 MLP × SmearGate 的 16MB 极限压缩语言模型(val_bpb 1.1458)
Parameter Golf 实战:10L Int5-MLP + BigramHash(10240) + SWA(0.4) 如何在 16MB 内逼近 1.14 val_bpb
Parameter Golf 实战:10L Int5 MLP + BigramHash 10240 + SWA 0.4 如何在 16MB 内逼近 1.14 va
parameter-golf 16MB 赛道记录解析:Parallel Residuals 与 Mini Depth Recurrence 以 1.1063 BPB 刷新 SOTA
parameter golf 16MB 赛道记录解析:Parallel Residuals 与 Mini Depth Recurrence 以 1.1063 B
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考