吳恩達deeplearning.ai系列課程筆記+編程作業(13)序列模型(Sequence Models)-第一週 循環序列模型(Recurrent Neural Networks)

第五門課 序列模型(Sequence Models)

第一週 循環序列模型(Recurrent Neural Networks)


本週編程作業見:

1.1 爲什麼選擇序列模型?(Why Sequence Models?)

       循環神經網絡(RNN)之類的模型在語音識別、自然語言處理和其他領域中引起變革。我們先看一些例子,這些例子都有效使用了序列模型。
       在這裏插入圖片描述
       在進行語音識別時,給定了一個輸入音頻片段 X X ,並要求輸出對應的文字記錄 Y Y 。這個例子裏輸入和輸出數據都是序列模型,因爲 X X 是一個按時播放的音頻片段,輸出 Y Y 是一系列單詞。所以之後將要學到的一些序列模型,如循環神經網絡等等在語音識別方面是非常有用的。

       音樂生成問題是使用序列數據的另一個例子,在這個例子中,只有輸出數據 Y Y 是序列,而輸入數據可以是空集,也可以是個單一的整數,這個數可能指代你想要生成的音樂風格,也可能是你想要生成的那首曲子的頭幾個音符。輸入的 X X 可以是空的,或者就是個數字,然後輸出序列 Y Y

       在處理情感分類時,輸入數據 X X 是序列,你會得到類似這樣的輸入:「There is nothing to like in this movie.」,你認爲這句評論對應幾星?

       系列模型在DNA序列分析中也十分有用,你的DNA可以用ACGT四個字母來表示。所以給定一段DNA序列,你能夠標記出哪部分是匹配某種蛋白質的嗎?

       在機器翻譯過程中,你會得到這樣的輸入句:「Voulez-vou chante avecmoi?」(法語:要和我一起唱麼?),然後要求你輸出另一種語言的翻譯結果。

       在進行視頻行爲識別時,你可能會得到一系列視頻幀,然後要求你識別其中的行爲。

       在進行命名實體識別時,可能會給定一個句子要你識別出句中的人名。

       所以這些問題都可以被稱作使用標籤數據 ( X , Y ) (X,Y) 作爲訓練集的監督學習但從這一系列例子中你可以看出序列問題有很多不同類型。有些問題裏,輸入數據 X X 和輸出數據 Y Y 都是序列,但就算在那種情況下, X X Y Y 有時也會不一樣長。或者像上圖編號1所示和上圖編號2的 X X Y Y 有相同的數據長度。在另一些問題裏,只有 X X 或者只有 Y Y 是序列。

       所以在本節我們學到適用於不同情況的序列模型。

1.2 數學符號(Notation)

       本節先從定義符號開始一步步構建序列模型。

       比如說你想要建立一個序列模型,它的輸入語句是這樣的:「Harry Potter and Herminoe Granger invented a new spell.」,(這些人名都是出自於J.K.Rowling筆下的系列小說Harry Potter)。假如你想要建立一個能夠自動識別句中人名位置的序列模型,那麼這就是一個命名實體識別問題,這常用於搜索引擎,比如說索引過去24小時內所有新聞報道提及的人名,用這種方式就能夠恰當地進行索引。命名實體識別系統可以用來查找不同類型的文本中的人名、公司名、時間、地點、國家名和貨幣名等等。
       在這裏插入圖片描述
       現在給定這樣的輸入數據 x x ,假如你想要一個序列模型輸出 y y ,使得輸入的每個單詞都對應一個輸出值,同時這個 y y 能夠表明輸入的單詞是否是人名的一部分。技術上來說這也許不是最好的輸出形式,還有更加複雜的輸出形式,它不僅能夠表明輸入詞是否是人名的一部分,它還能夠告訴你這個人名在這個句子裏從哪裏開始到哪裏結束。比如Harry Potter(上圖編號1所示)、Hermione Granger(上圖標號2所示)。

       更簡單的那種輸出形式:

       這個輸入數據是9個單詞組成的序列,所以最終我們會有9個特徵集和來表示這9個單詞,並按序列中的位置進行索引, x < 1 > x^{<1>} x < 2 > x^{<2>} x < 3 > x^{<3>} 等等一直到 x < 9 > x^{<9>} 來索引不同的位置,我將用 x < t > x^{<t>} 來索引這個序列的中間位置。 t t 意味着它們是時序序列,但不論是否是時序序列,我們都將用 t t 來索引序列中的位置。

       輸出數據也是一樣,我們還是用 y < 1 > y^{<1>} y < 2 > y^{<2>} y < 3 > y^{<3>} 等等一直到 y < 9 > y^{<9>} 來表示輸出數據。同時我們用 T x T_{x} 來表示輸入序列的長度,這個例子中輸入是9個單詞,所以 T x = 9 T_{x}= 9 。我們用 T y T_{y} 來表示輸出序列的長度。在這個例子裏 T x = T y T_{x} =T_{y} ,上一節裏你知道 T x T_{x} T y T_{y} 可以有不同的值。

       你應該記得我們之前用的符號,我們用 x ( i ) x^{(i)} 來表示第 i i 個訓練樣本,所以爲了指代第 t t 個元素,或者說是訓練樣本i的序列中第 t t 個元素用 x ( i ) < t > x^{\left(i \right) <t>} 這個符號來表示。如果 T x T_{x} 是序列長度,那麼你的訓練集裏不同的訓練樣本就會有不同的長度,所以 T x ( i ) T_{x}^{(i)} 就代表第 i i 個訓練樣本的輸入序列長度。同樣 y ( i ) < t > y^{\left( i \right) < t>} 代表第 i i 個訓練樣本中第 t t 個元素, T y ( i ) T_{y}^{(i)} 就是第 i i 個訓練樣本的輸出序列的長度。

       所以在這個例子中, T x ( i ) = 9 T_{x}^{(i)}=9 ,但如果另一個樣本是由15個單詞組成的句子,那麼對於這個訓練樣本, T x ( i ) = 15 T_{x}^{(i)}=15

       既然我們這個例子是NLP,也就是自然語言處理,這是我們初次涉足自然語言處理,一件我們需要事先決定的事是怎樣表示一個序列裏單獨的單詞,你會怎樣表示像Harry這樣的單詞, x < 1 > x^{<1>} 實際應該是什麼?

       接下來我們討論一下怎樣表示一個句子裏單個的詞。想要表示一個句子裏的單詞,第一件事是做一張詞表,有時也稱爲詞典,意思是列一列你的表示方法中用到的單詞。這個詞表(下圖所示)中的第一個詞是a,也就是說詞典中的第一個單詞是a,第二個單詞是Aaron,然後更下面一些是單詞and,再後面你會找到Harry,然後找到Potter,這樣一直到最後,詞典裏最後一個單詞可能是Zulu
       在這裏插入圖片描述

       因此a是第一個單詞,Aaron是第二個單詞,在這個詞典裏,and出現在367這個位置上,Harry是在4075這個位置,Potter在6830,詞典裏的最後一個單詞Zulu可能是第10,000個單詞。所以在這個例子中我用了10,000個單詞大小的詞典,這對現代自然語言處理應用來說太小了。對於商業應用來說,或者對於一般規模的商業應用來說30,000到50,000詞大小的詞典比較常見,但是100,000詞的也不是沒有,而且有些大型互聯網公司會用百萬詞,甚至更大的詞典。許多商業應用用的詞典可能是30,000詞,也可能是50,000詞。不過我將用10,000詞大小的詞典做說明,因爲這是一個很好用的整數。

       如果你選定了10,000詞的詞典,構建這個詞典的一個方法是遍歷你的訓練集,並且找到前10,000個常用詞,你也可以去瀏覽一些網絡詞典,它能告訴你英語裏最常用的10,000個單詞,接下來你可以用one-hot表示法來表示詞典裏的每個單詞。
       在這裏插入圖片描述
       舉個例子,在這裏 x < 1 > x^{<1>} 表示Harry這個單詞,它就是一個第4075行是1,其餘值都是0的向量(上圖編號1所示),因爲那是Harry在這個詞典裏的位置。

       同樣 x < 2 > x^{<2>} 是個第6830行是1,其餘位置都是0的向量(上圖編號2所示)。

       and在詞典裏排第367,所以 x < 3 > x^{<3>} 就是第367行是1,其餘值都是0的向量(上圖編號3所示)。如果你的詞典大小是10,000的話,那麼這裏的每個向量都是10,000維的。

       因爲a是字典第一個單詞, x < 7 > x^{<7>} 對應a,那麼這個向量的第一個位置爲1,其餘位置都是0的向量(上圖編號4所示)。

       所以這種表示方法中, x < t > x^{<t>} 指代句子裏的任意詞,它就是個one-hot向量,因爲它只有一個值是1,其餘值都是0,所以你會有9個one-hot向量來表示這個句中的9個單詞,目的是用這樣的表示方式表示 X X ,用序列模型在 X X 和目標輸出 Y Y 之間學習建立一個映射。我會把它當作監督學習的問題,我確信會給定帶有 ( x y ) (x,y) 標籤的數據。

       那麼還剩下最後一件事,我們將在之後討論,如果你遇到了一個不在你詞表中的單詞,答案就是創建一個新的標記,也就是一個叫做Unknow Word的僞造單詞,用<UNK>作爲標記,來表示不在詞表中的單詞,我們之後會討論更多有關這個的內容。

       總結一下本節課的內容,我們描述了一套符號用來表述你的訓練集裏的序列數據 x x y y ,在下節課我們開始講述循環神經網絡中如何構建 X X Y Y 的映射。

