• python实现卷积运算
千次阅读
2021-07-20 18:39:41

一、卷积定义与朴素计算方法：

图1 卷积定义与计算方法

二、 Python代码实现

结合伪代码实现python代码如下（因为我是先写的代码，后才发现上面的伪代码，所以循环次序略有不同）：

import torch.nn as nn
import torch

def myConv2d(images, in_channels, out_channels, kernel_size, stride, padding, weights=None, bias=None):
if weights is None:
weights = torch.rand(out_channels, in_channels, kernel_size[0], kernel_size[1])
if bias is None:
bias = torch.zeros(out_channels)
n, c, w, h = images.shape
# new_image = torch.zeros(n, c, w + 2 * padding, h + 2 * padding)
images = images.clone()
images = torch.cat((torch.zeros(n, c, padding, h), images), 2)
images = torch.cat((images, torch.zeros(n, c, padding, h)), 2)
images = torch.cat((torch.zeros(n, c, w + 2 * padding, padding), images), 3)
images = torch.cat((images, torch.zeros(n, c, w + 2 * padding, padding)), 3)
n, c, w, h = images.shape
output = []
# 循环batch_size
for i, im in enumerate(images):
imout = []
# 循环feature map count, 也就是输出通道数
for j in range(out_channels):
feature_map = []
row = 0
# 下面两层循环为使用kernel滑动窗口遍历输入图片
while row + kernel_size[0] <= h:
row_feat_map = []
col = 0
while col + kernel_size[1] <= w:
# 卷积计算每个点的值，此处为了方便理解定义了channels,其实可以直接定义point=0，然后进行累加，最后再加上偏置
channels = [0 for x in range(c)]
for ch in range(c):
for y in range(kernel_size[0]):
for x in range(kernel_size[1]):
channels[ch] += im[ch][row + y][col + x] * weights[j][ch][y][x]
point = sum(channels) + bias[j]
row_feat_map.append(point)
col += stride[1]
feature_map.append(row_feat_map)
row += stride[0]
imout.append(feature_map)
output.append(imout)

if __name__ == "__main__":
# 测试参数
image_w, image_h = 7,7
in_channels = 1
out_channels = 1
kernel_size = (2, 3)
stride = (2,3)

# 输入图片与网络权重
image = torch.rand(1, in_channels, image_w, image_h)
weights = torch.rand(out_channels, in_channels, kernel_size[0], kernel_size[1])
bias = torch.ones(out_channels)

# pytorch运算结果
net = nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, bias=True)
net.weight = nn.Parameter(weights)
net.bias = nn.Parameter(bias)
net.eval()
output = net(image)
print(output)

# 自己实现的结果
output = myConv2d(image, in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, weights=weights, bias=bias)
print(output)

三、卷积运算图示

下图展示了padding=1, stride=(1,1), 不使用偏置bias的情况下，使用3*3的卷积核在的两个通道的5*5图片上的计算过程，其中卷积核权重为[[1,0,1], [-1,1,0], [0,-1,0]].

四、卷积运算分析

假设输入图片大小为W * H * C,  卷积核为F * Kw * Kh * C。

输出层大小：Osize = F * Ow * Oh

Ow = (W + Padding * 2 - Kw)

Oh = (H + Padding * 2 - Kh)

卷积层参数个数：F * C * Kw * Kh

卷积层运算量FLOPs:  2 * C * Kw * Kh * Ow * Oh * F

其中最内层循环计算每个点的计算量是2 * C * Kw * Kh, 2指的是最内层一次浮点乘和一次浮点加。

参考链接：

