提交 dfbc185e 编写于 作者: A Aston Zhang

till fcn

上级 ab694ee7
# 全卷积网络(FCN)
在图像分类里,我们通过卷积层和池化层逐渐减少图像高宽最终得到跟预测类别数一样长的向量。例如用于ImageNet分类的ResNet-18里,我们将高宽为224的输入图像首先减少到高宽7,然后使用全局池化层得到512维输出,最后使用全连接层输出长为1000的预测向量
我们在上节介绍了,语义分割对图像中的每个像素预测类别。全卷积网络(fully convolutional network,简称FCN)采用卷积神经网络实现了从图像像素到像素类别的变换。与之前介绍的卷积神经网络有所不同,全卷积网络通过转置卷积(transposed convolution)层将中间层特征图的高和宽变换回输入图像的尺寸,从而令预测结果与输入图像在空间维(高和宽)上一一对应:给定空间维上的位置,通道维的输出即该位置对应像素的类别预测
但在语义分割里,我们需要对每个像素预测类别,也就是需要输出形状需要是$1000\times 224\times 224$。如果仍然使用全连接层作为输出,那么这一层权重将多达数百GB。本小节我们将介绍利用卷积神经网络解决语义分割的一个开创性工作之一:全卷积网络(fully convolutional network,简称FCN)[1]。FCN里将最后的全连接层修改成转置卷积层(transposed convolution)来得到所需大小的输出
我们先导入实验所需的包或模块,然后解释什么是转置卷积层
```{.python .input n=2}
import sys
......@@ -18,19 +18,18 @@ import sys
## 转置卷积层
假设$f$是一个卷积层,给定输入$x$,我们可以计算前向输出$y=f(x)$。在反向求导$z=\frac{\partial\, y}{\partial\,x}$时,我们知道$z$会得到跟$x$一样形状的输出。因为卷积运算的导数是自己本身,我们可以合法定义转置卷积层,记为$g$,为交换了前向和反向求导函数的卷积层。也就是$z=g(y)$。
下面的例子描述我们如何将卷积计算转换成矩阵乘法。
顾名思义,转置卷积层得名于矩阵的转置操作。事实上,卷积运算还可以通过矩阵乘法来实现。在下面的例子中,我们定义高和宽分别为4的输入`X`,以及高和宽分别为3的卷积核`K`。打印二维卷积运算的输出以及卷积核。可以看到,输出的高和宽分别为2。
```{.python .input}
X = nd.arange(1, 17).reshape((1, 1, 4, 4))
K = nd.arange(1, 10).reshape((1, 1, 3, 3))
conv = nn.Conv2D(channels=1, kernel_size=3)
conv.initialize(init.Constant(K))
conv(X), conv.weight.data()
conv(X), K
```
下面我们将卷积核`K`改写成含有大量零元素的稀疏矩阵`W`,即权重矩阵。权重矩阵的形状为(4,16),其中的非零元素来自卷积核`K`中的元素。将输入`X`逐行连结,得到长度为16的向量。然后将`W`与向量化的`X`做矩阵乘法,得到长度为4的向量。对其变形后,我们可以得到和上面卷积运算相同的结果。可见,我们在这个例子中使用矩阵乘法实现了卷积运算。
```{.python .input}
W, k = nd.zeros((4, 16)), nd.zeros(11)
k[:3], k[4:7], k[8:] = K[0, 0, 0, :], K[0, 0, 1, :], K[0, 0, 2, :]
......@@ -38,7 +37,11 @@ W[0, 0:11], W[1, 1:12], W[2, 4:15], W[3, 5:16] = k, k, k, k
nd.dot(W, X.reshape(16)).reshape((1, 1, 2, 2)), W
```
下面我们构造一个卷积层并打印它的输出形状。
现在我们从矩阵乘法的角度来描述卷积运算。设输入向量为$\boldsymbol{x}$,权重矩阵为$\boldsymbol{W}$,卷积的前向计算函数的实现可以看作将函数输入乘以权重矩阵,并输出向量$\boldsymbol{y} = \boldsymbol{W}\boldsymbol{x}$。我们知道,反向传播需要依据链式法则。由于$\nabla_\boldsymbol{x} \boldsymbol{y} = \boldsymbol{W}^\top$,卷积的反向传播函数的实现可以看作将函数输入乘以转置后的权重矩阵$\boldsymbol{W}^\top$。而转置卷积层正是交换了卷积层的前向计算函数与反向传播函数:这两个函数可以看作将函数输入向量分别乘以$\boldsymbol{W}^\top$和$\boldsymbol{W}$。
不难想象,转置卷积层可以用来交换卷积层输入和输出的形状。让我们继续用矩阵乘法描述卷积。设权重矩阵是形状为$4\times16$的矩阵,对于长度为16的输入向量,卷积前向计算输出长度为4的向量。假如输入向量的长度为4,转置权重矩阵的形状为$16\times4$,那么转置卷积层将输出长度为16的向量。在模型设计中,转置卷积层常用于将较小的特征图变换为更大的特征图。在全卷积网络中,当输入是高和宽较小的特征图时,转置卷积层可以用来将高和宽放大到输入图像的尺寸。
我们来看一个例子。构造一个卷积层`conv`,并设输入`X`的形状为(1,3,64,64)。卷积输出`Y`的通道数增加到10,但高和宽分别缩小了一半。
```{.python .input n=3}
conv = nn.Conv2D(10, kernel_size=4, padding=1, strides=2)
......@@ -49,7 +52,7 @@ Y = conv(X)
Y.shape
```
使用同样的卷积窗、填充和步幅的转置卷积层,我们可以得到和`x`形状一样的输出
下面我们通过创建`Conv2DTranspose`实例来构造转置卷积层`conv_trans`。这里我们设`conv_trans`的卷积核形状、填充以及步幅与`conv`中的相同,并设输出通道数为3。当输入为卷积层`conv`的输出`Y`时,转置卷积层输出与卷积层输入的高和宽相同:转置卷积层将特征图的高和宽分别放大了2倍
```{.python .input n=4}
conv_trans = nn.Conv2DTranspose(3, kernel_size=4, padding=1, strides=2)
......@@ -57,8 +60,6 @@ conv_trans.initialize()
conv_trans(Y).shape
```
简单来说,卷积层通常使得输入高宽变小,而转置卷积层则一般用来将高宽增大。
## FCN模型
FCN的核心思想是将一个卷积网络的最后全连接输出层替换成转置卷积层来获取对每个输入像素的预测。具体来说,它去掉了过于损失空间信息的全局池化层,并将最后的全连接层替换成输出通道是原全连接层输出大小的$1\times 1$卷积层,最后接上转置卷积层来得到需要形状的输出。图9.11描述了FCN模型。
......@@ -217,6 +218,7 @@ gb.show_images(imgs[::3] + imgs[1::3] + imgs[2::3], 3, n);
## 练习
* 用矩阵乘法来实现卷积运算是否高效?为什么?
* 试着改改最后的转置卷积层的参数设定。
* 看看双线性插值初始化是不是必要的。
* 试着改改训练参数来使得收敛更好些。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册