《Sequence Models》課堂筆記

Lesson 5 Sequence Models

這篇文章實際上是 Coursera 上吳恩達老師的深度學習專業課程的第五門課程的課程筆記。git

參考了其餘人的筆記繼續概括的。github

符號定義

假如咱們想要創建一個可以自動識別句中人名地名等位置的序列模型,也就是一個命名實體識別問題,這經常使用於搜索引擎。命名實體識別系統能夠用來查找不一樣類型的文本中的人名、公司名、時間、地點、國家名和貨幣名等等。算法

咱們輸入語句 "Harry Potter and Herminoe Granger invented a new spell." 做爲輸入數據 \(x\),咱們想要這個序列模型輸出 \(y\),使得輸入的每一個單詞都對應一個輸出值,同時這個 \(y\) 可以代表輸入的單詞是不是人名的一部分。技術上來講,還有更加複雜的輸出形式,它不只可以代表輸入詞是不是人名的一部分,它還可以告訴你這我的名在這個句子裏從哪裏開始到哪裏結束。api

以簡單的輸出形式爲例。這個輸入數據是 9 個單詞組成的序列,因此最終咱們會有 9 個特徵集合來表示這 9 個單詞,並按序列中的位置進行索引,\(x^{<1>},x^{<2>}\) 直到 \(x^{<9>}\) 來索引不一樣的位置。網絡

輸出數據也是同樣,用 \(y^{<1>},y^{<2>}\)\(y^{<9>}\) 來表示輸出數據。同時使用 \(T_x\) 來表示輸入序列的長度,\(T_y\) 表示輸出序列的長度。在這裏例子裏,\(T_x=9\),且 \(T_x=T_y\)app

想要表示一個句子裏的單詞,首先須要作一張詞表(或者說詞典),也就是列一列咱們的表示方法中用到的單詞。如下圖這個詞表爲例,它是一個 10,000 個單詞大小的詞表。這對現代天然語言處理應用來講過小了,對於通常規模的商業應用來講 30,000 到 50,000 詞大小的詞表比較常見,有些大型互聯網公司會有百萬詞等。less

咱們以這個 10,000 詞的詞表爲例。咱們用 one-hot 表示法來表示詞典裏的每一個單詞,也就是說 \(x^{<1>}\) 表示 Harry 這個單詞,而 Harry 在詞表中的第 4075 行,因此 \(x^{<1>}\) 最終表示爲一個長度爲 10,000,在 4075 行爲 1,其他行爲 0 的向量。同理,其餘的詞也這樣進行編碼。dom

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

若是直接把 9 個 one-hot 向量輸入到一個標準神經網絡中,通過一些隱藏層,最終會輸出 9 個值爲 0 或者 1 的項來代表每一個輸入單詞是不是人名的一部分。機器學習

可是結果發現這種方法並很差,主要有兩個問題。ide

  • 輸入和輸出數據在不一樣例子中能夠有不一樣的長度,不是全部的例子都有相同的 \(T_x\)\(T_y\)。並且即便每一個句子都有最大長度,咱們能夠填充使每一個輸入語句都達到最大長度,但這仍然不是一個很好的方式。
  • 這樣一個神經網絡結構,它並不共享從文本的不一樣位置上學到的特徵。也就是說,若是神經網絡已經學習到了在位置 1 出現的 Harry 多是人名的一部分,那麼若是 Harry 出如今其餘位置,它也能自動識別其爲人名的一部分的話就行了。這其實相似於卷積神經網絡中,咱們但願將圖片的局部學到的內容快速推廣到圖片的其餘部分。因此用一個更好的表達方式,可以讓咱們減小模型中參數的數量。

循環神經網絡以下圖所示。將第一個詞輸入一個神經網絡層,讓神經網絡嘗試預測輸出,判斷這是不是人名的一部分。而接下來第二個詞,它不只用 \(x^{<2>}\) 來預測 \(y^{<2>}\),它也會輸入來自上一層神經網絡的激活值,接下來的詞也以此類推。因此在每個時間步中,循環神經網絡傳遞一個激活值到下一個時間步中用於計算。若是 \(T_x\)\(T_y\) 不相等,這個結果會須要做出一些改變。

要開始整個流程,在零時刻須要構造一個激活值 \(a^{<0>}\),這一般是零向量。固然也有其餘初始化 \(a^{<0>}\) 的方法,不過使用零向量的僞激活值是最多見的選擇。

循環神經網絡是從左向右掃描數據,同時每一個時間步的參數也是共享的。咱們用 \(W_{ax}\) 來表示管理着從 \(x_{<1>}\) 到隱藏層的鏈接的一系列參數,而激活值也就是水平聯繫是由參數 \(W_aa\) 決定的,同理,輸出結果由 \(W_ya\) 決定。這些參數在每一個時間步都是相同的。

這個循環神經網絡的一個缺點就是它只使用了這個序列中以前的信息來作出預測,如預測 \(\hat{y}^{<3>}\) 時,它沒有用到 \(x^{<4>},x^{<5>}\) 等的信息。因此對於這兩個句子

Teddy Roosevelt was a great President.

Teddy bears are on sale!

爲了判斷 Teddy 是不是人名的一部分,僅僅知道句中前兩個詞是徹底不夠的。因此後續咱們須要使用雙向循環神經網絡 (BRNN) 來解決這個問題。

咱們仍以單向神經網絡爲例瞭解其計算過程。

通常開始先輸入 \(a^{<0>}\),接着就是前向傳播過程。
\[ a^{<1>} = g_{1}(W_{{aa}}a^{< 0 >} + W_{{ax}}x^{< 1 >} + b_{a})\\ \hat y^{< 1 >} = g_{2}(W_{{ya}}a^{< 1 >} + b_{y})\\ \cdots \cdots \]
循環神經網絡用的激活函數常常是 tanh,偶爾也會用 ReLU。

前向傳播公式的泛化公式以下,在 t 時刻
\[ a^{< t >} = g_{1}(W_{aa}a^{< t - 1 >} + W_{ax}x^{< t >} + b_{a})\\ \hat y^{< t >} = g_{2}(W_{{ya}}a^{< t >} + b_{y}) \]
咱們的符號約定,以 \(W_{ax}\) 爲例,第二個下標意味着它要乘以某個 \(x\) 類型的量,而後第一個下標 \(a\) 表示它是用來計算某個 \(a\) 類型的變量。其餘幾個矩陣符號也是同理。

爲了簡化這些符號,咱們能夠簡化一下,第一個計算 \(a^{<t>}\) 的公式能夠寫做
\[ a^{<t>} =g(W_{a}\left\lbrack a^{< t-1 >},x^{} \right\rbrack +b_{a}) \]
而後咱們定義 \(W_a\) 爲矩陣 \(W_{aa}\)\(W_{ax}\) 水平並列放置,即 \([ {{W}_{aa}}\vdots {{W}_{ax}}]=W_{a}\)。而 \(\left\lbrack a^{< t - 1 >},x^{< t >}\right\rbrack\) 表示的是將這兩個向量堆在一塊兒,即 \(\begin{bmatrix}a^{< t-1 >} \\ x^{< t >} \\\end{bmatrix}\)。這樣,咱們就把兩個參數矩陣壓縮成了一個參數矩陣,當咱們創建更復雜模型時,這能簡化咱們要用到的符號。

同理,對於 \(\hat y^{< t >}\) 的計算,也能夠寫做
\[ \hat y^{< t >} = g(W_{y}a^{< t >} +b_{y}) \]
RNN 前向傳播示意圖以下。

nn-

穿越時間的反向傳播

爲了計算反向傳播,咱們先定義一個元素損失函數。
\[ L^{}( \hat y^{},y^{}) = - y^{}\log\hat y^{}-( 1- y^{})log(1-\hat y^{}) \]
它對應的是序列中一個具體的詞,若是它是某我的的名字,那麼 \(y^{<t>}\) 的值爲 1,而後神經網絡將輸出這個詞是名字的機率值。它被定義爲標準邏輯迴歸損失函數,也叫交叉熵損失函數 (cross entropy loss)

