python实现卷积操作
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 卷积的三种模式:
FULL
橙色部分为image, 蓝色部分为filter. full模式的意思是, 从filter和image刚相交开始做卷积, 白色部分为填0.SAME
当filter的中心与image的边角重合时, 开始做卷积运算.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实现卷积操作相关推荐
- python 实现卷积操作
python实现卷积操作 调用tf.nn.conv2d()实现卷积 自己实现卷积函数 我们知道,tensorflow里面自带卷积函数,tf.nn.conv2d()就可以实现相关功能,本文主要是自己实现 ...
- DeepLearning:手动编辑python实现卷积操作
目前的深度学习框架真正去实现卷积的时候,使用的是矩阵乘法的方式,使用im2col操作将输入数据与权重展开成二维矩阵,然后直接做矩阵乘法, 缺点是占用许多内存.具体原理看下面这张图就能明白: 图片的上面 ...
- 基于Python的卷积神经网络和特征提取
基于Python的卷积神经网络和特征提取 发表于2015-08-27 21:39| 4577次阅读| 来源blog.christianperone.com/| 13 条评论| 作者Christi ...
- 【深度学习】越来越卷,教你使用Python实现卷积神经网络(CNN)
@Author:Runsen https://blog.csdn.net/weixin_44510615/article/details/117409037 卷积神经网络 Yann LeCun 和Yo ...
- python的文件操作、模块操作、os模块、time、datatime模块以及模块的制作
Day12新手小白学python 第十二节 python的文件操作.模块操作.os模块.time.datatime模块以及模块的制作 目录 Day12新手小白学python 前言 一.文件打开关闭 二 ...
- 【深度学习入门】——亲手实现图像卷积操作
深度学习中有一个很重要的概念就是卷积神经网络 CNN,卷积神经网络中又有卷积层.池化层的概念.尤其是卷积层,理解难度比较大,虽然书中或者是视频中都有详细介绍过它的基础概念,但对于求知欲望很强烈的我,我 ...
- 人工智能:如何使用opencv4 和python实现卷积功能
Neural Networks and Deep Learning基础介绍 Inception系列 从ResNet到DenseNet tensorflow中文社区 这个博客主要通过回答以下几个问题来实 ...
- Python模块MySQLdb操作mysql出现2019错误:Can't initialize character set utf-8
我使用python的MySQLdb模块实现了一个mysql client, 在测试时,出现了如下错误 Python模块MySQLdb操作mysql出现2019错误:Can't initialize c ...
- Python 炫技操作:合并字典的七种方法
来源 | Python编程时光(ID: Cool-Python) Python 语言里有许多(而且是越来越多)的高级特性,是 Python 发烧友们非常喜欢的.在这些人的眼里,能够写出那些一般开发者看 ...
- Python OpenCV像素操作
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:opencv学堂 Python OpenCV像素操作 环 ...
最新文章
- Excel 2007 (Excel.Application) Workbooks.Add 出现内存不够的解决办法
- Python字符串常用方法(二)
- python为什么不能自动语法_Python 为什么不支持 i++ 自增语法,不提供 ++ 操作符?...
- 大数据初学者必备的详细版学习路线图
- C#编程(三十五)----------foreach和yield
- CodeForces - 1370E Binary Subsequence Rotation(思维)
- laravel使用migrate操作数据库迁移
- 《朝花夕拾》金句摘抄(三)
- 国内的优秀HTML5前端开发框架
- visual studio 2013 快速安全ocx(ActiveX控件)开发
- TakeColor鼠标位置不对/取色不准
- p1口实验_「正点原子NANO STM32开发板资料连载」第二章 实验硬件资源详解
- 采样频率和带宽的关系_磁共振成像带宽
- Python3批量爬取指定微博中的图片
- 在来一次 快转存哦
- 台式计算机硬盘能扩大吗,电脑怎么增加磁盘内存
- 在Word里怎么设置每页不同的页眉
- 输出 2~n之间所有素数,并求和,n由键盘输入。素数是只能被1和自身整除的整数。要求编写函数判断自然数x是否为素数
- 中国分电器及点火线圈市场现状研究分析与发展前景预测报告(2022)
- 手把手教你如何使用Multisim对Digilent FPGA开发板进行编程
热门文章
- 使用CHM文档 采集随笔(续)
- 关于DOS和命令行的故事
- Zend Studio小技巧:自动生成版本信息
- win10下cuda、cudnn、c++的cuda环境(build tool of Visual Studio 2019)、anaconda的pytorch-gpu环境、gcc编译环境
- Java多线程实现-Runnable接口
- 第四季-专题6-Linux内核子系统
- Android 详解自定义View抽奖转盘
- 让人耗尽脑汁的需求分析工作(转--Fireball)
- java学习中,二分法查找数组中的元素(java 学习中的小记录)
- 【转】windows下mongodb安装与使用整理