2D_convolutional_layer

二维卷积层

最近在B站看沐神的动手学深度学习视频,记录一下学习过程
查看本文的jupyter notebook格式,更加清晰美观哦!

卷积神经网络是含有卷积层的神经网络。此文章所介绍的卷积神经网络均使用最常见的二维卷积层。它有高和宽两个空间维度,常用来处理图像数据。
二维互相关运算
虽然卷积层得名于卷积运算,但我们通常在卷积层中使用更加直观的互相关(cross-correlation)运算.在corr2d函数中实现互相关运算。它接受输入数组X与核数组K,并输出数组Y。
from mxnet import autograd, nd
from mxnet.gluon import nn
def corr2d(X, K): 
    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
X = nd.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
K = nd.array([[0, 1], [2, 3]])
corr2d(X, K)
[[19. 25.]
 [37. 43.]]
<NDArray 2x2 @cpu(0)>
二维卷积层。下面基于corr2d函数来实现一个自定义的二维卷积层。前向计算函数forward直接调用corr2d函数再加上偏差。
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()
(nd.random.normal(shape=(3, )))d
[0.4838046  0.29956347 0.15302546]
<NDArray 3 @cpu(0)>
图像中物体边缘检测.下面来看一个卷积层的简单应用:检测图像中物体边缘,即找到像素变化的位置。首先构造一张6 x 8的图像(即高和宽分别为6像素和8像素的图像)。它的中间4列为黑(0),其余为白(1)。
(nd.random.normal(shape=3))
[ 1.2546344  -0.54877406 -0.68106437]
<NDArray 3 @cpu(0)>
X = nd.ones((6, 8))
X[:, 2:6] = 0
X
[[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.]]
<NDArray 6x8 @cpu(0)>
然后构造一个高和宽分别为1和2的卷积核K。当它与输入做互相关运算时,如果横向相邻元素相同,输出为0;否则输出非0.
K = nd.array([[1, -1]])
Y = corr2d(X, K)
Y
[[ 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.]]
<NDArray 6x7 @cpu(0)>
从上面的结果可以看出,从白到黑和从黑到白的边缘分别被检测成了1和-1。其余部分的输出全是0。由此,卷积层可以通过重复使用卷积核有效表征局部空间。
通过数据学习核数组
之前构造的Conv2D类,由于corr2d使用了对单个元素赋值([i, j]=)的操作,因而无法自动求梯度。下面我们是用Gluon提供的Conv2D类来实现。
# 构造一个输出通道数为1,核数组形状为(1,2)的二维卷积层
conv2d = nn.Conv2D(2, kernel_size=(1, 2))
conv2d.initialize()

# 二维卷积层使用4维输入,格式为(样本,通道,高,宽),这里批量大小(批量中的样本数)和通道数均为1
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))

for i in range(10):
    with autograd.record():
        Y_hat = conv2d(X)
        l = (Y_hat - Y) ** 2
    l.backward()
    # 为简单起见,这里忽略了偏差
    conv2d.weight.data()[:] -= 3e-2 * conv2d.weight.grad()
    if (i+1)%2 == 0:
        print('batch %d, loss %.3f' % (i+1, l.sum().asscalar()))
batch 2, loss 10.347
batch 4, loss 1.781
batch 6, loss 0.317
batch 8, loss 0.061
batch 10, loss 0.013
可以看到迭代10次之后已经降到了一个比较小的值。学习到的核数组入下:
conv2d.weight.data().reshape((1, 2))
[[ 0.98359346 -0.99278635]]
<NDArray 1x2 @cpu(0)>
互相关运算和卷积运算
实际上,卷积运算和互相关运算类似。为了得到卷积运算的输出,我们只需要将核数组左右翻转并上下翻转,再与输入数组做互相关运算。由于在深度学习中,核数组都是学习出来的:卷积层无论使用互相关运算或卷积运算都不影响模型预测时的输出。
特征图和感受野
二维卷积层输出的二维数组可以看作输入在空间维度(宽和高)上某一级的表征,也叫特征图(feature map)。影响元素x的前向计算的所有可能输入区域(可能大于输入的实际尺寸)叫做x的感受野(receptive field).我们经常使用“元素”一词来描述数组或矩阵中的成员,在神经网络术语中,这些元素也可称为“单元”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值