整個序列的損失函數爲
\[ L(\hat y,y) = \ \sum_{t = 1}^{T_{x}}{L^{< t >}(\hat y^{< t >},y^{< t >})} \]
也就是把每一個單獨時間步的損失函數都加起來。

在這個反向傳播過程當中,最重要的信息傳遞或者說最重要的遞歸運算就是這個從右到左的運算,因此它被叫作穿越時間反向傳播 (backpropagation through time)

RNN 反向傳播示意圖以下。

nn_cell_backpro

不一樣類型的循環神經網絡

並非全部的狀況都知足 \(T_x=T_y\)。好比電影情感分類,輸出 \(y\) 能夠是 1 到 5 的整數,而輸入是一個序列。

以前的命名實體識別問題,屬於多對多 (many-to-many) 的結構。由於輸入序列有不少的輸入,而輸出序列也有不少的輸出。還有一種多對多結構,和命名實體識別問題不一樣,它的輸入和輸出的序列多是不一樣長度的。例如,機器翻譯,不一樣語言對於同一句話可能會有不一樣的長度的語句。而情感分類問題,屬於多對一 (many-to-one) 的結構。由於它有不少輸入,而後輸出一個數字。固然也有一對一 (one-to-one) 結構,也就是標準的神經網絡。
其實還有一對多 (one-to-many) 的結構。例子是音樂生成,咱們可使用神經網絡經過咱們輸入的一個整數(用來表示音樂類型或者第一個音符等信息)來生成一段音樂。

語言模型和序列生成

假如咱們在作一個語音識別系統,聽到一個句子

The apple and pear (pair) salad was delicious.

語音識別系統就要判斷,在這個句子中是 pear 仍是 pair。這裏,就要使用一個語言模型,它能計算出這兩句話各自的可能性。

這個機率指的是,假設咱們隨機拿起一張報紙,打開任意郵件,或者任意網頁或者聽某人說一句話,這個即將從世界上的某個地方獲得的句子會是某個特定句子的機率是多少。

使用 RNN 創建出這樣的模型,首先須要一個訓練集,包含一個很大的英文文本語料庫 (corpus) 或者其餘的語言(這取決於咱們的目的)。語料庫是天然語言處理的一個專有名詞,意思就是很長的或者說數量衆多的句子組成的文本。

若是訓練集中有這麼一句話

Cats average 15 hours of sleep a day.

那麼首先將這個句子標記化,就是像以前那樣,創建一個詞典,而後將每一個單詞都轉換爲對應的 one-hot 向量。而後咱們要定義句子的結尾,通常的作法就是增長一個額外的標記,叫作 EOS,用來表示句子的結尾。這樣能幫助咱們明白一個句子何時結束。

在標記化的過程當中,咱們能夠自行決定要不要把標點符號當作標記。若是要把標點符號看做標記的話,那麼咱們創建的詞典也應該加入這些標點符號。

若是訓練集有一些詞不在創建的詞典裏,以下面這個句子

The Egyptian Mau is a bread of cat.

Mau 這個詞可能比較少見,並不在咱們創建的詞典裏。這種狀況下,咱們能夠把 Mau 替換成一個叫作 UNK 的表明未知詞的標誌,咱們只針對 UNK 創建機率模型,而不是針對這個具體的詞 Mau。

完成標記化後,意味着輸入的句子都映射到了各個標誌上。下一步就是構建 RNN。

仍然以 "Cats average 15 hours of sleep a day。「 做爲輸入爲例。在第 0 個時間步,計算激活項 \(a^{<1>}\),它是以 \(x^{<1>}\) 做爲輸入的函數,而\(x^{<1>},a^{<1>}\) 都會被設爲全爲 0 的向量。因而 \(a^{<1>}\) 要作的就是它會經過 softmax 進行一些預測來計算出第一個詞可能會是什麼,結果爲 \(\hat{y}^{<1>}\)。這一步其實就是經過一個 softmax 層來預測詞典中任意單詞會是第一個詞的機率。

在下一時間步中,使用激活項 \(a^{<1>}\),而後輸入 \(x^{<2>}\) 告訴模型,第一個詞是 Cats,以此來計算第二個詞會是什麼。同理,輸出結果贊成通過 softmax 層進行預測,預測這些詞的機率。以此類推。

爲了訓練這個網絡,咱們須要定義代價函數。在某個時間步 \(t\),若是真正的詞是 \(y^{<t>}\),而神經網絡的 softmax 層預測結果值爲 \(\hat{y}^{<t>}\)。那麼 softmax 損失函數爲
\[ L\left( \hat y^{<t>},y^{<t>}\right) = - \sum_{i}^{}{y_{i}^{<t>}\log\hat y_{i}^{<t>}} \]
而整體損失函數爲
\[ L = \sum_{t}^{}{L^{< t >}\left( \hat y^{<t>},y^{<t>} \right)} \]
也就是把全部單個預測的損失函數相加。

若是咱們用很大的訓練集來訓練這個 RNN,那麼咱們能夠經過開頭一系列單詞來預測以後單詞的機率。假設一個新句子只有三個單詞,那麼這個句子的機率計算以下
\[ P(y^{<1>},y^{<2>},y^{<3>})=P(y^{<1>})P(y^{<2>}|y^{<1>})P(y^{<3>}|y^{<1>},y^{<2>}) \]

對新序列採樣

在訓練一個序列模型以後,要想了解這個模型學到了什麼,一種非正式的方法就是進行一次新序列採樣。

咱們要作的就是對這些機率分佈進行採樣來生成一個新的單詞序列。

第一步要作的就是對咱們想要模型生成的第一個詞進行採樣。輸入 \(x^{<1>},a^{<1>}\) 爲 0 向量,而後獲得一個 softmax 結果,根據這個 softmax 的分佈進行隨機採樣。也就是對這個結果使用 numpy 命令 (np.random.choice)。

而後根據模型結構,以此類推。直到獲得 EOS 標識或者達到所設定的時間步。若是不想採樣到未知標識 UNK,能夠拒絕採樣到的未知標識,繼續在剩下的詞中進行重採樣。

根據實際應用,也能夠構建一個基於字符的 RNN 結構,這樣字典僅包含從 a 到 z 的字母,也能夠再包含一些標點符號,特殊字符,數字等。這樣序列 \(y^{<1>},y^{<2>},\cdots\) 將會是單獨的字符而不是單詞。

這種結構優勢是,咱們沒必要擔憂會出現未知的標識。而一個主要缺點就是,最後會獲得太多太長的序列,計算成本比較高昂。

門控循環單元 (Gated recurrent unit, GRU)

循環神經網絡的梯度消失

對於下面兩個句子。

The cat, which already ate ......, was full.

The cats, which ate ......, were full.

前面的名詞和動詞應該保持一致的單複數形式,可是基本的 RNN 模型不擅長捕獲這種長期依賴效應。由於梯度消失問題,後面層的輸出偏差很難影響前面層的計算。

儘管梯度爆炸也是會出現,可是梯度爆炸很明顯。由於指數級大的梯度會讓參數變得極其大,以致於網絡參數崩潰,咱們會看到不少 NaN,這意味着網絡計算出現了數值溢出。若是發現了梯度爆炸問題,一個解決辦法就是用梯度修剪。梯度修剪的意思就是觀察梯度向量,若是它大於某個閾值,縮放梯度向量,保證它不會太大。

GRU

標準的 RNN 單元以下圖所示。

1521560729

使用 GRU 可使 RNN 更好地捕捉深層鏈接,並改善梯度消失問題。

仍然使用上面提到的單複數例子。GRU 會有個新的變量稱爲 \(c\),表明細胞 (cell),即記憶細胞。記憶細胞的做用是提供了記憶的能力,好比貓是單數仍是複數,當它看到以後的句子的時候,它仍可以判斷句子的主語是單數仍是複數。因而在時間 \(t\) 處,有記憶細胞 \(c^{<t>}\),而後 GRU 實際輸出了激活值 \(a^{<t>}\),且 \(c^{<t>}=a^{<t>}\)

