Skip to content

Commit

Permalink
[1e feedback code] ch2-5
Browse files Browse the repository at this point in the history
  • Loading branch information
astonzhang committed Jan 8, 2019
1 parent 1cc9298 commit 795c047
Show file tree
Hide file tree
Showing 24 changed files with 123 additions and 124 deletions.
20 changes: 10 additions & 10 deletions chapter_convolutional-neural-networks/alexnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,23 +60,23 @@ import os
import sys
net = nn.Sequential()
# 使用较大的 11 x 11 窗口来捕获物体。同时使用步幅 4 来较大减小输出高和宽。
# 这里使用的输出通道数比 LeNet 中的也要大很多。
# 使用较大的11 x 11窗口来捕获物体。同时使用步幅4来较大幅度减小输出高和宽。这里使用的输出通
# 道数比LeNet中的也要大很多
net.add(nn.Conv2D(96, kernel_size=11, strides=4, activation='relu'),
nn.MaxPool2D(pool_size=3, strides=2),
# 减小卷积窗口,使用填充为 2 来使得输入输出高宽一致,且增大输出通道数
# 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
nn.Conv2D(256, kernel_size=5, padding=2, activation='relu'),
nn.MaxPool2D(pool_size=3, strides=2),
# 连续三个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
# 前两个卷积层后不使用池化层来减小输入的高和宽
# 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
# 前两个卷积层后不使用池化层来减小输入的高和宽
nn.Conv2D(384, kernel_size=3, padding=1, activation='relu'),
nn.Conv2D(384, kernel_size=3, padding=1, activation='relu'),
nn.Conv2D(256, kernel_size=3, padding=1, activation='relu'),
nn.MaxPool2D(pool_size=3, strides=2),
# 这里全连接层的输出个数比 LeNet 中的大数倍。使用丢弃层来缓解过拟合
# 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
nn.Dense(4096, activation="relu"), nn.Dropout(0.5),
nn.Dense(4096, activation="relu"), nn.Dropout(0.5),
# 输出层。由于这里使用 Fashion-MNIST,所以用类别数为 10,而非论文中的 1000。
# 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
nn.Dense(10))
```

Expand All @@ -95,10 +95,10 @@ for layer in net:
虽然论文中AlexNet使用ImageNet数据,但因为ImageNet数据训练时间较长,我们仍用前面的Fashion-MNIST数据集来演示AlexNet。读取数据的时候我们额外做了一步将图像高和宽扩大到AlexNet使用的图像高和宽224。这个可以通过`Resize`类来实现。也就是说,我们在`ToTensor`类前使用`Resize`类,然后使用`Compose`类来将这两个变化串联以方便调用。

```{.python .input n=3}
# 本函数已保存在 d2lzh 包中方便以后使用。
# 本函数已保存在d2lzh包中方便以后使用
def load_data_fashion_mnist(batch_size, resize=None, root=os.path.join(
'~', '.mxnet', 'datasets', 'fashion-mnist')):
root = os.path.expanduser(root) # 展开用户路径 '~'
root = os.path.expanduser(root) # 展开用户路径'~'
transformer = []
if resize:
transformer += [gdata.vision.transforms.Resize(resize)]
Expand All @@ -116,7 +116,7 @@ def load_data_fashion_mnist(batch_size, resize=None, root=os.path.join(
return train_iter, test_iter
batch_size = 128
# 如出现 out of memory 的报错信息,可减小 batch_size 或 resize。
# 如出现out of memory的报错信息,可减小batch_size或resize
train_iter, test_iter = load_data_fashion_mnist(batch_size, resize=224)
```

Expand Down
24 changes: 12 additions & 12 deletions chapter_convolutional-neural-networks/batch-norm.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,27 @@ from mxnet import autograd, gluon, init, nd
from mxnet.gluon import nn
def batch_norm(X, gamma, beta, moving_mean, moving_var, eps, momentum):
# 通过 autograd 来判断当前模式为训练模式或预测模式。
# 通过autograd来判断当前模式是训练模式还是预测模式
if not autograd.is_training():
# 如果是在预测模式下,直接使用传入的移动平均所得的均值和方差
# 如果是在预测模式下,直接使用传入的移动平均所得的均值和方差
X_hat = (X - moving_mean) / nd.sqrt(moving_var + eps)
else:
assert len(X.shape) in (2, 4)
if len(X.shape) == 2:
# 使用全连接层的情况,计算特征维上的均值和方差
# 使用全连接层的情况,计算特征维上的均值和方差
mean = X.mean(axis=0)
var = ((X - mean) ** 2).mean(axis=0)
else:
# 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要
# 保持 X 的形状以便后面可以做广播运算。
# 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持
# X的形状以便后面可以做广播运算
mean = X.mean(axis=(0, 2, 3), keepdims=True)
var = ((X - mean) ** 2).mean(axis=(0, 2, 3), keepdims=True)
# 训练模式下用当前的均值和方差做标准化
# 训练模式下用当前的均值和方差做标准化
X_hat = (X - mean) / nd.sqrt(var + eps)
# 更新移动平均的均值和方差
# 更新移动平均的均值和方差
moving_mean = momentum * moving_mean + (1.0 - momentum) * mean
moving_var = momentum * moving_var + (1.0 - momentum) * var
Y = gamma * X_hat + beta # 拉伸和偏移
Y = gamma * X_hat + beta # 拉伸和偏移
return Y, moving_mean, moving_var
```

Expand All @@ -96,19 +96,19 @@ class BatchNorm(nn.Block):
shape = (1, num_features)
else:
shape = (1, num_features, 1, 1)
# 参与求梯度和迭代的拉伸和偏移参数,分别初始化成 0 和 1。
# 参与求梯度和迭代的拉伸和偏移参数,分别初始化成0和1
self.gamma = self.params.get('gamma', shape=shape, init=init.One())
self.beta = self.params.get('beta', shape=shape, init=init.Zero())
# 不参与求梯度和迭代的变量,全在 CPU 上初始化成 0。
# 不参与求梯度和迭代的变量,全在内存上初始化成0
self.moving_mean = nd.zeros(shape)
self.moving_var = nd.zeros(shape)
def forward(self, X):
# 如果 X 不在 CPU 上,将 moving_mean 和 moving_var 复制到 X 所在设备上。
# 如果X不在内存上,将moving_mean和moving_var复制到X所在显存上
if self.moving_mean.context != X.context:
self.moving_mean = self.moving_mean.copyto(X.context)
self.moving_var = self.moving_var.copyto(X.context)
# 保存更新过的 moving_mean 和 moving_var。
# 保存更新过的moving_mean和moving_var
Y, self.moving_mean, self.moving_var = batch_norm(
X, self.gamma.data(), self.beta.data(), self.moving_mean,
self.moving_var, eps=1e-5, momentum=0.9)
Expand Down
8 changes: 4 additions & 4 deletions chapter_convolutional-neural-networks/channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import d2lzh as d2l
from mxnet import nd
def corr2d_multi_in(X, K):
# 我们首先沿着 X 和 K 的第 0 维(通道维)遍历。然后使用 * 将结果列表变成 add_n 函数
# 的位置参数(positional argument)来进行相加
# 首先沿着X和K的第0维(通道维)遍历。然后使用*将结果列表变成add_n函数的位置参数
# (positional argument)来进行相加
return nd.add_n(*[d2l.corr2d(x, k) for x, k in zip(X, K)])
```

Expand All @@ -43,7 +43,7 @@ corr2d_multi_in(X, K)

```{.python .input n=3}
def corr2d_multi_in_out(X, K):
# 对 K 的第 0 维遍历,每次同输入 X 做互相关计算。所有结果使用 stack 函数合并在一起。
# 对K的第0维遍历,每次同输入X做互相关计算。所有结果使用stack函数合并在一起
return nd.stack(*[corr2d_multi_in(X, k) for k in K])
```

Expand Down Expand Up @@ -74,7 +74,7 @@ def corr2d_multi_in_out_1x1(X, K):
c_o = K.shape[0]
X = X.reshape((c_i, h * w))
K = K.reshape((c_o, c_i))
Y = nd.dot(K, X) # 全连接层的矩阵乘法
Y = nd.dot(K, X) # 全连接层的矩阵乘法
return Y.reshape((c_o, h, w))
```

Expand Down
10 changes: 5 additions & 5 deletions chapter_convolutional-neural-networks/conv-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ $$
from mxnet import autograd, nd
from mxnet.gluon import nn
def corr2d(X, K): # 本函数已保存在 d2lzh 包中方便以后使用。
def corr2d(X, K): # 本函数已保存在d2lzh包中方便以后使用
h, w = K.shape
Y = nd.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
Expand Down Expand Up @@ -95,12 +95,12 @@ Y
虽然我们之前构造了`Conv2D`类,但由于`corr2d`使用了对单个元素赋值(`[i, j]=`)的操作因而无法自动求梯度。下面我们使用Gluon提供的`Conv2D`类来实现这个例子。

```{.python .input n=83}
# 构造一个输出通道数为 1(将在后面小节介绍通道),核数组形状是(1,2)的二维卷积层
# 构造一个输出通道数为1(将在5.3节介绍通道),核数组形状是(1,2)的二维卷积层
conv2d = nn.Conv2D(1, kernel_size=(1, 2))
conv2d.initialize()
# 二维卷积层使用 4 维输入输出,格式为(样本,通道,高,宽),这里批量大小(批量中的样本数)
# 和通道数均为 1。
# 二维卷积层使用4维输入输出,格式为(样本,通道,高,宽),这里批量大小(批量中的样本数)和通道数
# 均为1
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))
Expand All @@ -109,7 +109,7 @@ for i in range(10):
Y_hat = conv2d(X)
l = (Y_hat - Y) ** 2
l.backward()
# 为了简单起见这里忽略了偏差。
# 简单起见,这里忽略了偏差
conv2d.weight.data()[:] -= 3e-2 * conv2d.weight.grad()
if (i + 1) % 2 == 0:
print('batch %d, loss %.3f' % (i + 1, l.sum().asscalar()))
Expand Down
8 changes: 4 additions & 4 deletions chapter_convolutional-neural-networks/densenet.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class DenseBlock(nn.Block):
def forward(self, X):
for blk in self.net:
Y = blk(X)
X = nd.concat(X, Y, dim=1) # 在通道维上将输入和输出连结
X = nd.concat(X, Y, dim=1) # 在通道维上将输入和输出连结
return X
```

Expand Down Expand Up @@ -89,14 +89,14 @@ net.add(nn.Conv2D(64, kernel_size=7, strides=2, padding=3),
ResNet里通过步幅为2的残差块在每个模块之间减小高和宽。这里我们则使用过渡层来减半高和宽,并减半通道数。

```{.python .input n=5}
num_channels, growth_rate = 64, 32 # num_channels:当前的通道数。
num_channels, growth_rate = 64, 32 # num_channels为当前的通道数
num_convs_in_dense_blocks = [4, 4, 4, 4]
for i, num_convs in enumerate(num_convs_in_dense_blocks):
net.add(DenseBlock(num_convs, growth_rate))
# 上一个稠密的输出通道数。
# 上一个稠密块的输出通道数
num_channels += num_convs * growth_rate
# 在稠密块之间加入通道数减半的过渡层
# 在稠密块之间加入通道数减半的过渡层
if i != len(num_convs_in_dense_blocks) - 1:
net.add(transition_block(num_channels // 2))
```
Expand Down
12 changes: 6 additions & 6 deletions chapter_convolutional-neural-networks/googlenet.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ from mxnet import gluon, init, nd
from mxnet.gluon import nn
class Inception(nn.Block):
# c1 - c4 为每条线路里的层的输出通道数。
# c1 - c4为每条线路里的层的输出通道数
def __init__(self, c1, c2, c3, c4, **kwargs):
super(Inception, self).__init__(**kwargs)
# 线路 1,单 1 x 1 卷积层。
# 线路1,单1 x 1卷积层
self.p1_1 = nn.Conv2D(c1, kernel_size=1, activation='relu')
# 线路 2,1 x 1 卷积层后接 3 x 3 卷积层。
# 线路2,1 x 1卷积层后接3 x 3卷积层
self.p2_1 = nn.Conv2D(c2[0], kernel_size=1, activation='relu')
self.p2_2 = nn.Conv2D(c2[1], kernel_size=3, padding=1,
activation='relu')
# 线路 3,1 x 1 卷积层后接 5 x 5 卷积层。
# 线路3,1 x 1卷积层后接5 x 5卷积层
self.p3_1 = nn.Conv2D(c3[0], kernel_size=1, activation='relu')
self.p3_2 = nn.Conv2D(c3[1], kernel_size=5, padding=2,
activation='relu')
# 线路 4,3 x 3 最大池化层后接 1 x 1 卷积层。
# 线路4,3 x 3最大池化层后接1 x 1卷积层
self.p4_1 = nn.MaxPool2D(pool_size=3, strides=1, padding=1)
self.p4_2 = nn.Conv2D(c4, kernel_size=1, activation='relu')
Expand All @@ -41,7 +41,7 @@ class Inception(nn.Block):
p2 = self.p2_2(self.p2_1(x))
p3 = self.p3_2(self.p3_1(x))
p4 = self.p4_2(self.p4_1(x))
return nd.concat(p1, p2, p3, p4, dim=1) # 在通道维上连结输出
return nd.concat(p1, p2, p3, p4, dim=1) # 在通道维上连结输出
```

## GoogLeNet模型
Expand Down
14 changes: 7 additions & 7 deletions chapter_convolutional-neural-networks/lenet.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ net.add(nn.Conv2D(channels=6, kernel_size=5, activation='sigmoid'),
nn.MaxPool2D(pool_size=2, strides=2),
nn.Conv2D(channels=16, kernel_size=5, activation='sigmoid'),
nn.MaxPool2D(pool_size=2, strides=2),
# Dense 会默认将(批量大小,通道,高,宽)形状的输入转换成
# (批量大小,通道 * 高 * 宽)形状的输入
# Dense会默认将(批量大小,通道,高,宽)形状的输入转换成(批量大小,通道 * 高 * 宽)形
# 状的输入
nn.Dense(120, activation='sigmoid'),
nn.Dense(84, activation='sigmoid'),
nn.Dense(10))
Expand Down Expand Up @@ -63,7 +63,7 @@ train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
因为卷积神经网络计算比多层感知机要复杂,建议使用GPU来加速计算。我们尝试在`gpu(0)`上创建NDArray,如果成功则使用`gpu(0)`,否则仍然使用CPU。

```{.python .input}
def try_gpu(): # 本函数已保存在 d2lzh 包中方便以后使用
def try_gpu(): # 本函数已保存在 d2lzh 包中方便以后使用
try:
ctx = mx.gpu()
_ = nd.zeros((1,), ctx=ctx)
Expand All @@ -78,12 +78,12 @@ ctx
相应地,我们对[“Softmax回归的从零开始实现”](../chapter_deep-learning-basics/softmax-regression-scratch.md)一节中描述的`evaluate_accuracy`函数略作修改。由于数据刚开始存在CPU使用的内存上,当`ctx`变量代表GPU及相应的显存时,我们通过[“GPU计算”](../chapter_deep-learning-computation/use-gpu.md)一节中介绍的`as_in_context`函数将数据复制到显存上,例如`gpu(0)`

```{.python .input}
# 本函数已保存在 d2lzh 包中方便以后使用。该函数将被逐步改进:它的完整实现将在“图像增广”一节
# 中描述
# 本函数已保存在d2lzh包中方便以后使用。该函数将被逐步改进:它的完整实现将在“图像增广”一节中
# 描述
def evaluate_accuracy(data_iter, net, ctx):
acc_sum, n = nd.array([0], ctx=ctx), 0
for X, y in data_iter:
# 如果 ctx 代表 GPU 及相应的显存,将数据复制到显存上
# 如果ctx代表GPU及相应的显存,将数据复制到显存上
X, y = X.as_in_context(ctx), y.as_in_context(ctx).astype('float32')
acc_sum += (net(X).argmax(axis=1) == y).sum()
n += y.size
Expand All @@ -93,7 +93,7 @@ def evaluate_accuracy(data_iter, net, ctx):
我们同样对[“Softmax回归的从零开始实现”](../chapter_deep-learning-basics/softmax-regression-scratch.md)一节中定义的`train_ch3`函数略作修改,确保计算使用的数据和模型同在内存或显存上。

```{.python .input}
# 本函数已保存在 d2lzh 包中方便以后使用。
# 本函数已保存在d2lzh包中方便以后使用
def train_ch5(net, train_iter, test_iter, batch_size, trainer, ctx,
num_epochs):
print('training on', ctx)
Expand Down
6 changes: 3 additions & 3 deletions chapter_convolutional-neural-networks/nin.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ net.add(nin_block(96, kernel_size=11, strides=4, padding=0),
nn.MaxPool2D(pool_size=3, strides=2),
nin_block(384, kernel_size=3, strides=1, padding=1),
nn.MaxPool2D(pool_size=3, strides=2), nn.Dropout(0.5),
# 标签类别数是 10。
# 标签类别数是10
nin_block(10, kernel_size=3, strides=1, padding=1),
# 全局平均池化层将窗口形状自动设置成输入的高和宽
# 全局平均池化层将窗口形状自动设置成输入的高和宽
nn.GlobalAvgPool2D(),
# 将四维的输出转成二维的输出,其形状为批量大小,10)。
# 将四维的输出转成二维的输出,其形状为(批量大小,10)
nn.Flatten())
```

Expand Down
10 changes: 5 additions & 5 deletions chapter_convolutional-neural-networks/padding-and-strides.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ $$(n_h-k_h+p_h+1)\times(n_w-k_w+p_w+1),$$
from mxnet import nd
from mxnet.gluon import nn
# 定义一个便利函数来计算卷积层。它初始化卷积层权重,并对输入和输出做相应的升维和降维
# 定义一个便利函数来计算卷积层。它初始化卷积层权重,并对输入和输出做相应的升维和降维
def comp_conv2d(conv2d, X):
conv2d.initialize()
# (1,1)代表批量大小和通道数(后面章节将介绍)均为 1。
# (1,1)代表批量大小和通道数(5.3节将介绍)均为1
X = X.reshape((1, 1) + X.shape)
Y = conv2d(X)
return Y.reshape(Y.shape[2:]) # 排除不关心的前两维:批量和通道
return Y.reshape(Y.shape[2:]) # 排除不关心的前两维:批量和通道
# 注意这里是两侧分别填充 1 行或列,所以在两侧一共填充 2 行或列。
# 注意这里是两侧分别填充1行或列,所以在两侧一共填充2行或列
conv2d = nn.Conv2D(1, kernel_size=3, padding=1)
X = nd.random.uniform(shape=(8, 8))
comp_conv2d(conv2d, X).shape
Expand All @@ -45,7 +45,7 @@ comp_conv2d(conv2d, X).shape
当卷积核的高和宽不同时,我们也可以通过设置高和宽上不同的填充数使输出和输入具有相同的高和宽。

```{.python .input n=2}
# 使用高为 5、宽为 3 的卷积核。在高和宽两侧的填充数分别为 2 和 1。
# 使用高为5、宽为3的卷积核。在高和宽两侧的填充数分别为2和1
conv2d = nn.Conv2D(1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape
```
Expand Down
2 changes: 1 addition & 1 deletion chapter_convolutional-neural-networks/pooling.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ X

```{.python .input n=16}
pool2d = nn.MaxPool2D(3)
pool2d(X) # 因为池化层没有模型参数,所以不需要调用参数初始化函数
pool2d(X) # 因为池化层没有模型参数,所以不需要调用参数初始化函数
```

我们可以手动指定步幅和填充。
Expand Down
2 changes: 1 addition & 1 deletion chapter_convolutional-neural-networks/resnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import d2lzh as d2l
from mxnet import gluon, init, nd
from mxnet.gluon import nn
class Residual(nn.Block): # 本类已保存在 d2lzh 包中方便以后使用。
class Residual(nn.Block): # 本类已保存在d2lzh包中方便以后使用
def __init__(self, num_channels, use_1x1conv=False, strides=1, **kwargs):
super(Residual, self).__init__(**kwargs)
self.conv1 = nn.Conv2D(num_channels, kernel_size=3, padding=1,
Expand Down
4 changes: 2 additions & 2 deletions chapter_convolutional-neural-networks/vgg.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
```{.python .input n=3}
def vgg(conv_arch):
net = nn.Sequential()
# 卷积层部分
# 卷积层部分
for (num_convs, num_channels) in conv_arch:
net.add(vgg_block(num_convs, num_channels))
# 全连接层部分
# 全连接层部分
net.add(nn.Dense(4096, activation='relu'), nn.Dropout(0.5),
nn.Dense(4096, activation='relu'), nn.Dropout(0.5),
nn.Dense(10))
Expand Down
Loading

0 comments on commit 795c047

Please sign in to comment.