文章目錄
引言
本文是吳恩達深度學習第五課:序列模型。本次課程將會學到如何爲自然語言、語言和其他序列數據構建模型。會了解如何構建並訓練一個循環神經網絡,和常用的變體,比如GRU和LSTM。能應用序列模型到自然語音處理,包括情感分析。能應用序列模型到語音應用,包括語音識別和智能作曲。
第五課有以下三個部分,本文是第一部分。
- 循環神經網絡
- 自然語音處理與詞嵌入
- 序列模型與注意力機制
序列模型能解決什麼問題
所有的這些問題都可以使用有標籤數據作爲訓練集,以監督學習的方式來解決。但是從中可以看到有很多不同的序列問題。
有的問題都爲序列,比如語音識別問題中。
有的問題可以有不同的長度,比如情感分類和命名識別識別。
下面幾節探討的是如何構建序列模型。
符號定義
我們先從符號定義開始,一步一步構建序列模型。
假如你要構建的序列模型,它的輸入語句是這樣的。
假設你想建立一個序列模型,能自動識別語句中人名的位置,這種問題是命名實體識別問題。
給定一個這樣的輸入,你想要一個序列模型輸出,使得輸入的每個單詞都對應一個輸出值。同時能表示對應的單詞是否是人名的一部分。
作爲輸入的序列數據中只有9個單詞,所以我們會得到9組特徵來代表9個單詞。並按序列中的位置進行索引,用上標<1>
到<9>
來索引不同的位置。
用來表示輸入序列的長度,用來表示輸出序列的長度。
表示第個樣本序列中的第個元素。
並且訓練集裏不同的訓練樣本可以有不同的長度,表示第個樣本輸入序列的長度。
在自然語言處理問題中,一件優先需要解決的問題是如何表示一個序列裏單獨的單詞。
常用的方法是做一張詞表(詞典),
在本例中,詞典的大小爲10000。如果你想要構建一個這樣的詞典,那麼需要到你的訓練集中去查找出現頻率最高的1萬的單詞,或者用網上的字典。然後通過one-hot形式來表示每個單詞。
比如單詞Harry背表示爲一個向量,向量的大小和詞典一樣大,只有單詞Harry的位置爲1,其餘都爲0。
這個例子中,我們就有9個one-hot向量。如果遇到不在詞典中的單詞怎麼辦,常用的辦法是創建一個未知單詞標記,來表示不在詞典中的單詞。
循環神經網絡
關於循環神經網絡個人覺得李宏毅老師講的比較好,課堂筆記見循環神經網絡
現在我們來探討一下如何建一個神經網絡模型來學習到的映射。
先看一下如果我們使用標準的網絡要怎樣解決這個問題。
輸出是1或0,表示對應的單詞是否是人名的一部分。
但是這個網絡結構並不好,爲什麼呢,來看一下:
- 輸入和輸出在不同的樣本中可以有不同的長度
- 這種結構就無法滿足這種靈活性
- 沒有共享文本序列不同位置上學到的特徵
- 比如已經學到了出現在位置1的Harry是人名的一部分,如果Harry出現在其他位置時,應該也要能識別爲人名的一部分。但普通的神經網絡不具備這種性質。
我們要學習的循環神經網絡就沒有這個缺點。
我們用循環神經網絡來解決這個問題,如果從左到右的順序處理這個文本序列,那麼先將第一個單詞輸入到神經網絡。
在將第二個單詞輸入到神經網絡時,循環神經網絡不僅通過輸入來決定,還利用了時間步1的激活值。
剩下的輸入也是這樣
所以在每一個時間步中,循環神經網絡都傳遞了一個激活值到下一個時間步中,這裏指定了一個初始的激活值,,一般是零向量。
從這裏可以看到,循環神經網絡是從左向右掃描數據,同時每個時間步的參數也是共享的。控制從到隱藏層的參數,在每個時間步都是相同的(其實這就是同一個神經網絡,只不過按照讀入順序展開了而已)。
然後激活值是由參數決定的,輸出結果是由決定的。
這裏要指出的是,後面的輸出是由前面所有輸入影響的。比如輸出不僅由輸入決定,還受的影響。
從這裏可以看到這個網絡有一個缺點是,它只用到了之前的信息做決定,沒有用到後面的信息。
比如爲了判斷Teddy是否是人名的一部分,僅僅知道He ,said, Teddy這幾個詞是不夠的,如果能知道後面的信息會更有幫助。
下面這段話中的Teddy就不是人名。
Teddy bear are on sale(泰迪熊在售)
所以這種網絡的缺點是在某一時刻的預測只使用了該時間點序列之前的信息。
我們寫出這個神經網絡所做的計算。
介紹下命名,這裏下標中的表示要乘以的值,這裏要乘以;而下標中的表示要計算的值,整個式子是要計算。
RNN中計算的激活函數通常是Tanh。
而計算輸出的激活函數根據業務的不同選擇也會不同。
計算時刻的公式如下:
這些公式定義了RNN神經網絡的前向傳播。
爲了更好的描述更加複雜的神經網絡,我們簡化一下上面這些公式表示。
把和按列疊加起來得到。
這個符號表示按行堆疊起來。這樣一來右邊的等式和左邊的等式是一樣的。
第二個等式也簡化了一下表示。
穿越時光反向傳播
我們上一節中已經學過了正向傳播的計算,而反向傳播的方向是與正向傳播剛好相反的。如紅色箭頭所示。
前向傳播的計算可以這樣表示出來,每次計算都使用相同的參數。
有了的值之後就可以計算。
爲了計算反向傳播,我們需要一個損失函數,假設這裏做的是命名識別識別,識別是否爲人名,並且輸出概率。
那麼對於這種是否的二分類問題,我們可以使用交叉熵損失函數。
計算每個時間點的損失,累加起來就是總體的損失函數。
反向傳播就是從損失函數開始,驗證相反的反向求梯度。
在這個反向傳播的過程中,最重要的信息傳遞就是上圖粉色框框出來的那部分,在計算正向傳播時,從左到右,時間點不斷增加;而計算反向傳播時,時間點不斷減小,就像時光倒流一樣。
不同類型的循環神經網絡
我們在第一節中看過這些例子。下面看我們如何設計RNN來處理這些情況。
先來看下的情況。
這是一種多對多的結構,這種我們已經見過了。下面來看處理情感分類問題中,輸入是一個句子,輸出可能是0/1(正面評價/負面評價),或者是1-5(評分)。
這種是多對一的情況,輸入一個句子,最終纔得到一個輸出。除了有多對一的結構,還有一對多。
那就是音樂生成,在這個例子中,輸入可以是一個整數(可能表示想要的音樂類型,或第一個音符),輸出就是一段音樂。
在多對多的例子中,還有可能輸入長度和輸出長度是不一樣的。
比如在機器翻譯中,會有兩種結構,左邊的是編碼器,用來讀取輸入。右邊的是解碼器,用來進行翻譯。
最後還有一種簡單的一對一的結構。
語言模型和序列生成
在本節中我們來學習如何用RNN來構建一個語言模型。
以語音識別爲例來解釋語言模型。
在語音識別中,假設有人說了這樣一個句子。但是pair和pear的發音相近,那麼應該識別成哪句話呢,其實這裏可以根據經驗,即出現哪個單詞的概率最大,就輸出哪個單詞。
使用語言模型,能計算出每句話出現的可能性。
假設計算出這兩句話的概率如上,我們就知道應該選第二句話。具體的是估計句子中每個單詞出現的概率。
那麼如何建立一個語言模型呢,你需要一個很大的語料庫,比如英文文本語料庫。
語料庫:數量很多的句子組成的文本
假設你的訓練集中有這樣一句話,貓一天睡15個小時。我們要生成這樣一句話。
第一件要做的事情是向量化這個句子,需要一個很大的詞典,然後轉換爲one-hot向量。
在這之前,先進行標記化(標記這個句子),可能還要定義一個句尾標識。
在標記化的過程中,可以考慮是否識別標點符號。
如果你遇到了一些不在你字典中的詞彙,那麼可以把這些詞彙標記爲未知(UNK)。
在完成了標記化後,我們將輸入句子的每個單詞,映射到了字典中的各個詞上。
接下里需要構建一個RNN來建立這些序列的概率模型。
在第0個時間步,需要通過softmax來預測第一個詞的概率,此時和都是零向量。
通過softmax來預測字典中任意詞彙會是第一個詞的概率。假設我們字典大小爲10000的話,那麼就會有10002個結果(加上了UNK和EOS)。這裏假設輸出的是cats。
接下來計算出第二個詞會是什麼。
這裏輸入是正確的第一個單詞,然後輸出是考慮給定第一個詞爲cats的條件下,第二詞最有可能是什麼。
按照這樣的方式就可以生成整個句子。爲了訓練這個網絡,我們需要定義代價函數,因爲用到了softmax函數,我們可以用softmax損失函數。
如果用了很大的訓練集來訓練這個RNN,你就可以通過開頭的一些單詞,來預測之後單詞的概率。
也可以計算新句子出現的概率。
第一個softmax輸出告訴你,第二個告訴你,第三個softmax層輸出。把這些概率相乘就是這個新句子出現的概率。
這就是用RNN來訓練一個語言模型。
對新序列採樣
在我們訓練了一個序列模型以後,我們可以通過採樣新的序列來了解它學到了什麼。
假設我們已經訓練好這樣一個模型,那如何採樣呢。
輸入都是零向量,第一個輸出輸出了字典中每個詞出現的概率。然後用numpy.random.choice
隨機選擇一個單詞。
在採樣第二個單詞時,這裏輸入的生成的第一個單詞。即計算給定第一個單詞的情況下,每個單詞出現的概率。
重複這個步驟,知道遇到了句子結尾標誌(EOS),此時說明句子生成完畢了。如果沒有EOS的話,那麼需要定義一個句子的長度。
這樣我們就構建好了一個字級(詞彙級)RNN,如果詞典中是每個字符,那麼構建的就是字符級RNN。
RNN的梯度消失問題
以語言模型的例子爲例,假設要生成的句子爲The cat(cats) ,which already ate …,was(were) full.
在英語中要考慮單複數,如果前面是cat,那麼後面就是was;如果前面是cats,後面就是were。
在這個例子中,後面的單詞對前面的單詞有長期的依賴,但是我們現在見過的基本RNN模型無法處理這種長期依賴。
這個問題和我們之前看到的很深的網絡一樣,假設這裏有100層,由於梯度消失的問題,輸出的梯度很難傳遞到最前面的幾層。RNN同樣有這個問題。
這是基本RNN的一個缺點,我們下面幾節會看到如何處理這個問題。
在很深的神經網絡中,還存在梯度爆炸的問題,導致參數值過大,然後出現很多NaN的情況。這是數值過大導致計算結果溢出。
梯度爆炸有一個解決方法是梯度修剪(gradient clipping),就是設定一個閾值,當梯度向量超過某個閾值時,將它減少到閾值。
然而梯度消失問題更難解決,因此也是我們下幾節重點考慮的。
GRU單元
我們已經見過這個公式了,這裏的激活函數是tanh函數。畫出RNN單元的話如下,
我們將會使用類似的圖片來介紹門控循環單元(GRU)。
Cho et al., 2014. On the properties of neural machine translation: Encoder-decoder approaches
Chung et al., 2014. Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling.
還是以這個句子爲例,這裏是單數,後面應該是was,現在我們來看下GRU單元會怎麼做。
GRU單元會有個新的變量,c
,代表記憶細胞。可以記住前面是單數還是複數。
對於GRU來說,的值等於。在每個時間步,我們將用一個候選值來覆蓋記憶細胞內的值,這個候選值的計算公式如下:
在GRU中真正重要的思想是,我們有一個門,它的值在0到1之間,可以控制是否更新記憶細胞內的值。
把tanh中的式子代入sigmoid函數即可得到0到1之間的值。
通過tanh函數計算候選值,通過sigmoid函數來判斷是否更新值,
可以這麼理解,假設單數的cat 的c值爲1,然後我們一直存儲它,直到was的位置,就知道前面爲單數。而門決定什麼時候更新這個值。
下面寫出門控制更新的式子:
可以看到,但門的值爲1時,就用候選值覆蓋細胞內的值;否則當門值爲0時,則保存細胞內的值不變。
下面畫出GRU的示意圖。
上圖中紫色部分就是上面帶有門的那個公式。
GRU的優勢是,當從左到右掃描一個句子的時候,通過門來決定是否要更新記憶細胞內的值,這個例子句子中是已知保存細胞內的值,直到was的位置。
只要sigmoid的參數值是一個很大的負數,那麼整個sigmoid就容易取到零值,就很容易保持細胞的值不變。
這樣即使經過很多的時間步,值也能被保留,這樣就能緩解梯度消失的問題。
可以是一個向量,候選值和門值都和它是同樣的維度。如果門控是100維向量,可以把它看成是100位(bit)的值,它告訴你這個100維記憶單元哪一位是你想要更新的。
對位元素進行元素乘法的做法,只是一位一位的告訴GRU單元,在記憶細胞中哪個向量的維度在每步計算時需要更新,因此可以選擇更新其他位時保持某些位不變。 比如用1位來保存貓的單複數,用一些其他的位來標識談論的內容是食物(裏面出現了eat這個詞)。
我們上面介紹的實際上是一個簡化版的GRU單元,下面看下完整的GRU單元。
這是我們之前介紹的公式,這裏要改寫一下。再增加一個控制門,這個門告訴你如何通過來計算下一個候選值。
長短記憶網絡(LSTM)
除了GRU可以讓你在序列中學習比較深的連接,其他類型的單元也可以做到這一點,比如LSTM。
Hochreiter & Schmidhuber 1997. Long short-term memory
LSTM是一個比GRU更強大和通用的單元。
它的計算式子如下:
一個LSTM的新特性是,它不只有一個更新門控制,還有一個(遺忘門),以及一個新的sigmoid的輸出門(輸出門)。
最後記憶細胞的更新如上。可以結合下面這個圖來理解。
最後輸出門主要控制了輸出的取值。
所以LSTM有三個門,還是看一下吳老師畫的圖吧。
用與分別計算了遺忘門,更新門和輸出門的結果。
然後通過tanh函數來計算候選值。
你可以生成一堆類似的單元,然後根據時序將它們連接起來。
前一個時間步的輸出是下個時間步的輸入。圖中上部有一條流程直線(紅色的線)表示如何計算,只要你恰當的設置了遺忘門和更新門,LSTM可以相對簡單地將的值傳遞到圖的右側。
這就是爲什麼LSTM可以長時間記住某些數值的原因。
雙向RNN神經網絡
我們已經學習了RNN網絡的基礎構建,但還有兩個想法可以讓你建立更強大的模型,一個是雙向RNN,它可以讓你在一個時間步同時獲得序列中前部分和後部分的信息;第二個是深層RNN,會在下節中介紹。
爲了引入雙向RNN,我們先看下這個網絡,這個網絡的一個問題是,爲了弄清楚第三個單詞Teddy是否爲人名的一部分,我們只考慮句子的前半部分是不夠的,因此這是單向(正向)RNN的缺點。
一個雙向RNN(BRNN)可以解決這個問題。BRNN的工作原理如下:
現在看到的還只是正向(前向遞歸層)的部分,下面來畫出反向(後向遞歸層)的部分。
給定一個輸入序列,到。前向序列將首先計算,然後是,直到。
相反地,後向序列將從開始,反向計算,直到。
注意,以上都是前向傳播,有一部分是從左到右,另一部分是從右到左。
計算完了所有的激活值後,就可以做出預測了。預測的公式如下:
比如在輸出時,這樣左邊和右邊的信息都能考慮到。
BRNN的缺點是,需要整個序列,然後才能在任何地方進行預測。
深層RNN
在學習非常複雜的函數,有時把多層RNN結構堆疊在一起,形成更深層的模型會更有幫助。
在本節我們將看到如何構建這些深層的RNN。
假設構建了一個3層的RNN。
上圖是我們所見過的標準RNN,這裏更改了一些符號,比如輸入表示時刻0的第一層的激活值。
把它們堆疊到一起就得到了下圖:
因爲我們要同時考慮激活值的層數和時間點。下面我們看一下如何計算這個數值,以爲例,看如何計算。
它有一個來自底部的輸入,和一個來自左邊的輸入。
對於RNN來說,有三層已經算很多了,因爲時間這一維度的存在,使得即使只有很少的層數的網絡也會變得很大。