在每一個時間步,咱們將用一個候選值重寫記憶細胞,即 \({\tilde{c}}^{<t>}\)。而後咱們用 tanh 函數來計算
\[ {\tilde{c}}^{<t>} =tanh(W_{c}\left\lbrack c^{<t-1>},x^{<t>} \right\rbrack +b_{c}) \]
GRU 中真正重要的思想是咱們有一個門,記爲 \(\Gamma_{u}\),其中下標 \(u\) 表明更新 (update) 。它是一個 0 到 1 之間的值。它的計算方式以下
\[ \Gamma_{u}= \sigma(W_{u}\left\lbrack c^{<t-1>},x^{<t>} \right\rbrack +b_{u}) \]
對於大多數可能的輸入,sigmoid 函數的輸出老是很是接近 0 或者 1,因此這個值大多數狀況下也是很是接近 0 或 1 的。

因此 GRU 的關鍵部分就是使用 \(\tilde{c}\) 來更新 \(c\),而後使用門來決定是否真的要更新。即
\[ c^{<t>} = \Gamma_{u}*{\tilde{c}}^{<t>} +\left( 1- \Gamma_{u} \right)*c^{<t-1>} \]
GRU 的一個簡化示意圖以下。

由於 \(\Gamma_u\) 很接近 0,那麼更新式子就會變成 \(c^{<t>}=c^{<t-1>}\)。也就是說,即便通過不少不少的時間步,\(c^{<t>}\) 的值也很好地被維持了,這就是緩解梯度消失問題的關鍵。

而對於一個完整的 GRU,咱們須要在計算第一個式子中給記憶細胞的新候選值加上一個新的項。咱們要添加一個新的門 \(\Gamma_r\),其中下標 \(r\) 能夠表明相關性 (relevance)。這個門的做用是告訴咱們,計算出的下一個 \(c^{<t>}\) 的候選值 \(\tilde{c}^{<t-1>}\)\(c^{<t-1>}\) 有多大的相關性。它的計算方式以下
\[ \Gamma_{r}= \sigma(W_{r}\left\lbrack c^{<t-1>},x^{<t>} \right\rbrack + b_{r}) \]
那麼完整的 GRU 計算公式則爲
\[ \tilde{c}^{<t>}=tanh(W_c[\Gamma_r\times c^{<t-1>},x^{<t>}]+b_c)\\ \Gamma_{u}= \sigma(W_{u}\left\lbrack c^{<t-1>},x^{<t>} \right\rbrack +b_{u})\\ \Gamma_{r}= \sigma(W_{r}\left\lbrack c^{<t-1>},x^{<t>} \right\rbrack + b_{r})\\ c^{<t>} = \Gamma_{u}*{\tilde{c}}^{<t>} +\left( 1- \Gamma_{u} \right)*c^{<t-1>}\\ a^{<t>}=c^{<t>} \]

長短時間記憶單元 (long short term memory unit, LSTM unit)

LSTM 是一個比 GRU 更增強大和通用的版本。

LSTM 的主要公式以下
\[ \tilde{c}^{<t>}=tanh(W_c[a^{<t-1>},x^{<t>}]+b_c)\\ \Gamma_u=\sigma(W_u[a^{<t-1>},x^{<t>}]+b_u)\\ \Gamma_f=\sigma(W_f[a^{<t-1>},x^{<t>}]+b_f)\\ \Gamma_o=\sigma(W_o[a^{<t-1>},x^{<t>}]+b_o)\\ c^{<t>}=\Gamma_u \times \tilde{c}^{<t>}+\Gamma_f \times c^{<t-1>}\\ a^{<t>}=\Gamma_o \times c^{<t>} \]
在 LSTM 中,咱們再也不有 \(a^{<t>}=c^{<t>}\),咱們專門使用 \(a^{<t>}\) 或者 \(a^{<t-1>}\),而不是用 \(c^{<t-1>}\),也再也不用相關門 \(\Gamma_r\)。LSTM 保留了更新門,但不只僅由更新門來控制,加入了遺忘門 (the forget gate) \(\Gamma_f\)輸出門 (the output gate) \(\Gamma_o\)

因此給了記憶細胞選擇權去維持舊的值 \(c^{<t-1>}\) 或者加上新的值 \(\tilde{c}^{<t>}\)

LSTM 示意圖以下。

能夠發如今上圖中的序列中,上面有條線顯示了只要正確地設置了遺忘門和更新門,LSTM 是很容易把 \(c^{<0>}\) 的值一直往下傳遞的。固然,這個圖示和通常使用的版本有些許不一樣。最經常使用的版本的門值不只取決於 \(a^{<t-1>}\)\(x^{<t>}\),偶爾也能夠偷窺一下 \(c^{<t-1>}\) 的值(上圖中編號 13),這叫作窺視孔鏈接 (peephole connection)

LSTM 前向傳播圖:

ST

STM_rn

LSTM 反向傳播計算:

門求偏導
\[ d \Gamma_o^{\langle t \rangle} = da_{next}*\tanh(c_{next}) * \Gamma_o^{\langle t \rangle}*(1-\Gamma_o^{\langle t \rangle})\\ d\tilde c^{\langle t \rangle} = dc_{next}*\Gamma_i^{\langle t \rangle}+ \Gamma_o^{\langle t \rangle} (1-\tanh(c_{next})^2) * i_t * da_{next} * \tilde c^{\langle t \rangle} * (1-\tanh(\tilde c)^2)\\ d\Gamma_u^{\langle t \rangle} = dc_{next}*\tilde c^{\langle t \rangle} + \Gamma_o^{\langle t \rangle} (1-\tanh(c_{next})^2) * \tilde c^{\langle t \rangle} * da_{next}*\Gamma_u^{\langle t \rangle}*(1-\Gamma_u^{\langle t \rangle})\\ d\Gamma_f^{\langle t \rangle} = dc_{next}*\tilde c_{prev} + \Gamma_o^{\langle t \rangle} (1-\tanh(c_{next})^2) * c_{prev} * da_{next}*\Gamma_f^{\langle t \rangle}*(1-\Gamma_f^{\langle t \rangle}) \]
參數求偏導
\[ dW_f = d\Gamma_f^{\langle t \rangle} * \begin{pmatrix} a_{prev} \\ x_t\end{pmatrix}^T\\ dW_u = d\Gamma_u^{\langle t \rangle} * \begin{pmatrix} a_{prev} \\ x_t\end{pmatrix}^T\\ dW_c = d\tilde c^{\langle t \rangle} * \begin{pmatrix} a_{prev} \\ x_t\end{pmatrix}^T\\ dW_o = d\Gamma_o^{\langle t \rangle} * \begin{pmatrix} a_{prev} \\ x_t\end{pmatrix}^T \]
爲了計算 \(db_f, db_u, db_c, db_o\),須要各自對 \(d\Gamma_f^{\langle t \rangle}, d\Gamma_u^{\langle t \rangle}, d\tilde c^{\langle t \rangle}, d\Gamma_o^{\langle t \rangle}\) 求和。

最後,計算隱藏狀態、記憶狀態和輸入的偏導數。
\[ da_{prev} = W_f^T*d\Gamma_f^{\langle t \rangle} + W_u^T * d\Gamma_u^{\langle t \rangle}+ W_c^T * d\tilde c^{\langle t \rangle} + W_o^T * d\Gamma_o^{\langle t \rangle} \\ dc_{prev} = dc_{next}\Gamma_f^{\langle t \rangle} + \Gamma_o^{\langle t \rangle} * (1- \tanh(c_{next})^2)*\Gamma_f^{\langle t \rangle}*da_{next} \\ dx^{\langle t \rangle} = W_f^T*d\Gamma_f^{\langle t \rangle} + W_u^T * d\Gamma_u^{\langle t \rangle}+ W_c^T * d\tilde c_t + W_o^T * d\Gamma_o^{\langle t \rangle} \]
何時用 GRU,何時用 LSTM,其實沒有統一的標準。

GRU 的優勢是,它是個更加簡單的模型,因此容易建立一個更大的網絡,並且它只有兩個門,在計算性上也運行得更快,而後它能夠擴大模型的規模。

