卷积的实现


输入数据NCHW

[in, ic, ih, iw]: in=batch;ic=input channel ;ih=input height; iw=input width

输出数据

[on,oc,oh,ow]:on=output batch;oc=output channel;oh=output height;ow=output width

卷积核

[oc,ic,kh,kw]:oc=output channel;ic=input channel;kh=kernel height;kw=kernel width

这里卷积核可以有多维,要跟输入的channel维度一致。

卷积核可以有多个,有多少卷积核,输出的feature map就有多少通道。

oh=ih-kh+1

ow=iw-kw+1

strides

步进。filter在input上滑动时的步长,默认为1。一般做下采样时>1,比如h和w的strides为[2,2],则输出为[1, 14, 14, 10]。

引入步长后:oh = (ih - kh)/sh + 1;ow = (iw - kw)/sw + 1

四维卷积实现如下:

def conv_4d(x, weights, bias, out_h, out_w, stride=1):
    batch_size = x.shape[0]
    input_channel = x.shape[1]
    output_channel = weights.shape[0]
    filter_height = weights.shape[2]
    filter_width = weights.shape[3]
    rs = np.zeros((batch_size, num_output_channel, out_h, out_w))

    for bs in range(batch_size):
        for oc in range(output_channel):
            rs[bs,oc] += bias[oc]
            for ic in range(input_channel):
                for i in range(out_h):
                    for j in range(out_w):
                        ii = i * stride
                        jj = j * stride
                        for fh in range(filter_height):
                            for fw in range(filter_width):
                                rs[bs,oc,i,j] += x[bs,ic,fh+ii,fw+jj] * weights[oc,ic,fh,fw]

上面的函数包含以下几重循环:

  1. 批量数据循环(第一维):bs in batch_size,对每个样本进行计算;
  2. 输出通道循环(第二维):oc in output_channel。这里先把bias加上了,后加也可以;
  3. 输入通道循环:ic in input_channel;
  4. 输出图像纵坐标循环:i in out h
  5. 输出图像横坐标循环:j in out_w。循环4和5完成对输出图像的每个点的遍历,在下面的子循环中计算并填充值;
  6. 卷积核纵向循环(第三维):fh in filter_height
  7. 卷积核横向循环(第四维):fw in filter_width。循环6和7完成卷积核与输入图像的卷积计算,并保存到循环4和5指定的输出图像的点上。

参考:

卷积运算

卷积前向计算代码实现

多通道卷积计算