从零学习大模型(2)——从文字到数字:Tokenizer 与 Embedding 如何让 AI 读懂人类语言

0 评论 1035 浏览 4 收藏 18 分钟

从 ChatGPT 到文心一言,大模型已成产品革新的关键。但要真正理解它们的能力,产品经理必须掌握底层的语言处理机制。这篇文章将拆解 Tokenizer 与 Embedding 的核心逻辑,用产品视角解析 AI 如何“读懂”语言。

当我们向 ChatGPT 输入 “帮我写一封请假邮件” 时,这个看似简单的交互背后,隐藏着 AI 理解人类语言的核心步骤 —— 将文字转化为机器可处理的数字信号。在这个过程中,Tokenizer(分词器)和 Embedding(词嵌入)扮演着 “语言翻译官” 的角色:Tokenizer 负责把文本拆分成 AI 能理解的基本单元,Embedding 则将这些单元转化为包含语义信息的数值向量。正是这两个模块的协同工作,让机器得以跨越 “人类语言” 与 “机器语言” 的鸿沟。

为什么需要 Tokenizer?从 “单词困境” 说起

在 AI 处理语言的早期,研究者们曾尝试用 “单词级” 的方式处理文本 —— 即给每个单词分配一个唯一的数字(如 “苹果”=1001,“手机”=1002)。这种方法简单直接,但很快遇到了无法解决的问题。

首先是未登录词(OOV)难题,人类语言会不断产生新词(如 “内卷”“AI 生成”),模型无法识别不在预设词汇表里的词,只能用 “未知标记”()代替,导致语义丢失。其次是词汇表爆炸,仅英语就有超过 100 万个单词,加上中文、法语等多语言场景,词汇表会无限膨胀,不仅占用大量内存,还会让模型难以训练。最后是语义割裂,“苹果”(水果)和 “苹果”(公司)共用一个编码,“开心” 和 “不开心” 被视为完全无关的词,模型无法捕捉词汇间的内在联系。

为解决这些问题,研究者们提出了子词分词(Subword Tokenization)思想:将单词拆分成更小的语义单元(如 “unhappiness” 拆成 “un + happy + ness”)。这些子词既能组合出所有可能的单词(解决 OOV),又能通过共享子词减少词汇表大小(如 “happy” 可用于 “happiness”“unhappy”),还能保留语义关联(“un-” 表示否定)。

而 Tokenizer 的核心任务,就是实现这种 “智能拆分”—— 它就像一位精通词根词缀的语言学家,能根据语言规律将文本切分成最适合模型处理的子词单元。

主流子词分词算法:BPE、BBPE 与 WordPiece 的 “拆分智慧”

目前主流的子词分词算法都基于 “从最小单元开始,逐步合并高频组合” 的思路,但在细节上各有侧重。理解这些算法,就能明白 AI 是如何 “拆解语言” 的。

1. BPE(字节对编码):从字符到子词的 “合并游戏”

BPE(Byte Pair Encoding)是最经典的子词算法,最初用于数据压缩,2015 年被引入 NLP 领域后,成为 GPT、Transformer-XL 等模型的标配分词器。它的核心逻辑可以概括为 “从字符开始,不断合并最常见的相邻对”。

BPE 的工作原理分为三步完成子词构建。初始化阶段,将所有单词拆分成字符,并在词尾添加特殊标记(如</w>)区分词边界。例如 “cats” 拆分为 “c a t s ”,“cat” 拆分为 “c a t ”。然后进入统计合并阶段,遍历所有文本,统计相邻字符对的出现频率,将最频繁的对合并为新子词。比如 “t” 和 “在“cat</w>”“bat</w>”中频繁出现,就合并为“t</w>;下次若 “ca” 出现次数最多,则合并为 “ca”。最后是迭代终止,重复合并过程,直到达到预设的词汇表大小(如 32000)或迭代次数。最终词汇表中会包含字符、常用子词(如 “cat”“ing”)和完整单词(如 “the”)。

当处理新文本时,BPE 会用 “最长匹配” 策略拆分单词:从最长可能的子词开始尝试匹配,若匹配失败则缩短长度。例如处理 “cats” 时,先检查整个单词 “cats” 是否在词汇表中(若不在则进入下一步);尝试 “cat”+“s”(若 “cat” 在词汇表,“s” 也在,则拆分为 “cat + s”);最终输出子词序列(如 “cat + s”)。

这种方式既能保证常见词被完整保留(如 “the” 直接作为一个子词),又能将罕见词拆分为已知子词(如 “fluffiness” 拆为 “fluff + i + ness”)。

BPE 的最大优势是简单高效 —— 仅通过频率统计就能构建子词表,无需语言学知识,且能处理任意语言。但它完全依赖频率,可能合并无意义的高频组合(如 “ab” 在 “about”“able” 中频繁出现,但本身无语义),且对多语言混合文本的支持较弱(不同语言的字符编码可能冲突)。

