0. 前言

卷积神经网络与全连接神经网络类似, 可以理解成一种变换, 这种变换一般由卷积、池化、激活函数等一系列操作组合而成. 本文就“卷积”部分稍作介绍.

1. 卷积介绍

卷积可以看作是输入和卷积核之间的内积运算, 是两个实质函数之间的一种数学运算. 在卷积运算中, 通常使用卷积核将输入数据进行卷积运算得到的输出作为特征映射, 每个卷积核可获得一个特征映射.
如图所示, 一张大小为5×5×35 \times5 \times35×5×3的图片经过零填充后, 大小变为 7×7×37 \times 7 \times 37×7×3. 使用两个大小为3×3×33 \times 3 \times 33×3×3的卷积核进行步长为111的卷积运算, 最后得到一个大小为3×3×23 \times 3 \times 23×3×2的 feature map.

可以看到, 卷积核在图片所对应的矩阵中滑动. 每滑动到一个位置, 将对应数字相乘并求和, 得到一个特征图矩阵的元素.
注意, 卷积核每次滑动的步长为111, 才能滑动到矩阵的边缘部分.

1.1 卷积的三种模式:

  1. FULL

    橙色部分为image, 蓝色部分为filter. full模式的意思是, 从filter和image刚相交开始做卷积, 白色部分为填0.

  2. SAME

    当filter的中心与image的边角重合时, 开始做卷积运算.

  3. VALID

    当filter全部在image里面的时候,进行卷积运算.

1.2 feature map 公式计算

首先定义如下参数,

  • 输入大小 B×H×W×CB \times H\times W \times CB×H×W×C
  • 卷积核大小 b×h×w×Cb \times h \times w \times Cb×h×w×C
  • 步长 SSS

1.FULL:
输出大小 B×⌊H+h+1S⌋×⌊W+w+1S⌋×bB \times \lfloor \frac {H + h +1} S \rfloor \times \lfloor \frac {W + w +1} S \rfloor \times bB×⌊SH+h+1​⌋×⌊SW+w+1​⌋×b

2.SAME:
输出大小 B×⌊HS⌋×⌊WS⌋×bB \times \lfloor \frac HS \rfloor \times \lfloor \frac WS \rfloor\times bB×⌊SH​⌋×⌊SW​⌋×b

3.VALID:
输出大小 B×⌊H−h+1S⌋×⌊W−w+1S⌋×bB \times \lfloor \frac {H - h +1} S \rfloor \times \lfloor \frac {W - w +1}{S} \rfloor \times bB×⌊SH−h+1​⌋×⌊SW−w+1​⌋×b

Tensorflow中的卷积有“same”和“valid”两种模式
Pytorch中可以直接通过设置参数“padding"来控制零层的填充.

同样, 我们可以基于零层填充的圈数PPP, 得到我们的另一个计算公式:
输出大小 B×⌊H−h+2PS+1⌋×⌊W−w+2PS+1⌋×bB \times \lfloor \frac{H-h+2P}{S} + 1 \rfloor \times \lfloor \frac{W-w+2P}{S} + 1 \rfloor \times bB×⌊SH−h+2P​+1⌋×⌊SW−w+2P​+1⌋×b

2. 代码实现

