前面一節(jié)我們講了cnn以及如何使用pytorch實現(xiàn)簡單的多層卷積神經(jīng)網(wǎng)絡眼虱,下面我們將進入rnn,對于rnn我也涉及不多席纽,歡迎各位高手提出寶貴的意見捏悬。
關于rnn將分成三個部分,第一個部分先介紹rnn的基本結構以及在pytorch里面api的各個參數(shù)所表示的含義润梯,下一個部分將介紹rnn如何在MNIST數(shù)據(jù)集上做分類过牙,最后一個部分涉及一點點自然語言處理的東西甥厦。
RNN
首先介紹一下什么是rnn,rnn特別擅長處理序列類型的數(shù)據(jù)寇钉,因為他是一個循環(huán)的結構
一個序列的數(shù)據(jù)依次進入網(wǎng)絡A刀疙,網(wǎng)絡A循環(huán)的往后傳遞。
這就是RNN的基本結構類型摧莽。而最早的RNN模型庙洼,序列依次進入網(wǎng)絡中,之前進入序列的數(shù)據(jù)會保存信息而對后面的數(shù)據(jù)產(chǎn)生影響镊辕,所以RNN有著記憶的特性油够,而同時越前面的數(shù)據(jù)進入序列的時間越早,所以對后面的數(shù)據(jù)的影響也就越弱征懈,簡而言之就是一個數(shù)據(jù)會更大程度受到其臨近數(shù)據(jù)的影響石咬。但是我們很有可能需要更長時間之前的信息,而這個能力傳統(tǒng)的RNN特別弱卖哎,于是有了LSTM這個變體鬼悠。
LSTM
這就是LSTM的模型結構,也是一個向后傳遞的鏈式模型亏娜,而現(xiàn)在廣泛使用的RNN其實就是LSTM焕窝,序列中每個數(shù)據(jù)傳入LSTM可以得到兩個輸出,而這兩個輸出和序列中下一個數(shù)據(jù)一起又作為傳入LSTM的輸入维贺,然后不斷地循環(huán)向后它掂,直到序列結束。
下面結合pytorch一步一步來看數(shù)據(jù)傳入LSTM是怎么運算的
首先需要定義好LSTM網(wǎng)絡溯泣,需要nn.LSTM()虐秋,首先介紹一下這個函數(shù)里面的參數(shù)
input_size 表示的是輸入的數(shù)據(jù)維數(shù)
hidden_size 表示的是輸出維數(shù)
num_layers 表示堆疊幾層的LSTM,默認是1
bias True 或者 False垃沦,決定是否使用bias
batch_first True 或者 False客给,因為nn.lstm()接受的數(shù)據(jù)輸入是(序列長度,batch肢簿,輸入維數(shù))靶剑,這和我們cnn輸入的方式不太一致,所以使用batch_first译仗,我們可以將輸入變成(batch抬虽,序列長度,輸入維數(shù))
dropout 表示除了最后一層之外都引入一個dropout
bidirectional 表示雙向LSTM纵菌,也就是序列從左往右算一次阐污,從右往左又算一次,這樣就可以兩倍的輸出
第一步首先是將傳入的數(shù)據(jù)$x_t$和前面輸出的$h_{t-1}$咱圆,$x_t$是輸入的維數(shù)笛辟,比如是K功氨,$h_{t-1}$是網(wǎng)絡的輸出維數(shù),比如M手幢,因為輸出的維度是M捷凄,權重w的維數(shù)就是(M, M)和(M, K),b的維數(shù)就是(M, 1)和(M, 1)围来,最后經(jīng)過sigmoid激活函數(shù)跺涤,得到的f的維數(shù)是(M, 1)。
對于第一個數(shù)據(jù)监透,需要定義初始的h_0和c_0桶错,所以nn.lstm()的輸入Inputs:input, (h_0, c_0),表示輸入的數(shù)據(jù)以及h_0和c_0胀蛮,這個可以自己定義院刁,如果不定義,默認就是0
第二步也是差不多的操作粪狼,只不多是另外兩個權重加上不同的激活函數(shù)退腥,一個使用的是sigmoid,一個使用的是tanh再榄,得到的輸出$i_t$和$\tilde{C}_t$都是(M, 1)狡刘。
接著這個乘法是矩陣每個位置對應相乘,然后將兩個矩陣加起來困鸥,得到的輸出$C_t$是(M, 1)颓帝。
最后一步得到的$o_t$也是(M, 1),然后$C_t$經(jīng)過激活函數(shù)tanh窝革,再和$o_t$每個位置相乘,得到的輸出$h_t$也是(M, 1)吕座。
最后得到的輸出就是$h_t$和$C_t$虐译,維數(shù)分別都是(M, 1),而輸入$x_t$維數(shù)都是(K, 1)吴趴。
lstm = nn.LSTM(10, 30, batch_first=True)
可以通過這樣定義一個一層的LSTM輸入是10漆诽,輸出是30
lstm.weight_hh_l0.size()
lstm.weight_ih_l0.size()
lstm.bias_hh_l0.size()
lstm.bias__ih_l0.size()
可以分別得到權重的維數(shù),注意之前我們定義的4個weights被整合到了一起锣枝,比如這個lstm厢拭,輸入是10維,輸出是30維撇叁,相對應的weight就是30x10供鸠,這樣的權重有4個,然后pytorch將這4個組合在了一起陨闹,方便表示楞捂,也就是lstm.weight_ih_l0薄坏,所以它的維數(shù)就是120x10
我們定義一個輸入
x = Variable(torch.randn((50, 100, 10)))
h0 = Variable(torch.randn(1, 50, 30))
c0 = Variable(torch.randn(1, 50 ,30))
x的三個數(shù)字分別表示batch_size為50,序列長度為100寨闹,每個數(shù)據(jù)維數(shù)為10
h0的第二個參數(shù)表示batch_size為50胶坠,輸出維數(shù)為30,第一個參數(shù)取決于網(wǎng)絡層數(shù)和是否是雙向的繁堡,如果雙向需要乘2沈善,如果是多層,就需要乘以網(wǎng)絡層數(shù)
c0的三個參數(shù)和h0是一致的
out, (h_out, c_out) = lstm(x, (h0, c0))
這樣就可以得到網(wǎng)絡的輸出了椭蹄,和上面講的一致闻牡,另外如果不傳入h0和c0,默認的會傳入相同維數(shù)的0矩陣
這就是我們如何在pytorch上使用RNN的基本操作了塑娇,了解完最基本的參數(shù)我們才能夠使用其來做應用澈侠。
本文參考的資料來自如下博客
更多的RNN的應用可以看這個資源
本文代碼已經(jīng)上傳到了github上
歡迎查看我的知乎專欄,深度煉丹
歡迎訪問我的博客