GRU
时间步数较大或者较小时,循环神经网络梯度较容易出现梯度衰减/梯度爆炸。
虽然裁剪梯度可以应对梯度爆炸,但没法解决梯度衰减问题。
所以提出⻔控循环神经⽹络GRU,来捕捉时间序列中时间步距离较⼤的依赖关系
RNN存在的问题:梯度较容易出现衰减或爆炸(BPTT)
⻔控循环神经⽹络:捕捉时间序列中时间步距离较⼤的依赖关系
RNN:
H
t
=
ϕ
(
X
t
W
x
h
+
H
t
−
1
W
h
h
+
b
h
)
H_{t} = ϕ(X_{t}W_{xh} + H_{t-1}W_{hh} + b_{h})
Ht=ϕ(XtWxh+Ht−1Whh+bh)
GRU:
R
t
=
σ
(
X
t
W
x
r
+
H
t
−
1
W
h
r
+
b
r
)
Z
t
=
σ
(
X
t
W
x
z
+
H
t
−
1
W
h
z
+
b
z
)
H
~
t
=
t
a
n
h
(
X
t
W
x
h
+
(
R
t
⊙
H
t
−
1
)
W
h
h
+
b
h
)
H
t
=
Z
t
⊙
H
t
−
1
+
(
1
−
Z
t
)
⊙
H
~
t
R_{t} = σ(X_tW_{xr} + H_{t−1}W_{hr} + b_r)\ Z_{t} = σ(X_tW_{xz} + H_{t−1}W_{hz} + b_z)\ widetilde{H}_t = tanh(X_tW_{xh} + (R_t ⊙H_{t−1})W_{hh} + b_h)\ H_t = Z_t⊙H_{t−1} + (1−Z_t)⊙widetilde{H}_t
Rt=σ(XtWxr+Ht−1Whr+br)Zt=σ(XtWxz+Ht−1Whz+bz)H
t=tanh(XtWxh+(Rt⊙Ht−1)Whh+bh)Ht=Zt⊙Ht−1+(1−Zt)⊙H
t
• 重置⻔有助于捕捉时间序列⾥短期的依赖关系;
• 更新⻔有助于捕捉时间序列⾥⻓期的依赖关系。
初始化参数
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
30num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size print('will use', device) def get_params(): def _one(shape): ts = torch.tensor(np.random.normal(0, 0.01, size=shape), device=device, dtype=torch.float32) #正态分布 return torch.nn.Parameter(ts, requires_grad=True) def _three(): return (_one((num_inputs, num_hiddens)), _one((num_hiddens, num_hiddens)), torch.nn.Parameter(torch.zeros(num_hiddens, device=device, dtype=torch.float32), requires_grad=True)) W_xz, W_hz, b_z = _three() # 更新门参数 W_xr, W_hr, b_r = _three() # 重置门参数 W_xh, W_hh, b_h = _three() # 候选隐藏状态参数 # W_x=x*h, W_h=h*h, b=h(x输入个数,h隐藏单元个数) # x=n*x(n批量大小,x输入个数) #(1*x)(x*h)+(1*h)(h*h)+h = h # 输出层参数 #输出到一个output,如果是分类器,q个类别,则输出到形状为q的tensor上 #Ht大小为h,output大小为q,则W_hq=h*q, b_q=q W_hq = _one((num_hiddens, num_outputs)) b_q = torch.nn.Parameter(torch.zeros(num_outputs, device=device, dtype=torch.float32), requires_grad=True) return nn.ParameterList([W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q]) def init_gru_state(batch_size, num_hiddens, device): #隐藏状态H-1初始化 return (torch.zeros((batch_size, num_hiddens), device=device), ) #每个batch_size需要一个H-1,每个H-1都初始化为0
GRU模型
1
2
3
4
5
6
7
8
9
10
11
12
13def gru(inputs, state, params): W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q = params #十二个参数初始化 H, = state outputs = [] for X in inputs: #对input的每一个样本X Z = torch.sigmoid(torch.matmul(X, W_xz) + torch.matmul(H, W_hz) + b_z) R = torch.sigmoid(torch.matmul(X, W_xr) + torch.matmul(H, W_hr) + b_r) H_tilda = torch.tanh(torch.matmul(X, W_xh) + R * torch.matmul(H, W_hh) + b_h) H = Z * H + (1 - Z) * H_tilda Y = torch.matmul(H, W_hq) + b_q #Y即需要的output outputs.append(Y) return outputs, (H,) #返回output和最后一个隐藏层H
训练模型
1
2
3num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2 pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']
1
2
3
4
5
6
7d2l.train_and_predict_rnn(gru, get_params, init_gru_state, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, False, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes) #把第一个参数改成gru
简洁实现
1
2
3
4
5
6
7
8
9
10
11
12
13num_hiddens=256 num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2 pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开'] lr = 1e-2 # 注意调整学习率 gru_layer = nn.GRU(input_size=vocab_size, hidden_size=num_hiddens) model = d2l.RNNModel(gru_layer, vocab_size).to(device) d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes) #epoch增加,困惑度减小
LSTM
** 长短期记忆long short-term memory **:
遗忘门:控制上一时间步的记忆细胞
输入门:控制当前时间步的输入
输出门:控制从记忆细胞到隐藏状态
记忆细胞:⼀种特殊的隐藏状态的信息的流动
I t = σ ( X t W x i + H t − 1 W h i + b i ) F t = σ ( X t W x f + H t − 1 W h f + b f ) O t = σ ( X t W x o + H t − 1 W h o + b o ) C ~ t = t a n h ( X t W x c + H t − 1 W h c + b c ) C t = F t ⊙ C t − 1 + I t ⊙ C ~ t H t = O t ⊙ t a n h ( C t ) I_t = σ(X_tW_{xi} + H_{t−1}W_{hi} + b_i) \ F_t = σ(X_tW_{xf} + H_{t−1}W_{hf} + b_f)\ O_t = σ(X_tW_{xo} + H_{t−1}W_{ho} + b_o)\ widetilde{C}_t = tanh(X_tW_{xc} + H_{t−1}W_{hc} + b_c)\ C_t = F_t ⊙C_{t−1} + I_t ⊙widetilde{C}_t\ H_t = O_t⊙tanh(C_t) It=σ(XtWxi+Ht−1Whi+bi)Ft=σ(XtWxf+Ht−1Whf+bf)Ot=σ(XtWxo+Ht−1Who+bo)C t=tanh(XtWxc+Ht−1Whc+bc)Ct=Ft⊙Ct−1+It⊙C tHt=Ot⊙tanh(Ct)
记忆细胞:特殊的隐藏状态,形状和隐藏状态Ht-1相同
初始化参数
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
26num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size print('will use', device) def get_params(): def _one(shape): ts = torch.tensor(np.random.normal(0, 0.01, size=shape), device=device, dtype=torch.float32) return torch.nn.Parameter(ts, requires_grad=True) def _three(): return (_one((num_inputs, num_hiddens)), _one((num_hiddens, num_hiddens)), torch.nn.Parameter(torch.zeros(num_hiddens, device=device, dtype=torch.float32), requires_grad=True)) W_xi, W_hi, b_i = _three() # 输入门参数 W_xf, W_hf, b_f = _three() # 遗忘门参数 W_xo, W_ho, b_o = _three() # 输出门参数 W_xc, W_hc, b_c = _three() # 候选记忆细胞参数 # 输出层参数 W_hq = _one((num_hiddens, num_outputs)) b_q = torch.nn.Parameter(torch.zeros(num_outputs, device=device, dtype=torch.float32), requires_grad=True) return nn.ParameterList([W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c, W_hq, b_q]) def init_lstm_state(batch_size, num_hiddens, device): #H-1和C-1的初始化 return (torch.zeros((batch_size, num_hiddens), device=device), torch.zeros((batch_size, num_hiddens), device=device))
LSTM模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def lstm(inputs, state, params): [W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c, W_hq, b_q] = params (H, C) = state outputs = [] for X in inputs: I = torch.sigmoid(torch.matmul(X, W_xi) + torch.matmul(H, W_hi) + b_i) F = torch.sigmoid(torch.matmul(X, W_xf) + torch.matmul(H, W_hf) + b_f) O = torch.sigmoid(torch.matmul(X, W_xo) + torch.matmul(H, W_ho) + b_o) C_tilda = torch.tanh(torch.matmul(X, W_xc) + torch.matmul(H, W_hc) + b_c) C = F * C + I * C_tilda H = O * C.tanh() Y = torch.matmul(H, W_hq) + b_q outputs.append(Y) return outputs, (H, C) #返回当前列表,当前H,当前C
训练模型
1
2
3
4
5
6
7
8
9
10num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2 pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开'] d2l.train_and_predict_rnn(lstm, get_params, init_lstm_state, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, False, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes) #把第一个参数改成lstm
简洁实现
1
2
3
4
5
6
7
8
9
10
11
12num_hiddens=256 num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2 pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开'] lr = 1e-2 # 注意调整学习率 lstm_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens) model = d2l.RNNModel(lstm_layer, vocab_size) d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes)
深度循环神经网络
H t ( 1 ) = ϕ ( X t W x h ( 1 ) + H t − 1 ( 1 ) W h h ( 1 ) + b h ( 1 ) ) H t ( ℓ ) = ϕ ( H t ( ℓ − 1 ) W x h ( ℓ ) + H t − 1 ( ℓ ) W h h ( ℓ ) + b h ( ℓ ) ) O t = H t ( L ) W h q + b q boldsymbol{H}_t^{(1)} = phi(boldsymbol{X}_t boldsymbol{W}_{xh}^{(1)} + boldsymbol{H}_{t-1}^{(1)} boldsymbol{W}_{hh}^{(1)} + boldsymbol{b}_h^{(1)})\ boldsymbol{H}_t^{(ell)} = phi(boldsymbol{H}_t^{(ell-1)} boldsymbol{W}_{xh}^{(ell)} + boldsymbol{H}_{t-1}^{(ell)} boldsymbol{W}_{hh}^{(ell)} + boldsymbol{b}_h^{(ell)})\ boldsymbol{O}_t = boldsymbol{H}_t^{(L)} boldsymbol{W}_{hq} + boldsymbol{b}_q Ht(1)=ϕ(XtWxh(1)+Ht−1(1)Whh(1)+bh(1))Ht(ℓ)=ϕ(Ht(ℓ−1)Wxh(ℓ)+Ht−1(ℓ)Whh(ℓ)+bh(ℓ))Ot=Ht(L)Whq+bq
好处:可以抽取到更高层更抽象的信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14num_hiddens=256 num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2 pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开'] lr = 1e-2 # 注意调整学习率 #区别,num_layers=2(前面不写的话默认=1) gru_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens,num_layers=2) model = d2l.RNNModel(gru_layer, vocab_size).to(device) d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes)
1
2
3
4
5
6
7
8
9
10gru_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens,num_layers=6) model = d2l.RNNModel(gru_layer, vocab_size).to(device) d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes) #num_layers=2比=6的结果要好,说明深度循环神经网络不是越深越好,因为越深模型越复杂,对数据集要求也更高 #所以具体参数设置需要实验+经验结合
双向循环神经网络
在自然语言处理中较为常用
H
→
t
=
ϕ
(
X
t
W
x
h
(
f
)
+
H
→
t
−
1
W
h
h
(
f
)
+
b
h
(
f
)
)
H
←
t
=
ϕ
(
X
t
W
x
h
(
b
)
+
H
←
t
+
1
W
h
h
(
b
)
+
b
h
(
b
)
)
begin{aligned} overrightarrow{boldsymbol{H}}_t &= phi(boldsymbol{X}_t boldsymbol{W}_{xh}^{(f)} + overrightarrow{boldsymbol{H}}_{t-1} boldsymbol{W}_{hh}^{(f)} + boldsymbol{b}_h^{(f)})\ overleftarrow{boldsymbol{H}}_t &= phi(boldsymbol{X}_t boldsymbol{W}_{xh}^{(b)} + overleftarrow{boldsymbol{H}}_{t+1} boldsymbol{W}_{hh}^{(b)} + boldsymbol{b}_h^{(b)}) end{aligned}
HtHt=ϕ(XtWxh(f)+Ht−1Whh(f)+bh(f))=ϕ(XtWxh(b)+Ht+1Whh(b)+bh(b))
H
t
=
(
H
→
t
,
H
←
t
)
boldsymbol{H}_t=(overrightarrow{boldsymbol{H}}_{t}, overleftarrow{boldsymbol{H}}_t)
Ht=(Ht,Ht)
O
t
=
H
t
W
h
q
+
b
q
boldsymbol{O}_t = boldsymbol{H}_t boldsymbol{W}_{hq} + boldsymbol{b}_q
Ot=HtWhq+bq
两个方向,另一个方向相当于,x1=xt’,xt=x1’。然后两个隐藏层concat拼接起来
好处,相当于同时考虑了前面的和后面的字对该字的影响
1
2
3
4
5
6
7
8
9
10
11
12
13
14num_hiddens=128 num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e-2, 1e-2 pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开'] lr = 1e-2 # 注意调整学习率 #区别:加上bidirectional=True gru_layer = nn.GRU(input_size=vocab_size, hidden_size=num_hiddens,bidirectional=True) model = d2l.RNNModel(gru_layer, vocab_size).to(device) d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes)
习题
-
LSTM单元中控制当前时间步输入的结构是?b
遗忘门
输入门
输出门
记忆细胞
-
实现深层循环神经网络需要修改的参数是?d
input_size
hidden_size
bidirectional
num_layers
-
下列关于GRU说法正确的是?c
GRU有遗忘门、更新门两种门控结构
GRU中重置门有助于捕捉时间序列里长期的依赖关系
GRU中更新门有助于捕捉时间序列里长期的依赖关系
GRU中遗忘门有助于捕捉时间序列里长期的依赖关系
答案解释
GRU有重置门和更新门,没有遗忘门。重置门有助于捕捉时间序列里短期的依赖关系,更新门有助于捕捉时间序列⾥长期的依赖关系。参考视频1分20秒起关于GRU的原理讲解。 -
在LSTM模型的初始化中,下列不需要初始化的参数是?a
每个循环单元中的记忆细胞和循环单元的值
第0个循环单元的记忆细胞和循环单元的值
门控单元中用于计算遗忘门的权重与偏差
用于计算输出的权重与偏差
答案解释 每个循环单元中的记忆细胞和循环单元的值为LSTM模型中的隐状态,而非参数,因此不需要初始化。
-
下列关于RNN的说法错误的是?d
GRU、LSTM都能捕捉时间序列中时间步距离较⼤的依赖关系。
双向循环神经网络在文本任务里能做到同时考虑上文和下文与当前词之间的依赖。
LSTM和GRU能一定程度缓解梯度消失与梯度爆炸的问题。
深层循环网络能有效抽取更高层更抽象的信息,层数越深效果越好。
答案解释 层数越深效果未必越好,层数的加深会导致模型的收敛变得困难。
-
双向循环神经网络前向和后向RNN连结的方式是 b
前向的output和后向的output用concat进行连结
前向的H_t和后向的H_t用concat进行连结
前向的output和后向的output按元素相加
前向的H_t和后向的H_t按元素相加
最后
以上就是温柔招牌最近收集整理的关于《动手学——循环神经网络进阶》笔记GRULSTM深度循环神经网络双向循环神经网络的全部内容,更多相关《动手学——循环神经网络进阶》笔记GRULSTM深度循环神经网络双向循环神经网络内容请搜索靠谱客的其他文章。
发表评论 取消回复