本篇是在之前兩篇基礎上接着寫的:
也可以不看,如果以下有看不懂的,再回過頭來看上面兩篇也行。
前言
目錄
-
閥門和狀態描述
-
LSTM cell
-
LSTM整個過程
需要理解:
-
遺忘門,更新門,輸出門的作用是什么,它們是怎么發揮作用的。
-
單元狀態 cell state 是如何來選擇性保留信息。
下面這張圖將示意LSTM的操作。

LSTM單元,它在每一個時間步長跟蹤更新“單元狀態”或者是記憶變量。
同之前講的RNN例子一樣,我們將以一個時間步長的LSTM單元執行開始,接着你就可以用for循環處理Tx個時間步長。
閥門和狀態概述
遺忘門
概念:
-
假設我們正在閱讀一段文本中的單詞,並計划使用LSTM跟蹤語法結構,例如判斷主體是單數(“ puppy”)還是復數(“ puppies”)。
-
如果主體更改其狀態(從單數詞更改為復數詞),那么先前的記憶狀態將過時,因此我們“忘記”過時的狀態。
-
“遺忘門”是一個張量,它包含介於0和1之間的值。
-
如果遺忘門中的一個單元的值接近於0,則LSTM將“忘記”之前單元狀態相應單位的存儲值。
-
如果遺忘門中的一個單元的值接近於1,則LSTM將記住大部分相應的值。
公式:

公式的解釋:
-
包含控制遺忘門行為的權重。
-
之前時間步長的隱藏狀態和當前時間步長的輸入連接在一起乘以。
-
sigmoid函數讓每個門的張量值在0到1之間。
-
遺忘門和之前的單元狀態有相同的shape。
-
這就意味着它們可以按照元素相乘。
-
將張量和相乘相當於在之前的單元狀態應用一層蒙版。
-
如果中的單個值是0或者接近於0,那么乘積就接近0.
-
這就是使得存儲在對應單位的值在下一個時間步長不會被記住。
-
同樣,如果中的1個值接近於1,那么乘積就接近之前單元狀態的原始值。
-
LSTM就會在下一個時間步長中保留對應單位的值。
在代碼中的變量名:
-
Wf: 遺忘門的權重
-
Wb: 遺忘門的偏差
-
ft: 遺忘門
候選值
概念:
-
候選值是包含當前時間步長信息的張量,它可能會存儲在當前單元狀態中。
-
傳遞候選值的哪些部分取決於更新門。
-
候選值是一個張量,它的范圍從-1到1。
-
代字號“〜”用於將候選值與單元狀態區分開。
公式:

公式的解釋:
-
'tanh'函數產生的值介於-1和+1之間。
在代碼中的變量名:
-
cct: 候選值
更新門
概念:
-
我們使用更新門來確定候選的哪些部分要添加到單元狀態中。
-
更新門是包含0到1之間值的張量。
-
當更新門中的單位接近於0時,它將阻止候選值中的相應值傳遞到。
-
當更新門中的單位接近1時,它允許將候選的值傳遞到。
-
注意,我們使用下標“i”而不是“u”來遵循文獻中使用的約定。
公式:

公式的解釋:
-
類似於遺忘門(此處為),用sigmoid函數乘后值就落在了0到1之間。
-
將更新門與候選元素逐元素相乘,並將此乘積()用於確定單元狀態。
在代碼中的變量名:
在代碼中,我們將使用學術文獻中的變量名。這些變量不使用“ u”表示“更新”。
-
wi是更新門的權重
-
bi是更新門的偏差
-
it是更新門
單元狀態
概念:
-
單元狀態是傳遞到未來時間步長的“記憶/內存(memory)”。
-
新單元狀態是先前單元狀態和候選值的組合。
公式:

公式的解釋:
-
之前的單元狀態通過遺忘門調整(加權)。
-
候選值通過更新門調整(加權)。
在代碼中的變量名:
-
c: 單元狀態,包含所有的時間步長,c的shape是(na, m, T)
-
c_next: 下一個時間步長的單元狀態,的shape (na, m)
-
c_prev: 之前的單元狀態,的shape (na, m)
輸出門

