用純Python實現循環神經網絡RNN向前傳播過程(吳恩達DeepLearning.ai作業)
Google TensorFlow程序員點讚的文章!
前言
目錄:
- 向量表示以及它的維度
- rnn cell
- rnn 向前傳播
重點關注:
- 如何把數據向量化的,它們的維度是怎麼來的
- 一共其實就是兩步: 單個單元的rnn計算,拉通來的rnn計算
在看本文前,可以先看看這篇文章回憶一下:
吳恩達deepLearning.ai循環神經網絡RNN學習筆記(理論篇)
我們將實現以下結構的RNN,在這個例子中 Tx = Ty。
向量表示以及它的維度
Input with nx number of units
對單個輸入樣本,x(i) 是一維輸入向量。
用語言來舉個例子,將具有5k個單詞詞彙量的語言用one-hot編碼成具有5k個單位的向量,所以 x(i) 的維度是(5000,)。
我們將用符號 nx 表示單個訓練樣本的單位數。
Batches of size m
如果我們取小批量(mini-batches),每個批次有20個訓練樣本。
爲了受益於向量化,我們將20個樣本 x(i) 變成一個2維數組(矩陣)。
比如一個維度是(5000,20)的向量。
我們用m來表示訓練樣本的數量。
所以小批量訓練數據的維度是 (nx, m)。
Time steps of size Tx
循環神經網絡有多個時間步驟,我們用t來表示。
我們將看到訓練樣本 x(i) 將經歷多個時間步驟 Tx, 比如如果有10個時間步驟,那麼 Tx = 10。
3D Tensor of shape (nx, m, Tx)
輸入x就是用維度是 (nx, m, Tx) 的三維張量來表示。
Taking a 2D slice for each time step:
每一個時間步驟,我們用小批量訓練樣本(不是單個的訓練樣本)。
所以針對每個時間步驟t,我們用維度是 (nx, m)的2維切片。
我們把它表示成xt。
隱藏狀態a的維度
a的定義: 從一個時間步驟到另一個時間步驟的激活值 at, 我們把它叫做隱藏狀態。
同輸入張量 x 一樣,對於單個訓練樣本的隱藏狀態,它的向量長度是na。
如果我們是包含了m個訓練樣本的小批量數據,那麼小批量維度是 (na, m)。
如果我們把時間步加進去,那麼隱藏狀態的維度就是 (na, m, Tx)。
我們將用索引t來遍歷時間步,每次操作是從3維張量切片成的2維向量。
我們用at來表示2維的切片,它的維度是 (na, m)。
預測值y^的維度
同輸入x和隱藏狀態一樣,y^是一個維度是 (ny, m, Ty) 的3維張量。
ny: 代表預測值的單位數。
m: 小批次訓練的樣本數量。
Ty: 預測的時間數。
比如單個時間步 t,2維的切片 y^ 的維度是 (ny, m)。
RNN cell
我們的第一個任務就是執行單個時間步驟的計算,計算如下圖。
輸入是a^, xt,輸出是at, yt^。以下的代碼其實就是把上面的公式代碼化,總的步驟分成4步:
取出參數。
計算at。
計算yt^。
返回輸出的at, yt^,還要存儲一些值緩存起來。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import numpy as np
def rnn_cell_forward(xt, a_prev, parameters):
"""
Implements a single forward step of the RNN-cell as described in Figure (2)
Arguments:
xt -- your input data at timestep "t", numpy array of shape (n_x, m).
a_prev -- Hidden state at timestep "t-1", numpy array of shape (n_a, m)
parameters -- python dictionary containing:
Wax -- Weight matrix multiplying the input, numpy array of shape (n_a, n_x) Waa -- Weight matrix multiplying the hidden state, numpy array of shape (n_a, n_a)
Wya -- Weight matrix relating the hidden-state to the output, numpy array of shape (n_y, n_a)
ba -- Bias, numpy array of shape (n_a, 1)
by -- Bias relating the hidden-state to the output, numpy array of shape (n_y, 1)
Returns:
a_next -- next hidden state, of shape (n_a, m)
yt_pred -- prediction at timestep "t", numpy array of shape (n_y, m)
cache -- tuple of values needed for the backward pass, contains (a_next, a_prev, xt, parameters)
"""
# 取計算的參數
Wax = parameters["Wax"]
Waa = parameters["Waa"]
Wya = parameters["Wya"]
ba = parameters["ba"]
by = parameters["by"]
# 用公式計算下一個單元的激活值
a_next = np.tanh(np.dot(Waa, a_prev) + np.dot(Wax, xt) + ba)
# 計算當前cell的輸出
yt_pred = softmax(np.dot(Wya, a_next) + by)
# 用於向後傳播的緩存值
cache = (a_next, a_prev, xt, parameters)
return a_next, yt_pred, cache
RNN向前傳播
一個循環神經網絡就是不斷的重複你上面創建的rnn 單元。
如果你的輸入數據序列是10個時間步,那麼你就要重複你的rnn cell 10次。
在每個時間步中,每個單元將用2個輸入:
a: 前一個單元的隱藏狀態。
xt: 當前時間步的輸入數據。
每個時間步有兩個輸出:
一個隱藏狀態at
一個測值y^⟨t⟩
權重和偏差 (Waa,ba,Wax,bx) 將在每個時間步中循環使用,它們保存在"parameters"的變量中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def rnn_forward(x, a0, parameters):
"""
Implement the forward propagation of the recurrent neural network described in Figure (3).
Arguments:
x -- Input data for every time-step, of shape (n_x, m, T_x).
a0 -- Initial hidden state, of shape (n_a, m)
parameters -- python dictionary containing:
Waa -- Weight matrix multiplying the hidden state, numpy array of shape (n_a, n_a)
Wax -- Weight matrix multiplying the input, numpy array of shape (n_a, n_x)
Wya -- Weight matrix relating the hidden-state to the output, numpy array of shape (n_y, n_a)
ba -- Bias numpy array of shape (n_a, 1)
by -- Bias relating the hidden-state to the output, numpy array of shape (n_y, 1)
Returns:
a -- Hidden states for every time-step, numpy array of shape (n_a, m, T_x)
y_pred -- Predictions for every time-step, numpy array of shape (n_y, m, T_x)
caches -- tuple of values needed for the backward pass, contains (list of caches, x)
"""
# 用於存儲所有cache的列表,初始化它
caches = []
# 取一些緯度值,用於後面初始化變量
n_x, m, T_x = x.shape
n_y, n_a = parameters["Wya"].shape
# 初始化 a 和 y_pred
a = np.zeros((n_a, m, T_x))
y_pred = np.zeros((n_y, m, T_x))
# 初始化 a_next
a_next = a0
# loop over all time-steps of the input 'x'
for t in range(T_x):
# Update next hidden state, compute the prediction, get the cache
xt = x[:,:,t] # 通過切片的方式從輸入變量x中取出當前t時間步的輸入xt
a_next, yt_pred, cache = rnn_cell_forward(xt, a_next, parameters)
# 保存當前單元計算的a_next值
a[:,:,t] = a_next
# 保存當前單元的預測值y
y_pred[:,:,t] = yt_pred
# 添加每個單元的緩存值
caches.append(cache)
# store values needed for backward propagation in cache
caches = (caches, x)
return a, y_pred, caches
恭喜你(^▽^),到這裏你已經能夠從0到1的構建循環神經網絡的向前傳播過程。
在現代深度學習框架中,您僅需實現前向傳遞,而框架將處理後向傳遞,因此大多數深度學習工程師無需理會後向傳遞的細節。我就不寫向後傳播了。