上一篇只講了 Tokenizer 最快的用法,但仔細想想還是寫得再詳細一點好了
昨天的 tokenizer()
可以將一串句子變成電腦看得懂的編碼,但他其實包含三個動作
- 將句子拆分成一個一個字詞
- 將字詞轉換成編碼
- 添加 Special Token
這篇就一步一步慢慢走,解釋一下 tokenizer 底下的一些方法,也來試試上一篇底下提過的中文模型 bert-base-chinese
from transformers import AutoTokenizer
string = "臣本布衣,躬耕於南陽,苟全性命於亂世,不求聞達于諸侯。"
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
將句子拆分成字詞:.tokenize()
word = tokenizer.tokenize(string)插播一下,如果用的是英文,會發現模型的分詞器不是單純靠 空格 去區分每個詞,像
print(word)
# ['臣', '本', '布', '衣', ',', '躬', '耕', '於', '南', '陽', ',', '苟', '全', '性', '命', '於', '亂', '世', ',', '不', '求', '聞', '達', '于', '諸', '侯', '。']
transformer
就會分為 transform
和 ##er
,這個分詞法稱為 Subword Tokenization,有興趣的朋友可以看這一篇,我覺得解釋得很詳細將字詞轉換成編碼:.convert_tokens_to_ids()
id = tokenizer.convert_tokens_to_ids(word)
print(id)
# [5628, 3315, 2357, 6132, 8024, 6717, 5449, 3176, 1298, 7382, 8024, 5732, 1059, 2595, 1462, 3176, 748, 686, 8024, 679, 3724, 5472, 6888, 754, 6328, 908, 511]
會發現他只是很單純的把每個字轉成對應的編碼,並沒有標示句子開頭的 [CLS] 跟結尾的 [SEP],所以要用另外一個方法把這些 Special Token 加進去
添加 Special Token:.prepare_for_model()
token = tokenizer.prepare_for_model(id)
print(token)
# {'input_ids': [101, 5628, 3315, 2357, 6132, 8024, 6717, 5449, 3176, 1298, 7382, 8024, 5732, 1059, 2595, 1462, 3176, 748, 686, 8024, 679, 3724, 5472, 6888, 754, 6328, 908, 511, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
你會發現跟昨天的輸出結果一模一樣,因為他就是將編碼串轉換成適合輸入到模型的樣子
解碼還原:.decode()
orignal = tokenizer.decode(token['input_ids'])
print(orignal)
# [CLS] 臣 本 布 衣 , 躬 耕 於 南 陽 , 苟 全 性 命 於 亂 世 , 不 求 聞 達 于 諸 侯 。 [SEP]
其實只要做到上一步就好了,畢竟沒有必要好不容易編碼完,又再解碼回去
這邊要注意的是,因為上一步輸出的是字典,所以要指定 input_ids 這個 key 的 value
總整理
- .tokenize():將句子拆分成字詞
- .convert_tokens_to_ids():將字詞轉換成編碼
- .prepare_for_model():添加 Special Token
- 上一篇用到的 tokenizer() 就是以上三個方法的集合體
- .decode():解碼還原
喜歡我的內容也請幫我按個讚喔~非常感謝🥹