來源?| OSCHINA 社區
作者 | OneFlow深度學習框架
在 GPT 模型中,tokenization(詞元化)指的是將用戶輸入的文本分割成 token(詞元)的過程,以讓 GPT 能更好地理解輸入文本的詞義、句法和語義,以及生成更連貫的輸出內容。這是非常重要的預處理操作,對模型的最終效果有重大影響。
而 tokenizer(詞元生成器)是將文本切分成 token 的工具或組件。它將原始文本轉換成模型可處理的數字形式,為 GPT 的生成與推理提供基礎能力。
本文詳細介紹了 GPT?tokenizer?的工作原理。作者 Simon Willison 是開源 Web 應用框架 Django 的共同發起人,他也開源了用于探索和發布數據的工具 Datasette。
作者|Simon Willison
OneFlow?編譯
翻譯|賈川 語言大模型(如 GPT-3/4、LLaMA 和 PaLM)使用 token 作為基本單位進行工作。它們接受文本作為輸入,將其轉換為 token(整數),然后預測接下來應該出現哪些 token。 通過操作這些 token,可以更好地了解它們在語言模型內部的工作原理。 OpenAI 提供了一個 tokenizer,用以探索 token 的工作方式。我自己構建了一個更有意思的工具,是一個 Observable notebook(?https://observablehq.com/@simonw/gpt-tokenizer?)。在這個 Observable notebook 中,你可以將文本轉換為 token,將 token 轉換為文本,還可以搜索整個 token 表。 這個 Observable notebook 看起來是這樣的:
我在這里切分的文本是:
The dog eats the apples El perro come las manzanas 片仮名
在給定示例中,總共生成了 21 個整數 token。5 個對應英文文本,8 個對應西班牙文本,6 個(每個字符兩個)對應三個日文字符。兩個換行符也分別被表示為整數 token。 ? Observable notebook 使用了 GPT-2 的?tokenizer(基于 EJ Fox 和 Ian Johnson 所創建的?優秀 notebook?),主要作為教育工具使用,不過 GPT-3 及更高版本的最新?tokenizer?與 GPT-2 的?tokenizer?存在些許差異。 ?
1
探索一些有趣的 token
通過與?tokenizer?進行交互可以發現各種有趣的模式。?大?多數常見的英語單詞都分配一個 token,如上所示:
“The”: 464
“ dog”: 3290
“ eats”: 25365
“ the”: 262
“ apples”: 22514
需要注意的是:字母的大小寫很重要。以單詞 “the” 為例,大寫字母 T 的 “The” 對應的 token 是 464,而以小寫字母 t 開頭且有一個前導空格的單詞 “the” 對應的 token 卻是 262。 許多單詞的 token 里都包含了一個前導空格,這樣就不再需要為每個空格字符使用一個額外的 token,從而能更有效地對整個句子進行編碼, 相比英語,在對其他語言進行切分時,效率可能要低點。?西班牙語 “El perro come las manzanas” 這句話的編碼如下:
“El”: 9527
“ per”: 583
“ro”: 305
“ come”: 1282
“ las”: 39990
“ man”: 582
“zan”: 15201
“as”: 292
此處就顯示出了對英語的偏向。因為 “man” 是一個英語單詞,所以它的 token ID 較低,為 582。而 “zan” 不是一個在英語中獨立存在的單詞,但也是一個常見的字符序列,因此仍然值得擁有自己的 token,所以它的 token ID 為 15201。 有些語言甚至會出現單個字符編碼為多個 token 的情況,比如以下這些日語:
片: 31965 229
仮: 20015 106
名: 28938 235
2
故障 token
“故障 token”(glitch tokens)是一類令人著迷的 token 子集。其中一個有趣的例子是 token 23282,即 “davidjl”。 可以通過在 notebook 的搜索框中搜索 “david” 來找到該 token。
Scale AI 的 prompt 工程師 Riley Goodside 指出了與該 token 相關的一些奇怪行為。
為什么會發生這種情況?這是一個有趣的謎題。 token 23282 可能與 Reddit 上的用戶 “davidjl123” 有關。該用戶是 /r/counting 子論壇的一位熱情用戶,他經常在該論壇上發布遞增數,并且已經發布了超過 163,000 次這樣的帖子。 據推測,/r/counting 子論壇中的數據最終被用于訓練 GPT-2 的 tokenizer。由于用戶 davidjl123 在該子論壇中出現了數十萬次,所以最終分配到了屬于自己的 token。 為什么這種情況會導致類似問題呢?到目前為止,我看到最好的解釋來自 Hacker News 上的用戶 @londons_explore
這些故障 token 都位于 token 嵌入空間的中心附近。這意味著,模型在區分這些 token 和其他位于嵌入空間中心附近的 token 時存在困難,因此當被要求 “重復” 這些 token 時,模型會選擇錯誤的 token。 ? 這種情況發生的原因是,這些 token 在互聯網上出現了很多次(例如,davidjl 用戶在 Reddit 上有 163000 個帖子,僅僅是計算遞增的數字),但是這些 token 本身并不難以預測(因此,在訓練過程中,梯度變得幾乎為零,并且嵌入向量會衰減到零,這是某些優化器在歸一化權重時會進行的操作)。
在 “?SolidGoldMagikarp (plus, prompt generation)?” 這篇帖子下,LessWrong 對這種現象進行了詳細說明。
3
用 tiktoken 進行 token 計數
OpenAI 的模型都有 token 限制。有時在將文本傳遞給 API 之前,需要計算字符串中的 token 數量,以確保不超過該限制。 其中,一個需要計算 token 數量的技術是 “檢索增強生成(Retrieval Augmented Generation)”,通過對文檔語料庫運行搜索(或嵌入搜索)來回答用戶的問題,提取最有可能的內容,并將其作為上下文涵蓋在 prompt 中。 成功實現這種模式的關鍵是,在 token 限制內包含盡可能多的相關上下文,因此需要能夠計算 token 數量。 OpenAI 提供了一個名為 tiktoken(?https://github.com/openai/tiktoken?)的 Python 庫來實現這一功能。 如果你深入研究這個庫,就會發現它目前包括五種不同的切分方案:r50k_base、p50k_base、p50k_edit、cl100k_base 和 gpt2。 其中,cl100k_base 是最相關的,它是 GPT-4 和當前 ChatGPT 使用的經濟型 gpt-3.5-turbo 模型的 tokenizer。 text-davinci-003 使用的是 p50k_base 。在 tiktoken/model.py 的 MODEL_TO_ENCODING 詞典中可以找到模型與 tokenizer 的完整映射。 以下是如何使用 tiktoken 的代碼示例:
import tiktoken
encoding = tiktoken.encoding_for_model("gpt-4") # or "gpt-3.5-turbo" or "text-davinci-003" tokens = encoding.encode("Here is some text") token_count?=?len(tokens)
現在token將是一個包含四個整數token?ID的數組——在該例中是[8586,?374,?1063,?1495]。
使用.decode()方法將一個token?ID數組轉換回文本:
text?=?encoding.decode(tokens) #?'Here?is?some?text'第一次調用 encoding_for_model () 時,編碼數據將通過 HTTP 從 openaipublic.blob.core.windows.net Azure Blob 存儲桶(storage bucket)獲取(代碼:?https://github.com/openai/tiktoken/blob/0.4.0/tiktoken_ext/openai_public.py?)。這些數據會被緩存在臨時目錄中,但如果機器重新啟動,該目錄將被清除。你可通過設置 TIKTOKEN_CACHE_DIR 環境變量來強制使用更持久的緩存目錄。
4
ttok
幾周前,我介紹了?tto?k(https://github.com/simonw/ttok)?,這是 tiktoken 的一個命令行封裝工具,具有兩個關鍵功能:一是可以計算輸入給它的文本中的 token 數量,二是可以將該文本截斷為指定數量的 token。 它可以計算輸入到其中的文本中的 token 數:
?
# Count tokens echo -n "Count these tokens" | ttok # Outputs: 3 (the newline is skipped thanks to echo -n) # Truncation curl 'https://simonwillison.net/' | strip-tags -m | ttok -t 6 # Outputs: Simon Willison’s Weblog # View integer token IDs echo"Show these tokens" | ttok --tokens #?Outputs:?7968?1521?11460?198? 使用 - m gpt2 或類似選項可選擇使用適用于不同模型的編碼。
?
?
5
token 生成過程
一旦你理解了 token,那么 GPT 工具生成文本的方式就會變得更加明了。 特別有趣的是,觀察到 GPT-4 將其輸出流式化為獨立的 token(GPT-4 的速度略慢于 3.5 版本,可以更容易觀察到其生成過程)。 以下是使用我的 llm CLI(?https://github.com/simonw/llm?)工具從 GPT-4 生成文本的結果,命令是 llm -s 'Five names for a pet pelican' -4:
如你所見,不在詞典中的名字(如 “Pelly”)占據了多個 token,而 “Captain Gulliver” 作為一個整體輸出了 token “Captain”。 ?
編輯:黃飛
?
評論
查看更多