从零手写 Byte-Level BPE 分词器:开启通向大语言模型的第一道门

不依赖 HuggingFace tokenizers,纯使用 Python 从底层 UTF-8 字节流出发手写工业级 Byte-Level BPE 分词器:解析 256 原子字节零 OOV 机制、纸上推演 Pair 统计合并、标点吸附正则 (Fused Punctuation) 解决 93% 孤立标点震荡,并实现特殊标记原子级提取保护。

本文目录34 个章节

本章导读: 很多初学者在初次接触大模型时,往往急于跳进注意力机制(Attention)和深度网络,却把最基础的“分词器(Tokenizer)”当作一个可有可无的黑盒工具。 殊不知,分词器是大模型与人类世界交流的唯一咽喉要道。如果分词器设计糟糕,模型连最基本的数数、代码缩进都学不会,甚至会因为词表外词(OOV)而频频报出乱码。 现代最顶尖的大模型(GPT-4、LLaMA-3、Qwen-2.5)无一例外全部采用 Byte-Level BPE(字节级字节对编码)。 本章将像一位耐心的编程导师,带你从计算机最底层的 ASCII 码和 UTF-8 变长字节谈起,手把手带你推导算法,并一行代码一行代码地手写出一个生产级的纯 Python 分词器。

1.1 寻根溯源:计算机到底是怎么看文字的?

在写任何一行代码之前,我们必须先在脑海中建立起计算机世界的物理图景。

1.1.1 硅基芯片的物理局限

计算机的 CPU 和 GPU 芯片本质上是数十亿个微型晶体管组成的电路开关。 开关只有两种状态:开(1)关(0)。 计算机连一个英文字母 'a' 都不认识,它只能存储和运算二进制数字。

为了在屏幕上显示人类语言,人类给每一个文字符号编造了一个唯一的数字代号:

