網(wǎng)站建設(shè)建議推廣價(jià)格一般多少
???
1 RNN的缺陷——長期依賴的問題 (The Problem of Long-Term Dependencies)
前面一節(jié)我們學(xué)習(xí)了RNN神經(jīng)網(wǎng)絡(luò),它可以用來處理序列型的數(shù)據(jù),比如一段文字,視頻等等。RNN網(wǎng)絡(luò)的基本單元如下圖所示,可以將前面的狀態(tài)作為當(dāng)前狀態(tài)的輸入。
但也有一些情況,我們需要更“長期”的上下文信息。比如預(yù)測最后一個(gè)單詞“我在中國長大……我說一口流利的**?!薄岸唐凇钡男畔@示,下一個(gè)單詞很可能是一種語言的名字,但如果我們想縮小范圍,我們需要更長期語境——“我在中國長大”,但這個(gè)相關(guān)信息與需要它的點(diǎn)之間的距離完全有可能變得非常大。
不幸的是,隨著這種距離的擴(kuò)大,RNN無法學(xué)會(huì)連接這些信息。
從理論上講,RNN絕對有能力處理這種“長期依賴性”。人們可以為他們精心選擇參數(shù),以解決這種形式的問題。遺憾的是,在實(shí)踐中,RNN似乎無法學(xué)習(xí)它們。
幸運(yùn)的是,GRU也沒有這個(gè)問題!
2、GRU
什么是GRU
GRU(Gate Recurrent Unit)是循環(huán)神經(jīng)網(wǎng)絡(luò)(Recurrent Neural Network, RNN)的一種。和LSTM(Long-Short Term Memory)一樣,也是為了解決長期記憶和反向傳播中的梯度等問題而提出來的。
GRU和LSTM在很多情況下實(shí)際表現(xiàn)上相差無幾,那么為什么我們要使用新人GRU(2014年提出)而不是相對經(jīng)受了更多考驗(yàn)的LSTM(1997提出)呢。
用論文中的話說,相比LSTM,使用GRU能夠達(dá)到相當(dāng)?shù)男Ч?#xff0c;并且相比之下更容易進(jìn)行訓(xùn)練,能夠很大程度上提高訓(xùn)練效率,因此很多時(shí)候會(huì)更傾向于使用GRU。
2.1總體結(jié)構(gòu)框架
前面我們講到,神經(jīng)網(wǎng)絡(luò)的各種結(jié)構(gòu)都是為了挖掘變換數(shù)據(jù)特征的,所以下面我們也將結(jié)合數(shù)據(jù)特征的維度來對比介紹一下RNN&&LSTM的網(wǎng)絡(luò)結(jié)構(gòu)。
多層感知機(jī)(線性連接層)結(jié)構(gòu)
從特征角度考慮:
輸入特征:是n*1的單維向量(這也是為什么卷積神經(jīng)網(wǎng)絡(luò)在linear層前要把所有特征層展平),
隱藏層:然后根據(jù)隱藏層神經(jīng)元的數(shù)量m將前層輸入的特征用m*1的單維向量進(jìn)行表示(對特征進(jìn)行了提取變換,隱藏層的數(shù)據(jù)特征),單個(gè)隱藏層的神經(jīng)元數(shù)量就代表網(wǎng)絡(luò)參數(shù),可以設(shè)置多個(gè)隱藏層;
輸出特征:最終根據(jù)輸出層的神經(jīng)元數(shù)量y輸出y*1的單維向量。
卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)
?從特征角度考慮:
輸入特征:是(batch)*channel*width*height的張量,
卷積層(等):然后根據(jù)輸入通道channel的數(shù)量c_in和輸出通道channel的數(shù)量c_out會(huì)有c_out*c_in*k*k個(gè)卷積核將前層輸入的特征進(jìn)行卷積(對特征進(jìn)行了提取變換,k為卷積核尺寸),卷積核的大小和數(shù)量c_out*c_in*k*k就代表網(wǎng)絡(luò)參數(shù),可以設(shè)置多個(gè)卷積層;每一個(gè)channel都代表提取某方面的一種特征,該特征用width*height的二維張量表示,不同特征層之間是相互獨(dú)立的(可以進(jìn)行融合)。
輸出特征:根據(jù)場景的需要設(shè)置后面的輸出,可以是多分類的單維向量等等。
循環(huán)神經(jīng)網(wǎng)絡(luò)RNN系列結(jié)構(gòu)
從特征角度考慮:
輸入特征:是(batch)*T_seq*feature_size的張量(T_seq代表序列長度,注意不是batch_size).
我們來詳細(xì)對比一下卷積神經(jīng)網(wǎng)絡(luò)的輸入特征,
(batch)*T_seq*feature_size
(batch)*channel*width*height,
逐個(gè)進(jìn)行分析,RNN系列的基礎(chǔ)輸入特征表示是feature_size*1的單維向量,比如一個(gè)單詞的詞向量,比如一個(gè)股票價(jià)格的影響因素向量,而CNN系列的基礎(chǔ)輸入特征是width*height的二維張量;
再來看一下序列T_seq和通道channel,RNN系列的序列T_seq是指一個(gè)連續(xù)的輸入,比如一句話,一周的股票信息,而且這個(gè)序列是有時(shí)間先后順序且互相關(guān)聯(lián)的,而CNN系列的通道channel則是指不同角度的特征,比如彩色圖像的RGB三色通道,過程中每個(gè)通道代表提取了每個(gè)方面的特征,不同通道之間是沒有強(qiáng)相關(guān)性的,不過也可以進(jìn)行融合。
最后就是batch,兩者都有,在RNN系列,batch就是有多個(gè)句子,在CNN系列,就是有多張圖片(每個(gè)圖片可以有多個(gè)通道)
隱藏層:明確了輸入特征之后,我們再來看看隱藏層代表著什么。隱藏層有T_seq個(gè)隱狀態(tài)H_t(和輸入序列長度相同),每個(gè)隱狀態(tài)H_t類似于一個(gè)channel,對應(yīng)著T_seq中的t時(shí)刻的輸入特征;而每個(gè)隱狀態(tài)H_t是用hidden_size*1的單維向量表示的,所以一個(gè)隱含層是T_seq*hidden_size的張量;對應(yīng)時(shí)刻t的輸入特征由feature_size*1變?yōu)閔idden_size*1的向量。如圖中所示,同一個(gè)隱含層不同時(shí)刻的參數(shù)W_ih和W_hh是共享的;隱藏層可以有num_layers個(gè)(圖中只有1個(gè))
以t時(shí)刻具體闡述一下:
X_t是t時(shí)刻的輸入,是一個(gè)feature_size*1的向量
W_ih是輸入層到隱藏層的權(quán)重矩陣
H_t是t時(shí)刻的隱藏層的值,是一個(gè)hidden_size*1的向量
W_hh是上一時(shí)刻的隱藏層的值傳入到下一時(shí)刻的隱藏層時(shí)的權(quán)重矩陣
Ot是t時(shí)刻RNN網(wǎng)絡(luò)的輸出
從上右圖中可以看出這個(gè)RNN網(wǎng)絡(luò)在t時(shí)刻接受了輸入Xt之后,隱藏層的值是St,輸出的值是Ot。但是從結(jié)構(gòu)圖中我們可以發(fā)現(xiàn)St并不單單只是由Xt決定,還與t-1時(shí)刻的隱藏層的值St-1有關(guān)。
2.2 GRU的輸入輸出結(jié)構(gòu)
GRU的輸入輸出結(jié)構(gòu)與普通的RNN是一樣的。有一個(gè)當(dāng)前的輸入xt,和上一個(gè)節(jié)點(diǎn)傳遞下來的隱狀態(tài)(hidden state)ht-1 ,這個(gè)隱狀態(tài)包含了之前節(jié)點(diǎn)的相關(guān)信息。結(jié)合xt和 ht-1,GRU會(huì)得到當(dāng)前隱藏節(jié)點(diǎn)的輸出yt 和傳遞給下一個(gè)節(jié)點(diǎn)的隱狀態(tài) ht。
圖 GRU的輸入輸出結(jié)構(gòu)
那么,GRU到底有什么特別之處呢?下面來對它的內(nèi)部結(jié)構(gòu)進(jìn)行分析!
2.3 GRU的內(nèi)部結(jié)構(gòu)
不同于LSTM有3個(gè)門控,GRU僅有2個(gè)門控,
第一個(gè)是“重置門”(reset gate),其根據(jù)當(dāng)前時(shí)刻的輸入xt和上一時(shí)刻的隱狀態(tài)ht-1變換后經(jīng)sigmoid函數(shù)輸出介于0和1之間的數(shù)字,用于將上一時(shí)刻隱狀態(tài)ht-1重置為ht-1’,即ht-1’=ht-1*r。
再將ht-1’與輸入xt進(jìn)行拼接,再通過一個(gè)tanh激活函數(shù)來將數(shù)據(jù)放縮到-1~1的范圍內(nèi)。即得到如下圖2-3所示的h’。
第一個(gè)是“更新門”(update gate),其根據(jù)當(dāng)前時(shí)刻的輸入xt和上一時(shí)刻的隱狀態(tài)ht-1變換后經(jīng)sigmoid函數(shù)輸出介于0和1之間的數(shù)字,
最終的隱狀態(tài)ht的更新表達(dá)式即為:
再次強(qiáng)調(diào)一下,門控信號(hào)(這里的z)的范圍為0~1。門控信號(hào)越接近1,代表”記憶“下來的數(shù)據(jù)越多;而越接近0則代表”遺忘“的越多。
2.4 小結(jié)
GRU很聰明的一點(diǎn)就在于,使用了同一個(gè)門控z就同時(shí)可以進(jìn)行遺忘和選擇記憶(LSTM則要使用多個(gè)門控)。與LSTM相比,GRU內(nèi)部少了一個(gè)”門控“,參數(shù)比LSTM少,但是卻也能夠達(dá)到與LSTM相當(dāng)?shù)墓δ???紤]到硬件的計(jì)算能力和時(shí)間成本,因而很多時(shí)候我們也就會(huì)選擇更加”實(shí)用“的GRU。
3代碼
import torch
import torch.nn as nndef my_gru(input,initial_states,w_ih,w_hh,b_ih,b_hh):h_prev=initial_statesbatch_size,T_seq,feature_size=input.shapehidden_size=w_ih.shape[0]//3batch_w_ih=w_ih.unsqueeze(0).tile(batch_size,1,1)batch_w_hh=w_hh.unsqueeze(0).tile(batch_size,1,1)output=torch.zeros(batch_size,T_seq,hidden_size)for t in range(T_seq):x=input[:,t,:]w_times_x=torch.bmm(batch_w_ih,x.unsqueeze(-1))w_times_x=w_times_x.squeeze(-1)# print(batch_w_hh.shape,h_prev.shape)# 計(jì)算兩個(gè)tensor的矩陣乘法,torch.bmm(a,b),tensor a 的size為(b,h,w),tensor b的size為(b,w,m)# 也就是說兩個(gè)tensor的第一維是相等的,然后第一個(gè)數(shù)組的第三維和第二個(gè)數(shù)組的第二維度要求一樣,# 對于剩下的則不做要求,輸出維度 (b,h,m)# batch_w_hh=batch_size*(3*hidden_size)*hidden_size# h_prev=batch_size*hidden_size*1# w_times_x=batch_size*hidden_size*1##squeeze,在給定維度(維度值必須為1)上壓縮維度,負(fù)數(shù)代表從后開始數(shù)w_times_h_prev=torch.bmm(batch_w_hh,h_prev.unsqueeze(-1))w_times_h_prev=w_times_h_prev.squeeze(-1)r_t=torch.sigmoid(w_times_x[:,:hidden_size]+w_times_h_prev[:,:hidden_size]+b_ih[:hidden_size]+b_hh[:hidden_size])z_t=torch.sigmoid(w_times_x[:,hidden_size:2*hidden_size]+w_times_h_prev[:,hidden_size:2*hidden_size]+b_ih[hidden_size:2*hidden_size]+b_hh[hidden_size:2*hidden_size])n_t=torch.tanh(w_times_x[:,2*hidden_size:3*hidden_size]+w_times_h_prev[:,2*hidden_size:3*hidden_size]+b_ih[2*hidden_size:3*hidden_size]+b_hh[2*hidden_size:3*hidden_size])h_prev=(1-z_t)*n_t+z_t*h_prevoutput[:,t,:]=h_prevreturn output,h_previf __name__=="__main__":fc=nn.Linear(12,6)batch_size=2T_seq=5feature_size=4hidden_size=3# output_feature_size=3input=torch.randn(batch_size,T_seq,feature_size)h_prev=torch.randn(batch_size,hidden_size)gru_layer=nn.GRU(feature_size,hidden_size,batch_first=True)output,h_final=gru_layer(input,h_prev.unsqueeze(0))# for k,v in gru_layer.named_parameters():# print(k,v.shape)# print(output,h_final)my_output, my_h_final=my_gru(input,h_prev,gru_layer.weight_ih_l0,gru_layer.weight_hh_l0,gru_layer.bias_ih_l0,gru_layer.bias_hh_l0)# print(my_output, my_h_final)# print(torch.allclose(output,my_output))
參考資料
https://zhuanlan.zhihu.com/p/32481747
https://speech.ee.ntu.edu.tw/~tlkagk/courses/MLDS_2018/Lecture/Seq%20(v2).pdf
https://www.bilibili.com/video/BV1jm4y1Q7uh/?spm_id_from=333.788&vd_source=cf7630d31a6ad93edecfb6c5d361c659