可是 LSTM 更增強大和靈活。如今大部分的人仍是會把 LSTM 做爲默認的選擇來嘗試。

雙向循環神經網絡

咱們以一個只有 4 個單詞的句子爲例。那麼這個網絡會有一個前向的循環單元爲 \({\overrightarrow{a}}^{<1>},{\overrightarrow{a}}^{<2>},{\overrightarrow{a}}^{<3>},{\overrightarrow{a}}^{<4>}\),這四個循環單元輸入,都會獲得對應的輸出 \(\hat{y}^{<1>},\hat{y}^{<2>},\hat{y}^{<3>},\hat{y}^{<4>}\)

接下來,咱們增長一個反向循環層,\({\overleftarrow{a}}^{<1>},{\overleftarrow{a}}^{<2>},{\overleftarrow{a}}^{<3>},{\overleftarrow{a}}^{<4>}\),一樣這一層也向上鍊接。這樣,這個網絡以下所示。先前向計算,而後再反向計算,把全部激活值都計算完了就能夠計算預測結果了。

這些單元能夠是標準 RNN 單元,也能夠是 GRU 或者 LSTM 單元。並且實踐中,不少 NLP 問題,有 LSTM 單元的雙向 RNN 模型是用得最多的。

BRNN 的缺點就是須要完整的數據序列,才能預測任意位置。

深層循環神經網絡 (Deep RNNs)

一個標準的神經網絡,首先是輸入 \(x\),而後堆疊上隱含層。深層 RNN 相似,堆疊隱含層,而後每層按時間展開就是了,以下圖所示。

對於標準的神經網絡,可能有很深的網絡,可是對於 RNN 來講,有三層就已經很多了。因爲時間的維度,RNN 網絡會變得至關大。

詞嵌入 (Word embedding)

詞嵌入是語言表示的一種方式,可讓算法自動的理解一些相似的詞。好比男人對女人,國王對王后等等。

以前咱們是用詞典的 one-hot 向量來表示詞,好比說 man 在詞典中第 5391 個位置,那麼它的 one-hot 向量標記爲 \(O_{5391}\)。這種表示方法的一大缺點就是它把每一個詞都孤立起來了,使得算法對相關詞的泛化能力不強。

舉個例子,咱們的語言模型已經學習到了 "I want a glass of orange juice",可是當它看到 "I want a glass of apple ____" 時,算法可能沒法填出 juice 這個單詞。算法不知道 apple 和 orange 的關係很接近,由於任何兩個 one-hot 向量的內積都是 0。

可是若是咱們用特徵化來表示每一個詞,假如說這些特徵維度 Gender, Royal, Age 等等,這樣對於不一樣的單詞,算法會泛化得更好。

固然,咱們最終學習的特徵可能不會像 Gender, Royal 等這些比較好理解,甚至不太好用實際意義去解釋。

接下來,咱們能夠把詞嵌入應用到命名實體識別任務當中,儘管咱們可能只有一個很小的訓練集,100,000 個單詞,甚至更小。咱們可使用遷移學習,把互聯網上免費得到的大量的無標籤文本中學習到的知識遷移到一個任務中。

因此,如何用詞嵌入作遷移學習的步驟以下:

  • 先從大量的文本集中學習詞嵌入。一個很是大的文本集,或者能夠下載網上預訓練好的詞嵌入模型,網上能夠知道很多,並且詞嵌入模型通常都有許可。
  • 用這些詞嵌入模型遷移到咱們的新的只有少許標註訓練集的任務中,好比說用一個 300 維的詞嵌入來表示單詞。
  • 在新的任務上訓練模型,能夠選擇要不要繼續微調,用新的數據調整詞嵌入。固然,通常來講,只有新數據有比較大的數據量時,纔會進行微調。

假如說咱們以這四個維度的特徵來表徵詞。詞的特徵向量都以符號 \(e\) 表示。

那麼
\[ e_{\text{man}} - e_{\text{woman}} = \begin{bmatrix} - 1 \\ 0.01 \\ 0.03 \\ 0.09 \\ \end{bmatrix} - \begin{bmatrix} 1 \\ 0.02 \\ 0.02 \\ 0.01 \\ \end{bmatrix} = \begin{bmatrix} - 2 \\ - 0.01 \\ 0.01 \\ 0.08 \\ \end{bmatrix} \approx \begin{bmatrix} - 2 \\ 0 \\ 0 \\ 0 \\ \end{bmatrix}\\ e_{\text{king}} - e_{\text{queen}} = \begin{bmatrix} - 0.95 \\ 0.93 \\ 0.70 \\ 0.02 \\ \end{bmatrix} - \begin{bmatrix} 0.97 \\ 0.95 \\ 0.69 \\ 0.01 \\ \end{bmatrix} = \begin{bmatrix} - 1.92 \\ - 0.02 \\ 0.01 \\ 0.01 \\ \end{bmatrix} \approx \begin{bmatrix} - 2 \\ 0 \\ 0 \\ 0 \\ \end{bmatrix} \]
能夠發現這兩組向量相減獲得的向量基本一致。也就代表,這兩對詞都只在 gender 這個特徵維度有顯著差別。

咱們可使用餘弦類似度來表徵這些向量的類似度。
\[ \text{sim}\left( u,v \right) = \frac{u^{T}v}{\left| \left| u \right| \right|_{2}\left| \left| v \right| \right|_{2}} \]
這樣,咱們就能經過計算類似度來找到相近的詞。

當咱們應用算法來學習詞嵌入時,實際上是在學習一個嵌入矩陣 (embedding matrix)

假設咱們的詞典有 10,000 個單詞,咱們要作的就是學習一個嵌入矩陣 \(E\),它將是一個 \(300\times10,000\) 的矩陣。這個矩陣的各列表明的是詞典中 10,000 個單詞所表明的特徵向量。

學習詞嵌入

創建一個語言模型是學習詞嵌入的好方法。

如何創建神經網絡來預測序列中的下一個單詞呢?首先,如下圖中的句子爲例。先使用 one-hot 向量表示這些單詞,而後生成一個參數矩陣 \(E\),用 \(E\) 乘以 one-hot 向量 \(o\),這樣獲得嵌入向量 \(e\)。因而咱們有了不少 300 維的嵌入向量,把它們放進神經網絡中,而後再經過一個 softmax 層,而後 softmax 分類器會在 10,000 個可能的輸出中預測結尾這個單詞。

實際上,更常見的是有一個固定的歷史窗口。舉個例子,咱們老是想預測給定四個單詞(也能夠是其餘的個數)後的下一個單詞,這樣就能夠適應很長或者很短的句子。用一個固定的歷史窗口意味着能夠處理任意長度的句子,由於輸入的維度老是固定的。因此,這個模型的參數就是矩陣 \(E\),對全部的單詞用的都是同一個矩陣 \(E\)

固然除了選前四個單詞,還有其餘的上下文構建方式。可是創建語言模型,用目標詞的前幾個單詞做爲上下文是常見作法。

Word2Vec

假設在訓練集中給定了一個這樣的句子 "I want a glass of orange juice to go along with my cereal.",在 skip-gram 模型中,咱們要作的是抽取上下文和目標詞配對,來構造一個監督學習問題。上下文不必定老是目標單詞之間離得最近的四個單詞或 n 個單詞。

咱們要作的是隨機選一個詞做爲上下文詞,而後隨機在必定詞距內選另外一個詞做爲目標詞。因而咱們將構造一個監督學習問題,它給定上下文詞,要求預測在這個詞必定詞距內隨機選擇的某個目標詞。顯然,這不是個很是簡單的學習問題。可是,構造這個監督學習問題的目標並非想要解決這個監督學習問題自己,而是想要使用這個學習問題來學到一個好的詞嵌入模型。

