1.tiktoken是OpenAI編寫的進行高效分詞操作的庫文件。
2.操作過程:
enc = tiktoken.get_encoding("gpt2") train_ids = enc.encode_ordinary(train_data) val_ids = enc.encode_ordinary(val_data)
以這段代碼為例,get_encoding是創建了一個Encoding對象,結構如下:
{"name": "gpt2", #Encoding的名稱"pat_str": r"""'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+""", #分詞正則表達式"mergeable_ranks": {b"!": 0, b"\"": 1, ...}, # 50,000+ 條目 #存儲預加載的分詞表"special_tokens": {"<|endoftext|>": 50256}, #特殊分詞"explicit_n_vocab": 50257 #增加的特殊分詞 }
encode_ordinary是利用BPE合并來對輸入的train_data進行編碼。
BPE合并:利用預加載的mergeable_ranks字典,通過最大前綴匹配查找最大字詞映射對train_data編碼。
while current_byte in mergeable_ranks:find next byte that forms existing tokenmerge if found in ranks
3.為什么說tiktoken高效?
使用高性能語言Rust實現
避免Python解釋器開銷;直接操作字節數組,避免Python對象的創建開銷;并行處理。
基于Trie樹的高效查找
struct TrieNode {children: HashMap<u8, TrieNode>,token_id: Option<u32>, // 匹配成功時返回 token ID }
優化:Aho-Corasick 自動機,可以通過增加失敗指針fail來避免每次失敗從頭遍歷。就相當于這條路走不通,但是不會從頭走,而是會走附近的分岔路看看有沒有可以走的。
BPE合并的增量處理
fn encode_bytes(bytes: &[u8], trie: &Trie) -> Vec<u32> {let mut tokens = Vec::new();let mut start = 0;while start < bytes.len() {let (end, token_id) = trie.longest_match(&bytes[start..]);tokens.push(token_id);start += end;}tokens }
單次遍歷:在掃描過程中同時完成匹配和合并
貪心最長匹配:總是選擇可能的最長token
預加載mergeable_ranks
不需要實時建立,提高效率