更多相关内容
• 主要讲下实际卷积运算中关于padding=same和padding=valid的输出特征图的大小，以及池化后特征图的大小。 1. 正文 1. 卷积运算 特别说明：卷积（除不尽）向下取整！！！！ 特别说明：卷积（除不尽）向下取整！！！！ ...
• 使用pytorch演示卷积，反卷积，池化等运算。。。。。。
• 连续时间信号卷积运算的 MATLAB 实现 一实验目的 1 理解掌握卷积的概念及物理意义 2 理解单位冲击响应的概念及物理意义 二实验原理 根据前述知识连续信号卷积运算定义为 f (t ) f (t ) f (t ) f ( ) f (t ) d 1 2 1...
• python实现卷积运算，有调用函数和不调用函数两种方法都写在里面了，可以帮助理解卷积
• 然而由于参数训练过程计算量太大，滑动卷积矩阵乘计算非常的费时，完成一个卷积神经网络模型的训练往往需要消耗大量的时间，针对这个问题，本次实验将构建一个基于CUDA架构的编程环境，采用CUDA/C++编程实现二维的...
• 卷积运算的动图解析
• 卷积运算在信号处理课程中是非常重要的一种数学运算,根据卷积的定义,应用MATLAB软件编程演示了其计算过程,并用声音信号作为实例,演示了声音信号经过卷积运算后的结果,帮助学生更好的理解卷积的计算过程以及卷积定理...
• 主要介绍了python scipy卷积运算的实现方法,文中通过示例代码介绍的非常详细，对大家的学习或者工作具有一定的参考学习价值，需要的朋友们下面随着小编来一起学习学习吧
• 主要介绍了Python使用scipy模块实现一维卷积运算,结合实例形式分析了scipy模块的功能及使用scipy模块进行一维卷积运算的相关操作技巧,需要的朋友可以参考下
• FPGA的可配置卷积运算单元的设计与实现.pdf
• 利用 Fourier-Laplace变换对ω-型超可微函数空间 D (R )以及其上的ω-超广义函数空间 ε(R )的一些乘积和卷积运算进行了讨论,给出了关于卷积问题的一个结果,证明了 D (Ω)关于乘法运 算是封闭的。
• ## 卷积运算

千次阅读 多人点赞 2018-06-15 17:58:19
转自：https://www.cnblogs.com/sevenyuan/p/7810755.html原创：https://www.zhihu.com/question/22298352从数学上讲，卷积就是一种运算。某种运算，能被定义出来，至少有以下特征：首先是抽象的、符号化的其次，在...

转自：https://www.cnblogs.com/sevenyuan/p/7810755.html

原创：https://www.zhihu.com/question/22298352

从数学上讲，卷积就是一种运算。

某种运算，能被定义出来，至少有以下特征：

• 首先是抽象的、符号化的
• 其次，在生活、科研中，有着广泛的作用

比如加法：

•  ，是抽象的，本身只是一个数学符号
• 在现实中，有非常多的意义，比如增加、合成、旋转等等

卷积，是我们学习高等数学之后，新接触的一种运算，因为涉及到积分、级数，所以看起来觉得很复杂。

1 卷积的定义

我们称  为  的卷积

其连续的定义为：

其离散的定义为：

这两个式子有一个共同的特征：

这个特征有什么意义？

我们令  ，那么  就是下面这些直线：

如果遍历这些直线，就好比，把毛巾沿着角卷起来：

此处受到 荆哲：卷积为什么叫「卷」积？ 答案的启发。

只看数学符号，卷积是抽象的，不好理解的，但是，我们可以通过现实中的意义，来习惯卷积这种运算，正如我们小学的时候，学习加减乘除需要各种苹果、糖果来帮助我们习惯一样。

我们来看看现实中，这样的定义有什么意义。

2 离散卷积的例子：丢骰子

我有两枚骰子：

把这两枚骰子都抛出去：

求：

这里问题的关键是，两个骰子加起来要等于4，这正是卷积的应用场景。

我们把骰子各个点数出现的概率表示出来：

那么，两枚骰子点数加起来为4的情况有：

因此，两枚骰子点数加起来为4的概率为：

符合卷积的定义，把它写成标准的形式就是：

3 连续卷积的例子：做馒头

楼下早点铺子生意太好了，供不应求，就买了一台机器，不断的生产馒头。

假设馒头的生产速度是  ，那么一天后生产出来的馒头总量为：

馒头生产出来之后，就会慢慢腐败，假设腐败函数为  ，比如，10个馒头，24小时会腐败：

想想就知道，第一个小时生产出来的馒头，一天后会经历24小时的腐败，第二个小时生产出来的馒头，一天后会经历23小时的腐败。

如此，我们可以知道，一天后，馒头总共腐败了：

这就是连续的卷积。

4 图像处理

4.1 原理

有这么一副图像，可以看到，图像上有很多噪点：

高频信号，就好像平地耸立的山峰：

看起来很显眼。

平滑这座山峰的办法之一就是，把山峰刨掉一些土，填到山峰周围去。用数学的话来说，就是把山峰周围的高度平均一下。

平滑后得到：

4.2 计算

卷积可以帮助实现这个平滑算法。

有噪点的原图，可以把它转为一个矩阵：

然后用下面这个平均矩阵（说明下，原图的处理实际上用的是正态分布矩阵，这里为了简单，就用了算术平均矩阵）来平滑图像：

记得刚才说过的算法，把高频信号与周围的数值平均一下就可以平滑山峰。

