From 9a65612e7d0ec4c7e3f0c648fb5373651006df31 Mon Sep 17 00:00:00 2001 From: Aston Zhang Date: Fri, 6 Mar 2020 03:04:47 +0000 Subject: [PATCH] 3e feedback --- .../async-computation.md | 2 +- .../hybridize.md | 2 +- .../multiple-gpus.md | 6 ++--- chapter_computer-vision/anchor.md | 6 ++--- chapter_computer-vision/fcn.md | 2 +- chapter_computer-vision/fine-tuning.md | 6 ++--- .../kaggle-gluon-cifar10.md | 2 +- chapter_computer-vision/kaggle-gluon-dog.md | 4 ++-- chapter_computer-vision/neural-style.md | 4 ++-- .../object-detection-dataset.md | 6 ++--- chapter_computer-vision/ssd.md | 8 +++---- .../alexnet.md | 6 ++--- .../densenet.md | 2 +- .../googlenet.md | 2 +- chapter_convolutional-neural-networks/nin.md | 2 +- .../pooling.md | 2 +- .../resnet.md | 4 ++-- chapter_convolutional-neural-networks/vgg.md | 4 ++-- chapter_deep-learning-basics/backprop.md | 6 ++--- chapter_deep-learning-basics/dropout.md | 2 +- .../kaggle-house-price.md | 22 +++++++++---------- .../linear-regression-gluon.md | 2 +- .../linear-regression-scratch.md | 4 ++-- chapter_deep-learning-basics/mlp-gluon.md | 2 +- chapter_deep-learning-basics/mlp-scratch.md | 4 ++-- .../numerical-stability-and-init.md | 2 +- .../softmax-regression-scratch.md | 6 ++--- .../underfit-overfit.md | 4 ++-- chapter_introduction/deep-learning-intro.md | 2 +- .../fasttext.md | 2 +- chapter_natural-language-processing/glove.md | 2 +- .../machine-translation.md | 2 +- .../sentiment-analysis-cnn.md | 8 +++---- .../sentiment-analysis-rnn.md | 12 +++++----- .../seq2seq.md | 2 +- .../similarity-analogy.md | 2 +- .../word2vec-gluon.md | 6 ++--- .../word2vec.md | 2 +- chapter_optimization/adagrad.md | 2 +- chapter_optimization/gd-sgd.md | 2 +- chapter_optimization/minibatch-sgd.md | 4 ++-- chapter_optimization/momentum.md | 2 +- chapter_optimization/rmsprop.md | 4 ++-- chapter_prerequisite/ndarray.md | 2 +- chapter_recurrent-neural-networks/deep-rnn.md | 8 +++---- .../rnn-scratch.md | 4 ++-- 46 files changed, 96 insertions(+), 96 deletions(-) diff --git a/chapter_computational-performance/async-computation.md b/chapter_computational-performance/async-computation.md index 57c60974c..bb5f470db 100644 --- a/chapter_computational-performance/async-computation.md +++ b/chapter_computational-performance/async-computation.md @@ -117,7 +117,7 @@ with Benchmark('asynchronous.'): ## 异步计算对内存的影响 -为了解释异步计算对内存使用的影响,让我们先回忆一下前面章节的内容。在前面章节中实现的模型训练过程中,我们通常会在每个小批量上评测一下模型,如模型的损失或者精度。细心的读者也许已经发现了,这类评测常用到同步函数,如`asscalar`函数或者`asnumpy`函数。如果去掉这些同步函数,前端会将大量的小批量计算任务在极短的时间内丢给后端,从而可能导致占用更多内存。当我们在每个小批量上都使用同步函数时,前端在每次迭代时仅会将一个小批量的任务丢给后端执行计算,并通常会减小内存占用。 +为了解释异步计算对内存使用的影响,让我们先回忆一下前面章节的内容。在前面章节中实现的模型训练过程中,我们通常会在每个小批量上评测一下模型,如模型的损失或者准确率。细心的读者也许已经发现了,这类评测常用到同步函数,如`asscalar`函数或者`asnumpy`函数。如果去掉这些同步函数,前端会将大量的小批量计算任务在极短的时间内丢给后端,从而可能导致占用更多内存。当我们在每个小批量上都使用同步函数时,前端在每次迭代时仅会将一个小批量的任务丢给后端执行计算,并通常会减小内存占用。 由于深度学习模型通常比较大,而内存资源通常有限,建议大家在训练模型时对每个小批量都使用同步函数,例如,用`asscalar`函数或者`asnumpy`函数评价模型的表现。类似地,在使用模型预测时,为了减小内存的占用,也建议大家对每个小批量预测时都使用同步函数,例如,直接打印出当前小批量的预测结果。 diff --git a/chapter_computational-performance/hybridize.md b/chapter_computational-performance/hybridize.md index ca3881b59..93987034a 100644 --- a/chapter_computational-performance/hybridize.md +++ b/chapter_computational-performance/hybridize.md @@ -164,7 +164,7 @@ class HybridNet(nn.HybridBlock): 在继承`HybridBlock`类时,我们需要在`hybrid_forward`函数中添加额外的输入`F`。我们知道,MXNet既有基于命令式编程的`NDArray`类,又有基于符号式编程的`Symbol`类。由于这两个类的函数基本一致,MXNet会根据输入来决定`F`使用`NDArray`或`Symbol`。 -下面创建了一个`HybridBlock`实例。可以看到在默认情况下`F`使用`NDArray`。而且,我们打印出了输入`x`和使用ReLU激活函数的隐藏层的输出。 +下面创建了一个`HybridBlock`实例。可以看到,在默认情况下`F`使用`NDArray`。而且,我们打印出了输入`x`和使用ReLU激活函数的隐藏层的输出。 ```{.python .input} net = HybridNet() diff --git a/chapter_computational-performance/multiple-gpus.md b/chapter_computational-performance/multiple-gpus.md index 7f21efa22..8d0b5443c 100644 --- a/chapter_computational-performance/multiple-gpus.md +++ b/chapter_computational-performance/multiple-gpus.md @@ -181,7 +181,7 @@ def train(num_gpus, batch_size, lr): train(num_gpus=1, batch_size=256, lr=0.2) ``` -保持批量大小和学习率不变,将使用的GPU数量改为2。可以看到,测试精度的提升同上一个实验中的结果大体相当。因为有额外的通信开销,所以我们并没有看到训练时间的显著降低。因此,我们将在下一节实验计算更加复杂的模型。 +保持批量大小和学习率不变,将使用的GPU数量改为2。可以看到,测试准确率的提升同上一个实验中的结果大体相当。因为有额外的通信开销,所以我们并没有看到训练时间的显著降低。因此,我们将在下一节实验计算更加复杂的模型。 ```{.python .input n=13} train(num_gpus=2, batch_size=256, lr=0.2) @@ -190,11 +190,11 @@ train(num_gpus=2, batch_size=256, lr=0.2) ## 小结 * 可以使用数据并行更充分地利用多块GPU的计算资源,实现多GPU训练模型。 -* 给定超参数的情况下,改变GPU数量时模型的训练精度大体相当。 +* 给定超参数的情况下,改变GPU数量时模型的训练准确率大体相当。 ## 练习 -* 在多GPU训练实验中,使用2块GPU训练并将`batch_size`翻倍至512,训练时间有何变化?如果希望测试精度与单GPU训练中的结果相当,学习率应如何调节? +* 在多GPU训练实验中,使用2块GPU训练并将`batch_size`翻倍至512,训练时间有何变化?如果希望测试准确率与单GPU训练中的结果相当,学习率应如何调节? * 将实验的模型预测部分改为用多GPU预测。 diff --git a/chapter_computer-vision/anchor.md b/chapter_computer-vision/anchor.md index ceb266f09..03531dff3 100644 --- a/chapter_computer-vision/anchor.md +++ b/chapter_computer-vision/anchor.md @@ -1,6 +1,6 @@ # 锚框 -目标检测算法通常会在输入图像中采样大量的区域,然后判断这些区域中是否包含我们感兴趣的目标,并调整区域边缘从而更准确地预测目标的真实边界框(ground-truth bounding box)。不同的模型使用的区域采样方法可能不同。这里我们介绍其中的一种方法:它以每个像素为中心生成多个大小和宽高比(aspect ratio)不同的边界框。这些边界框被称为锚框(anchor box)。我们将在后面基于锚框实践目标检测。 +目标检测算法通常会在输入图像中采样大量的区域,然后判断这些区域中是否包含我们感兴趣的目标,并调整区域边缘从而更准确地预测目标的真实边界框(ground-truth bounding box)。不同的模型使用的区域采样方法可能不同。这里我们介绍其中的一种方法:它以每个像素为中心生成多个大小和宽高比(aspect ratio)不同的边界框。这些边界框被称为锚框(anchor box)。我们将在[“单发多框检测(SSD)”](ssd.md)一节基于锚框实践目标检测。 首先,导入本节需要的包或模块。这里我们新引入了`contrib`包,并修改了NumPy的打印精度。由于`NDArray`的打印实际调用NumPy的打印函数,本节打印出的`NDArray`中的浮点数更简洁一些。 @@ -102,7 +102,7 @@ $$J(\mathcal{A},\mathcal{B}) = \frac{\left|\mathcal{A} \cap \mathcal{B}\right|}{ 假设图像中锚框分别为$A_1, A_2, \ldots, A_{n_a}$,真实边界框分别为$B_1, B_2, \ldots, B_{n_b}$,且$n_a \geq n_b$。定义矩阵$\boldsymbol{X} \in \mathbb{R}^{n_a \times n_b}$,其中第$i$行第$j$列的元素$x_{ij}$为锚框$A_i$与真实边界框$B_j$的交并比。 -首先,我们找出矩阵$\boldsymbol{X}$中最大元素,并将该元素的行索引与列索引分别记为$i_1,j_1$。我们为锚框$A_{i_1}$分配真实边界框$B_{j_1}$。显然,锚框$A_{i_1}$和真实边界框$B_{j_1}$在所有的“锚框—真实边界框”的配对中相似度最高。接下来,将矩阵$\boldsymbol{X}$中第$i_1$行和第$j_1$列上的所有元素丢弃。找出矩阵$\boldsymbol{X}$中剩余的最大元素,并将该元素的行索引与列索引分别记为$i_2,j_2$。我们为锚框$A_{i_2}$分配真实边界框$B_{j_2}$,再将矩阵$\boldsymbol{X}$中第$i_2$行和第$j_2$列上的所有元素丢弃。此时矩阵$\boldsymbol{X}$中已有两行两列的元素被丢弃。 +首先,我们找出矩阵$\boldsymbol{X}$中最大元素,并将该元素的行索引与列索引分别记为$i_1,j_1$。我们为锚框$A_{i_1}$分配真实边界框$B_{j_1}$。显然,锚框$A_{i_1}$和真实边界框$B_{j_1}$在所有的“锚框—真实边界框”的配对中相似度最高。接下来,将矩阵$\boldsymbol{X}$中第$i_1$行和第$j_1$列上的所有元素丢弃。找出矩阵$\boldsymbol{X}$中剩余的最大元素,并将该元素的行索引与列索引分别记为$i_2,j_2$。我们为锚框$A_{i_2}$分配真实边界框$B_{j_2}$,再将矩阵$\boldsymbol{X}$中第$i_2$行和第$j_2$列上的所有元素丢弃。此时矩阵$\boldsymbol{X}$中已有2行2列的元素被丢弃。 依此类推,直到矩阵$\boldsymbol{X}$中所有$n_b$列元素全部被丢弃。这个时候,我们已为$n_b$个锚框各分配了一个真实边界框。 接下来,我们只遍历剩余的$n_a - n_b$个锚框:给定其中的锚框$A_i$,根据矩阵$\boldsymbol{X}$的第$i$行找到与$A_i$交并比最大的真实边界框$B_j$,且只有当该交并比大于预先设定的阈值时,才为锚框$A_i$分配真实边界框$B_j$。 @@ -136,7 +136,7 @@ show_bboxes(fig.axes, ground_truth[:, 1:] * bbox_scale, ['dog', 'cat'], 'k') show_bboxes(fig.axes, anchors * bbox_scale, ['0', '1', '2', '3', '4']); ``` -我们可以通过`contrib.nd`模块中的`MultiBoxTarget`函数来为锚框标注类别和偏移量。该函数将背景类别设为0,并令从零开始的目标类别的整数索引自加1(1为狗,2为猫)。我们通过`expand_dims`函数为锚框和真实边界框添加样本维,并构造形状为(批量大小, 包括背景的类别个数, 锚框数)的任意预测结果。 +我们可以通过`contrib.nd`模块中的`MultiBoxTarget`函数来为锚框标注类别和偏移量。该函数将背景类别设为0,并令从0开始的目标类别的整数索引自加1(1为狗,2为猫)。我们通过`expand_dims`函数为锚框和真实边界框添加样本维,并构造形状为(批量大小, 包括背景的类别个数, 锚框数)的任意预测结果。 ```{.python .input n=7} labels = contrib.nd.MultiBoxTarget(anchors.expand_dims(axis=0), diff --git a/chapter_computer-vision/fcn.md b/chapter_computer-vision/fcn.md index ebc4db437..b3361a5b0 100644 --- a/chapter_computer-vision/fcn.md +++ b/chapter_computer-vision/fcn.md @@ -73,7 +73,7 @@ pretrained_net = model_zoo.vision.resnet18_v2(pretrained=True) pretrained_net.features[-4:], pretrained_net.output ``` -下面我们创建全卷积网络实例`net`。它复制了`pretrained_net`实例成员变量`features`里除去最后两层的所有层以及预训练得到的模型参数。 +下面我们创建全卷积网络实例`net`。它复制了`pretrained_net`实例的成员变量`features`里除去最后两层的所有层以及预训练得到的模型参数。 ```{.python .input n=6} net = nn.HybridSequential() diff --git a/chapter_computer-vision/fine-tuning.md b/chapter_computer-vision/fine-tuning.md index fdb1f6e92..593d18e5a 100644 --- a/chapter_computer-vision/fine-tuning.md +++ b/chapter_computer-vision/fine-tuning.md @@ -1,6 +1,6 @@ # 微调 -在前面的一些章节中,我们介绍了如何在只有6万张图像的Fashion-MNIST训练数据集上训练模型。我们还描述了学术界当下使用最广泛的大规模图像数据集ImageNet,它有超过1,000万的图像和1,000类的物体。然而,我们平常接触到数据集的规模通常在这两者之间。 +在前面的一些章节中,我们介绍了如何在只有6万张图像的Fashion-MNIST训练数据集上训练模型。我们还描述了学术界当下使用最广泛的大规模图像数据集ImageNet,它有超过1,000万的图像和1,000类的物体。然而,我们平常接触到的数据集的规模通常在这两者之间。 假设我们想从图像中识别出不同种类的椅子,然后将购买链接推荐给用户。一种可能的方法是先找出100种常见的椅子,为每种椅子拍摄1,000张不同角度的图像,然后在收集到的图像数据集上训练一个分类模型。这个椅子数据集虽然可能比Fashion-MNIST数据集要庞大,但样本数仍然不及ImageNet数据集中样本数的十分之一。这可能会导致适用于ImageNet数据集的复杂模型在这个椅子数据集上过拟合。同时,因为数据量有限,最终训练得到的模型的精度也可能达不到实用的要求。 @@ -11,7 +11,7 @@ 本节我们介绍迁移学习中的一种常用技术:微调(fine tuning)。如图9.1所示,微调由以下4步构成。 1. 在源数据集(如ImageNet数据集)上预训练一个神经网络模型,即源模型。 -2. 创建一个新的神经网络模型,即目标模型。它复制了源模型上除了输出层外的所有模型设计及其参数。我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样适用于目标数据集。我们还假设源模型的输出层跟源数据集的标签紧密相关,因此在目标模型中不予采用。 +2. 创建一个新的神经网络模型,即目标模型。它复制了源模型上除了输出层外的所有模型设计及其参数。我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样适用于目标数据集。我们还假设源模型的输出层与源数据集的标签紧密相关,因此在目标模型中不予采用。 3. 为目标模型添加一个输出大小为目标数据集类别个数的输出层,并随机初始化该层的模型参数。 4. 在目标数据集(如椅子数据集)上训练目标模型。我们将从头训练输出层,而其余层的参数都是基于源模型的参数微调得到的。 @@ -97,7 +97,7 @@ test_augs = gdata.vision.transforms.Compose([ pretrained_net = model_zoo.vision.resnet18_v2(pretrained=True) ``` -预训练的源模型实例含有两个成员变量,即`features`和`output`。前者包含模型除输出层以外的所有层,后者为模型的输出层。这样划分主要是为了方便微调除输出层以外所有层的模型参数。下面打印源模型的成员变量`output`。作为一个全连接层,它将ResNet最终的全局平均池化层输出变换成ImageNet数据集上1000类的输出。 +预训练的源模型实例含有两个成员变量,即`features`和`output`。前者包含模型除输出层以外的所有层,后者为模型的输出层。这样划分主要是为了方便微调除输出层以外所有层的模型参数。下面打印源模型的成员变量`output`。作为一个全连接层,它将ResNet最终的全局平均池化层输出变换成ImageNet数据集上1,000类的输出。 ```{.python .input n=7} pretrained_net.output diff --git a/chapter_computer-vision/kaggle-gluon-cifar10.md b/chapter_computer-vision/kaggle-gluon-cifar10.md index c77ae631b..be331c931 100644 --- a/chapter_computer-vision/kaggle-gluon-cifar10.md +++ b/chapter_computer-vision/kaggle-gluon-cifar10.md @@ -291,7 +291,7 @@ def train(net, train_iter, valid_iter, num_epochs, lr, wd, ctx, lr_period, print(epoch_s + time_s + ', lr ' + str(trainer.learning_rate)) ``` -## 训练并验证模型 +## 训练模型 现在,我们可以训练并验证模型了。下面的超参数都是可以调节的,如增加迭代周期等。由于`lr_period`和`lr_decay`分别设为80和0.1,优化算法的学习率将在每80个迭代周期后自乘0.1。简单起见,这里仅训练1个迭代周期。 diff --git a/chapter_computer-vision/kaggle-gluon-dog.md b/chapter_computer-vision/kaggle-gluon-dog.md index febc08be3..74a0ad815 100644 --- a/chapter_computer-vision/kaggle-gluon-dog.md +++ b/chapter_computer-vision/kaggle-gluon-dog.md @@ -179,7 +179,7 @@ test_iter = gdata.DataLoader(test_ds.transform_first(transform_test), ## 定义模型 -这个比赛的数据属于ImageNet数据集的子集,因此我们可以使用[“微调”](fine-tuning.md)一节中介绍的思路,选用在ImageNet完整数据集上预训练的模型来抽取图像特征,以作为自定义小规模输出网络的输入。Gluon提供了丰富的预训练模型,这里以预训练的ResNet-34模型为例。由于比赛数据集属于预训练数据集的子集,因此我们直接复用预训练模型在输出层的输入,即抽取的特征。然后,我们可以将原输出层替换成自定义的可训练的小规模输出网络,如两个串联的全连接层。与[“微调”](fine-tuning.md)一节中的实验不同,这里不再训练用于抽取特征的预训练模型:这样既节省了训练时间,又省去了存储其模型参数的梯度的空间。 +这个比赛的数据集属于ImageNet数据集的子集,因此我们可以使用[“微调”](fine-tuning.md)一节中介绍的思路,选用在ImageNet完整数据集上预训练的模型来抽取图像特征,以作为自定义小规模输出网络的输入。Gluon提供了丰富的预训练模型,这里以预训练的ResNet-34模型为例。由于比赛数据集属于预训练数据集的子集,因此我们直接复用预训练模型在输出层的输入,即抽取的特征。然后,我们可以将原输出层替换成自定义的可训练的小规模输出网络,如两个串联的全连接层。与[“微调”](fine-tuning.md)一节中的实验不同,这里不再训练用于抽取特征的预训练模型:这样既节省了训练时间,又省去了存储其模型参数的梯度的空间。 需要注意的是,我们在图像增广中使用了ImageNet数据集上RGB三个通道的均值和标准差做标准化,这和预训练模型所做的标准化是一致的。 @@ -249,7 +249,7 @@ def train(net, train_iter, valid_iter, num_epochs, lr, wd, ctx, lr_period, print(epoch_s + time_s + ', lr ' + str(trainer.learning_rate)) ``` -## 训练并验证模型 +## 训练模型 现在,我们可以训练并验证模型了。以下超参数都是可以调节的,如增加迭代周期等。由于`lr_period`和`lr_decay`分别设为10和0.1,优化算法的学习率将在每10个迭代周期后自乘0.1。 diff --git a/chapter_computer-vision/neural-style.md b/chapter_computer-vision/neural-style.md index 6abf8a748..865a80c8e 100644 --- a/chapter_computer-vision/neural-style.md +++ b/chapter_computer-vision/neural-style.md @@ -2,7 +2,7 @@ 如果你是一位摄影爱好者,也许接触过滤镜。它能改变照片的颜色样式,从而使风景照更加锐利或者令人像更加美白。但一个滤镜通常只能改变照片的某个方面。如果要照片达到理想中的样式,经常需要尝试大量不同的组合,其复杂程度不亚于模型调参。 -在本节中,我们将介绍如何使用卷积神经网络自动将某图像中的样式应用在另一图像之上,即样式迁移(style transfer)[1]。这里我们需要两张输入图像,一张是内容图像,另一张是样式图像,我们将使用神经网络修改内容图像使其在样式上接近样式图像。图9.12中的内容图像为本书作者在西雅图郊区的雷尼尔山国家公园(Mount Rainier National Park)拍摄的风景照,而样式图像则是一副主题为秋天橡树的油画。最终输出的合成图像在保留了内容图像中物体主体形状的情况下应用了样式图像的油画笔触,同时也让整体颜色更加鲜艳。 +在本节中,我们将介绍如何使用卷积神经网络自动将某图像中的样式应用在另一图像之上,即样式迁移(style transfer)[1]。这里我们需要两张输入图像,一张是内容图像,另一张是样式图像,我们将使用神经网络修改内容图像使其在样式上接近样式图像。图9.12中的内容图像为本书作者在西雅图郊区的雷尼尔山国家公园(Mount Rainier National Park)拍摄的风景照,而样式图像则是一幅主题为秋天橡树的油画。最终输出的合成图像在保留了内容图像中物体主体形状的情况下应用了样式图像的油画笔触,同时也让整体颜色更加鲜艳。 ![输入内容图像和样式图像,输出样式迁移后的合成图像](../img/style-transfer.svg) @@ -121,7 +121,7 @@ def content_loss(Y_hat, Y): ### 样式损失 -样式损失也一样通过平方误差函数衡量合成图像与样式图像在样式上的差异。为了表达样式层输出的样式,我们先通过`extract_features`函数计算样式层的输出。假设该输出的样本数为1,通道数为$c$,高和宽分别为$h$和$w$,我们可以把输出变换成$c$行$hw$列的矩阵$\boldsymbol{X}$。矩阵$\boldsymbol{X}$可以看作是由$c$个长度为$hw$的向量$\boldsymbol{x}_1, \ldots, \boldsymbol{x}_c$组成的。其中向量$\boldsymbol{x}_i$代表了通道$i$上的样式特征。这些向量的格拉姆矩阵(Gram matrix)$\boldsymbol{X}\boldsymbol{X}^\top \in \mathbb{R}^{c \times c}$中$i$行$j$列的元素$x_{ij}$即向量$\boldsymbol{x}_i$与$\boldsymbol{x}_j$的内积,它表达了通道$i$和通道$j$上样式特征的相关性。我们用这样的格拉姆矩阵表达样式层输出的样式。需要注意的是,当$hw$的值较大时,格拉姆矩阵中的元素容易出现较大的值。此外,格拉姆矩阵的高和宽皆为通道数$c$。为了让样式损失不受这些值的大小影响,下面定义的`gram`函数将格拉姆矩阵除以了矩阵中元素的个数,即$chw$。 +样式损失也一样通过平方误差函数衡量合成图像与样式图像在样式上的差异。为了表达样式层输出的样式,我们先通过`extract_features`函数计算样式层的输出。假设该输出的样本数为1,通道数为$c$,高和宽分别为$h$和$w$,我们可以把输出变换成$c$行$hw$列的矩阵$\boldsymbol{X}$。矩阵$\boldsymbol{X}$可以看作由$c$个长度为$hw$的向量$\boldsymbol{x}_1, \ldots, \boldsymbol{x}_c$组成的。其中向量$\boldsymbol{x}_i$代表了通道$i$上的样式特征。这些向量的格拉姆矩阵(Gram matrix)$\boldsymbol{X}\boldsymbol{X}^\top \in \mathbb{R}^{c \times c}$中$i$行$j$列的元素$x_{ij}$即向量$\boldsymbol{x}_i$与$\boldsymbol{x}_j$的内积,它表达了通道$i$和通道$j$上样式特征的相关性。我们用这样的格拉姆矩阵表达样式层输出的样式。需要注意的是,当$hw$的值较大时,格拉姆矩阵中的元素容易出现较大的值。此外,格拉姆矩阵的高和宽皆为通道数$c$。为了让样式损失不受这些值的大小影响,下面定义的`gram`函数将格拉姆矩阵除以了矩阵中元素的个数,即$chw$。 ```{.python .input n=11} def gram(X): diff --git a/chapter_computer-vision/object-detection-dataset.md b/chapter_computer-vision/object-detection-dataset.md index 876a34ddc..7affbf868 100644 --- a/chapter_computer-vision/object-detection-dataset.md +++ b/chapter_computer-vision/object-detection-dataset.md @@ -3,9 +3,9 @@ 在目标检测领域并没有类似MNIST或Fashion-MNIST那样的小数据集。为了快速测试模型,我们合成了一个小的数据集。我们首先使用一个开源的皮卡丘3D模型生成了1,000张不同角度和大小的皮卡丘图像。然后我们收集了一系列背景图像,并在每张图的随机位置放置一张随机的皮卡丘图像。我们使用MXNet提供的im2rec工具将图像转换成二进制的RecordIO格式 [1]。该格式既可以降低数据集在磁盘上的存储开销,又能提高读取效率。如果想了解更多的图像读取方法,可以查阅GluonCV工具包的文档 [2]。 -## 下载数据集 +## 获取数据集 -RecordIO格式的皮卡丘数据集可以直接在网上下载。下载数据集的操作定义在`_download_pikachu`函数中。 +RecordIO格式的皮卡丘数据集可以直接在网上下载。获取数据集的操作定义在`_download_pikachu`函数中。 ```{.python .input n=1} %matplotlib inline @@ -70,7 +70,7 @@ for ax, label in zip(axes, batch.label[0][0:10]): ## 小结 * 合成的皮卡丘数据集可用于测试目标检测模型。 -* 目标检测的数据读取跟图像分类的类似。然而,在引入边界框后,标签形状和图像增广(如随机裁剪)发生了变化。 +* 目标检测的数据读取与图像分类的类似。然而,在引入边界框后,标签形状和图像增广(如随机裁剪)发生了变化。 ## 练习 diff --git a/chapter_computer-vision/ssd.md b/chapter_computer-vision/ssd.md index 83d346a11..fbdd15c99 100644 --- a/chapter_computer-vision/ssd.md +++ b/chapter_computer-vision/ssd.md @@ -3,7 +3,7 @@ 我们在前几节分别介绍了边界框、锚框、多尺度目标检测和数据集,下面我们基于这些背景知识来构造一个目标检测模型:单发多框检测(single shot multibox detection,SSD)[1]。它简单、快速,并得到了广泛应用。该模型的一些设计思想和实现细节常适用于其他目标检测模型。 -## 模型 +## 定义模型 图9.4描述了单发多框检测模型的设计。它主要由一个基础网络块和若干个多尺度特征块串联而成。其中基础网络块用来从原始图像中抽取特征,因此一般会选择常用的深度卷积神经网络。单发多框检测论文中选用了在分类层之前截断的VGG [1],现在也常用ResNet替代。我们可以设计基础网络,使它输出的高和宽较大。这样一来,基于该特征图生成的锚框数量较多,可以用来检测尺寸较小的目标。接下来的每个多尺度特征块将上一层提供的特征图的高和宽缩小(如减半),并使特征图中每个单元在输入图像上的感受野变得更广阔。如此一来,图9.4中越靠近顶部的多尺度特征块输出的特征图越小,故而基于特征图生成的锚框也越少,加之特征图中每个单元感受野越大,因此更适合检测尺寸较大的目标。由于单发多框检测基于基础网络块和各个多尺度特征块生成不同数量和不同大小的锚框,并通过预测锚框的类别和偏移量(即预测边界框)检测不同大小的目标,因此单发多框检测是一个多尺度的目标检测模型。 @@ -123,7 +123,7 @@ def get_blk(i): return blk ``` -接下来,我们定义每个模块如何进行前向计算。跟之前介绍的卷积神经网络不同,这里不仅返回卷积计算输出的特征图`Y`,还返回根据`Y`生成的当前尺度的锚框,以及基于`Y`预测的锚框类别和偏移量。 +接下来,我们定义每个模块如何进行前向计算。与之前介绍的卷积神经网络不同,这里不仅返回卷积计算输出的特征图`Y`,还返回根据`Y`生成的当前尺度的锚框,以及基于`Y`预测的锚框类别和偏移量。 ```{.python .input n=11} def blk_forward(X, blk, size, ratio, cls_predictor, bbox_predictor): @@ -263,7 +263,7 @@ for epoch in range(20): epoch + 1, 1 - acc_sum / n, mae_sum / m, time.time() - start)) ``` -## 预测 +## 预测目标 在预测阶段,我们希望能把图像里面所有我们感兴趣的目标检测出来。下面读取测试图像,将其变换尺寸,然后转成卷积层需要的四维格式。 @@ -313,7 +313,7 @@ display(img, output, threshold=0.3) ## 练习 -* 限于篇幅原因,实验中忽略了单发多框检测的一些实现细节。你能从以下几个方面进一步改进模型吗? +* 限于篇幅,实验中忽略了单发多框检测的一些实现细节。你能从以下几个方面进一步改进模型吗? ### 损失函数 diff --git a/chapter_convolutional-neural-networks/alexnet.md b/chapter_convolutional-neural-networks/alexnet.md index aa09b9aab..7446abdd8 100644 --- a/chapter_convolutional-neural-networks/alexnet.md +++ b/chapter_convolutional-neural-networks/alexnet.md @@ -42,7 +42,7 @@ AlexNet与LeNet的设计理念非常相似,但也有显著的区别。 AlexNet第一层中的卷积窗口形状是$11\times11$。因为ImageNet中绝大多数图像的高和宽均比MNIST图像的高和宽大10倍以上,ImageNet图像的物体占用更多的像素,所以需要更大的卷积窗口来捕获物体。第二层中的卷积窗口形状减小到$5\times5$,之后全采用$3\times3$。此外,第一、第二和第五个卷积层之后都使用了窗口形状为$3\times3$、步幅为2的最大池化层。而且,AlexNet使用的卷积通道数也大于LeNet中的卷积通道数数十倍。 -紧接着最后一个卷积层的是两个输出个数为4,096的全连接层。这两个巨大的全连接层带来将近1 GB的模型参数。由于早期显存的限制,最早的AlexNet使用双数据流的设计使一个GPU只需要处理一半模型。幸运的是,显存在过去几年得到了长足的发展,因此通常我们不再需要这样的特别设计了。 +紧接着最后一个卷积层的是两个输出个数为4,096的全连接层。这两个巨大的全连接层带来将近1 GB的模型参数。由于早期显存的限制,最早的AlexNet使用双数据流的设计使一块GPU只需要处理一半模型。幸运的是,显存在过去几年得到了长足的发展,因此通常我们不再需要这样的特别设计了。 第二,AlexNet将sigmoid激活函数改成了更加简单的ReLU激活函数。一方面,ReLU激活函数的计算更简单,例如它并没有sigmoid激活函数中的求幂运算。另一方面,ReLU激活函数在不同的参数初始化方法下使模型更容易训练。这是由于当sigmoid激活函数输出极接近0或1时,这些区域的梯度几乎为0,从而造成反向传播无法继续更新部分模型参数;而ReLU激活函数在正区间的梯度恒为1。因此,若模型参数初始化不当,sigmoid函数可能在正区间得到几乎为0的梯度,从而令模型无法得到有效训练。 @@ -90,7 +90,7 @@ for layer in net: print(layer.name, 'output shape:\t', X.shape) ``` -## 读取数据 +## 读取数据集 虽然论文中AlexNet使用ImageNet数据集,但因为ImageNet数据集训练时间较长,我们仍用前面的Fashion-MNIST数据集来演示AlexNet。读取数据的时候我们额外做了一步将图像高和宽扩大到AlexNet使用的图像高和宽224。这个可以通过`Resize`实例来实现。也就是说,我们在`ToTensor`实例前使用`Resize`实例,然后使用`Compose`实例来将这两个变换串联以方便调用。 @@ -133,7 +133,7 @@ d2l.train_ch5(net, train_iter, test_iter, batch_size, trainer, ctx, num_epochs) ## 小结 -* AlexNet跟LeNet结构类似,但使用了更多的卷积层和更大的参数空间来拟合大规模数据集ImageNet。它是浅层神经网络和深度神经网络的分界线。 +* AlexNet与LeNet结构类似,但使用了更多的卷积层和更大的参数空间来拟合大规模数据集ImageNet。它是浅层神经网络和深度神经网络的分界线。 * 虽然看上去AlexNet的实现比LeNet的实现也就多了几行代码而已,但这个观念上的转变和真正优秀实验结果的产生令学术界付出了很多年。 ## 练习 diff --git a/chapter_convolutional-neural-networks/densenet.md b/chapter_convolutional-neural-networks/densenet.md index 0bc071e71..419ec639d 100644 --- a/chapter_convolutional-neural-networks/densenet.md +++ b/chapter_convolutional-neural-networks/densenet.md @@ -109,7 +109,7 @@ net.add(nn.BatchNorm(), nn.Activation('relu'), nn.GlobalAvgPool2D(), nn.Dense(10)) ``` -## 获取数据并训练模型 +## 训练模型 由于这里使用了比较深的网络,本节里我们将输入高和宽从224降到96来简化计算。 diff --git a/chapter_convolutional-neural-networks/googlenet.md b/chapter_convolutional-neural-networks/googlenet.md index e07c2cef9..3c4e9de9e 100644 --- a/chapter_convolutional-neural-networks/googlenet.md +++ b/chapter_convolutional-neural-networks/googlenet.md @@ -106,7 +106,7 @@ for layer in net: print(layer.name, 'output shape:\t', X.shape) ``` -## 获取数据和训练模型 +## 训练模型 我们使用高和宽均为96像素的图像来训练GoogLeNet模型。训练使用的图像依然来自Fashion-MNIST数据集。 diff --git a/chapter_convolutional-neural-networks/nin.md b/chapter_convolutional-neural-networks/nin.md index 33efe828a..e3345bd1d 100644 --- a/chapter_convolutional-neural-networks/nin.md +++ b/chapter_convolutional-neural-networks/nin.md @@ -57,7 +57,7 @@ for layer in net: print(layer.name, 'output shape:\t', X.shape) ``` -## 获取数据和训练模型 +## 训练模型 我们依然使用Fashion-MNIST数据集来训练模型。NiN的训练与AlexNet和VGG的类似,但这里使用的学习率更大。 diff --git a/chapter_convolutional-neural-networks/pooling.md b/chapter_convolutional-neural-networks/pooling.md index 1d0b16e3a..0bfb33264 100644 --- a/chapter_convolutional-neural-networks/pooling.md +++ b/chapter_convolutional-neural-networks/pooling.md @@ -106,7 +106,7 @@ pool2d(X) * 最大池化和平均池化分别取池化窗口中输入元素的最大值和平均值作为输出。 * 池化层的一个主要作用是缓解卷积层对位置的过度敏感性。 * 可以指定池化层的填充和步幅。 -* 池化层的输出通道数跟输入通道数相同。 +* 池化层的输出通道数与输入通道数相同。 ## 练习 diff --git a/chapter_convolutional-neural-networks/resnet.md b/chapter_convolutional-neural-networks/resnet.md index dc77586ce..2e06c4642 100644 --- a/chapter_convolutional-neural-networks/resnet.md +++ b/chapter_convolutional-neural-networks/resnet.md @@ -83,7 +83,7 @@ def resnet_block(num_channels, num_residuals, first_block=False): return blk ``` -接着我们为ResNet加入所有残差块。这里每个模块使用两个残差块。 +接着我们为ResNet加入所有残差块。这里每个模块使用2个残差块。 ```{.python .input n=5} net.add(resnet_block(64, 2, first_block=True), @@ -110,7 +110,7 @@ for layer in net: print(layer.name, 'output shape:\t', X.shape) ``` -## 获取数据和训练模型 +## 训练模型 下面我们在Fashion-MNIST数据集上训练ResNet。 diff --git a/chapter_convolutional-neural-networks/vgg.md b/chapter_convolutional-neural-networks/vgg.md index 7542f0716..12f977922 100644 --- a/chapter_convolutional-neural-networks/vgg.md +++ b/chapter_convolutional-neural-networks/vgg.md @@ -24,7 +24,7 @@ def vgg_block(num_convs, num_channels): ## VGG网络 -与AlexNet和LeNet一样,VGG网络由卷积层模块后接全连接层模块构成。卷积层模块串联数个`vgg_block`,其超参数由变量`conv_arch`定义。该变量指定了每个VGG块里卷积层个数和输出通道数。全连接模块则跟AlexNet中的一样。 +与AlexNet和LeNet一样,VGG网络由卷积层模块后接全连接层模块构成。卷积层模块串联数个`vgg_block`,其超参数由变量`conv_arch`定义。该变量指定了每个VGG块里卷积层个数和输出通道数。全连接模块则与AlexNet中的一样。 现在我们构造一个VGG网络。它有5个卷积块,前2块使用单卷积层,而后3块使用双卷积层。第一块的输出通道是64,之后每次对输出通道数翻倍,直到变为512。因为这个网络使用了8个卷积层和3个全连接层,所以经常被称为VGG-11。 @@ -61,7 +61,7 @@ for blk in net: 可以看到,每次我们将输入的高和宽减半,直到最终高和宽变成7后传入全连接层。与此同时,输出通道数每次翻倍,直到变成512。因为每个卷积层的窗口大小一样,所以每层的模型参数尺寸和计算复杂度与输入高、输入宽、输入通道数和输出通道数的乘积成正比。VGG这种高和宽减半以及通道翻倍的设计使多数卷积层都有相同的模型参数尺寸和计算复杂度。 -## 获取数据和训练模型 +## 训练模型 因为VGG-11计算上比AlexNet更加复杂,出于测试的目的我们构造一个通道数更小,或者说更窄的网络在Fashion-MNIST数据集上进行训练。 diff --git a/chapter_deep-learning-basics/backprop.md b/chapter_deep-learning-basics/backprop.md index ef3c9a007..4f3322f1c 100644 --- a/chapter_deep-learning-basics/backprop.md +++ b/chapter_deep-learning-basics/backprop.md @@ -1,6 +1,6 @@ # 正向传播、反向传播和计算图 -前面几节里我们使用了小批量随机梯度下降的优化算法来训练模型。在实现中,我们只提供了模型的正向传播的计算,即对输入计算模型输出,然后通过`autograd`模块来调用系统自动生成的`backward`函数计算梯度。基于反向传播算法的自动求梯度极大简化了深度学习模型训练算法的实现。本节我们将使用数学和计算图两个方式来描述正向传播和反向传播。具体来说,我们将以带$L_2$范数正则化的含单隐藏层的多层感知机为样例模型解释正向传播和反向传播。 +前面几节里我们使用了小批量随机梯度下降的优化算法来训练模型。在实现中,我们只提供了模型的正向传播的计算,即对输入计算模型输出,然后通过`autograd`模块来调用系统自动生成的`backward`函数计算梯度。基于反向传播算法的自动求梯度极大简化了深度学习模型训练算法的实现。本节我们将使用数学来描述正向传播和反向传播。具体来说,我们将以带$L_2$范数正则化的含单隐藏层的多层感知机为样例模型解释正向传播和反向传播。 ## 正向传播 @@ -106,13 +106,13 @@ $$ 另一方面,反向传播的梯度计算可能依赖于各变量的当前值,而这些变量的当前值是通过正向传播计算得到的。举例来说,参数梯度$\partial J/\partial \boldsymbol{W}^{(2)} = (\partial J / \partial \boldsymbol{o}) \boldsymbol{h}^\top + \lambda \boldsymbol{W}^{(2)}$的计算需要依赖隐藏层变量的当前值$\boldsymbol{h}$。这个当前值是通过从输入层到输出层的正向传播计算并存储得到的。 -因此,在模型参数初始化完成后,我们交替地进行正向传播和反向传播,并根据反向传播计算的梯度迭代模型参数。既然我们在反向传播中使用了正向传播中计算得到的中间变量来避免重复计算,那么这个复用也导致正向传播结束后不能立即释放中间变量内存。这也是训练要比预测占用更多内存的一个重要原因。另外需要指出的是,这些中间变量的个数大体上与网络层数线性相关,每个变量的大小跟批量大小和输入个数也是线性相关的,它们是导致较深的神经网络使用较大批量训练时更容易超内存的主要原因。 +因此,在模型参数初始化完成后,我们交替地进行正向传播和反向传播,并根据反向传播计算的梯度迭代模型参数。既然我们在反向传播中使用了正向传播中计算得到的中间变量来避免重复计算,那么这个复用也导致正向传播结束后不能立即释放中间变量内存。这也是训练要比预测占用更多内存的一个重要原因。另外需要指出的是,这些中间变量的个数大体上与网络层数线性相关,每个变量的大小与批量大小和输入个数也是线性相关的,它们是导致较深的神经网络使用较大批量训练时更容易超内存的主要原因。 ## 小结 * 正向传播沿着从输入层到输出层的顺序,依次计算并存储神经网络的中间变量。 -* 反向传播沿着从输出层到输入层的顺序,依次计算并存储神经网络中间变量和参数的梯度。 +* 反向传播沿着从输出层到输入层的顺序,依次计算并存储神经网络的中间变量和参数的梯度。 * 在训练深度学习模型时,正向传播和反向传播相互依赖。 diff --git a/chapter_deep-learning-basics/dropout.md b/chapter_deep-learning-basics/dropout.md index 3721d5b53..6c6993621 100644 --- a/chapter_deep-learning-basics/dropout.md +++ b/chapter_deep-learning-basics/dropout.md @@ -17,7 +17,7 @@ $$h_i' = \frac{\xi_i}{1-p} h_i.$$ $$E(h_i') = \frac{E(\xi_i)}{1-p}h_i = h_i.$$ -即丢弃法不改变其输入的期望值。让我们对图3.3中的隐藏层使用丢弃法,一种可能的结果如图3.5所示,其中$h_2$和$h_5$被清零。这时输出值的计算不再依赖$h_2$和$h_5$,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。由于在训练中隐藏层神经元的丢弃是随机的,即$h_1, \ldots, h_5$都有可能被清零,输出层的计算无法过度依赖$h_1, \ldots, h_5$中的任一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。在测试模型时,我们为了拿到更加确定性的结果,一般不使用丢弃法。 +即丢弃法不改变其输入的期望值。让我们对图3.3中的隐藏层使用丢弃法,一种可能的结果如图3.5所示,其中$h_2$和$h_5$被清零。这时输出值的计算不再依赖$h_2$和$h_5$,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。由于在训练中隐藏层神经元的丢弃是随机的,即$h_1, \ldots, h_5$都有可能被清零,输出层的计算无法过度依赖$h_1, \ldots, h_5$中的任一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。在测试模型时,我们为了得到更加确定性的结果,一般不使用丢弃法。 ![隐藏层使用了丢弃法的多层感知机](../img/dropout.svg) diff --git a/chapter_deep-learning-basics/kaggle-house-price.md b/chapter_deep-learning-basics/kaggle-house-price.md index 76f706c87..7ca7235cb 100644 --- a/chapter_deep-learning-basics/kaggle-house-price.md +++ b/chapter_deep-learning-basics/kaggle-house-price.md @@ -15,11 +15,11 @@ ![房价预测比赛的网页信息。比赛数据集可通过点击“Data”标签获取](../img/house_pricing.png) -## 获取和读取数据集 +## 读取数据集 比赛数据分为训练数据集和测试数据集。两个数据集都包括每栋房子的特征,如街道类型、建造年份、房顶类型、地下室状况等特征值。这些特征值有连续的数字、离散的标签甚至是缺失值“na”。只有训练数据集包括了每栋房子的价格,也就是标签。我们可以访问比赛网页,点击图3.8中的“Data”标签,并下载这些数据集。 -我们将通过`pandas`库读入并处理数据。在导入本节需要的包前请确保已安装`pandas`库,否则请参考下面的代码注释。 +我们将通过`pandas`库读取并处理数据。在导入本节需要的包前请确保已安装`pandas`库,否则请参考下面的代码注释。 ```{.python .input n=3} # 如果没有安装pandas,则反注释下面一行 @@ -40,13 +40,13 @@ train_data = pd.read_csv('../data/kaggle_house_pred_train.csv') test_data = pd.read_csv('../data/kaggle_house_pred_test.csv') ``` -训练数据集包括1460个样本、80个特征和1个标签。 +训练数据集包括1,460个样本、80个特征和1个标签。 ```{.python .input n=11} train_data.shape ``` -测试数据集包括1459个样本和80个特征。我们需要将测试数据集中每个样本的标签预测出来。 +测试数据集包括1,459个样本和80个特征。我们需要将测试数据集中每个样本的标签预测出来。 ```{.python .input n=5} test_data.shape @@ -64,7 +64,7 @@ train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]] all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:])) ``` -## 预处理数据 +## 预处理数据集 我们对连续数值的特征做标准化(standardization):设该特征在整个数据集上的均值为$\mu$,标准差为$\sigma$。那么,我们可以将该特征的每个值先减去$\mu$再除以$\sigma$得到标准化后的每个特征值。对于缺失的特征值,我们将其替换成该特征的均值。 @@ -123,7 +123,7 @@ def log_rmse(net, features, labels): return rmse.asscalar() ``` -下面的训练函数跟本章中前几节的不同在于使用了Adam优化算法。相对之前使用的小批量随机梯度下降,它对学习率相对不那么敏感。我们将在之后的“优化算法”一章里详细介绍它。 +下面的训练函数与本章中前几节的不同在于使用了Adam优化算法。相对之前使用的小批量随机梯度下降,它对学习率相对不那么敏感。我们将在之后的“优化算法”一章里详细介绍它。 ```{.python .input n=14} def train(net, train_features, train_labels, test_features, test_labels, @@ -146,7 +146,7 @@ def train(net, train_features, train_labels, test_features, test_labels, return train_ls, test_ls ``` -## $K$折交叉验证 +## $k$折交叉验证 我们在[“模型选择、欠拟合和过拟合”](underfit-overfit.md)一节中介绍了$K$折交叉验证。它将被用来选择模型设计并调节超参数。下面实现了一个函数,它返回第`i`折交叉验证时所需要的训练和验证数据。 @@ -168,7 +168,7 @@ def get_k_fold_data(k, i, X, y): return X_train, y_train, X_valid, y_valid ``` -在$K$折交叉验证中我们训练$K$次并返回训练和验证的平均误差。 +在$k$折交叉验证中我们训练$k$次并返回训练和验证的平均误差。 ```{.python .input n=15} def k_fold(k, X_train, y_train, num_epochs, @@ -202,7 +202,7 @@ print('%d-fold validation: avg train rmse %f, avg valid rmse %f' % (k, train_l, valid_l)) ``` -有时候你会发现一组参数的训练误差可以达到很低,但是在$K$折交叉验证上的误差可能反而较高。这种现象很可能是由过拟合造成的。因此,当训练误差降低时,我们要观察$K$折交叉验证上的误差是否也相应降低。 +有时候你会发现一组参数的训练误差可以达到很低,但是在$k$折交叉验证上的误差可能反而较高。这种现象很可能是由过拟合造成的。因此,当训练误差降低时,我们要观察$k$折交叉验证上的误差是否也相应降低。 ## 预测并在Kaggle提交结果 @@ -237,13 +237,13 @@ train_and_pred(train_features, test_features, train_labels, test_data, ## 小结 * 通常需要对真实数据做预处理。 -* 可以使用$K$折交叉验证来选择模型并调节超参数。 +* 可以使用$k$折交叉验证来选择模型并调节超参数。 ## 练习 * 在Kaggle提交本节的预测结果。观察一下,这个结果在Kaggle上能拿到什么样的分数? -* 对照$K$折交叉验证结果,不断修改模型(例如添加隐藏层)和调参,能提高Kaggle上的分数吗? +* 对照$k$折交叉验证结果,不断修改模型(例如添加隐藏层)和调参,能提高Kaggle上的分数吗? * 如果不使用本节中对连续数值特征的标准化处理,结果会有什么变化? * 扫码直达讨论区,在社区交流方法和结果。你能发掘出其他更好的技巧吗? diff --git a/chapter_deep-learning-basics/linear-regression-gluon.md b/chapter_deep-learning-basics/linear-regression-gluon.md index 3189d89cd..66e082372 100644 --- a/chapter_deep-learning-basics/linear-regression-gluon.md +++ b/chapter_deep-learning-basics/linear-regression-gluon.md @@ -18,7 +18,7 @@ labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b labels += nd.random.normal(scale=0.01, shape=labels.shape) ``` -## 读取数据 +## 读取数据集 Gluon提供了`data`包来读取数据。由于`data`常用作变量名,我们将导入的`data`模块用添加了Gluon首字母的假名`gdata`代替。在每一次迭代中,我们将随机读取包含10个数据样本的小批量。 diff --git a/chapter_deep-learning-basics/linear-regression-scratch.md b/chapter_deep-learning-basics/linear-regression-scratch.md index 7a98c336a..acd45716e 100644 --- a/chapter_deep-learning-basics/linear-regression-scratch.md +++ b/chapter_deep-learning-basics/linear-regression-scratch.md @@ -55,7 +55,7 @@ plt.scatter(features[:, 1].asnumpy(), labels.asnumpy(), 1); # 加分号只显 我们将上面的`plt`作图函数以及`use_svg_display`函数和`set_figsize`函数定义在`d2lzh`包里。以后在作图时,我们将直接调用`d2lzh.plt`。由于`plt`在`d2lzh`包中是一个全局变量,我们在作图前只需要调用`d2lzh.set_figsize()`即可打印矢量图并设置图的尺寸。 -## 读取数据 +## 读取数据集 在训练模型的时候,我们需要遍历数据集并不断读取小批量数据样本。这里我们定义一个函数:它每次返回`batch_size`(批量大小)个随机样本的特征和标签。 @@ -128,7 +128,7 @@ def sgd(params, lr, batch_size): # 本函数已保存在d2lzh包中方便以后 在训练中,我们将多次迭代模型参数。在每次迭代中,我们根据当前读取的小批量数据样本(特征`X`和标签`y`),通过调用反向函数`backward`计算小批量随机梯度,并调用优化算法`sgd`迭代模型参数。由于我们之前设批量大小`batch_size`为10,每个小批量的损失`l`的形状为(10, 1)。回忆一下[“自动求梯度”](../chapter_prerequisite/autograd.md)一节。由于变量`l`并不是一个标量,运行`l.backward()`将对`l`中元素求和得到新的变量,再求该变量有关模型参数的梯度。 -在一个迭代周期(epoch)中,我们将完整遍历一遍`data_iter`函数,并对训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。这里的迭代周期个数`num_epochs`和学习率`lr`都是超参数,分别设3和0.03。在实践中,大多超参数都需要通过反复试错来不断调节。虽然迭代周期数设得越大模型可能越有效,但是训练时间可能过长。而有关学习率对模型的影响,我们会在后面“优化算法”一章中详细介绍。 +在一个迭代周期(epoch)中,我们将完整遍历一遍`data_iter`函数,并对训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。这里的迭代周期个数`num_epochs`和学习率`lr`都是超参数,分别设3和0.03。在实践中,大多超参数都需要通过反复试错来不断调节。虽然迭代周期数设得越大模型可能越有效,但是训练时间可能过长。我们会在后面“优化算法”一章中详细介绍学习率对模型的影响。 ```{.python .input n=12} lr = 0.03 diff --git a/chapter_deep-learning-basics/mlp-gluon.md b/chapter_deep-learning-basics/mlp-gluon.md index 8d6ff8ecf..66d05197f 100644 --- a/chapter_deep-learning-basics/mlp-gluon.md +++ b/chapter_deep-learning-basics/mlp-gluon.md @@ -19,7 +19,7 @@ net.add(nn.Dense(256, activation='relu'), net.initialize(init.Normal(sigma=0.01)) ``` -## 读取数据并训练模型 +## 训练模型 我们使用与[“softmax回归的简洁实现”](softmax-regression-gluon.md)一节中训练softmax回归几乎相同的步骤来读取数据并训练模型。 diff --git a/chapter_deep-learning-basics/mlp-scratch.md b/chapter_deep-learning-basics/mlp-scratch.md index ec0f54eed..05c34573c 100644 --- a/chapter_deep-learning-basics/mlp-scratch.md +++ b/chapter_deep-learning-basics/mlp-scratch.md @@ -9,7 +9,7 @@ from mxnet import nd from mxnet.gluon import loss as gloss ``` -## 获取和读取数据 +## 读取数据集 这里继续使用Fashion-MNIST数据集。我们将使用多层感知机对图像进行分类。 @@ -37,7 +37,7 @@ for param in params: ## 定义激活函数 -这里我们使用基础的`maximum`函数来实现ReLU,而非直接调用`relu`函数。 +这里我们使用基础的`maximum`函数来实现ReLU,而非直接调用MXNet的`relu`函数。 ```{.python .input n=4} def relu(X): diff --git a/chapter_deep-learning-basics/numerical-stability-and-init.md b/chapter_deep-learning-basics/numerical-stability-and-init.md index 5b0c897ed..34823fa8d 100644 --- a/chapter_deep-learning-basics/numerical-stability-and-init.md +++ b/chapter_deep-learning-basics/numerical-stability-and-init.md @@ -14,7 +14,7 @@ 在神经网络中,通常需要随机初始化模型参数。下面我们来解释这样做的原因。 -回顾[“多层感知机”](mlp.md)一节图3.3描述的多层感知机。为了方便解释,假设输出层只保留一个输出单元$o_1$(删去$o_2$和$o_3$以及指向它们的箭头),且隐藏层使用相同的激活函数。如果将每个隐藏单元的参数都初始化为相等的值,那么在正向传播时每个隐藏单元将根据相同的输入计算出相同的值,并传递至输出层。在反向传播中,每个隐藏单元的参数梯度值相等。因此,这些参数在使用基于梯度的优化算法迭代后值依然相等。之后的迭代也是如此。在这种情况下,无论隐藏单元有多少,隐藏层本质上只有1个隐藏单元在发挥作用。因此,正如在前面的实验中所做的那样,我们通常将神经网络的模型参数,特别是权重参数,进行随机初始化。 +回顾[“多层感知机”](mlp.md)一节图3.3描述的多层感知机。为了方便解释,假设输出层只保留一个输出单元$o_1$(删去$o_2$和$o_3$以及指向它们的箭头),且隐藏层使用相同的激活函数。如果将每个隐藏单元的参数都初始化为相等的值,那么在正向传播时每个隐藏单元将根据相同的输入计算出相同的值,并传递至输出层。在反向传播中,每个隐藏单元的参数梯度值相等。因此,这些参数在使用基于梯度的优化算法迭代后值依然相等。之后的迭代也是如此。在这种情况下,无论隐藏单元有多少,隐藏层本质上只有1个隐藏单元在发挥作用。因此,正如在前面的实验中所做的那样,我们通常对神经网络的模型参数,特别是权重参数,进行随机初始化。 ### MXNet的默认随机初始化 diff --git a/chapter_deep-learning-basics/softmax-regression-scratch.md b/chapter_deep-learning-basics/softmax-regression-scratch.md index 4e392a6b1..429f743ea 100644 --- a/chapter_deep-learning-basics/softmax-regression-scratch.md +++ b/chapter_deep-learning-basics/softmax-regression-scratch.md @@ -8,7 +8,7 @@ import d2lzh as d2l from mxnet import autograd, nd ``` -## 获取和读取数据 +## 读取数据集 我们将使用Fashion-MNIST数据集,并设置批量大小为256。 @@ -92,7 +92,7 @@ def cross_entropy(y_hat, y): 给定一个类别的预测概率分布`y_hat`,我们把预测概率最大的类别作为输出类别。如果它与真实类别`y`一致,说明这次预测是正确的。分类准确率即正确预测数量与总预测数量之比。 -为了演示准确率的计算,下面定义准确率`accuracy`函数。其中`y_hat.argmax(axis=1)`返回矩阵`y_hat`每行中最大元素的索引,且返回结果与变量`y`形状相同。我们在[“数据操作”](../chapter_prerequisite/ndarray.md)一节介绍过,相等条件判断式`(y_hat.argmax(axis=1) == y)`是一个值为0(相等为假)或1(相等为真)的`NDArray`。由于标签类型为整数,我们先将变量`y`变换为浮点数再进行相等条件判断。 +为了演示准确率的计算,下面定义准确率`accuracy`函数。其中`y_hat.argmax(axis=1)`返回矩阵`y_hat`每行中最大元素的索引,且返回结果与变量`y`形状相同。我们在[“数据操作”](../chapter_prerequisite/ndarray.md)一节介绍过,相等条件判别式`(y_hat.argmax(axis=1) == y)`是一个值为0(相等为假)或1(相等为真)的`NDArray`。由于标签类型为整数,我们先将变量`y`变换为浮点数再进行相等条件判断。 ```{.python .input n=11} def accuracy(y_hat, y): @@ -127,7 +127,7 @@ evaluate_accuracy(test_iter, net) ## 训练模型 -训练softmax回归的实现跟[“线性回归的从零开始实现”](linear-regression-scratch.md)一节介绍的线性回归中的实现非常相似。我们同样使用小批量随机梯度下降来优化模型的损失函数。在训练模型时,迭代周期数`num_epochs`和学习率`lr`都是可以调的超参数。改变它们的值可能会得到分类更准确的模型。 +训练softmax回归的实现与[“线性回归的从零开始实现”](linear-regression-scratch.md)一节介绍的线性回归中的实现非常相似。我们同样使用小批量随机梯度下降来优化模型的损失函数。在训练模型时,迭代周期数`num_epochs`和学习率`lr`都是可以调的超参数。改变它们的值可能会得到分类更准确的模型。 ```{.python .input n=21} num_epochs, lr = 5, 0.1 diff --git a/chapter_deep-learning-basics/underfit-overfit.md b/chapter_deep-learning-basics/underfit-overfit.md index 31b556c6d..d5a28f3ff 100644 --- a/chapter_deep-learning-basics/underfit-overfit.md +++ b/chapter_deep-learning-basics/underfit-overfit.md @@ -26,9 +26,9 @@ 然而在实际应用中,由于数据不容易获取,测试数据极少只使用一次就丢弃。因此,实践中验证数据集和测试数据集的界限可能比较模糊。从严格意义上讲,除非明确说明,否则本书中实验所使用的测试集应为验证集,实验报告的测试结果(如测试准确率)应为验证结果(如验证准确率)。 -### $K$ 折交叉验证 +### $k$ 折交叉验证 -由于验证数据集不参与模型训练,当训练数据不够用时,预留大量的验证数据显得太奢侈。一种改善的方法是$K$折交叉验证($K$-fold cross-validation)。在$K$折交叉验证中,我们把原始训练数据集分割成$K$个不重合的子数据集,然后我们做$K$次模型训练和验证。每一次,我们使用一个子数据集验证模型,并使用其他$K-1$个子数据集来训练模型。在这$K$次训练和验证中,每次用来验证模型的子数据集都不同。最后,我们对这$K$次训练误差和验证误差分别求平均。 +由于验证数据集不参与模型训练,当训练数据不够用时,预留大量的验证数据显得太奢侈。一种改善的方法是$k$折交叉验证($k$-fold cross-validation)。在$k$折交叉验证中,我们把原始训练数据集分割成$k$个不重合的子数据集,然后我们做$k$次模型训练和验证。每一次,我们使用一个子数据集验证模型,并使用其他$k-1$个子数据集来训练模型。在这$k$次训练和验证中,每次用来验证模型的子数据集都不同。最后,我们对这$k$次训练误差和验证误差分别求平均。 diff --git a/chapter_introduction/deep-learning-intro.md b/chapter_introduction/deep-learning-intro.md index d7e468971..87815715c 100644 --- a/chapter_introduction/deep-learning-intro.md +++ b/chapter_introduction/deep-learning-intro.md @@ -67,7 +67,7 @@ * 另一个重大发展是生成对抗网络的发明 [8]。传统上,用在概率分布估计和生成模型上的统计方法更多地关注于找寻正确的概率分布,以及正确的采样算法。生成对抗网络的关键创新在于将采样部分替换成了任意的含有可微分参数的算法。这些参数将被训练到使辨别器不能再分辨真实的和生成的样本。生成对抗网络可使用任意算法来生成输出的这一特性为许多技巧打开了新的大门。例如生成奔跑的斑马 [9]和生成名流的照片 [10] 都是生成对抗网络发展的见证。 -* 许多情况下单块GPU已经不能满足在大型数据集上进行训练的需要。过去10年内我们构建分布式并行训练算法的能力已经有了极大的提升。设计可扩展算法的最大瓶颈在于深度学习优化算法的核心:随机梯度下降需要相对更小的批量。与此同时,更小的批量也会降低GPU的效率。如果使用1,024块GPU,每块GPU的批量大小为32个样本,那么单步训练的批量大小将是32,000个以上。近年来李沐 [11]、Yang You等人 [12]以及Xianyan Jia等人 [13]的工作将批量大小增至多达64,000个样例,并把在ImageNet数据集上训练ResNet-50模型的时间降到了7分钟。与之对比,最初的训练时间需要以天来计算。 +* 许多情况下单块GPU已经不能满足在大型数据集上进行训练的需要。过去10年内我们构建分布式并行训练算法的能力已经有了极大的提升。设计可扩展算法的最大瓶颈在于深度学习优化算法的核心:随机梯度下降需要相对更小的批量。与此同时,更小的批量也会降低GPU的效率。如果使用1,024块GPU,每块GPU的批量大小为32个样本,那么单步训练的批量大小将是32,000个以上。近年来李沐 [11]、Yang You等人 [12]以及Xianyan Jia等人 [13]的工作将批量大小增至多达64,000个样例,并把在ImageNet数据集上训练ResNet-50模型的时间降到了7分钟。与之相比,最初的训练时间需要以天来计算。 * 并行计算的能力也为至少在可以采用模拟情况下的强化学习的发展贡献了力量。并行计算帮助计算机在围棋、雅达利游戏、星际争霸和物理模拟上达到了超过人类的水准。 diff --git a/chapter_natural-language-processing/fasttext.md b/chapter_natural-language-processing/fasttext.md index e286c0037..36a155267 100644 --- a/chapter_natural-language-processing/fasttext.md +++ b/chapter_natural-language-processing/fasttext.md @@ -16,7 +16,7 @@ fastText的其余部分同跳字模型一致,不在此重复。可以看到, ## 小结 * fastText提出了子词嵌入方法。它在word2vec中的跳字模型的基础上,将中心词向量表示成单词的子词向量之和。 -* 子词嵌入利用构词上的规律,通常可以提升生僻词表示的质量。 +* 子词嵌入利用构词上的规律,通常可以提升生僻词表征的质量。 ## 练习 diff --git a/chapter_natural-language-processing/glove.md b/chapter_natural-language-processing/glove.md index d96e8c18d..0bc0b3425 100644 --- a/chapter_natural-language-processing/glove.md +++ b/chapter_natural-language-processing/glove.md @@ -10,7 +10,7 @@ $$q_{ij}=\frac{\exp(\boldsymbol{u}_j^\top \boldsymbol{v}_i)}{ \sum_{k \in \mathc $$-\sum_{i\in\mathcal{V}}\sum_{j\in\mathcal{V}} x_{ij} \log\,q_{ij}.$$ -我们将数据集中所有以词$w_i$为中心词的背景词的数量之和$\left|\mathcal{C}_i\right|$记为$x_i$,并将以$w_i$为中心词生成背景词$w_j$的条件概率$x_{ij}/x_i$记作$p_{ij}$。我们可以进一步改写跳字模型的损失函数为 +我们将数据集中所有以词$w_i$为中心词的背景词的数量之和$\left|\mathcal{C}_i\right|$记为$x_i$,并将以$w_i$为中心词生成背景词$w_j$的条件概率$x_{ij}/x_i$记作$p_{ij}$。我们可以进一步将跳字模型的损失函数改写为 $$-\sum_{i\in\mathcal{V}} x_i \sum_{j\in\mathcal{V}} p_{ij} \log\,q_{ij}.$$ diff --git a/chapter_natural-language-processing/machine-translation.md b/chapter_natural-language-processing/machine-translation.md index bdecf90b0..a260c4625 100644 --- a/chapter_natural-language-processing/machine-translation.md +++ b/chapter_natural-language-processing/machine-translation.md @@ -2,7 +2,7 @@ 机器翻译是指将一段文本从一种语言自动翻译到另一种语言。因为一段文本序列在不同语言中的长度不一定相同,所以我们使用机器翻译为例来介绍编码器—解码器和注意力机制的应用。 -## 读取和预处理数据 +## 读取和预处理数据集 我们先定义一些特殊符号。其中“<pad>”(padding)符号用来添加在较短序列后,直到每个序列等长,而“<bos>”和“<eos>”符号分别表示序列的开始和结束。 diff --git a/chapter_natural-language-processing/sentiment-analysis-cnn.md b/chapter_natural-language-processing/sentiment-analysis-cnn.md index 2a0b50491..627e44313 100644 --- a/chapter_natural-language-processing/sentiment-analysis-cnn.md +++ b/chapter_natural-language-processing/sentiment-analysis-cnn.md @@ -1,6 +1,6 @@ # 文本情感分类:使用卷积神经网络(textCNN) -在“卷积神经网络”一章中我们探究了如何使用二维卷积神经网络来处理二维图像数据。在之前的语言模型和文本分类任务中,我们将文本数据看作是只有一个维度的时间序列,并很自然地使用循环神经网络来表征这样的数据。其实,我们也可以将文本当作一维图像,从而可以用一维卷积神经网络来捕捉临近词之间的关联。本节将介绍将卷积神经网络应用到文本分析的开创性工作之一:textCNN [1]。 +在“卷积神经网络”一章中我们探究了如何使用二维卷积神经网络来处理二维图像数据。在之前的语言模型和文本分类任务中,我们将文本数据看作只有一个维度的时间序列,并很自然地使用循环神经网络来表征这样的数据。其实,我们也可以将文本当作一维图像,从而可以用一维卷积神经网络来捕捉临近词之间的关联。本节将介绍将卷积神经网络应用到文本分析的开创性工作之一:textCNN [1]。 首先导入实验所需的包和模块。 @@ -95,7 +95,7 @@ textCNN模型主要使用了一维卷积层和时序最大池化层。假设输 ![textCNN的设计](../img/textcnn.svg) -下面我们来实现textCNN模型。与上一节相比,除了用一维卷积层替换循环神经网络外,这里我们还使用了两个嵌入层,一个的权重固定,另一个则参与训练。 +下面我们来实现textCNN模型。与上一节相比,除了用一维卷积层替换循环神经网络外,这里我们还使用了两个嵌入层,一个的权重固定,另一个的权重则参与训练。 ```{.python .input n=10} class TextCNN(nn.Block): @@ -139,7 +139,7 @@ net.initialize(init.Xavier(), ctx=ctx) ### 加载预训练的词向量 -同上一节一样,加载预训练的100维GloVe词向量,并分别初始化嵌入层`embedding`和`constant_embedding`,前者参与训练,而后者权重固定。 +同上一节一样,加载预训练的100维GloVe词向量,并分别初始化嵌入层`embedding`和`constant_embedding`,前者权重参与训练,而后者权重固定。 ```{.python .input n=7} glove_embedding = text.embedding.create( @@ -149,7 +149,7 @@ net.constant_embedding.weight.set_data(glove_embedding.idx_to_vec) net.constant_embedding.collect_params().setattr('grad_req', 'null') ``` -### 训练并评价模型 +### 训练模型 现在就可以训练模型了。 diff --git a/chapter_natural-language-processing/sentiment-analysis-rnn.md b/chapter_natural-language-processing/sentiment-analysis-rnn.md index 1600d9b3a..7cbc84042 100644 --- a/chapter_natural-language-processing/sentiment-analysis-rnn.md +++ b/chapter_natural-language-processing/sentiment-analysis-rnn.md @@ -2,7 +2,7 @@ 文本分类是自然语言处理的一个常见任务,它把一段不定长的文本序列变换为文本的类别。本节关注它的一个子问题:使用文本情感分类来分析文本作者的情绪。这个问题也叫情感分析(sentiment analysis),并有着广泛的应用。例如,我们可以分析用户对产品的评论并统计用户的满意度,或者分析用户对市场行情的情绪并用以预测接下来的行情。 -同搜索近义词和类比词一样,文本分类也属于词嵌入的下游应用。在本节中,我们将应用预训练的词向量和含多个隐藏层的双向循环神经网络,来判断一段不定长的文本序列中包含的是正面还是负面的情绪。 +同求近义词和类比词一样,文本分类也属于词嵌入的下游应用。在本节中,我们将应用预训练的词向量和含多个隐藏层的双向循环神经网络,来判断一段不定长的文本序列中包含的是正面还是负面的情绪。 在实验开始前,导入所需的包或模块。 @@ -17,13 +17,13 @@ import random import tarfile ``` -## 文本情感分类数据 +## 文本情感分类数据集 我们使用斯坦福的IMDb数据集(Stanford's Large Movie Review Dataset)作为文本情感分类的数据集 [1]。这个数据集分为训练和测试用的两个数据集,分别包含25,000条从IMDb下载的关于电影的评论。在每个数据集中,标签为“正面”和“负面”的评论数量相等。 -### 读取数据 +### 读取数据集 -首先下载这个数据集到`../data`路径下,然后解压至`../data/aclImdb`下。 +首先下载这个数据集到`../data`路径下,然后解压至`../data/aclImdb`路径下。 ```{.python .input n=3} # 本函数已保存在d2lzh包中方便以后使用 @@ -54,7 +54,7 @@ def read_imdb(folder='train'): # 本函数已保存在d2lzh包中方便以后 train_data, test_data = read_imdb('train'), read_imdb('test') ``` -### 预处理数据 +### 预处理数据集 我们需要对每条评论做分词,从而得到分好词的评论。这里定义的`get_tokenized_imdb`函数使用最简单的方法:基于空格进行分词。 @@ -165,7 +165,7 @@ net.embedding.weight.set_data(glove_embedding.idx_to_vec) net.embedding.collect_params().setattr('grad_req', 'null') ``` -### 训练并评价模型 +### 训练模型 这时候就可以开始训练模型了。 diff --git a/chapter_natural-language-processing/seq2seq.md b/chapter_natural-language-processing/seq2seq.md index 70a0e7b89..9bd021e86 100644 --- a/chapter_natural-language-processing/seq2seq.md +++ b/chapter_natural-language-processing/seq2seq.md @@ -18,7 +18,7 @@ ## 编码器 -编码器的作用是把一个不定长的输入序列变换成一个定长的背景变量$\boldsymbol{c}$,并在该背景变量中编码输入序列信息。常用的编码器是循环神经网络。 +编码器的作用是把一个不定长的输入序列变换成一个定长的背景变量$\boldsymbol{c}$,并在该背景变量中编码输入序列信息。编码器可以使用循环神经网络。 让我们考虑批量大小为1的时序数据样本。假设输入序列是$x_1,\ldots,x_T$,例如$x_i$是输入句子中的第$i$个词。在时间步$t$,循环神经网络将输入$x_t$的特征向量$\boldsymbol{x}_t$和上个时间步的隐藏状态$\boldsymbol{h}_{t-1}$变换为当前时间步的隐藏状态$\boldsymbol{h}_t$。我们可以用函数$f$表达循环神经网络隐藏层的变换: diff --git a/chapter_natural-language-processing/similarity-analogy.md b/chapter_natural-language-processing/similarity-analogy.md index dc90f7b5e..c5c166545 100644 --- a/chapter_natural-language-processing/similarity-analogy.md +++ b/chapter_natural-language-processing/similarity-analogy.md @@ -4,7 +4,7 @@ ## 使用预训练的词向量 -MXNet的`contrib.text`包提供了跟自然语言处理相关的函数和类(更多参见GluonNLP工具包 [1])。下面查看它目前提供的预训练词嵌入的名称。 +MXNet的`contrib.text`包提供了与自然语言处理相关的函数和类(更多参见GluonNLP工具包 [1])。下面查看它目前提供的预训练词嵌入的名称。 ```{.python .input} from mxnet import nd diff --git a/chapter_natural-language-processing/word2vec-gluon.md b/chapter_natural-language-processing/word2vec-gluon.md index f2ddec6ac..67ab7c239 100644 --- a/chapter_natural-language-processing/word2vec-gluon.md +++ b/chapter_natural-language-processing/word2vec-gluon.md @@ -17,7 +17,7 @@ import time import zipfile ``` -## 处理数据集 +## 预处理数据集 PTB(Penn Tree Bank)是一个常用的小型语料库 [1]。它采样自《华尔街日报》的文章,包括训练集、验证集和测试集。我们将在PTB训练集上训练词嵌入模型。该数据集的每一行作为一个句子。句子中的每个词由空格隔开。 @@ -158,7 +158,7 @@ sampling_weights = [counter[w]**0.75 for w in idx_to_token] all_negatives = get_negatives(all_contexts, sampling_weights, 5) ``` -## 读取数据 +## 读取数据集 我们从数据集中提取所有中心词`all_centers`,以及每个中心词对应的背景词`all_contexts`和噪声词`all_negatives`。我们将通过随机小批量来读取它们。 @@ -218,7 +218,7 @@ embed(x) ### 小批量乘法 -我们可以使用小批量乘法运算`batch_dot`对两个小批量中的矩阵一一做乘法。假设第一个小批量中包含$n$个形状为$a\times b$的矩阵$\boldsymbol{X}_1, \ldots, \boldsymbol{X}_n$,第二个小批量中包含$n$个形状为$b\times c$的矩阵$\boldsymbol{Y}_1, \ldots, \boldsymbol{Y}_n$。这两个小批量的矩阵乘法输出为$n$个形状为$a\times c$的矩阵$\boldsymbol{X}_1\boldsymbol{Y}_1, \ldots, \boldsymbol{X}_n\boldsymbol{Y}_n$。因此,给定两个形状分别为($n$, $a$, $b$)和($n$, $b$, $c$)的`NDArray`,小批量乘法输出的形状为($n$, $a$, $c$)。 +我们可以使用小批量乘法运算`batch_dot`对两个小批量中的矩阵一一做乘法。假设第一个小批量包含$n$个形状为$a\times b$的矩阵$\boldsymbol{X}_1, \ldots, \boldsymbol{X}_n$,第二个小批量包含$n$个形状为$b\times c$的矩阵$\boldsymbol{Y}_1, \ldots, \boldsymbol{Y}_n$。这两个小批量的矩阵乘法输出为$n$个形状为$a\times c$的矩阵$\boldsymbol{X}_1\boldsymbol{Y}_1, \ldots, \boldsymbol{X}_n\boldsymbol{Y}_n$。因此,给定两个形状分别为($n$, $a$, $b$)和($n$, $b$, $c$)的`NDArray`,小批量乘法输出的形状为($n$, $a$, $c$)。 ```{.python .input n=17} X = nd.ones((2, 1, 4)) diff --git a/chapter_natural-language-processing/word2vec.md b/chapter_natural-language-processing/word2vec.md index ab87d1340..bb2e4ae8a 100644 --- a/chapter_natural-language-processing/word2vec.md +++ b/chapter_natural-language-processing/word2vec.md @@ -39,7 +39,7 @@ $$P(w_o \mid w_c) = \frac{\text{exp}(\boldsymbol{u}_o^\top \boldsymbol{v}_c)}{ \ $$ \prod_{t=1}^{T} \prod_{-m \leq j \leq m,\ j \neq 0} P(w^{(t+j)} \mid w^{(t)}),$$ -这里小于1和大于$T$的时间步可以忽略。 +这里小于1或大于$T$的时间步可以被忽略。 ### 训练跳字模型 diff --git a/chapter_optimization/adagrad.md b/chapter_optimization/adagrad.md index 05b75baf6..7f1bdf4cc 100644 --- a/chapter_optimization/adagrad.md +++ b/chapter_optimization/adagrad.md @@ -7,7 +7,7 @@ x_1 \leftarrow x_1 - \eta \frac{\partial{f}}{\partial{x_1}}, \quad x_2 \leftarrow x_2 - \eta \frac{\partial{f}}{\partial{x_2}}. $$ -在[“动量法”](./momentum.md)一节里我们看到当$x_1$和$x_2$的梯度值有较大差别时,需要选择足够小的学习率使得自变量在梯度值较大的维度上不发散。但这样会导致自变量在梯度值较小的维度上迭代过慢。动量法依赖指数加权移动平均使得自变量的更新方向更加一致,从而降低发散的可能。本节我们介绍AdaGrad算法,它根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题 [1]。 +在[“动量法”](./momentum.md)一节里我们看到,当$x_1$和$x_2$的梯度值有较大差别时,需要选择足够小的学习率使得自变量在梯度值较大的维度上不发散。但这样会导致自变量在梯度值较小的维度上迭代过慢。动量法依赖指数加权移动平均使得自变量的更新方向更加一致,从而降低发散的可能。本节我们介绍AdaGrad算法,它根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题 [1]。 ## 算法 diff --git a/chapter_optimization/gd-sgd.md b/chapter_optimization/gd-sgd.md index 6aec30ed4..1043e240d 100644 --- a/chapter_optimization/gd-sgd.md +++ b/chapter_optimization/gd-sgd.md @@ -156,7 +156,7 @@ $$\nabla f(\boldsymbol{x}) = \frac{1}{n} \sum_{i = 1}^n \nabla f_i(\boldsymbol{x $$\boldsymbol{x} \leftarrow \boldsymbol{x} - \eta \nabla f_i(\boldsymbol{x}).$$ -这里$\eta$同样是学习率。可以看到每次迭代的计算开销从梯度下降的$\mathcal{O}(n)$降到了常数$\mathcal{O}(1)$。值得强调的是,随机梯度$\nabla f_i(\boldsymbol{x})$是对梯度$\nabla f(\boldsymbol{x})$的无偏估计: +这里$\eta$同样是学习率。可以看到,每次迭代的计算开销从梯度下降的$\mathcal{O}(n)$降到了常数$\mathcal{O}(1)$。值得强调的是,随机梯度$\nabla f_i(\boldsymbol{x})$是对梯度$\nabla f(\boldsymbol{x})$的无偏估计: $$E_i \nabla f_i(\boldsymbol{x}) = \frac{1}{n} \sum_{i = 1}^n \nabla f_i(\boldsymbol{x}) = \nabla f(\boldsymbol{x}).$$ diff --git a/chapter_optimization/minibatch-sgd.md b/chapter_optimization/minibatch-sgd.md index 4e9b5a647..a8d1a9a84 100644 --- a/chapter_optimization/minibatch-sgd.md +++ b/chapter_optimization/minibatch-sgd.md @@ -14,10 +14,10 @@ $$\boldsymbol{x}_t \leftarrow \boldsymbol{x}_{t-1} - \eta_t \boldsymbol{g}_t.$$ 基于随机采样得到的梯度的方差在迭代过程中无法减小,因此在实际中,(小批量)随机梯度下降的学习率可以在迭代过程中自我衰减,例如$\eta_t=\eta t^\alpha$(通常$\alpha=-1$或者$-0.5$)、$\eta_t = \eta \alpha^t$(如$\alpha=0.95$)或者每迭代若干次后将学习率衰减一次。如此一来,学习率和(小批量)随机梯度乘积的方差会减小。而梯度下降在迭代过程中一直使用目标函数的真实梯度,无须自我衰减学习率。 -小批量随机梯度下降中每次迭代的计算开销为$\mathcal{O}(|\mathcal{B}|)$。当批量大小为1时,该算法即为随机梯度下降;当批量大小等于训练数据样本数时,该算法即为梯度下降。当批量较小时,每次迭代中使用的样本少,这会导致并行处理和内存使用效率变低。这使得在计算同样数目样本的情况下比使用更大批量时所花时间更多。当批量较大时,每个小批量梯度里可能含有更多的冗余信息。为了得到较好的解,批量较大时比批量较小时需要计算的样本数目可能更多,例如增大迭代周期数。 +小批量随机梯度下降中每次迭代的计算开销为$\mathcal{O}(|\mathcal{B}|)$。当批量大小为1时,该算法即随机梯度下降;当批量大小等于训练数据样本数时,该算法即梯度下降。当批量较小时,每次迭代中使用的样本少,这会导致并行处理和内存使用效率变低。这使得在计算同样数目样本的情况下比使用更大批量时所花时间更多。当批量较大时,每个小批量梯度里可能含有更多的冗余信息。为了得到较好的解,批量较大时比批量较小时需要计算的样本数目可能更多,例如增大迭代周期数。 -## 读取数据 +## 读取数据集 本章里我们将使用一个来自NASA的测试不同飞机机翼噪音的数据集来比较各个优化算法 [1]。我们使用该数据集的前1,500个样本和5个特征,并使用标准化对数据进行预处理。 diff --git a/chapter_optimization/momentum.md b/chapter_optimization/momentum.md index 1f9bbec82..6a000a15d 100644 --- a/chapter_optimization/momentum.md +++ b/chapter_optimization/momentum.md @@ -99,7 +99,7 @@ $$y_t \approx 0.05 \sum_{i=0}^{19} 0.95^i x_{t-i}.$$ $$\boldsymbol{v}_t \leftarrow \gamma \boldsymbol{v}_{t-1} + (1 - \gamma) \left(\frac{\eta_t}{1 - \gamma} \boldsymbol{g}_t\right). $$ -由指数加权移动平均的形式可得,速度变量$\boldsymbol{v}_t$实际上对序列$\{\eta_{t-i}\boldsymbol{g}_{t-i} /(1-\gamma):i=0,\ldots,1/(1-\gamma)-1\}$做了指数加权移动平均。换句话说,相比于小批量随机梯度下降,动量法在每个时间步的自变量更新量近似于将前者对应的最近$1/(1-\gamma)$个时间步的更新量做了指数加权移动平均后再除以$1-\gamma$。所以,在动量法中,自变量在各个方向上的移动幅度不仅取决当前梯度,还取决于过去的各个梯度在各个方向上是否一致。在本节之前示例的优化问题中,所有梯度在水平方向上为正(向右),而在竖直方向上时正(向上)时负(向下)。这样,我们就可以使用较大的学习率,从而使自变量向最优解更快移动。 +由指数加权移动平均的形式可得,速度变量$\boldsymbol{v}_t$实际上对序列$\{\eta_{t-i}\boldsymbol{g}_{t-i} /(1-\gamma):i=0,\ldots,1/(1-\gamma)-1\}$做了指数加权移动平均。换句话说,相比于小批量随机梯度下降,动量法在每个时间步的自变量更新量近似于将前者对应的最近$1/(1-\gamma)$个时间步的更新量做了指数加权移动平均后再除以$1-\gamma$。所以,在动量法中,自变量在各个方向上的移动幅度不仅取决于当前梯度,还取决于过去的各个梯度在各个方向上是否一致。在本节之前示例的优化问题中,所有梯度在水平方向上为正(向右),而在竖直方向上时正(向上)时负(向下)。这样,我们就可以使用较大的学习率,从而使自变量向最优解更快移动。 ## 从零开始实现 diff --git a/chapter_optimization/rmsprop.md b/chapter_optimization/rmsprop.md index 83cda6c28..c42e94c0c 100644 --- a/chapter_optimization/rmsprop.md +++ b/chapter_optimization/rmsprop.md @@ -12,7 +12,7 @@ $$\boldsymbol{s}_t \leftarrow \gamma \boldsymbol{s}_{t-1} + (1 - \gamma) \boldsy $$\boldsymbol{x}_t \leftarrow \boldsymbol{x}_{t-1} - \frac{\eta}{\sqrt{\boldsymbol{s}_t + \epsilon}} \odot \boldsymbol{g}_t, $$ -其中$\eta$是学习率,$\epsilon$是为了维持数值稳定性而添加的常数,如$10^{-6}$。因为RMSProp算法的状态变量$\boldsymbol{s}_t$是对平方项$\boldsymbol{g}_t \odot \boldsymbol{g}_t$的指数加权移动平均,所以可以看作是最近$1/(1-\gamma)$个时间步的小批量随机梯度平方项的加权平均。如此一来,自变量每个元素的学习率在迭代过程中就不再一直降低(或不变)。 +其中$\eta$是学习率,$\epsilon$是为了维持数值稳定性而添加的常数,如$10^{-6}$。因为RMSProp算法的状态变量$\boldsymbol{s}_t$是对平方项$\boldsymbol{g}_t \odot \boldsymbol{g}_t$的指数加权移动平均,所以可以看作最近$1/(1-\gamma)$个时间步的小批量随机梯度平方项的加权平均。如此一来,自变量每个元素的学习率在迭代过程中就不再一直降低(或不变)。 照例,让我们先观察RMSProp算法对目标函数$f(\boldsymbol{x})=0.1x_1^2+2x_2^2$中自变量的迭代轨迹。回忆在[“AdaGrad算法”](adagrad.md)一节使用的学习率为0.4的AdaGrad算法,自变量在迭代后期的移动幅度较小。但在同样的学习率下,RMSProp算法可以更快逼近最优解。 @@ -56,7 +56,7 @@ def rmsprop(params, states, hyperparams): p[:] -= hyperparams['lr'] * p.grad / (s + eps).sqrt() ``` -我们将初始学习率设为0.01,并将超参数$\gamma$设为0.9。此时,变量$\boldsymbol{s}_t$可看作是最近$1/(1-0.9) = 10$个时间步的平方项$\boldsymbol{g}_t \odot \boldsymbol{g}_t$的加权平均。 +我们将初始学习率设为0.01,并将超参数$\gamma$设为0.9。此时,变量$\boldsymbol{s}_t$可看作最近$1/(1-0.9) = 10$个时间步的平方项$\boldsymbol{g}_t \odot \boldsymbol{g}_t$的加权平均。 ```{.python .input n=24} d2l.train_ch7(rmsprop, init_rmsprop_states(), {'lr': 0.01, 'gamma': 0.9}, diff --git a/chapter_prerequisite/ndarray.md b/chapter_prerequisite/ndarray.md index c4f6c2ebe..e212e8f44 100644 --- a/chapter_prerequisite/ndarray.md +++ b/chapter_prerequisite/ndarray.md @@ -230,7 +230,7 @@ D.asnumpy() ## 练习 -* 运行本节中的代码。将本节中条件判断式`X == Y`改为`X < Y`或`X > Y`,看看能够得到什么样的`NDArray`。 +* 运行本节中的代码。将本节中条件判别式`X == Y`改为`X < Y`或`X > Y`,看看能够得到什么样的`NDArray`。 * 将广播机制中按元素运算的两个`NDArray`替换成其他形状,结果是否和预期一样? diff --git a/chapter_recurrent-neural-networks/deep-rnn.md b/chapter_recurrent-neural-networks/deep-rnn.md index 7a92a3ce4..bcb157057 100644 --- a/chapter_recurrent-neural-networks/deep-rnn.md +++ b/chapter_recurrent-neural-networks/deep-rnn.md @@ -5,19 +5,19 @@ ![深度循环神经网络的架构](../img/deep-rnn.svg) -具体来说,在时间步$t$里,设小批量输入$\boldsymbol{X}_t \in \mathbb{R}^{n \times d}$(样本数为$n$,输入个数为$d$),第$\ell$隐藏层($\ell=1,\ldots,L$)的隐藏状态为$\boldsymbol{H}_t^{(\ell)} \in \mathbb{R}^{n \times h}$(隐藏单元个数为$h$),输出层变量为$\boldsymbol{O}_t \in \mathbb{R}^{n \times q}$(输出个数为$q$),且隐藏层的激活函数为$\phi$。第1隐藏层的隐藏状态和之前的计算一样: +具体来说,在时间步$t$里,设小批量输入$\boldsymbol{X}_t \in \mathbb{R}^{n \times d}$(样本数为$n$,输入个数为$d$),第$l$隐藏层($l=1,\ldots,L$)的隐藏状态为$\boldsymbol{H}_t^{(l)} \in \mathbb{R}^{n \times h}$(隐藏单元个数为$h$),输出层变量为$\boldsymbol{O}_t \in \mathbb{R}^{n \times q}$(输出个数为$q$),且隐藏层的激活函数为$\phi$。第1隐藏层的隐藏状态和之前的计算一样: $$\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{W}_{xh}^{(1)} \in \mathbb{R}^{d \times h}$、$\boldsymbol{W}_{hh}^{(1)} \in \mathbb{R}^{h \times h}$和偏差 $\boldsymbol{b}_h^{(1)} \in \mathbb{R}^{1 \times h}$分别为第1隐藏层的模型参数。 -当$1 < \ell \leq L$时,第$\ell$隐藏层的隐藏状态的表达式为 +当$1 < l \leq L$时,第$l$隐藏层的隐藏状态的表达式为 -$$\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{H}_t^{(l)} = \phi(\boldsymbol{H}_t^{(l-1)} \boldsymbol{W}_{xh}^{(l)} + \boldsymbol{H}_{t-1}^{(l)} \boldsymbol{W}_{hh}^{(l)} + \boldsymbol{b}_h^{(l)}),$$ -其中权重$\boldsymbol{W}_{xh}^{(\ell)} \in \mathbb{R}^{h \times h}$、$\boldsymbol{W}_{hh}^{(\ell)} \in \mathbb{R}^{h \times h}$和偏差 $\boldsymbol{b}_h^{(\ell)} \in \mathbb{R}^{1 \times h}$分别为第$\ell$隐藏层的模型参数。 +其中权重$\boldsymbol{W}_{xh}^{(l)} \in \mathbb{R}^{h \times h}$、$\boldsymbol{W}_{hh}^{(l)} \in \mathbb{R}^{h \times h}$和偏差 $\boldsymbol{b}_h^{(l)} \in \mathbb{R}^{1 \times h}$分别为第$l$隐藏层的模型参数。 最终,输出层的输出只需基于第$L$隐藏层的隐藏状态: diff --git a/chapter_recurrent-neural-networks/rnn-scratch.md b/chapter_recurrent-neural-networks/rnn-scratch.md index 6948b8d0a..b59177bd0 100644 --- a/chapter_recurrent-neural-networks/rnn-scratch.md +++ b/chapter_recurrent-neural-networks/rnn-scratch.md @@ -155,7 +155,7 @@ def grad_clipping(params, theta, ctx): ## 定义模型训练函数 -跟之前章节的模型训练函数相比,这里的模型训练函数有以下几点不同: +与之前章节的模型训练函数相比,这里的模型训练函数有以下几点不同: 1. 使用困惑度评价模型。 2. 在迭代模型参数前裁剪梯度。 @@ -192,7 +192,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_size, vocab_size) outputs = nd.concat(*outputs, dim=0) # Y的形状是(batch_size, num_steps),转置后再变成长度为 # batch * num_steps 的向量,这样跟输出的行一一对应