在自然語言處理中,Tokenization是將文本轉換為標記的過程。標記是文本中的最小單位,可以是單詞、字符、子詞等。Tokenization是自然語言處理的第一步,它將文本轉換為機器可讀的形式,為後續的處理提供了基礎。在本文中,我們將探討Tokenization的基本概念,以及常見的Tokenization方法。
Tokenization
Tokenization 的形式有非常多種,目前大致可以分成三大類
Character Tokenization
也就是直接把文本用字符作為最小單位進行分割,不考慮詞彙的意義。
在Python裡面我們只要使用list()
函數就可以將一個字符串轉換為字符列表。
1
2
string = 'Tokenization is a crucial step in text processing where text is split into smaller units, such as words, phrases, or symbols.'
list(string)
可以得到輸出:
1
['T', 'o', 'k', 'e', 'n', 'i', 'z', 'a', 't', 'i', 'o', 'n', ' ', 'i', 's', ' ', 'a', ' ', 'c', 'r', 'u', 'c', 'i', 'a', 'l', ' ', 's', 't', 'e', 'p', ' ', 'i', 'n', ' ', 't', 'e', 'x', 't', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', 'i', 'n', 'g', ' ', 'w', 'h', 'e', 'r', 'e', ' ', 't', 'e', 'x', 't', ' ', 'i', 's', ' ', 's', 'p', 'l', 'i', 't', ' ', 'i', 'n', 't', 'o', ' ', 's', 'm', 'a', 'l', 'l', 'e', 'r', ' ', 'u', 'n', 'i', 't', 's', ',', ' ', 's', 'u', 'c', 'h', ' ', 'a', 's', ' ', 'w', 'o', 'r', 'd', 's', ',', ' ', 'p', 'h', 'r', 'a', 's', 'e', 's', ',', ' ', 'o', 'r', ' ', 's', 'y', 'm', 'b', 'o', 'l', 's', '.']
因為機器看不懂這些字符,所以我們要對他們進行編碼,將他們Mapping到一個數字上。
首先用set()
把不重複的字符找出來,然後用enumerate()
對他們進行編碼。
1
2
map_dict = {k:v for v,k in enumerate(set(list(string)))}
print(map_dict)
可以得到輸出:
1
{'d': 0, 'r': 1, ',': 2, 'u': 3, 'T': 4, 'z': 5, 'p': 6, 'x': 7, 'c': 8, '.': 9, 'l': 10, ' ': 11, 'n': 12, 'h': 13, 's': 14, 'm': 15, 'y': 16, 'b': 17, 'i': 18, 'o': 19, 'g': 20, 'k': 21, 'a': 22, 'e': 23, 'w': 24, 't': 25}
最後再用map()
函數對字符進行編碼。
1
2
encoded_string = list(map(lambda x: map_dict[x], list(string)))
print(encoded_string)
可以得到輸出:
1
[2, 13, 4, 14, 24, 20, 25, 1, 10, 20, 13, 24, 12, 20, 16, 12, 1, 12, 0, 21, 8, 0, 20, 1, 5, 12, 16, 10, 14, 17, 12, 20, 24, 12, 10, 14, 15, 10, 12, 17, 21, 13, 0, 14, 16, 16, 20, 24, 19, 12, 18, 11, 14, 21, 14, 12, 10, 14, 15, 10, 12, 20, 16, 12, 16, 17, 5, 20, 10, 12, 20, 24, 10, 13, 12, 16, 22, 1, 5, 5, 14, 21, 12, 8, 24, 20, 10, 16, 23, 12, 16, 8, 0, 11, 12, 1, 16, 12, 18, 13, 21, 3, 16, 23, 12, 17, 11, 21, 1, 16, 14, 16, 23, 12, 13, 21, 12, 16, 6, 22, 9, 13, 5, 16, 7]
這些數字就是字符的編碼,機器可以通過這些數字來理解文本的內容,但是character tokenization的缺點非常明顯,就是完全他忽略了詞彙的意義,對於語言的理解是非常有限的。
Word Tokenization
這邊示範一個最簡單的方法,就是使用Python的split()
函數,將文本按照空格進行分割。
這個方法也叫做whitespace tokenization,它的缺點是無法處理標點符號,對於一些特殊的文本處理任務可能不夠靈活。
1
2
string = 'Tokenization is a crucial step in text processing where text is split into smaller units, such as words, phrases, or symbols.'
print(string.split())
可以得到輸出:
1
['Tokenization', 'is', 'a', 'crucial', 'step', 'in', 'text', 'processing', 'where', 'text', 'is', 'split', 'into', 'smaller', 'units,', 'such', 'as', 'words,', 'phrases,', 'or', 'symbols.']
可以看到很多的標點符號都被當作單詞的一部分,這樣對於後續的處理會不太方便使用,因此我們需要一些其他更進階的演算法來進行tokenization。
Subword Tokenization
在這個段落我會介紹一種最常見的Subword Tokenization方法 Byte Pair Encoding (BPE)。
Byte-Pair Encoding (BPE)
BPE的主要精神就是將相鄰兩個常見的字符組合成一個新的字符,然後不斷重複這個過程,直到達到指定的詞彙數量。步驟如下:
- 初始化vocabulary list,將每個字符作為一個詞彙,
</w>
則是 end-of-word 的意思。 - 將出現頻率最高的相鄰兩個字符組合成一個新的字符,並將這個字符加入vocabulary list。
- 用新的vocabulary去取代原本的字符,重複步驟2直到達到指定的vocabulary數量。
以下是一個簡單的例子:
1
2
3
4
5
vocab = {'l o w </w>' : 5,
'l o w e r </w>' : 2,
'n e w e s t </w>': 6,
'w i d e s t </w>': 3
}
一開始vocabulary list 裡面包含了所有的character:
1
</w> d e i l n o r s t w
一共有11個字符,此時相鄰的pair所對應倒的出現頻率如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
defaultdict(int,
{('l', 'o'): 7,
('o', 'w'): 7,
('w', '</w>'): 5,
('w', 'e'): 8,
('e', 'r'): 2,
('r', '</w>'): 2,
('n', 'e'): 6,
('e', 'w'): 6,
('e', 's'): 9,
('s', 't'): 9,
('t', '</w>'): 9,
('w', 'i'): 3,
('i', 'd'): 3,
('d', 'e'): 3})
出現頻率最高的相鄰兩個字符有三種,其中一種是e s
,頻率為 9,所以我們將e s
組合成一個新的字符es
,然後加入vocabulary list:
1
</w> d e i l n o r s t w es
此時再計算相鄰的pair所對應倒的出現頻率:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
defaultdict(int,
{('l', 'o'): 7,
('o', 'w'): 7,
('w', '</w>'): 5,
('w', 'e'): 2,
('e', 'r'): 2,
('r', '</w>'): 2,
('n', 'e'): 6,
('e', 'w'): 6,
('w', 'es'): 6,
('es', 't'): 9,
('t', '</w>'): 9,
('w', 'i'): 3,
('i', 'd'): 3,
('d', 'es'): 3})
可以看到es t
的頻率最高,所以我們將es t
組合成一個新的字符est
,然後加入vocabulary list:
1
</w> d e i l n o r s t w es est
接著我們一直重複以上步驟,直到達到指定的vocabulary數量為止,假設數量為16,那麼最後的vocabulary list如下:
1
</w> d e i l n o r s t w es est est</w> lo low
這樣我們就得到了一個包含16個詞彙的vocabulary list,這個list可以用來將文本轉換為subwords。
比如說我們有一個句子lowest
,我們可以用這個vocabulary list將它轉換為low est</w>
。
若是遇到一個不在vocabulary list裡面的詞彙,我們可以用<unk>
來表示。
比如說我們有一個句子fest
,我們可以用這個vocabulary list將它轉換為<unk> est</w>
。
References
[1] 台大資訊陳縕儂 深度學習之應用
[2] 大魔術熊貓工程師 - 當代的 Tokenizer algorithm
本文是我的第二篇文章,如果您喜歡,請繼續關注我的Blog :)