import numpy as np
import mathclass Conv2D():def __init__(self, inputShape, outputChannel, kernelSize, stride=1, method=""):self.height = inputShape[1]self.width = inputShape[2]self.inputChannel = inputShape[-1]self.outputChannel = outputChannelself.batchSize = inputShape[0]self.stride = strideself.kernelSize = kernelSizeself.method = method# initial the parameters of the kernel, do not initial them as zeroself.weights = np.random.standard_normal([self.inputChannel, kernelSize, kernelSize, self.outputChannel])self.bias = np.random.standard_normal(self.outputChannel)# the shape of the output"""# This part has some problemsif method == "FULL":self.output = np.zeros(inputShape[0],math.floor((inputShape[1] - kernelSize + 2 * (kernelSize - 1)) / self.stride) + 1,math.floor((inputShape[2] - kernelSize + 2 * (kernelSize - 1)) / self.stride) + 1,self.outputChannel)  """if method == "SAME":self.output = np.zeros((self.batchSize, math.floor(self.height / self.stride), math.floor(self.width / self.stride),self.outputChannel))if method == "VALID":self.output = np.zeros([self.batchSize, math.floor((self.height - kernelSize + 1) / self.stride),math.floor((self.width - kernelSize + 1) / self.stride),self.outputChannel])def forward(self, x):weights = self.weights.reshape([-1, self.outputChannel])  # shape: [(h*w),#]# Filling operation# Note that: x is 4-dimensional."""if self.method == "FULL":x = np.pad(x, ((0, 0), (self.kernelSize - 1, self.kernelSize - 1), (self.kernelSize - 1, self.kernelSize - 1),(0, 0)), 'constant', constant_values=0)"""if self.method == "SAME":x = np.pad(x, ((0, 0), (self.kernelSize // 2, self.kernelSize // 2), (self.kernelSize // 2, self.kernelSize // 2),(0, 0)), 'constant', constant_values=0)convOut = np.zeros(self.output.shape)for i in range(self.batchSize):img_i = x[i]# img_i = x[i][np.newaxis, :, :, :]colImage_i = self.im2col(img_i, self.kernelSize, self.stride)convOut[i] = np.reshape(np.dot(colImage_i, weights) + self.bias, self.output[0].shape)return convOut# im2col functiondef im2col(self, image, kernelSize, stride):imageCol = []for i in range(0, image.shape[0] - kernelSize + 1, stride):for j in range(0, image.shape[1] - kernelSize + 1, stride):col = image[i:i + kernelSize, j:j + kernelSize, :].reshape([-1])# col = image[:, i:i + kernelSize, j:j + kernelSize, :].reshape([-1])  # Do not use .view([-1])imageCol.append(col)imageCol = np.array(imageCol)  # shape: [(h*w),(c*h*w)] kernel's height, width and channelsreturn imageCol# Test partinputData = np.random.random((4, 5, 5, 3))
print("inputShape: ", inputData.shape)
kernel = list([3, 3, 32])
print("kernel size: ", kernel)
conv2d = Conv2D(inputShape=inputData.shape, outputChannel=kernel[2], kernelSize=kernel[0], stride=1, method='VALID')
outputData = conv2d.forward(inputData)
print("outputShape: ", outputData.shape)

本文形状的命名方式为(batchsize,height,width,channels)(\text {batchsize}, \text {height}, \text {width}, \text {channels})(batchsize,height,width,channels), 与Tensorflow中命名一致.
与Pytorch中的命名为(batchsize,channels,height,width)(\text {batchsize}, \text {channels}, \text {height}, \text {width})(batchsize,channels,height,width)有所不同.

重点:
由于图片转换后得到的矩阵为4维矩阵, 我们在进行计算处理的过程中会对矩阵进行降维处理; 并且在进行矩阵乘法时, 也要注意两矩阵是否满足矩阵乘法的条件.


参考资料:
https://www.bilibili.com/video/BV1VV411478E
https://www.bilibili.com/video/BV1m34y1m7TD
https://zhuanlan.zhihu.com/p/63974249
https://blog.csdn.net/god_frey09/article/details/105188005
https://blog.csdn.net/v_JULY_v/article/details/51812459
https://www.jianshu.com/p/46b6615a7251
https://blog.csdn.net/dwyane12138/article/details/78449898

