[{"data":1,"prerenderedAt":110},["ShallowReactive",2],{"articles":3,"article:ai\u002Ftokenizer":37},{"articles":4},[5,9,13,17,21,25,29,33],{"slug":6,"title":7,"description":8},"demo\u002Ftypst-syntax","Typst 语法样板","用于验证博客 Typst 子集的样板：标题、段落、列表、代码块、表格和网格。",{"slug":10,"title":11,"description":12},"ai\u002Ftokenizer","Tokenizer 定义与实现","Tokenizer 的学习笔记：定义、基本概念与实现。",{"slug":14,"title":15,"description":16},"code\u002Fjavascript\u002Fnpm-pnpm","Node.js 包管理：从单个包到 Workspace","一份面向初学者的 npm 与 pnpm 学习笔记。",{"slug":18,"title":19,"description":20},"code\u002Frust\u002Fcargo","Cargo：从单个包到 Workspace","一份面向初学者的 Cargo 学习笔记。",{"slug":22,"title":23,"description":24},"notes\u002Fopensuse","OpenSUSE 折腾指南","得益于OpenSUSE的Yast，安装过程可以说是相当的舒服，全部图形化操作，是我在安装过许多Linux发行版中，最方便最舒服的。这里就不详细写出安装步骤了（其实是我没有记录过程），但会提供官方文档。",{"slug":26,"title":27,"description":28},"notes\u002Fwin-deepin-dualboot","Windows + Deepin 双系统的安装与使用","说实话我受够了Windows的环境搭建，想要精简就极度繁琐，想要方便就得用宇宙IDE，占十几二十多GB存储。因此，Linux就是最好的选择，除非你需要写Win或Mac的软件等特定情况。",{"slug":30,"title":31,"description":32},"notes\u002Fpicgo-smms","Obsidian 或 Typora + Picgo + smms 实现图片自动上传",">typora写作是很舒服，但是到了图片上传我简直太难了。上一篇博客我说我图床用的是imgchr，现在我屈服了，玩博客用imgchr简直是魔鬼好吧，图片上传完了，居然是乱序上传，导致我很难改图片地址。",{"slug":34,"title":35,"description":36},"notes\u002Fhexo-blog","github + hexo博客搭建教程","托更了很久，我一点不好意思都没有手动滑稽，我想应该没有人等着我的教程的吧。之所以这时才做这教程，是因为我准备开启新项目了，如果还不填坑的话，坑就越来越多，然后就不想填了。为了避免这种情况，所以我决定先",{"slug":10,"title":11,"description":12,"authors":38,"keywords":40,"date":44,"updated":45,"visible":46,"headings":47,"bodyHtml":108,"plainText":109},[39],"sikongjueluo",[41,42,43],"tokenizer","bpe","llm","2026-09-11",null,true,[48,51,54,57,61,64,67,70,73,76,79,82,84,87,89,92,94,97,100,102,105],{"level":49,"text":11,"id":50},2,"tokenizer-定义与实现",{"level":52,"text":53,"id":53},3,"基本概念",{"level":52,"text":55,"id":56},"为什么需要 Tokenizer","为什么需要-tokenizer",{"level":58,"text":59,"id":60},4,"字符 \u002F Byte 级","字符-byte-级",{"level":58,"text":62,"id":63},"Word 级","word-级",{"level":52,"text":65,"id":66},"Tokenizer 如何产生","tokenizer-如何产生",{"level":52,"text":68,"id":69},"Tokenizer 基本算法","tokenizer-基本算法",{"level":58,"text":71,"id":72},"BPE（Byte Pair Encoding）","bpe-byte-pair-encoding",{"level":58,"text":74,"id":75},"Unigram","unigram",{"level":58,"text":77,"id":78},"WordPiece","wordpiece",{"level":52,"text":80,"id":81},"Tokenizer 的设计","tokenizer-的设计",{"level":58,"text":83,"id":83},"训练语料",{"level":58,"text":85,"id":86},"Vocabulary Size","vocabulary-size",{"level":58,"text":88,"id":88},"评价指标",{"level":52,"text":90,"id":91},"Tokenizer 的局限","tokenizer-的局限",{"level":52,"text":93,"id":93},"未来研究方向",{"level":58,"text":95,"id":96},"Learnable Tokenizer","learnable-tokenizer",{"level":58,"text":98,"id":99},"无固定 Tokenizer","无固定-tokenizer",{"level":58,"text":101,"id":101},"层次化计算",{"level":58,"text":103,"id":104},"输出与 Diffusion","输出与-diffusion",{"level":52,"text":106,"id":107},"从 Tokenizer 到 Latent Thought","从-tokenizer-到-latent-thought","\u003Ch3 id=\"基本概念\">基本概念\u003C\u002Fh3>\u003Cp>Tokenizer 是连接\u003Cstrong>原始文本\u003C\u002Fstrong>与\u003Cstrong>LLM 数值输入\u003C\u002Fstrong>的编码系统，其基本任务是：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">文本\n→ Token 序列\n→ Token ID 序列\n→ LLM\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>例如：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">\"unbelievable\"\n→ [\"un\", \"believ\", \"able\"]\n→ [412, 8271, 539]\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>一个完整的 Tokenizer 通常包含：\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cstrong>Vocabulary\u003C\u002Fstrong>：\u003Ccode>Token ↔ ID\u003C\u002Fcode> 的映射；\u003C\u002Fli>\u003Cli>\u003Cstrong>Tokenization Rules\u003C\u002Fstrong>：文本如何被切分为 Token；\u003C\u002Fli>\u003Cli>\u003Cstrong>Normalization\u003C\u002Fstrong>：Unicode、空格等文本规范化规则；\u003C\u002Fli>\u003Cli>\u003Cstrong>Special Tokens\u003C\u002Fstrong>：如 \u003Ccode>&lt;BOS&gt;\u003C\u002Fcode>、\u003Ccode>&lt;EOS&gt;\u003C\u002Fcode>、\u003Ccode>&lt;PAD&gt;\u003C\u002Fcode>；\u003C\u002Fli>\u003Cli>\u003Cstrong>Decoder\u003C\u002Fstrong>：Token 序列如何恢复为文本。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>因此，Tokenizer 并不只是一个映射表。\u003Ccode>tokenizer.json\u003C\u002Fcode> 只是将这些规则和数据序列化保存下来。\u003C\u002Fp>\u003Ch3 id=\"为什么需要-tokenizer\">为什么需要 Tokenizer\u003C\u002Fh3>\u003Cp>LLM 不能直接处理字符串，只能处理数值向量，因此首先需要把文本转换为离散 ID。\u003C\u002Fp>\u003Cp>最直接的两种粒度都有明显问题。\u003C\u002Fp>\u003Ch4 id=\"字符-byte-级\">字符 \u002F Byte 级\u003C\u002Fh4>\u003Cp>例如：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">unbelievable\n→ u n b e l i e v a b l e\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>优点：\u003C\u002Fp>\u003Cul>\u003Cli>词表很小；\u003C\u002Fli>\u003Cli>可以表示任意文本；\u003C\u002Fli>\u003Cli>几乎不存在 OOV（未知词）问题。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>缺点：\u003C\u002Fp>\u003Cul>\u003Cli>序列很长；\u003C\u002Fli>\u003Cli>LLM 需要进行更多次计算。\u003C\u002Fli>\u003C\u002Ful>\u003Ch4 id=\"word-级\">Word 级\u003C\u002Fh4>\u003Cp>例如：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">unbelievable\n→ [unbelievable]\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>优点：\u003C\u002Fp>\u003Cul>\u003Cli>序列较短。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>缺点：\u003C\u002Fp>\u003Cul>\u003Cli>词表会非常大；\u003C\u002Fli>\u003Cli>\u003Ccode>unbelievable\u003C\u002Fcode>、\u003Ccode>unbelievably\u003C\u002Fcode> 等需要分别存储；\u003C\u002Fli>\u003Cli>无法良好处理新词、代码和多语言文本。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>因此现代 LLM 通常采用 \u003Cstrong>Subword\u003C\u002Fstrong>：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">unbelievable\n→ un + believ + able\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Tokenizer 本质上是在：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">小词表 + 长序列\n        ↕\n大词表 + 短序列\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>之间寻找合适的计算折中。\u003C\u002Fp>\u003Ch3 id=\"tokenizer-如何产生\">Tokenizer 如何产生\u003C\u002Fh3>\u003Cp>所谓“训练 Tokenizer”，通常不是神经网络意义上的梯度训练，而是：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">准备代表性语料\n      ↓\n确定预处理规则\n      ↓\n选择 Tokenizer 算法\n      ↓\n统计 \u002F 优化语料\n      ↓\nVocabulary + Rules\n      ↓\n保存 Tokenizer\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>例如选择：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">algorithm = BPE\nvocab_size = 32000\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>算法会根据训练语料自动学习哪些文本片段值得成为独立 Token。\u003C\u002Fp>\u003Cp>因此可以将 Tokenizer 训练类比为：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">LLM:\n数据 + 网络结构 + 优化算法\n→ Model Weights\n\nTokenizer:\n语料 + Tokenizer 算法 + 超参数\n→ Vocabulary + Rules\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Tokenizer 一般在 LLM 正式训练前确定，并在训练和推理期间保持一致。\u003C\u002Fp>\u003Ch3 id=\"tokenizer-基本算法\">Tokenizer 基本算法\u003C\u002Fh3>\u003Ch4 id=\"bpe-byte-pair-encoding\">BPE（Byte Pair Encoding）\u003C\u002Fh4>\u003Cp>BPE 的核心思想是：\u003C\u002Fp>\u003Cp>&gt; 不断合并语料中最常共同出现的相邻片段。\u003C\u002Fp>\u003Cp>例如训练语料：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">low\nlower\nlowest\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>初始拆分：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">l o w\nl o w e r\nl o w e s t\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>统计相邻组合：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">(l, o) → 3\n(o, w) → 3\n(w, e) → 2\n...\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>于是执行：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">l + o → lo\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>得到：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">lo w\nlo w e r\nlo w e s t\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>继续统计：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">lo + w → low\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>最终可能得到：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">Vocabulary:\nl\no\nw\nlo\nlow\ner\nest\n...\n\nMerge Rules:\nl  o  → lo\nlo w  → low\ne  r  → er\n...\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>简化后的 BPE 训练算法：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"python\">vocab \u003Cspan style=\"color: #d73948\">=\u003C\u002Fspan> \u003Cspan style=\"color: #4b69c6\">initial_units\u003C\u002Fspan>(corpus)\n\n\u003Cspan style=\"color: #d73948\">while\u003C\u002Fspan> \u003Cspan style=\"color: #4b69c6\">len\u003C\u002Fspan>(vocab) \u003Cspan style=\"color: #d73948\">&lt;\u003C\u002Fspan> target_vocab_size:\n    pairs \u003Cspan style=\"color: #d73948\">=\u003C\u002Fspan> \u003Cspan style=\"color: #4b69c6\">count_adjacent_pairs\u003C\u002Fspan>(corpus)\n    a, b \u003Cspan style=\"color: #d73948\">=\u003C\u002Fspan> \u003Cspan style=\"color: #4b69c6\">most_frequent\u003C\u002Fspan>(pairs)\n\n    new_token \u003Cspan style=\"color: #d73948\">=\u003C\u002Fspan> a \u003Cspan style=\"color: #d73948\">+\u003C\u002Fspan> b\n\n    corpus \u003Cspan style=\"color: #d73948\">=\u003C\u002Fspan> \u003Cspan style=\"color: #4b69c6\">merge\u003C\u002Fspan>(corpus, a, b)\n    vocab.\u003Cspan style=\"color: #4b69c6\">add\u003C\u002Fspan>(new_token)\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>因此 BPE 可以理解为一种\u003Cstrong>根据语料自动学习压缩字典\u003C\u002Fstrong>的方法。\u003C\u002Fp>\u003Cp>常见片段：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">the\ning\ntion\n人工\n智能\nreturn\nfunction\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>更容易成为独立 Token。\u003C\u002Fp>\u003Ch4 id=\"unigram\">Unigram\u003C\u002Fh4>\u003Cp>Unigram 的思路与 BPE 相反。\u003C\u002Fp>\u003Cp>BPE 从很小的词表开始：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">字符 \u002F Byte\n→ 不断添加 Token\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Unigram 通常从一个较大的候选词表开始：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">大量候选 Token\n→ 不断删除价值较低的 Token\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>每个 Token 都带有一个概率：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">Token       Probability\nun          0.08\nbelieve     0.03\nable        0.05\n...\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>对于：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">unbelievable\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>可能存在多种切分：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">un + believable\nun + believe + able\nu + n + believe + able\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Unigram 根据整条 Token 序列的概率选择较优方案：\u003C\u002Fp>\u003Cmath display=\"block\">\u003Cmi>𝑃\u003C\u002Fmi>\u003Cmrow>\u003Cmo>(\u003C\u002Fmo>\u003Cmrow>\u003Cmsub>\u003Cmi>𝑡\u003C\u002Fmi>\u003Cmn>1\u003C\u002Fmn>\u003C\u002Fmsub>\u003Cmo>,\u003C\u002Fmo>\u003Cmi>…\u003C\u002Fmi>\u003Cmo>,\u003C\u002Fmo>\u003Cmsub>\u003Cmi>𝑡\u003C\u002Fmi>\u003Cmi>𝑛\u003C\u002Fmi>\u003C\u002Fmsub>\u003C\u002Fmrow>\u003Cmo>)\u003C\u002Fmo>\u003C\u002Fmrow>\u003Cmo>=\u003C\u002Fmo>\u003Cmunder>\u003Cmo form=\"prefix\" lspace=\"0em\">∏\u003C\u002Fmo>\u003Cmi>𝑖\u003C\u002Fmi>\u003C\u002Fmunder>\u003Cmi>𝑃\u003C\u002Fmi>\u003Cmrow>\u003Cmo>(\u003C\u002Fmo>\u003Cmsub>\u003Cmi>𝑡\u003C\u002Fmi>\u003Cmi>𝑖\u003C\u002Fmi>\u003C\u002Fmsub>\u003Cmo>)\u003C\u002Fmo>\u003C\u002Fmrow>\u003C\u002Fmath>\u003Cp>训练过程中逐渐删除贡献较小的 Token，直到词表达到目标大小。\u003C\u002Fp>\u003Cp>其特点是：\u003C\u002Fp>\u003Cul>\u003Cli>不依赖固定的 BPE Merge 顺序；\u003C\u002Fli>\u003Cli>同一字符串可以存在多个候选切分；\u003C\u002Fli>\u003Cli>可以通过概率模型选择更合适的 Token 序列。\u003C\u002Fli>\u003C\u002Ful>\u003Ch4 id=\"wordpiece\">WordPiece\u003C\u002Fh4>\u003Cp>WordPiece 与 BPE 类似，也通过 Subword 构建词表。\u003C\u002Fp>\u003Cp>区别主要在于 Token 的选择标准不同：\u003C\u002Fp>\u003Cul>\u003Cli>BPE 主要根据相邻片段出现频率；\u003C\u002Fli>\u003Cli>WordPiece 更关注加入某个 Token 后对语言建模能力的改善。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>BERT 是典型的 WordPiece 使用者。\u003C\u002Fp>\u003Cp>例如：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">playing\n→ play + ##ing\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>其中 \u003Ccode>##\u003C\u002Fcode> 表示该 Token 出现在单词内部。\u003C\u002Fp>\u003Ch3 id=\"tokenizer-的设计\">Tokenizer 的设计\u003C\u002Fh3>\u003Cp>设计 Tokenizer 时主要需要决定以下内容：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">训练语料\n   ↓\n基础单位：Byte \u002F Character\n   ↓\nNormalization\n   ↓\nPre-tokenization\n   ↓\nBPE \u002F Unigram \u002F WordPiece\n   ↓\nVocabulary Size\n   ↓\nSpecial Tokens\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>其中最重要的几个因素是：\u003C\u002Fp>\u003Ch4 id=\"训练语料\">训练语料\u003C\u002Fh4>\u003Cp>Tokenizer 会直接反映训练数据分布。\u003C\u002Fp>\u003Cp>如果大量数据是代码，可能学习：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">return\nconst\ndef\n::\n==\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>如果大量数据是中文，则可能学习：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">中国\n人工智能\n模型\n系统\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>因此 Tokenizer 本身也是一种\u003Cstrong>针对数据分布的编码设计\u003C\u002Fstrong>。\u003C\u002Fp>\u003Ch4 id=\"vocabulary-size\">Vocabulary Size\u003C\u002Fh4>\u003Cp>词表越大：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">文本\n→ 更少 Token\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>但 Embedding 和输出层参数更多。\u003C\u002Fp>\u003Cp>对于隐藏维度 \u003Cmath>\u003Cmi>𝑑\u003C\u002Fmi>\u003C\u002Fmath>：\u003C\u002Fp>\u003Cmath display=\"block\">\u003Cmsub>\u003Cmi>𝑁\u003C\u002Fmi>\u003Cmtext>embedding\u003C\u002Fmtext>\u003C\u002Fmsub>\u003Cmo>=\u003C\u002Fmo>\u003Cmi>𝑉\u003C\u002Fmi>\u003Cmo lspace=\"0.2222222222222222em\" rspace=\"0.2222222222222222em\">×\u003C\u002Fmo>\u003Cmi>𝑑\u003C\u002Fmi>\u003C\u002Fmath>\u003Cp>其中 \u003Cmath>\u003Cmi>𝑉\u003C\u002Fmi>\u003C\u002Fmath> 为词表大小。\u003C\u002Fp>\u003Cp>因此：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">Vocabulary ↑\nSequence Length ↓\nEmbedding Parameters ↑\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>不存在无限增大词表的收益。\u003C\u002Fp>\u003Ch4 id=\"评价指标\">评价指标\u003C\u002Fh4>\u003Cp>Tokenizer 不应只看“能否编码文本”，还应关注：\u003C\u002Fp>\u003Cul>\u003Cli>平均 Token 数；\u003C\u002Fli>\u003Cli>\u003Ccode>bytes \u002F token\u003C\u002Fcode>；\u003C\u002Fli>\u003Cli>中文、英文等不同语言的编码效率；\u003C\u002Fli>\u003Cli>Code Tokenization 效率；\u003C\u002Fli>\u003Cli>Vocabulary Size；\u003C\u002Fli>\u003Cli>对未知字符和异常输入的鲁棒性。\u003C\u002Fli>\u003C\u002Ful>\u003Ch3 id=\"tokenizer-的局限\">Tokenizer 的局限\u003C\u002Fh3>\u003Cp>传统 Tokenizer 有一个根本特点：\u003C\u002Fp>\u003Cp>&gt; Token 的划分规则在 LLM 训练之前就已经固定。\u003C\u002Fp>\u003Cp>例如 BPE 可能始终将某个字符串编码为：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">un + believable\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>而不会根据上下文动态改变计算粒度。\u003C\u002Fp>\u003Cp>它本身并不知道：\u003C\u002Fp>\u003Cul>\u003Cli>当前 Token 的语义；\u003C\u002Fli>\u003Cli>当前任务是否困难；\u003C\u002Fli>\u003Cli>哪些区域值得更多计算；\u003C\u002Fli>\u003Cli>哪些区域可以被高度压缩。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>因此 Tokenizer 实际上人为规定了 LLM 的\u003Cstrong>基础计算粒度\u003C\u002Fstrong>。\u003C\u002Fp>\u003Ch3 id=\"未来研究方向\">未来研究方向\u003C\u002Fh3>\u003Ch4 id=\"learnable-tokenizer\">Learnable Tokenizer\u003C\u002Fh4>\u003Cp>一种直接思路是：\u003C\u002Fp>\u003Cp>&gt; 让一个神经网络决定文本应该如何分块。\u003C\u002Fp>\u003Cp>例如：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">Bytes\n  ↓\nSmall Neural Network\n  ↓\nDynamic Chunks\n  ↓\nLarge Language Model\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>与固定 BPE 不同，Chunk 可以根据上下文动态变化。\u003C\u002Fp>\u003Cp>简单区域可以使用较大的 Chunk：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">[The cat is sitting]\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>复杂区域则使用更细粒度：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">[x] [9] [Q] [@] [7]\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>此时 Tokenization 不再是独立的数据预处理，而成为模型的一部分。\u003C\u002Fp>\u003Ch4 id=\"无固定-tokenizer\">无固定 Tokenizer\u003C\u002Fh4>\u003Cp>进一步可以完全取消传统 Vocabulary：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">UTF-8 Bytes\n     ↓\nLocal Encoder\n     ↓\nLatent Patches\n     ↓\nGlobal Model\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>其中：\u003C\u002Fp>\u003Cul>\u003Cli>Local Model 处理字符、拼写等局部结构；\u003C\u002Fli>\u003Cli>Global Model 处理语义、知识与推理。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>核心思想从：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">如何设计一个更好的 Tokenizer？\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>变成：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">模型应该如何自动决定自己的计算粒度？\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>这类方法的优势包括：\u003C\u002Fp>\u003Cul>\u003Cli>不依赖人工固定词表；\u003C\u002Fli>\u003Cli>无 OOV；\u003C\u002Fli>\u003Cli>对多语言更加自然；\u003C\u002Fli>\u003Cli>可以动态分配计算资源；\u003C\u002Fli>\u003Cli>Global Model 可以在更短的序列上工作。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>主要问题则集中在输出侧。\u003C\u002Fp>\u003Ch4 id=\"层次化计算\">层次化计算\u003C\u002Fh4>\u003Cp>传统 LLM 基本在单一 Token 粒度上进行计算：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">token\ntoken\ntoken\ntoken\n  ↓\nLarge Transformer\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>但语言本身具有天然层次：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">Byte\n ↓\nCharacter\n ↓\nSubword\n ↓\nWord\n ↓\nPhrase\n ↓\nSentence\n ↓\nConcept\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>因此一种可能的未来架构是：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">Bytes\n  ↓\nTiny Local Model\n  ↓\nLexical Chunks\n  ↓\nSmall Model\n  ↓\nSemantic Chunks\n  ↓\nLarge Global Model\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>低层模型负责：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">字符\n拼写\n局部语法\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>高层模型负责：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">语义\n知识\n推理\n规划\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>其目的不是单纯“去掉 Tokenizer”，而是避免让昂贵的大模型对所有低层信息进行同等级计算。\u003C\u002Fp>\u003Ch4 id=\"输出与-diffusion\">输出与 Diffusion\u003C\u002Fh4>\u003Cp>无 Tokenizer 或 Latent 模型的一个核心困难是输出。\u003C\u002Fp>\u003Cp>传统自回归模型：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">token_1\n→ token_2\n→ token_3\n→ ...\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>优点是质量高、因果关系明确，但必须逐步生成。\u003C\u002Fp>\u003Cp>Diffusion 可以同时更新多个位置：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">[MASK] [MASK] [MASK] [MASK]\n        ↓\n[word] [MASK] [word] [MASK]\n        ↓\n[word] [word] [word] [word]\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>因此它有机会提高并行生成能力。\u003C\u002Fp>\u003Cp>但 Diffusion 也存在：\u003C\u002Fp>\u003Cul>\u003Cli>需要多次 Denoising；\u003C\u002Fli>\u003Cli>每一步可能重新计算整段序列；\u003C\u002Fli>\u003Cli>输出长度处理更困难；\u003C\u002Fli>\u003Cli>更少 Denoising Step 通常意味着质量下降。\u003C\u002Fli>\u003C\u002Ful>\u003Cp>因此目前的核心问题仍是：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">Generation Speed\n        ↕\nGeneration Quality\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>一种值得关注的结构是：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">        Global Model\n             ↓\n      Semantic Latent\n             ↓\n     Local Diffusion Model\n             ↓\n     Token \u002F Byte Sequence\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Global Model 负责低频、高层的推理；\u003C\u002Fp>\u003Cp>Local Decoder 负责高速展开具体语言。\u003C\u002Fp>\u003Ch3 id=\"从-tokenizer-到-latent-thought\">从 Tokenizer 到 Latent Thought\u003C\u002Fh3>\u003Cp>更进一步，可以质疑另一个假设：\u003C\u002Fp>\u003Cp>&gt; 推理本身是否必须以语言 Token 的形式进行？\u003C\u002Fp>\u003Cp>传统 Chain-of-Thought：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">内部表示\n→ 语言 Token\n→ 内部表示\n→ 语言 Token\n→ ...\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>模型每进行一步推理，都必须把内部状态转换成人类语言。\u003C\u002Fp>\u003Cp>但人的思考体验往往并不完全表现为逐词生成：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">问题\n ↓\n模糊的概念 \u002F 联想 \u002F 候选方案\n ↓\n形成表达意图\n ↓\n组织语言\n ↓\n逐字、逐词说出\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>因此可以考虑：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">Input\n  ↓\nEncoder\n  ↓\nContinuous Latent Thought\n  ↓\nReasoning \u002F Planning\n  ↓\nCommunicative Intent\n  ↓\nLanguage Decoder\n  ↓\nText\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>此时语言只是智能系统的一种输入输出形式，而不是推理本身。\u003C\u002Fp>\u003Cp>这种架构可能允许连续表示同时保留多个候选方案，而不必像 Token Generation 一样过早做离散选择。\u003C\u002Fp>\u003Cp>最终问题也从：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">如何设计 Tokenizer？\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>逐渐演化为：\u003C\u002Fp>\u003Cpre>\u003Ccode data-lang=\"text\">模型应该使用什么内部表示进行思考？\n\n不同计算粒度之间应该如何组织？\n\n语言是否只是内部认知状态的一种表达形式？\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>这已经从 Tokenizer 问题进一步扩展为 \u003Cstrong>LLM 表示与推理架构问题\u003C\u002Fstrong>。\u003C\u002Fp>","基本概念Tokenizer 是连接原始文本与LLM 数值输入的编码系统，其基本任务是：文本 → Token 序列 → Token ID 序列 → LLM例如：\"unbelievable\" → [\"un\", \"believ\", \"able\"] → [412, 8271, 539]一个完整的 Tokenizer 通常包含：Vocabulary：Token ↔ ID 的映射；Tokenization Rules：文本如何被切分为 Token；Normalization：Unicode、空格等文本规范化规则；Special Tokens：如 \u003CBOS>、\u003CEOS>、\u003CPAD>；Decoder：Token 序列如何恢复为文本。因此，Tokenizer 并不只是一个映射表。tokenizer.json 只是将这些规则和数据序列化保存下来。为什么需要 TokenizerLLM 不能直接处理字符串，只能处理数值向量，因此首先需要把文本转换为离散 ID。最直接的两种粒度都有明显问题。字符 \u002F Byte 级例如：unbelievable → u n b e l i e v a b l e优点：词表很小；可以表示任意文本；几乎不存在 OOV（未知词）问题。缺点：序列很长；LLM 需要进行更多次计算。Word 级例如：unbelievable → [unbelievable]优点：序列较短。缺点：词表会非常大；unbelievable、unbelievably 等需要分别存储；无法良好处理新词、代码和多语言文本。因此现代 LLM 通常采用 Subword：unbelievable → un + believ + ableTokenizer 本质上是在：小词表 + 长序列 ↕ 大词表 + 短序列之间寻找合适的计算折中。Tokenizer 如何产生所谓“训练 Tokenizer”，通常不是神经网络意义上的梯度训练，而是：准备代表性语料 ↓ 确定预处理规则 ↓ 选择 Tokenizer 算法 ↓ 统计 \u002F 优化语料 ↓ Vocabulary + Rules ↓ 保存 Tokenizer例如选择：algorithm = BPE vocab_size = 32000算法会根据训练语料自动学习哪些文本片段值得成为独立 Token。因此可以将 Tokenizer 训练类比为：LLM: 数据 + 网络结构 + 优化算法 → Model Weights Tokenizer: 语料 + Tokenizer 算法 + 超参数 → Vocabulary + RulesTokenizer 一般在 LLM 正式训练前确定，并在训练和推理期间保持一致。Tokenizer 基本算法BPE（Byte Pair Encoding）BPE 的核心思想是：> 不断合并语料中最常共同出现的相邻片段。例如训练语料：low lower lowest初始拆分：l o w l o w e r l o w e s t统计相邻组合：(l, o) → 3 (o, w) → 3 (w, e) → 2 ...于是执行：l + o → lo得到：lo w lo w e r lo w e s t继续统计：lo + w → low最终可能得到：Vocabulary: l o w lo low er est ... Merge Rules: l o → lo lo w → low e r → er ...简化后的 BPE 训练算法：vocab = initial_units(corpus) while len(vocab) \u003C target_vocab_size: pairs = count_adjacent_pairs(corpus) a, b = most_frequent(pairs) new_token = a + b corpus = merge(corpus, a, b) vocab.add(new_token)因此 BPE 可以理解为一种根据语料自动学习压缩字典的方法。常见片段：the ing tion 人工 智能 return function更容易成为独立 Token。UnigramUnigram 的思路与 BPE 相反。BPE 从很小的词表开始：字符 \u002F Byte → 不断添加 TokenUnigram 通常从一个较大的候选词表开始：大量候选 Token → 不断删除价值较低的 Token每个 Token 都带有一个概率：Token Probability un 0.08 believe 0.03 able 0.05 ...对于：unbelievable可能存在多种切分：un + believable un + believe + able u + n + believe + ableUnigram 根据整条 Token 序列的概率选择较优方案：𝑃(𝑡1,…,𝑡𝑛)=∏𝑖𝑃(𝑡𝑖)训练过程中逐渐删除贡献较小的 Token，直到词表达到目标大小。其特点是：不依赖固定的 BPE Merge 顺序；同一字符串可以存在多个候选切分；可以通过概率模型选择更合适的 Token 序列。WordPieceWordPiece 与 BPE 类似，也通过 Subword 构建词表。区别主要在于 Token 的选择标准不同：BPE 主要根据相邻片段出现频率；WordPiece 更关注加入某个 Token 后对语言建模能力的改善。BERT 是典型的 WordPiece 使用者。例如：playing → play + ##ing其中 ## 表示该 Token 出现在单词内部。Tokenizer 的设计设计 Tokenizer 时主要需要决定以下内容：训练语料 ↓ 基础单位：Byte \u002F Character ↓ Normalization ↓ Pre-tokenization ↓ BPE \u002F Unigram \u002F WordPiece ↓ Vocabulary Size ↓ Special Tokens其中最重要的几个因素是：训练语料Tokenizer 会直接反映训练数据分布。如果大量数据是代码，可能学习：return const def :: ==如果大量数据是中文，则可能学习：中国 人工智能 模型 系统因此 Tokenizer 本身也是一种针对数据分布的编码设计。Vocabulary Size词表越大：文本 → 更少 Token但 Embedding 和输出层参数更多。对于隐藏维度 𝑑：𝑁embedding=𝑉×𝑑其中 𝑉 为词表大小。因此：Vocabulary ↑ Sequence Length ↓ Embedding Parameters ↑不存在无限增大词表的收益。评价指标Tokenizer 不应只看“能否编码文本”，还应关注：平均 Token 数；bytes \u002F token；中文、英文等不同语言的编码效率；Code Tokenization 效率；Vocabulary Size；对未知字符和异常输入的鲁棒性。Tokenizer 的局限传统 Tokenizer 有一个根本特点：> Token 的划分规则在 LLM 训练之前就已经固定。例如 BPE 可能始终将某个字符串编码为：un + believable而不会根据上下文动态改变计算粒度。它本身并不知道：当前 Token 的语义；当前任务是否困难；哪些区域值得更多计算；哪些区域可以被高度压缩。因此 Tokenizer 实际上人为规定了 LLM 的基础计算粒度。未来研究方向Learnable Tokenizer一种直接思路是：> 让一个神经网络决定文本应该如何分块。例如：Bytes ↓ Small Neural Network ↓ Dynamic Chunks ↓ Large Language Model与固定 BPE 不同，Chunk 可以根据上下文动态变化。简单区域可以使用较大的 Chunk：[The cat is sitting]复杂区域则使用更细粒度：[x] [9] [Q] [@] [7]此时 Tokenization 不再是独立的数据预处理，而成为模型的一部分。无固定 Tokenizer进一步可以完全取消传统 Vocabulary：UTF-8 Bytes ↓ Local Encoder ↓ Latent Patches ↓ Global Model其中：Local Model 处理字符、拼写等局部结构；Global Model 处理语义、知识与推理。核心思想从：如何设计一个更好的 Tokenizer？变成：模型应该如何自动决定自己的计算粒度？这类方法的优势包括：不依赖人工固定词表；无 OOV；对多语言更加自然；可以动态分配计算资源；Global Model 可以在更短的序列上工作。主要问题则集中在输出侧。层次化计算传统 LLM 基本在单一 Token 粒度上进行计算：token token token token ↓ Large Transformer但语言本身具有天然层次：Byte ↓ Character ↓ Subword ↓ Word ↓ Phrase ↓ Sentence ↓ Concept因此一种可能的未来架构是：Bytes ↓ Tiny Local Model ↓ Lexical Chunks ↓ Small Model ↓ Semantic Chunks ↓ Large Global Model低层模型负责：字符 拼写 局部语法高层模型负责：语义 知识 推理 规划其目的不是单纯“去掉 Tokenizer”，而是避免让昂贵的大模型对所有低层信息进行同等级计算。输出与 Diffusion无 Tokenizer 或 Latent 模型的一个核心困难是输出。传统自回归模型：token_1 → token_2 → token_3 → ...优点是质量高、因果关系明确，但必须逐步生成。Diffusion 可以同时更新多个位置：[MASK] [MASK] [MASK] [MASK] ↓ [word] [MASK] [word] [MASK] ↓ [word] [word] [word] [word]因此它有机会提高并行生成能力。但 Diffusion 也存在：需要多次 Denoising；每一步可能重新计算整段序列；输出长度处理更困难；更少 Denoising Step 通常意味着质量下降。因此目前的核心问题仍是：Generation Speed ↕ Generation Quality一种值得关注的结构是： Global Model ↓ Semantic Latent ↓ Local Diffusion Model ↓ Token \u002F Byte SequenceGlobal Model 负责低频、高层的推理；Local Decoder 负责高速展开具体语言。从 Tokenizer 到 Latent Thought更进一步，可以质疑另一个假设：> 推理本身是否必须以语言 Token 的形式进行？传统 Chain-of-Thought：内部表示 → 语言 Token → 内部表示 → 语言 Token → ...模型每进行一步推理，都必须把内部状态转换成人类语言。但人的思考体验往往并不完全表现为逐词生成：问题 ↓ 模糊的概念 \u002F 联想 \u002F 候选方案 ↓ 形成表达意图 ↓ 组织语言 ↓ 逐字、逐词说出因此可以考虑：Input ↓ Encoder ↓ Continuous Latent Thought ↓ Reasoning \u002F Planning ↓ Communicative Intent ↓ Language Decoder ↓ Text此时语言只是智能系统的一种输入输出形式，而不是推理本身。这种架构可能允许连续表示同时保留多个候选方案，而不必像 Token Generation 一样过早做离散选择。最终问题也从：如何设计 Tokenizer？逐渐演化为：模型应该使用什么内部表示进行思考？ 不同计算粒度之间应该如何组织？ 语言是否只是内部认知状态的一种表达形式？这已经从 Tokenizer 问题进一步扩展为 LLM 表示与推理架构问题。",1789407125076]