從2019年到現在,是時候重新審視Tokenization了

機器之心報導

編輯:陳陳

2019 年問世的 GPT-2,其 tokenizer 使用了 BPE 算法,這種算法至今仍很常見,但這種方式是最優的嗎?來自 HuggingFace 的一篇文章給出瞭解釋。

「9.9 和 9.11 到底哪個大?」這個問題一度難壞了各家大模型。

關於模型為什麼會答錯,研究人員給出了各種猜測,包括預訓練數據的構成和模型架構本身。

在一篇新博客中,來自 HuggingFace 的研究者討論了可能造成這一問題的原因之一 ——tokenization,並重點分析了它如何影響模型的數學能力,尤其是算術能力。

回顧 Tokenization

早在 2019 年,GPT-2 論文就詳細介紹了將 BPE(byte-pair encoding)用於語言模型的 tokenization 方法。此方法的工作原理是將頻繁出現的子詞合併為單個單元,直到詞彙量達到目標大小。

然而,這種做法生成的詞彙表在很大程度上取決於輸入到 tokenizer 中的訓練數據,從而導致了在數字編碼方式上的不一致性。例如,在訓練數據中常見的數字(例如 1-100、1943 年這樣的表示)很可能被表示為單個 token,而較少見到的數字則被拆分成多個 token,如下所示:

四年後,Llama 系列來了!Llama 和 Llama 2 使用 SentencePiece (一個用於基於文本生成的無監督文本 tokenizer )的 BPE 實現,並對數字進行了顯著的調整:它們將所有數字拆分為單個數字。這意味著只有 10 個唯一 token(0-9)來表示任何數字,從而簡化了 LLM 的數字表示。Deepseek 後來發佈了一個模型 (DeepSeek-V2),它有一個類似的單位數(single-digit)的 tokenizer 。

後來,Llama 3 採用了不同的方法來處理數字,將它們 tokenizing 為三位數。因此,從 1 到 999 的數字每個數都有唯一的 token,而從 1000 開始的數字由這些 token 組成。

一個新的範式:從右到左的 Tokenization

到目前為止,我們所看到的 tokenization 方法都是從左到右處理文本的。例如,如果三位數字的分詞法遇到序列 12345,它將從開頭掃瞄,將其分解為 123 和 45 這樣的片段。

與從左到右(L2R)的分詞方法不同,從右到左(R2L)的分詞方法以三個字符為一組,從文本的末尾開始向開頭處理。使用 R2L 分詞,序列 12345 將通過從右側掃瞄進行分詞,首先分割出 345,然後再處理 12。最近,一些前沿的閉源模型也在探索使用這種 R2L 分詞方法,這已經被證明對某些算術運算有益,因為 R2L 表示可以防止操作數的錯位。還有傳言稱 Claude 使用了這種 R2L 分詞方法。

為了更好地理解錯位是什麼樣子的,讓我們以 3789 + 8791 為例:

如上所示,在三位數從左到右(L2R)的例子中,9 + 1 應該映射到數字 0,但實際上卻與 8 組合在一起形成了 80,因為前面的三個 token(125)已經被分在一起了。tokenization 邊界的偏移在學習過程中引入了額外的複雜性,已經證明準確性是有害的。

而在從右到左(R2L)的例子中,數字 580 和對應的子操作數 789 和 791 很好地對齊了。

以下是用於處理數字 tokenization 的技術概述:

不同方法的比較

該研究旨在比較多個 tokenizer 以及它們處理數字的不同方式,以儘量減少模型架構、訓練配置和預訓練數據等外部因素在評估結果中的影響。因此,每個模型之間唯一的區別應該是 tokenizer。

實驗選擇了 3 種 tokenizer,分別是 GPT-2 的 BPE tokenizer、Llama 3 的三位數 tokenizer(three-digit tokenizer)和 Deepseek 的單位數 tokenizer(single-digit tokenizer)。

from transformers import AutoTokenizer

from tokenizers import pre_tokenizers, Regex

# Initialize all tokenizers

tokenizer = AutoTokenizer.from_pretrained (“meta-llama/Meta-Llama-3-8B”)

# Add an extra step to the existing pre-tokenizer steps

