《动手学深度学习》mxnet版/第五章学习笔记
第五章
描述卷积神经网络中卷积层和池化层的工作原理,并解释填充、步幅、输入通道和输出通道的含义
- 二维卷积层
- 填充和步幅
- 多输入通道和多输出通道
- 使用重复元素的网络(VGG)
- 残差网络(ResNet)
二维卷积层
from mxnet import autograd, nd
from mxnet.gluon import nn
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]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i: i + h, j: j + w] * K).sum()
return Y
class Conv2D(nn.Block):
#函数__init__里我们声明weight和bias这两个模型参数。前向计算函数forward则是直接调用corr2d函数再加上偏 差
def __init__(self, kernel_size, **kwargs):
super(Conv2D, self).__init__(**kwargs)
self.weight = self.params.get('weight', shape=kernel_size)
self.bias = self.params.get('bias', shape=(1,))
def forward(self, x):
return corr2d(x, self.weight.data()) + self.bias.data()
特征图和感受野
二维卷积层输出的二维数组可以看作是输入在空间维度(宽和高)上某一级的表征,也叫特征图 (feature map)
填充和步幅
填充 (padding)是指在输入高和宽的两侧填充元素 (通常是0元素)
卷积神经网络经常使用奇数高宽的卷积核,如1、3、5和7,所以两端上的填充个数相等。
卷积窗口从输入数组的最左上方开始,按从左往右、从上往下的顺序,依次在输入数组上滑动。我们将每次滑动的行数和列数称为步幅(stride),可以减小输出的高和宽。
多输入通道和多输出通道
1 X 1卷积层
卷积窗口形状为1 X 1(kh = kw = 1)的多通道卷积层。我们通常称之为1 X 1卷积层,并将其中的卷积运算称为1 X 1卷积。1 X 1卷积层被当作保持高和宽维度形状不变的全连接层使用。于是,我们可以通过调整网络层之间的通道数来控制模型复杂度。
池化层
为了缓解卷积层对位置的过度敏感性,以及减少计算量。
池化层直接计算池化窗口内元素的最大值或者平均值。该运算也分别叫做最大池化或平均池化
填充
池化层也可以在输入的高和宽两侧的填充并调整窗口的移动步幅来改变输出形状
多通道
在处理多通道输入数据时,池化层对每个输入通道分别池化,而不是像卷积层那样将各通道的输入按通道相加
使用重复元素的网络(VGG)
VGG块的组成规律是:连续使用数个相同的填充为1、窗口形状为3X3的卷积层后接上一个步幅为2、窗口形状为2X2的最大池化层。卷积层保持输入的高和宽不变,而池化层则对其减半。我们使用vgg_block函数来实现这个基础的VGG块,它可以指定卷积层的数量num_convs和输出通道数num_channels
import d2lzh as d2l
from mxnet import gluon, init, nd
from mxnet.gluon import nn
def vgg_block(num_convs, num_channels): #卷积层的数,输出通道数
blk = nn.Sequential()
for _ in range(num_convs):
blk.add(nn.Conv2D(num_channels, kernel_size=3, padding=1, activation='relu'))
blk.add(nn.MaxPool2D(pool_size=2, strides=2))
return blk
与AlexNet和LeNet一样,VGG网络由卷积层模块后接全连接层模块构成。卷积层模块串联数个vgg_block,其超参数由变量conv_arch定义。该变量指定了每个VGG块里卷积层个数和输出通道数。全连接模块则跟AlexNet中的一样。 现在我们构造一个VGG网络。
它有5个卷积块,前2块使用单卷积层,而后3块使用双卷积层。第 一块的输出通道是64,之后每次对输出通道数翻倍,直到变为512。因为这个网络使用了8个卷积 层和3个全连接层,所以经常被称为VGG-11
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))
return net net = vgg(conv_arch)