概念:
-
輸出門決定時間步長要輸出的預測值。
-
輸出門與其他門一樣,它包含從0到1的值。
公式:
公式的解釋:
-
輸出門由之前的隱藏狀態和當前的輸入 決定。
-
sigmoid函數讓值的范圍在0到1之間。
在代碼中的變量名:
-
wo: 輸出門的權重
-
bo: 輸出門的偏差
-
ot: 輸出門
隱藏狀態
概念:
-
隱藏狀態將傳遞到LSTM單元的下一個時間步長。
-
它用於確定下一個時間步長的三個門()。
-
隱藏狀態也用於預測。
公式:

公式的解釋:
-
隱藏狀態由單元狀態結合輸出門確定。
-
單元狀態通過“ tanh”函數把值縮放到-1和+1之間。
-
輸出門的作用就像一個“掩碼mask”,它既可以保留的值,也可以使這些值不包含在隱藏狀態中。
在代碼中的變量名:
-
a: 隱藏狀態,包含時間步長,shape (na, m, Tx)
-
a_prev: 前一步的隱藏狀態,的shape (na, m)
-
a_next: 下一步的隱藏狀態,的shape (na, m)
預測值
概念:
-
此用例的預測是分類,所以我們用softmax。
公式:

在代碼中的變量名:
-
y_pred: 預測,包含所有的時間步長,的shape (ny, m, Tx),注意,本例中Tx=Ty。
-
yt_pred: 當前時間步長t的預測值,shape是(ny, m)
LSTM cell
一共三個步驟:
1. 連接隱藏狀態和輸入成一個單獨的矩陣
2. 依次計算上面那6個公式
3. 計算預測值
def lstm_cell_forward(xt, a_prev, c_prev, parameters): """ Implement a single forward step of the LSTM-cell as described in Figure (4) 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) c_prev -- Memory state at timestep "t-1", numpy array of shape (n_a, m) parameters -- python dictionary containing: Wf -- Weight matrix of the forget gate, numpy array of shape (n_a, n_a + n_x) bf -- Bias of the forget gate, numpy array of shape (n_a, 1) Wi -- Weight matrix of the update gate, numpy array of shape (n_a, n_a + n_x) bi -- Bias of the update gate, numpy array of shape (n_a, 1) Wc -- Weight matrix of the first "tanh", numpy array of shape (n_a, n_a + n_x) bc -- Bias of the first "tanh", numpy array of shape (n_a, 1) Wo -- Weight matrix of the output gate, numpy array of shape (n_a, n_a + n_x) bo -- Bias of the output gate, numpy array of shape (n_a, 1) Wy -- Weight matrix relating the hidden-state to the output, numpy array of shape (n_y, n_a) 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) c_next -- next memory 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, c_next, a_prev, c_prev, xt, parameters) Note: ft/it/ot stand for the forget/update/output gates, cct stands for the candidate value (c tilde), c stands for the cell state (memory) """ # 從 "parameters" 中取出參數。 Wf = parameters["Wf"] # 遺忘門權重 bf = parameters["bf"] Wi = parameters["Wi"] # 更新門權重 (注意變量名下標是i不是u哦) bi = parameters["bi"] # (notice the variable name) Wc = parameters["Wc"] # 候選值權重 bc = parameters["bc"] Wo = parameters["Wo"] # 輸出門權重 bo = parameters["bo"] Wy = parameters["Wy"] # 預測值權重 by = parameters["by"] # 連接 a_prev 和 xt concat = np.concatenate((a_prev, xt), axis=0) # 等價於下面代碼 # 從 xt 和 Wy 中取出維度 # n_x, m = xt.shape # n_y, n_a = Wy.shape # concat = np.zeros((n_a + n_x, m)) # concat[: n_a, :] = a_prev # concat[n_a :, :] = xt # 計算 ft (遺忘門), it (更新門)的值 # cct (候選值), c_next (單元狀態), # ot (輸出門), a_next (隱藏單元) ft = sigmoid(np.dot(Wf, concat) + bf) # 遺忘門 it = sigmoid(np.dot(Wi, concat) + bi) # 更新門 cct = np.tanh(np.dot(Wc, concat) + bc) # 候選值 c_next = ft * c_prev + it * cct # 單元狀態 ot = sigmoid(np.dot(Wo, concat) + bo) # 輸出門 a_next = ot * np.tanh(c_next) # 隱藏狀態 # 計算LSTM的預測值 yt_pred = softmax(np.dot(Wy, a_next) + by) # 用於反向傳播的緩存 cache = (a_next, c_next, a_prev, c_prev, ft, it, cct, ot, xt, parameters) return a_next, c_next, yt_pred, cache
LSTM向前傳播
我們已經實現了一個時間步長的LSTM,現在我們可以用for循環對它進行迭代,處理一系列的Tx輸入。

