Skip to content

Commit

Permalink
3e feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
astonzhang committed Mar 6, 2020
1 parent a0fd614 commit 9a65612
Show file tree
Hide file tree
Showing 46 changed files with 96 additions and 96 deletions.
2 changes: 1 addition & 1 deletion chapter_computational-performance/async-computation.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ with Benchmark('asynchronous.'):

## 异步计算对内存的影响

为了解释异步计算对内存使用的影响,让我们先回忆一下前面章节的内容。在前面章节中实现的模型训练过程中,我们通常会在每个小批量上评测一下模型,如模型的损失或者精度。细心的读者也许已经发现了,这类评测常用到同步函数,如`asscalar`函数或者`asnumpy`函数。如果去掉这些同步函数,前端会将大量的小批量计算任务在极短的时间内丢给后端,从而可能导致占用更多内存。当我们在每个小批量上都使用同步函数时,前端在每次迭代时仅会将一个小批量的任务丢给后端执行计算,并通常会减小内存占用。
为了解释异步计算对内存使用的影响,让我们先回忆一下前面章节的内容。在前面章节中实现的模型训练过程中,我们通常会在每个小批量上评测一下模型,如模型的损失或者准确率。细心的读者也许已经发现了,这类评测常用到同步函数,如`asscalar`函数或者`asnumpy`函数。如果去掉这些同步函数,前端会将大量的小批量计算任务在极短的时间内丢给后端,从而可能导致占用更多内存。当我们在每个小批量上都使用同步函数时,前端在每次迭代时仅会将一个小批量的任务丢给后端执行计算,并通常会减小内存占用。

由于深度学习模型通常比较大,而内存资源通常有限,建议大家在训练模型时对每个小批量都使用同步函数,例如,用`asscalar`函数或者`asnumpy`函数评价模型的表现。类似地,在使用模型预测时,为了减小内存的占用,也建议大家对每个小批量预测时都使用同步函数,例如,直接打印出当前小批量的预测结果。

Expand Down
2 changes: 1 addition & 1 deletion chapter_computational-performance/hybridize.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 3 additions & 3 deletions chapter_computational-performance/multiple-gpus.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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预测。


Expand Down
6 changes: 3 additions & 3 deletions chapter_computer-vision/anchor.md
Original file line number Diff line number Diff line change
@@ -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`中的浮点数更简洁一些。

Expand Down Expand Up @@ -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$。

Expand Down Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion chapter_computer-vision/fcn.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 3 additions & 3 deletions chapter_computer-vision/fine-tuning.md
Original file line number Diff line number Diff line change
@@ -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数据集的复杂模型在这个椅子数据集上过拟合。同时,因为数据量有限,最终训练得到的模型的精度也可能达不到实用的要求。

Expand All @@ -11,7 +11,7 @@
本节我们介绍迁移学习中的一种常用技术:微调(fine tuning)。如图9.1所示,微调由以下4步构成。

1. 在源数据集(如ImageNet数据集)上预训练一个神经网络模型,即源模型。
2. 创建一个新的神经网络模型,即目标模型。它复制了源模型上除了输出层外的所有模型设计及其参数。我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样适用于目标数据集。我们还假设源模型的输出层跟源数据集的标签紧密相关,因此在目标模型中不予采用。
2. 创建一个新的神经网络模型,即目标模型。它复制了源模型上除了输出层外的所有模型设计及其参数。我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样适用于目标数据集。我们还假设源模型的输出层与源数据集的标签紧密相关,因此在目标模型中不予采用。
3. 为目标模型添加一个输出大小为目标数据集类别个数的输出层,并随机初始化该层的模型参数。
4. 在目标数据集(如椅子数据集)上训练目标模型。我们将从头训练输出层,而其余层的参数都是基于源模型的参数微调得到的。

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion chapter_computer-vision/kaggle-gluon-cifar10.md
Original file line number Diff line number Diff line change
Expand Up @@ -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个迭代周期。

Expand Down
4 changes: 2 additions & 2 deletions chapter_computer-vision/kaggle-gluon-dog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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三个通道的均值和标准差做标准化,这和预训练模型所做的标准化是一致的。

Expand Down Expand Up @@ -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。

Expand Down
Loading

0 comments on commit 9a65612

Please sign in to comment.