# 1. Tokenizing ## Tokenizing **Tokenizing** 是将数据(如文本)分解为更小、可管理的部分,称为 _tokens_ 的过程。每个 token 都会被分配一个唯一的数字标识符(ID)。这是为机器学习模型处理文本做准备的基本步骤,尤其是在自然语言处理(NLP)中。 > [!TIP] > 这个初始阶段的目标非常简单:**以某种合理的方式将输入划分为 tokens(ids)**。 ### **How Tokenizing Works** 1. **Splitting the Text:** - **Basic Tokenizer:** 一个简单的 tokenizer 可能会将文本拆分为单个单词和标点符号,去除空格。 - _Example:_\ 文本: `"Hello, world!"`\ Tokens: `["Hello", ",", "world", "!"]` 2. **Creating a Vocabulary:** - 为了将 tokens 转换为数字 ID,创建一个 **vocabulary**。这个 vocabulary 列出了所有唯一的 tokens(单词和符号),并为每个 token 分配一个特定的 ID。 - **Special Tokens:** 这些是添加到 vocabulary 中以处理各种场景的特殊符号: - `[BOS]`(开始序列):表示文本的开始。 - `[EOS]`(结束序列):表示文本的结束。 - `[PAD]`(填充):用于使批次中的所有序列具有相同的长度。 - `[UNK]`(未知):表示不在 vocabulary 中的 tokens。 - _Example:_\ 如果 `"Hello"` 被分配 ID `64`,`","` 是 `455`,`"world"` 是 `78`,`"!"` 是 `467`,那么:\ `"Hello, world!"` → `[64, 455, 78, 467]` - **Handling Unknown Words:**\ 如果像 `"Bye"` 这样的单词不在 vocabulary 中,它将被替换为 `[UNK]`。\ `"Bye, world!"` → `["[UNK]", ",", "world", "!"]` → `[987, 455, 78, 467]`\ _(假设 `[UNK]` 的 ID 是 `987`)_ ### **Advanced Tokenizing Methods** 虽然基本的 tokenizer 对于简单文本效果良好,但在处理大型 vocabulary 和新词或稀有词时存在局限性。高级 tokenizing 方法通过将文本分解为更小的子单元或优化 tokenization 过程来解决这些问题。 1. **Byte Pair Encoding (BPE):** - **Purpose:** 通过将稀有或未知单词分解为频繁出现的字节对,减少 vocabulary 的大小并处理稀有或未知单词。 - **How It Works:** - 从单个字符作为 tokens 开始。 - 迭代地将最频繁的 token 对合并为一个单一的 token。 - 继续直到没有更多频繁的对可以合并。 - **Benefits:** - 消除了对 `[UNK]` token 的需求,因为所有单词都可以通过组合现有的子词 tokens 来表示。 - 更高效和灵活的 vocabulary。 - _Example:_\ `"playing"` 可能被 tokenized 为 `["play", "ing"]`,如果 `"play"` 和 `"ing"` 是频繁的子词。 2. **WordPiece:** - **Used By:** 像 BERT 这样的模型。 - **Purpose:** 类似于 BPE,它将单词分解为子词单元,以处理未知单词并减少 vocabulary 大小。 - **How It Works:** - 从单个字符的基础 vocabulary 开始。 - 迭代地添加最频繁的子词,以最大化训练数据的可能性。 - 使用概率模型决定合并哪些子词。 - **Benefits:** - 在拥有可管理的 vocabulary 大小和有效表示单词之间取得平衡。 - 高效处理稀有和复合单词。 - _Example:_\ `"unhappiness"` 可能被 tokenized 为 `["un", "happiness"]` 或 `["un", "happy", "ness"]`,具体取决于 vocabulary。 3. **Unigram Language Model:** - **Used By:** 像 SentencePiece 这样的模型。 - **Purpose:** 使用概率模型确定最可能的子词 tokens 集合。 - **How It Works:** - 从一组潜在的 tokens 开始。 - 迭代地移除那些对模型的训练数据概率提升最小的 tokens。 - 最终确定一个 vocabulary,其中每个单词由最可能的子词单元表示。 - **Benefits:** - 灵活且可以更自然地建模语言。 - 通常会导致更高效和紧凑的 tokenizations。 - _Example:_\ `"internationalization"` 可能被 tokenized 为更小的、有意义的子词,如 `["international", "ization"]`。 ## Code Example 让我们通过来自 [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch02/01_main-chapter-code/ch02.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch02/01_main-chapter-code/ch02.ipynb) 的代码示例更好地理解这一点: ```python # Download a text to pre-train the model import urllib.request url = ("https://raw.githubusercontent.com/rasbt/LLMs-from-scratch/main/ch02/01_main-chapter-code/the-verdict.txt") file_path = "the-verdict.txt" urllib.request.urlretrieve(url, file_path) with open("the-verdict.txt", "r", encoding="utf-8") as f: raw_text = f.read() # Tokenize the code using GPT2 tokenizer version import tiktoken token_ids = tiktoken.get_encoding("gpt2").encode(txt, allowed_special={"[EOS]"}) # Allow the user of the tag "[EOS]" # Print first 50 tokens print(token_ids[:50]) #[40, 367, 2885, 1464, 1807, 3619, 402, 271, 10899, 2138, 257, 7026, 15632, 438, 2016, 257, 922, 5891, 1576, 438, 568, 340, 373, 645, 1049, 5975, 284, 502, 284, 3285, 326, 11, 287, 262, 6001, 286, 465, 13476, 11, 339, 550, 5710, 465, 12036, 11, 6405, 257, 5527, 27075, 11] ``` ## 参考文献 - [https://www.manning.com/books/build-a-large-language-model-from-scratch](https://www.manning.com/books/build-a-large-language-model-from-scratch)