提交 8536f28c 编写于 作者: A Aston Zhang

revise all

上级 6e5ce7d9
# 使用AWS运行代码
* equential类/实例, HybridSequential类/实例
当本地机器的计算资源有限时,我们可以通过云计算服务获取更强大的计算资源来运行本书中的深度学习代码。本节将介绍如何在AWS(亚马逊的云计算服务)上申请实例并通过Jupyter笔记本运行代码。本节中的例子有如下两个步骤:
......
......@@ -62,7 +62,7 @@
|$\mathbb{P}(\cdot)$|概率分布|
|$\cdot \sim \mathbb{P}$|随机变量$\cdot$的概率分布是$\mathbb{P}$|
|$\mathbb{P}(\cdot \mid \cdot)$|条件概率分布|
|$\mathbb{E}_\cdot(f(\cdot))$|函数$f(\cdot)$对$\cdot$的数学期望|
|$\mathbb{E}_\cdot\left(f(\cdot)\right)$|函数$f(\cdot)$对$\cdot$的数学期望|
## 复杂度
......
......@@ -3,11 +3,11 @@
MXNet使用异步计算来提升计算性能。理解它的工作原理既有助于开发更高效的程序,又有助于在内存资源有限的情况下主动降低计算性能从而减小内存开销。我们先导入本节中实验需要的包或模块。
```{.python .input n=1}
import os
import time
import subprocess
from mxnet import autograd, gluon, nd
from mxnet.gluon import loss as gloss, nn
import os
import subprocess
import time
```
## MXNet中的异步计算
......
......@@ -169,8 +169,8 @@ def train(num_gpus, batch_size, lr):
train_time = time.time() - start
net = lambda x: lenet(x, gpu_params[0]) # 在 GPU 0 上验证模型。
test_acc = gb.evaluate_accuracy(test_iter, net, ctx[0])
print('epoch %d, time: %.1f sec, test acc: %.2f' % (
epoch + 1, train_time, test_acc))
print('epoch %d, time: %.1f sec, test acc: %.2f'
% (epoch + 1, train_time, test_acc))
```
## 多GPU训练训练实验
......
......@@ -29,8 +29,7 @@ gb.plt.imshow(img); # 加分号只显示图。
```{.python .input n=2}
# 注意坐标轴原点是图像的左上角。bbox 是 bounding box 的缩写。
dog_bbox = [60, 45, 378, 516]
cat_bbox = [400, 112, 655, 493]
dog_bbox, cat_bbox = [60, 45, 378, 516], [400, 112, 655, 493]
```
我们可以在图中将边框画出来检查其准确性。画之前我们定义一个辅助函数`bbox_to_rect`。它将边界框表示成matplotlib的边框格式。
......
......@@ -10,7 +10,7 @@ sys.path.insert(0, '..')
%matplotlib inline
import gluonbook as gb
from mxnet import gluon, init, nd, image
from mxnet import gluon, image, init, nd
from mxnet.gluon import data as gdata, loss as gloss, model_zoo, nn
import numpy as np
import sys
......@@ -74,10 +74,9 @@ net(x).shape
```{.python .input n=8}
num_classes = 21
net.add(
nn.Conv2D(num_classes, kernel_size=1),
nn.Conv2DTranspose(num_classes, kernel_size=64, padding=16, strides=32)
)
net.add(nn.Conv2D(num_classes, kernel_size=1),
nn.Conv2DTranspose(num_classes, kernel_size=64, padding=16,
strides=32))
```
## 模型初始化
......@@ -134,9 +133,7 @@ net[-2].initialize(init=init.Xavier())
我们使用较大的输入图像尺寸,其值选成了32的倍数。数据的读取方法已在上一节描述。
```{.python .input n=13}
input_shape = (320, 480)
batch_size = 32
colormap2label = nd.zeros(256**3)
input_shape, batch_size, colormap2label = (320, 480), 32, nd.zeros(256**3)
for i, cm in enumerate(gb.VOC_COLORMAP):
colormap2label[(cm[0] * 256 + cm[1]) * 256 + cm[2]] = i
voc_dir = gb.download_voc_pascal(data_dir='../data')
......
......@@ -34,12 +34,12 @@ import sys
sys.path.insert(0, '..')
%matplotlib inline
import zipfile
import gluonbook as gb
from mxnet import gluon, init, nd
from mxnet.gluon import data as gdata, loss as gloss, model_zoo
from mxnet.gluon import utils as gutils
import os
import zipfile
data_dir = '../data'
base_url = 'https://apache-mxnet.s3-accelerate.amazonaws.com/'
......
......@@ -224,9 +224,7 @@ def train(train_iter, test_iter, net, loss, trainer, ctx, num_epochs):
```{.python .input n=38}
def train_with_data_aug(train_augs, test_augs, lr=0.001):
batch_size = 256
ctx = try_all_gpus()
net = gb.resnet18(10)
batch_size, ctx, net = 256, try_all_gpus(), gb.resnet18(10)
net.initialize(ctx=ctx, init=init.Xavier())
# 这里使用了 Adam 优化算法。
trainer = gluon.Trainer(net.collect_params(), 'adam',
......
......@@ -19,7 +19,7 @@ sys.path.insert(0, '..')
import datetime
import gluonbook as gb
from mxnet import autograd, gluon, init
from mxnet.gluon import data as gdata, nn, loss as gloss
from mxnet.gluon import data as gdata, loss as gloss, nn
import os
import pandas as pd
import shutil
......@@ -110,21 +110,14 @@ def reorg_cifar10_data(data_dir, label_file, train_dir, test_dir, input_dir,
```{.python .input n=3}
if demo:
# 注意:此处使用小训练集。
train_dir = 'train_tiny'
# 注意:此处使用小测试集。
test_dir = 'test_tiny'
# 注意:此处将批量大小相应设小。使用 Kaggle 比赛的完整数据集时可设较大整数。
batch_size = 1
# 注意:此处使用小训练集和小测试集并将批量大小相应设小。
# 使用 Kaggle 比赛的完整数据集时可设批量大小为较大整数。
train_dir, test_dir, batch_size = 'train_tiny', 'test_tiny', 1
else:
train_dir = 'train'
test_dir = 'test'
batch_size = 128
data_dir = '../data/kaggle_cifar10'
label_file = 'trainLabels.csv'
input_dir = 'train_valid_test'
valid_ratio = 0.1
train_dir, test_dir, batch_size = 'train', 'test', 128
data_dir, label_file = '../data/kaggle_cifar10', 'trainLabels.csv'
input_dir, valid_ratio = 'train_valid_test', 0.1
reorg_cifar10_data(data_dir, label_file, train_dir, test_dir, input_dir,
valid_ratio)
```
......@@ -148,15 +141,13 @@ transform_train = gdata.vision.transforms.Compose([
gdata.vision.transforms.ToTensor(),
# 对图像的每个通道做标准化。
gdata.vision.transforms.Normalize([0.4914, 0.4822, 0.4465],
[0.2023, 0.1994, 0.2010])
])
[0.2023, 0.1994, 0.2010])])
# 测试时,无需对图像做标准化以外的增强数据处理。
transform_test = gdata.vision.transforms.Compose([
gdata.vision.transforms.ToTensor(),
gdata.vision.transforms.Normalize([0.4914, 0.4822, 0.4465],
[0.2023, 0.1994, 0.2010])
])
[0.2023, 0.1994, 0.2010])])
```
接下来,我们可以使用`ImageFolderDataset`类来读取整理后的数据集,其中每个数据样本包括图像和标签。需要注意的是,我们要在`DataLoader`中调用刚刚定义好的图像增广函数。其中`transform_first`函数指明对每个数据样本中的图像做数据增广。
......@@ -249,8 +240,7 @@ def train(net, train_data, valid_data, num_epochs, lr, wd, ctx, lr_period,
{'learning_rate': lr, 'momentum': 0.9, 'wd': wd})
prev_time = datetime.datetime.now()
for epoch in range(num_epochs):
train_l = 0.0
train_acc = 0.0
train_l, train_acc = 0.0, 0.0
if epoch > 0 and epoch % lr_period == 0:
trainer.set_learning_rate(trainer.learning_rate * lr_decay)
for X, y in train_data:
......@@ -281,20 +271,11 @@ def train(net, train_data, valid_data, num_epochs, lr, wd, ctx, lr_period,
## 训练并验证模型
现在,我们可以训练并验证模型了。以下的超参数都是可以调节的,例如增加迭代周期。
现在,我们可以训练并验证模型了。以下的超参数都是可以调节的,例如增加迭代周期。由于`lr_period``lr_decay`分别设80和0.1,优化算法的学习率将在每80个迭代周期时自乘0.1。
```{.python .input n=8}
ctx = gb.try_gpu()
num_epochs = 1
# 学习率。
lr = 0.1
# 权重衰减参数。
wd = 5e-4
# 优化算法的学习率将在每 80 个迭代周期时自乘 0.1。
lr_period = 80
lr_decay = 0.1
net = get_net(ctx)
ctx, num_epochs, lr, wd = gb.try_gpu(), 1, 0.1, 5e-4,
lr_period, lr_decay, net = 80, 0.1, get_net(ctx)
net.hybridize()
train(net, train_data, valid_data, num_epochs, lr, wd, ctx, lr_period,
lr_decay)
......
......@@ -113,17 +113,12 @@ def reorg_dog_data(data_dir, label_file, train_dir, test_dir, input_dir,
```{.python .input n=3}
if demo:
# 注意:此处使用小数据集。
input_dir = 'train_valid_test_tiny'
# 注意:此处将批量大小相应设小。使用 Kaggle 比赛的完整数据集时可设较大整数。
batch_size = 1
# 注意:此处使用小数据集并将批量大小相应设小。使用 Kaggle 比赛的完整数据集时可设批量大
# 小为较大整数。
input_dir, batch_size = 'train_valid_test_tiny', 1
else:
label_file = 'labels.csv'
train_dir = 'train'
test_dir = 'test'
input_dir = 'train_valid_test'
batch_size = 128
valid_ratio = 0.1
label_file, train_dir, test_dir = 'labels.csv', 'train', 'test'
input_dir, batch_size, valid_ratio = 'train_valid_test', 128, 0.1
reorg_dog_data(data_dir, label_file, train_dir, test_dir, input_dir,
valid_ratio)
```
......@@ -151,8 +146,7 @@ transform_train = gdata.vision.transforms.Compose([
gdata.vision.transforms.ToTensor(),
# 对图像的每个通道做标准化。
gdata.vision.transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
[0.229, 0.224, 0.225])])
# 测试时,只使用确定性的图像预处理操作。
transform_test = gdata.vision.transforms.Compose([
......@@ -161,8 +155,7 @@ transform_test = gdata.vision.transforms.Compose([
gdata.vision.transforms.CenterCrop(224),
gdata.vision.transforms.ToTensor(),
gdata.vision.transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
[0.229, 0.224, 0.225])])
```
接下来,我们可以使用`ImageFolderDataset`类来读取整理后的数据集,其中每个数据样本包括图像和标签。需要注意的是,我们要在`DataLoader`中调用刚刚定义好的图像增广函数。其中`transform_first`函数指明对每个数据样本中的图像做数据增广。
......@@ -267,20 +260,11 @@ def train(net, train_data, valid_data, num_epochs, lr, wd, ctx, lr_period,
## 训练并验证模型
现在,我们可以训练并验证模型了。以下的超参数都是可以调节的,例如增加迭代周期。
现在,我们可以训练并验证模型了。以下的超参数都是可以调节的,例如增加迭代周期。由于`lr_period``lr_decay`分别设10和0.1,优化算法的学习率将在每10个迭代周期时自乘0.1。
```{.python .input n=9}
ctx = gb.try_gpu()
num_epochs = 1
# 学习率。
lr = 0.01
# 权重衰减参数。
wd = 1e-4
# 优化算法的学习率将在每 10 个迭代周期时自乘 0.1。
lr_period = 10
lr_decay = 0.1
net = get_net(ctx)
ctx, num_epochs, lr, wd = gb.try_gpu(), 1, 0.01, 1e-4
lr_period, lr_decay, net = 10, 0.1, get_net(ctx)
net.hybridize()
train(net, train_data, valid_data, num_epochs, lr, wd, ctx, lr_period,
lr_decay)
......
......@@ -64,8 +64,7 @@ pretrained_net = model_zoo.vision.vgg19(pretrained=True)
我们知道VGG使用了五个卷积块来构建网络,块之间使用最大池化层来做间隔(参考[“使用重复元素的网络(VGG)”](../chapter_convolutional-neural-networks/vgg.md)小节)。原论文中使用每个卷积块的第一个卷积层输出来匹配样式(称之为样式层),和第四块中的最后一个卷积层来匹配内容(称之为内容层)[1]。我们可以打印`pretrained_net`来获取这些层的具体位置。
```{.python .input n=11}
style_layers = [0, 5, 10, 19, 28]
content_layers = [25]
style_layers, content_layers = [0, 5, 10, 19, 28], [25]
```
当然,样式层和内容层有多种选取方法。通常越靠近输入层越容易匹配内容和样式的细节信息,越靠近输出则越倾向于语义的内容和全局的样式。这里我们选取比较靠后的内容层来避免合成图像过于保留内容图像细节,使用多个位置的样式层来匹配局部和全局样式。
......@@ -149,8 +148,7 @@ def tv_loss(y_hat):
```{.python .input n=12}
style_channels = [net[l].weight.shape[0] for l in style_layers]
style_weights = [1e4 / c**2 for c in style_channels]
content_weights = [1]
tv_weight = 10
content_weights, tv_weight = [1], 10
```
## 训练
......@@ -198,9 +196,7 @@ def train(x, content_y, style_y, ctx, lr, max_epochs, lr_decay_epoch):
现在我们可以真正开始训练了。首先我们将图像调整到高为300宽200来进行训练,这样使得训练更加快速。合成图像的初始值设成了内容图像,使得初始值能尽可能接近训练输出来加速收敛。
```{.python .input n=19}
image_shape = (300, 200)
ctx = gb.try_gpu()
ctx, image_shape = gb.try_gpu(), (300, 200)
net.collect_params().reset_ctx(ctx)
content_x, content_y = get_contents(image_shape, ctx)
style_x, style_y = get_styles(image_shape, ctx)
......
......@@ -53,8 +53,7 @@ def load_data_pikachu(batch_size, edge_size=256):
shuffle=False)
return train_iter, val_iter
batch_size = 32
edge_size = 256
batch_size, edge_size = 32, 256
train_iter, _ = load_data_pikachu(batch_size, edge_size)
```
......
......@@ -67,8 +67,7 @@ train_images, train_labels = read_voc_images()
我们画出前面五张图像和它们对应的标注。在标注,白色代表边框黑色代表背景,其他不同的颜色对应不同物体类别。
```{.python .input n=4}
n = 5
imgs = train_images[0:n] + train_labels[0:n]
n, imgs = 5, train_images[0:n] + train_labels[0:n]
gb.show_images(imgs, 2, n);
```
......
......@@ -203,11 +203,10 @@ train_data.reshape(label_shape=(3, 5))
模型和训练器的初始化跟之前类似。
```{.python .input n=16}
ctx = gb.try_gpu()
net = TinySSD(num_classes=2)
ctx, net = gb.try_gpu(), TinySSD(num_classes=2)
net.initialize(init=init.Xavier(), ctx=ctx)
trainer = gluon.Trainer(net.collect_params(),
'sgd', {'learning_rate': 0.1, 'wd': 5e-4})
trainer = gluon.Trainer(net.collect_params(), 'sgd',
{'learning_rate': 0.1, 'wd': 5e-4})
```
### 损失和评估函数
......
......@@ -12,7 +12,7 @@ import collections
import gluonbook as gb
import itertools
import math
from mxnet import autograd, nd, gluon
from mxnet import autograd, gluon, nd
from mxnet.gluon import data as gdata, loss as gloss, nn
import random
import sys
......@@ -93,8 +93,7 @@ subsampled_dataset = [[
```{.python .input n=7}
def get_center_context_arrays(coded_sentences, max_window_size):
centers = []
contexts = []
centers, contexts = [], []
for sentence in coded_sentences:
# 每个句子至少要有 2 个词才可能组成一对“中心词-背景词”。
if len(sentence) < 2:
......
......@@ -47,7 +47,7 @@ $$f(\boldsymbol{v}_i - \boldsymbol{v}_j, \tilde{\boldsymbol{v}}_k) = \frac{p_{ik
由于共现概率比值是一个标量,我们可以使用向量之间的内积把函数$f$的自变量进一步改写,得到
$$f((\boldsymbol{v}_i - \boldsymbol{v}_j)^\top \tilde{\boldsymbol{v}}_k) = \frac{p_{ik}}{p_{jk}}.$$
$$f\left((\boldsymbol{v}_i - \boldsymbol{v}_j)^\top \tilde{\boldsymbol{v}}_k\right) = \frac{p_{ik}}{p_{jk}}.$$
由于任意一对词共现的对称性,我们希望以下两个性质可以同时被满足:
......@@ -56,7 +56,7 @@ $$f((\boldsymbol{v}_i - \boldsymbol{v}_j)^\top \tilde{\boldsymbol{v}}_k) = \frac
为了满足以上两个性质,一方面,我们令
$$f((\boldsymbol{v}_i - \boldsymbol{v}_j)^\top \tilde{\boldsymbol{v}}_k) = \frac{f(\boldsymbol{v}_i^\top \tilde{\boldsymbol{v}}_k)}{f(\boldsymbol{v}_j^\top \tilde{\boldsymbol{v}}_k)},$$
$$f\left((\boldsymbol{v}_i - \boldsymbol{v}_j)^\top \tilde{\boldsymbol{v}}_k\right) = \frac{f(\boldsymbol{v}_i^\top \tilde{\boldsymbol{v}}_k)}{f(\boldsymbol{v}_j^\top \tilde{\boldsymbol{v}}_k)},$$
并得到$f(x) = \text{exp}(x)$。以上两式的右边联立,
......@@ -100,7 +100,7 @@ $$ - \text{log} \mathbb{P} (w_o \mid w_c) = -\text{log} \frac{1}{1+\text{exp}(-\
直接替换成
$$ - \text{log} \mathbb{P} (w_o \mid w_c) = -\text{log} \frac{1}{1+\text{exp}(-\boldsymbol{u}_o^\top \sum_{g \in \mathcal{G}_{w_c}} \boldsymbol{z}_g)} - \sum_{k=1, w_k \sim \mathbb{P}(w)}^K \text{log} \frac{1}{1+\text{exp}(\boldsymbol{u}_{i_k}^\top \sum_{g \in \mathcal{G}_{w_c}} \boldsymbol{z}_g)}. $$
$$ - \text{log} \mathbb{P} (w_o \mid w_c) = -\text{log} \frac{1}{1+\text{exp}\left(-\boldsymbol{u}_o^\top \sum_{g \in \mathcal{G}_{w_c}} \boldsymbol{z}_g\right)} - \sum_{k=1, w_k \sim \mathbb{P}(w)}^K \text{log} \frac{1}{1+\text{exp}\left(\boldsymbol{u}_{i_k}^\top \sum_{g \in \mathcal{G}_{w_c}} \boldsymbol{z}_g\right)}. $$
可以看到,原中心词向量被替换成了中心词的子词向量之和。与word2vec和GloVe不同,词典以外的新词的词向量可以使用fastText中相应的子词向量之和。
......
......@@ -19,28 +19,16 @@ from mxnet.gluon import data as gdata, loss as gloss, nn, rnn
下面定义一些特殊符号。其中“&lt;pad&gt;”(padding)符号使每个序列等长。我们已经在前面几节介绍了,“&lt;bos&gt;”和“&lt;eos&gt;”符号分别表示序列的开始和结束。
```{.python .input}
PAD = '<pad>'
BOS = '<bos>'
EOS = '<eos>'
PAD, BOS, EOS = '<pad>', '<bos>', '<eos>'
```
以下设置了模型超参数。我们在编码器和解码器中分别使用了一层和两层的循环神经网络。实验中,我们选取长度不超过5的输入和输出序列,并将预测时输出序列的最大长度设为20。这些序列长度考虑了句末添加的“&lt;eos&gt;”符号。
```{.python .input}
num_epochs = 40
eval_interval = 10
lr = 0.005
batch_size = 2
max_seq_len = 5
max_test_output_len = 20
encoder_num_layers = 1
decoder_num_layers = 2
encoder_drop_prob = 0.1
decoder_drop_prob = 0.1
encoder_embed_size = 256
encoder_num_hiddens = 256
decoder_num_hiddens = 256
alignment_size = 25
num_epochs, eval_interval, lr, batch_size, max_seq_len = 40, 10, 0.005, 2, 5
max_test_output_len, encoder_num_layers, decoder_num_layers = 20, 1, 2
encoder_drop_prob, decoder_drop_prob, encoder_embed_size = 0.1, 0.1, 256
encoder_num_hiddens, decoder_num_hiddens, alignment_size = 256, 256, 25
ctx = mx.cpu(0)
```
......@@ -50,10 +38,7 @@ ctx = mx.cpu(0)
```{.python .input}
def read_data(max_seq_len):
input_tokens = []
output_tokens = []
input_seqs = []
output_seqs = []
input_tokens, output_tokens, input_seqs, output_seqs = [], [], [], []
with io.open('../data/fr-en-small.txt') as f:
lines = f.readlines()
for line in lines:
......@@ -63,8 +48,7 @@ def read_data(max_seq_len):
if len(cur_input_tokens) < max_seq_len and \
len(cur_output_tokens) < max_seq_len:
input_tokens.extend(cur_input_tokens)
# 句末附上 EOS 符号。
cur_input_tokens.append(EOS)
cur_input_tokens.append(EOS) # 句末附上 EOS 符号。
# 添加 PAD 符号使每个序列等长(长度为 max_seq_len)。
while len(cur_input_tokens) < max_seq_len:
cur_input_tokens.append(PAD)
......@@ -142,8 +126,7 @@ class Decoder(nn.Block):
flatten=False))
self.rnn = rnn.GRU(num_hiddens, num_layers, dropout=drop_prob,
input_size=num_hiddens)
self.out = nn.Dense(num_outputs, in_units=num_hiddens,
flatten=False)
self.out = nn.Dense(num_outputs, in_units=num_hiddens, flatten=False)
self.rnn_concat_input = nn.Dense(
num_hiddens, in_units=num_hiddens + encoder_num_hiddens,
flatten=False)
......@@ -233,8 +216,7 @@ def translate(encoder, decoder, decoder_init_state, fr_ens, ctx, max_seq_len):
下面定义模型训练函数。为了初始化解码器的隐藏状态,我们通过一层全连接网络来变换编码器最早时间步的输出隐藏状态。解码器中,当前时间步的预测词将作为下一时间步的输入。其实,我们也可以使用样本输出序列在当前时间步的词作为下一时间步的输入。这叫作强制教学(teacher forcing)。
```{.python .input}
loss = gloss.SoftmaxCrossEntropyLoss()
eos_id = output_vocab.token_to_idx[EOS]
loss, eos_id = gloss.SoftmaxCrossEntropyLoss(), output_vocab.token_to_idx[EOS]
def train(encoder, decoder, decoder_init_state, max_seq_len, ctx,
eval_fr_ens):
......@@ -324,7 +306,7 @@ train(encoder, decoder, decoder_init_state, max_seq_len, ctx, eval_fr_ens)
设$k$为我们希望评价的$n$个连续词的最大长度,例如$k=4$。设$n$个连续词的精度为$p_n$。它是模型预测序列与样本标签序列匹配$n$个连续词的数量与模型预测序列中$n$个连续词数量之比。举个例子,假设标签序列为$ABCDEF$,预测序列为$ABBCD$。那么$p_1 = 4/5, p_2 = 3/4, p_3 = 1/3, p_4 = 0$。设$len_{\text{label}}$和$len_{\text{pred}}$分别为标签序列和模型预测序列的词数。那么,BLEU的定义为
$$ \exp(\min(0, 1 - \frac{len_{\text{label}}}{len_{\text{pred}}})) \prod_{n=1}^k p_n^{1/2^n}.$$
$$ \exp\left(\min\left(0, 1 - \frac{len_{\text{label}}}{len_{\text{pred}}}\right)\right) \prod_{n=1}^k p_n^{1/2^n}.$$
需要注意的是,匹配较长连续词比匹配较短连续词更难。因此,一方面,匹配较长连续词应被赋予更大权重。而上式中$p_n^{1/2^n}$的指数相当于权重。随着$n$的提高,$n$个连续词的精度的权重随着$1/2^n$的减小而增大。例如$0.5^{1/2} \approx 0.7, 0.5^{1/4} \approx 0.84, 0.5^{1/8} \approx 0.92, 0.5^{1/16} \approx 0.96$。另一方面,模型预测较短序列往往会得到较高的$n$个连续词的精度。因此,上式中连乘项前面的系数是为了惩罚较短的输出。举个例子,当$k=2$时,假设标签序列为$ABCDEF$,而预测序列为$AB$。虽然$p_1 = p_2 = 1$,但惩罚系数$\exp(1-6/2) \approx 0.14$,因此BLEU也接近0.14。当预测序列和标签序列完全一致时,BLEU为1。
......
......@@ -43,8 +43,7 @@ def corr1d(X, K):
让我们重现图10.2中一维互相关运算的结果。
```{.python .input n=11}
X = nd.array([0, 1, 2, 3, 4, 5, 6])
K = nd.array([1, 2])
X, K = nd.array([0, 1, 2, 3, 4, 5, 6]), nd.array([1, 2])
corr1d(X, K)
```
......@@ -198,13 +197,8 @@ class TextCNN(nn.Block):
我们定义3个卷积核,它们的核宽分别为3、4和5,输出通道数均为100。
```{.python .input n=11}
num_outputs = 2
lr = 0.001
num_epochs = 5
batch_size = 64
embed_size = 100
ngram_kernel_sizes = [3, 4, 5]
nums_channels = [100, 100, 100]
num_outputs, lr, num_epochs, batch_size, embed_size = 2, 0.001, 5, 64, 100
ngram_kernel_sizes, nums_channels = [3, 4, 5], [100, 100, 100]
ctx = gb.try_all_gpus()
```
......
......@@ -50,8 +50,7 @@ download_imdb()
```{.python .input n=5}
# 本函数已保存在 gluonbook 包中方便以后使用。
def read_imdb(dir_url, seg='train'):
pos_or_neg = ['pos', 'neg']
data = []
pos_or_neg, data = ['pos', 'neg'], []
for label in pos_or_neg:
files = os.listdir(os.path.join('../data/', dir_url, seg, label))
for file in files:
......@@ -193,16 +192,8 @@ class BiRNN(nn.Block):
由于情感分类的训练数据集并不是很大,为应对过拟合现象,我们将直接使用在更大规模语料上预训练的词向量作为每个词的特征向量。在训练中,我们不再更新这些词向量,即不再迭代模型嵌入层中的参数。
```{.python .input n=11}
num_outputs = 2
lr = 0.8
num_epochs = 5
batch_size = 64
embed_size = 100
num_hiddens = 100
num_layers = 2
bidirectional = True
ctx = gb.try_all_gpus()
num_outputs, lr, num_epochs, batch_size, embed_size = 2, 0.8, 5, 64, 100
num_hiddens, num_layers, bidirectional, ctx = 100, 2, True, gb.try_all_gpus()
net = BiRNN(vocab, embed_size, num_hiddens, num_layers, bidirectional,
num_outputs)
net.initialize(init.Xavier(), ctx=ctx)
......
......@@ -31,10 +31,10 @@ import sys
sys.path.insert(0, '..')
%matplotlib inline
import math
import numpy as np
import gluonbook as gb
import math
from mxnet import nd
import numpy as np
```
接下来我们使用$x=10$作为初始值,设$\eta=0.2$。使用梯度下降对$x$迭代10次,可见最后$x$的值较接近最优解。
......@@ -108,7 +108,7 @@ $$\boldsymbol{x} \leftarrow \boldsymbol{x} - \eta \nabla f(\boldsymbol{x}).$$
下面我们构造一个输入为二维向量$\boldsymbol{x} = [x_1, x_2]^\top$和输出为标量的目标函$f(\boldsymbol{x})=x_1^2+2x_2$。可以知道$\nabla f(\boldsymbol{x}) = [2x_1, 4x_2]^\top$。然后观察梯度下降从初始点$[5,2]$开始对$\boldsymbol{x}$的更新轨迹。首先定义两个辅助函数,第一个使用给定的自变量更新函数来从初始点$[5,2]$开始迭代$\boldsymbol{x}$20次,第二个函数可视化$\boldsymbol{x}$的更新轨迹。
```{.python .input n=10}
def train_2d(trainer): # 本函数将保存在 GluonBook 包中方便以后使用。
def train_2d(trainer): # 本函数将保存在 gluonbook 包中方便以后使用。
x1, x2, s1, s2 = -5, -2, 0, 0 # s1 和 s2 是自变量状态,之后章节会使用。
results = [(x1, x2)]
for i in range(20):
......@@ -117,7 +117,7 @@ def train_2d(trainer): # 本函数将保存在 GluonBook 包中方便以后使
print('epoch %d, x1 %f, x2 %f' % (i + 1, x1, x2))
return results
def show_trace_2d(f, results): # 本函数将保存在 GluonBook 包中方便以后使用。
def show_trace_2d(f, results): # 本函数将保存在 gluonbook 包中方便以后使用。
gb.plt.plot(*zip(*results), '-o', color='#ff7f0e')
x1, x2 = np.meshgrid(np.arange(-5.5, 1.0, 0.1), np.arange(-3.0, 1.0, 0.1))
gb.plt.contour(x1, x2, f(x1, x2), colors='#1f77b4')
......
......@@ -58,8 +58,8 @@ def sgd(params, states, hyperparams):
```{.python .input n=4}
# 本函数已保存在 gluonbook 包中方便以后使用。
def train_ch7(trainer_fn, states, hyperparams, features, labels, batch_size=10,
num_epochs=2):
def train_ch7(trainer_fn, states, hyperparams, features, labels,
batch_size=10, num_epochs=2):
# 初始化模型。
net, loss = gb.linreg, gb.squared_loss
w = nd.random.normal(scale=0.01, shape=(features.shape[1], 1))
......
......@@ -129,15 +129,15 @@ def sgd_momentum(params, states, hyperparams):
我们先将动量超参数`mom`设0.5,这时可以看成是使用最近2个时刻的$2\nabla f_\mathcal{B}(\boldsymbol{x})$的加权平均作为梯度的随机梯度下降,因此我们需要对应调下学习率(从上节的0.5减小到了0.02)。
```{.python .input n=15}
gb.train_ch7(sgd_momentum, init_momentum_states(),
{'lr': 0.02, 'mom': 0.5}, features, labels)
gb.train_ch7(sgd_momentum, init_momentum_states(), {'lr': 0.02, 'mom': 0.5},
features, labels)
```
将动量超参数`mom`增大到了0.9时,这个特殊梯度是最近10个时刻的$10\nabla f_\mathcal{B}(\boldsymbol{x})$的加权平均。因此我们需要进一步调低学习率。
```{.python .input n=8}
gb.train_ch7(sgd_momentum, init_momentum_states(),
{'lr': 0.004, 'mom': 0.9}, features, labels)
gb.train_ch7(sgd_momentum, init_momentum_states(), {'lr': 0.004, 'mom': 0.9},
features, labels)
```
## 使用Gluon的实现
......@@ -145,8 +145,8 @@ gb.train_ch7(sgd_momentum, init_momentum_states(),
在Gluon中,只需要在随机梯度下降的训练器中通过`momentum`来指定动量超参数即可得到动量法。
```{.python .input n=9}
gb.train_gluon_ch7('sgd', {'learning_rate': 0.02, 'momentum': 0.5},
features, labels)
gb.train_gluon_ch7('sgd', {'learning_rate': 0.02, 'momentum': 0.5}, features,
labels)
```
## 小结
......
......@@ -24,8 +24,8 @@ import sys
sys.path.insert(0, '..')
%matplotlib inline
import math
import gluonbook as gb
import math
from mxnet import nd
```
......@@ -70,8 +70,8 @@ def rmsprop(params, states, hyperparams):
```{.python .input n=24}
features, labels = gb.get_data_ch7()
gb.train_ch7(rmsprop, init_rmsprop_states(),
{'lr': 0.01, 'gamma': 0.9}, features, labels)
gb.train_ch7(rmsprop, init_rmsprop_states(), {'lr': 0.01, 'gamma': 0.9},
features, labels)
```
## 使用Gluon的实现
......@@ -79,7 +79,7 @@ gb.train_ch7(rmsprop, init_rmsprop_states(),
使用名称`rmsprop`可以获取Gluon中预实现的RMSProp算法。注意超参数$\gamma$此时通过`gamma1`指定。
```{.python .input n=29}
gb.train_gluon_ch7('rmsprop', {'learning_rate': 0.01, 'gamma1': 0.9},
gb.train_gluon_ch7('rmsprop', {'learning_rate': 0.01, 'gamma1': 0.9},
features, labels)
```
......
......@@ -83,9 +83,7 @@ from mxnet.gluon import rnn
以下部分对模型参数进行初始化。超参数`num_hiddens`定义了隐藏单元的个数。
```{.python .input n=2}
num_inputs = vocab_size
num_hiddens = 256
num_outputs = vocab_size
num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size
ctx = gb.try_gpu()
def get_params():
......@@ -141,14 +139,8 @@ def gru(inputs, state, params):
使用同前一节类似的超参数训练,但我们这里减少了迭代周期数,且训练模型时只采用了相邻采样。
```{.python .input n=5}
num_epochs = 160
num_steps = 35
batch_size = 32
lr = 1e2
clipping_theta = 1e-2
prefixes = ['分开', '不分开']
pred_period = 40
pred_len = 50
num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']
```
设置好超参数后,我们将训练模型并跟据前缀“分开”和“不分开”分别创作长度为50个字符的一段歌词。我们每过30个迭代周期便根据当前训练的模型创作一段歌词。。
......@@ -168,7 +160,6 @@ gb.train_and_predict_rnn(gru, get_params, init_gru_state, num_hiddens,
```{.python .input n=6}
gru_layer = rnn.GRU(num_hiddens)
model = gb.RNNModel(gru_layer, vocab_size)
gb.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,
......
......@@ -90,9 +90,7 @@ from mxnet.gluon import rnn
以下部分对模型参数进行初始化。超参数`num_hiddens`定义了隐藏单元的个数。
```{.python .input n=2}
num_inputs = vocab_size
num_hiddens = 256
num_outputs = vocab_size
num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size
ctx = gb.try_gpu()
def get_params():
......@@ -154,15 +152,8 @@ def lstm(inputs, state, params):
使用同前一样的超参数。
```{.python .input n=5}
get_inputs = gb.to_onehot
num_epochs = 160
num_steps = 35
batch_size = 32
lr = 1e2
clipping_theta = 1e-2
prefixes = ['分开', '不分开']
pred_period = 40
pred_len = 50
num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']
```
开始模型训练。
......@@ -182,7 +173,6 @@ gb.train_and_predict_rnn(lstm, get_params, init_lstm_state, num_hiddens,
```{.python .input n=6}
lstm_layer = rnn.LSTM(num_hiddens)
model = gb.RNNModel(lstm_layer, vocab_size)
gb.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,
......
......@@ -6,11 +6,11 @@
import sys
sys.path.insert(0, '..')
import gluonbook as gb
import math
from mxnet import autograd, gluon, init, nd
from mxnet.gluon import loss as gloss, nn, rnn
import time
import gluonbook as gb
from mxnet import autograd, nd, gluon, init
from mxnet.gluon import rnn, nn, loss as gloss
(corpus_indices, char_to_idx, idx_to_char,
vocab_size) = gb.load_data_jay_lyrics()
......@@ -143,14 +143,8 @@ def train_and_predict_rnn_gluon(model, num_hiddens, vocab_size, ctx,
使用和上一节一样的超参数来训练模型。
```{.python .input n=19}
num_epochs = 200
batch_size = 32
lr = 1e2
clipping_theta = 1e-2
prefixes = ['分开', '不分开']
pred_period = 50
pred_len = 50
num_epochs, batch_size, lr, clipping_theta = 200, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 50, 50, ['分开', '不分开']
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,
......
......@@ -6,11 +6,11 @@
import sys
sys.path.insert(0, '..')
import math
import time
import gluonbook as gb
import math
from mxnet import autograd, nd
from mxnet.gluon import loss as gloss
import time
(corpus_indices, char_to_idx, idx_to_char,
vocab_size) = gb.load_data_jay_lyrics()
......@@ -24,7 +24,7 @@ from mxnet.gluon import loss as gloss
nd.one_hot(nd.array([0, 2]), vocab_size)
```
我们每次采样的小批量的形状是(`batch_size`, `num_steps`)。下面这个函数将其转换成`num_steps`个可以输入进网络的形状为(`batch_size`, `vocab_size`)的矩阵。也就是总时间步$T=$`num_steps`,时间步$t$的输入$\boldsymbol{X_t} \in \mathbb{R}^{n \times d}$,其中$n=$`batch_size`,$d=$`vocab_size`(one-hot向量长度)。
我们每次采样的小批量的形状是(`batch_size`, `num_steps`)。下面这个函数将其转换成`num_steps`个可以输入进网络的形状为(`batch_size`, `vocab_size`)的矩阵。也就是总时间步$T=$`num_steps`,时间步$t$的输入$\boldsymbol{X}_t \in \mathbb{R}^{n \times d}$,其中$n=$`batch_size`,$d=$`vocab_size`(one-hot向量长度)。
```{.python .input n=3}
# 本函数已保存在 gluonbook 包中方便以后使用。
......@@ -41,9 +41,7 @@ len(inputs), inputs[0].shape
接下来,我们初始化模型参数。隐藏单元个数 `num_hiddens`是一个超参数。
```{.python .input n=4}
num_inputs = vocab_size
num_hiddens = 256
num_outputs = vocab_size
num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size
ctx = gb.try_gpu()
print('will use', ctx)
......@@ -198,7 +196,7 @@ def train_and_predict_rnn(rnn, get_params, init_rnn_state, num_hiddens,
inputs = to_onehot(X, vocab_size)
# outputs 有 num_steps 个形状为(batch_size,vocab_size)的矩阵。
(outputs, state) = rnn(inputs, state, params)
# 拼接之后形状为(num_steps * batch_size, vocab_size)。
# 拼接之后形状为(num_steps * batch_sizevocab_size)。
outputs = nd.concat(*outputs, dim=0)
# Y 的形状是(batch_size,num_steps),转置后再变成长
# batch * num_steps 的向量,这样跟输出的行一一对应。
......@@ -225,14 +223,8 @@ def train_and_predict_rnn(rnn, get_params, init_rnn_state, num_hiddens,
现在我们可以训练模型了。首先,设置模型超参数。我们将根据前缀“分开”和“不分开”分别创作长度为50个字符的一段歌词。我们每过50个迭代周期便根据当前训练的模型创作一段歌词。
```{.python .input n=12}
num_epochs = 200
num_steps = 35
batch_size = 32
lr = 1e2
clipping_theta = 1e-2
prefixes = ['分开', '不分开']
pred_period = 50
pred_len = 50
num_epochs, num_steps, batch_size, lr, clipping_theta = 200, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 50, 50, ['分开', '不分开']
```
下面采用随机采样训练模型并创作歌词。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册