1.3 循環神經網絡模型(Recurrent Neural Network Model)

       上節中,你瞭解了我們用來定義序列學習問題的符號。現在我們討論一下怎樣才能建立一個模型,建立一個神經網絡來學習 X X Y Y 的映射。

       可以嘗試的方法之一是使用標準神經網絡,在我們之前的例子中,我們有9個輸入單詞。想象一下,把這9個輸入單詞,可能是9個one-hot向量,然後將它們輸入到一個標準神經網絡中,經過一些隱藏層,最終會輸出9個值爲0或1的項,它表明每個輸入單詞是否是人名的一部分。
       在這裏插入圖片描述
       但結果表明這個方法並不好,主要有兩個問題,

       一、是輸入和輸出數據在不同例子中可以有不同的長度,不是所有的例子都有着同樣輸入長度 T x T_{x} 或是同樣輸出長度的 T y T_{y} 。即使每個句子都有最大長度,也許你能夠填充(pad)或零填充(zero pad)使每個輸入語句都達到最大長度,但仍然看起來不是一個好的表達方式。

       二、一個像這樣單純的神經網絡結構,它並不共享從文本的不同位置上學到的特徵。具體來說,如果神經網絡已經學習到了在位置1出現的Harry可能是人名的一部分,那麼如果Harry出現在其他位置,比如 x &lt; t &gt; x^{&lt;t&gt;} 時,它也能夠自動識別其爲人名的一部分的話,這就很棒了。這可能類似於你在卷積神經網絡中看到的,你希望將部分圖片裏學到的內容快速推廣到圖片的其他部分,而我們希望對序列數據也有相似的效果。和你在卷積網絡中學到的類似,用一個更好的表達方式也能夠讓你減少模型中參數的數量。

       之前我們提到過這些(上圖編號1所示的 x &lt; 1 &gt; x^{&lt;1&gt;} …… x &lt; t &gt; x^{&lt;t&gt;} …… x &lt; T x &gt; x^{&lt; T_{x}&gt;} )都是10,000維的one-hot向量,因此這會是十分龐大的輸入層。如果總的輸入大小是最大單詞數乘以10,000,那麼第一層的權重矩陣就會有着巨量的參數。但循環神經網絡就沒有上述的兩個問題

       那麼什麼是循環神經網絡呢?我們先建立一個(下圖編號1所示)。如果你以從左到右的順序讀這個句子,第一個單詞就是,假如說是 x &lt; 1 &gt; x^{&lt;1&gt;} ,我們要做的就是將第一個詞輸入一個神經網絡層,第一個神經網絡的隱藏層,我們可以讓神經網絡嘗試預測輸出,判斷這是否是人名的一部分。循環神經網絡做的是,當它讀到句中的第二個單詞時,假設是 x &lt; 2 &gt; x^{&lt;2&gt;} ,它不是僅用 x &lt; 2 &gt; x^{&lt;2&gt;} 就預測出 y ^ &lt; 2 &gt; {\hat{y}}^{&lt;2&gt;} ,他也會輸入一些來自時間步1的信息。具體而言,時間步1的激活值就會傳遞到時間步2。然後,在下一個時間步,循環神經網絡輸入了單詞 x &lt; 3 &gt; x^{&lt;3&gt;} ,然後它嘗試預測輸出了預測結果 y ^ &lt; 3 &gt; {\hat{y}}^{&lt;3&gt;} ,等等,一直到最後一個時間步,輸入了 x &lt; T x &gt; x^{&lt;T_{x}&gt;} ,然後輸出了 y ^ &lt; T y &gt; {\hat{y}}^{&lt; T_{y} &gt;} 。至少在這個例子中 T x = T y T_{x} =T_{y} ,同時如果 T x T_{x} T y T_{y} 不相同,這個結構會需要作出一些改變。所以在每一個時間步中,循環神經網絡傳遞一個激活值到下一個時間步中用於計算。
       在這裏插入圖片描述
       要開始整個流程,在零時刻需要構造一個激活值 a &lt; 0 &gt; a^{&lt;0&gt;} ,這通常是零向量。有些研究人員會隨機用其他方法初始化 a &lt; 0 &gt; a^{&lt;0&gt;} ,不過使用零向量作爲零時刻的僞激活值是最常見的選擇,因此我們把它輸入神經網絡。

       在一些研究論文中或是一些書中你會看到這類神經網絡,用這樣的圖形來表示(上圖編號2所示),在每一個時間步中,你輸入 x &lt; t &gt; x^{&lt;t&gt;} 然後輸出 y &lt; t &gt; y^{&lt;t&gt;} 。然後爲了表示循環連接有時人們會像這樣畫個圈,表示輸回網絡層,有時他們會畫一個黑色方塊,來表示在這個黑色方塊處會延遲一個時間步。我個人認爲這些循環圖很難理解,所以在本次課程中,我畫圖更傾向於使用左邊這種分佈畫法(上圖編號1所示)。不過如果你在教材中或是研究論文中看到了右邊這種圖表的畫法(上圖編號2所示),它可以在心中將這圖展開成左圖那樣。

       循環神經網絡是從左向右掃描數據,同時每個時間步的參數也是共享的,所以下頁幻燈片中我們會詳細講述它的一套參數,我們用 W ax W_{\text{ax}} 來表示管理着從 x &lt; 1 &gt; x^{&lt;1&gt;} 到隱藏層的連接的一系列參數,每個時間步使用的都是相同的參數 W ax W_{\text{ax}} 。而激活值也就是水平聯繫是由參數 W a a W_{aa} 決定的,同時每一個時間步都使用相同的參數 W a a W_{aa} ,同樣的輸出結果由 W ya W_{\text{ya}} 決定。下圖詳細講述這些參數是如何起作用。
       在這裏插入圖片描述
       在這個循環神經網絡中,它的意思是在預測 y ^ &lt; 3 &gt; {\hat{y}}^{&lt; 3 &gt;} 時,不僅要使用 x &lt; 3 &gt; x^{&lt;3&gt;} 的信息,還要使用來自 x &lt; 1 &gt; x^{&lt;1&gt;} x &lt; 2 &gt; x^{&lt;2&gt;} 的信息,因爲來自 x &lt; 1 &gt; x^{&lt;1&gt;} 的信息可以通過這樣的路徑(上圖編號1所示的路徑)來幫助預測 y ^ &lt; 3 &gt; {\hat{y}}^{&lt;3&gt;} 。這個循環神經網絡的一個缺點就是它只使用了這個序列中之前的信息來做出預測,尤其當預測 y ^ &lt; 3 &gt; {\hat{y}}^{&lt;3&gt;} 時,它沒有用到 x &lt; 4 &gt; x^{&lt;4&gt;} x &lt; 5 &gt; x^{&lt;5&gt;} x &lt; 6 &gt; x^{&lt;6&gt;} 等等的信息。所以這就有一個問題,因爲如果給定了這個句子,「Teddy Roosevelt was a great President.」,爲了判斷Teddy是否是人名的一部分,僅僅知道句中前兩個詞是完全不夠的,還需要知道句中後部分的信息,這也是十分有用的,因爲句子也可能是這樣的,「Teddy bears are on sale!」。因此如果只給定前三個單詞,是不可能確切地知道Teddy是否是人名的一部分,第一個例子是人名,第二個例子就不是,所以你不可能只看前三個單詞就能分辨出其中的區別。

       所以這樣特定的神經網絡結構的一個限制是它在某一時刻的預測僅使用了從序列之前的輸入信息並沒有使用序列中後部分的信息,我們會在之後的雙向循環神經網絡(BRNN)的講解中處理這個問題。但對於現在,這個更簡單的單向神經網絡結構就夠我們來解釋關鍵概念了,之後只要在此基礎上作出修改就能同時使用序列中前面和後面的信息來預測 y ^ &lt; 3 &gt; {\hat{y}}^{&lt;3&gt;} ,不過我們會在之後講述這些內容,接下來我們具體地寫出這個神經網絡計算了些什麼。
       在這裏插入圖片描述

       這裏是一張清理後的神經網絡示意圖,和我之前提及的一樣,一般開始先輸入 a &lt; 0 &gt; a^{&lt;0&gt;} ,它是一個零向量。接着就是前向傳播過程,先計算激活值 a &lt; 1 &gt; a^{&lt;1&gt;} ,然後再計算 y &lt; 1 &gt; y^{&lt;1&gt;}

        a &lt; 1 &gt; = g 1 ( W a a a &lt; 0 &gt; + W a x x &lt; 1 &gt; + b a ) a^{&lt;1&gt;} = g_{1}(W_{{aa}}a^{&lt; 0 &gt;} + W_{{ax}}x^{&lt; 1 &gt;} + b_{a})

        y ^ &lt; 1 &gt; = g 2 ( W y a a &lt; 1 &gt; + b y ) \hat y^{&lt; 1 &gt;} = g_{2}(W_{{ya}}a^{&lt; 1 &gt;} + b_{y})

       我將用這樣的符號約定來表示這些矩陣下標,舉個例子 W ax W_{\text{ax}} ,第二個下標意味着 W ax W_{\text{ax}} 要乘以某個 x x 類型的量,然後第一個下標 a a 表示它是用來計算某個 a a 類型的變量。同樣的,可以看出這裏的 W ya W_{\text{ya}} 乘上了某個 a a 類型的量,用來計算出某個 y ^ \hat {y} 類型的量。

       循環神經網絡用的激活函數經常是tanh,不過有時候也會用ReLU,但是tanh是更通常的選擇,我們有其他方法來避免梯度消失問題,我們將在之後進行講述。選用哪個激活函數是取決於你的輸出 y y ,如果它是一個二分問題,那麼我猜你會用sigmoid函數作爲激活函數,如果是 k k 類別分類問題的話,那麼可以選用softmax作爲激活函數。不過這裏激活函數的類型取決於你有什麼樣類型的輸出 y y ,對於命名實體識別來說 y y 只可能是0或者1,那我猜這裏第二個激活函數 g g 可以是sigmoid激活函數。

       更一般的情況下,在 t t 時刻,

        a &lt; t &gt; = g 1 ( W a a a &lt; t 1 &gt; + W a x x &lt; t &gt; + b a ) a^{&lt; t &gt;} = g_{1}(W_{aa}a^{&lt; t - 1 &gt;} + W_{ax}x^{&lt; t &gt;} + b_{a})

        y ^ &lt; t &gt; = g 2 ( W y a a &lt; t &gt; + b y ) \hat y^{&lt; t &gt;} = g_{2}(W_{{ya}}a^{&lt; t &gt;} + b_{y})

       所以這些等式定義了神經網絡的前向傳播,你可以從零向量 a &lt; 0 &gt; a^{&lt;0&gt;} 開始,然後用 a &lt; 0 &gt; a^{&lt;0&gt;} x &lt; 1 &gt; x^{&lt;1&gt;} 來計算出 a &lt; 1 &gt; a^{&lt;1&gt;} y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} ,然後用 x &lt; 2 &gt; x^{&lt;2&gt;} a &lt; 1 &gt; a^{&lt;1&gt;} 一起算出 a &lt; 2 &gt; a^{&lt;2&gt;} y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} 等等,像圖中這樣,從左到右完成前向傳播。

       現在爲了幫我們建立更復雜的神經網絡,我實際要將這個符號簡化一下,我在下一張幻燈片裏複製了這兩個等式(上圖編號1所示的兩個等式)。
       在這裏插入圖片描述
       接下來爲了簡化這些符號,我要將這部分( W aa a &lt; t 1 &gt; + W ax x &lt; t &gt; W_{\text{aa}}a^{&lt;t -1&gt;} +W_{\text{ax}}x^{&lt;t&gt;} )(上圖編號1所示)以更簡單的形式寫出來,我把它寫做 a &lt; t &gt; = g ( W a [ a &lt; t 1 &gt; , x &lt; t &gt; ] + b a ) a^{&lt;t&gt;} =g(W_{a}\left\lbrack a^{&lt; t-1 &gt;},x^{&lt;t&gt;} \right\rbrack +b_{a}) (上圖編號2所示),那麼左右兩邊劃線部分應該是等價的。所以我們定義 W a W_{a} 的方式是將矩陣 W a a W_{aa} 和矩陣 W a x W_{{ax}} 水平並列放置, [ W a a W a x ] = W a [ {{W}_{aa}}\vdots {{W}_{ax}}]=W_{a} (上圖編號3所示)。舉個例子,如果 a a 是100維的,然後延續之前的例子, x x 是10,000維的,那麼 W a a W_{aa} 就是個 100 100 (100,100) 維的矩陣, W a x W_{ax} 就是個 100 10 , 000 (100,10,000) 維的矩陣,因此如果將這兩個矩陣堆起來, W a W_{a} 就會是個 100 10 , 100 (100,10,100) 維的矩陣。

       用這個符號( [ a &lt; t 1 &gt; , x &lt; t &gt; ] \left\lbrack a^{&lt; t - 1 &gt;},x^{&lt; t &gt;}\right\rbrack )的意思是將這兩個向量堆在一起,我會用這個符號表示,即 [ a &lt; t 1 &gt; x &lt; t &gt; ] \begin{bmatrix}a^{&lt; t-1 &gt;} \\ x^{&lt; t &gt;} \\\end{bmatrix} (上圖編號4所示),最終這就是個10,100維的向量。你可以自己檢查一下,用這個矩陣乘以這個向量,剛好能夠得到原來的量,因爲此時,矩陣 [ W a a W a x ] [ {{W}_{aa}}\vdots {{W}_{ax}}] 乘以 [ a &lt; t 1 &gt; x &lt; t &gt; ] \begin{bmatrix} a^{&lt; t - 1 &gt;} \\ x^{&lt; t &gt;} \\ \end{bmatrix} ,剛好等於 W a a a &lt; t 1 &gt; + W a x x &lt; t &gt; W_{{aa}}a^{&lt;t-1&gt;} + W_{{ax}}x^{&lt;t&gt;} ,剛好等於之前的這個結論(上圖編號5所示)。這種記法的好處是我們可以不使用兩個參數矩陣 W a a W_{{aa}} W a x W_{{ax}} ,而是將其壓縮成一個參數矩陣 W a W_{a} ,所以當我們建立更復雜模型時這就能夠簡化我們要用到的符號。

       同樣對於這個例子( y ^ &lt; t &gt; = g ( W y a a &lt; t &gt; + b y ) \hat y^{&lt;t&gt;} = g(W_{ya}a^{&lt;t&gt;} +b_{y}) ),我會用更簡單的方式重寫, y ^ &lt; t &gt; = g ( W y a &lt; t &gt; + b y ) \hat y^{&lt; t &gt;} = g(W_{y}a^{&lt; t &gt;} +b_{y}) (上圖編號6所示)。現在 W y W_{y} b y b_{y} 符號僅有一個下標,它表示在計算時會輸出什麼類型的量,所以 W y W_{y} 就表明它是計算 y y 類型的量的權重矩陣,而上面的 W a W_{a} b a b_{a} 則表示這些參數是用來計算 a a 類型或者說是激活值的。

       RNN前向傳播示意圖:
       在這裏插入圖片描述

       你現在知道了基本的循環神經網絡,下節我們會一起來討論反向傳播,以及你如何能夠用RNN進行學習。

