DL4-Deep Learning for Language Modeling

這個系列文章是我對李宏毅教授深度學習課程的一個筆記。

講一下用RNN做language model。那什麼是language model?

language model

他要做的事情就是估測一個word sequence(也就是一句話的概率),也就是說給你一個句子(由一串辭彙word構成的),這個w就代表的是word,例子中有n個word,這n個w合起來就是一個句子。language model要做的事情就是,你要找一個function告訴我們說這個句子出現的概率有多大。

那這件事情有什麼用呢?比如你可以用在語音辨識上面,在語音辨識上你一定需要language model,因為在做語音辨識的時候,有時候不同的word sequence,他可能有同樣的發音。

舉例來說:

  1. recognize speech和wreck a beach,他們的發音其實是一樣的(破壞一個海灘和語音辨識的英文發音是一樣的)。所以光聽語音你是沒有辦法去判斷,是破壞一個海灘還是語音辨識,所以你要通過概率來發現說語音辨識句子出現的概率比破壞海灘句子出現的概率還要大(因為我們不該常常破壞海灘),最後的output就是語音辨識。
  2. 那在翻譯的時候有時候也需要language model。
  3. 他其實還有一個很好的應用,就是sentence generation(句子的生成),如果有一個app是要讓你的machine說一句話,這個時候你就需要用到language model,machine有很多個句子是可以進行選擇的,通過language model來選擇哪個句子是最有可能的。

如果不用neural network,那傳統上language model是怎麼做的呢?

傳統方式的language model的生成

就用N-gram,那怎麼去estimate一句話的概率呢?概率這個東西,我們可以收集一個很大的data base[資料庫],去count w1-wn出現的次數。然後我們就可以知道如果說一句話的話,w1-wn他的概率是多少,但是麻煩的就是,w1-wn這個句子,在training set裡面,八成一次都沒有出現過,那要怎麼辦呢?我們要把p(w1-wn)的概率拆成比較小的component(成分),而每一個component的概率使我們可以從data base裡面估測出來的,在把每一個conponent的概率乘起來,就變成這一整個sequence的概率。

所以說N-gram的概念就是說,我們把(w1-wn)的概率拆成條件概率,而這裡面的每一個概率都是可以從training data中估測出來的,假設我們要估測p("beach|nice")的概率是多大(nice後面接beach的概率有多大的話),我們只需要計算nice beach這兩個辭彙在整個training data set裡面出現的次數再除去nice這個辭彙出現的次數,你就可以得到在nice後面接beach的概率。上面那個例子叫做2-gram model,如果你每一個component只考慮前一個word的話,這個叫做2-gram(bi-gram也就是binary gram的縮寫),如果考慮前兩個word就是3-gram...

如果用NN做language model要怎麼去做呢?先說要怎麼做。

首先要收集training data,接下來learn一個neural network,這個neural network的作用就是perdit下一個辭彙,我們lean一個neural network,他的input是潮水和退了,他的output目標就是就,然後你就用cross entropy去minimize你的network output還有他的target。input是退了和就,他的output就是知道,input是就和知道,output就是誰。NN-base language model就是這個樣子。有了neural network以後要怎麼算句子的概率呢?

我們同樣把一個句子拆成2-gram概率的相乘。但是我們現在用NN base language model的話,這些概率就不是從統計來,就不是從count data base裡面那些辭彙出現的次數來得到這個概率,這個概率就是network的output,也就是說,假設現在我們想要知道wreck放在句首的概率的話,我們需要有一個token(標記)代表說句子的起始,我們把句子的起始這件事情也當做是一個辭彙來看待,我們的neural network就input句子的起始的這一個token,然後讓他去預測wreck這個word是下一個word的概率,你把這個概率拿出來就放在上面拆分的哪個地方。然後你把wreck這個辭彙,用1-of-N encoding來表示,然後把它丟到network裡面,然後讓他predict下一個辭彙是什麼,假設世界上有十萬個辭彙,那麼他的output就有十萬維,那每一維都會有一個數字,你把wreck丟進去的話,每一個辭彙都會有一個數字代表這個辭彙是wreck這個辭彙下一個辭彙的概率,如果a的概率是多少,那麼wreck後面就是接a的概率,然後就反覆下去。把所有的詞的概率統統乘起來,就是得到這個句子的概率了。

