Pre-tokenization

BPE 之前,
先立柵欄

上一步我們讓 BPE 自由地把常見的東西黏起來。但如果真的讓它「自由」,它會黏出你不想要的東西。

先用一條固定規則把文字剁開。BPE 只能在每一塊裡面合併,永遠不准跨過柵欄。

不立柵欄會發生什麼事。

把一小段英文直接丟給 BPE,不做任何切割。它學到的前十二條規則是這樣:

第一步就跨過了空格。到第八步,一個句點加一個空格加一個詞加一個空格被黏成單一 token。這種 token 換個標點就失效,詞表會被各種組合吃光。

那條柵欄規則,其實是一條正規表達式。

這是 GPT-2 公開的那一條 — 後來幾乎所有人都從它改。

's 't 're 've 'm 'll 'd英文縮寫,一個一個寫死在規則裡
?\p{L}+可有可無的一個空格,加上一串字母
?\p{N}+可有可無的一個空格,加上一串數字
?[^\s\p{L}\p{N}]+可有可無的一個空格,加上一串符號
\s+(?!\S) \s+剩下的空白,自成一塊

注意每一條前面那個 「可有可無的空格」:空格被黏在詞的前面。所以 the 和 the 在模型眼裡是兩個不同的東西。

自己立立看。

貼任何文字進去,看柵欄落在哪。切出來的塊數,就是 BPE 之後最多能合併到的下限。

同一句話,八種語言。

「今天天氣很好。」交給同一條柵欄規則。柵欄落在哪,差很多。

位元組數用 UTF-8 計算。塊數 = 這條規則切出幾塊。

壞法有三種,而且方向不一樣。

然後這些就變成帳單。

同樣一句「今天天氣很好」,英文 26 個位元組,印地文要 45 個。切得越碎、位元組越多,同一個意思花掉的 token 就越多。

token 花得多,代表三件事同時發生:context window 變小、API 帳單變貴、模型看到的訓練訊號更破碎。同一個模型,換一種語言就變笨又變貴 — 其中一部分的原因,早在 BPE 開跑之前的這條正規表達式裡就決定了。

最不起眼的那一步,
把每種語言的待遇先寫死了。