比如我要平滑  点，就在矩阵中，取出  点附近的点组成矩阵  ，和  进行卷积计算后，再填回去：

要注意一点，为了运用卷积，  虽然和  同维度，但下标有点不一样：

我用一个动图来说明下计算过程：

写成卷积公式就是：

要求  ，一样可以套用上面的卷积公式。

这样相当于实现了  这个矩阵在原来图像上的划动（准确来说，下面这幅图把  矩阵旋转了  ）：

展开全文
• 【OpenCV学习笔记】之卷积及卷积算子（convolution）_点滴成海~的博客-CSDN博客_卷积算子（关于卷积运算） opencv RNG函数 - 0MrMKG - 博客园（对于RNG函数的解答） （一）首先是对于边缘的填充（避免有些像素卷积...

参考：

opencv RNG函数 - 0MrMKG - 博客园（对于RNG函数的解答）

（一）首先是对于边缘的填充（避免有些像素卷积不了）

C++ void copyMakeBorder（
Mat src, // 输入图像
Mat dst, // 添加边缘图像
int top, // 边缘长度，一般上下左右都取相同值，
int bottom,
int left,
int right,
int borderType // 边缘类型
Scalar value ）

关于borderType的值：

- BORDER_CONSTANT – 填充边缘用指定像素值

- BORDER_REPLICATE – 填充边缘像素用已知的边缘像素值。

- BORDER_WRAP – 用另外一边的像素来补偿填充
下面实现对于图片边缘地区进行填补像素：#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat Origin = imread("0003.jpg");
if (!Origin.data)
{
cout << "ERROR" << endl;
return -1;
}
Mat OutPut1 = Mat(Origin.size(), Origin.type());
Mat OutPut2 = Mat(Origin.size(), Origin.type());
Mat OutPut3 = Mat(Origin.size(), Origin.type());
int added_cols = Origin.cols * 0.06;
int added_rows = Origin.rows * 0.06;
RNG rng(14);
Scalar color = (rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
imshow("OUTPUT    BORDER_ISOLATED", OutPut1);
imshow("OUTPUT    BORDER_DEFAULT", OutPut2);
imshow("OUTPUT    BORDER_CONSTANT", OutPut3);
waitKey(0);

}

（二）卷积运算代码基础

<1>自定义卷积模糊：