LSTM的多個時間步長
指導:
-
從變量x 和 parameters中獲得 的維度。
-
初始化三維張量 , 和 .
-
: 隱藏狀態, shape
-
: 單元狀態, shape
-
: 預測, shape (注意在這個例子里 ).
-
注意 將一個變量設置來和另一個變量相等是"按引用復制". 換句話說,就是不用使用c = a, 否則這兩個變量指的是同一個變量,更改任何其中一個變量另一個變量的值都會跟着變。
-
初始化二維張量
-
儲存了t時間步長的隱藏狀態,它的變量名是a_next。
-
, 時間步長0時候的初始隱藏狀態,調用該函數時候傳入的值,它的變量名是a0。
-
和 代表單個時間步長,所以他們的shape都是
-
通過傳入函數的初始化隱藏狀態來初始化 。
-
用0來初始化 。
-
變量名是 c_next.
-
表示單個時間步長, 所以它的shape是
-
注意: create c_next as its own variable with its own location in memory. 不要將它通過3維張量的切片來初始化,換句話說, 不要 c_next = c[:,:,0].
-
對每個時間步長,做以下事情:
-
從3維的張量 中, 獲取在時間步長t處的2維切片 。
-
調用你之前定義的 lstm_cell_forward 函數,獲得隱藏狀態,單元狀態,預測值。
-
存儲隱藏狀態,單元狀態,預測值到3維張量中。
-
把緩存加入到緩存列表。
def lstm_forward(x, a0, parameters): """ Implement the forward propagation of the recurrent neural network using an LSTM-cell described in Figure (4). 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: Wf -- Weight matrix of the forget gate, numpy array of shape (n_a, n_a + n_x) bf -- Bias of the forget gate, numpy array of shape (n_a, 1) Wi -- Weight matrix of the update gate, numpy array of shape (n_a, n_a + n_x) bi -- Bias of the update gate, numpy array of shape (n_a, 1) Wc -- Weight matrix of the first "tanh", numpy array of shape (n_a, n_a + n_x) bc -- Bias of the first "tanh", numpy array of shape (n_a, 1) Wo -- Weight matrix of the output gate, numpy array of shape (n_a, n_a + n_x) bo -- Bias of the output gate, numpy array of shape (n_a, 1) Wy -- Weight matrix relating the hidden-state to the output, numpy array of shape (n_y, n_a) 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 -- Predictions for every time-step, numpy array of shape (n_y, m, T_x) c -- The value of the cell state, numpy array of shape (n_a, m, T_x) caches -- tuple of values needed for the backward pass, contains (list of all the caches, x) """ # 初始化 "caches", 用來存儲每個時間步長的cache值的 caches = [] Wy = parameters['Wy'] # 從 x 和 parameters['Wy'] 的shape中獲取緯度值 n_x, m, T_x = x.shape n_y, n_a = Wy.shape # 初始化 "a", "c" and "y" a = np.zeros((n_a, m, T_x)) c = np.zeros((n_a, m, T_x)) y = np.zeros((n_y, m, T_x)) # 初始化 a_next and c_next a_next = a0 c_next = np.zeros(a_next.shape) # loop over all time-steps for t in range(T_x): # 從3維張量x中獲取t時間步長的2維張量xt xt = x[:, :, t] # 更新下一個時間步長的隱藏狀態, 下一個單元狀態, 計算預測值 a_next, c_next, yt, cache = lstm_cell_forward(xt, a_next, c_next, parameters) # 把下一個時間步長長的隱藏狀態保存起來 a[:,:,t] = a_next # 把下一個時間步長長的單元狀態保存起來 c[:,:,t] = c_next # 把預測值保存起來 y[:,:,t] = yt # 保存緩存值 caches.append(cache) # 用於向后傳播 caches = (caches, x) return a, y, c, caches
恭喜你!現在,你已經為LSTM實現了前向傳播。使用深度學習框架時,實施前向傳播足以構建出色性能的系統。