如果今天是RNN-base language mode,他的training也是一個樣子的:

也就是說我收集了很多data,這個RNN呢?input begin的時候,他就要output潮水,input潮水他就output退了,input的退了他就output就,input就就output知道...那和NN不一樣的地方就是他在output為知道的時候,他是看了"begin","潮水","退了","就"...這麼多的辭彙,才能決定說接下來的output會是"知道",如果是NN的話,他現在的input就predictoutput,如果是RNN的話,他會看這個句子之前所有的辭彙,再決定他的output。

那要怎麼使用RNN-based language model呢?

也就是你如何去估測這個p(w1,w2,w3....wn)這個概率呢?你把RNNlearn出來以後,你就丟一個begin進去,看他在w1這個辭彙的分數也就是p(w1),接下來把w1丟進去,就得到p(w2|w1)...依次類推。然後把所有的概率統統的乘起來,你就得到一個句子的概率。

那做RNN的好處就是可以model比較long-term的information,也可以是多層的。

接下來,解釋一下,為什麼需要NN-base language model,用NN-base language model相較於傳統的model有什麼好處:

那我們先看一下傳統的N-gram的language model,傳統的最大的問題就是,哪個概率你很難估測的准,因為我們永遠沒有足夠的data,讓我們把概率真的估計的很准,尤其是當我們的N很大的時候,我們會遇到data sparsity[數據稀疏],因為我們的data不夠,所以我們沒有辦法把所有的n-gram在data base上都觀察的到。所以有一些n-gram概率,我們是估計不準的。

舉例來說:假設我的training data裡面有一個句子是"the dog ran",另一個句子是"the cat jumped"。那如果你在估計一個3-gram language model的概率的時候,"the dog"後面接"jumped"的概率就會變成是0,"the dog"後面接"ran"的概率是有值的,同理"the cat"後面接"ran"的概率就會是0,但是這件事情並不是正確的,因為"dog"不只會"jump"也會"ran","cat"不止會"jumped"還會"ran"。只是因為我們的data base太小了,如果你把全世界中所有時間的句子統統的收集起來的話,你就可以正確的用N-gram language mode估測出概率來。但是我們沒有辦法來做這件事情,所以我們估測的概率是不準的,有一些N-gram,比如"the dog"後面接"jumped",這樣的概率是0,但是實際上他並不一定是0,他其實還是有可能會出現的,但是data base不夠大,所以我們沒有辦法觀察到這件事情。所以傳統的一個解法叫做smoothing,smoothing意思就是說不要真正給一個N-gram概率為0,你給他一個小小的概率。怎樣使用smoothing其實也是一個很大的學問,這個就不在討論。

那今天用NN的話,用deep learning有什麼好處呢?

想到data sparsity[數據稀疏]的問題,你就會想到matrix factorization[矩陣因子分解]。我們可以把n-gram的概率看成是一個table,這個table其中一個dimension代表的是history,另外一個dimension代表的是vocabulary[辭彙],這個table上面的每一個element,代表的是給某一個history,他之後接下一個word的概率。比如0.2代表的是看見"cat"作為history,接下來接"jumped"的概率是0.2,所以我們可以estimate一個2-gram language mode,然後把2-gram language mode的值寫作是一個table。當然你也可以很輕易的generalize[概括]到3-gram,你把table上的history上的辭彙改成三個辭彙,就可以泛化到3-gram...,那你會發現說,在這個表格裡面,大部分的空格其實都是0。很多2-gram在你的data base裡面一次都沒有看到,所以他estimate出來的概率都是0。但是他的概率是0,不代表說他真的就是0,只是我們的data base不夠大,所以我們沒有看到。這種問題和推薦系統的問題是一樣的。所以我們可以套用推薦系統的方法來解這個問題。那如何去解呢?

