生活中的所有事物都是與時間相關(guān)的,也就形成了一個序列。為了對序列數(shù)據(jù)(文本、演講、視頻等)我們可以使用神經(jīng)網(wǎng)絡(luò)并導(dǎo)入整個序列,但是這樣我們的數(shù)據(jù)輸入尺寸是固定的,局限性就很明顯。如果重要的時序特征事件恰好落在輸入窗以外,就會產(chǎn)生更大的問題。所以我們需要的是:
能對任意長度序列做逐個元素讀取的神經(jīng)網(wǎng)絡(luò)(比如視頻就是一系列的圖片;我們每次給神經(jīng)網(wǎng)絡(luò)一張圖);
有記憶的神經(jīng)網(wǎng)絡(luò),能夠記得若干個時間步以前的事件、這些問題和需求已經(jīng)催生出多中不同的循環(huán)神經(jīng)網(wǎng)絡(luò)。
圖1:長短期記憶(LSTM)單元。LSTM有四個輸入權(quán)重和四個循環(huán)權(quán)重。Peepholes是記憶細(xì)胞和門之間的額外連接,但他們對性能提升幫助不到,所以常被忽略。
循環(huán)神經(jīng)網(wǎng)絡(luò)
若我們想讓一個常規(guī)的神經(jīng)網(wǎng)絡(luò)解決兩個數(shù)相加的問題,那我們只需要輸入兩個數(shù)字,再訓(xùn)練兩數(shù)之和的預(yù)測即可。如果現(xiàn)在有3個數(shù)要相加,那么我們可以:
拓展網(wǎng)絡(luò)架構(gòu),添加輸入和權(quán)重,再重新訓(xùn)練;
把第一次的輸出(即兩數(shù)之和)和第三個數(shù)作為輸入,再返回給網(wǎng)絡(luò)。
方案(2)顯然更好,因?yàn)槲覀兿M苊庵匦掠?xùn)練整個網(wǎng)絡(luò)(網(wǎng)絡(luò)已經(jīng)“知道”如何將兩個數(shù)相加)。如果我們的任務(wù)變成:先對兩數(shù)做加法,再減去兩個不同的數(shù),那這個方案又不好使了。即使我們使用額外的權(quán)重,也不能保證正確的輸出。相反,我們可以嘗試“修改程序”,把網(wǎng)絡(luò)由“加法”變成“減法”。通過隱藏層的加權(quán)可以實(shí)現(xiàn)這一步(見圖2),如此便讓網(wǎng)絡(luò)的內(nèi)核隨著每個新的輸入而變化。網(wǎng)絡(luò)將學(xué)習(xí)著在相加兩個數(shù)之后,把程序從“加法”變成“減法”,然后就解決了問題。
我們甚至可以泛化這一方法,傳遞給網(wǎng)絡(luò)兩個數(shù)字,再傳入一個“特殊”的數(shù)字——代表著數(shù)學(xué)運(yùn)算“加法”,“減法”或“乘法”。實(shí)踐當(dāng)中這樣或許不盡完美,但也能得到大體正確的結(jié)果了。不過這里的主要問題倒不在于得到正確結(jié)果,而是我們可以訓(xùn)練循環(huán)神經(jīng)網(wǎng)絡(luò),使之能夠?qū)W習(xí)任意輸入序列所產(chǎn)生的特殊輸出,這就威力大了。
例如,我們可以教網(wǎng)絡(luò)學(xué)會詞語的序列。Soumith Chintala和Wojciech Zaremba寫了一篇優(yōu)秀的博客講述用RNN做自然語言處理。RNN也可以用于生成序列。Andrej Karpathy寫了這篇[有趣而生動的博客],展示了字詞級別的RNN,可以模仿各種文風(fēng),從莎士比亞,到Linux源碼,再到給小孩兒起名。
長短期記憶(Long Short Term Memory, LSTM)
長短期記憶單元使用自連接的線性單元,權(quán)重為常數(shù)1.0。這使得流入自循環(huán)的值(前向傳播)或梯度(反向傳播)可以保持不變(乘以1.0的輸入或誤差還是原來的值;前一時間步的輸出或誤差也和下一時間步的輸出相同),因而所有的值和梯度都可以在需要的時候準(zhǔn)確回調(diào)。這個自循環(huán)的單元,記憶細(xì)胞,提供了一種可以儲存信息的記憶功能,對之前的若干個時間步當(dāng)中有效。這對很多任務(wù)都極其有效,比如文本數(shù)據(jù),LSTM可以存儲前一段的信息,并對當(dāng)前段落的序列應(yīng)用這些信息。
另外,深度網(wǎng)絡(luò)中一個很普遍的問題叫作“梯度消失”問題,也即,梯度隨著層數(shù)增多而越來越小。有了LSTM中的記憶細(xì)胞,就有了連續(xù)的梯度流(誤差保持原值),從而消除了梯度消失問題,能夠?qū)W習(xí)幾百個時間步那么長的序列。
然而有時我們會想要拋掉舊有信息,替換以更新、更相關(guān)的信息。同時我們又不想釋放無效信息干擾其余部分的網(wǎng)絡(luò)。為了解決這個問題,LSTM單元擁有一個遺忘門,在不對網(wǎng)絡(luò)釋放信息的情況下刪除自循環(huán)單元內(nèi)的信息(見圖1)。遺忘門將記憶細(xì)胞里的值乘以0~1之間的數(shù)字,其中0表示遺忘,1表示保持原樣。具體的數(shù)值宥當(dāng)前輸入和上一時間步的LSTM單元輸出決定。
在其他時間,記憶細(xì)胞還需要保持多個時間步內(nèi)不變,為此LSTM增加了另一道門,輸入門(或?qū)懭腴T)。當(dāng)輸入門關(guān)閉時,新信息就不會流入,原有信息得到保護(hù)。
另一個門將記憶細(xì)胞的輸出值乘以0(抹除輸出)~1()之間的數(shù),當(dāng)多個記憶相互競爭時這很有用:一個記憶細(xì)胞可能說:“我的記憶非常重要!所以我現(xiàn)在就要釋放”,但是網(wǎng)絡(luò)卻可能說:“你的記憶是很重要,不過現(xiàn)在又其他更重要的記憶細(xì)胞,所以我給你的輸出門賦予一個微小的數(shù)值,給其他門大數(shù)值,這樣他們會勝出”。
LSTM單元的連接方式初看可能有些復(fù)雜,你需要一些時間去理解。但是當(dāng)你分別考察各個部件的時候,會發(fā)現(xiàn)其結(jié)構(gòu)其實(shí)跟普通的循環(huán)神經(jīng)網(wǎng)絡(luò)沒啥兩樣——輸入和循環(huán)權(quán)重流向所有的門,連接到自循環(huán)記憶細(xì)胞。
想要更深入地了解LSTM并認(rèn)識整個架構(gòu),我推薦閱讀:LSTM: A Search Space Odyssey和original LSTM paper。
詞嵌入(Word Embedding)
圖3:菜譜的二維詞嵌入空間,這里我們局部放大了“南歐”的聚類群
想象"cat"和其他所有與"cat"相關(guān)聯(lián)的詞匯,你可能會想到"kitten","feline"。再想一些不那么相似,但是又比"car"要相似得多的,比如"lion","tiger","dog","animal"或者動詞"purring","mewing","sleeping"等等。
再想象一個三維的空間,我們把詞"cat"放在正中間。上面提到的詞語當(dāng)中,與"cat"相似的,空間位置也離得更近;比如"kitty","feline"就離中央很近;"tiger"和"lion"就稍微遠(yuǎn)一點(diǎn);"dog"再遠(yuǎn)一點(diǎn);而"car"就不知遠(yuǎn)到哪里去了。可以看圖3這個詞嵌入二維空間的例子。
如果我們我們用向量來代表空間里的每一個詞,那么每個向量就由3個坐標(biāo)構(gòu)成,比如"cat"是(0, 0, 0),"kitty"可能是(0,1, 0,2, -0,3)而"car"則是(10, 0, -15)。這個向量空間,就是詞嵌入空間,每個詞對應(yīng)的三個坐標(biāo)可以用做算法的輸入數(shù)據(jù)。
典型的詞嵌入空間含有上千個詞和上百個維度,人類是很難直觀理解的,但是相似的詞距離近這個規(guī)律仍然成立。對于機(jī)器來說,這是一種很好的詞匯表征,可以提高自然語言處理能力。
如果你想要學(xué)習(xí)更多詞嵌入的內(nèi)容,以及如何應(yīng)用于創(chuàng)建模型“理解”語言,推薦閱讀:Understanding Natural Language with Deep Neural Networks Using Torch,作者:Soumith Chintala和Wojciech Zaremba。
編碼-解碼
讓我們暫時停下自然語言處理,來想象一個西紅柿,想象那些適合西紅柿的配料或菜肴。如果你的想法和那些網(wǎng)上最常見的菜譜差不多,那你想到的可能是諸如奶酪和薩拉米;帕爾馬干酪、羅勒、通心粉;或其他配料比如橄欖油、百里香和西芹等等。(換作中國人來想,肯定是雞蛋)。這些配料主要都是意大利、地中海菜系。
還是那個西紅柿,如果要吃墨西哥菜系,你想到的可能是豆子、玉米、辣椒、芫荽葉或鱷梨。
你剛才所想的,就是把詞匯“西紅柿”的表征變換成了新的表征:“墨西哥菜里的西紅柿”。
“編碼”(Encoder)做的是同樣的事,它通過變換詞匯的表征,把輸入詞匯逐個變換為新的“思維向量”。就像給“西紅柿”加入了上下文“墨西哥菜”,這是“編碼-解碼”架構(gòu)的第一步。
編碼-解碼架構(gòu)的第二步是基于這樣一個事實(shí):不同的語種在詞嵌入空間里,具有相似的幾何結(jié)構(gòu),即便對同一個事物,描述用詞完全不同。比如在德語里“貓”是"Katze",狗是"Hund",與英語截然不同,但是兩個詞之間的關(guān)系確實(shí)一樣。Karze與Hund的關(guān)系,跟Car與Dog的關(guān)系完全一致,換言之,即使詞匯本身不同,他們背后的“思維向量”確實(shí)一樣的。當(dāng)然也有些詞匯很難用其他語言表達(dá)(比如中文里的“緣分”之類),但是這種情況比較稀罕,總體上是成立的。
基于以上思想,我們就可以構(gòu)建解碼網(wǎng)絡(luò)了。我們把英語編碼器產(chǎn)生的“思維向量”傳遞給德語解碼器。德語解碼器會把這些思維向量或關(guān)系變換映射到德語詞嵌入空間里,然后就會產(chǎn)生一句話,保持英語句子里的關(guān)系。如此我們就有了一個能做翻譯的網(wǎng)絡(luò),這個思想目前仍在發(fā)展,結(jié)果雖然不完美,但卻在極快提高,不久就會成為翻譯的最佳方法。