版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/github_39655029/article/details/87603342
卷积神经网络convolutional neural network是含有卷积层convolutional layer的神经网络,二维卷积层具有高和宽两个空间维度,常用于处理图像数据;
在二维卷积层中,一个二维输入数组和一个二维核数组通过互相关运算输出一个二维数组; 二维互相关运算中,卷积窗口从输入数组的最左上方开始,然后按照从左往右、从上往下的顺序在输入数组上滑动; 输出的维度确定:假设输入形状是 nh×nw ,卷积核窗口形状是 kh×kw ,那么输出形状:
在这一层中将输入和卷积核做互相关运算,并加上一个标量偏差来得到输出。卷积层的模型参数包括卷积核和标量偏差,训练模型时,先对卷积核随机初始化,然后不断迭代卷积核和偏差;
卷积运算的输出等于将核数组左右翻转并上下翻转,再与输入数组做互相关运算,深度学习中的的核数组都是通过学习得到的;
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/2/18 10:43
# @Author : Cunyu
# @Site : cunyu1943.github.io
# @File : chapter5.py
# @Software: PyCharm
from mxnet import autograd, nd
from mxnet.gluon import nn
# 二维互相关运算函数
def corr2d(X, K):
# 获取核的高,宽
h, w = K.shape
# 定义一个全为0的输出
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]])
# 二维互相关运算结果
print(corr2d(X, K))
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()
指在输入高和宽的两侧填充元素( 常为0元素); 若在高的两侧一共填充ph行,在宽的两侧一共填充pw列,则输出形状为: (nh - kh + ph + 1) x (nw - kw + pw + 1);
指卷积窗口从输入数组的最左上方开始,按从左往右、从上往下的顺序,依次在输入数组上滑动,每次滑动的行数和列数; 一般来说,当高上步幅为 sh ,宽上步幅为 sw 时,输出形状为: ⌊(nh−kh+ph+sh)/sh⌋×⌊(nw−kw+pw+sw)/sw⌋;
"""
填充
"""
from mxnet import nd
from mxnet.gluon import nn
# 定义一个函数计算卷积层,初始化卷积层权重,并对输入和输出做出相应升降维
def comp_conv2d(conv2d, X):
conv2d.initialize()
# (1, 1)代表批量大小和通道数(“多输入通道和多输出通道”一节将介绍)均为1
X = X.reshape((1, 1) + X.shape)
Y = conv2d(X)
return Y.reshape(Y.shape[2:]) # 排除不关心的前两维:批量和通道
# 注意这里是两侧分别填充1行或列,所以在两侧一共填充2行或列
conv2d = nn.Conv2D(1, kernel_size=3, padding=1)
X = nd.random.uniform(shape=(8, 8))
print("卷积核高宽相同时输出形状")
print(comp_conv2d(conv2d, X).shape)
# 使用高5,宽3的卷积核,在高和宽两侧的填充数分别为2和1
conv2d = nn.Conv2D(1, kernel_size=(5, 3), padding=(2, 1))
print("卷积核高宽不同时输出形状")
print(comp_conv2d(conv2d, X).shape)
"""
步幅
"""
# 高和宽的步幅均为2,使得输入的高和宽减半
conv2d = nn.Conv2D(1, kernel_size=3, padding=1, strides=2)
print('步幅为2,输出形状')
print(comp_conv2d(conv2d, X).shape)
# 高和宽的步幅不同时,使得输入的高和宽减半
conv2d = nn.Conv2D(1, kernel_size=(3, 5), padding=(0,1), strides=(3,4))
print('不同步幅输出形状')
print(comp_conv2d(conv2d, X).shape)
"""
多通道输入
"""
import d2lzh as d2l
from mxnet import nd
def corr2d_multi_in(X, K):
# 先沿X和K的第0维遍历,然后使用*将结果列表变成add_n函数的位置参数
# (positional argument)来进行相加
return nd.add_n(*[d2l.corr2d(x, k) for x, k in zip(X, K)])
# 输入
X = nd.array([[[0, 1, 2], [3, 4, 5], [6, 7, 8]],
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]])
# 核
K = nd.array([[[0, 1], [2, 3]], [[1, 2], [3, 4]]])
print('输出')
print(corr2d_multi_in(X, K))
"""
多通道输出
"""
# 互相关运算函数来计算多通道的输出
def corr2d_multi_in_out(X, K):
# 对K的第0维遍历,每次同输入X做互相关计算,所有结果使用stack函数合并
return nd.stack(*[corr2d_multi_in(X, k) for k in K])
K = nd.stack(K, K + 1, K + 2)
print('核数组')
print(K.shape)
print('输出')
print(corr2d_multi_in_out(X, K))