每一個history,我們都用一個vector來表示他。每一個vocabulary我們也都用vector來描述他,這個v和h的dimension要是一樣的,因為一會要做他們的inner product[內積],dimension一樣的才能乘起來。這個v和h是要被學出來的,那怎麼去學他呢?你要去minimizing右下角的哪個function。我們假設這個table裡面的element都用n加上兩個下標來表示,你希望minimizing的東西就是你希望讓 v^{i} cdot h^{j} 他的值和 n_{ij} 越接近越好。接下來你用gradient descent運算一把,你就可以把v和h的vector統統都找出來,你就可以給每一個history一個vector,就可以給vocabulary每一個辭彙一個vector。接下來你就可以根據找出來的vector,把這些是0的數值空格的分數算出來,也就是說 n_{12} 就變成了 h^{1}v^{2} 。 你就可以把是0空格的哪些分數把他算出來,他們相乘的時候不會是0。

這樣的好處就是,有兩個辭彙,他們是相近的,有兩個history他們是很相近的。比如說"dog"和"cat",他們其實是很相近的,他們的 h^{dog}h^{cat} 是很接近的。如果 v^{jump}cdot h^{cat} 是很大的,那 v^{jump}cdot h^{dog} 也會跟著值很大,就算是你在training data裡面從來沒有看到過"dog"後面接"jumped",但是憑著"dog"的vector和"cat"vector很像這件事情,你就可以估測出既然"cat"和"jumped"想接的概率很大,"dog"與"jumped"相接的概率也會很大。這個和一般的smoothing不一樣,用這個matrix factorization的方法你等於也是做了smoothing,但是和一般的smoothing的方法是不一樣的,一般的smoothing方法,你是沒辦法真正的去考慮辭彙的意思是什麼,只是說這邊0.2太大減一點分給其他的詞,但是如果你今天用matrix factorization的方法,你可以真的把辭彙的意思考慮進去,你會考慮說這個"dog"和"jumped"他們這個0可能是會有值的,但是"dog"和"cried"以及"dog"和"laughed"這些值通常是比較小的。

那這個東西和NN有什麼關係呢?其實matrix factorization是可以寫成NN的,他可以寫成只有一個layer的neural network:

你可以這樣想,因為我們這邊需要考慮的是概率,所有每一個column的和都是1,他才能是概率。我們今天算的是,某一個history後面接某一個vocabulary的概率。每一個column的和必須要是1,他才是一個概率。

這邊要做一個小小的更改,我么假設"dog"這個history他的vector就是 h^{dog} 。我們可以把 h^{dog}v^{ran}做inner product,我們可以把 h^{dog}v^{cried}做inner product,對每一個vocabulary的v做inner product。每一個vocabulary就可以得到一個數值,但是這些數值的和,你沒有辦法當成概率來看,因為他的和不是1,甚至有可能是負數。那怎麼辦呢?你就做一個softmax,做一個softmax以後,你就可以把 h^{dog} cdot v^{ran} 的結果通過softmax結果看成是dog後面接ran的概率。你就可以把 h^{dog} cdot v^{caried} 的結果通過softmax的結果看成是"dog"後面接"cried"的概率。接下來在training的時候,我們知道說根據training data,假設"dog"後面接"ran"的概率是0.2。"dog"後面接"cried"的概率是0,那這個vector就是你的target。那你再learn你的參數的時候,你就會希望說,這些做完inner product的結果和這個target的cross entropy是被minimizing的。這件事情其實你就可以把想他想成就是一個NN,怎麼說呢?我們的這個history就是這個NN的input。input的dimension就是看你的history有幾個可能,假設我們今天考慮2-gram。那input每一個dimension與hidden layer相接的這些weight,就是哪一個history對應的vector,也就是對用到"cat"的哪個history,他跟hidden layer這些dimension相接的這些weight,就是 h^{cat} ,對應到"dog"哪個dimension,與之間hidden layer相接的這些value就是 h^{dog} 。那今天input就是用1-of-N encoding來表示,假設你今天看見的history是"dog"的話,用1-of-N encoding來表示的話,就是"dog"哪一維度是1,其他的都是0。你把這個vector丟到network裡面去,假設我們不考慮activation function的話,得到的就是 h^{dog} ,接下來乘以v這件事情,你就可以把他想成是另外一個layer,那把h與v做inner product這件事情想成是做另外一個layer,然後在使用softmax得到一個layer的output,然後一直train下去。這就是為什麼NN用來做language model的應用。那其實在這種n-gram language model,這種新的n-gram language model在2010年以後才比較流行。一開始用matrix factorization來做,後來發現使用NN的performance是比較好的,使用NN的話,你不僅可以迭一層,你還可以考慮RNN。

