# 吳恩達老師_深度學習_序列神經網路_第一週_循環序列模型 ###### tags: `deep learning` `Andrew Ng` ## 1-1.Why sequence models? ![](https://i.imgur.com/k2tk2wl.png) **課程說明**:那些例子有效的應用了序列模型 ### Examples of sequence data ![](https://i.imgur.com/9ImMIHi.png) * 在做語音辨視的時候,給定了一個輸入音頻片段X,要求輸出對應文字Y * 音樂生成,輸入可以是空集合,輸出的部份會是一個序列 * 情感分類,輸入是序列,輸出可能是幾顆星 * DNA分析 * 機器翻譯 * 影片動作分析,輸入是影片,輸出是識別行為 * 命名實體識別,輸入是一個句子,識別出句中的人名 可以發現種類很多,有輸入、輸出皆為序列,也有不是,長度亦不相同。 ## 1-2.Notation ![](https://i.imgur.com/sxJOG3T.png) **課程說明**:符號定義 ### Motivating example ![](https://i.imgur.com/QA1jq6i.png) 假設輸入x是一個句子,我們要判斷這句子中的人名位置,那這就是一個命名實體識別問題,這常用於搜尋引擎,比如索引過去24小時內新聞出現過的人名,也可以用於查找不同類型文件中的人名、公司名、時間、地點... 這個輸入句子有9個單字,輸出y會對應9個特徵集合來表示這9個單字(這是一個簡單的範例,實務上有更為複雜的處理方式)並按序列中的位置進行索引,以$x^{<1>},x^{<2>}.x^{<t>}..x^{<9>}$來表示,輸出的部份以$y^{<1>},y^{<2>}.y^{<t>}..y^{<9>}$。 $x^{<t>},y^{<t>}$索引序列中的位置 $T_x=9$表示輸入序列的長度 $T_y=9$表示輸出序列的長度 $x^{(i)<t>}$表示序列樣本$x^{(i)}$第$t$個索引 $T_x^{(i)}$表示樣本$x^{(i)}$的序列長度 ### Representing words ![](https://i.imgur.com/3b5l3B4.png) 在談NLP之前要先了解我們如何表示句子裡的單詞,第一件事就是建立一張詞表(VOCABULARY)(或稱字典),接著以ONE HOT的方式來記錄每一個單詞,9個單字就代表會有9個ONE HOT向量。 :::info 對一般企業來說,字典詞量約30K~50K,此課程以10K詞量說明(10000維) ::: ## 1-3.Recurrent Neural Network Model ![](https://i.imgur.com/lURoBSz.png) **課程說明**:學習如何讓輸入x映射到輸出y(循環神經網路) ### Why not a standard network? ![](https://i.imgur.com/k5PX9O6.png) 以標準神經網路來看,我們有九個單詞,輸入就是九個one hot向量,最後學習之後輸出y是否為人名的一部份,但結果來看,這效能並不會好。 問題一:輸入跟輸出會有不同的長度,每次的輸入長度也不一定相同,即使可以預先開啟一個十分大的one hot向量輸入,但這會造成學習參數過多。 問題二:無法共享從文本中學到的特徵。(不同地方學到的人名單詞無法共享) ### Recurrent Neural Network ![](https://i.imgur.com/BLsiic3.png) 開始建置RNN,首先輸入第一個單詞$x^{<1>}$(是一個one hot向量),預測輸出得到$\hat{y}^{<1>}$判斷是否為人名的一部份。 對於第二個單詞$x^{<2>}$,它不僅僅是用$x^{<2>}$就預測出$\hat{y}^{<2>}$,它還包含了上一個時步(time-step) 訊息($a^{<2>}$),以此循環計算到$x^{<T_x>}$與$\hat{y}^{<T_y>}$ RNN中,每一個時步(time-step)都會傳遞一個啟動值(activation)到下一個時步,也因此我們需要初始化$a^{<0>}$,通常為零向量<sub>(部份研究會使用非零向量,但零向量最常見)</sub>。RNN從左到右掃描資料,每個時間步的參數是共享的,這意味著$\hat{y}^{<3>}$不單是有$x^{<3>}$的信息,還包括著$x^{<1>}、x^{<2>}$,這種模式也看到一個缺點,就是$x^{<t>}$只跟之前的信息有關聯,跟之後的沒有。(後續會有BRNN說明)無法以一個句子的上下文來看的話,對單詞是否為人名的判斷是會造成誤差的。 $W_{ax}$連接著$x^{<t>}$到隱藏層的一系列參數 $W_{aa}$管理著啟動函數(水平關聯) $W_{ya}$輸出參數 :::info * 此例$T_x$與$T_y$相同,若不同結構上需做出改變 * 部份書本與論文會使用最右邊的圖來表示RNN的循環,此課程會以展開方式說明 ::: ### Forward Propagation ![](https://i.imgur.com/HX0YA8i.png) * 從$a^{<0>}$開始,它是一個零向量 * $a^{<0>}=\overrightarrow{0}$ * $a^{<1>}=g(W_{aa}a^{<0>}+W_{ax}x^{<1>}+b_a)$ * RNN較常使用tanh做啟動函數 * $\hat{y}^{<1>}$=g(W_{ya}a^{<1>}+b_y) * 啟動函數取決你的輸出 * 二分類則sigmoid * k類則softmax 整合公式: * $a^{<t>}=g(W_{aa}a^{<t-1>}+W_{ax}x^{<t>}+b_a)$ * $\hat{y}^{<t>}=g(W_{ya}a^{<t>}+b_y)$ ### Simplified RNN notation ![](https://i.imgur.com/FdMeKkY.png) 簡化公式: * $a^{<t>}=g(W_{aa}a^{<t-1>}+W_{ax}x^{<t>}+b_a)$ * $a^{<t>}=g(W_{a}[a^{<t-1>}+x^{<t>}]+b_a)$ * $W_{a}=[W_{aa}\mid W_{ax}]$ 假設$W_{aa}$=(100,100),$W_{ax}$=(100,10000)那$W_{a}=[W_{aa}\mid W_{ax}]$就會是(100,10100),$[a^{<t-1>}+x^{<t>}]$會是(10100)維的向量 * $\hat{y}^{<t>}=g(W_{ya}a^{<t>}+b_y)$ * $\hat{y}^{<t>}=g(W_{y}a^{<t>}+b_y)$ ## 1-4.Backpropagation through time ![](https://i.imgur.com/ftSX58O.png) **課程說明**:RNN中的反向傳播 ### Forward propagation and backpropagation ![](https://i.imgur.com/tMx64l0.png) ![](https://i.imgur.com/aPXsyF6.png) * 定義損失函數(loss function) * $L^{<t>}(\hat{y}^{<t>}, y^{<t>})=-y^{<t>}log\hat{y}^{<t>}-(1-y^{<t>})log(1-\hat{y}^{<t>})$ * 同logistic的損失函數(又稱交叉熵損失函數cross entropy loss) * 在某個時步上對單詞預測的損失函數 * cost function * $L(\hat{y}, y)=\sum_{t=1}^{T_y}L^{<t>}(\hat{y}^{<t>}, y^{<t>})$ * 這是一個序列的成本函數 * Forward propagation * $x^{<1>},x^{<2>}...x^{<T_x>}$ * 由$a^{<0>}$依續計算$a^{<1>},a^{<2>}...a^{<T_x>}$ * 為了計算啟動函數,會需要參數$W_a,b_a$ * 這個參數在後續每一個序列都會用到 * 有了$a^{<1>}$就可以計算出預測$\hat{y}^{<1>}$...$\hat{y}^{<T_y>}$ * 為了計算預測$\hat{y}$,需要參數$W_y,b_y$ * 這個參數在後續每一個序列都會用到 * 計算各時步的損失函數 * 加總損失函數 * Backpropagation * 紅色線 * 以梯度下降法優化更新參數 * 最重要的在紅框處,這稱為穿越時間反向傳播 * backpropagation through time ## 1-5.Different types of RNNs ![](https://i.imgur.com/jKUWnoe.png) **課程說明**:更多的RNN架構 ### Examples of sequence data ![](https://i.imgur.com/JVRp1qi.png) 這是課程一開始的各種序列神經的說明,並非所有的情況$T_x$都等於$T_y$,機器翻譯來說,不同的語言的單字數量就可以表示同一個意思。 ### Examples of RNN architectures ![](https://i.imgur.com/NPDJ5j1.png) 上圖左的部份是我們目前學習過的架構,$T_x$等於$T_y$,這種稱之為多對多結構。 上圖中是情感分析,輸入是一句評論,而輸出則是1-5的分數,這時候的輸入是一句文本,這是一種多對一的結構,RNN上不會針對每一個輸入都有一個輸出,而是在最後一個時步上得到輸出。 上圖右是一個一對一的結構,但就跟標準神經網路一樣,輸入x得到y ### Examples of RNN architectures ![](https://i.imgur.com/Rag6Acz.png) 上圖左是一對多的結構,輸入x甚至可以是一個空值,結構上輸入x,得到第一個輸出,接著沒有輸入x,繼續的得到第二個、第三、....第$T_y$輸出。 上圖右是多對多並且$T_x$不等於$T_y$的情況,首先讀入句子x的單詞$x^{<1>}...x^{<T_x>}$,再輸出$y^{<1>}...y^{<T_y>}$,這種模式有兩個區塊,前面輸入的encoder(編碼器)以及後面輸出的decoder(解碼器) ### Summary of RNN types ![](https://i.imgur.com/2D6TPfH.png) 總結各種的RNN類型,另外還有一種會在後續的課程中提到。 ## 1-6.Language model and sequence generation ![](https://i.imgur.com/allZGnr.png) **課程說明**:自然語言模型 ### What is language modelling? ![](https://i.imgur.com/Aveb1Yo.png) 什麼是自然語言模型,舉例來說,如語音辨視,一句話(如上圖範例)聽起來很像兩個可能句子,但是透過模型來計算出最高機率的那一句。自然語言模型告訴你的就是某個句子出現的概率是多少。 ### Language modelling with an RNN ![](https://i.imgur.com/brrB7HU.png) 要建置出自然語言模型,我們需要幾個工作: * 訓練一個包含很大的英文文本語料庫或其它想建置的語言的語料庫 * 語料庫是NLP(自然語言處理)的專有名詞,意指有大量英文句子的數據集 * 取讀語音 * Cats average 15 hours of sleep a day. * $y^{<1>}...y^{<EOS>}$ * 需要透過EOS讓系統知道句子的結束點 * 這並非必需,本週的程式練習就沒有用到了 * 句點的部份依需求決定是否視為其中一個輸出 * 針對句子內如果有語料庫內未有的單字可設置為UNK * 我們會只對UNK設置機率模型,而不會針對未知的單字 ### RNN model ![](https://i.imgur.com/L7zhZHq.png) Cats average 15 hours of sleep a day.\<EOS\> * time-step-0 * $a^{<0>}$,0向量 * time-step-1 * 以$x^{<1>}$為輸入,0向量 * 通過softmax($a^{<1>}$)進行預測,計算出$\hat{y}^{<1>}$ * 計算第一個單字為Cats、average、...的機率 * 可能輸出10002種結果(假設字典有10000,加上UNK與EOS) * time-step-2 * 計算第二個詞的機率 * $P(|Cats)$ * average * 啟動函數為softmax($a^{<2>}$) * $\hat{y}^{<1>}$為輸入 * 即$\hat{y}^{<1>}=x^{<2>}$ * 此例輸入為Cats * time-step-3 * 計算第二個詞的機率 * $P(|Cats average)$ * average * 啟動函數為softmax($a^{<3>}$) * $\hat{y}^{<2>}$為輸入 * 即$\hat{y}^{<2>}=x^{<3>}$ * 此例輸入為average * ....... * time-step-9 * $\hat{y}^{<8>}$為輸入 * 即$\hat{y}^{<8>}=x^{<9>}$ * 此例輸入為day 此RNN中,每一個時步都會考慮前面得到的單字,從左到右每次預測一個字。 * loss function * $L(\hat{y}^{<t\>>}, y^{<t\>>})=-\sum_i y_i^{<t\>>}log\hat{y}_i^{<t\>>}$ * cost function * $L=\sum_t L^{<t\>>}(\hat{y}^{<t\>>}, y^{<t\>>})$ 給定一個有三個單字的句子,這時候會算出機率 * $P(y^{<1>},y^{<2>},y^{<3>})=P(y^{<1>})P(y^{<2>}|y^{<1>})P(y^{<3>}|y^{<1>}y^{<2>})$ ## 1-7.Sampling novel sequences ![](https://i.imgur.com/wdYR07N.png) **課程說明**:序列採樣了解序列神經學習到什麼 ### Sampling a sequence from a trained RNN ![](https://i.imgur.com/UEtG97p.png) 一個序列模型模擬了任意特定單字序列的概率,我們要做的就是對這個概率分佈進行採樣,如下說明(基於詞彙的RNN模型): * 對第一個詞進行採樣 * $x^{<1>}、a^{<0>}$為0向量,經softmax之後得到概率 * 這概率就是你字典內的單詞以及UNK、EOS出現的概率 ```python # 對結果做取樣 numpy.random.choice ``` * 對第二個詞進行採樣 * 以剛才的取樣做下一個時步的輸入 * 取得第二個詞的預測概率 * ...以此方式取至最後 * 為了避免取樣取得了UNK,可以設置如果取得UNK就重新取樣 * 也可以不理會 ### Character-level language model ![](https://i.imgur.com/GSZkfuk.png) 依實際應用,還可以設置一個基於字符(character level)的RNN結構,你的字典就會是『a、b、c、 、,、。、A、B、C、0、9....』。 以基於字符訓練模型,序列就會是單獨的字符,上例『Cats average 15 hours of sleep a day.\<EOS\>』的輸出就不會是一個單字,$y^{<1>}$就會是C,$y^{<2>}$就會是a,$y^{<3>}$就會是t...基於字符的模型有優點會有相對的缺點 * 優點: * 不必擔心出現UNK的標誌 * 缺點: * 會得到一個過長的序列 * 訓練成本較高 目前所見較多的自然語言處理都是採用基於詞彙的模型,但隨著計算效能的提升,也會有特殊的應用採用基於字符的模型。 ### Sequence generation ![](https://i.imgur.com/TkJ5O1E.png) 在本週練習中可以自己實現出這樣的模型,左邊是訓練的文本,右邊是根據莎士比亞風格的文本自己生成的新聞稿。 ## 1-8.Vanishing gradients with RNNs ![](https://i.imgur.com/aPLKAsg.png) **課程說明**:梯度消失的問題 ### Vanishing gradients with RNNs ![](https://i.imgur.com/D3zBon0.png) 『The cat, which already ate and maybe already ate..., was full』 『The cats, which already ate and maybe already ate..., were full』 單數用was,複數用were,這是一個長期的依賴,因為最前面的單詞對後面的單詞有影響。但我們目前所學習的RNN不擅長補捉這種長期依賴效應。 之前的課程提過,如果是一個很深的深度神經網路的話,很難將$\hat{y}$的梯度傳播回去,也就是很難影響到前面層的神經網路的權重,相同的問題也存在RNN。 這代表無法讓RNN記住前面的單詞是單數還是複數來生成後面的相對應的動詞的單數或複數,何況在英文文法中,which之後可以任意長度。也因此,基本的RNN模型會有很多局部影響,但後面的輸出很難受到前面輸入的影響。 另外,隨著神經網路的深度漸深,梯度不僅可能指數型的下降,也會上升,梯度爆炸與消失的問題是不可避免的。而在訓練RNN的時候,梯度下降是首要需處理的問題,並非是梯度爆炸不會發生,而是因為它很容易被發現,因為參數會大到崩潰,你會看到很多NaN,這就代表你的數值精度已無法處理。 當發生梯度爆炸的時候,一個解決方法就是用梯度修剪(gradient clipping),所指為觀察你的梯度向量,如果大於某個閥值就縮放梯度向量,保證它不會太大,但梯度消失更難處理,這是下節課會提到的。 總結來說,我們在之前的課程知道神經網路愈深的時候就會造成導數呈指數型下降或上升,在RNN中,如果我們處理1000或10000個時間序列的數據集,那也會造成一樣的問題。 ## 1-9.Gated Recurrent Unit(GRU) ![](https://i.imgur.com/Ot7Ahev.png) **課程說明**:GRU ### RNN unit ![](https://i.imgur.com/B76Vq41.png) $a^{<t>}=g(W_a[a^{<t-1>}, x^{<t>}]+b_a)$ 我們都很清楚這是基本RNN計算啟動函式的公式(如左圖方框),當前輸入與上個時步的啟動函數乘上權重加上偏差單元。 ### GRU(simplified) ![](https://i.imgur.com/nFFYVkc.png) 『The cat, which already ate and maybe already ate..., was full』 當我們從左到右讀這個句子,GRU會有新的變數,稱為『c』,代表cell,memory cell,memory cell提供了記憶的能力,當GRU讀到was的時候它會記得前面是cat是單數或複數,於是在時步t中有了$c^{<t>}$的相關記錄。 在每個時步裡,我們會用一個候選值$\overline{c}^{<t>}$覆寫記憶單元,$\overline{c}^{<t>}=tanh(w_c[c^{<t-1>}, x^{<t>}]+b_c)$,它是個替代值,用以代替表示$c^{<t>}$。 GRU中的重點,Gate($\Gamma_u$),該值介於0與1之間,直觀來看,它是經過sigmoid計算之後所得的值($\sigma(w_u[c^{<t-1>},x^{<t>}]+b_u)$),透過sigmoid的圖示也可以了解到,$\Gamma_u$在多數情況下非常接近0或1。 $\Gamma_u$的用意在於確認是否要以$\overline{c}^{<t>}$來覆寫記憶單元,以我們的句子來看,cat是單數,我們設置了$c^{<t>}=1$(如果是複數我們就設置為0),GRU單元會記住$c^{<t>}$的值,一直到後面的動詞的時候告訴它,這是單數,所以使用was。 $\Gamma_u$即用來決定什麼時候你會需要更新這個值,它GRU看到The cat,更新為1,然後到後面吃飽了,就可以忘記它了。 $c^{<t>}=\Gamma_u*\overline{c}^{<t>}+(1-\Gamma_u)*\overline{c}^{<t-1>}$,直觀來看,當$\Gamma_u=1$即代表將此時步現值更新為候選值,當$\Gamma_u=0$即代表不要更新,一直保留舊值。 以圖示呈現的話,即如左圖,上個時步的輸出$c^{<t-1>}=a^{<t-1>}$與這個時步的輸入$x^{<t>}$,經過tanh計算出$\overline{c}^{<t>}$,再利用sigmoid計算出$\Gamma_u$,結合之後決定是否更新$c^{<t>}$,最後產出一個新的$c^{<t>}=a^{<t>}$ 而因為$\Gamma_u$非常容易接近0,也許是0.0000001或更小,這種情況下$c^{<t>}$就會等於$c^{<t-1>}$,這對維持memory cell的值有利,即使經過很多次的時步還是能夠維持住,這樣就不會有梯度消失的問題,也因此允許神經網路運行在非常龐大的詞句。 $c^{<t>}$可以是向量,其維度相等於$\overline{c}^{<t>}$與$\Gamma_u$ 在GRU中$c^{<t>}=a^{<t>}$,但在LSTMs是不相等的,為了有所區別,在GRU課程中會以不同符號說明。 ### Full GRU ![](https://i.imgur.com/wHqOeH7.png) $\overline{c}^{<t>}=tanh(w_c[\Gamma_r*c^{<t-1>}, x^{<t>}]+b_c)$ $\Gamma_u=\sigma(w_u[c^{<t-1>},x^{<t>}]+b_u)$ $c^{<t>}=\Gamma_u*\overline{c}^{<t>}+(1-\Gamma_u)*\overline{c}^{<t-1>}$ 第一個候選值的部份我們做了稍微的調整,加入了$\Gamma_r$,可以想成是相關性,讓$\Gamma_r$計算出下一個候選值跟$c^{<t>}$的相關性。 $\Gamma_r=\sigma(w_r[c^{<t-1>},x^{<t>}]+b_r)$ ## 1-10.LSTM(long short term memory)unit ![](https://i.imgur.com/0BZRDfk.png) **課程說明**:長短期記憶模型 ### GRU and LSTM ![](https://i.imgur.com/Fxb9oNY.png) $\overline{c}^{<t>}=tanh(w_c[\Gamma_r*c^{<t-1>}, x^{<t>}]+b_c)$ $\Gamma_u=\sigma(w_u[c^{<t-1>},x^{<t>}]+b_u)$ $\Gamma_r=\sigma(w_r[c^{<t-1>},x^{<t>}]+b_r)$ $c^{<t>}=\Gamma_u*\overline{c}^{<t>}+(1-\Gamma_u)*\overline{c}^{<t-1>}$ $c^{<t>}=a^{<t>}$ 這是我們在GRU中所見過的式子,在LSTM中,我們會些許調整數學式 $\overline{c}^{<t>}=tanh(w_c[a^{<t-1>}, x^{<t>}]+b_c)$ $\Gamma_u=\sigma(w_u[a^{<t-1>},x^{<t>}]+b_u)\rightarrow update$ $\Gamma_f=\sigma(w_f[a^{<t-1>},x^{<t>}]+b_f)\rightarrow forget$ $\Gamma_o=\sigma(w_o[a^{<t-1>},x^{<t>}]+b_o)\rightarrow output$ $c^{<t>}=\Gamma_u*\overline{c}^{<t>}+(\Gamma_f)*c^{<t-1>}$ $a^{<t>}=\Gamma_o*c^{<t>}$ ### LSTM in pictures ![](https://i.imgur.com/tvdNhVQ.png) 直觀的以圖示來看LSTM,雖然圖示有點複雜,但數學式來看的話並不複雜! LSTM有些版本也許不同,主要差異常$\Gamma$的考量並不只是$a^{<t-1>},x^{<t>}$,也會考量到$c^{<t-1>}$(上一個memory cell的值),這稱為peephole connection(窺視孔連接) GRU的出現比LSTM還要晚,使用上也沒有辦法明確的說出該使用那一種模型,但GRU有點類似於LSTM的簡易版,計算性能上也運行的較快。但真的要試的話,較多的人還是會選擇LSTM為首選。 ## 1-11.Bidirectional RNN ![](https://i.imgur.com/3jlXxuw.png) **課程說明**:雙向RNN ### Getting information from the future ![](https://i.imgur.com/lefQ5vt.png) 這是一個人名識別的案例『He said, Teddy bears are on sale!』『He said, Teddy Roosevelt was a great President』,一樣是『Teddy』有不同的函義,單從前面語句無法判斷。 『不管是標準的RNN或是GRU、LSTM都只有前向』 ### Bidirectional RNN(BRNN) ![](https://i.imgur.com/IIpbjye.png) 為了減化,以四個輸入說明,為$x^{<1>}~x^{<4>}$,在連接上可以看到有方向性,這是因為我們要加入一個反向連接(綠色)。 給定一個序列,依序計算出$a^{<1>}~a^{<4>}$,而反向序列則是$a^{<4>}~a^{<1>}$,這並非反向傳播,而是反向連接的前向傳播。 $y^{<t>}=g(w_y[\overrightarrow{a}^{<t>},\overlefttarrow{a}^{<t>}]+b^_y)$ 『He said, Teddy Roosevelt...』這時候所考量的就不單是前面的He said,還有後面來的資訊。不少NLP都是經由有LSTM的BRNN模型,當然標準RNN與GRU也可以如此使用。 ## 1-12.Deep RNNs ![](https://i.imgur.com/1XtKxL9.png) **課程說明**:建構更深的RNN模型 ### Deep RNN example ![](https://i.imgur.com/9E6wVR1.png) 一個標準的神經網路會堆疊很多隱藏層,最後得到輸出%\hat{y}%,在RNN也是類似的方式,對於啟動函式$a^{<t>}$,我們會加上一個符號來表式層$a^{[l]<t>}$,第$l$層第$t$個時步,堆疊上去就會有多隱藏層的RNN。 數學式則為$a^{[2]<3>}=g(w_a^{[2]}[a^{[2]<2>},a{[1]<3>}]+b_a^{{[2]}})$,這是第二層第三個時步的啟動函式,有來自前面的第二層第二個時步的資料以及第一層第三個時步的資料,注意到每一層有它自己的權重、偏差。 在RNN中,三層已經不小了,因為時間序列的維度問題,RNN網路會變的相當大,也會有較深的網路但並不做水平方向的連接,這並不限於標準RNN才可以堆疊,GRN、LSTM也可以,當然也可以BRNN,但計算成本的付出必需要注意。