咱們要解決的基本的監督學習問題是學習一種映射關係,從上下文 \(c\) 到某個目標詞 \(t\)。從 one-hot 向量 \(O_c\) 開始,而後乘以嵌入矩陣 \(E\) 獲得上下文詞的嵌入向量,\(e_c=EO_c\)。接着,把向量 \(e_c\) 喂入 softmax 單元,輸出 \(\hat{y}\),預測不一樣目標詞的機率:
\[ Softmax:p(t|c)=\frac{e^{\theta_t^T e_c}}{\sum_{j=1}^{10,000}e^{\theta_j^T e_c}} \]
其中 \(\theta_t\) 是一個與輸出 \(t\) 有關的參數,即某個詞 \(t\) 和標籤相符的機率是多少,這裏省略了 softmax 中的誤差項,想要加上的話也是能夠加上的。

因而 softmax 的損失函數爲
\[ L(\hat{y},y)=-\sum_{i=1}^{10,000}y_i\log{\hat{y_i}} \]
矩陣 \(E\) 將會有不少參數,優化這個關於全部這些參數的損失函數,就能獲得一個較好的嵌入向量集。這個就叫作 skip-gram 模型。

這個算法首要的問題就是計算速度,尤爲是在 softmax 模型中,每次要計算這個機率,就要對詞典中全部詞作求和計算,這個求和操做是至關慢的。

這裏有一些解決方案,如分級 (hierarchical) 的 softmax 分類器負採樣 (Negative Sampling)

分級 softmax 分類器

這個分類器的意思是,經過一層一層的節點來分類詞。這樣計算成本與詞典大小的對數成正比,而不是詞典大小的線性函數。在實踐中,不會使用一棵完美平衡的分類樹或者說一棵左邊和右邊分支的詞數相同的對稱樹,而是會被構形成經常使用詞在頂部,不經常使用的詞在樹的更深處。這是一種加速 softmax 分類器的方法。

負採樣

這個算法要作的是構造一個新的監督學習算法。給定一對單詞來預測者是不是一對上下文詞-目標詞 (context-target)。

好比,orange 和 juice 爲一對正樣本,orange 和 king 爲一對負樣本。咱們要作的就是採樣獲得一個上下文詞和一個目標詞。正樣本的生成方式與 word2vec 相似,先抽取一個上下文詞,在必定詞距內選一個目標詞,標記爲 1。而後爲了生成一個負樣本,咱們將用相同的上下文詞,再在字典中隨機選一個詞,標記爲 0。若是咱們挑選負樣本的時候,從字典中隨機選到的詞,正好出如今了詞距內,可是咱們標記爲負樣本也不要緊。

而後,咱們將構造一個監督學習問題。咱們的算法輸入詞對,預測其標籤。

K 值的選取。論文做者推薦小數據集的話,K 從 5 到 20 比較好;若是數據集很大,K 就選的小一點,如 K 等於 2 到 5。這個例子中,咱們使 \(K=4\)

咱們定義一個邏輯迴歸模型,給定輸入的 \(c,t\) 對(上下文詞 \(c\) 和目標詞 \(t\))的條件下輸出 \(y=1\) 的機率,即
\[ P(y=1|c,t)=\sigma(\theta_t^Te_c) \]
把它畫成一個神經網絡,若是輸入詞是 orange,即第 6257 個詞,那麼輸入它的 one-hot 向量,乘以嵌入矩陣 \(E\),得到嵌入向量 \(e_{6257}\)。這樣,咱們獲得了 10,000 個可能的邏輯迴歸分類問題。其中一個是用來判斷目標詞是不是 juice 的分類器。但不是每次迭代都訓練所有 10,000 個,\(K=5\) 時,咱們只訓練其中的 5 個。訓練對應真正目標詞那一個分類器,再訓練 4 個隨機選取的負樣本,因此不使用一個巨大的 softmax,而是把它轉變爲多個二分類問題。二分類問題每一個都很容易計算,並且每次迭代只要訓練它們其中的幾個。

其中一個重要的細節就是如何選取負樣本。一個方法是根據語言中的經驗頻率對這些詞進行採樣,可是 like, the, of, and 這種詞有很高的頻率。另外一個就是用 1 除以詞典總詞數,即 \(\frac{1}{|v|}\),均勻且隨機地抽取負樣本,可是這對於英文單詞的分佈是很是沒有表明性的。做爲一個折中,論文做者根據經驗,採用如下方式進行採樣,也就是實際觀察到的英文文本的分佈:
\[ P(w_i)=\frac{{f(w_i)^{\frac{3}{4}}}}{\sum_{j=1}^{10,000}{f(w_j)}^{\frac{3}{4}}} \]
也就是 \(f(w_i)\) 是觀測到的在語料庫中的某個單詞的詞頻,經過 \(\frac{3}{4}\) 次方的計算,使其處於徹底獨立的分佈和訓練集的觀測分佈兩個極端之間。

GloVe 詞向量

GloVe 算法不如 Word2Vec 或是 Skip-Gram 模型用的多,可是也有研究者熱衷於它,多是由於其簡便性。

GloVe 表明用詞表示的全局變量。仍是挑選語料庫中位置相近的兩個詞,即上下文-目標詞。GloVe 算法作的就是使其關係開始明確化。假設 \(X_{ij}\) 是單詞 \(i\) 在單詞 \(j\) 上下文中出現的次數,那麼這裏 \(i\)\(j\) 就和 \(t\)\(c\) 的功能同樣。

若是對於上下文的定義是目標詞必定範圍詞距的單詞,那麼 \(X_{ij}=X_{ji}\);而若是對於上下文的定義爲目標詞的前一個單詞,那麼 \(X_{ij}\)\(X_{ji}\) 就不會相同。

