1. Pytorch_循環神經網路RNN
RNN是Recurrent Neural Networks的縮寫,即循環神經網路,它常用於解決序列問題。RNN有記憶功能,除了當前輸入,還把上下文環境作為預測的依據。它常用於語音識別、翻譯等場景之中。
RNN是序列模型的基礎,盡管能夠直接調用現成的RNN演算法,但後續的復雜網路很多構建在RNN網路的基礎之上,如Attention方法需要使用RNN的隱藏層數據。RNN的原理並不復雜,但由於其中包括循環,很難用語言或者畫圖來描述,最好的方法是自己手動編寫一個RNN網路。本篇將介紹RNN網路的原理及具體實現。
在學習循環神經網路之前,先看看什麼是序列。序列sequence簡稱seq,是有先後順序的一組數據。自然語言處理是最為典型的序列問題,比如將一句話翻譯成另一句話時,其中某個詞彙的含義不僅取決於它本身,還與它前後的多個單詞相關。類似的,如果想預測電影的情節發展,不僅與當前的畫面有關,還與當前的一系列前情有關。在使用序列模型預測的過程中,輸入是序列,而輸出是一個或多個預測值。
在使用深度學習模型解決序列問題時, 最容易混淆的是,序列與序列中的元素 。在不同的場景中,定義序列的方式不同,當分析單詞的感情色彩時,一個單詞是一個序列seq;當分析句子感情色彩時,一個句子是一個seq,其中的每個單詞是序列中的元素;當分析文章感情色彩時,一篇文章是一個seq。簡單地說,seq是最終使用模型時的輸入數據,由一系列元素組成。
當分析句子的感情色彩時,以句為seq,而句中包含的各個單詞的含義,以及單詞間的關系是具體分析的對象,此時,單詞是序列中的元素,每一個單詞又可有多維特徵。從單詞中提取特徵的方法將在後面的自然語言處理中介紹。
RNN有很多種形式,單個輸入單個輸入;多個輸入多個輸出,單個輸入多個輸出等等。
舉個最簡單的例子:用模型預測一個四字短語的感情色彩,它的輸入為四個元素X={x1,x2,x3,x4},它的輸出為單個值Y={y1}。字的排列順序至關重要,比如「從好變壞」和「從壞變好」,表達的意思完全相反。之所以輸入輸出的個數不需要一一對應,是因為中間的隱藏層,變向存儲中間信息。
如果把模型設想成黑盒,如下圖所示:
如果模型使用全連接網路,在每次迭代時,模型將計算各個元素x1,x2...中各個特徵f1,f2...代入網路,求它們對結果y的貢獻度。
RNN網路則要復雜一些,在模型內部,它不是將序列中所有元素的特徵一次性輸入模型,而是每一次將序列中單個元素的特徵輸入模型,下圖描述了RNN的數據處理過程,左圖為分步展示,右圖將所有時序步驟抽象成單一模塊。
第一步:將第一個元素x1的特徵f1,f2...輸入模型,模型根據輸入計算出隱藏層h。
第二步:將第二個元素x2的特徵輸入模型,模型根據輸入和上一步產生的h再計算隱藏層h,其它元素以此類推。
第三步:將最後一個元素xn的特徵輸入模型,模型根據輸入和上一步產生的h計算隱藏層h和預測值y。
隱藏層h可視為將序列中前面元素的特徵和位置通過編碼向前傳遞,從而對輸出y發生作用,隱藏層的大小決定了模型攜帶信息量的多少。隱藏層也可以作為模型的輸入從外部傳入,以及作為模型的輸出返回給外部調用。
本例仍使用上篇中的航空乘客序列數據,分別用兩種方法實現RNN:自己編寫程序實現RNN模型,以及調用Pytorch提供的RNN模型。前一種方法主要用於剖析原理,後一種用於展示常用的調用方法。
首先導入頭文件,讀取乘客數據,做歸一化處理,並將數據切分為測試集和訓練集,與之前不同的是加入了create_dataset函數,用於生成序列數據,序列的輸入部分,每個元素中包括兩個特徵:前一個月的乘客量prev和月份值mon,這里的月份值並不是關鍵特徵,主要用於在常式中展示如何使用多個特徵。
第一步:實現模型類,此例中的RNN模型除了全連接層,還生成了一個隱藏層,並在下一次前向傳播時將隱藏層輸出的數據與輸入數據組合後再代入模型運算。
第二步,訓練模型,使用全部數據訓練500次,在每次訓練時,內部for循環將序列中的每個元素代入模型,並將模型輸出的隱藏層和下一個元素一起送入下一次迭代。
第三步:預測和作圖,預測的過程與訓練一樣,把全部數據拆分成元素代入模型,並將每一次預測結果存儲在數組中,並作圖顯示。
需要注意的是,在訓練和預測過程中,每一次開始輸入新序列之前,都重置了隱藏層,這是由於隱藏層的內容只與當前序列相關,序列之間並無連續性。
程序輸出結果如下圖所示:
經過500次迭代,使用RNN的效果明顯優於上一篇中使用全連接網路的擬合效果,還可以通過調整超參數以及選擇不同特徵,進一步優化。
使用Pytorch提供的RNN模型,torch.nn.RNN類可直接使用,是循環網路最常用的解決方案。RNN,LSTM,GRU等循環網路都實現在同一源碼文件torch/nn/moles/rnn.py中。
第一步:創建模型,模型包含兩部分,第一部分是Pytorch提供的RNN層,第二部分是一個全連接層,用於將RNN的輸出轉換成輸出目標的維度。
Pytorch的RNN前向傳播允許將隱藏層數據h作為參數傳入模型,並將模型產生的h和y作為函數返回值。形如: pred, h_state = model(x, h_state)
什麼情況下需要接收隱藏層的狀態h_state,並轉入下一次迭代呢?當處理單個seq時,h在內部前向傳遞;當序列與序列之間也存在前後依賴關系時,可以接收h_state並傳入下一步迭代。另外,當模型比較復雜如LSTM模型包含眾多參數,傳遞會增加模型的復雜度,使訓練過程變慢。本例未將隱藏層轉到模型外部,這是由於模型內部實現了對整個序列的處理,而非處理單個元素,而每次代入的序列之間又沒有連續性。
第二步:訓練模型,與上例中把序列中的元素逐個代入模型不同,本例一次性把整個序列代入了模型,因此,只有一個for循環。
Pythorch支持批量處理,前向傳遞時輸入數據格式是[seq_len, batch_size, input_dim),本例中輸入數據的維度是[100, 1, 2],input_dim是每個元素的特徵數,batch_size是訓練的序列個數,seq_len是序列的長度,這里使用70%作為訓練數據,seq_len為100。如果數據維度的順序與要求不一致,一般使用transpose轉換。
第三步:預測和作圖,將全部數據作為序列代入模型,並用預測值作圖。
程序輸出結果如下圖所示:
可以看到,經過500次迭代,在前100個元素的訓練集上擬合得很好,但在測試集效果較差,可能存在過擬合。
2. 搭建神經網路用什麼軟體
用Matlab就可以了, 裡面有神經網路的工具箱很方便的。