之前整理過(guò)齋藤康毅的深度學(xué)習(xí)神作《深度學(xué)習(xí)入門(mén):基于Python的理論與實(shí)現(xiàn)》,對(duì)小白非常友好,它沒(méi)有用任何的現(xiàn)成框架(比如pyTorch、tensorFlow等等),而是直接用python自帶的庫(kù)手把手教你,從如何實(shí)現(xiàn)梯度下降開(kāi)始到手磕一個(gè)CNN經(jīng)典網(wǎng)絡(luò),讓你不再對(duì)深度學(xué)習(xí)框架的內(nèi)部機(jī)制感到神秘。
短短幾年,這位大佬再度出了“續(xù)集”—《深度學(xué)習(xí)進(jìn)階:自然語(yǔ)言處理》[1]?。梢哉f(shuō)是NLP入門(mén)必讀的經(jīng)典著作了?。?/p>
小齋這次的寫(xiě)作風(fēng)格和前作一樣,都是手把手教你從實(shí)現(xiàn)詞向量開(kāi)始,像搭積木一樣,再到如何實(shí)現(xiàn)經(jīng)典網(wǎng)絡(luò)NLP屆的界的經(jīng)典網(wǎng)絡(luò)RNN、LSTM、seq2seq和Attention等NLP中重要的深度學(xué)習(xí)技術(shù)。
(太感人了,這次終于要搞懂詞向量究竟是個(gè)什么鬼了!(逃
凡我不能創(chuàng)造的,我就不能理解。
— 理查德·費(fèi)曼(致敬費(fèi)曼)
話不多說(shuō),這次我不再整理的和上個(gè)系列一樣那么詳細(xì)(繁冗)了(個(gè)人覺(jué)得沒(méi)必要,那樣整理還不如直接看書(shū)來(lái)的直接痛快。所以這一次我會(huì)摘取基礎(chǔ)又重要的部分,如果你想再詳細(xì)深究下去,乖,去參考原書(shū)噢!
本書(shū)用到的庫(kù):
Numpy
Matplotlib
(真的是只用了這兩個(gè)基本庫(kù)!(強(qiáng)
如果要用GPU加速運(yùn)算的話,再加一個(gè)CuPy庫(kù)。
作者強(qiáng)調(diào),自己動(dòng)手的經(jīng)驗(yàn)、花時(shí)間思考的經(jīng)驗(yàn),都是無(wú)法復(fù)制的。(所以,聽(tīng)話,要自己嘗試敲1敲代碼噢!
本書(shū)第一章為上一本書(shū)神經(jīng)網(wǎng)絡(luò)的復(fù)習(xí),咱直接跳到第二章 從詞向量開(kāi)始
正文開(kāi)始
目錄
什么是自然語(yǔ)言處理?
同義詞詞典
基于計(jì)數(shù)的方法
基于計(jì)數(shù)的方法改進(jìn)
必做練習(xí)
-
語(yǔ)料庫(kù)的預(yù)處理。實(shí)現(xiàn)分詞(將文本分割成單詞,以單詞為最小單元輸入給模型)
-
單詞ID化(將單詞用ID來(lái)表示,相當(dāng)于給每一個(gè)單詞編個(gè)代號(hào),和我們學(xué)生編個(gè)學(xué)號(hào)一個(gè)意思,方便定位和管理唄)
-
利用共現(xiàn)矩陣表示文本的詞向量。
(這些練習(xí)會(huì)在后續(xù)搭建模型的時(shí)候用得到噢!相當(dāng)于我們先造積木,之后搭網(wǎng)絡(luò)就有素材啦!本章的詞向量表示也就是對(duì)文本進(jìn)行預(yù)處理的準(zhǔn)備工作?。?/span>
注意:全文的講解都是以
(存在一個(gè)問(wèn)題 —> 找到解決辦法 —> 新的解決辦法又有什么問(wèn)題 —> 又找到解決辦法 )的思路一步一步引出各種概念和解決方案的。
我們的學(xué)習(xí)過(guò)程也是如此,市面上突然出現(xiàn)的各種模型也是如此,了解它解決了什么問(wèn)題也就知道亂七八糟的各種模型為什么會(huì)出現(xiàn)了。
什么是自然語(yǔ)言處理?
-
自然語(yǔ)言:就是我們平常使用的語(yǔ)言,如漢語(yǔ)、英語(yǔ);
-
自然語(yǔ)言處理:就是讓機(jī)器理解人類(lèi)的語(yǔ)言,理解了人類(lèi)語(yǔ)言才能對(duì)我們的語(yǔ)言進(jìn)行進(jìn)一步解讀和分析!(比如對(duì)人類(lèi)的情感進(jìn)行分析、對(duì)文本進(jìn)行分類(lèi)、能夠?qū)崿F(xiàn)人機(jī)對(duì)話等等)
在沒(méi)有深度學(xué)習(xí)的時(shí)候,專(zhuān)家們是這樣進(jìn)行詞向量的表示的:
同義詞詞典
最著名的同義詞詞典當(dāng)屬WordNet [2]啦。WordNet等同義詞詞典中對(duì)大量單詞人工的定義了同義詞和層級(jí)結(jié)構(gòu)關(guān)系等。
同義詞詞典存在的問(wèn)題
-
難以順應(yīng)時(shí)代的變化。語(yǔ)言是活的,新詞會(huì)不斷出現(xiàn)。
-
人力成本高,WordNet收錄了超過(guò)20W個(gè)單詞。
-
無(wú)法表示單詞的微妙差異。即使是含義相近的單詞,也有細(xì)微的差別。比如,vintage 和retro(類(lèi)似復(fù)古的意思)雖然表示相同的含義,但是用法不同,而這種細(xì)微的差別在同義詞詞典中是無(wú)法表示出來(lái)的(讓人來(lái)解釋是相當(dāng)困難的)。
Marty:“This is heavy (棘手).”
Dr. Brown:“In the future, things are so heavy (重)?”
— 電影《回到未來(lái)》
在電影《回到未來(lái)》中,有這樣一個(gè)場(chǎng)景:從1985 年穿越回來(lái)的馬蒂和生活在1955年的的博士的對(duì)話中,對(duì)“heavy”的含義有不同的理解。如果要處理這樣的單詞變化,就需要人工不停地更新同義詞詞典。
基于計(jì)數(shù)的方法(基于統(tǒng)計(jì))
目標(biāo):從海量文本數(shù)據(jù)中自動(dòng)提取單詞含義,減少人為干擾。
-
語(yǔ)料庫(kù)(corpus):就是我們輸入模型的大量文本,比如句子、文章等等。
這里將用一句話作為語(yǔ)料庫(kù)來(lái)闡述接下來(lái)的所有概念。
'you say goodbye and I say hello.' > text =
語(yǔ)料庫(kù)的預(yù)處理
1、進(jìn)行句子的分詞,并標(biāo)記每個(gè)單詞的ID。(就像給每個(gè)學(xué)生編上學(xué)號(hào)ID一樣,方便后續(xù)指定某一個(gè)學(xué)生呀!)
>>>text=text.lower()//將所有單詞轉(zhuǎn)化為小寫(xiě)
>>>text=text.replace('.','.')//使句號(hào)其和前一個(gè)單詞分開(kāi)
>>>text
'yousaygoodbyeandisayhello.'
>>>words=text.split('')//切分句子
>>>words
['you', 'say', 'goodbye', 'and', 'i', 'say', 'hello', '.'] //由八個(gè)詞組成的數(shù)組
首先,使用lower()方法將所有單詞轉(zhuǎn)化為小寫(xiě),這樣可以將句子開(kāi)頭的單詞也作為常規(guī)單詞處理。然后,將空格作為分隔符,通過(guò)split(' ')切分句子??紤]到句子結(jié)尾處的句號(hào)(.),我們先在句號(hào)前插人一個(gè)空格(即用 ' .'替換'.'),再進(jìn)行分詞。
2、我們進(jìn)一步給單詞標(biāo)上 ID,以便使用單詞 ID 列表,方便為后續(xù)對(duì)每個(gè)單詞進(jìn)行操作。
將單詞列表轉(zhuǎn)化為單詞 ID 列表,然后再將其轉(zhuǎn)化為 NumPy 數(shù)組。
word_to_id={}//將單詞轉(zhuǎn)化為單詞ID
id_to_word={}//將單詞ID轉(zhuǎn)化為單詞(鍵是單詞ID,值是單詞)
forwordinwords:
ifwordnotinword_to_id:
//如果單詞不在word_to_id中,則分別向word_to_id和id_to_word添加新ID和單詞
new_id=len(word_to_id)
word_to_id[word]=new_id
id_to_word[new_id] = word
corpus = np.array([word_to_id[w] for w in words])
如果單詞不在 word_to_id 中,則分別向 word_to_id 和id_to_word 添加新 ID 和單詞
如下為創(chuàng)建好了單詞 ID 和單詞的對(duì)應(yīng)表
>id_to_word
{0:'you',1:'say',2:'goodbye',3:'and',4:'i',5:'hello',6:'.'}
>word_to_id
{'you': 0, 'say': 1, 'goodbye': 2, 'and': 3, 'i': 4, 'hello': 5, '.': 6}
最后,我們將單詞列表轉(zhuǎn)化為單詞 ID 列表,然后再將其轉(zhuǎn)化為 NumPy 數(shù)組。
>corpus
array([0, 1, 2, 3, 4, 1, 5, 6])
將第一步和第二步封裝為一個(gè)preprocess() 函數(shù),使用這個(gè)函數(shù),可以按如下方式對(duì)語(yǔ)料庫(kù)進(jìn)行預(yù)處理。( 代碼在common/util.py)
輸入要處理的語(yǔ)料庫(kù)text,輸出corpus, word_to_id, id_to_word
'You say goodbye and I say hello.' > text =
>corpus,word_to_id,id_to_word=preprocess(text)
corpus 是單詞ID 列表,word_to_id 是單詞到單詞 ID 的字典,id_to_word 是單詞 ID 到單詞的字典。
語(yǔ)料庫(kù)的預(yù)處理已完成。這里準(zhǔn)備的 corpus、word_to_id 和 id_to_word 這 3 個(gè)變量名在本書(shū)接下來(lái)的很多地方都會(huì)用到。
接下來(lái)的目標(biāo)就是使用語(yǔ)料庫(kù)提取單詞含義,這里先使用基于計(jì)數(shù)的方法,也就是基于統(tǒng)計(jì)的方法,能夠得到詞向量?。ㄒ簿褪菍卧~表示為向量)
分布式假說(shuō)(distributional hypothesis)
-
分布式假說(shuō)(distributional hypothesis):某個(gè)單詞的含義由它周?chē)膯卧~形成。(某個(gè)人存在的價(jià)值由它的社會(huì)屬性構(gòu)成?!蚁拐f(shuō)的)
單詞本身沒(méi)有含義,單詞含義由它所在的上下文(語(yǔ)境)形成。
比如“I drink beer.” “We drink wine.” , drink 的附近常有飲料出現(xiàn)。
另外,從“I guzzle beer.” “We guzzle wine.”可知,guzzle 和 drink 所在的語(yǔ)境相似。進(jìn)而我們可以推測(cè)出guzzle 和 drink 是近義詞(guzzle 是“大口喝”的意思) 。
基于這一假說(shuō),我們就可以通過(guò)單詞的上下文來(lái)表示該單詞。如圖,左側(cè)和右側(cè)的 2 個(gè)單詞就是上下文。
這里的窗口大小可以控制你需要關(guān)心多少單詞的上下文。顯而易見(jiàn),關(guān)心的上下文單詞數(shù)越多,單詞的含義越準(zhǔn)確,但是所需要的存儲(chǔ)量就越大,看你自己的取舍咯!這里簡(jiǎn)單起見(jiàn),窗口大小為1。
如何基于分布式假設(shè)使用向量表示單詞,最直截了當(dāng)?shù)膶?shí)現(xiàn)方法是對(duì)周?chē)鷨卧~的數(shù)量進(jìn)行計(jì)數(shù)。
共現(xiàn)矩陣(co-occurrence matrix)
-
共現(xiàn)矩陣(co-occurrence matrix):用上下文共同出現(xiàn)的單詞次數(shù)作為該單詞的向量。即若兩個(gè)單詞挨著出現(xiàn)一次,次數(shù)加一。
上面已經(jīng)處理好語(yǔ)料庫(kù)了,接下來(lái)構(gòu)建共現(xiàn)矩陣,也就是計(jì)算每個(gè)單詞的上下文所包含的單詞的頻數(shù)。在這個(gè)例子中,我們將窗口大小設(shè)為 1,從單詞 ID 為 0 的 you 開(kāi)始。
單詞 you 的上下文僅有 say 這個(gè)單詞,如下圖所示。
所以單詞you可表示為:
即可以用向量 [0, 1, 0, 0, 0, 0, 0] 表示單詞 you。其他單詞也是重復(fù)如此操作。
于是得到了共現(xiàn)矩陣:
接下來(lái),我們來(lái)實(shí)際創(chuàng)建一下上面的共現(xiàn)矩陣。
將圖 2-7 的結(jié)果按原樣手動(dòng)輸入。
C=np.array([
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ], ], dtype=np.int32)
這就是共現(xiàn)矩陣。使用這個(gè)共現(xiàn)矩陣,可以獲得各個(gè)單詞的向量,如下所示。
print(C[0])#單詞ID為0的向量
#[0100000]
print(C[4])#單詞ID為4的向量
#[0101000]print(C[word_to_id['goodbye']])#goodbye的向量
# [0 1 0 1 0 0 0]
我們通過(guò)共現(xiàn)矩陣成功地用向量表示了單詞。但手動(dòng)輸入共現(xiàn)矩陣太麻煩,這一操作顯然可以自動(dòng)化。下面,我們來(lái)實(shí)現(xiàn)一個(gè)能直接從語(yǔ)料庫(kù)生成共現(xiàn)矩陣的函數(shù)。
通過(guò)函數(shù)create_co_matrix()能直接從語(yǔ)料庫(kù)生成共現(xiàn)矩陣。(代碼實(shí)現(xiàn)在common/util.py)
其中參數(shù) corpus 是單詞 ID 列表,參數(shù) vocab_ size 是詞匯個(gè)數(shù),window_size 是窗口大小。
defcreate_co_matrix(corpus,vocab_size,window_size=1):
corpus_size=len(corpus)
co_matrix = np.zeros((vocab_size, vocab_size), dtype=np.int32)
foridx,word_idinenumerate(corpus):
foriinrange(1,window_size+1):
left_idx=idx-i
right_idx=idx+i
ifleft_idx>=0:
left_word_id=corpus[left_idx]
co_matrix[word_id,left_word_id]+=1
ifright_idx
right_word_id=corpus[right_idx]
co_matrix[word_id,right_word_id]+=1
return co_matrix
首先,用元素為 0 的二維數(shù)組對(duì) co_matrix 進(jìn)行初始化。然后,針對(duì)語(yǔ)料庫(kù)中的每一個(gè)單詞,計(jì)算它的窗口中包含的單詞。同時(shí),檢查窗口內(nèi)的單詞是否超出了語(yǔ)料庫(kù)的左端和右端。
這樣一來(lái),無(wú)論語(yǔ)料庫(kù)多大,都可以自動(dòng)生成共現(xiàn)矩陣。之后,我們都將使用這個(gè)函數(shù)生成共現(xiàn)矩陣。
到這里我們終于第一次成功的用向量表示單詞啦!將正式邁入文本詞向量表示的道路!
寫(xiě)到這發(fā)現(xiàn)篇幅太長(zhǎng)了,為了能有更好的學(xué)習(xí)體驗(yàn),接下來(lái)共現(xiàn)矩陣存在的問(wèn)題以及改進(jìn)方式就下一篇再見(jiàn)啦!
責(zé)任編輯:xj
原文標(biāo)題:小白跟學(xué)系列之手把手搭建NLP經(jīng)典模型(含代碼)
文章出處:【微信公眾號(hào):深度學(xué)習(xí)自然語(yǔ)言處理】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
模型
+關(guān)注
關(guān)注
1文章
3123瀏覽量
48664 -
自然語(yǔ)言處理
+關(guān)注
關(guān)注
1文章
603瀏覽量
13489 -
nlp
+關(guān)注
關(guān)注
1文章
486瀏覽量
21993
原文標(biāo)題:小白跟學(xué)系列之手把手搭建NLP經(jīng)典模型(含代碼)
文章出處:【微信號(hào):zenRRan,微信公眾號(hào):深度學(xué)習(xí)自然語(yǔ)言處理】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論