不過對於 GloVe 算法,咱們能夠定義上下文和目標詞爲任意兩個位置相近的單詞,假設是左右各 10 詞的距離,那麼 \(X_{{ij}}\) 就是一個可以獲取單詞 \(i\) 和單詞 \(j\) 出現位置相近時或是彼此接近的頻率的計數器。GloVe 模型作的就是進行優化,將它們之間的差距進行最小化處理。
\[ minimize \sum_{i=1}^{10,000} \sum_{j=1}^{10,000} f(X_{ij})(\theta_i^Te_j+b_i+b_j'-\log{X_{ij}})^2 \]
而若是 \(X_{ij}=0\) 的話,\(log0\) 爲未定義,爲負無窮大。因此公式中加上了一個額外的加權項 \(f(X_{ij})\),這樣 \(X_{ij}=0\) 時,咱們有 \(0log0=0\)。這個加權項還有一個做用是,有些詞在英語中出現十分頻繁如 this, is, of, a 等,它們被叫做中止詞,加權項能夠給予大量有意義的運算給不經常使用詞,一樣給中止詞更大但不至於過度的權重。所以,有一些對加權函數 \(f\) 的選擇有着啓發性的原則。

情感分類 (Sentiment Classification)

情感分類任務就是看一段文本,而後分辨這我的是否喜歡他們在討論的這個東西,這是天然語言處理中最重要的模塊之一,常常用在許多應用中。情感分類一個最大的挑戰就是可能標記的訓練集沒有那麼多,可是有了詞嵌入,即便只有中等大小的標記的訓練集,也能構建一個不錯的情感分類器。

下圖是一個簡單的情感分類模型。假設輸入爲 "The dessert is excellent",咱們從詞典中取出這些詞,而後造成 one-hot 向量,乘以嵌入矩陣 \(E\) 來獲取嵌入向量。其中嵌入矩陣能夠從很大的訓練集上訓練得到。接着,對這些嵌入向量進行求和或者平均,就會獲得一個特徵向量,把它輸入 softmax 分類器,輸出 \(\hat{y}\) 也就是一星到五星的機率值。

這個算法運用的平均值運算單元適用於任何長短的評論,它實際上會把全部單詞的意思給平均起來。

這個算法有一個問題就是沒有考慮詞序,尤爲是這樣一個負面的評價。

"Completely lacking in good taste, good service, and good ambiance."

這個句子中出現了不少 good,分類器極可能會認爲這是一個好的評價。

這樣,咱們有一個更加複雜的模型來處理,使用 RNN 來作情感分類。以下圖所示。

詞嵌入糾偏

一個已經完成學習的詞嵌入可能會輸出ManComputer Programmer,同時輸出WomanHomemaker,那個結果看起來是錯的,而且它執行了一個十分不良的性別歧視。所以根據訓練模型所使用的文本,詞嵌入可以反映出性別、種族、年齡、性取向等其餘方面的偏見,一件我尤爲熱衷的事是,這些偏見都和社會經濟狀態相關,我認爲每一個人不論你出身富裕仍是貧窮,亦或是兩者之間,我認爲每一個人都應當擁有好的機會,同時由於機器學習算法正用來制定十分重要的決策,它也影響着世間萬物,從大學錄取到人們找工做的途徑,到貸款申請,不論你的的貸款申請是否會被批准,再到刑事司法系統,甚至是判決標準,學習算法都在做出很是重要的決策,因此我認爲咱們儘可能修改學習算法來儘量減小或是理想化消除這些非預期類型的偏見是十分重要的。

假設說咱們已經完成一個詞嵌入的學習,先咱們要作的事就是辨別出咱們想要減小或想要消除的特定偏見的趨勢。

以性別偏見爲例。主要有如下三個步驟。

  • 對於性別偏見來講。咱們將一些性別相關的詞對進行嵌入向量相減,如 \(e_{he}-e_{she},e_{male}-e_{female}\),而後將這些值取平均。這個趨勢,看起來就是性別趨勢,可是與咱們想要處理的特定偏見無關,因此這就是個無偏的性別趨勢。實際上,它會用一個更加複雜的算法——奇異值分解(SVU),和主成分分析很相似。

  • 中和步驟。對於那些定義不確切的詞能夠將其處理一下。如 grandmother, grandfather 這些詞定義中原本就含有性別意義,而 doctor, babysitter 這些詞咱們但願它是中立的。因此對於中立詞,咱們想要減小他們在水平方向上的距離。

  • 均衡步。意思是說你可能會有這樣的詞對,grandmother和grandfather,或者是girl和boy,對於這些詞嵌入,你只但願性別是其區別。那爲何要那樣呢?在這個例子中,babysitter和grandmother之間的距離或者說是類似度其實是小於babysitter和grandfather之間的(上圖編號1所示),所以這可能會加劇不良狀態,或者多是非預期的偏見,也就是說grandmothers相比於grandfathers最終更有可能輸出babysitting。因此在最後的均衡步中,咱們想要確保的是像grandmother和grandfather這樣的詞都可以有一致的類似度,或者說是相等的距離,和babysitter或是doctor這樣性別中立的詞同樣。這其中會有一些線性代數的步驟,但它主要作的就是將grandmother和grandfather移至與中間軸線等距的一對點上(上圖編號2所示),如今性別歧視的影響也就是這兩個詞與babysitter的距離就徹底相同了(上圖編號3所示)。因此整體來講,會有許多對像grandmother-grandfather,boy-girl,sorority-fraternity,girlhood-boyhood,sister-brother,niece-nephew,daughter-son這樣的詞對,咱們可能想要經過均衡步來解決它們。

均衡背後的關鍵思想是確保一對特定的單詞與49維\(g_\perp\)距離相等 。均衡步驟還能夠確保兩個均衡步驟如今與\(e_{receptionist}^{debiased}\) 距離相同,或者用其餘方法進行均衡。下圖演示了均衡算法的工做原理:

qualize1

主要步驟以下:

$$
\mu = \frac{e_{w1} + e_{w2}}{2}\

\mu_{B} = \frac {\mu * \text{bias_axis}}{||\text{bias_axis}||_2} + ||\text{bias_axis}||_2 *\text{bias_axis}\

\mu_{\perp} = \mu - \mu_{B} \

e_{w1B} = \sqrt{ |{1 - ||\mu_{\perp} ||^2_2} |} * \frac{(e_{{w1}} - \mu_{\perp}) - \mu_B} {|(e_{w1} - \mu_{\perp}) - \mu_B)|}\

e_{w2B} = \sqrt{ |{1 - ||\mu_{\perp} ||^2_2} |} * \frac{(e_{\text{w2}} - \mu_{\perp}) - \mu_B} {|(e_{w2} - \mu_{\perp}) - \mu_B)|} \

$e_1 = e_{w1B} + \mu_{\perp} \
$e_2 = e_{w2B} + \mu_{\perp}
$$

序列模型

基礎模型

如何構建一個網絡來實現機器翻譯呢?好比實現輸出法語句子 "Jane visite I'Afrique en septembre.",輸出英語句子 "Jane is visiting Africa in September."。

首先,創建一個網絡,這個網絡叫編碼網絡 (encoder network),以下圖編號 1 所示。它是一個 RNN 的結構,RNN 的單元能夠是 GRU 也能夠是 LSTM。每次只向該網絡中輸入一個法語單詞,將輸入序列接收完畢後,這個 RNN 網絡會輸出一個向量來表明這個輸入序列。在這個網絡後面,咱們創建一個解碼網絡 (decoder network),以下圖編號2所示。它以編碼網絡的輸出做爲輸入,被訓練爲每次輸出一個翻譯後的單詞,一直到它輸出序列的結尾或者句子結尾標記。

這個模型簡單地用一個編碼網絡來對輸入的法語句子進行編碼,而後用一個解碼網絡來生成對應的英語翻譯。

與此相似的結構也被用來作圖像描述,給出一張圖片,以下圖中的貓的圖片,它能自動地輸出該圖片的描述:一隻貓坐在椅子上。

咱們以前已經知道如何將圖片輸入到卷積神經網絡中,好比一個預訓練的 AlexNet 結構(上圖編號 2)。而後讓其學習圖片的編碼或者學習圖片的一系列特徵,也就是去掉 softmax 單元(上圖編號 3)後的部分會輸出一個 4096 維的特徵向量,也就是一個圖像的編碼網絡。而後把這個向量輸入到 RNN 中(上圖編號 4),使用 RNN 來生成圖像的描述。

選擇最可能的句子

咱們能夠把機器翻譯當作是創建一個條件語言模型,在語言模型中上方是一個咱們以前創建的模型,這個模型能夠估計句子的可能性,也就是語言模型所作的事情。而機器翻譯分爲兩部分:編碼網絡(下圖綠色)和解碼網絡(下圖紫色),而咱們發現解碼網絡其實和語言模型幾乎如出一轍。不一樣在於語言模型老是以零向量(下圖編號 4)開始,而機器翻譯的編碼網絡會計算出一系列向量(下圖編號 2)來表示輸入的句子,解碼網絡則以這個句子的特徵開始,而不是零向量。因此吳恩達老師稱之爲條件語言模型 (conditional language model)

咱們想實現真正地經過模型將法語翻譯成英文,經過輸入的法語句子獲得各類英文翻譯所對應的可能性。\(x\) 在這裏是法語句子 "Jane visite I'Afrique en septembre"。咱們不想讓模型隨機地輸出,即從獲得的分佈中進行隨機取樣,而是找到一個英語句子 \(y\),使得條件機率最大化。

解決這種問題,最通用的算法就是集束搜索 (Beam Search),而不用貪心搜索 (Greedy Search)

貪心搜索指的是一種來自計算機科學的算法。生成第一個詞的分佈之後,它將會根據條件語言模型挑選出最有可能的第一個詞進入機器翻譯模型中,而後繼續挑選最有可能的第二個詞,接着一直日後挑選最有可能的詞。

可是咱們真正須要的是一次性挑選出整個單詞序列,從 \(y^{<1>},y^{<2>}\)\(y^{<T_y>}\) 來使得總體的機率最大化。因此貪心算法並無論用。

上圖中編號 1 的翻譯明顯比編號 2 的好,因此咱們但願機器翻譯模型會輸出第一個句子的 \(P(y|x)\) 比第二個句子要高。但若是使用貪心算法來挑選出了 "Jane is" 做爲前兩個詞,由於在英語中 going 更加常見,因此模型會選擇 "Jane is going" 而不是 "Jane is visiting" 做爲翻譯,最終獲得一個欠佳的句子。

集束搜索算法首先作的就是挑選要輸出的英語翻譯中的第一個單詞,爲了簡化問題,咱們忽略大小寫,列出了 10,000 個詞的詞彙表。集束搜索的第一步是用這個網絡(綠色是編碼網絡;紫色是解碼網絡),來評估第一個單詞的機率值。給定輸入序列 \(x\),即法語句子,輸出 \(y\) 的機率值是多少。

