在自然語言處理(NLP)任務(wù)中,怎么處理數(shù)據(jù):即怎么把文字輸入到模型中進(jìn)行處理?
在神經(jīng)網(wǎng)絡(luò)或者說在機(jī)器學(xué)習(xí)領(lǐng)域中,數(shù)據(jù)主要以向量的形式存在,表現(xiàn)形式為多維矩陣;但怎么把現(xiàn)實(shí)世界中的數(shù)據(jù)輸入到神經(jīng)網(wǎng)絡(luò)中是機(jī)器學(xué)習(xí)的一個前提。
而現(xiàn)實(shí)世界中的數(shù)據(jù)格式雖然多種多樣,但事實(shí)上無非以下幾種主要模態(tài):
- 文字
- 圖片
- 視頻
但我們也知道,計(jì)算機(jī)只認(rèn)識數(shù)字,而不認(rèn)識文字和圖片;因此,就需要把這些數(shù)據(jù)轉(zhuǎn)換為計(jì)算機(jī)能夠識別的格式;而在神經(jīng)網(wǎng)絡(luò)模型中就是怎么把這些數(shù)據(jù)轉(zhuǎn)換為向量的格式。
簡單來說,就是把現(xiàn)實(shí)世界中的數(shù)據(jù)轉(zhuǎn)化為用多維矩陣進(jìn)行表示的過程。圖片是由多個像素點(diǎn)組成,因此天生的就可以用矩陣表示;但文字卻不同,處理起來要復(fù)雜得多。至于視頻,就是動起來的多張圖片。
文本處理
在自然語言處理任務(wù)中,要想把文本數(shù)據(jù)輸入到神經(jīng)網(wǎng)絡(luò)中,需要經(jīng)過大概以下幾個步驟:
- 分詞
- 構(gòu)建詞匯表
- 文本序列化
但為什么自然語言處理需要經(jīng)過以下幾個步驟? 下面來介紹一下每個步驟的作用:
1. 分詞
在自然語言體系中,語義是以詞或句子的形態(tài)體現(xiàn)的;因此,我們就需要去理解詞或句子的意思;但眾所周知的是,以我們漢語為例常用的詞和字就幾千個;而我們生活中絕大部分的語義都是由重復(fù)的字和詞組成的。
因此,從效率的角度來講,我們不可能把每個句子的語義都記下來;我們需要的是找到其中常用的字和詞,然后通過類似排列組合的方式組合成一個個句子。
所以,自然語言處理的第一步就是分詞;也就是說通過某種方式把句子中相同的字或詞挑出來,組成一個字詞列表。而常用的分詞技術(shù)根據(jù)不同的語言又有不同的實(shí)現(xiàn)方式;比如說在英語體系中,很多時候每個單詞就表示單獨(dú)的意思;因此最簡單的分詞方式就是把每個不同的單詞都找出來。
但在漢語言中,由于存在多音字,成語等具有復(fù)雜語言的形態(tài);因此,漢語分詞就不能使用找不同字的形式。
因此,分詞的難點(diǎn)是怎么對文本數(shù)據(jù)進(jìn)行拆分,但又不會影響到詞語本身對意思。
2. 詞匯表
理解了什么是分詞,以及為什么要分詞,那么再理解詞匯表就很簡單了;對句子進(jìn)行分詞之后,就獲取到了一個字和詞的列表;因此就可以根據(jù)這個列表來構(gòu)建詞匯表,變成讓計(jì)算機(jī)可以處理的數(shù)字格式。
學(xué)過計(jì)算機(jī)原理的應(yīng)該都知道,計(jì)算機(jī)無法直接處理文字,因此文字在計(jì)算機(jī)中是通過編碼的方式來實(shí)現(xiàn)的;比如說大名鼎鼎的ASCII碼表,就是用八位二進(jìn)制表示的。
而ASCII碼表本質(zhì)上就是一個字典結(jié)構(gòu),即使用K-V的形式來表示字符;需要計(jì)算機(jī)處理時就使用二進(jìn)制表示,需要現(xiàn)實(shí)給人看時就使用字符表示;而詞匯表就是類似ASCII碼表的形式,把字或詞作為K,把數(shù)字作為V。
這樣一個數(shù)字就可以代表一個字或詞;這樣就可以讓計(jì)算機(jī)處理。
在詞匯表中有兩個比較特殊的詞匯,那就是UNK和PAD;我們知道常用的漢字只有幾千個,但實(shí)際上的漢字有上萬個;因此,我們根據(jù)文本數(shù)據(jù)的內(nèi)容,可能并不能獲取到所有的漢字;因此遇到“沒見過”的漢字該怎么辦呢,這時就使用UNK來表示。
而在矩陣計(jì)算中,需要的是相同的矩陣形式;比如說需要5*5的固定矩陣;但在自然語言中,每個句子的長度都不一樣;短的可能就一兩個字,長的可能有幾十個字;這時變換的矩陣維度就不在相同。
dict = { "UNK_TAG": 0, "PAD_TAG": 1}
因此,就可以使用PAD對文字比較少的句子進(jìn)行補(bǔ)充;而對文字比較長的句子進(jìn)行截取。
3. 文本序列化
在經(jīng)過分詞和構(gòu)建詞匯表之后,就可以對文本進(jìn)行序列化;在自然語言處理任務(wù)中,文本需要轉(zhuǎn)換為編碼的數(shù)字進(jìn)行表示;也就是把文字變成數(shù)字表示。
dict_1 = { "UNK_TAG": 0, "PAD_TAG": 1}
dict_2 = { 0: "UNK_TAG", 1: "PAD_TAG"}
所以就有了一個從文字變成數(shù)字和從數(shù)字變成文字的過程;本質(zhì)上其實(shí)就是在詞匯表中,根據(jù)文本獲取其編碼的數(shù)字,以及根據(jù)編碼的數(shù)字獲取文字。
文本序列化最重要的一步,就是把數(shù)字表示的句子轉(zhuǎn)換成向量表示,也就是多維矩陣;而這就需要通過one-hot或者word embedding的方式來進(jìn)行序列化。
但是在使用word embedding之前,需要把句子的數(shù)字列表轉(zhuǎn)換為tensor格式。
# 將句子列表轉(zhuǎn)換為tensor
sentences_tensor = torch.tensor(sentences, dtype=torch.long)
# 定義 Embedding 層
embedding = nn.Embedding(vocab_size, embedding_dim)
# 通過 Embedding 層
embedded_sentences = embedding(sentences_tensor)