
原文链接:
【动手学深度学习笔记】之二维卷积层mp.weixin.qq.com
1.二维卷积层
本节介绍卷积神经网络中最常见的二维卷积层。二维卷积层常用来处理图像数据,它具有两个空间维度(高和宽)。
1.1二维互相关运算
1.1.1原理分析
在二维互相关运算中,卷积窗口从左上角开始,每次向右滑动一列,直到到达最右边,然后回到最左边的列并向下滑动一行,继续重复上面的动作,直到到达右当卷积窗口滑动到某个位置时,窗口中的输入子片段与卷积窗口阵列按元素相乘并求和,并得到排列中相应位置的元素。
听着实在是复杂,看个实例吧。
我们对大小为
根据互相关运算的过程,首先是核排列会和
然后向右滑动一列,核排列与
上一次卷积窗体已经滑到了最右列,所以现在卷积窗体返回最垂直列并向下滑动一行,核排列与
现在卷积窗口滑动到了右下角,核排列与
最后将四次运算的数,与窗口同顺序分开在输出二维排列中,得到输出二维排列。
1.1.2程序实现
分析上述过程可知,输出数组的大小与输入数组,核数组存在关系:
式中,
并且横向滑动次数和
根据数组行列数之间的关系和运算方法,最终程序实现如下。
def cross(X,K):H_i = X.shape[0]W_i = X.shape[1]h = K.shape[0]w = K.shape[1]Y = torch.zeros((H_i-h+1,W_i-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
现在来构造输入多重和核分布,测试一下互相关运算函数
X = torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
K = torch.tensor([[0, 1], [2, 3]])
cross(X, K)
得到输出相对为
tensor([[19., 25.],[37., 43.]])
1.2二维卷积层
窗口形状为
二维卷积层的模型参数为卷积核(重量)和标量偏差(bias)。训练模型时,同样是线随机初始化模型参数,然后不断更新迭代参数。二维卷积层将输入和卷积核做互相关运算,并加上一个标量偏差来得到输出。
1.2.1实现二维卷积层
class Conv(nn.Module):def __init__(self, kernel_size):super(Conv, self).__init__()#类型为Parameter的tensor自动添加到参数列表self.weight = nn.Parameter(torch.randn(kernel_size))self.bias = nn.Parameter(torch.randn(1)) #只有一组输出,所以只需要一个偏差参数def forward(self, x):#正向传播:互相关运算之后加上偏差return cross(x, self.weight) + self.bias
1.3互相关运算的应用
下面使用二维卷积层检测图像中物体的边缘(发生变化的位置)。
首先初始化一张
X = torch.ones(6,8)
X[:,2:6] = 0
输出X为
tensor([[1., 1., 0., 0., 0., 0., 1., 1.],[1., 1., 0., 0., 0., 0., 1., 1.],[1., 1., 0., 0., 0., 0., 1., 1.],[1., 1., 0., 0., 0., 0., 1., 1.],[1., 1., 0., 0., 0., 0., 1., 1.],[1., 1., 0., 0., 0., 0., 1., 1.]])
然后构造一个大小为
K = torch.tensor([[1, -1]])
最后使用互相关运算,计算得到输出值。
Y = cross(X, K)
输出数组Y为:
tensor([[ 0., 1., 0., 0., 0., -1., 0.],[ 0., 1., 0., 0., 0., -1., 0.],[ 0., 1., 0., 0., 0., -1., 0.],[ 0., 1., 0., 0., 0., -1., 0.],[ 0., 1., 0., 0., 0., -1., 0.],[ 0., 1., 0., 0., 0., -1., 0.]])
可以看出,我们将从白到黑的边缘和从黑到白的边缘分别检测到1和-1。其余部分的输出全是0。使用卷积核可以有效地表征局部空间。
1.4二维卷积层的应用
这一部分将使用1.3中的输入数组X和输出数组Y来训练卷积神经网络,最终得到卷积核。
net = Conv(kernel_size = (1,2))
step =20#训练周期
lr = 0.01#学习率for i in range(step):Y_hat = net(X)l = ((Y_hat - Y) ** 2).sum()l.backward()net.weight.grad.fill_(0)net.bias.grad.fill_(0)if (i+1)%5 ==0:print('Step %d, loss %.3f' % (i + 1, l.item()))print("weight:",net.weight.data)
print("bias:",net.bias.data)
各个学习周期的损失为
Step 5, loss 7.531
Step 10, loss 1.380
Step 15, loss 0.304
Step 20, loss 0.076
训练结束后模型参数为
weight: tensor([[ 0.8960, -0.9054]])
bias: tensor([0.0053])
训练得到的参数与真实参数[1,-1]
还是比较接近的。
1.5卷积运算
为了得到卷积运算的输出,我们只需将核重叠到左右并排上下,再与输入数组做互相关运算。
1.6特征图和感受野
二维卷积层输出的二维细分可以被预定输入数组在空间尺寸上某一级的表征,也就是特征图。
如1.1中输入数组中的
整个输入样本都是输出样本的感受野。