1.4 通過時間的反向傳播(Backpropagation through time)

       之前我們已經學過了循環神經網絡的基礎結構,我們將來了解反向傳播是怎樣在循環神經網絡中運行的。和之前一樣,當你在編程框架中實現循環神經網絡時,編程框架通常會自動處理反向傳播。但我認爲,在循環神經網絡中,對反向傳播的運行有一個粗略的認識還是非常有用的,讓我們來一探究竟。
       在這裏插入圖片描述
       在之前你已經見過對於前向傳播(上圖藍色箭頭所指方向)怎樣在神經網絡中從左到右地計算這些激活項,直到輸出所有地預測結果。而對於反向傳播,我想你已經猜到了,反向傳播地計算方向(上圖紅色箭頭所指方向)與前向傳播基本上是相反的。
       在這裏插入圖片描述
       我們來分析一下前向傳播的計算,現在你有一個輸入序列, x &lt; 1 &gt; x^{&lt;1&gt;} x &lt; 2 &gt; x^{&lt;2&gt;} x &lt; 3 &gt; x^{&lt;3&gt;} 一直到 x &lt; T x &gt; x^{&lt; T_{x} &gt;} ,然後用 x &lt; 1 &gt; x^{&lt;1&gt;} 還有 a &lt; 0 &gt; a^{&lt;0&gt;} 計算出時間步1的激活項,再用 x &lt; 2 &gt; x^{&lt;2&gt;} a &lt; 1 &gt; a^{&lt;1&gt;} 計算出 a &lt; 2 &gt; a^{&lt;2&gt;} ,然後計算 a &lt; 3 &gt; a^{&lt;3&gt;} 等等,一直到 a &lt; T x &gt; a^{&lt; T_{x} &gt;}

       爲了真正計算出 a &lt; 1 &gt; a^{&lt;1&gt;} ,你還需要一些參數, W a W_{a} b a b_{a} ,用它們來計算出 a &lt; 1 &gt; a^{&lt;1&gt;} 。這些參數在之後的每一個時間步都會被用到,於是繼續用這些參數計算 a &lt; 2 &gt; a^{&lt;2&gt;} a &lt; 3 &gt; a^{&lt;3&gt;} 等等,所有的這些激活項都要取決於參數 W a W_{a} b a b_{a} 。有了 a &lt; 1 &gt; a^{&lt;1&gt;} ,神經網絡就可以計算第一個預測值 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} ,接着到下一個時間步,繼續計算出 y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} y ^ &lt; 3 &gt; \hat y^{&lt;3&gt;} ,等等,一直到 y ^ &lt; T y &gt; \hat y^{&lt;T_{y}&gt;} 。爲了計算出 y ^ {\hat{y}} ,需要參數 W y W_{y} b y b_{y} ,它們將被用於所有這些節點。
       在這裏插入圖片描述

       然後爲了計算反向傳播,你還需要一個損失函數。我們先定義一個元素損失函數(上圖編號1所示)

        L &lt; t &gt; ( y ^ &lt; t &gt; , y &lt; t &gt; ) = y &lt; t &gt; log y ^ &lt; t &gt; ( 1 y ^ &lt; t &gt; ) l o g ( 1 y ^ &lt; t &gt; ) L^{&lt;t&gt;}( \hat y^{&lt;t&gt;},y^{&lt;t&gt;}) = - y^{&lt;t&gt;}\log\hat y^{&lt;t&gt;}-( 1-\hat y^{&lt;t&gt;})log(1-\hat y^{&lt;t&gt;})

       它對應的是序列中一個具體的詞,如果它是某個人的名字,那麼 y &lt; t &gt; y^{&lt;t&gt;} 的值就是1,然後神經網絡將輸出這個詞是名字的概率值,比如0.1。我將它定義爲標準邏輯迴歸損失函數,也叫交叉熵損失函數(Cross Entropy Loss),它和之前我們在二分類問題中看到的公式很像。所以這是關於單個位置上或者說某個時間步 t t 上某個單詞的預測值的損失函數。

       現在我們來定義整個序列的損失函數,將 L L 定義爲(上圖編號2所示)

        L ( y ^ , y ) =   t = 1 T x L &lt; t &gt; ( y ^ &lt; t &gt; , y &lt; t &gt; ) L(\hat y,y) = \ \sum_{t = 1}^{T_{x}}{L^{&lt; t &gt;}(\hat y^{&lt; t &gt;},y^{&lt; t &gt;})}

       在這個計算圖中,通過 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} 可以計算對應的損失函數,於是計算出第一個時間步的損失函數(上圖編號3所示),然後計算出第二個時間步的損失函數,然後是第三個時間步,一直到最後一個時間步,最後爲了計算出總體損失函數,我們要把它們都加起來,通過下面的等式(上圖編號2所示的等式)計算出最後的 L L (上圖編號4所示),也就是把每個單獨時間步的損失函數都加起來。

       這就是完整的計算圖,在之前的例子中,你已經見過反向傳播,所以你應該能夠想得到反向傳播算法需要在相反的方向上進行計算和傳遞信息,最終你做的就是把前向傳播的箭頭都反過來,在這之後你就可以計算出所有合適的量,然後你就可以通過導數相關的參數,用梯度下降法來更新參數。

       在這個反向傳播的過程中,最重要的信息傳遞或者說最重要的遞歸運算就是這個從右到左的運算,這也就是爲什麼這個算法有一個很別緻的名字,叫做通過(穿越)時間反向傳播backpropagation through time)。取這個名字的原因是對於前向傳播,你需要從左到右進行計算,在這個過程中,時刻 t t 不斷增加。而對於反向傳播,你需要從右到左進行計算,就像時間倒流。「通過時間反向傳播」,就像穿越時光,這種說法聽起來就像是你需要一臺時光機來實現這個算法一樣。

       RNN反向傳播示意圖:

       在這裏插入圖片描述
       希望你大致瞭解了前向和反向傳播是如何在RNN中工作的,到目前爲止,你只見到了RNN中一個主要的例子,其中輸入序列的長度和輸出序列的長度是一樣的。在下節課將展示更多的RNN架構,這將讓你能夠處理一些更廣泛的應用。

