1. rustbpe 是什么 & 为什么选它

  • 定位:nanochat 内置的 Rust 实现 byte-level BPE 分词器;训练阶段用它以获得高性能与可控性;推理阶段通常切到 OpenAI tiktoken 以复用成熟高效实现。二者在编码方案上设计为可对齐与互通。(GitHub)
  • 算法结构正则预分词(regex splitting) 先做粗切,再在 UTF-8 字节级上做 BPE 合并学习(byte-level BPE),与 GPT 系常见做法一致:对多语种/符号/表情健壮,且能避免未知字符问题。(GitHub)
  • 代码位置rustbpe/ 为 Rust 库,经 maturin 编译为 Python 扩展;测试覆盖在仓库测试集中(例如 tokenizer 单测)。(GitHub)
  • 为何自研:作者在教程中指出,纯 Python 训练器(如教学用 minbpe)在规模化训练阶段偏慢,而 Hugging Face tokenizers 对初学者而言心智负担较高。rustbpe 追求“轻量 + 高性能 + 易改”的工程折中。(GitHub)

2. 从 0 到可用:构建、训练、评测

2.1 编译 Rust 模块(maturin)

# 安装 Rust(Linux/macOS)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"

# 在 nanochat 仓库根目录,将 rustbpe 构建成 Python 扩展
uv run maturin develop --release --manifest-path rustbpe/Cargo.toml
# 或者使用一次性调用
uvx maturin develop --release --manifest-path rustbpe/Cargo.toml

以上即官方推荐路径:先用 rustup 装好 toolchain,再调用 maturin 构建 Python 扩展。(GitHub)

2.2 准备训练语料分片

# 示例:下载 240 个数据分片(数量因模型/训练时长而异)
python -m nanochat.dataset -n 240

README/教程给出了分片数量的经验式:大致以“参数量 × 20 ≈ tokens,再 ×4.8 ≈ 字符数,除以 2.5e8 估算所需分片数”;分片太少会重复过同一数据,降低有效学习速度。(GitHub)

2.3 训练与评测

# 训练 tokenizer(默认约 20 亿字符,几乎“分钟级”完成)
python -m scripts.tok_train --max_chars=2000000000

# 评测 tokenizer(生成压缩率等报告)
python -m scripts.tok_eval

讨论区标准流程:默认 vocab_size=65536,压缩率目标约 4.8 chars/token。(huggingface.co)

3. 研究与调参:四个关键旋钮

大多通过 scripts.tok_train 的命令行或 Python wrapper 传入。

  1. vocab_size(默认 65,536)
  • 越大:序列更短、压缩率更高,但 embedding/softmax 变大、显存与计算也升高;
  • 越小:模型头更轻,但序列更长;
  • 建议以 65k 为基线,按业务/资源权衡到 32k/128k 做对照实验。(GitHub)
  1. 正则预分词(regex splitting)
  • 对中文连续字符、英文词干、URL、代码符号、数字等进行可控切段
  • 你可以设计 basiccode_math 两套正则,对中文/技术/代码/数学语料分别测试 chars/token 与下游任务效果。(GitHub)
  1. 特殊 token 预留
  • 聊天 schema(如 <|user|>, <|assistant|>)需保留成整体 token;
  • 预留太少→提示模板被拆碎;太多→浪费词位。建议少量保留并在对齐阶段验证效果。(GitHub)
  1. 训练字符量 --max_chars
  • 教程示例常用 2B chars 即可得到稳定的 merges 前列;
  • 可做 0.5B / 1B / 2B 的稳定性对照,观察前 1–2 万 merges 是否基本不变。(huggingface.co)

4. 读词表与 merges:如何做 sanity check

  • Top-N merges 稳定性:增大 --max_chars 后,前 10k merges 排名是否稳定;
  • 不同类别的粒度:中文是否被过度拆成单字?代码/数学多字符运算符是否能成块?
  • 压缩率(chars/token)~4.8 是官方示例的通用目标值;可分别对中文、代码、数学域单独测一遍,避免“总体掩盖局部”。(huggingface.co)

Hugging Face 的相关说明也提到:nanochat 的 tokenizer 训练目标是快速拿到 ~4.8 的压缩率并与推理侧 tiktoken 对齐。(huggingface.co)

5. 与主训练/推理的衔接(tiktoken 兼容)

  • 训练期:用 rustbpe 做 encode/decode 与 merges 学习,优点是快、轻、可控
  • 推理期:通常切换到 tiktoken,以复用高度优化的工业实现(CUDA/并发/缓存等),在相同编码方案下保持互通。这正是 nanochat 的工程权衡:训练可黑盒少、推理走工业件。(GitHub)

6. 做个“科学”的 tokenizer 基准