貪婪算法只會挑選最可能的一個單詞,而後繼續,而集束搜索則會考慮多個選擇。集束搜索算法會有一個參數 \(B\),稱爲集束寬 (beam width)。本例中咱們設爲 3,意味着集束搜索一次會考慮 3 個詞,而後把結果存在計算機內存裏以便後面嘗試使用這三個詞。

假設咱們選出了第一個單詞三個最有可能的選擇爲 in, jane, september,集束搜索的第二步會針對每一個第一個單詞考慮第二個單詞是什麼,以下圖編號 1。爲了評估第二個詞的機率值,咱們用神經網絡,綠色是編碼部分(下圖編號 2)。對於解碼部分,當決定單詞 in 後面是什麼時,解碼器的第一個輸出 \(y^{<1>}\) 爲 in (下圖編號 3),而後把它喂回下一個網絡單元(下圖編號 4)。這裏的目的是找出第一個單詞是 in 的狀況下,第二個單詞是什麼,即 \(y^{<2>}\) (下圖編號 5)。

在第二步中,咱們更關心的是要找到最可能的單詞對(下圖編號 7),而不只僅是最大機率的第二個單詞。按照條件機率的準則,單詞對的機率能夠表示爲第一個單詞的機率(下圖編號 8)乘以以第一個單詞爲條件的第二個單詞的機率(下圖編號 9),然後者能夠從編號 10 的網絡中獲得。

同理,對於第一個單詞的第二個備選 "jane" ,第三個備選 "september" 也是一樣的步驟。因爲咱們一直用的集束寬爲 3,而且詞彙表裏有 10,000 個單詞,那麼最終會有 \(3\times10,000\) 也就是 30,000 個可能的結果。而後依舊按照單詞對的機率選出前三個,減小到集束寬的大小。集束搜索算法會保存這些結果,而後用於下一次集束搜索。

接下來的步驟,繼續選擇與第二步相似。值得注意的是,若是集束寬等於 1,只考慮一種可能結果,這實際上就變成了貪婪搜索算法。

改進集束搜索

有一些小技巧能夠幫助集束搜索算法運行的更好。

長度歸一化 (length normalization) 就是對集束搜索算法稍做調整的一種方式。集束搜索其實就是最大化
\[ \begin{equation} \mathop{\arg\max}_{y} \prod_{t=1}^{T_y}P(y^{<t>}|x,y^{<1>},\dots,y^{<t-1>}) \end{equation} \]
而連乘的乘積其實就是 \(P(y^{<1>},\dots,y^{<{T_y}>}|x)\)。若是計算它,其實相乘的這些機率值都是小於 1 的,一般遠小於 1。而不少小於 1 的數相乘,會獲得很小很小的數字,會形成數值下溢 (numerical underflow)。指的是數值過小了,致使電腦的浮點表示不能精確地存儲。所以在實踐中,咱們取 log 值,從而獲得一個數值上更穩定的算法。即
\[ \begin{equation} \mathop{\arg\max}_{y} \sum_{t=1}^{T_y}\log P(y^{<t>}|x,y^{<1>},\dots,y^{<t-1>}) \end{equation} \]
對於目標函數,還能夠作一些改變,可使得機器翻譯表現得更好。若是使用上面的目標函數,那麼對於一個很長的句子,這個句子的機率會很低,由於乘了不少項小於 1 的數字。因此這個目標函數有一個缺點是,它可能不天然地傾向於簡短的翻譯結果。咱們能夠再也不最大化這個目標函數,而是對其進行歸一化,經過除以翻譯結果的單詞數 \(T_y\)。這樣就是取每一個單詞的機率對數值的平均了,這樣很明顯地減小了對輸出長的結果的懲罰。即
\[ \begin{equation} \frac{1}{T_y^{\alpha}} \sum_{t=1}^{T_y}\log P(y^{<t>}|x,y^{<1>},\dots,y^{<t-1>})\end{equation} \]
上式中的參數 \(\alpha\),可使得歸一化更加柔和,\(\alpha\) 能夠等於 0.7。若是 \(\alpha\) 等於 1,就至關於徹底用句子長度來歸一化,若是 \(\alpha\) 等於 0,就至關於徹底沒有歸一化。它就是算法另外一個超參數,須要調整大小來獲得最好的結果。

對於如何選擇集束寬參數 \(B\)\(B\) 越大,考慮的選擇越多,找到的句子可能越好;可是算法的計算代價也會越大,算法會運行得慢一些,內存佔用也會增大。在實踐中,其實使用 \(B=3\) 有點偏小。在生產中,常常能夠看到把集束寬設爲 10,集束寬爲 100 對於生產系統來講有點過大;但對於科研來講,人們想得到最好的結果用來發表論文,因此常常能夠看到集束寬爲 1,000 甚至 3,000。對不少應用來講,從集束寬爲 1,到 3,到 10,可能能夠看到一個很大的提高;可是當集束寬從 1,000 增長到 3,000 時,效果可能就沒那麼明顯了。

集束搜索的偏差分析

如下面的例子來講明。

仍然須要翻譯法語句子 "Jane visite I'Afrique en septembre"。假設機器翻譯的 dev 集中,也就是開發集 (development set),人工是這樣翻譯的 "Jane visits Africa in September",記爲 \(y^*\)。當已經完成學習 RNN 模型,也就是已完成學習的翻譯模型中運行集束搜索算法時,它輸出的翻譯爲 "Jane visited Africa last September",記爲 \(\hat{y}\)

咱們的模型有兩個主要部分:RNN 模型和集束搜索算法。如今,咱們想要找出形成輸出 \(\hat{y}\) 這個不太好的翻譯的緣由。

RNN 其實是個編碼器和解碼器,它會計算 \(P(y|x)\)。咱們可使用這個模型來計算 \(P(y^*|x)\)\(P(\hat{y}|x)\),而後比較一下這兩個值哪一個更大。

第一種狀況: \(P(y^*|x)>P(\hat{y}|x)\)

這種狀況下,意味着集束搜索選擇了 \(\hat{y}\),也就是集束搜索算法此時不可以輸出一個使 \(P(y|x)\) 最大化的 \(y\) 值,由於集束搜索算法的目的就是尋找一個 \(y\) 值來使它更大。

所以這種狀況下,咱們可以得出是集束搜索算法出錯了。

第二種狀況: \(P(y^*|x)\le P(\hat{y}|x)\)

這種狀況下,意味着相比與 \(\hat{y}\)\(y^*\) 成爲輸出的可能性更小,可是後者其實上是比前者更好的翻譯結果。也就是說,這種狀況下,是 RNN 模型出了問題。

因此偏差分析的過程其實就以下圖這樣。先遍歷開發集,而後在其中找出算法產生的錯誤。經過這個過程,咱們就可以執行偏差分析,得出集束搜索算法和 RNN 模型出錯的比例,來指導模型的優化。

Bleu 得分

Bleu 表明的是 bilingual evaluation understudy (雙語評估替補),這是一種常見的衡量機器翻譯的準確性的方法。

假如咱們有一個法語句子 "Le chat est sur le tapis",而後其對應的一我的工翻譯參考爲 "The cat is on the mat"。不過有多種至關不錯的翻譯。因此其餘的人,也許會翻譯爲 "There is a cat on the mat"。實際上,這兩個都是很好的翻譯。Bleu 得分作的就是,給定一個機器生成的翻譯,它可以自動地計算一個分數來衡量機器翻譯的好壞。直覺告訴咱們,只要這個機器生成的翻譯與任何一我的工翻譯的結果足夠接近,那麼它就會獲得一個高的 Bleu 分數。

咱們以一個極端的例子爲例。假設機器翻譯 (MT) 的輸出是 "the the the the the the the"。這顯然是一個十分糟糕的翻譯。衡量機器翻譯輸出質量的方法之一,是觀察輸出結果的每個詞看其是否出如今參考中,這杯稱做是機器翻譯的精確度。這種狀況下,機器翻譯輸出了七個單詞而且這七個詞中的每個都出如今了參考 1 或是參考 2。單詞 the 在兩個參考中都出現了,因此看上去每一個詞都是很合理的,即這個精確度就是 \(\frac{7}{7}\),看起來是一個極好的精確度。