1.5 不同類型的循環神經網絡(Different types of RNNs)

       現在你已經瞭解了一種RNN結構,它的輸入量 T x T_{x} 等於輸出數量 T y T_{y} 。事實上,對於其他一些應用, T x T_{x} T y T_{y} 並不一定相等。在這,你會看到更多的RNN的結構。
       在這裏插入圖片描述
       你應該還記得第一節講的有很多例子輸入 x x 和輸出 y y ,有各種類型,並不是所有的情況都滿足 T x = T y T_{x}=T_{y}

       比如音樂生成這個例子, T x T_{x} 可以是長度爲1甚至爲空集。再比如電影情感分類,輸出 y y 可以是1到5的整數,而輸入是一個序列。在命名實體識別中,這個例子中輸入長度和輸出長度是一樣的。

       還有一些情況,輸入長度和輸出長度不同,他們都是序列但長度不同,比如機器翻譯,一個法語句子和一個英語句子不同數量的單詞卻能表達同一個意思。

       所以我們應該修改基本的RNN結構來處理這些問題,該內容參考了Andrej Karpathy的博客,一篇叫做《循環神經網絡的非理性效果》(「The Unreasonable Effectiveness of Recurrent Neural Networks」)的文章,我們看一些例子。

       你已經見過 T x = T y T_{x} = T_{y} 的例子了(下圖編號1所示),也就是我們輸入序列 x &lt; 1 &gt; x^{&lt;1&gt;} x &lt; 2 &gt; x^{&lt;2&gt;} ,一直到 x &lt; T x &gt; x^{&lt; T_{x}&gt;} ,我們的循環神經網絡這樣工作,輸入 x &lt; 1 &gt; x^{&lt;1&gt;} 來計算 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} 等等一直到 y ^ &lt; T y &gt; \hat y^{&lt;T_{y}&gt;} 。在原先的圖裏,我會畫一串圓圈表示神經元,大部分時候爲了讓符號更加簡單,此處就以簡單的小圈表示。這個就叫做「多對多」(many-to-many)的結構,因爲輸入序列有很多的輸入,而輸出序列也有很多輸出。

       現在我們看另外一個例子,假如說,你想處理情感分類問題(下圖編號2所示),這裏 x x 可能是一段文本,比如一個電影的評論,「These is nothing to like in this movie.」(「這部電影沒什麼還看的。」),所以 x x 就是一個序列,而 y y 可能是從1到5的一個數字,或者是0或1,這代表正面評價和負面評價,而數字1到5代表電影是1星,2星,3星,4星還是5星。所以在這個例子中,我們可以簡化神經網絡的結構,輸入 x &lt; 1 &gt; x^{&lt;1 &gt;} x &lt; 2 &gt; x^{&lt; 2 &gt;} ,一次輸入一個單詞,如果輸入文本是「These is nothing to like in this movie」,那麼單詞的對應如下圖編號2所示。我們不再在每個時間上都有輸出了,而是讓這個RNN網絡讀入整個句子,然後在最後一個時間上得到輸出,這樣輸入的就是整個句子,所以這個神經網絡叫做「多對一」(many-to-one)結構,因爲它有很多輸入,很多的單詞,然後輸出一個數字。
       在這裏插入圖片描述

       爲了完整性,還要補充一個「一對一」(one-to-one)的結構(上圖編號3所示),這個可能沒有那麼重要,這就是一個小型的標準的神經網絡,輸入 x x 然後得到輸出 y y ,我們這個系列課程的前兩個課程已經討論過這種類型的神經網絡了。
       在這裏插入圖片描述

       除了「多對一」的結構,也可以有「一對多」(one-to-many)的結構。對於一個「一對多」神經網絡結構的例子就是音樂生成(上圖編號1所示),事實上,你會在這個課後編程練習中去實現這樣的模型,你的目標是使用一個神經網絡輸出一些音符。對應於一段音樂,輸入 x x 可以是一個整數,表示你想要的音樂類型或者是你想要的音樂的第一個音符,並且如果你什麼都不想輸入, x x 可以是空的輸入,可設爲0向量。

       這樣這個神經網絡的結構,首先是你的輸入 x x ,然後得到RNN的輸出,第一個值,然後就沒有輸入了,再得到第二個輸出,接着輸出第三個值等等,一直到合成這個音樂作品的最後一個音符,這裏也可以寫上輸入 a &lt; 0 &gt; a^{&lt;0&gt;} (上圖編號3所示)。有一個後面纔會講到的技術細節,當你生成序列時通常會把第一個合成的輸出也餵給下一層(上圖編號4所示),所以實際的網絡結構最終就像這個樣子。

       我們已經討論了「多對多」、「多對一」、「一對一」和「一對多」的結構,對於「多對多」的結構還有一個有趣的例子值得詳細說一下,就是輸入和輸出長度不同的情況。你剛纔看過的多對多的例子,它的輸入長度和輸出長度是完全一樣的。而對於像機器翻譯這樣的應用,輸入句子的單詞的數量,比如說一個法語的句子,和輸出句子的單詞數量,比如翻譯成英語,這兩個句子的長度可能不同,所以還需要一個新的網絡結構,一個不同的神經網絡(上圖編號2所示)。首先讀入這個句子,讀入這個輸入,比如你要將法語翻譯成英語,讀完之後,這個網絡就會輸出翻譯結果。有了這種結構 T x T_{x} T y T_{y} 就可以是不同的長度了。同樣,你也可以畫上這個 a &lt; 0 &gt; a^{&lt;0&gt;} 。這個網絡的結構有兩個不同的部分,這(上圖編號5所示)是一個編碼器,獲取輸入,比如法語句子,這(上圖編號6所示)是解碼器,它會讀取整個句子,然後輸出翻譯成其他語言的結果。
       在這裏插入圖片描述

       這就是一個「多對多」結構的例子,到這周結束的時候,你就能對這些各種各樣結構的基本構件有一個很好的理解。嚴格來說,還有一種結構,我們會在第四周涉及到,就是「注意力」(attention based)結構,但是根據我們現在畫的這些圖不好理解這個模型。

       總結一下這些各種各樣的RNN結構,這(上圖編號1所示)是「一對一」的結構,當去掉 a &lt; 0 &gt; a^{&lt;0&gt;} 時它就是一種標準類型的神經網絡。還有一種「一對多」的結構(上圖編號2所示),比如音樂生成或者序列生成。還有「多對一」,這(上圖編號3所示)是情感分類的例子,首先讀取輸入,一個電影評論的文本,然後判斷他們是否喜歡電影還是不喜歡。還有「多對多」的結構(上圖編號4所示),命名實體識別就是「多對多」的例子,其中 T x = T y T_{x}=T_{y} 。最後還有一種「多對多」結構的其他版本(上圖編號5所示),對於像機器翻譯這樣的應用, T x T_{x} T y T_{y} 就可以不同了。

       現在,你已經瞭解了大部分基本的模塊,這些就是差不多所有的神經網絡了,除了序列生成,有些細節的問題我們會在下節課講解。

       我希望你從本節中瞭解到用這些RNN的基本模塊,把它們組合在一起就可以構建各種各樣的模型。但是正如我前面提到的,序列生成還有一些不一樣的地方,在這周的練習裏,你也會實現它,你需要構建一個語言模型,結果好的話會得到一些有趣的序列或者有意思的文本。

1.6 語言模型和序列生成(Language model and sequence generation)

       在自然語言處理中,構建語言模型是最基礎的也是最重要的工作之一,並且能用RNN很好地實現。在本節中,你將學習用RNN構建一個語言模型,在本週結束的時候,還會有一個很有趣的編程練習,你能在練習中構建一個語言模型,並用它來生成莎士比亞文風的文本或其他類型文本。
       在這裏插入圖片描述
       所以什麼是語言模型呢?比如你在做一個語音識別系統,你聽到一個句子,「the apple and pear(pair) salad was delicious.」,所以我究竟說了什麼?我說的是 「the apple and pair salad」,還是「the apple and pear salad」?(pearpair是近音詞)。你可能覺得我說的應該更像第二種,事實上,這就是一個好的語音識別系統要幫助輸出的東西,即使這兩句話聽起來是如此相似。而讓語音識別系統去選擇第二個句子的方法就是使用一個語言模型,他能計算出這兩句話各自的可能性。

       舉個例子,一個語音識別模型可能算出第一句話的概率是 P ( The apple and pair salad ) = 3.2 × 1 0 13 P( \text{The apple and pair salad}) = 3.2 \times 10^{-13} ,而第二句話的概率是 P ( The apple and pear salad ) = 5.7 × 1 0 10 P\left(\text{The apple and pear salad} \right) = 5.7 \times 10^{-10} ,比較這兩個概率值,顯然我說的話更像是第二種,因爲第二句話的概率比第一句高出1000倍以上,這就是爲什麼語音識別系統能夠在這兩句話中作出選擇。

       所以語言模型所做的就是,它會告訴你某個特定的句子它出現的概率是多少,根據我所說的這個概率,假設你隨機拿起一張報紙,打開任意郵件,或者任意網頁或者聽某人說下一句話,並且這個人是你的朋友,這個你即將從世界上的某個地方得到的句子會是某個特定句子的概率是多少,例如「the apple and pear salad」。它是兩種系統的基本組成部分,一個剛纔所說的語音識別系統,還有機器翻譯系統,它要能正確輸出最接近的句子。而語言模型做的最基本工作就是輸入一個句子,準確地說是一個文本序列, y &lt; 1 &gt; y^{&lt;1&gt;}​ y &lt; 2 &gt; y^{&lt;2&gt;}​ 一直到 y &lt; T y &gt; y^{&lt;T_{y}&gt;}​ 。對於語言模型來說,用 y y​ 來表示這些序列比用 x x​ 來表示要更好,然後語言模型會估計某個句子序列中各個單詞出現的可能性。

       那麼如何建立一個語言模型呢?爲了使用RNN建立出這樣的模型,你首先需要一個訓練集,包含一個很大的英文文本語料庫(corpus)或者其它的語言,你想用於構建模型的語言的語料庫。語料庫是自然語言處理的一個專有名詞,意思就是很長的或者說數量衆多的英文句子組成的文本。