卷积核的定义，以及调用卷积核的函数Api：

 Mat Model = (Mat_<char>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
C++ void filter2D(
Mat src, //输入图像
Mat dst, // 模糊图像
int depth, // 图像深度32/8
Mat kernel, // 卷积核/模板
Point anchor, // 锚点位置
double delta // 计算出来的像素+delta)其中 kernel是可以自定义的卷积核
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat Input = imread("0004.jpg");
Mat Output_1 = Mat(Input.size(), Input.type());
Mat Output_2 = Mat(Input.size(), Input.type());
Mat Output_3 = Mat(Input.size(), Input.type());
if (!Input.data)
{
cout << "ERROR" << endl;
return -1;
}
Mat Model_1 = (Mat_<char>(3,3) << 0, 1 , 0, 0, 1, 0, 0, 1, 0);
Mat Model_2 = (Mat_<char>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);
Mat Model_3 = (Mat_<char>(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);
Point ANCHOR = Point(-1, -1);

filter2D(Input, Output_1,-1, Model_1,ANCHOR,BORDER_DEFAULT);
filter2D(Input, Output_2, -1, Model_2, ANCHOR,100, BORDER_DEFAULT);
filter2D(Input, Output_3, -1, Model_3, ANCHOR,100 ,BORDER_DEFAULT);
imshow("input", Input);
imshow("output1", Output_1);
imshow("output2", Output_2);
imshow("output3", Output_3);
waitKey(0);
}

<2>Sobel算子：

关于sobel算子具体内容，移步：

科学网—Sobel算子的数学基础 - 彭真明的博文

OpenCV函数Sobel算子详解-代码狗

C++ void Sobel (
InputArray Src // 输入图像
OutputArray dst// 输出图像，大小与输入图像一致
int depth // 输出图像深度.
Int dx  // X方向，几阶导数
int dy // Y方向，几阶导数
int ksize, SOBEL算子kernel大小，必须是1、3、5、7、
double scale  = 1
double delta = 0
int borderType = BORDER_DEFAULT)

参数解释：
src：原图ddepth：处理结果图像深度，一般我们都填-1，即与原图深度相同。但在这里我们需要填写cv2.CV_64F。简单来说就是如果填写-1，我们在计算梯度时产生的负数就会被程序默认为0，导致有一边的边缘出不来。而cv2.CV_64F范围更大，可以保留负数。dx：计算x方向的梯度dy：计算y方向的梯度ksize：卷积核的尺寸。默认为3，即3*3的矩阵。原文链接：https://blog.csdn.net/weixin_45939019/article/details/104410567
//改进版本的sobel算子：C++ void Scharr (                    InputArray Src // 输入图像                    OutputArray dst// 输出图像，大小与输入图像一致                    int depth // 输出图像深度.                     Int dx.  // X方向，几阶导数                    int dy // Y方向，几阶导数.                     double scale  = 1                    double delta = 0                    int borderType = BORDER_DEFAULT)

（to be continued。。。。。。）

（三）常用卷积核

以下为原图片：

<1>什么都不处理（3*3）

很容易理解，就是0*8+中间原像素值

<2>图像锐化滤波器Sharpness Filter（3*3）（梯度锐化和拉普拉斯锐化）

注意一下，中间值为8就是边缘检测，为9就是原图的图像锐化

另外，如果卷积核更大，则锐化的程度也会更细致。

具体分析见：

Matlab图像处理—锐化滤波器__三三_的博客-CSDN博客_锐化滤波

<3>边缘检测Edge Detection

相当于求导的离散版本：你将当前的像素值减去前一个像素值，这样你就可以得到这个函数在这两个位置的差别或者斜率。

上面的是垂直边缘检测，以此类推，可以实现水平和斜向45度的边缘检测。

<4>Canny边缘检测Edge Detection

<5>浮雕Embossing Filter

浮雕滤波器可以给图像一种3D阴影的效果。只要将中心一边的像素减去另一边的像素就可以了。这时候，像素值有可能是负数，我们将负数当成阴影，将正数当成光，然后我们对结果图像加上128的偏移。这时候，图像大部分就变成灰色了。（转载）

这里我将灰度值调高了100

<6>均值模糊Box Filter (Averaging)

注意这里的1应该是十三分之一，这里没有处理，只是将最后输出的图片的灰度值更改了。

均值就得求平均。

你想要更模糊的效果，加大滤波器的大小即可。或者对图像应用多次模糊也可以。

<7>高斯模糊

均值模糊很简单，但不是很平滑。高斯模糊就有这个优点，所以被广泛用在图像降噪上。特别是在边缘检测之前，都会用来移除细节。高斯滤波器是一个低通滤波器。（转载）

低通滤波可以简单的认为：设定一个频率点，当信号频率高于这个频率时不能通过，在数字信号中，这个频率点也就是截至频率，当频域高于这个截止频率时，则全部赋值为0。因为在这一处理过程中，让低频信号全部通过，所以称为低通滤波。

低通过滤的概念存在于各种不同的领域，诸如电子电路，数据平滑，声学阻挡，图像模糊等领域经常会用到。

在数字图像处理领域，从频域看，低通滤波可以对图像进行平滑去噪处理。

//_src _IN_ 输入的源影像
//_dst _OUT_ 输出的目标影像
//kSize 核大小 如果大小为负数的话，那么根据输入的sigma进行计算
//ksize 大小可以为1，3，5，7，最大值为7
//计算的公式为 sigma = 0.3\*((ksize - 1)\*0.5 - 1) + 0.8
//sigmal1 X方向上的sigma值
//sigmal2 Y方向上的sigma值
//如果sigmal值为负数的话，那么使用默认的滤波过滤器
void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
double sigma1, double sigma2,
int borderType )

<8>运动模糊Motion Blur

(to be continued.......)

(还有很多要补充的）

展开全文
• 卷积神经网络（Convolutional Neural Network，CNN）针对全连接网络 的局限做出了修正，加入了卷积层（Convolution层）和池化层（Pooling 知 层）。...单通道，二维卷积运算示例： 如上图所示，红色的方框圈中的数

卷积神经网络（Convolutional Neural Network，CNN）针对全连接网络 的局限做出了修正，加入了卷积层（Convolution层）和池化层（Pooling 知 层）。

CNN被广泛应用于图像识别、语音识别等各种场合，在图像识别的比赛中， 基于深度学习的方法几乎都以CNN为基础（比如，AlexNet、VGGNet、 Google Inception Net及微软的ResNet等）上。近几年深度学习大放异彩， CNN功不可没。

## 单通道，二维卷积运算示例：

如上图所示，红色的方框圈中的数字和卷积核乘积再相加得到输出数据。

## 单通道，二维，带偏置的卷积示例：

带偏置的计算实在上述乘积运算之后加上偏置。

## 输出矩阵的大小计算

卷积运算输出矩阵大小计算公式

其中，输入大小为(H, W)，滤波器大小为(FH, FW)，输出大小为(OH, OW)，填 充为P，步幅为S。例如：输入大小（28,31）；填充2；步幅3；滤波器大小 (5,5)，则输出矩阵大小为：

## 多通道卷积计算

多通道卷积会按通道进行输入数据和滤波器的卷积运算，并将结果相加， 从而得到输出

多通道、多卷积核卷积计算：

• 每个通道先与第一组卷积核执行卷 积，然后多通道结果叠加，产生一 个输出
• 每个通道与下一组卷积核执行卷积， 产生另一个输出
• 有多少组卷积核，就有多少个通道 输出
展开全文
• ## 卷积运算原理

万次阅读 多人点赞 2019-12-26 22:08:56
卷积运算 内容选自吴恩达老师的深度学习课程当中，在此记录。以边缘检测为例，介绍卷积是如何进行运算的。 一、边缘检测示例 首先是垂直边缘检测，对左边的一个6×6的灰度图像进行卷积运算，中间3×3的即为我们通常...
• 在TensorFlow中，通过tf.nn.cinv2d函数可以方便的实现2D卷积运算。tf.nn.conv2d基于输入X:[b,h,w,]和卷积核W:[k,k,,]进行卷积运算，得到输出O[b,,,],其中表示输入通道数，表示卷积核的数量，也是输出特征图的通道数...
• 滤波通常是指对图像中特定频率的分量进行过滤或抑制。图像滤波是在尽可能保留图像细节特征的条件下对目标图像的噪声进行抑制，是常用的图像预处理操作。...线性滤波器就是指基于线性核的滤波，也就是卷积运算
• MATLAB中实现卷积运算和理论分析中的卷积运算有什么区别。 欢迎使用Markdown编辑器 你好！ 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章，了解一下...
• 卷积运算在测试信号处理中占有重要地位，特别是关于信号的时域与变换域分析它成为沟通时-频域关系的一个桥梁。 该程序输入两个信号，且信号类型可选，例如正弦信号，冲击信号等，并采用卷积滑动杆来控制卷积过程。
• 卷积运算的机理相似，但滤波器首先要旋转180度。 相关运算的计算步骤： （1）移动相关核的中心元素，使它位于输入图像待处理像素的正上方; （2）将输入图像的像素值作为权重，乘以相关核; （3）将上面各步得到的...
• 使用C语言和卷积运算实现N点移动平均滤波器程序。 输入信号如下所示： (1)    x[n]=sin(πn/64)(1)\;\;x[n]=sin(\pi n/64)(1)x[n]=sin(πn/64) (2)    x[n]=sin(πn/64)+0.2sin(10πn/64)+0.1sin(20πn/64)...
• 实验一matlab实现序列卷积运算 精品文档 精品文档 收集于网络如有侵权请联系管理员删除 收集于网络如有侵权请联系管理员删除 精品文档 收集于网络如有侵权请联系管理员删除 前言 MATLAB 是一套功能强大的工程计算及...
• 卷积运算意义-CV领域 利用全连接网络进行图像识别一般会遇到两个问题： （1）可训练参数过多，且容易过拟合； （2）模型准确率不够高。 为解决这两个问题，相关学者提出了卷积神经网络模型，早期在CV领域的卷积神经...
• ## 全网最全的卷积运算过程

千次阅读 多人点赞 2021-04-10 14:44:36
卷积运算 1.卷积核的通道（也叫滤波器）的个数得与被卷积的图片通道数相同 eg:输入图片是1024×1024×3，即通道数为3，那么每个卷积核得有3个通道 2.卷积核做的是线性运算，核上的每个值与它滑动到的对应位置上的值...
• ## verilog实现矩阵卷积运算

千次阅读 多人点赞 2019-05-24 09:23:19
verilog实现卷积运算 卷积的运算原理 卷积是一种线性运算，是很多普通图像处理操作的基本算法之一。它提供了两个数组相乘的方式，两个数组拥有不同的大小，但是具有相同的维数，生成了一个用于相同维数的新数组。...
• 还是对于matlab软件的应用以及对于卷积云算的了解
• //输入卷积矩阵 int row1 = 3, col1 = 3; int a[3][3]; //cout<<"输入卷积矩阵的行数："; //cin>>row1; //cout<<"输入卷积矩阵的列数："; //cin>>col1; cout << "输入卷积...

...