因此這種方法並非頗有用,將其進行改良,咱們把每個單詞的計分上限定爲它在參考句子中出現的最屢次數。在參考 1 中,單詞 the 出現了兩次;參考 2 中,單詞 the 出現了一次。因此單詞 the 的得分上限爲 2。那麼這個改良後的精確度爲 \(\frac{2}{7}\)。分母爲 7 個詞中單詞 the 總共出現的次數,分子爲單詞 the 在參考中的出現的計數。

到目前爲止,咱們都只是關注單獨的單詞。若是咱們想考慮成對的單詞,定義一下二元詞組 (bigrams) 的 Bleu 得分。固然這僅僅只是最終的 Bleu 得分的一部分,可能會考慮單個單詞以及二元或多元詞組。在下面的例子中,咱們分別統計 MT 輸出的二元詞組在 MT 輸出和參考中的計數。所以 \(\frac{4}{6}=\frac{2}{3}\) 爲二元詞組的改良後的精確度。

如今咱們將其泛化爲 n 元詞組,其精確度定義爲
\[ P_n=\frac{\sum_{n-grams\in\hat{y}}Count_{clip}(n-gram)}{\sum_{n-grams\in\hat{y}}Count(n-gram)} \]
最終的 Bleu 得分被定義爲(以綜合 \(P_1,P_2,P_3,P_4\) 爲例)
\[ Combined Bleu score = exp(\frac{1}{4}\sum_{n=1}^4P_n) \]
實際上還會用到額外的一個叫作 \(BP\) 的懲罰因子來調整,其意思爲簡短懲罰 (brevity penalty)。那麼定義則爲
\[ Combined Bleu score = BP\cdot exp(\frac{1}{4}\sum_{n=1}^4P_n)\\ BP=\begin{cases} 1 & if\ MT\_output\_length > reference\_output\_length\\ exp(1-\frac{reference\_output\_length}{MT\_output\_length}) & otherwise \end{cases} \]

注意力模型 (Attention Model)

像下圖這樣一個很長的法語句子,咱們的神經網絡中,綠色部分的編碼器要作的就是讀整個句子,而後記憶整個句子,再在感知機中傳遞。而對於紫色部分的解碼器,它將生成英文翻譯。

可是人工翻譯並不會經過讀整個法語句子,再記憶裏面的東西,而後從零開始翻譯成英語句子。人工翻譯會一部分一部分地翻譯,由於記憶整個句子是很是困難的。對於機器翻譯來講也是如此,對於短句子效果可能很是好,有相對高的 Bleu 分數,可是對於長句子,它的表現就會變差。

注意力模型源於機器翻譯,但也推廣到了其餘應用領域。

仍然以法語句子 "Jane visite I'Afrique en Septerbre" 爲例。假定咱們使用一個雙向的 RNN,爲了計算每一個輸入單詞的特徵集。它可使用 GRU 或者 LSTM 做爲基本單元,實踐中, LSTM 使用得更爲常常一些。而後,使用另外一個 RNN 生成對應的英文翻譯,咱們使用記號 \(S\) 表示這個 RNN 的隱藏狀態而不用 \(A\)

當咱們嘗試生成英文翻譯的第一個詞時,咱們應該看對應法語句子的第一個單詞及它附近的詞。因此注意力模型就會計算注意力權重,咱們使用 \(\alpha^{<1,1>}\) 來表示當生成第一個詞時,注意力放在第一塊信息處的權重。對應的有 \(\alpha^{<1,2>},\alpha^{<1,3>}\)。把他們綜合起來做爲翻譯第一個詞的上下文語境,記爲 \(C\),這就是這個 RNN 的一個單元。其餘單詞以此類推,直到最終生成 <EOS>。

再次說明,注意力權重 \(\alpha^{<t,t>}\) 表示的是,生成第 t 個英文詞時,須要花多少注意力在第 t 個法語詞上面。

咱們仍然使用 \(t\) 來表示時間步,\(a^{<t>}\) 就是時間步 \(t\) 上的特徵向量。使用 \(t'\) 來索引法語句子裏面的詞。那麼 \(t=1\) 時的上下文語境,就是經過計算注意力權重(上圖編號 1)和其對應的特徵向量(上圖編號 2)的乘積和。即
\[ C^{<1>}=\sum_{t'}\alpha^{<1,t'>}a^{<t'>} \]
注意,在一個時間步中,全部的注意力權重均爲非負,且它們的和爲 1,即
\[ \sum_{t'}\alpha^{<1,t'>}=1 \]

\(\alpha^{<t,t'>}\) 是花費在 \(a^{<t'>}\) 上的注意力權重。它的公式如上圖所示。計算它以前,咱們須要先計算 \(e^{<t,t'>}\),關鍵要用 softmax 以確保這些權重加起來等於 1。

計算 \(e\) 值能夠訓練一個上圖所示的小型的神經網絡。咱們不知道具體的函數去計算它,可是可使用梯度降低算法計算一個正確的函數。

這個算法的一個缺點就是它要花費三次方的時間,也就是說這個算法的複雜度是 \(O(n^3)\)。可是在機器翻譯的應用上,輸入和輸出的句子通常不會太長,可能三次方的消耗也是能夠接受的。

語音識別 (Speech recognition)

語音識別問題指的是,輸出音頻片斷 \(x\) 自動地生成文本 \(y\)

咱們使用注意力模型來構建語音識別系統。就是在橫軸上,也就是輸入音頻的不一樣時間幀上,用注意力模型來輸出文本描述。

也可使用 CTC 損失函數來作語言識別,其中 CTC 指的是 Connectionist Temporal Classification。

其算法思想以下:

假設語言片斷內容爲 "the quick brown fox",這時咱們使用一個新的網絡,結構如上圖所示。輸入的 \(x\) 與輸出 \(y\) 的長度是同樣的,示例的只是一個簡單的單向 RNN 結構。在實踐中,它能夠是雙向的 LSTM 或 GRU,而且一般是很深的模型。注意,這裏時間步的數量很是大。在語音識別中,一般輸入的時間步數量要比輸出的時間步數量多出不少。這種狀況下,CTC 損失函數容許 RNN 生成相似這樣的輸出 "ttt",而後一個空白符,咱們如下劃線表示,而後 "h_eee___" 等。這樣的輸出(如上圖所示)對應的就是 "the q"。這樣,須要輸出的內容其實只有 19 個字符,可是神經網絡容許有不少這種重複的字符和不少插入在其中的空白符,使得它能強制輸出 1000 個字符。

觸發詞檢測 (Trigger Word Detection)

如今有不少智能系統有其對應的觸發詞模塊,以下圖所示。

對於觸發詞檢測,最好的算法是什麼,目前尚未一個普遍的定論。

咱們以一個算法爲例。如今有一個 RNN 結構,咱們須要把一個音頻片斷計算出它的聲譜圖特徵 (spectrogram features) 獲得特徵向量 \(x^{<1>},x^{<2>},\dots\)。而後,把它放到另外一個 RNN 中,再定義目標標籤 \(y\)。假如音頻片斷中的某一點爲剛剛說完一個觸發詞,那麼以前的目標標籤都設爲 0,這點以後對應觸發詞的音頻特徵設爲 1。這樣的標籤方案對於 RNN 來講是可行的,而且確實運行得不錯。不過該算法一個明顯的缺點就是它構建了一個很不平衡的訓練集,0 的數量比 1 多太多了。

這裏有一個解決方法,雖然聽起來有點簡單粗暴,但確實能使其變得更容易訓練。比起只在一個時間步上去輸出 1,其實你能夠在輸出變回 0 以前,屢次輸出 1,或說在固定的一段時間內輸出多個 1。這樣的話,就稍微提升了 1 與 0 的比例。

References

[1] Coursera深度學習教程中文筆記

相關文章
相關標籤/搜索