在這裏插入圖片描述
       假如說,你在訓練集中得到這麼一句話,「Cats average 15 hours of sleep a day.」(貓一天睡15小時),你要做的第一件事就是將這個句子標記化,意思就是像之前例子中一樣,建立一個字典,然後將每個單詞都轉換成對應的one-hot向量,也就是字典中的索引。可能還有一件事就是你要定義句子的結尾,一般的做法就是增加一個額外的標記,叫做EOS(上圖編號1所示),它表示句子的結尾,這樣能夠幫助你搞清楚一個句子什麼時候結束,我們之後會詳細討論這個。EOS標記可以被附加到訓練集中每一個句子的結尾,如果你想要你的模型能夠準確識別句子結尾的話。在本週的練習中我們不需要使用這個EOS標記,不過在某些應用中你可能會用到它,不過稍後就能見到它的用處。於是在本例中我們,如果你加了EOS標記,這句話就會有9個輸入,有 y &lt; 1 &gt; y^{&lt;1&gt;} y &lt; 2 &gt; y^{&lt;2&gt;} 一直到 y &lt; 9 &gt; y^{&lt;9&gt;} 。在標記化的過程中,你可以自行決定要不要把標點符號看成標記,在本例中,我們忽略了標點符號,所以我們只把day看成標誌,不包括後面的句號,如果你想把句號或者其他符號也當作標誌,那麼你可以將句號也加入你的字典中。

       現在還有一個問題,如果你的訓練集中有一些詞並不在你的字典裏,比如說你的字典有10,000個詞,10,000個最常用的英語單詞。現在這個句,「The Egyptian Mau is a bread of cat.」其中有一個詞Mau,它可能並不是預先的那10,000個最常用的單詞,在這種情況下,你可以把Mau替換成一個叫做UNK的代表未知詞的標誌,我們只針對UNK建立概率模型,而不是針對這個具體的詞Mau

       完成標識化的過程後,這意味着輸入的句子都映射到了各個標誌上,或者說字典中的各個詞上。下一步我們要構建一個RNN來構建這些序列的概率模型。在下一張幻燈片中會看到的一件事就是最後你會將 x &lt; t &gt; x^{&lt;t&gt;} 設爲 y &lt; t 1 &gt; y^{&lt;t-1&gt;}
       在這裏插入圖片描述
       現在我們來建立RNN模型,我們繼續使用「Cats average 15 hours of sleep a day.」這個句子來作爲我們的運行樣例,我將會畫出一個RNN結構。在第0個時間步,你要計算激活項 a &lt; 1 &gt; a^{&lt;1&gt;} ,它是以 x &lt; 1 &gt; x^{&lt;1 &gt;} 作爲輸入的函數,而 x &lt; 1 &gt; x^{&lt;1&gt;} 會被設爲全爲0的集合,也就是0向量。在之前的 a &lt; 0 &gt; a^{&lt;0&gt;} 按照慣例也設爲0向量,於是 a &lt; 1 &gt; a^{&lt;1&gt;} 要做的就是它會通過softmax進行一些預測來計算出第一個詞可能會是什麼,其結果就是 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} (上圖編號1所示),這一步其實就是通過一個softmax層來預測字典中的任意單詞會是第一個詞的概率,比如說第一個詞是 a a 的概率有多少,第一個詞是Aaron的概率有多少,第一個詞是cats的概率又有多少,就這樣一直到Zulu是第一個詞的概率是多少,還有第一個詞是UNK(未知詞)的概率有多少,還有第一個詞是句子結尾標誌的概率有多少,表示不必閱讀。所以 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} 的輸出是softmax的計算結果,它只是預測第一個詞的概率,而不去管結果是什麼。在我們的例子中,最終會得到單詞Cats。所以softmax層輸出10,000種結果,因爲你的字典中有10,000個詞,或者會有10,002個結果,因爲你可能加上了未知詞,還有句子結尾這兩個額外的標誌。

       然後RNN進入下個時間步,在下一時間步中,仍然使用激活項 a &lt; 1 &gt; a^{&lt;1&gt;} ,在這步要做的是計算出第二個詞會是什麼。現在我們依然傳給它正確的第一個詞,我們會告訴它第一個詞就是Cats,也就是 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} ,告訴它第一個詞就是Cats,這就是爲什麼 y &lt; 1 &gt; = x &lt; 2 &gt; y^{&lt;1&gt;} = x^{&lt;2&gt;} (上圖編號2所示)。然後在第二個時間步中,輸出結果同樣經過softmax層進行預測,RNN的職責就是預測這些詞的概率(上圖編號3所示),而不會去管結果是什麼,可能是b或者arron,可能是Cats或者Zulu或者UNK(未知詞)或者EOS或者其他詞,它只會考慮之前得到的詞。所以在這種情況下,我猜正確答案會是average,因爲句子確實就是Cats average開頭的。

       然後再進行RNN的下個時間步,現在要計算 a &lt; 3 &gt; a^{&lt;3&gt;} 。爲了預測第三個詞,也就是15,我們現在給它之前兩個詞,告訴它Cats average是句子的前兩個詞,所以這是下一個輸入, x &lt; 3 &gt; = y &lt; 2 &gt; x^{&lt;3&gt;} = y^{&lt;2&gt;} ,輸入average以後,現在要計算出序列中下一個詞是什麼,或者說計算出字典中每一個詞的概率(上圖編號4所示),通過之前得到的Catsaverage,在這種情況下,正確結果會是15,以此類推。

       一直到最後,沒猜錯的話,你會停在第9個時間步,然後把 x &lt; 9 &gt; x^{&lt;9&gt;} 也就是 y &lt; 8 &gt; y^{&lt;8&gt;} 傳給它(上圖編號5所示),也就是單詞day,這裏是 a &lt; 9 &gt; a^{&lt;9&gt;} ,它會輸出 y &lt; 9 &gt; y^{&lt;9&gt;} ,最後的得到結果會是EOS標誌,在這一步中,通過前面這些得到的單詞,不管它們是什麼,我們希望能預測出EOS句子結尾標誌的概率會很高(上圖編號6所示)。

       所以RNN中的每一步都會考慮前面得到的單詞,比如給它前3個單詞(上圖編號7所示),讓它給出下個詞的分佈,這就是RNN如何學習從左往右地每次預測一個詞。

       接下來爲了訓練這個網絡,我們要定義代價函數。於是,在某個時間步 t t ,如果真正的詞是 y &lt; t &gt; y^{&lt;t&gt;} ,而神經網絡的softmax層預測結果值是 y &lt; t &gt; y^{&lt;t&gt;} ,那麼這(上圖編號8所示)就是softmax損失函數, L ( y ^ &lt; t &gt; , y &lt; t &gt; &gt; ) = i y i &lt; t &gt; log y ^ i &lt; t &gt; L\left( \hat y^{&lt;t&gt;},y^{&lt;t&gt;}&gt;\right) = - \sum_{i}^{}{y_{i}^{&lt;t&gt;}\log\hat y_{i}^{&lt;t&gt;}} 。而總體損失函數(上圖編號9所示) L = t L &lt; t &gt; ( y ^ &lt; t &gt; , y &lt; t &gt; ) L = \sum_{t}^{}{L^{&lt; t &gt;}\left( \hat y^{&lt;t&gt;},y^{&lt;t&gt;} \right)} ,也就是把所有單個預測的損失函數都相加起來。
       在這裏插入圖片描述
       如果你用很大的訓練集來訓練這個RNN,你就可以通過開頭一系列單詞像是Cars average 15或者Cars average 15 hours of來預測之後單詞的概率。現在有一個新句子,它是 y &lt; 1 &gt; y^{&lt;1&gt;} y &lt; 2 &gt; y^{&lt;2&gt;} y &lt; 3 &gt; y^{&lt;3&gt;} ,爲了簡單起見,它只包含3個詞(如上圖所示),現在要計算出整個句子中各個單詞的概率,方法就是第一個softmax層會告訴你 y &lt; 1 &gt; y^{&lt;1&gt;} 的概率(上圖編號1所示),這也是第一個輸出,然後第二個softmax層會告訴你在考慮 y &lt; 1 &gt; y^{&lt;1&gt;} 的情況下 y &lt; 2 &gt; y^{&lt;2&gt;} 的概率(上圖編號2所示),然後第三個softmax層告訴你在考慮 y &lt; 1 &gt; y^{&lt;1&gt;} y &lt; 2 &gt; y^{&lt;2&gt;} 的情況下 y &lt; 3 &gt; y^{&lt;3&gt;} 的概率(上圖編號3所示),把這三個概率相乘,最後得到這個含3個詞的整個句子的概率。

       這就是用RNN訓練一個語言模型的基礎結構,可能我說的這些東西聽起來有些抽象,不過別擔心,你可以在編程練習中親自實現這些東西。下一節課用語言模型做的一件最有趣的事就是從模型中進行採樣。