编码演进代际核心设计原理典型字符编码示例优势与历史局限性
第一代:ASCII (1960s)仅用 7 位二进制 (01270 \sim 127) 记录字符字符 'A' \to 65 (二进制 01000001)内存极其紧凑(仅 1 字节),但面对中文、日文、阿拉伯文等非拉丁语系彻底抓瞎。
第二代:Unicode 万国码 (1990s)为全球所有语言符号分配唯一数学编号(码点 Code Point)汉字 '中' \to U+4E2D (十进制 20013)<br>Emoji '🚀' \to U+1F680 (十进制 128640)统一了全球文字,但若固定用 4 字节存储,全英文文本体积将瞬间暴涨 4 倍,浪费极大。
第三代:UTF-8 变长编码 (工业标准)动态变长前缀码:根据字符码点动态分配 1 ~ 4 个字节英文占 1 字节('A' \to [65]<br>汉字占 3 字节('中' \to [228, 184, 173]<br>Emoji 占 4 字节('🚀' \to [240, 159, 154, 128]黄金平衡:向前完美兼容 ASCII,紧凑无浪费,成为现代互联网与现代大模型的通用基石!

1.1.2 深入 UTF-8 的二进制底层:拿具体文字开刀

让我们在 Python 终端里输入几行代码,亲眼看看人类文字在计算机内存里到底长什么样:

PYTHON
# 1. 英文只占 1 个字节 (十进制 65)
print(list("A".encode("utf-8")))     # 输出: [65]

# 2. 汉字占 3 个字节!
print(list("中".encode("utf-8")))     # 输出: [228, 184, 173]

# 3. 火箭 Emoji 占 4 个字节!
print(list("🚀".encode("utf-8")))    # 输出: [240, 159, 154, 128]

请停下来仔细观察这三个输出! 你会发现一个惊人的事实: 不论是英文、中文还是 Emoji,它们在计算机底层全部由 02550 \sim 255 的整数(单个字节 Byte)构成

  • 字母 'A' 是 1 个字节;
  • 汉字 '中' 是由 228、184、173 这 3 个连续的字节拼成的;
  • 火箭 Emoji '🚀' 是由 240、159、154、128 这 4 个字节拼成的。

这就是大模型分词器最重要的地基!

1.2 为什么传统分词会走向死局?

在自然语言处理早期,科学家们尝试过两种最直观的分词方式,但都付出了惨痛的代价:

分词方案类型切分机制举例 ("unbelievable")核心优势致命缺陷
1. 词级分词 (Word-Level)["unbelievable"](字典直接收录整词)直观符合人类直觉1. 词表无限膨胀(几百万词收不全)<br>2. 遇到新词/打错字输出 <UNK> 乱码
2. 字符级分词 (Char-Level)['u', 'n', 'b', 'e', 'l', ...](只认单字母或单字)基础字符集很小(几十到几千)1. 序列极度膨胀(一个单词占 12 个位置)<br>2. 极易撑爆上下文窗口,单字母语义贫瘠
3. 字节级 BPE (Byte-Level BPE)["un", "believ", "able"](256 原子 + 贪心合并分子)黄金平衡:高频词直接合并压缩,生僻词退化为单字节拼合完美攻克前两者缺陷,现代大模型唯一工业级通用标配方案

💡 核心认知:化学世界的“原子与分子”

  • 为什么永远不会报错未知词 <UNK>
    • 在 Byte-Level BPE 中,我们直接把 256 个基础字节(数值 02550 \sim 255)作为词表的第 0 号到第 255 号基本零件
    • 既然世界上任何文字在计算机里都不过是这 256 个字节的组合,那么即使遇到火星文或者刚刚发明的网络新梗,分词器大不了退化成单字节输出,永远不可能出现“我不认识这个字”的崩溃!
  • 怎么节约长度?
    • 如果两个字节经常连在一起出现(比如 't''h'),算法就会把它们合成一个新分子 'th'
    • 汉字 '中' 的 3 个字节经常手拉手出现,算法就会把这 3 个字节直接融合成一个单独的 Token 编号!

1.3 纸上推演:BPE 算法是怎么被发明出来的?

我们不看任何晦涩的论文公式,拿一张纸、一支笔,在纸上亲自推演一轮完整的 BPE 算法。

初始状态

假设我们的迷你语料库里只有 4 个单词,右侧是它们在文章里出现的次数:

  • "low":出现 5 次
  • "lower":出现 2 次
  • "newest":出现 6 次
  • "widest":出现 3 次

第一步:全部拆散为单个字母原子

在每个字母之间加上空格,把它们还原为最基础的状态:

  • l o w (5 次)
  • l o w e r (2 次)
  • n e w e s t (6 次)
  • w i d e s t (3 次)

第二步:拿放大镜扫描全场,统计相邻二元对 (Pair) 的总频次

让我们像侦探一样,统计所有紧挨在一起的两个符号一共出现了多少次:

  • (e, s):在 "newest" 里出现 6 次,在 "widest" 里出现 3 次 \to 合计 9 次
  • (s, t):在 "newest" 里出现 6 次,在 "widest" 里出现 3 次 \to 合计 9 次
  • (l, o):在 "low" 里出现 5 次,在 "lower" 里出现 2 次 \to 合计 7 次
  • (o, w):在 "low" 里出现 5 次,在 "lower" 里出现 2 次 \to 合计 7 次

谁是全场出现频次最高的冠军? 很明显,是 (e, s)(9 次)!

第三步:颁发全新工牌,执行第一次合并!

我们把全场所有的 es 紧紧焊接在一起,创造一个全新 Token:"es"! 此时,语料库变成了:

  • l o w
  • l o w e r
  • n e w [es] t (6 次)
  • w i d [es] t (3 次)

第四步:进入下一轮循环!

现在全场最高频的相邻对变成了谁? 是刚刚诞生的 ([es], t)!它在两个单词里各出现 6 次和 3 次,合计又是 9 次! 我们立刻把它再次合并,诞生了英文里最著名的最高级后缀:"est"

看到其中的奥妙了吗? BPE 算法在完全不需要任何语言学语法词典的情况下,纯粹靠概率统计,自然而然地挖出了语言中高频的词根、词缀和常见单词!

1.4 预分词正则:为什么合并前必须先用“切菜刀”?

很多初学者自己动手写 BPE 时,经常会遇到一个莫名其妙的严重 Bug: 句号、逗号会和单词黏糊糊地连在一起,比如把 "apple." 或者 "cat," 合并成了一个单独的词!

文本
===================================================================================
                   未加预分词 (No Pre-tokenization) 导致的灾难
===================================================================================
语料里有两句话:
  "I eat an apple. You eat an apple."

BPE 统计全局文本时发现: "apple" 后面经常跟着 "."
结果: BPE 强行把它们焊死在了一起,生成了一个新 Token: "apple." (带句号的苹果)

灾难后果:
  下次用户向模型提问: "Do you like apple?" (句末是问号)
  此时模型查遍词表,只认识带句号的 "apple.",根本无法复用 "apple" 的语义!
===================================================================================

💡 切菜刀原理:预分词正则 (Pre-tokenization)

为了解决这个问题,现代 GPT 和 LLaMA 都会在合并前使用正则表达式切菜刀: 先按语义把一整段长文本切成独立的食材块:

  • 单词独立一块(如 "apple"
  • 标点符号独立一块(如 ","".""?"
  • 空格独立一块
  • 数字独立一块

核心铁律:BPE 合并只允许在各自独立的食材块内部进行,严禁跨越标点和单词的边界!

经典预分词正则表达式解剖:

PYTHON
SPLIT_REGEX = re.compile(r"""'(?:[sdmt]|ll|ve|re)| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+""")
  • '(?:[sdmt]|ll|ve|re):把英文紧缩词摘出来(如 I've 里的 'veit's 里的 's);
  • ?\p{L}+:匹配可选前置空格 + 连续文字(中英文汉字与字母);
  • ?\p{N}+:匹配数字(保证 100 不会被乱黏连);
  • ?[^\s\p{L}\p{N}]+:匹配标点符号和各种 Emoji 符号。

1.5 一行代码一行代码手写分词器

现在,我们把上面的理论变成结结实实的 Python 代码。 请打开工作区中的 src/tokenizer.py。我们将分模块逐行剖析它是如何搭建起来的。

模块 1:类的初始化与基础地基搭建

PYTHON
class ByteBpeTokenizer:
    SPLIT_REGEX = SPLIT_REGEX

    def __init__(self):
        # 1. 必须准备的 4 个特殊标记 (Special Tokens)
        self.special_tokens = ["<pad>", "<s>", "</s>", "<unk>"]
        self.pad_token_id = 0  # 占位补齐符:用于短文本补齐
        self.bos_token_id = 1  # 句子开始符 (Beginning of Sequence)
        self.eos_token_id = 2  # 句子结束符 (End of Sequence)
        self.unk_token_id = 3  # 兜底未知符

        # 2. 映射字典
        self.vocab: Dict[int, bytes] = {}            # 数字 ID -> 原始字节串
        self.token_to_id: Dict[bytes, int] = {}      # 原始字节串 -> 数字 ID
        self.merges: Dict[Tuple[int, int], int] = {} # 记录合并规则: (id_a, id_b) -> 新合并ID

        # 3. 初始化地基
        self._init_base_vocab()

导师提问:为什么需要特殊符号?

  • 比如模型在自回归生成时,怎么知道一篇文章什么时候写完了?就是靠输出了 </s>(EOS)这个结束符号!
  • 当模型吐出 </s> 时,外层的 while 循环就会立刻触发 break 停机。

接下来看地基函数 _init_base_vocab

PYTHON
    def _init_base_vocab(self):
        """装入 4 个特殊标记和 256 个基础字节原子"""
        current_id = 0
        # 先存特殊标记 (占用 ID 0, 1, 2, 3)
        for st in self.special_tokens:
            b_st = st.encode("utf-8")
            self.vocab[current_id] = b_st
            self.token_to_id[b_st] = current_id
            current_id += 1

        # 紧接着存入 0 ~ 255 的基础单字节 (占用 ID 4 ~ 259)
        for b in range(256):
            b_byte = bytes([b])
            self.vocab[current_id] = b_byte
            self.token_to_id[b_byte] = current_id
            current_id += 1

这段代码执行完毕后,分词器在起跑线上就已经拥有了 260 个基础词汇(4 个特殊标记 + 256 个字节原子)。

模块 2:训练核心——寻找最高频 Pair 并实施合并

训练分词器的过程,就是把语料库反复遍历、不断寻找最高频 Pair 的过程:

PYTHON
    def train(self, texts: List[str], target_vocab_size: int = 4096, verbose: bool = True):
        # 第一步:预分词。把所有句子切成块,并转为基础字节的数字列表
        words = []
        for text in texts:
            for match in self.SPLIT_REGEX.finditer(text):
                chunk = match.group()
                # 将切块编码成字节,并查表转为初始 ID 列表
                token_ids = [self.token_to_id[bytes([b])] for b in chunk.encode("utf-8")]
                if token_ids:
                    words.append(token_ids)

        # 第二步:迭代合并。需要合并的次数 = 目标词表大小 - 当前已有大小
        num_merges = target_vocab_size - self.vocab_size
        for step in range(num_merges):
            pair_counts: Dict[Tuple[int, int], int] = {}
            # 扫描所有单词,统计相邻 pair 出现次数
            for word in words:
                for i in range(len(word) - 1):
                    pair = (word[i], word[i + 1])
                    pair_counts[pair] = pair_counts.get(pair, 0) + 1

            if not pair_counts:
                break # 没有可合并的了,提前结束

            # 找出出现次数最多的冠军 Pair
            best_pair = max(pair_counts, key=pair_counts.get)
            if pair_counts[best_pair] < 2:
                break # 如果最高频的 pair 才出现 1 次,合并毫无价值,停机

            # 产生新 Token 并注册到字典
            new_id = self.vocab_size
            self.merges[best_pair] = new_id
            new_bytes = self.vocab[best_pair[0]] + self.vocab[best_pair[1]]
            self.vocab[new_id] = new_bytes
            self.token_to_id[new_bytes] = new_id

            # 就地替换:在原数据集中把所有的 best_pair 替换为 new_id
            new_words = []
            for word in words:
                i = 0
                new_word = []
                while i < len(word):
                    if i < len(word) - 1 and (word[i], word[i + 1]) == best_pair:
                        new_word.append(new_id)
                        i += 2 # 跨越两位
                    else:
                        new_word.append(word[i])
                        i += 1
                new_words.append(new_word)
            words = new_words

模块 3:编码 (Encode) 与解码 (Decode)

编码:文本 \to 数字

当我们输入一句话时,分词器怎么把学到的规则应用上去?

PYTHON
    def encode(self, text: str, add_bos: bool = False, add_eos: bool = False) -> List[int]:
        result = []
        if add_bos:
            result.append(self.bos_token_id) # 句子开头加上 <s>

        for match in self.SPLIT_REGEX.finditer(text):
            chunk = match.group()
            # 1. 拆成单字节 ID
            chunk_ids = [self.token_to_id[bytes([b])] for b in chunk.encode("utf-8")]
            # 2. 按照学到的合并规则逐级合并
            merged_ids = self._merge_token_sequence(chunk_ids)
            result.extend(merged_ids)

        if add_eos:
            result.append(self.eos_token_id) # 句子末尾加上 </s>

        return result

解码:数字 \to 文本

解码是编码的完美逆过程:将数字 ID 查表换回字节,然后一次性拼装解出 UTF-8 字符串:

PYTHON
    def decode(self, token_ids: List[int], skip_special_tokens: bool = True) -> str:
        byte_chunks = []
        for tid in token_ids:
            # 忽略掉 <s>, </s>, <pad> 等控制符号
            if skip_special_tokens and tid in [self.pad_token_id, self.bos_token_id, self.eos_token_id, self.unk_token_id]:
                continue
            if tid in self.vocab:
                byte_chunks.append(self.vocab[tid])

        # 核心:将所有散落的字节拼成完整的 bytes 数组,再反解出汉字与 Emoji
        all_bytes = b"".join(byte_chunks)
        return all_bytes.decode("utf-8", errors="replace")

1.5 工业级实战演进:预分词边界陷阱与标点吸附技术 (Fused Punctuation)

在实际大模型落地(尤其是古诗词、代码、数学等高密度符号场景)中,我们往往会遭遇一个极其隐蔽而致命的架构陷阱:标点符号概率偏置与单字孤立震荡

1.5.1 隐蔽的 GPT-2 正则边界陷阱

经典 GPT-2 / GPT-4 的预分词正则表达式如下:

PYTHON
SPLIT_REGEX = re.compile(r"""'(?:[sdmt]|ll|ve|re)| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+""")
  • ?\p{L}+:将纯字母和纯汉字切分为词块;
  • ?[^\s\p{L}\p{N}]+:将标点符号强制切分为独立的词块!

灾难产生: 当输入古诗 "床前明月光,疑是地上霜。" 时,分词器在预分词阶段就会硬生生切分成: ["床前明月光", ",", "疑是地上霜", "。"]

因为 BPE 合并算法绝不允许跨越 Chunk 寻找字符对,这意味着: 无论你的语料规模多大、BPE 迭代多少万次,汉字和后面的逗号/句号都绝对不可能合并成一个 Token! 词表中永远只有孤立的汉字 和孤立的句号

在大模型自回归采样时,由于诗歌中逗号和句号占到了全语料的 12.5% 以上,模型一旦吐出单个汉字,下一步立刻被超高概率的孤立标点所吸引,诱发了“单字+标点”的病态震荡!

1.5.2 解决方案:标点吸附正则 (Fused Punctuation)

破解该物理隔离的最优雅手段,是微调预分词正则表达式,允许汉字在分块时贪婪吸附紧随其后的标点符号

PYTHON
# 标点吸附正则:允许汉字词块末尾吸收一个中文标点(,。!?;)
SPLIT_REGEX = re.compile(
    r"""'(?:[sdmt]|ll|ve|re)| ?\p{L}+(?:[,。!?;])?| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+"""
)

1.5.3 带来的三大降维打击收益

  1. 彻底根除标点诱惑(实测孤立标点暴降 93%): 在本项目 46 万首纯诗库实测中,标点吸附配合 4096 词表训练,使全语料的孤立标点(逗号/句号)占比从 13.11% 直降至 0.96%"光,"(Token 2929)、"霜。"(Token 2207)被自然合并为单个复合 Token。模型在生成句末最后一个汉字时,一步决策定音,不存在“写完字后发呆吐出孤立标点”的概率空档!
  2. 训练与推理提速 15%~20%: 一首 28 字的七言绝句原本需要 32 个 Token,合并后整整缩减至 28 个 Token,不仅上下文窗口更加宽裕,算力吞吐量也得到直接飞跃!
  3. 完美匹配 0.04B 参数预算: 4096 词表仅占 Embedding 4096×5122.10M4096 \times 512 \approx 2.10\text{M} 参数(仅占 0.04B 全模型的 5.5%),省下 2.1M 参数反哺深层 Transformer 隐藏层。

1.6 工业级实战进阶:结构化特殊 Token (Special Tokens) 与原子保护机制 (避坑指南 1)

在实际的大模型工业体系中,除了普通自然语言文字外,我们还需要引导模型理解系统结构边界(如文本起止、填充对齐、元数据提示等)。 这就是特殊标记(Special Tokens)的用武之地。

1.6.1 特殊 Token 的架构定义

在本项目中,我们为 0.04B Mini-LLaMA 定义了 8 个保留特殊标记:

PYTHON
DEFAULT_SPECIAL_TOKENS = [
    "<pad>",         # ID 0: 批次填充占位符
    "<s>",           # ID 1: 文本起始符 (BOS)
    "</s>",          # ID 2: 文本结束符 (EOS)
    "<unk>",         # ID 3: 未知字符标记 (Byte-Level 下作为冗余占位)
    "<|title|>",     # ID 4: 诗词题目引导标记
    "<|author|>",    # ID 5: 作者姓名引导标记
    "<|dynasty|>",   # ID 6: 朝代归属引导标记
    "<|content|>"    # ID 7: 诗词正文起始标记
]

紧接着这 8 个特殊标记,是 256 个基础字节(ID 8 ~ 263),再往后(ID 264 ~ 4095)则是 BPE 贪心合并出的诗歌文学词块。

1.6.2 避坑指南 1:特殊标记击穿陷阱 (Special Token BPE Split)

很多初学者实现自定义分词器时,最容易犯的一个隐蔽错误是:

“在词表中声明了 <|title|>,但调用 encode('<|title|>') 时,分词器却吐出了一串子词 ID!”

致命根因:预分词正则击穿

回顾 1.5 节的预分词正则 SPLIT_REGEXSPLIT_REGEX 会把文本切分成字母、汉字、标点符号。 当你传入 <|title|> 时:

  1. <| 被切为非文字符号;
  2. title 被切为英文单词;
  3. |> 被切为非文字符号。

结果是:你的特殊标记还没进入 BPE 合并逻辑,就在第一步被正则表达式强行撕成了 3 段碎片! 最终,模型根本没看到你精心设计的 ID 4(<|title|>),而是收到了由 ASCII 字节拼凑的一堆散乱碎屑,导致条件预训练彻底失效。

工业级解法:原子级正则提取保护 (Atomic Split Protection)

解法非常巧妙:在文本被送入 SPLIT_REGEX 预切分之前,先通过一个由特殊标记组成的专用正则表达式,将文本切分为“特殊标记”与“普通文本段”:

PYTHON
def _update_special_pattern(self):
    """按长度降序贪婪编译特殊标记正则"""
    if self.special_tokens:
        sorted_tokens = sorted(self.special_tokens, key=len, reverse=True)
        pattern_str = "(" + "|".join(re.escape(st) for st in sorted_tokens) + ")"
        self.special_token_pattern = re.compile(pattern_str)

encode() 中实行原子保护:

PYTHON
if allowed_special and self.special_token_pattern:
    parts = self.special_token_pattern.split(text)
    for part in parts:
        if not part:
            continue
        # 命中特殊标记:直接转为对应单一原子 ID,严禁拆散!
        if part in self.special_tokens:
            result.append(self.token_to_id[part.encode("utf-8")])
        else:
            # 普通文本才送进 SPLIT_REGEX 走常规 BPE 切分
            self._encode_chunk(part, result)

通过这一道保护闸门,无论文本多么复杂,特殊标记永远以“不可分割的单一原子 Token”精准送入神经网络,奠定了工业级条件预训练(Prefix Conditioning)的底层基石!

1.7 动手试炼:验证你的分词器

现在,在你的电脑终端里运行这个已经写好的单元测试:

BASH
python tests/test_tokenizer.py

屏幕输出实况:

TEXT
初始词表大小(含特殊标记与基础 256 字节): 264
[Tokenizer] 开始训练 BPE,初始词表大小: 264,目标词表大小: 320
[Tokenizer] 训练完成!最终词表大小: 276

--- 编解码结果 ---
原始文本: 从零手搓 Transformer 🚀 与 Tokenizer!
Token IDs: [1, 236, 195, 150, ..., 247, 196, 137, 2]
解码还原: 从零手搓 Transformer 🚀 与 Tokenizer!

--- 特殊 Token 原子提取与结构化元数据测试 ---
元数据序列: <|title|>登鹳雀楼<|author|>王之涣<|dynasty|>唐<|content|>白日依山尽,黄河入海流。</s>
元数据 Token IDs: [4, 239, 161, 195, 241, 193, 187, 241, 163, 136]...
跳过特殊标记还原: 登鹳雀楼王之涣唐白日依山尽,黄河入海流。

✅ Tokenizer 纯原生无损编解码与特殊 Token 原子保护校验 100% 通过!

看!不仅复杂的中文和英文单词被准确切分并还原,甚至连占用 4 个字节的航天火箭 Emoji 🚀 与多达 8 个专用结构化 Special Tokens 也毫发无损地被完整保护!

1.8 导师小结与课后练习

通过本章的学习,你不仅学会了如何使用分词器,更在底层吃透了它的每一个字节运转机理:

  1. UTF-8 变长字节:是我们实现“无死角编码”的物理基石;
  2. 256 个原子字节:是保证大模型永远不会报出 <UNK> 的免死金牌;
  3. 标点吸附正则:化解了古典诗词中高达 13% 的孤立标点诱惑,将标点孤立震荡降低 93%;
  4. 特殊标记原子保护:建立了结构化元数据与大模型之间的无损通道。

💡 课后动手小实验

在 Python 终端里尝试执行:

PYTHON
tok = ByteBpeTokenizer.load("data/tokenizer.json")
ids = tok.encode("<|title|>静夜思<|author|>李白<|content|>床前明月光")
print("第 0 个 ID:", ids[0])  # 看看是否等于 4 (<|title|>)?

思考一下:如果去掉 _update_special_pattern<|title|> 会被编码成几个数字?

当钥匙已经打造完毕,数字序列准备就绪,下一章,我们将正式迈入大模型的殿堂级中枢——第 02 章|从零手写现代 Transformer 架构

REFERENCES

参考链接

  1. 01Neural Machine Translation of Rare Words with Subword Units (Sennrich et al.)
  2. 02OpenAI tiktoken Byte-BPE Implementation
  3. 03Unicode Security Considerations and Regex Boundary Standards

所属系列

从零开始手搓大模型

下一步

继续浏览相关主题

沿着同一主题继续阅读。

查看最新资讯