tokenizer._tokenizer.pre_tokenizer = pre_tokenizers.Sequence (

[

# Added step: split by R2L digits

pre_tokenizers.Split (pattern = Regex (r”\d {1,3}(?=(\d {3})*\b)”),

behavior=“isolated”, invert = False),

# Below: Existing steps from Llama 3’s tokenizer

pre_tokenizers.Split (pattern=Regex (r”(?i:’s|’t|’re|’ve|’m|’ll|’d)|[^\r\n\p {L}\p {N}]?\p {L}+|\p {N}{1,3}| ?[^\s\p {L}\p {N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+”),

behavior=“isolated”, invert=False),

pre_tokenizers.ByteLevel (add_prefix_space=False, trim_offsets=True, use_regex=False)

]

)

print (tokenizer.tokenize (“42069”)) # [42, 069]

訓練模型使用了原始的 Llama 架構,此外,該研究還調整了隱藏層的數量,以確保每個模型大致具有相同數量的參數(約 14.5 億)。

為了保持恒定的計算預算,本文減少了具有更大詞彙表模型中的隱藏層數量。

為了保持恒定的計算預算,本文減少了具有更大詞彙表模型中的隱藏層數量。

結果

算術問題

如下圖所示,單位數 tokenization 優於其他 tokenizer 方法。

結果顯示,雖然在較簡單的問題上差異不太明顯,但隨著問題複雜性的增加,表現最佳的 tokenizer(單位數分詞)與其他 tokenizer 之間的差距越來越大。這表明單位數分詞對於輸入數據長度的變化更為魯棒,並且能夠更好地捕捉複雜的模式,從而在其他分詞方法難以應對的場景中提升性能。

此外,本文還發現浮點數和整數之間的性能差距在所有 tokenizer 中都是相似的。這表明在這兩個類別中選擇 tokenizer 時,並不存在固有的權衡,即對於整數最優的 tokenizer 對於浮點數也是最優的。

如下圖所示,三位數 R2L tokenization 比標準三位數 L2R tokenization 具有更好的性能。

本文發現,與使用預設 L2R token 數據進行訓練相比,使用 R2L token 數據進行訓練的模型取得了顯著的改進(乘法除外)。這表明,與典型的從左到右編碼相比,它是算術運算的最佳設置。

當數字被從右向左每 3 位一組進行分塊時,Pure-BPE(Byte Pair Encoding)tokenizer 顯示出不一致的性能。

顯然,沒有任何額外數字預處理的純基於 BPE 的 tokenizer 不會從使用 R2L token 化中受益。一個可能的解釋是,這些 tokenizer 中數字分組的方式缺乏結構。

基於單詞的問題

雖然在基於單詞的問題上,不同 tokenizer 之間的性能差距不太明顯,但本文觀察到單位數 tokenizer 和三位數 tokenizer 通常優於基於 BPE 的 tokenizer。這表明,無論是單詞問題還是數字問題,這種趨勢都是一致的。

Llama 3 R2L 推理

接下來本文進行了另一項測試,即現有的預訓練 / 指令模型在接受與最初訓練方案不同的 token 化方案時表現如何,而無需重新訓練或微調。因此,本文基於 Llama3 8B Instruct 模型,並使用上述相同的代碼修改其 tokenizer,以在推理期間執行 R2L tokenization,而無需重新訓練新模型。

在三位數 tokenization 方案中進行兩個數相加需要注意的是:結果有時會產生比輸入數字更多的 token。例如將 999 和 111 相延長,它們單獨只需要一個 token,但是當它們相加產生 1110 時,需要兩個 token(1 和 110)。基於這個觀察,本文想探索在使用 L2R 和 R2L tokenization 對不同的 token 長度執行加法時,會產生多大的差異。

接下來,本文將把導致額外 token 的加法稱為進位(carry)加法,而那些沒有進位的加法稱為無進位(without carry)加法。

本文用 Llama3 8B Instruct 執行了不同數字長度和進位設置的算術任務。結果發現,減法、乘法或除法沒有任何顯著的性能差異,因此結果只展示了加法。

對於非進位加法,數字個數為 3 的倍數會產生完全相同的結果,因為像 528、491 這樣的數字無論 token 化方向如何都具有相同的 token。

哪種 tokenization 方法適合數學

雖然 BPE 仍然是一種流行的 tokenization 方法,但如果你必須使用具有最多 3 位數的 tokenizer,請確保數據 token 方向為 R2L。

如果你已經有一個經過訓練的模型,數據 token 方式為 L2R,那麼你可以通過使用 R2L 來獲得更好的數學性能。

最重要的是,對於算術運算,單位數 tokenization 的性能明顯優於其他方法。

總結而言,tokenization 對語言模型中的算術性能有顯著影響。通過仔細選擇,我們可以根據問題類型優化 tokenization 策略,從而提高 LLM 在數學任務上的表現。

原文鏈接:https://huggingface.co/spaces/huggingface/number-tokenization-blog