1.7 對新序列採樣(Sampling novel sequences)

       在你訓練一個序列模型之後,要想了解到這個模型學到了什麼,一種非正式的方法就是進行一次新序列採樣,來看看到底應該怎麼做。

       記住一個序列模型模擬了任意特定單詞序列的概率,我們要做的就是對這些概率分佈進行採樣來生成一個新的單詞序列。下圖編號1所示的網絡已經被上方所展示的結構訓練訓練過了,而爲了進行採樣(下圖編號2所示的網絡),你要做一些截然不同的事情。
       在這裏插入圖片描述
       第一步要做的就是對你想要模型生成的第一個詞進行採樣,於是你輸入 x &lt; 1 &gt; = 0 x^{&lt;1&gt;} =0 a &lt; 0 &gt; = 0 a^{&lt;0&gt;} =0 ,現在你的第一個時間步得到的是所有可能的輸出是經過softmax層後得到的概率,然後根據這個softmax的分佈進行隨機採樣。Softmax分佈給你的信息就是第一個詞a的概率是多少,第一個詞是aaron的概率是多少,第一個詞是zulu的概率是多少,還有第一個詞是UNK(未知標識)的概率是多少,這個標識可能代表句子的結尾,然後對這個向量使用例如numpy命令,np.random.choice(上圖編號3所示),來根據向量中這些概率的分佈進行採樣,這樣就能對第一個詞進行採樣了。

       然後繼續下一個時間步,記住第二個時間步需要 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} 作爲輸入,而現在要做的是把剛剛採樣得到的 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} 放到 a &lt; 2 &gt; a^{&lt;2&gt;} (上圖編號4所示),作爲下一個時間步的輸入,所以不管你在第一個時間步得到的是什麼詞,都要把它傳遞到下一個位置作爲輸入,然後softmax層就會預測 y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} 是什麼。舉個例子,假如說對第一個詞進行抽樣後,得到的是TheThe作爲第一個詞的情況很常見,然後把The當成 x &lt; 2 &gt; x^{&lt;2&gt;} ,現在 x &lt; 2 &gt; x^{&lt;2&gt;} 就是 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} ,現在你要計算出在第一詞是The的情況下,第二個詞應該是什麼(上圖編號5所示),然後得到的結果就是 y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} ,然後再次用這個採樣函數來對 y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} 進行採樣。

       然後再到下一個時間步,無論你得到什麼樣的用one-hot碼錶示的選擇結果,都把它傳遞到下一個時間步,然後對第三個詞進行採樣。不管得到什麼都把它傳遞下去,一直這樣直到最後一個時間步。

       那麼你要怎樣知道一個句子結束了呢?方法之一就是,如果代表句子結尾的標識在你的字典中,你可以一直進行採樣直到得到EOS標識(上圖編號6所示),這代表着已經抵達結尾,可以停止採樣了。另一種情況是,如果你的字典中沒有這個詞,你可以決定從20個或100個或其他個單詞進行採樣,然後一直將採樣進行下去直到達到所設定的時間步。不過這種過程有時候會產生一些未知標識(上圖編號7所示),如果你要確保你的算法不會輸出這種標識,你能做的一件事就是拒絕採樣過程中產生任何未知的標識,一旦出現就繼續在剩下的詞中進行重採樣,直到得到一個不是未知標識的詞。如果你不介意有未知標識產生的話,你也可以完全不管它們。

       這就是你如何從你的RNN語言模型中生成一個隨機選擇的句子。直到現在我們所建立的是基於詞彙的RNN模型,意思就是字典中的詞都是英語單詞(下圖編號1所示)。
       在這裏插入圖片描述

       根據你實際的應用,你還可以構建一個基於字符的RNN結構,在這種情況下,你的字典僅包含從az的字母,可能還會有空格符,如果你需要的話,還可以有數字0到9,如果你想區分字母大小寫,你可以再加上大寫的字母,你還可以實際地看一看訓練集中可能會出現的字符,然後用這些字符組成你的字典(上圖編號2所示)。

       如果你建立一個基於字符的語言模型,比起基於詞彙的語言模型,你的序列 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} y ^ &lt; 3 &gt; \hat y^{&lt;3&gt;} 在你的訓練數據中將會是單獨的字符,而不是單獨的詞彙。所以對於前面的例子來說,那個句子(上圖編號3所示),「Cats average 15 hours of sleep a day.」,在該例中C就是 y ^ &lt; 1 &gt; \hat y^{&lt;1&gt;} a就是 y ^ &lt; 2 &gt; \hat y^{&lt;2&gt;} t就是 y ^ &lt; 3 &gt; \hat y^{&lt;3&gt;} ,空格符就是 y ^ &lt; 4 &gt; \hat y^{&lt;4&gt;} 等等。

       使用基於字符的語言模型有有點也有缺點,優點就是你不必擔心會出現未知的標識,例如基於字符的語言模型會將Mau這樣的序列也視爲可能性非零的序列。而對於基於詞彙的語言模型,如果Mau不在字典中,你只能把它當作未知標識UNK不過基於字符的語言模型一個主要缺點就是你最後會得到太多太長的序列,大多數英語句子只有10到20個的單詞,但卻可能包含很多很多字符。所以基於字符的語言模型在捕捉句子中的依賴關係也就是句子較前部分如何影響較後部分不如基於詞彙的語言模型那樣可以捕捉長範圍的關係,並且基於字符的語言模型訓練起來計算成本比較高昂。所以我見到的自然語言處理的趨勢就是,絕大多數都是使用基於詞彙的語言模型,但隨着計算機性能越來越高,會有更多的應用。在一些特殊情況下,會開始使用基於字符的模型。但是這確實需要更昂貴的計算力來訓練,所以現在並沒有得到廣泛地使用,除了一些比較專門需要處理大量未知的文本或者未知詞彙的應用,還有一些要面對很多專有詞彙的應用。

       在現有的方法下,現在你可以構建一個RNN結構,看一看英文文本的語料庫,然後建立一個基於詞彙的或者基於字符的語言模型,然後從訓練的語言模型中進行採樣。
       在這裏插入圖片描述

       這裏有一些樣本,它們是從一個語言模型中採樣得到的,準確來說是基於字符的語言模型,你可以在編程練習中自己實現這樣的模型。如果模型是用新聞文章訓練的,它就會生成左邊這樣的文本,這有點像一篇不太合乎語法的新聞文本,不過聽起來,這句「Concussion epidemic」,to be examined,確實有點像新聞報道。用莎士比亞的文章訓練後生成了右邊這篇東西,聽起來很像是莎士比亞寫的東西:

       「The mortal moon hath her eclipse in love.

       And subject of this thou art another this fold.

       When besser be my love to me see sabl’s.

       For whose are ruse of mine eyes heaves.

       這些就是基礎的RNN結構和如何去建立一個語言模型並使用它,對於訓練出的語言模型進行採樣。在之後,我想探討在訓練RNN時一些更加深入的挑戰以及如何適應這些挑戰,特別是梯度消失問題來建立更加強大的RNN模型。下節課,我們將談到梯度消失並且會開始談到GRU,也就是門控循環單元和LSTM長期記憶網絡模型。

1.8 循環神經網絡的梯度消失(Vanishing gradients with RNNs)

       你已經瞭解了RNN時如何工作的了,並且知道如何應用到具體問題上,比如命名實體識別,比如語言模型,你也看到了怎麼把反向傳播用於RNN。其實,基本的RNN算法還有一個很大的問題,就是梯度消失的問題
       在這裏插入圖片描述

       你已經知道了RNN的樣子,現在我們舉個語言模型的例子,假如看到這個句子(上圖編號1所示),「The cat, which already ate ……, was full.」,前後應該保持一致,因爲cat是單數,所以應該用was。「The cats, which ate ……, were full.」(上圖編號2所示),cats是複數,所以用were。這個例子中的句子有長期的依賴,最前面的單詞對句子後面的單詞有影響。但是我們目前見到的基本的RNN模型(上圖編號3所示的網絡模型),不擅長捕獲這種長期依賴效應,解釋一下爲什麼。

       你應該還記得之前討論的訓練很深的網絡,我們討論了梯度消失的問題。比如說一個很深很深的網絡(上圖編號4所示),100層,甚至更深,對這個網絡從左到右做前向傳播然後再反向傳播。我們知道如果這是個很深的神經網絡,從輸出 y ^ \hat y 得到的梯度很難傳播回去,很難影響靠前層的權重,很難影響前面層(編號5所示的層)的計算。

       對於有同樣問題的RNN,首先從左到右前向傳播,然後反向傳播。但是反向傳播會很困難,因爲同樣的梯度消失的問題,後面層的輸出誤差(上圖編號6所示)很難影響前面層(上圖編號7所示的層)的計算。這就意味着,實際上很難讓一個神經網絡能夠意識到它要記住看到的是單數名詞還是複數名詞,然後在序列後面生成依賴單複數形式的was或者were。而且在英語裏面,這中間的內容(上圖編號8所示)可以任意長,對吧?所以你需要長時間記住單詞是單數還是複數,這樣後面的句子才能用到這些信息。也正是這個原因,所以基本的RNN模型會有很多局部影響,意味着這個輸出 y ^ &lt; 3 &gt; \hat y^{&lt;3&gt;} (上圖編號9所示)主要受 y ^ &lt; 3 &gt; \hat y^{&lt;3&gt;} 附近的值(上圖編號10所示)的影響,上圖編號11所示的一個數值主要與附近的輸入(上圖編號12所示)有關,上圖編號6所示的輸出,基本上很難受到序列靠前的輸入(上圖編號10所示)的影響,這是因爲不管輸出是什麼,不管是對的,還是錯的,這個區域都很難反向傳播到序列的前面部分,也因此網絡很難調整序列前面的計算。這是基本的RNN算法的一個缺點,我們會在下幾節內容處理這個問題。如果不管的話,RNN會不擅長處理長期依賴的問題
       在這裏插入圖片描述
       儘管我們一直在討論梯度消失問題,但是,你應該記得我們在講很深的神經網絡時,我們也提到了梯度爆炸,我們在反向傳播的時候,隨着層數的增多,梯度不僅可能指數型的下降,也可能指數型的上升事實上梯度消失在訓練RNN時是首要的問題,儘管梯度爆炸也是會出現,但是梯度爆炸很明顯,因爲指數級大的梯度會讓你的參數變得極其大,以至於你的網絡參數崩潰。所以梯度爆炸很容易發現,因爲參數會大到崩潰,你會看到很多NaN,或者不是數字的情況,這意味着你的網絡計算出現了數值溢出。如果你發現了梯度爆炸的問題,一個解決方法就是用梯度修剪。梯度修剪的意思就是觀察你的梯度向量,如果它大於某個閾值,縮放梯度向量,保證它不會太大,這就是通過一些最大值來修剪的方法。所以如果你遇到了梯度爆炸,如果導數值很大,或者出現了NaN,就用梯度修剪,這是相對比較魯棒的,這是梯度爆炸的解決方法。然而梯度消失更難解決

       總結一下,在前面的課程,我們瞭解了訓練很深的神經網絡時,隨着層數的增加,導數有可能指數型的下降或者指數型的增加,我們可能會遇到梯度消失或者梯度爆炸的問題。加入一個RNN處理1,000個時間序列的數據集或者10,000個時間序列的數據集,這就是一個1,000層或者10,000層的神經網絡,這樣的網絡就會遇到上述類型的問題。梯度爆炸基本上用梯度修剪就可以應對,但梯度消失比較棘手。我們下節會介紹GRU,門控循環單元網絡,這個網絡可以有效地解決梯度消失的問題,並且能夠使你的神經網絡捕獲更長的長期依賴。

