以下內容是個人參考網上的學習資料以及自己的理解進行總結的
1、循環神經網絡的介紹具體看
https://www.cnblogs.com/pinard/p/6509630.html
深度神經網絡無法利用數據中時間序列信息,循環神經網絡應勢而生。循環神經網絡的主要用途是處理和預測序列數據,它最擅長解決的問題是與時間序列相關的。它與CNN一樣參數是共享的。
循環神經網絡工作的關鍵點就是利用歷史的信息來幫助當前的決策,因此而帶來了更大的技術挑戰--長期依賴(此外RNN的序列過長時會出現梯度消失現象)LSTM(長短時記憶)的出現正是為了解決這一問題。LSTM是對RNN細胞進行了改造,加入了“遺忘門”它的作用是讓循環神經網絡“忘記”沒有用的信息,它會根據當前的輸入Xt和上一時刻的輸出Ht-1以及上一時刻的細胞狀態共同決定應該從上一時刻的細胞狀態記憶中遺忘什么。在循環神經網絡‘忘記’了部分之前的狀態后,它還需要從當前的輸入補充最新的記憶,這個過程是由輸入門完成的。“輸入門”會根據當前的輸入Xt和上一時刻的輸出Ht-1以及當前產生的新的細胞狀態決定哪些部分進入當前時刻的狀態Ct。“輸出門”它會根據更新后的狀態Ct,上一時刻的輸出Ht-1和當前的輸入Xt來決定該時刻的輸出Ht。
注意:LSTM相比於RNN具備長期的記憶功能是因為除了隱狀態Ht,增加了一個新的細胞狀態,通過對賦予LSTM長期記憶功能的細胞狀態不斷進行更新,一方面及時的遺忘無用的信息,另一方面及時的補充新的信息。
當前時刻的隱藏狀態輸出由當前輸入數據,之前的隱藏狀態和更新后的細胞狀態一起共同決定。
RNN以及其變種的一系列網絡最大的問題是,由於其循環的結構導致其無法並行計算,所以訓練RNN需要花費大量的時間。同時LSTM的記憶能力也是有限的,有論文證明當序列長度大於200時仍然會出現遺忘現象。
2、LSTM以及其變種(GRU等)圖解析
其中牽扯到的計算如下:
(忘記門部分)
(輸入門部分)
(當前時刻新細胞狀態的產生)
(細胞狀態的更新,忘記門結合上一時刻的細胞狀態決定需要遺忘的信息,輸入門結合當前時刻產生的新的細胞狀態決定應該添加什么信息,最終共同對包含長期記憶的細胞狀態進行更新)
(輸出門部分)
(輸出門結合包含長期記憶的細胞狀態共同決定當前時刻的輸出)
注意以上的*是元素級相乘,不是矩陣相乘。
根據以上的公式能夠發現,細胞的狀態無法對門控結構造成影響,可以加入窺視孔連接,使得細胞狀態得以對門控結構造成影響。細胞單元結構圖的改變:
相應計算公式的改變:
另一個變型GRU,它把LSTM中的遺忘門和輸入門合並為了一個單一的更新門,同時還混合了細胞狀態及隱藏狀態以及其它一些改動。GRU的門控結構減少到了兩個,分別為更新門和重置門,更新門用於控制前一時刻的狀態信息被帶入到當前狀態中的程度,更新門的值越大說明前一時刻的狀態信息帶入越多。重置門用於控制忽略前一時刻的狀態信息的程度,重置門的值越小說明忽略得越多。
細胞結構圖以及計算公式如下:
3.LSTM為什么選用sigmoid和tanh兩個激活函數是否可以改變
從LSTM的前向傳播計算公式中能夠得出,三個sigmoid激活函數用於門處,通過sigmoid轉換為0-1之間的值能夠得到對遺忘輸入輸出的更直觀的表示(因為后來又和細胞狀態相乘是否起到一個概率的作用),為什么不用其他sig函數因為sigmoid函數更容易達到飽和,其他的難以飽和,LSTM應該需要飽和的門來記住或忘記信息,不飽和的門會使得過去和現在的記憶一直在疊加,造成記憶錯亂。sigmoid激活函數最好不要改變。
兩個tanh用於細胞狀態處,有論文指出這個可以替換。
4、對於cell和num_units(hidden_size隱藏層神經元的個數)的說明(最開始學習時在這里比較迷惑)
就拿最基礎的RNN來說吧,cell其實就是一個RNN的網絡,
cell表示多個時刻(序列)組成的RNN網絡,從一個序列時刻到另一個序列時刻,cell的內部狀態(神經元)就會更新。也就是說,從空間上講,cell是同一個,但是時間上,cell_1表示輸入x(1),隱狀態h_1,cell_2表示輸入x(2),隱狀態h_2。
num_units(hidden_size)是RNN及其變種隱藏層節點的個數,也是神經網絡用於特征提取的核心部分,其它的一些網絡變換是為了使得隱藏層能夠更好的提取特征。
num_units越大則每個LSTM的Cell能記憶的東西就越多。
5、LSTM的隱藏層到底在哪,以及其內部參數個數的計算
以下內容參考:
https://blog.csdn.net/notheadache/article/details/81164264
https://www.zhihu.com/question/64470274
LSTM 的 cell 里面的 num_units 該怎么理解,其實也是很簡單,看看下圖:
可以看到cell在t時刻 里面有四個黃色小框,你如果理解了那個代表的含義一切就明白了,每一個小黃框代表一個前饋網絡層,對,就是經典的神經網絡的結構,num_units就是這個層的隱藏神經元個數,就這么簡單。其中1、2、4的激活函數是 sigmoid,第三個的激活函數是 tanh。
1)cell 的權重是共享的,這是什么意思呢?這是指這張圖片上有三個綠色的大框,代表三個 cell 對吧,但是實際上,它只是代表了一個 cell 在不同時序時候的狀態,所有的數據只會通過一個 cell,然后不斷更新它的權重。
2)那么一層的 LSTM 的參數有多少個?我們知道參數的數量是由 cell 的數量決定的,這里只有一個 cell,所以參數的數量就是這個 cell 里面用到的參數個數。假設 num_units 是128,輸入是28位的,那么結合2中提及的計算公式,可以得到,四個小黃框的參數一共有 128*(128+28)*4,可以看看 TensorFlow 的最簡單的 LSTM 的案例,中間層的參數就是這樣,不過還要加上輸出的時候的激活函數的參數,假設是10個類的話,就是128*10的 W 參數和10個bias 參數
3)cell 最上面的一條線的狀態即 s(t) 代表了長時記憶,而下面的 h(t)則代表了工作記憶或短時記憶。
6、LSTM相比於RNN能夠緩解梯度消失的原因
具體解析可參考:https://www.zhihu.com/question/34878706/answer/665429718
https://www.zhihu.com/question/44895610/answer/616818627
https://zhuanlan.zhihu.com/p/85776566
正向RNN中對於每一時刻的隱狀態由當前時刻的輸入和上一時刻的隱狀態共同決定:
在對式中的權值W進行更新時需要對W求導,而由於RNN網絡其特有的結構特性,使得在求導時會出現連乘操作:
而對於LSTM,相比於RNN加入了特有的門控結構,同時相比於RNN出了隱藏狀態h還多了一個細胞狀態C,沒時刻都會對細胞狀態進行更新,同時細胞狀態的引入也是LSTM具備長期記憶能力的關鍵。
7、BasicLSTMCell與LSTMCell的區別
BasicLSTMCell是LSTM實現的一個基礎版本,LSTMCell是LSTM實現的一個高級版本。主要說LSTMCell中的use_peepholes參數,默認的為False表示不使用窺視孔連接。即為LSTMCell能夠添加上面在第2條中所描述的窺視孔規則。
8、static_rnn和dynamic_rnn的區別:
靜態RNN不能處理變長數據,動態RNN能夠處理變長數據,這里的變長是說每個batch的最大長度能夠不同,可以根據不同batch其batch中最大長度的文本進行填充,靜態RNN是事先規定所有batch的句子最大長度都相同。注意:不管靜態還是動態的RNN,其每個batch的文本長度都要是相同的。
單向的RNN:
注意:輸出方面靜態和動態的都是兩個
輸入數據方面:static_rnn接收的是一個個List,對於三維的輸入x經過inputs=tf.unstack(x,axis=1)轉換即可。而dynamic_rnn是Array
輸出方面:Static_rnn輸出的是一個大的list,順序即為時間序列順序,里面是一個個array,一維是批次大小,二維是RNN隱藏層節點的個數。dynamic_rnn的輸出是一個三維的array,注意需要維度轉換,轉換為時間批次優先的,outputs=tf.transpose(outputs,[1,0,2])
作為下一全連接層輸入,只需取最后一個序列的結果,因為前面的信息都被學習到了,最后一個序列的輸出就是語義的表征,即為outputs[-1]即可。
雙向的RNN:
注意:輸出方面靜態的是三個,動態的是兩個
靜態的也是輸出一個list,順序即為時間序列順序,里面是一個個array,一維是批次大小,二維是RNN隱藏層節點的個數*2(這里是單向的二倍)。
具體代碼實現為:
inputs=tf.unstack(x,axis=1)
outputs,_,_=tf.nn.static_bidirectional_rnn(lstm_fw_cell,lstm_bw_cell,inputs,dtype=tf.float32)
動態的也是一個Tensor,需要先對輸出進行合並然后再轉換為時間批次優先。
具體代碼實現為:
outputs,output_states=tf.nn.bidirectional_dynamic_rnn(lstm_fw_cell,lstm_bw_cell,x,dtype=tf.float32)
outputs=tf.concat(outputs,2)#這里2可換為-1
outputs=tf.transpose(outputs,[1,0,2])
dynamic_rnn中重要參數與返回值說明
它比靜態RNN更加好用,注意的它的參數initial_state用於初始化cell的狀態,這個參數不用設置,但是必須設置另外一個參數dtype它用於設置期望的輸出和初始化state的類型,不設置initial_state必須要設置dtype,系統會自動按規定類型進行初始化。還有一個就是sequence_length用於指定輸入數據的有效長度,因為dynamic_rnn可以處理變長數據。對於其返回值,在說返回值之前還要說到一個參數time_major:若其值設置為False則表示非時間批次優先,input的shape為[batch_size,max_time,...],如果是True則shape為[max_time,batch_size,...]
一般選用默認的false因為符合輸入數據規范,同時dynamic_rnn的返回值有兩個outputs和state,那么注意這里一定要對outputs輸出進行維度轉換,轉換為時間批次優先,同時對於下面的全連接層只取最后一維。
outputs=tf.transpose(outputs,[1,0,2])
pred=tf.contrib.layers.fully_connected(outputs[-1],n_classes,activation_fn=None)
9、動態RNN的第二個輸出state的分析
具體參考:
https://blog.csdn.net/xiaokang06/article/details/80235950
對於dynamic_rnn的輸出state是一個元組,元組的長度是LSTM網絡的層數,state中的每一個元素為一個LSTMStateTuple,它的長度為2,第一個元素存的為每層LSTM最后一個時刻的c(細胞狀態),第二個元素存的為每層LSTM最后一個時刻的h(即為隱層的輸出),其中c和h的維度都是(batch_size,hidden_size)。其中LSTM最后一層的最后一個時間批次的輸出為output[:-1:],同時為state[-1].h。
注意:LSTM網絡結構從第一個輸出output中能夠得到最后一層各個時刻的輸出。從第二個輸出state中能夠得到各層最后一個時刻的細胞狀態c以及各層最后一個時刻隱層的輸出h。
10.如何用LSTM處理過長的數據
盡管LSTM相比於RNN能夠一定程度上緩解梯度消失問題,從而具備更好的記憶功能,但是當序列長度過長時仍然會出現梯度消失問題,有論文指出序列長度大於200LSTM也會容易出現梯度消失。
那么該如何用LSTM處理過長的數據,參考:https://blog.csdn.net/together_cz/article/details/73824127