Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
d2l-zh
提交
f262428c
D
d2l-zh
项目概览
OpenDocCN
/
d2l-zh
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
d2l-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
f262428c
编写于
1月 08, 2019
作者:
A
Aston Zhang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[1e feedback code] ch6
上级
fe3e960d
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
47 addition
and
47 deletion
+47
-47
chapter_recurrent-neural-networks/gru.md
chapter_recurrent-neural-networks/gru.md
+5
-5
chapter_recurrent-neural-networks/lang-model-dataset.md
chapter_recurrent-neural-networks/lang-model-dataset.md
+5
-5
chapter_recurrent-neural-networks/lstm.md
chapter_recurrent-neural-networks/lstm.md
+6
-6
chapter_recurrent-neural-networks/rnn-gluon.md
chapter_recurrent-neural-networks/rnn-gluon.md
+10
-10
chapter_recurrent-neural-networks/rnn-scratch.md
chapter_recurrent-neural-networks/rnn-scratch.md
+21
-21
未找到文件。
chapter_recurrent-neural-networks/gru.md
浏览文件 @
f262428c
...
...
@@ -91,13 +91,13 @@ def get_params():
_one((num_hiddens, num_hiddens)),
nd.zeros(num_hiddens, ctx=ctx))
W_xz, W_hz, b_z = _three() # 更新门参数
。
W_xr, W_hr, b_r = _three() # 重置门参数
。
W_xh, W_hh, b_h = _three() # 候选隐藏状态参数
。
# 输出层参数
。
W_xz, W_hz, b_z = _three() # 更新门参数
W_xr, W_hr, b_r = _three() # 重置门参数
W_xh, W_hh, b_h = _three() # 候选隐藏状态参数
# 输出层参数
W_hq = _one((num_hiddens, num_outputs))
b_q = nd.zeros(num_outputs, ctx=ctx)
#
创建梯度。
#
附上梯度
params = [W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q]
for param in params:
param.attach_grad()
...
...
chapter_recurrent-neural-networks/lang-model-dataset.md
浏览文件 @
f262428c
...
...
@@ -56,20 +56,20 @@ print('indices:', sample)
在随机采样中,每个样本是原始序列上任意截取的一段序列。相邻的两个随机小批量在原始序列上的位置不一定相毗邻。因此,我们无法用一个小批量最终时间步的隐藏状态来初始化下一个小批量的隐藏状态。在训练模型时,每次随机采样前都需要重新初始化隐藏状态。
```
{.python .input n=25}
# 本函数已保存在
d2lzh 包中方便以后使用。
# 本函数已保存在
d2lzh包中方便以后使用
def data_iter_random(corpus_indices, batch_size, num_steps, ctx=None):
# 减
一是因为输出的索引是相应输入的索引加一。
# 减
1是因为输出的索引是相应输入的索引加1
num_examples = (len(corpus_indices) - 1) // num_steps
epoch_size = num_examples // batch_size
example_indices = list(range(num_examples))
random.shuffle(example_indices)
# 返回从
pos 开始的长为 num_steps 的序列。
# 返回从
pos开始的长为num_steps的序列
def _data(pos):
return corpus_indices[pos: pos + num_steps]
for i in range(epoch_size):
# 每次读取
batch_size 个随机样本。
# 每次读取
batch_size个随机样本
i = i * batch_size
batch_indices = example_indices[i: i + batch_size]
X = [_data(j * num_steps) for j in batch_indices]
...
...
@@ -93,7 +93,7 @@ for X, Y in data_iter_random(my_seq, batch_size=2, num_steps=6):
为了使模型参数的梯度计算只依赖一次迭代读取的小批量序列,我们可以在每次读取小批量前将隐藏状态从计算图分离出来。我们将在后面几节的实现中了解这个处理方式。
```
{.python .input n=32}
# 本函数已保存在
d2lzh 包中方便以后使用。
# 本函数已保存在
d2lzh包中方便以后使用
def data_iter_consecutive(corpus_indices, batch_size, num_steps, ctx=None):
corpus_indices = nd.array(corpus_indices, ctx=ctx)
data_len = len(corpus_indices)
...
...
chapter_recurrent-neural-networks/lstm.md
浏览文件 @
f262428c
...
...
@@ -100,14 +100,14 @@ def get_params():
_one((num_hiddens, num_hiddens)),
nd.zeros(num_hiddens, ctx=ctx))
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_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 = nd.zeros(num_outputs, ctx=ctx)
#
创建梯度。
#
附上梯度
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]
for param in params:
...
...
chapter_recurrent-neural-networks/rnn-gluon.md
浏览文件 @
f262428c
...
...
@@ -43,7 +43,7 @@ Y.shape, len(state_new), state_new[0].shape
接下来我们继承Block类来定义一个完整的循环神经网络。它首先将输入数据使用one-hot向量表示后输入到
`rnn_layer`
中,然后使用全连接输出层得到输出。输出个数等于词典大小
`vocab_size`
。
```
{.python .input n=39}
# 本类已保存在
d2lzh 包中方便以后使用。
# 本类已保存在
d2lzh包中方便以后使用
class RNNModel(nn.Block):
def __init__(self, rnn_layer, vocab_size, **kwargs):
super(RNNModel, self).__init__(**kwargs)
...
...
@@ -52,11 +52,11 @@ class RNNModel(nn.Block):
self.dense = nn.Dense(vocab_size)
def forward(self, inputs, state):
# 将输入转置成
(num_steps,batch_size)后获取 one-hot 向量表示。
# 将输入转置成
(num_steps,batch_size)后获取one-hot向量表示
X = nd.one_hot(inputs.T, self.vocab_size)
Y, state = self.rnn(X, state)
# 全连接层会首先将
Y 的形状变成(num_steps * batch_size,num_hiddens),
#
它的输出形状为(num_steps * batch_size,vocab_size)。
# 全连接层会首先将
Y的形状变成(num_steps * batch_size,num_hiddens),它的输出
#
形状为(num_steps * batch_size,vocab_size)
output = self.dense(Y.reshape((-1, Y.shape[-1])))
return output, state
...
...
@@ -69,15 +69,15 @@ class RNNModel(nn.Block):
同前一节一样,以下定义了一个预测函数。这里的实现区别在于前向计算和初始化隐藏状态的函数接口。
```
{.python .input n=41}
# 本函数已保存在
d2lzh 包中方便以后使用。
# 本函数已保存在
d2lzh包中方便以后使用
def predict_rnn_gluon(prefix, num_chars, model, vocab_size, ctx, idx_to_char,
char_to_idx):
# 使用
model 的成员函数来初始化隐藏状态。
# 使用
model的成员函数来初始化隐藏状态
state = model.begin_state(batch_size=1, ctx=ctx)
output = [char_to_idx[prefix[0]]]
for t in range(num_chars + len(prefix) - 1):
X = nd.array([output[-1]], ctx=ctx).reshape((1, 1))
(Y, state) = model(X, state) # 前向计算不需要传入模型参数
。
(Y, state) = model(X, state) # 前向计算不需要传入模型参数
if t < len(prefix) - 1:
output.append(char_to_idx[prefix[t + 1]])
else:
...
...
@@ -97,7 +97,7 @@ predict_rnn_gluon('分开', 10, model, vocab_size, ctx, idx_to_char, char_to_idx
接下来实现训练函数。它的算法同上一节一样,但这里只使用了相邻采样来读取数据。
```
{.python .input n=18}
# 本函数已保存在
d2lzh 包中方便以后使用。
# 本函数已保存在
d2lzh包中方便以后使用
def train_and_predict_rnn_gluon(model, num_hiddens, vocab_size, ctx,
corpus_indices, idx_to_char, char_to_idx,
num_epochs, num_steps, lr, clipping_theta,
...
...
@@ -120,10 +120,10 @@ def train_and_predict_rnn_gluon(model, num_hiddens, vocab_size, ctx,
y = Y.T.reshape((-1,))
l = loss(output, y).mean()
l.backward()
# 梯度裁剪
。
# 梯度裁剪
params = [p.data() for p in model.collect_params().values()]
d2l.grad_clipping(params, clipping_theta, ctx)
trainer.step(1) # 因为已经误差取过均值,梯度不用再做平均
。
trainer.step(1) # 因为已经误差取过均值,梯度不用再做平均
l_sum += l.asscalar() * y.size
n += y.size
...
...
chapter_recurrent-neural-networks/rnn-scratch.md
浏览文件 @
f262428c
...
...
@@ -24,7 +24,7 @@ nd.one_hot(nd.array([0, 2]), vocab_size)
我们每次采样的小批量的形状是(批量大小,时间步数)。下面的函数将这样的小批量变换成数个可以输入进网络的形状为(批量大小,词典大小)的矩阵,总数与时间步数相等。也就是说,时间步$t$的输入$
\b
oldsymbol{X}_t
\i
n
\m
athbb{R}^{n
\t
imes d}$,其中$n$为批量大小,$d$为输入个数,即one-hot向量长度(词典大小)。
```
{.python .input n=3}
def to_onehot(X, size): # 本函数已保存在
d2lzh 包中方便以后使用。
def to_onehot(X, size): # 本函数已保存在
d2lzh包中方便以后使用
return [nd.one_hot(x, size) for x in X.T]
X = nd.arange(10).reshape((2, 5))
...
...
@@ -45,14 +45,14 @@ def get_params():
def _one(shape):
return nd.random.normal(scale=0.01, shape=shape, ctx=ctx)
# 隐藏层参数
。
# 隐藏层参数
W_xh = _one((num_inputs, num_hiddens))
W_hh = _one((num_hiddens, num_hiddens))
b_h = nd.zeros(num_hiddens, ctx=ctx)
# 输出层参数
。
# 输出层参数
W_hq = _one((num_hiddens, num_outputs))
b_q = nd.zeros(num_outputs, ctx=ctx)
# 附上梯度
。
# 附上梯度
params = [W_xh, W_hh, b_h, W_hq, b_q]
for param in params:
param.attach_grad()
...
...
@@ -72,7 +72,7 @@ def init_rnn_state(batch_size, num_hiddens, ctx):
```
{.python .input n=6}
def rnn(inputs, state, params):
# inputs
和 outputs 皆为 num_steps 个形状为(batch_size,vocab_size)的矩阵。
# inputs
和outputs皆为num_steps个形状为(batch_size,vocab_size)的矩阵
W_xh, W_hh, b_h, W_hq, b_q = params
H, = state
outputs = []
...
...
@@ -98,17 +98,17 @@ len(outputs), outputs[0].shape, state_new[0].shape
以下函数基于前缀
`prefix`
(含有数个字符的字符串)来预测接下来的
`num_chars`
个字符。这个函数稍显复杂,其中我们将循环神经单元
`rnn`
设置成了函数参数,这样在后面小节介绍其他循环神经网络时能重复使用这个函数。
```
{.python .input n=8}
# 本函数已保存在
d2lzh 包中方便以后使用。
# 本函数已保存在
d2lzh包中方便以后使用
def predict_rnn(prefix, num_chars, rnn, params, init_rnn_state,
num_hiddens, vocab_size, ctx, idx_to_char, char_to_idx):
state = init_rnn_state(1, num_hiddens, ctx)
output = [char_to_idx[prefix[0]]]
for t in range(num_chars + len(prefix) - 1):
# 将上一时间步的输出作为当前时间步的输入
。
# 将上一时间步的输出作为当前时间步的输入
X = to_onehot(nd.array([output[-1]], ctx=ctx), vocab_size)
# 计算输出和更新隐藏状态
。
# 计算输出和更新隐藏状态
(Y, state) = rnn(X, state, params)
# 下一个时间步的输入是
prefix 里的字符或者当前的最佳预测字符。
# 下一个时间步的输入是
prefix里的字符或者当前的最佳预测字符
if t < len(prefix) - 1:
output.append(char_to_idx[prefix[t + 1]])
else:
...
...
@@ -132,7 +132,7 @@ $$ \min\left(\frac{\theta}{\|\boldsymbol{g}\|}, 1\right)\boldsymbol{g}$$
的$L_2$范数不超过$
\t
heta$。
```
{.python .input n=10}
# 本函数已保存在
d2lzh 包中方便以后使用。
# 本函数已保存在
d2lzh包中方便以后使用
def grad_clipping(params, theta, ctx):
norm = nd.array([0], ctx)
for param in params:
...
...
@@ -164,7 +164,7 @@ def grad_clipping(params, theta, ctx):
另外,考虑到后面将介绍的其它循环神经网络,为了更通用,这里的函数实现更长一些。
```
{.python .input n=11}
# 本函数已保存在
d2lzh 包中方便以后使用。
# 本函数已保存在
d2lzh包中方便以后使用
def train_and_predict_rnn(rnn, get_params, init_rnn_state, num_hiddens,
vocab_size, ctx, corpus_indices, idx_to_char,
char_to_idx, is_random_iter, num_epochs, num_steps,
...
...
@@ -178,30 +178,30 @@ def train_and_predict_rnn(rnn, get_params, init_rnn_state, num_hiddens,
loss = gloss.SoftmaxCrossEntropyLoss()
for epoch in range(num_epochs):
if not is_random_iter: # 如使用相邻采样,在
epoch 开始时初始化隐藏状态。
if not is_random_iter: # 如使用相邻采样,在
epoch开始时初始化隐藏状态
state = init_rnn_state(batch_size, num_hiddens, ctx)
l_sum, n, start = 0.0, 0, time.time()
data_iter = data_iter_fn(corpus_indices, batch_size, num_steps, ctx)
for X, Y in data_iter:
if is_random_iter: # 如使用随机采样,在每个小批量更新前初始化隐藏状态
。
if is_random_iter: # 如使用随机采样,在每个小批量更新前初始化隐藏状态
state = init_rnn_state(batch_size, num_hiddens, ctx)
else: # 否则需要使用
detach 函数从计算图分离隐藏状态。
else: # 否则需要使用
detach函数从计算图分离隐藏状态
for s in state:
s.detach()
with autograd.record():
inputs = to_onehot(X, vocab_size)
# outputs
有 num_steps 个形状为(batch_size,vocab_size)的矩阵。
# outputs
有num_steps个形状为(batch_size,vocab_size)的矩阵
(outputs, state) = rnn(inputs, state, params)
# 拼接之后形状为
(num_steps * batch_size,vocab_size)。
# 拼接之后形状为
(num_steps * batch_size,vocab_size)
outputs = nd.concat(*outputs, dim=0)
# Y
的形状是(batch_size,num_steps)
,转置后再变成长度为
# batch * num_steps 的向量,这样跟输出的行一一对应
。
# Y
的形状是(batch_size,num_steps)
,转置后再变成长度为
# batch * num_steps 的向量,这样跟输出的行一一对应
y = Y.T.reshape((-1,))
# 使用交叉熵损失计算平均分类误差
。
# 使用交叉熵损失计算平均分类误差
l = loss(outputs, y).mean()
l.backward()
grad_clipping(params, clipping_theta, ctx) # 裁剪梯度
。
d2l.sgd(params, lr, 1) # 因为误差已经取过均值,梯度不用再做平均
。
grad_clipping(params, clipping_theta, ctx) # 裁剪梯度
d2l.sgd(params, lr, 1) # 因为误差已经取过均值,梯度不用再做平均
l_sum += l.asscalar() * y.size
n += y.size
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录