1.9 GRU單元(Gated Recurrent Unit(GRU))

       你已經瞭解了基礎的RNN模型的運行機制,在本節視頻中你將會學習門控循環單元,它改變了RNN的隱藏層,使其可以更好地捕捉深層連接,並改善了梯度消失問題,讓我們看一看。
       在這裏插入圖片描述
       你已經見過了這個公式, a &lt; t &gt; = g ( W a [ a &lt; t 1 &gt; , x &lt; t &gt; ] + b a ) a^{&lt; t &gt;} = g(W_{a}\left\lbrack a^{&lt; t - 1 &gt;},x^{&lt; t &gt;}\right\rbrack +b_{a}) ,在RNN的時間 t t 處,計算激活值。我把這個畫個圖,把RNN的單元畫個圖,畫一個方框,輸入 a &lt; t 1 &gt; a^{&lt;t-1&gt;} (上圖編號1所示),即上一個時間步的激活值,再輸入 x &lt; t &gt; x^{&lt;t&gt;} (上圖編號2所示),再把這兩個並起來,然後乘上權重項,在這個線性計算之後(上圖編號3所示),如果 g g 是一個tanh激活函數,再經過tanh計算之後,它會計算出激活值 a &lt; t &gt; a^{&lt;t&gt;} 。然後激活值 a &lt; t &gt; a^{&lt;t&gt;} 將會傳softmax單元(上圖編號4所示),或者其他用於產生輸出 y &lt; t &gt; y^{&lt;t&gt;} 的東西。就這張圖而言,這就是RNN隱藏層的單元的可視化呈現。我向展示這張圖,因爲我們將使用相似的圖來講解門控循環單元。
       在這裏插入圖片描述
       在這裏插入圖片描述
       許多GRU的想法都來分別自於Yu Young Chang, Kagawa,Gaza Hera, Chang Hung Chu
Jose Banjo的兩篇論文。我再引用上這個句子,「The cat, which already ate……, was full.」,你需要記得貓是單數的,爲了確保你已經理解了爲什麼這裏是was而不是were,「The cat was full.」或者是「The cats were full」。當我們從左到右讀這個句子,GRU單元將會有個新的變量稱爲 c c ,代表細胞(cell),即記憶細胞(下圖編號1所示)。記憶細胞的作用是提供了記憶的能力,比如說一隻貓是單數還是複數,所以當它看到之後的句子的時候,它仍能夠判斷句子的主語是單數還是複數。於是在時間 t t 處,有記憶細胞 c &lt; t &gt; c^{&lt;t&gt;} ,然後我們看的是,GRU實際上輸出了激活值 a &lt; t &gt; a^{&lt;t&gt;} c &lt; t &gt; = a &lt; t &gt; c^{&lt;t&gt;} = a^{&lt;t&gt;} (下圖編號2所示)。於是我們想要使用不同的符號 c c a a 來表示記憶細胞的值和輸出的激活值,即使它們是一樣的。我現在使用這個標記是因爲當我們等會說到LSTMs的時候,這兩個會是不同的值,但是現在對於GRU c &lt; t &gt; c^{&lt;t&gt;} 的值等於 a &lt; t &gt; a^{&lt;t&gt;} 的激活值。

       所以這些等式表示了GRU單元的計算,在每個時間步,我們將用一個候選值重寫記憶細胞,即 c ~ &lt; t &gt; {\tilde{c}}^{&lt;t&gt;} 的值,所以它就是個候選值,替代了 c &lt; t &gt; c^{&lt;t&gt;} 的值。然後我們用tanh激活函數來計算, c ~ &lt; t &gt; = t a n h ( W c [ c &lt; t 1 &gt; , x &lt; t &gt; ] + b c ) {\tilde{c}}^{&lt;t&gt;} =tanh(W_{c}\left\lbrack c^{&lt;t-1&gt;},x^{&lt;t&gt;} \right\rbrack +b_{c}) ,所以 c ~ &lt; t &gt; {\tilde{c}}^{&lt;t&gt;} 的值就是個替代值,代替表示 c &lt; t &gt; c^{&lt;t&gt;} 的值(下圖編號3所示)。
       在這裏插入圖片描述

       重點來了,在GRU中真正重要的思想是我們有一個門,我先把這個門叫做 Γ u \Gamma_{u} (上圖編號4所示),這是個下標爲 u u 的大寫希臘字母 Γ \Gamma u u 代表更新門,這是一個0到1之間的值。爲了讓你直觀思考GRU的工作機制,先思考 Γ u \Gamma_{u} ,這個一直在0到1之間的門值,實際上這個值是把這個式子帶入sigmoid函數得到的, Γ u = σ ( W u [ c &lt; t 1 &gt; , x &lt; t &gt; ] + b u ) \Gamma_{u}= \sigma(W_{u}\left\lbrack c^{&lt;t-1&gt;},x^{&lt;t&gt;} \right\rbrack +b_{u}) 。我們還記得sigmoid函數是上圖編號5所示這樣的,它的輸出值總是在0到1之間,對於大多數可能的輸入,sigmoid函數的輸出總是非常接近0或者非常接近1。在這樣的直覺下,可以想到 Γ u \Gamma_{u} 在大多數的情況下非常接近0或1。然後這個字母u表示「update」,我選了字母 Γ \Gamma 是因爲它看起來像門。還有希臘字母GG是門的首字母,所以G表示門。

       然後GRU的關鍵部分就是上圖編號3所示的等式,我們剛纔寫出來的用 c ~ \tilde{c} 更新 c c 的等式。然後門決定是否要真的更新它。於是我們這麼看待它,記憶細胞 c &lt; t &gt; c^{&lt;t&gt;} 將被設定爲0或者1,這取決於你考慮的單詞在句子中是單數還是複數,因爲這裏是單數情況,所以我們先假定它被設爲了1,或者如果是複數的情況我們就把它設爲0。然後GRU單元將會一直記住 c &lt; t &gt; c^{&lt;t&gt;} 的值,直到上圖編號7所示的位置, c &lt; t &gt; c^{&lt;t&gt;} 的值還是1,這就告訴它,噢,這是單數,所以我們用was。於是門,即 Γ u \Gamma_{u} 的作用就是決定什麼時候你會更新這個值,特別是當你看到詞組the cat,即句子的主語貓,這就是一個好時機去更新這個值。然後當你使用完它的時候,「The cat, which already ate……, was full.」,然後你就知道,我不需要記住它了,我可以忘記它了。
       在這裏插入圖片描述

       所以我們接下來要GRU用的式子就是 c &lt; t &gt; = Γ u c ~ &lt; t &gt; + ( 1 Γ u ) c &lt; t 1 &gt; c^{&lt;t&gt;} = \Gamma_{u}*{\tilde{c}}^{&lt;t&gt;} +\left( 1- \Gamma_{u} \right)*c^{&lt;t-1&gt;} (上圖編號1所示)。你應該注意到了,如果這個更新值 Γ u = 1 \Gamma_{u} =1 ,也就是說把這個新值,即 c &lt; t &gt; c^{&lt;t&gt;} 設爲候選值( Γ u = 1 \Gamma_{u} =1 時簡化上式, c &lt; t &gt; = c ~ &lt; t &gt; c^{&lt;t&gt;} = {\tilde{c}}^{&lt;t&gt;} )。將門值設爲1(上圖編號2所示),然後往前再更新這個值。對於所有在這中間的值,你應該把門的值設爲0,即 Γ u = 0 \Gamma_{u}= 0 ,意思就是說不更新它,就用舊的值。因爲如果 Γ u = 0 \Gamma_{u} = 0 ,則 c &lt; t &gt; = c &lt; t 1 &gt; c^{&lt;t&gt;} =c^{&lt;t-1&gt;} c &lt; t &gt; c^{&lt;t&gt;} 等於舊的值。甚至你從左到右掃描這個句子,當門值爲0的時候(上圖編號3所示,中間 Γ u = 0 \Gamma_{u}=0 一直爲0,表示一直不更新),就是說不更新它的時候,不要更新它,就用舊的值,也不要忘記這個值是什麼,這樣即使你一直處理句子到上圖編號4所示, c &lt; t &gt; c^{&lt;t&gt;} 應該會一直等 c &lt; t 1 &gt; c^{&lt;t-1&gt;} ,於是它仍然記得貓是單數的

       讓我再畫個圖來(下圖所示)解釋一下GRU單元,順便說一下,當你在看網絡上的博客或者教科書或者教程之類的,這些圖對於解釋GRU和我們稍後會講的LSTM是相當流行的。

       GRU單元輸入 c &lt; t 1 &gt; c^{&lt;t-1&gt;} (下圖編號1所示),對於上一個時間步,先假設它正好等於 a &lt; t 1 &gt; a^{&lt;t-1&gt;} ,所以把這個作爲輸入。然後 x &lt; t &gt; x^{&lt;t&gt;} 也作爲輸入(下圖編號2所示),然後把這兩個用合適權重結合在一起,再用tanh計算,算出 c ~ &lt; t &gt; {\tilde{c}}^{&lt;t&gt;} c ~ &lt; t &gt; = t a n h ( W c [ c &lt; t 1 &gt; , x &lt; t &gt; ] + b c ) {\tilde{c}}^{&lt;t&gt;} =tanh(W_{c}\left\lbrack c^{&lt;t-1&gt;},x^{&lt;t&gt;} \right\rbrack +b_{c}) ,即 c &lt; t &gt; c^{&lt;t&gt;} 的替代值。

       再用一個不同的參數集,通過sigmoid激活函數算出 Γ u \Gamma_{u} Γ u = σ ( W u [ c &lt; t 1 &gt; , x &lt; t &gt; ] + b u ) \Gamma_{u}= \sigma(W_{u}\left\lbrack c^{&lt;t-1&gt;},x^{&lt;t&gt;} \right\rbrack +b_{u}) ,即更新門。最後所有的值通過另一個運算符結合,我並不會寫出公式,但是我用紫色陰影標註的這個方框(下圖編號5所示,其所代表的運算過程即下圖編號13所示的等式),代表了這個式子。所以這就是紫色運算符所表示的是,它輸入一個門值(下圖編號6所示),新的候選值(下圖編號7所示),這再有一個門值(下圖編號8所示)和 c &lt; t &gt; c^{&lt;t&gt;} 的舊值(下圖編號9所示),所以它把這個(下圖編號1所示)、這個(下圖編號3所示)和這個(下圖編號4所示)作爲輸入一起產生記憶細胞的新值 c &lt; t &gt; c^{&lt;t&gt;} ,所以 c &lt; t &gt; c^{&lt;t&gt;} 等於 a &lt; t &gt; a^{&lt;t&gt;} 。如果你想,你也可以也把這個代入softmax或者其他預測 y &lt; t &gt; y^{&lt;t&gt;} 的東西。
       在這裏插入圖片描述
       這就是GRU單元或者說是一個簡化過的GRU單元,它的優點就是通過門決定,當你從左(上圖編號10所示)到右掃描一個句子的時候,這個時機是要更新某個記憶細胞,還是不更新,不更新(上圖編號11所示,中間 Γ u = 0 \Gamma_{u}=0 一直爲0,表示一直不更新)直到你到你真的需要使用記憶細胞的時候(上圖編號12所示),這可能在句子之前就決定了。因爲sigmoid的值,現在因爲門很容易取到0值,只要這個值是一個很大的負數,再由於數值上的四捨五入,上面這些門大體上就是0,或者說非常非常非常接近0。所以在這樣的情況下,這個更新式子(上圖編號13所示的等式)就會變成 c &lt; t &gt; = c &lt; t 1 &gt; c^{&lt;t&gt;} = c^{&lt;t-1&gt;} ,這非常有利於維持細胞的值。因爲 Γ u \Gamma_{u} 很接近0,可能是0.000001或者更小,這就不會有梯度消失的問題了。因爲 Γ u \Gamma_{u} 很接近0,這就是說 c &lt; t &gt; c^{&lt;t&gt;} 幾乎就等於 c &lt; t 1 &gt; c^{&lt;t-1&gt;} ,而且 c &lt; t &gt; c^{&lt;t&gt;} 的值也很好地被維持了,即使經過很多很多的時間步(上圖編號14所示)。這就是緩解梯度消失問題的關鍵,因此允許神經網絡運行在非常龐大的依賴詞上,比如說catwas單詞即使被中間的很多單詞分割開。
       在這裏插入圖片描述
       現在我想說下一些實現的細節,在這個我寫下的式子中 c &lt; t &gt; c^{&lt;t&gt;} 可以是一個向量(上圖編號1所示),如果你有100維的隱藏的激活值,那麼 c &lt; t &gt; c^{&lt;t&gt;} 也是100維的, c ~ &lt; t &gt; {\tilde{c}}^{&lt;t&gt;} 也是相同的維度( c ~ &lt; t &gt; = t a n h ( W c [ c &lt; t 1 &gt; , x &lt; t &gt; ] + b c ) {\tilde{c}}^{&lt;t&gt;} =tanh(W_{c}\left\lbrack c^{&lt;t-1&gt;},x^{&lt;t&gt;} \right\rbrack +b_{c}) ), Γ u \Gamma_{u} 也是相同的維度( Γ u = σ ( W u [ c &lt; t 1 &gt; , x &lt; t &gt; ] + b u ) \Gamma_{u}= \sigma(W_{u}\left\lbrack c^{&lt;t-1&gt;},x^{&lt;t&gt;} \right\rbrack +b_{u}) ),還有畫在框中的其他值。這樣的話「*」實際上就是元素對應的乘積( c &lt; t &gt; = Γ u c ~ &lt; t &gt; + ( 1 Γ u ) c &lt; t 1 &gt; c^{&lt;t&gt;} = \Gamma_{u}*{\tilde{c}}^{&lt;t&gt;} +\left( 1- \Gamma_{u} \right)*c^{&lt;t-1&gt;} ),所以這裏的 Γ u \Gamma_{u} :( Γ u = σ ( W u [ c &lt; t 1 &gt; , x &lt; t &gt; ] + b u ) \Gamma_{u}= \sigma(W_{u}\left\lbrack c^{&lt;t-1&gt;},x^{&lt;t&gt;} \right\rbrack +b_{u}) ),即如果門是一個100維的向量, Γ u \Gamma_{u} 也就100維的向量,裏面的值幾乎都是0或者1,就是說這100維的記憶細胞 c &lt; t &gt; c^{&lt;t&gt;} c &lt; t &gt; = a &lt; t &gt; c^{&lt;t&gt;}=a^{&lt;t&gt;} 上圖編號1所示)就是你要更新的比特。

       當然在實際應用中 Γ u \Gamma_{u} 不會真的等於0或者1,有時候它是0到1的一箇中間值(上圖編號5所示),但是這對於直觀思考是很方便的,就把它當成確切的0,完全確切的0或者就是確切的1。元素對應的乘積做的就是告訴GRU單元哪個記憶細胞的向量維度在每個時間步要做更新,所以你可以選擇保存一些比特不變,而去更新其他的比特。比如說你可能需要一個比特來記憶貓是單數還是複數,其他比特來理解你正在談論食物,因爲你在談論吃飯或者食物,然後你稍後可能就會談論「The cat was full.」,你可以每個時間點只改變一些比特。

       你現在已經理解GRU最重要的思想了,幻燈片中展示的實際上只是簡化過的GRU單元,現在來描述一下完整的GRU單元。

       對於完整的GRU單元我要做的一個改變就是在我們計算的第一個式子中給記憶細胞的新候選值加上一個新的項,我要添加一個門 Γ r \Gamma_{r} (下圖編號1所示),你可以認爲 r r 代表相關性(relevance)。這個 Γ r \Gamma_{r} 門告訴你計算出的下一個 c &lt; t &gt; c^{&lt;t&gt;} 的候選值 c ~ &lt; t &gt; {\tilde{c}}^{&lt;t&gt;} c &lt; t 1 &gt; c^{&lt;t-1&gt;} 有多大的相關性。計算這個門 Γ r \Gamma_{r} 需要參數,正如你看到的這個,一個新的參數矩陣 W r W_{r} Γ r = σ ( W r [ c &lt; t 1 &gt; , x &lt; t &gt; ] + b r ) \Gamma_{r}= \sigma(W_{r}\left\lbrack c^{&lt;t-1&gt;},x^{&lt;t&gt;} \right\rbrack + b_{r})
       在這裏插入圖片描述
       正如你所見,有很多方法可以來設計這些類型的神經網絡,然後我們爲什麼有 Γ r \Gamma_{r} ?爲什麼不用上一張幻燈片裏的簡單的版本?這是因爲多年來研究者們試驗過很多很多不同可能的方法來設計這些單元,去嘗試讓神經網絡有更深層的連接,去嘗試產生更大範圍的影響,還有解決梯度消失的問題,GRU就是其中一個研究者們最常使用的版本,也被發現在很多不同的問題上也是非常健壯和實用的。你可以嘗試發明新版本的單元,只要你願意。但是GRU是一個標準版本,也就是最常使用的。你可以想象到研究者們也嘗試了很多其他版本,類似這樣的但不完全是,比如我這裏寫的這個。然後另一個常用的版本被稱爲LSTM,表示長短時記憶網絡,這個我們會在下節中講到,但是GRULSTM是在神經網絡結構中最常用的兩個具體實例。

       還有在符號上的一點,我嘗試去定義固定的符號讓這些概念容易理解,如果你看學術文章的話,你有的時候會看到有些人使用另一種符號 x ~ \tilde{x} u u r r h h 表示這些量。但我試着在GRULSTM之間用一種更固定的符號,比如使用更固定的符號 Γ \Gamma 來表示門,所以希望這能讓這些概念更好理解。

       所以這就是GRU,即門控循環單元,這是RNN的其中之一。這個結構可以更好捕捉非常長範圍的依賴,讓RNN更加有效。然後我簡單提一下其他常用的神經網絡,比較經典的是這個叫做LSTM,即長短時記憶網絡,。