python实现卷积操作相关推荐

  1. python 实现卷积操作

    python实现卷积操作 调用tf.nn.conv2d()实现卷积 自己实现卷积函数 我们知道,tensorflow里面自带卷积函数,tf.nn.conv2d()就可以实现相关功能,本文主要是自己实现 ...

  2. DeepLearning:手动编辑python实现卷积操作

    目前的深度学习框架真正去实现卷积的时候,使用的是矩阵乘法的方式,使用im2col操作将输入数据与权重展开成二维矩阵,然后直接做矩阵乘法, 缺点是占用许多内存.具体原理看下面这张图就能明白: 图片的上面 ...

  3. 基于Python的卷积神经网络和特征提取

     基于Python的卷积神经网络和特征提取 发表于2015-08-27 21:39| 4577次阅读| 来源blog.christianperone.com/| 13 条评论| 作者Christi ...

  4. 【深度学习】越来越卷,教你使用Python实现卷积神经网络(CNN)

    @Author:Runsen https://blog.csdn.net/weixin_44510615/article/details/117409037 卷积神经网络 Yann LeCun 和Yo ...

  5. python的文件操作、模块操作、os模块、time、datatime模块以及模块的制作

    Day12新手小白学python 第十二节 python的文件操作.模块操作.os模块.time.datatime模块以及模块的制作 目录 Day12新手小白学python 前言 一.文件打开关闭 二 ...

  6. 【深度学习入门】——亲手实现图像卷积操作

    深度学习中有一个很重要的概念就是卷积神经网络 CNN,卷积神经网络中又有卷积层.池化层的概念.尤其是卷积层,理解难度比较大,虽然书中或者是视频中都有详细介绍过它的基础概念,但对于求知欲望很强烈的我,我 ...

  7. 人工智能:如何使用opencv4 和python实现卷积功能

    Neural Networks and Deep Learning基础介绍 Inception系列 从ResNet到DenseNet tensorflow中文社区 这个博客主要通过回答以下几个问题来实 ...

  8. Python模块MySQLdb操作mysql出现2019错误:Can't initialize character set utf-8

    我使用python的MySQLdb模块实现了一个mysql client, 在测试时,出现了如下错误 Python模块MySQLdb操作mysql出现2019错误:Can't initialize c ...

  9. Python 炫技操作:合并字典的七种方法

    来源 | Python编程时光(ID: Cool-Python) Python 语言里有许多(而且是越来越多)的高级特性,是 Python 发烧友们非常喜欢的.在这些人的眼里,能够写出那些一般开发者看 ...

  10. Python OpenCV像素操作

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:opencv学堂 Python OpenCV像素操作 环 ...

最新文章

  1. Excel 2007 (Excel.Application) Workbooks.Add 出现内存不够的解决办法
  2. Python字符串常用方法(二)
  3. python为什么不能自动语法_Python 为什么不支持 i++ 自增语法,不提供 ++ 操作符?...
  4. 大数据初学者必备的详细版学习路线图
  5. C#编程(三十五)----------foreach和yield
  6. CodeForces - 1370E Binary Subsequence Rotation(思维)
  7. laravel使用migrate操作数据库迁移
  8. 《朝花夕拾》金句摘抄(三)
  9. 国内的优秀HTML5前端开发框架
  10. visual studio 2013 快速安全ocx(ActiveX控件)开发
  11. TakeColor鼠标位置不对/取色不准
  12. p1口实验_「正点原子NANO STM32开发板资料连载」第二章 实验硬件资源详解
  13. 采样频率和带宽的关系_磁共振成像带宽
  14. Python3批量爬取指定微博中的图片
  15. 在来一次 快转存哦
  16. 台式计算机硬盘能扩大吗,电脑怎么增加磁盘内存
  17. 在Word里怎么设置每页不同的页眉
  18. 输出 2~n之间所有素数,并求和,n由键盘输入。素数是只能被1和自身整除的整数。要求编写函数判断自然数x是否为素数
  19. 中国分电器及点火线圈市场现状研究分析与发展前景预测报告(2022)
  20. 手把手教你如何使用Multisim对Digilent FPGA开发板进行编程

热门文章

  1. 使用CHM文档 采集随笔(续)
  2. 关于DOS和命令行的故事
  3. Zend Studio小技巧:自动生成版本信息
  4. win10下cuda、cudnn、c++的cuda环境(build tool of Visual Studio 2019)、anaconda的pytorch-gpu环境、gcc编译环境
  5. Java多线程实现-Runnable接口
  6. 第四季-专题6-Linux内核子系统
  7. Android 详解自定义View抽奖转盘
  8. 让人耗尽脑汁的需求分析工作(转--Fireball)
  9. java学习中,二分法查找数组中的元素(java 学习中的小记录)
  10. 【转】windows下mongodb安装与使用整理