那使用NN到底會有什麼好處呢?如果我們現在比較用NN和做N-gram language model所需要的參數量,你會發現,NN所需要的參數量是比較小的,如果今天我們做n-gram language model,你需要estimate的參數,是history的數目乘上vocabulary的數目,但是在這個neural network裡面,你需要estimate的參數有多少,遠小於history的數目乘以vocabulary的數目,你要estimate的參數是每一個history要給他vector h,每一個vocabulary word都給他一個vector v,h和v的dimension不要設的太大,你neural network所需要的參數是遠小於language model所需要的參數的。也就是說假設history的數目有h的絕對值 ,vocabulary的數目是v的絕對值個,如果你今天用n-gram language model的話,你需要估測的參數是h的絕對值乘上v的絕對值,很大。如果你今天使用NN-base language model,你需要的參數是你對每一個history都有一個vector,他這個vector的dimension是可以自己決定的,假設他是k,k不要設的太大,你可以設k=100之類的,然後為每一個vocabulary都給他一個vector,這個vector的dimension也是k,這個東西其實他會遠小於這個數值,所以你使用NN的好處並不是NN很大,NN有很多層,所以他可以暴力的去fit你的model,其實不是,你用n-gram才是暴力的方法,參數很多,你用neural network的時候,你用的參數是比較少的,他比較不容易overfitting,所以你會得到比較好的performance,NN的好處通常是因為你用的參數比較少,比較不會overfitting。

那為什麼要用RNN?

使用RNN的好處就是可以更減少參數。如果今天考慮的history,非常的長,( w_{1}-w_{t} )word那麼長,前t個辭彙所組成的history有多少個可能呢?有 v^{t} 那麼多,如果你今天的word的size有10萬個,那這個可能的history數目就變成了一個天文數字,你用1-of-n encoding 描述他很顯然是不行的,這個時候,我們就可以使用RNN來描述他,RNN就是反覆使用某一個function,所以把一個function f拿出來,每次把w1丟到f裡面得到h1,依次類推,最後把wt丟進f裡面產生ht,ht就是這一整個history的representation[表示],這一整個history,我們就可以用RNN最後的output ht來表示他,不管你的history有多長,RNN的參數都不會變多,你再把ht乘上一個vocabulary裡面每一個word v,再通過softmax就可以算出每一個word的概率。那在training的時候呢?你就看說,這個history( w_{1}-w_{t} )後面 w_{t+1} 是哪一個辭彙。那你的learn target就是哪一個辭彙是1,其他都是0,其實不需要統計說( w_{1}-w_{t} )後面接的 w_{t+1} 的distribution是什麼,因為( w_{1}-w_{t} )這個辭彙在training裡面,可能就只出現一次而已,他可能不會出現兩次以上可以讓你統計出distribution,他可能就只出現一次而已,所以在實際操作上你的target,就只是一個1-hot的vector就是( w_{1}-w_{t} )後面接的 w_{t+1} 的辭彙1,其他就是0,就是一個1-hot vactor。


推薦閱讀:

筆記工具推薦
5月前兩周語錄筆記:認知升級
Golang 學習筆記三
Numpy基礎知識
《Go程序設計語言》筆記四

TAG:筆記 | 深度學習DeepLearning |