Chung J, Gulcehre C, Cho K H, et al. Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling[J]. Eprint Arxiv, 2014.

Cho K�樣的但不完全是,比如我這裏寫的這個。然後另一個常用的版本被稱爲LSTM,表示長短時記憶網絡,這個我們會在下節中講到,但是GRULSTM是在神經網絡結構中最常用的兩個具體實例。

       還有在符號上的一點,我嘗試去定義固定的符號讓這些概念容易理解,如果你看學術文章的話,你有的時候會看到有些人使用另一種符號 x ~ \tilde{x} u u r r h h 表示這些量。但我試着在GRULSTM之間用一種更固定的符號,比如使用更固定的符號 Γ \Gamma 來表示門,所以希望這能讓這些概念更好理解。

       所以這就是GRU,即門控循環單元,這是RNN的其中之一。這個結構可以更好捕捉非常長範圍的依賴,讓RNN更加有效。然後我簡單提一下其他常用的神經網絡,比較經典的是這個叫做LSTM,即長短時記憶網絡,。

Chung J, Gulcehre C, Cho K H, et al. Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling[J]. Eprint Arxiv, 2014.

Cho K, Merrienboer B V, Bahdanau D, et al. On the Properties of Neural Machine Translation: Encoder-Decoder Approaches[J]. Computer Science, 2014.

1.10 長短期記憶(LSTM(long short term memory)unit)

       你已經學了GRU(門控循環單元)。它能夠讓你可以在序列中學習非常深的連接。其他類型的單元也可以讓你做到這個,比如LSTM即長短時記憶網絡,甚至比GRU更加有效。
       在這裏插入圖片描述
       這裏是上節中的式子,對於GRU我們有 a &lt; t &gt; = c &lt; t &gt; a^{&lt; t &gt;} = c^{&lt;t&gt;}

       還有兩個門:

       更新門 Γ u \Gamma_{u} the update gate

       相關門 Γ r \Gamma_{r} the relevance gate

        c ~ &lt; t &gt; {\tilde{c}}^{&lt;t&gt;} ,這是代替記憶細胞的候選值,然後我們使用更新門 Γ u \Gamma_{u} 來決定是否要用 c ~ &lt; t &gt; {\tilde{c}}^{&lt;t&gt;}

相關文章
相關標籤/搜索