1 循環神經網絡
循環神經網絡(Recurrent Neural Network,RNN)是一類具有短期記憶能力的神經網絡。在循環神經網絡中,神經元不但可以接受其它神經元的信息,也可以接受自身的信息,形成具有環路的網絡結構。和前饋神經網絡相比,循環神經網絡更加符合生物神經網絡的結構。循環神經網絡已經被廣泛應用在語音識別、語言模型以及自然語言生成等任務上。循環神經網絡的參數學習可以通過隨時間反向傳播算法(BPTT)[Werbos, 1990]來學習。隨時間反向傳播算法即按照時間的逆 序將錯誤信息一步步地往前傳遞。當輸入序列比較長時,會存在梯度爆炸和消失問題[Bengio et al., 1994, Hochreiter and Schmidhuber, 1997, Hochreiter et al., 2001],也稱爲長程依賴問題。(摘抄:《神經網絡與深度學習》)
2 基本循環神經網絡結構圖
如果把上面有W的那個帶箭頭的圈去掉,它就變成了最普通的全連接神經網絡。
- x是一個向量,它表示輸入層的值;
- s是一個向量,它表示隱藏層的值;
- U是輸入層到隱藏層的權重矩陣;
- o也是一個向量,它表示輸出層的值;
- V是隱藏層到輸出層的權重矩陣。那
- 權重矩陣 W就是隱藏層上一次的值作爲這一次的輸入的權重。因爲循環神經網絡的隱藏層的值s不僅僅取決於當前這次的輸入x,還取決於上一次隱藏層的值s。
3 BPTT
隨時間反向傳播(Backpropagation Through Time,BPTT)算法的主要 思想是通過類似前饋神經網絡的錯誤反向傳播算法 [Werbos, 1990] 來進行計算 梯度。 BPTT 算法將循環神經網絡看作是一個展開的多層前饋網絡,其中“每一 層”對應循環網絡中的“每個時刻”。這樣,循環神經網絡就可以按按照前 饋網絡中的反向傳播算法進行計算參數梯度。在“展開”的前饋網絡中,所有層 的參數是共享的,因此參數的真實梯度是所有“展開層”的參數梯度之和。
BPTT算法是針對循環層的訓練算法,它的基本原理和BP算法是一樣的,也包含同樣的三個步驟:
- 前向計算每個神經元的輸出值;
- 反向計算每個神經元的誤差項值,它是誤差函數E對神經元j的加權輸入的偏導數;
- 計算每個權重的梯度。
最後再用隨機梯度下降算法更新權重。
4 RNN問題
常見問題:梯度爆炸、梯度消失
梯度爆炸解決方法:
- 權重衰減:通過給參數增加 ℓ1 或 ℓ2 範數的正則化項來限制參數的取值範 圍,從而使得γ ≤ 1
- 梯度截斷:當梯度的模大於一定 閾值時,就將它截斷成爲一個較小的數
梯度消失解決方法:
- 合理的初始化權重值。初始化權重,使每個神經元儘可能不要取極大或極小值,以躲開梯度消失的區域。
- 使用relu代替sigmoid和tanh作爲激活函數。
- 使用其他結構的RNNs,比如長短時記憶網絡(LTSM)和Gated Recurrent Unit(GRU),這是最流行的做法。
5 雙向RNN
對於語言模型來說,很多時候光看前面的詞是不夠的,比如下面這句話:
我的手機壞了,我打算____一部新手機。
可以想象,如果我們只看橫線前面的詞,手機壞了,那麼我是打算修一修?換一部新的?還是大哭一場?這些都是無法確定的。但如果我們也看到了橫線後面的詞是『一部新手機』,那麼,橫線上的詞填『買』的概率就大得多了。
在上面的句子中,可以看到,一個時刻的輸出不但和過去時刻的信息有關,也和後續時刻的信息有關。比如給定一個句子,其中一個詞的詞性由它的上下文決定,即包含 左右兩邊的信息。因此,在這些任務中,我們可以增加一個按照時間的逆序來傳 遞信息的網絡層,來增強網絡的能力。 雙向循環神經網絡(Bidirectional Recurrent Neural Network,Bi-RNN)由 兩層循環神經網絡組成,它們的輸入相同,只是信息傳遞的方向不同。假設第1層按時間順序,第2層按時間逆序,在時刻t時的隱狀態定義爲 和
6 遞歸神經網絡
有時候把句子看做是詞的序列是不夠的,比如下面這句話『兩個外語學院的學生』:
上圖顯示了這句話的兩個不同的語法解析樹。可以看出來這句話有歧義,不同的語法解析樹則對應了不同的意思。一個是『兩個外語學院的/學生』,也就是學生可能有許多,但他們來自於兩所外語學校;另一個是『兩個/外語學院的學生』,也就是隻有兩個學生,他們是外語學院的。爲了能夠讓模型區分出兩個不同的意思,我們的模型必須能夠按照樹結構去處理信息,而不是序列,這就是遞歸神經網絡的作用。當面對按照樹/圖結構處理信息更有效的任務時,遞歸神經網絡通常都會獲得不錯的結果。
遞歸神經網絡的一般結構爲樹狀的層次結構,如圖(a)所示,當遞歸神經網絡的結構退化爲線性序列結構(圖b)時,遞歸神經網絡就 等價於簡單循環網絡。分別對應上面的例子的兩個結構。
7 LSTM
長短期記憶(Long Short-Term Memory,LSTM)網絡 [Gers et al., 2000, Hochreiter and Schmidhuber, 1997]是循環神經網絡的一個變體。
LSTM網絡主要改進在以下兩個方面:
- 新的內部狀態:LSTM 網絡引入一個新的內部狀態(internal state)
專門進行 線性的循環信息傳遞,同時(非線性)輸出信息給隱藏層的外部狀態
。
- 門控機制:LSTM網絡引入門控機制(Gating Mechanism)來控制信息傳遞的路徑。
下面是它的詳細說明:
長短時記憶網絡的思路比較簡單。原始RNN的隱藏層只有一個狀態,即h,它對於短期的輸入非常敏感。那麼,假如我們再增加一個狀態,即c,讓它來保存長期的狀態,那麼問題不就解決了麼?如下圖所示:
新增加的狀態c,稱爲單元狀態(cell state)。我們把上圖按照時間維度展開:
上圖僅僅是一個示意圖,我們可以看出,在t時刻,LSTM的輸入有三個:當前時刻網絡的輸入值、上一時刻LSTM的輸出值
、以及上一時刻的單元狀態
;LSTM的輸出有兩個:當前時刻LSTM輸出值
、和當前時刻的單元狀態
。注意
都是向量。
LSTM的關鍵,就是怎樣控制長期狀態c。在這裏,LSTM的思路是使用三個控制開關。
- 第一個開關,負責控制繼續保存長期狀態c;
- 第二個開關,負責控制把即時狀態輸入到長期狀態c;
- 第三個開關,負責控制是否把長期狀態c作爲當前的LSTM的輸出。
分別對應以下三個門:
- 輸入門
:控制當前時刻的候選狀態
有多少信息需要保存;
- 遺忘門
:控制上一個時刻的內部狀態
需要遺忘多少信息;
- 輸出門
:控制當前時刻的內部狀態ct有多少信息需要輸出給外部狀態
。
三個開關的作用如下圖所示:
8 門控循環單元網絡
門控循環單元(Gated Recurrent Unit,GRU)網絡 [Cho et al., 2014, Chung et al., 2014]是一種比LSTM網絡更加簡單的循環神經網絡。
GRU對LSTM做了兩個大改動:
- 將輸入門、遺忘門、輸出門變爲兩個門:更新門(Update Gate)和重置門(Reset Gate)。
- 將單元狀態與輸出合併爲一個狀態。
假設訓練集中所有文本/序列的長度統一爲n,我們需要對文本進行分詞,並使用詞嵌入得到每個詞固定維度的向量表示。對於每一個輸入文本/序列,我們可以在RNN的每一個時間步長上輸入文本中一個單詞的向量表示,計算當前時間步長上的隱藏狀態,然後用於當前時間步驟的輸出以及傳遞給下一個時間步長並和下一個單詞的詞向量一起作爲RNN單元輸入,然後再計算下一個時間步長上RNN的隱藏狀態,以此重複...直到處理完輸入文本中的每一個單詞,由於輸入文本的長度爲n,所以要經歷n個時間步長。
基於RNN的文本分類模型非常靈活,有多種多樣的結構。下面是兩種典型的結構。
- structure v1: embedding--->BiLSTM--->concat final dropout/average all output--->softmax layer
一般取前向/反向LSTM在最後一個時間步長上隱藏狀態,然後進行拼接,在經過一個softmax層(輸出層使用softmax激活函數)進行一個多分類;或者取前向/反向LSTM在每一個時間步長上的隱藏狀態,對每一個時間步長上的兩個隱藏狀態進行拼接,然後對所有時間步長上拼接後的隱藏狀態取均值,再經過一個softmax層(輸出層使用softmax激活函數)進行一個多分類(2分類的話使用sigmoid激活函數)。
- structure v2: embedding--->BiLSTM--->(dropout)--->concat dropout--->UniLSTM--->(dropout)-->softmax layer
與之前結構不同的是,在雙向LSTM(上圖不太準確,底層應該是一個雙向LSTM)的基礎上又堆疊了一個單向的LSTM。把雙向LSTM在每一個時間步長上的兩個隱藏狀態進行拼接,作爲上層單向LSTM每一個時間步長上的一個輸入,最後取上層單向LSTM最後一個時間步長上的隱藏狀態,再經過一個softmax層(輸出層使用softamx激活函數,2分類的話則使用sigmoid)進行一個多分類。
構建模型代碼:
import tensorflow as tf
from tensorflow import keras
import numpy as np
imdb = keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
print(sum(list(map(lambda x:len(x),train_data)))/len(train_data))
print(sum(list(map(lambda x:len(x),test_data)))/len(test_data))
max_len = 240
train_data = keras.preprocessing.sequence.pad_sequences(train_data,
value=word_index["<PAD>"],
padding='post',
maxlen=max_len)
test_data = keras.preprocessing.sequence.pad_sequences(test_data,
value=word_index["<PAD>"],
padding='post',
maxlen=max_len)
vocab_size = 10000
model = keras.Sequential()
model.add(keras.layers.Embedding(vocab_size, 128))
model.add(keras.layers.LSTM(128,dropout=0.2))
model.add(keras.layers.Dense(16, activation=tf.nn.relu))
model.add(keras.layers.Dense(1, activation=tf.nn.sigmoid))
model.add(keras.layers.Activation('sigmoid'))
model.summary()
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['acc'])
x_val = train_data[:10000]
partial_x_train = train_data[10000:]
y_val = train_labels[:10000]
partial_y_train = train_labels[10000:]
history = model.fit(partial_x_train,
partial_y_train,
epochs=40,
batch_size=512,
validation_data=(x_val, y_val),
verbose=1)
results = model.evaluate(test_data, test_labels)
print(results)
10 RCNN原理
TextRNN可以獲取上下文信息,但是單向RNN是有偏的模型(biased model),後面的詞佔得重要性更大。TextCNN是無偏的模型(unbiased model),能夠通過最大池化獲得最重要的特徵,但是特徵提取器大小固定,設定小了容易造成信息丟失,設定大了造成巨大的參數空間。
爲了解決TextRNN和TextCNN的模型缺陷,循環卷積神經網絡(Recurrent Convolutional Neural Networks,RCNN)提出了:
- 雙向循環結構:比傳統的基於窗口的神經網絡噪聲要小,能夠最大化地提取上下文信息;
- max-pooling池化層:自動決策哪個特徵更有重要作用。
推薦文章:
Recurrent Convolutional Neural Networks for Text Classification
一文讀懂文本分類基線深度模型從fastText、TextCNN、TextRNN、TextRCNN、HAN到Transformer