2. BBPE(字节级 BPE):打破语言壁垒的 “万能拆分器”

BBPE(Byte-Level BPE)是 BPE 的升级版,由 OpenAI 在 GPT-2 中提出。它的核心改进是将 “字符” 替换为 “字节” 作为最小单元(如 UTF-8 编码下,一个汉字对应 3 个字节),从而解决了多语言处理的痛点。

人类语言的字符编码复杂:英文用 1 个字节,中文用 3 个字节,emoji 可能用 4 个字节。传统 BPE 需要先处理字符编码,而 BBPE 直接以字节为单位(共 256 种可能的字节),天然支持所有语言和符号 —— 无论是中文、阿拉伯语,还是代码符号(如{})、emoji(如😊),都能被拆分为字节序列。

例如处理中文 “自然语言”,传统 BPE 需先将 “自”“然”“语”“言” 作为字符初始化;BBPE 直接使用它们的 UTF-8 字节(如 “自” 对应 0xE8 0x87 0xAA 三个字节),通过合并高频字节对(如 “自然” 的字节组合)形成子词。

BBPE 的设计让它特别适合处理 “非标准文本”。在代码生成任务中,能精准拆分for while等关键字和== !=等运算符;在多语言对话中,可同时处理 “Hello!你好😊” 中的英文、中文和 emoji;词汇表大小可控(如 GPT-3 使用 50257 大小的词表),兼顾覆盖度和效率。

目前 BBPE 已成为多语言模型的主流选择,GPT 系列、Claude 等均采用该算法。

3. WordPiece:兼顾语义的 “智能合并”

WordPiece 由谷歌提出,是 BERT、XLNet 等模型的分词器。它与 BPE 的核心区别在于合并标准 —— 不单纯看频率,而是通过 “互信息” 判断子词组合的必要性。

互信息(Mutual Information)衡量两个子词的 “绑定强度”:若两个子词经常一起出现(如 “un” 和 “happy”),且很少单独出现,则互信息高,优先合并。例如 “un” 和 “happy” 共现 50 次,“un” 单独出现 10 次,“happy” 单独出现 20 次,则互信息 = 50/(10×20)=0.25。若该值高于阈值,则合并为 “unhappy”。

这种策略能避免 BPE 的 “盲目合并”—— 例如 “New York” 中 “New” 和 “York” 互信息高,会被合并为子词,而 “the” 和 “of” 虽频率高但互信息低(可与其他词搭配),则不会合并。

WordPiece 在分词时,会给非首子词添加 “##” 前缀(如 “unhappiness” 拆为 “un + ##happy + ##ness”)。这个标记的作用是告诉模型:“##happy” 是单词的中间部分,不是独立单词。这种设计能帮助模型区分 “happy”(独立词)和 “##happy”(词缀),提升语义理解精度。

由于能更好地捕捉语义关联,WordPiece 在需要深度理解文本的任务(如问答、情感分析)中表现更优。BERT 正是通过这种分词方式,才能精准理解 “苹果” 在 “苹果手机” 和 “吃苹果” 中的不同含义。

不同模型的分词选择:为什么 GPT 用 BBPE,BERT 用 WordPiece?

模型对 Tokenizer 的选择,本质上是生成式模型更看重 “覆盖范围和效率”(选 BBPE),理解式模型更看重 “语义精度”(选 WordPiece)。

GPT 系列使用 BBPE,因为需支持多语言生成、代码和 emoji,BBPE 的字节级处理和全符号支持更适配。BERT 采用 WordPiece,由于专注自然语言理解,需精准捕捉语义关联,WordPiece 的互信息合并更符合需求。T5 使用 SentencePiece,多语言任务需统一处理空格和标点,SentencePiece(基于 BPE 的扩展)支持无空格文本。Llama 2 选择 BBPE,兼顾多语言对话和长文本生成,BBPE 的高效性和兼容性更优。

Tokenizer 在预训练中的 “全流程操作”

Tokenizer 不是简单的 “拆分工具”,而是预训练过程的 “前端处理器”,其处理质量直接影响模型性能。在实际预训练中,它需要完成以下关键操作。

面对原始语料(如网页、书籍、对话记录),Tokenizer 首先进行标准化处理。统一大小写(如将 “Apple”“APPLE” 转为 “apple”);处理特殊符号(如去除多余空格、统一标点为半角);过滤无效内容(如乱码、广告链接)。这一步的目的是减少噪声 —— 就像人类阅读前会先整理排版混乱的文本,模型也需要 “干净” 的输入。