建议三类基准,每项都输出表格与简图:

  1. 压缩率
  • 指标:chars/token(越大越好)或 bytes/token;
  • 语料:通用 + 中文 + 代码 + 数学(按你的真实分布抽样);
  • 对比:GPT-2(50257)、rustbpe(32k/65k/128k)、HF tokenizers、SentencePiece。(huggingface.co)
  1. 速度
  • 指标:encode throughput(chars/s 或 MB/s)训练时间
  • 设备:相同机器上 重复 3 次,取中位数
  • 经验:Rust 训练/编码通常较纯 Python 实现获得数量级提升;社区常见说法是自研 Rust tokenizer 能带来明显倍数加速,但以你的实测为准。(Crates.io)
  1. 一致性
  • 指标:与参考实现或固定 merges/vocab 的 encode/decode 完全等价
  • 方法:准备含中文/emoji/URL/代码/数学式的小集合,双向核对;
  • 建议把用例纳入仓库的 tokenizer 单测中,保障迭代稳定性。(GitHub)

7. 最小可用样例(Python 端)

前提:已按上文用 maturin 构建完成 rustbpe

from pathlib import Path
import json, importlib

rustbpe = importlib.import_module("rustbpe")

# 1) 加载产物(路径按你的训练输出)
vocab = json.loads(Path("artifacts/tokenizer/vocab.json").read_text(encoding="utf-8"))
merges = [l.strip() for l in Path("artifacts/tokenizer/merges.txt").read_text(encoding="utf-8").splitlines()
          if l.strip() and not l.startswith("#")]

# 2) 构建分词器(以仓库暴露的 Python API 为准)
tok = rustbpe.Tokenizer(vocab=vocab, merges=merges)

# 3) 编码/解码与压缩率
s = "北京大学和清华大学在人工智能与数据科学领域合作。a*b + c^2 = ? https://example.com"
ids = tok.encode(s)
print("ids:", ids)
print("recovered:", tok.decode(ids))
print("chars/token:", round(len(s) / max(1, len(ids)), 3))

若做端到端实验,直接使用 python -m scripts.tok_trainpython -m scripts.tok_eval;参数与输出路径以当前仓库脚本为准。(GitHub)

8. 可扩展的研究题

  1. 更友好的中文粒度:用正则保证中文连续片段优先成块,减少“单字化”碎片;对 32k/65k/128k 分别在新闻/论坛/古诗上对比 chars/token 与微调后的下游指标。
  2. 代码/数学优化:为 **, ->, ::, <=, >=, !=, <=>, 0x 等多字符运算符保留 merges,观察代码语料的压缩率改变。
  3. 域自适应 merges:用混合采样(如 50% 通用 + 50% 你的业务语料)训练 tokenizer;验证 top-10k merges 是否更贴合域特征,并连通到 SFT/RL 的端到端指标。
  4. 特殊 token 策略:对比把 <|user|>/<|assistant|> 放入 merges 与强制保留之间的效果差异(提示长度与对齐稳定性)。
  5. tiktoken 等价性:在固定 merges/vocab 情况下,验证 rustbpe 与 tiktoken 的完全一致(必要时编写小转换器)。(GitHub)

9. 与 nanochat 主流水线的衔接

  • 顺序先编译 rustbpedataset -n ... 拉分片 → tok_train 训练 → tok_eval 验证 → 进入 BASE / MID / SFT(必要时 RL)。(GitHub)
  • 更大档位(d26/d32):需要更多分片与更稳定的 merges;同时注意mid 阶段学习率计划近期有过方向写反的已知问题,SFT 与 RL 脚本是正确的——请更新到修复版本或在本地修正 lrm = 1 - progress。(GitHub)
  • 线上演示:作者给出了 d32 的在线托管示例与 $1000 档端到端设计(约 41.6 小时@8×H100),可对照你本地 tokenizer 配置与端到端评测。(GitHub)

10. 常见坑与排错

  • 工具链/编译:先装 rustup,再用 maturin;Windows 需 VS C++ Build Tools。(GitHub)
  • 分片不足:遵循 README 的分片估算,不足会导致过多重复遍历、学习变慢。(GitHub)
  • mid 学习率问题:若你 fork 了早期版本,务必核对 Issue #68 的修正说明。(GitHub)
  • 横向工具对比:若要与 HF tokenizers 做对照,可参考其 crates 页面/版本信息,确保同等设置下比较。(Crates.io)

11. 延伸阅读

  • nanochat 仓库(README、脚本、测试):端到端流水线、tokenizer 位置与单测入口。(GitHub)
  • 教程:Introducing nanochat(环境、开销、tok_train/tok_eval、分片经验式)。(GitHub)
  • Tokenizer 训练/评测帖(HF 空间):示例命令与结果展示(包含 tok_train / tok_eval)。(huggingface.co)
  • d32/$1000 档讨论:端到端设计与在线托管更新。(GitHub)
  • minbpe 教学仓库:与 rustbpe 思路对照、理解 BPE 合并本质。(huggingface.co)
  • 媒体解读(MarkTechPost 等):项目定位与成本视角。(MarkTechPost)
  • Rust 生态 tokenizer(横向参考):HF tokenizersrust_tokenizers。(Crates.io)
Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