在前面的章節里,給大家介紹了什么是神經網路,從基礎概念出發,為了識別MNIST資料集,我們搭建了一個全連接網路,然后又把卷積的概念引入進來后,給大家介紹了全連接網路的一種改進型——卷積神經網路,而且發現,在沒有優化網路結構的前提下,僅使用通用模型就取得了98%的準確率,優于全連接網路的95%準確率,
現在,把目光從擅長空間資料處理的卷積神經網路(CNN)轉入到擅長時序任務處理的回圈神經網路(RNN),又來看看它是怎么作業,
文章目錄
- 為什么使用回圈神經網路
- ECG信號
- 語音識別
- RNN的基本結構
- 斐波那契數列
- RNN網路的計算規則
為什么使用回圈神經網路
盡管FNN或者DNN(全連接網路,在一些論文里又被稱為密集神經網路 Dense Neural Network),是所有神經網路的基礎,理論上FNN也是可以用來處理時序任務,但事實上有比FNN更擅長時序任務的網路模型,這一類模型通常稱為回圈神經網路——RNN,
我們生活種常見的資料型別,如果簡單的分析會發現它們具有時間或空間方面的特性,比方說空間特性的圖片,和時間特性的音頻,當然也有同時具備這兩種特性的,比如說視頻,
ECG信號
與CNN專注于空間特征分析不同,RNN更擅長時間序列特征的分析,舉例來說,心電資料ECG(Electrocardiograph),單個心電資料從其波形資料上有T波、R波等,對于心內科的醫生來說,通過看心電圖,可以判斷出心臟作業狀態是否正常,是否有心顫等危險信號,

而通過一個觀察周期的心電圖資訊,例如下面這張圖,心內科醫生又可以很快判斷出竇性心律過快、過慢或者心律不齊等問題,從而為制定合理診斷提供依據,

可以看出,這一類資料有很強的順序關聯關系,如果想要分析和處理這一類資料,就要求我們一定以一定的順序方向去讀取和分析資料,
語音識別

如果我們想通過語音與計算機進行互動,直接通過語音是無法直接應用的,至少我們要先把語音轉化為文本資料后,才能分析出用戶的意圖,對于計算機來說,沒有處理過的語音資訊,就是一串帶有噪音的模擬信號而已,
雖然說CNN網路在最新的一些論文里也被用在了時序資料上,但是在時序資料的處理上,有比CNN更擅長的網路技術,這一類網路被稱為回圈神經網路(RNN:Recurrent Neural Network),
RNN的基本結構
斐波那契數列
為了讓你能理解RNN是怎么作業的,先讓我們回顧一下著名的斐波那契數列吧,它的數串列達形式是這樣的:
F n = F ( n ? 1 ) + F ( n ? 2 ) F_n = F_{(n - 1)} + F_{(n - 2)} Fn?=F(n?1)?+F(n?2)?
計算方法是從兩個1開始,即數列 F \mathbb{F} F 的 F 0 F_0 F0?, F 1 F_1 F1? 為1,這樣 F 2 = 2 , F 3 = 3 , ? F_2 = 2, F_3 = 3, \cdots F2?=2,F3?=3,?
[ 1 , 1 , 2 , 3 , 5 , 8 , 13 , ? ? ] [1, 1, 2, 3, 5, 8, 13, \cdots] [1,1,2,3,5,8,13,?]
我們用計算圖的形式表示這個計算程序:

可以看到,1 與 2 相加得到3,2 參加下一輪計算,與 3 相加得到5,以此類推,
如果我們以這個圖下方的數當作輸入 X X X,上方的數字為輸出 O O O,那么我們要得到 O n O_n On? 的輸出可以看到它依賴于上一時刻的 O ( n ? 1 ) O_{(n-1)} O(n?1)? 以及當前 X n X_n Xn? 的輸入,
用這個例子是為了說明,RNN的作業原理和斐波那契數列的運算規則很相似
RNN網路的計算規則
我們來看一下一個標準的RNN網路的計算公式
h t = tanh ? ( W i h x t + b i h + W h h h ( t ? 1 ) + b h h ) h_t = \tanh (W_{ih} x_{t} + b_{ih} +W_{hh} h_{(t?1)} + b_{hh}) ht?=tanh(Wih?xt?+bih?+Whh?h(t?1)?+bhh?)
要知道 y = W x + b \mathbf{y} = \mathbf{W} \mathbf{x} + \mathbf{b} y=Wx+b 是一個標準線性公式,如果我們令
{ y i = W i h x t + b i h y h = W h h h t ? 1 + b h h \left\{\begin{matrix} \mathbf{y_i} = W_{ih} x_{t} + b_{ih} \\ \mathbf{y_h} = W_{hh} h_{t-1} + b_{hh} \end{matrix}\right. {yi?=Wih?xt?+bih?yh?=Whh?ht?1?+bhh??
上面這個公式就表示為:
h t = tanh ? ( y i + y h ) h_t = \tanh (\mathbf{y_i} + \mathbf{y_h}) ht?=tanh(yi?+yh?)
其中 y i \mathbf{y_i} yi? 表示的就是與輸入相關的線性公式, y h \mathbf{y_h} yh? 就是在RNN中經常被提到的隱藏層,你可以理解為對上一次計算結果的保存,如果用圖表示RNN計算程序,那么就是下面這個樣子的:

一個基本的RNN節點會經常被描寫成這樣的結構:
- 當前輸入資料的 X i X_i Xi?,
- 用于回饋并計入下一次計算的 ω i \omega_i ωi? 也就是隱藏層 y h \mathbf{y_h} yh? 的權重
- 以及每一次計算輸出的 O i O_i Oi?,
由于 y h \mathbf{y_h} yh? 矩陣通常保存了上一次的計算結果,所以它的矩陣維度事實上是可以和 參與計算 O i O_i Oi? 的權重矩陣維度一致,盡管事實上在Pytorch提供的相關模型里也是這么設定的,但是要指出的是, O i O_i Oi? 與 ω i \omega_i ωi? 雖然有關系,但不是一回事,有些教科書或者講師可能會說它們是一回事,但其實它們的關系更像是雙胞胎兄弟,而不是同一個人,
用線性層的代碼直接實作一個RNN網路的話,通常是這樣的:
class RNN(torch.nn.Module):
"""
$h_t = tanh(W_{ih}x_t + b_{ih} + W_{hh}h_{(t-1)} + b_{hh})$
input_size: encoded data size, could be in one-hot-vector, or ascii based, and etc.
hidden_size: hidden state, to recorde previous computed weights
output_size: output features to predicate
"""
def __init__(self, input_size, hidden_size, output_size):
super(RNN, self).__init__()
self.hidden_size = hidden_size
self.i2h = torch.nn.Linear(input_size + hidden_size, hidden_size)
self.i2o = torch.nn.Linear(input_size + hidden_size, output_size)
self.softmax = torch.nn.LogSoftmax(dim=1)
def forward(self, x, h0):
"""
x: encoded substance of a sequence, for instance, 'a' to 'apple'
ho: previous computed features of hidden layer, if no knowledges need to
passed in first recurrent time, given a tensor with all-zero to the net
"""
combined = torch.cat((x, h0), 1)
h0 = self.i2h(combined)
output = self.i2o(combined)
output = self.softmax(output)
return output, h0
- 基本結構由兩個線性計算單元及一個Softmax構成;
- 運算的時候,要傳入當前的資料,以及先前的隱藏層資料;
- 資料通過cat命令轉化為一個完整的張量 combined;
- combined 分別送給負責隱藏層的 i2h 單元,和負責輸出的 i2o 單元;
- i2o單元得到的結果再通過 softmax 后回傳給用戶,
之所以說它們是一樣的唯一原因,僅僅是如果隱藏層輸出特征維度與 i2o 輸出的特征維度一致的時候, h 0 h_0 h0? 和 沒有 softmax 處理過的 output 才是一樣的,
通過上面的說明,我們可以知道 RNN的計算節點,本質上就是線性層堆疊,所以它并沒有你想象中的那么難理解,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297674.html
標籤:其他
上一篇:在ubuntu下將Pytorch模型部署到c++(一)(環境搭建)
下一篇:git的基本命令