完成清洗后,Tokenizer 按算法拆分文本(如用 BBPE 将 “我爱自然语言” 拆分为子词),再将每个子词映射到词汇表中的唯一索引(如 “我”=345,“爱”=678)。这个索引就像子词的 “身份证”,模型通过索引找到对应的嵌入向量。

为帮助模型理解文本结构,Tokenizer 会插入特殊标记。<CLS>用于句子级任务(如分类),放在句首作为整个句子的代表;<SEP>分隔两个句子(如问答任务中的 “问题 ++ 上下文”);<PAD>将不同长度的句子补成相同长度(便于批量训练);<MASK>在掩码语言模型(如 BERT)中掩盖部分子词,用于训练模型预测能力。例如 BERT 处理 “我爱 AI。它很有趣” 时,最终的 token 序列为[CLS] 我 爱 AI 。 [SEP] 它 很 有 趣 [SEP] [PAD] [PAD]。

模型能处理的序列长度有限(如 BERT 最大 512 个 token,GPT-3 支持 2048 个)。当文本过长时,Tokenizer 会截断(保留前 N 个 token);过短时则用<PAD>补齐,确保输入长度统一。这一步就像给文本 “定尺寸”—— 就像快递需要按标准尺寸打包,模型也需要固定长度的输入才能高效计算。

Embedding:给子词赋予 “语义灵魂”

经过 Tokenizer 处理的 token 索引只是 “数字标签”,无法直接用于计算。Embedding 的作用,就是将这些索引转化为包含语义信息的向量 —— 让 “苹果” 的向量与 “水果” 更接近,与 “手机” 的向量有一定关联。

嵌入层的核心作用:语义映射

Embedding 层本质是一个 “lookup table”(查询表)。表的行数等于词汇表大小(如 32000),列数等于嵌入维度(如 768);每行对应一个子词的向量(初始值随机,通过训练优化);输入 token 索引时,直接取出对应行的向量作为输出。

例如 “苹果” 的索引是 123,嵌入层就返回第 123 行的 768 维向量。训练过程中,模型会不断调整这些向量:当 “苹果” 和 “香蕉” 经常出现在类似语境(如 “吃”“水果” 附近),它们的向量会逐渐靠近;当 “苹果” 既出现在 “水果” 又出现在 “手机” 语境中,其向量会成为两种语义的 “混合体”,通过上下文进一步区分。

与位置编码的协同

如前文所述,Transformer 需要位置信息才能理解语序。在实际处理中,Embedding 向量会与位置编码向量相加 —— 这相当于给每个子词的 “语义向量” 加上 “位置标签”,让模型既知道 “这个词是什么意思”,又知道 “它在句子的哪个位置”。

为什么说 Tokenizer 是 “模型的地基”?

在大语言模型的 “能力金字塔” 中,Tokenizer 处于最底层。它决定了模型能 “看到” 什么(子词划分方式直接影响语义捕捉);它限制了模型的 “表达范围”(词汇表未覆盖的子词会导致信息丢失);它影响模型的 “计算效率”(子词过长会增加序列长度,过短会增加噪声)。

例如,若 Tokenizer 无法正确拆分 “量子计算”(拆成 “量 + 子 + 计 + 算” 而非 “量子 + 计算”),模型就难以学习这一概念的完整语义;若词汇表过小(如 8000),大量子词会被重复拆分,增加模型学习负担。

因此,设计 Tokenizer 时需要在 “词汇表大小”“子词粒度”“语言覆盖度” 之间找到平衡 —— 这也是为什么顶级模型的 Tokenizer 往往需要经过多轮调试和优化。

结语:从拆分到理解的 “语言桥梁”

Tokenizer 和 Embedding 看似是 “预处理工具”,实则是 AI 理解语言的 “第一道智慧”。从 BPE 的简单合并到 BBPE 的多语言支持,再到 WordPiece 的语义感知,这些算法的演进本质上是 “让机器更懂人类语言规律” 的过程。

当我们惊叹于 GPT 能写代码、BERT 能回答问题时,不妨记住:这些能力的起点,是 Tokenizer 将文本拆分成子词的那一刻,是 Embedding 给子词赋予语义向量的那一步。正是这 “拆分” 与 “映射” 的智慧,让机器终于能跨越语言的鸿沟,与人类实现真正的 “对话”。

未来,随着多模态模型的发展,Tokenizer 可能会进化为 “跨模态拆分器”(同时处理文本、图像、语音的基本单元),但核心逻辑不会改变 —— 理解的前提,是先学会 “拆解” 与 “关联”。

本文由 @红岸小兵 原创发布于人人都是产品经理。未经作者许可,禁止转载

题图来自Unsplash,基于CC0协议

该文观点仅代表作者本人,人人都是产品经理平台仅提供信息存储空间服务

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
评论
评论请登录
  1. 目前还没评论,等你发挥!