CNN中最常见的就是二维卷积层,它有高、宽两个维度,常用来处理图像数据。
在二维互相关运算中,一个二维输入数组 X X X和一个二维核 K K K(kernel)数组进行互相关运算,输出一个二维数组。
其中,核数组在卷积计算中称为卷积核或过滤器(filter)。
具体运算方式:
卷积核从输入的最左上方开始,从左往右、从上往下进行滑动当滑到某一位置时,窗口中的元素与输入的对应元素相乘,然后将所有乘积的结果相加,得到当前位置的输出以图中阴影部分为例: 0 ∗ 0 + 1 ∗ 1 + 3 ∗ 2 + 4 ∗ 3 = 19 0*0+1*1+3*2+4*3=19 0∗0+1∗1+3∗2+4∗3=19
另外,输出的形状可以根据输入和卷积核的形状计算。假设输入 X X X的形状为 ( h x , w x ) (h_x,w_x) (hx,wx),卷积核 K K K的形状为 ( h k , w k ) (h_k,w_k) (hk,wk),则输出 Y Y Y的形状: h y = h x − h k + 1 w y = w x − w k + 1 h_y=h_x-h_k+1 \\ w_y=w_x-w_k+1 hy=hx−hk+1wy=wx−wk+1
将核数组左右翻转、上下翻转,再与输入进行互相关运算,即得到卷积运算的输出。
卷积层的模型参数包括:卷积核、标量偏差。在训练模型的时候,通常先对参数初始化,然后通过迭代来优化参数。
下面简单实现一个自定义二维卷积层:
from mxnet import autograd, nd from mxnet.gluon import nn # 卷积操作 def corr2d(X, K): h = X.shape[0] - K.shape[0] + 1 w = X.shape[1] - K.shape[1] + 1 Y = nd.zeros((h, w)) for i in range(h): for j in range(w): Y[i, j] = (X[i : i + h, j : j + w] * K).sum() return Y # 二维卷积层 class Conv2D(nn.Block): 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)。
以下图为例: 输入中的阴影部分称为输出中阴影部分的感受野。