常规-分组-深度分离-分组深度分离卷积-参数量-计算量-dilation-python实现

article/2025/11/6 11:16:44

不同的卷积操作

  • 本文所用样本
  • 一般的卷积(常规的)
  • 分组卷积
  • 深度分离卷积
    • 逐通道卷积(depthwise conv)
    • 逐点卷积 (pointwise conv)
  • 分组深度分离卷积
  • 上面卷积总结
  • 卷积的dilation

本文所用样本

x = t o r c h . z e r o s ( 5 , 5 , 4 ) x = torch.zeros(5,5,4) x=torch.zeros(5,5,4), 维度分别表示(w, h, channels)

import torch
x = torch.zeros(5,5,4)
print(x.size())
# torch.Size([5, 5, 4])

假设我们期望卷积后,样本的大小变为(3, 3, 10)

一般的卷积(常规的)

为方便理解,示意图如下:
在这里插入图片描述
图片来源于:常规卷积.png
卷积后特征大小的计算公式:
w n e w = ( w − k + 2 × p ) s + 1 w_{new} = \frac{(w - k + 2\times p)}{s} +1 wnew=s(wk+2×p)+1
所以我们选(3,3,4,10,0,1)的卷积就可以了,维度分别对应(kernel_size_h, kernel_size_w, input_channel, output_channel, padding, stride)

import torch.nn as nn
x = x.transpose(0, 2) # 卷积的操作输入样本维度:(batchsize,channel,h,w),由于这里一个样本所以batchsize是1,我们需把channel放在首维。
conv_regular = nn.Conv2d(4, 10 , kernel_size=3, stride = 1)
y_regular = conv_regular(x)
print(y_regular.size())
# 计算卷积参数
num_params_regular = sum(p.numel() for p in conv_regular.parameters())
print('the number of model params: {}'.format(num_params_regular))
# torch.Size([10, 3, 3])
# the number of model params: 370

卷积层参数数量的计算公式:
n u m p a r a m e t e r = k e r n e l s i z e h × k e r n e l s i z e w × i n p u t c h a n n e l × o u t p u t c h a n n e l num_{parameter} = kernelsize_h \times kernelsize_w \times input_{channel} \times output_{channel} numparameter=kernelsizeh×kernelsizew×inputchannel×outputchannel
所以上面的卷积参数为: 3 ∗ 3 ∗ 4 ∗ 10 = 360 3*3*4*10=360 33410=360 但通过上面程序得出的参数为370,多了输出通道的个数—10。这是因为卷积核的每次滑动,输入到神经元的计算: f ( x ) + b i a s f(x)+bias f(x)+bias f ( x ) f(x) f(x)j就表示大小为输出通道为 k e r n e l s i z e h × k e r n e l s i z e w × i n p u t c h a n n e l kernelsize_h \times kernelsize_w \times input_{channel} kernelsizeh×kernelsizew×inputchannel 的卷积核与滑动时重叠的样本点乘再累加。10就是相当于有10个卷积核,每个卷积核有一个偏置,所以根据上面公式计算参数会少output_channel的数量。但通常我们会忽略偏置,直接用上面的公式计算参数量。
卷积层的计算量(乘法)计算公式:
k e r n e l s i z e h × k e r n e l s i z e w × ( h − k e r n e l s i z e h + 1 ) × ( w − k e r n e l s i z e w + 1 ) × i n p u t c h a n n e l × o u t p u t c h a n n e l kernelsize_h \times kernelsize_w \times (h-kernelsize_h+1) \times (w-kernelsize_w+1) \times input_channel \times output_channel kernelsizeh×kernelsizew×(hkernelsizeh+1)×(wkernelsizew+1)×inputchannel×outputchannel
所以上面的卷积操作的计算量为: 3 ∗ 3 ∗ ( 5 − 3 + 1 ) ∗ ( 5 − 3 + 1 ) ∗ 4 ∗ 10 = 3240 3*3*(5-3+1)*(5-3+1)*4*10=3240 33(53+1)(53+1)410=3240

分组卷积

分组的意思就是卷积时将通道进行分组,然后再计算。上面的常规卷积,每个卷积核的大小都是kernelsizekernelsize样本通道,即每个卷积核将样本的所有通道一起计算。示意图理解如下。
在这里插入图片描述
图片来源于: 分组卷积.png.
卷积后最终的(h,w,channel)都与上面常规的卷积一样。只是内部会先对通道进行分组,然后再进行常规的卷积,然后再将结果拼接起来。代码也很好实现,就在后面加一个“groups”参数就行了。

conv_group = nn.Conv2d(4, 10 , kernel_size=3, stride = 1, groups=2)
y_group = conv_group(x)
print(y_group.size())
num_params_regular = sum(p.numel() for p in conv_group.parameters())
print('the number of group conv params: {}'.format(num_params_regular))
# torch.Size([10, 3, 3])
# the number of group conv params: 190

分组卷积层参数数量的计算公式:
n u m p a r a m e t e r = k e r n e l s i z e h × k e r n e l s i z e w × i n p u t c h a n n e l g r o u p s × o u t p u t c h a n n e l g r o u p s × g r o u p s num_{parameter} = kernelsize_h \times kernelsize_w \times \frac{input_{channel}}{groups} \times \frac{output_{channel}}{groups} \times groups numparameter=kernelsizeh×kernelsizew×groupsinputchannel×groupsoutputchannel×groups
所以上面分组卷积参数为: 3 ∗ 3 ∗ 4 / 2 ∗ 10 / 2 ∗ 2 = 180 3*3*4/2*10/2*2=180 334/210/22=180,也和上面一样会多output_channel个偏置。
分组卷积层的计算量(乘法)计算公式:
k e r n e l s i z e h × k e r n e l s i z e w × ( h − k e r n e l s i z e h + 1 ) × ( w − k e r n e l s i z e w + 1 ) × i n p u t c h a n n e l g r o u p s × o u t p u t c h a n n e l g r o u p s × g r o u p s kernelsize_h \times kernelsize_w \times (h-kernelsize_h+1) \times (w-kernelsize_w+1) \times \frac{input_{channel}}{groups} \times \frac{output_{channel}}{groups} \times groups kernelsizeh×kernelsizew×(hkernelsizeh+1)×(wkernelsizew+1)×groupsinputchannel×groupsoutputchannel×groups
所以上面分组卷积的计算量为: 3 ∗ 3 ∗ ( 5 − 3 + 1 ) ∗ ( 5 − 3 + 1 ) ∗ 4 / 2 ∗ 10 / 2 ∗ 2 = 1620 3*3*(5-3+1)*(5-3+1)*4/2*10/2*2=1620 33(53+1)(53+1)4/210/22=1620
所以可以看出分组卷积能在输出维度一样的情况下,使得网络参数更少,计算量也更少-----参数和计算量都相当于除了组数。
但分组卷积存在问题:组与组通道之间信息不流通。
解决的办法可以是在叠卷积层时,不同层用不同的组数,如交替使用2,3的组数。

深度分离卷积

深度分离卷积由两部分组成:

逐通道卷积(depthwise conv)

逐通道卷积时分组卷积的一个特例:input_channel = output_channel = groups, 分组数等于输入通道数等于输出通道数。
便于理解,示意图如下图所示。
在这里插入图片描述
图片来源于: 逐通道卷积.png
样本通过4通道的逐通道卷积:

conv_depthwise = nn.Conv2d(4, 4 , kernel_size=3, stride = 1, groups=4)
y_depthwise = conv_depthwise(x)
print(y_depthwise.size())
num_params_regular = sum(p.numel() for p in conv_depthwise.parameters())
print('the number of depthwise conv params: {}'.format(num_params_regular))
# torch.Size([4, 3, 3])
# the number of depthwise conv params: 40

可见 样本大小是我们期望的大小,只是通道数和原来一样,所以这只是深度分离卷积的第一步----逐深度卷积。
由于这是分层卷积的一个特例,所以我们带入分层卷积的参数计算公式可得,这里逐层卷积参数为: 3 ∗ 3 ∗ 1 ∗ 1 ∗ 4 = 36 3*3*1*1*4=36 33114=36 然后再加4个卷积核的偏置。
计算量: 3 ∗ 3 ∗ ( 5 − 3 + 1 ) ∗ ( 5 − 3 + 1 ) ∗ 1 ∗ 1 ∗ 4 = 320 3*3*(5-3+1)*(5-3+1)*1*1*4=320 33(53+1)(53+1)114=320

逐点卷积 (pointwise conv)

用kernel_size=1的卷积,只改变特征的通道数,实现了深度方向的加权组合----弥补了第一步逐通道卷积时通道分组导致信息在通道之间不流通的缺点。
为便于理解,逐点卷积的示意图如下。
在这里插入图片描述

图片来源于:逐点卷积.png

conv_pointwise = nn.Conv2d(4, 10 , kernel_size=1, stride = 1)
y_pointwise = conv_pointwise(y_depthwise)
print(y_pointwise.size())
num_params_regular = sum(p.numel() for p in conv_pointwise.parameters())
print('the number of pointwise conv params: {}'.format(num_params_regular))
# torch.Size([10, 3, 3])
# the number of pointwise conv params: 50

逐点卷积可以看成kernel_size=1的常规的卷积,所以上面的卷积的参数量: 1 ∗ 1 ∗ 4 ∗ 10 = 40 1*1*4*10=40 11410=40 ,然后加10个卷积核的偏置。
计算量: 1 ∗ 1 ∗ ( 3 − 1 + 1 ) ∗ ( 3 − 1 + 1 ) ∗ 4 ∗ 10 = 360 1*1*(3-1+1)*(3-1+1)*4*10=360 11(31+1)(31+1)410=360

深度分离卷积就是逐通道卷积和逐点卷积的组合。即先进行逐通道卷积,将大小(h,w)满足目标,然后又通过逐点卷积将通道(c)满足目标。
从上面分析可得出深度分离卷积的参数量: 40 + 50 = 90 40+50=90 40+50=90
计算量为: 320 + 360 = 680 320+360=680 320+360=680
可见相对于分组卷积,深度分离卷积的参数和计算量进一步减小。

分组深度分离卷积

这个的意思就是先通道进行分组,然后再每组上做深度分离卷积。这样参数和计算量会进一步减小。
为便于理解,示意图如下。
在这里插入图片描述
图片来源于:论文:SMALL-FOOTPRINT KEYWORD SPOTTING ON RAWAUDIO DATA WITH SINC-CONVOLUTIONS

import torch.nn as nn
import torch.nn.functional as F
group = 2
input_channel = 4
output_channel = 10
conv_GDSconv = nn.ModuleList()
group_in_channel = int(input_channel/group)       # 分组注意整除,这里我只考虑了简单情况,没有完善。
group_out_channel = int(output_channel/group)
for i in range(group):i_groupp = nn.Sequential(nn.Conv2d(group_in_channel,group_in_channel,3,stride=1,groups=group_in_channel),              nn.Conv2d(group_in_channel, group_out_channel, kernel_size=1, stride=1),)conv_GDSconv.append(i_groupp)
i_c = 0
y_group = []
for block in conv_GDSconv:y_block = block(x[i_c:i_c+group_in_channel,:,:])   # 将x分组,然后每组做深度分离卷积y_group.append(y_block)i_c +=group_in_channel
y_GDSconv = torch.cat(y_group, dim=0)
print(y_GDSconv.size())
num_params_regular = sum(p.numel() for p in conv_GDSconv.parameters())
print('the number of GDS conv params: {}'.format(num_params_regular))
# torch.Size([10, 3, 3])
# the number of GDS conv params: 70

上面代码是分组数为2的分组深度分离卷积。
参数计算量:两组的深度分离卷积,即两组 ( 5 , 5 , 4 / 2 ) → ( 3 , 3 , 10 / 2 ) (5,5,4/2)\rightarrow (3,3,10/2) (5,5,4/2)(3,3,10/2)的深度分离卷积的变换。
每一组的参数: 3 ∗ 3 ∗ 1 ∗ 1 ∗ 2 + 2 ( b i a s ) + 1 ∗ 1 ∗ 4 / 2 ∗ 10 / 2 + 5 ( b i a s ) = 35 3*3*1*1*2 + 2(bias) + 1*1*4/2*10/2 + 5(bias) = 35 33112+2(bias)+114/210/2+5(bias)=35,所以总的参数为70。
计算量:
每一组计算量: 3 ∗ 3 ∗ ( 5 − 3 + 1 ) ∗ ( 5 − 3 + 1 ) ∗ 1 ∗ 1 ∗ 2 + 1 ∗ 1 ∗ ( 3 − 1 + 1 ) ∗ ( 3 − 1 + 1 ) ∗ 4 / 2 ∗ 10 / 2 = 252 3∗3∗(5−3+1)∗(5−3+1)∗1∗1∗2 + 1*1*(3-1+1)*(3-1+1)*4/2*10/2 = 252 33(53+1)(53+1)112+11(31+1)(31+1)4/210/2=252,所以总的参数量:504

上面卷积总结

( 5 , 5 , 4 ) → ( 3 , 3 , 10 ) (5,5,4)\rightarrow (3,3,10) (5,5,4)(3,3,10)的卷积实例而言:

卷积参数量计算量
常规卷积3703240
分组卷积1901620
深度分离卷积90680
分组深度分离卷积70504

卷积的dilation

为了便于理解,dilation卷积的示意图如下:

图1 常规的卷积
图2 dilation=2的卷积

图片来源于:卷积.gif
一般卷积的默认dilation=1, 当我们改变dilation的值后,就会两两卷积点中插入(dilation-1)的空白,如上图所示dilation=2。
用dilation后特征大小的计算公式:
w d i l a t i o n = ( w − d i a l a t i o n × ( k − 1 ) − 1 + 2 × p ) s + 1 w_{dilation} = \frac{(w - dialation\times (k-1) -1 + 2\times p)}{s} +1 wdilation=s(wdialation×(k1)1+2×p)+1
即用了dilation后新的kernel_size= d i a l a t i o n × ( k − 1 ) + 1 dialation\times (k-1) +1 dialation×(k1)+1 引用

conv_dilation = nn.Conv2d(4, 10 , kernel_size=3, stride = 1, dilation=2)
y_dilation = conv_dilation(x)
print(y_dilation.size())
num_params_regular = sum(p.numel() for p in conv_dilation.parameters())
print('the number of dilation conv params: {}'.format(num_params_regular))
# torch.Size([10, 1, 1])
# the number of dilation conv params: 370

dilation的作用一般是可以在相同参数下增大卷积的感受野。
dilatio卷积的感受野计算公式:
r e c e p t i v e f i l e d = ∑ i d i × ( k i − 1 ) receptive_{filed} = \sum_i{d_i\times(k_i-1)} receptivefiled=idi×(ki1)
公式来源于:论文:EFFICIENT KEYWORD SPOTTING USING DILATED CONVOLUTIONS AND GATING
其中, d i , k i d_i,k_i diki分别表示第i层的dilation的值,和第i层的卷积核的值。


http://chatgpt.dhexx.cn/article/pcrr7hsg.shtml

相关文章

深度学习中常用的几种卷积(下篇):膨胀卷积、可分离卷积(深度可分离、空间可分离)、分组卷积(附Pytorch测试代码)

卷积分类 一、膨胀卷积1.介绍2.调用方式3.实例4.缺点 二、可分离卷积1.空间可分离卷积1)介绍2)优点及缺点3)实例 2.深度可分离卷积1)介绍2)优点及缺点3)实例 三、分组卷积1.介绍2.调用方式以及nn.Conv2d的g…

tensorlfow 卷积操作解释

解释一下: tf.keras.layers.Conv2D(filters,kernel_size,strides=(1, 1),padding=valid,data_format=None,dilation_rate=(1, 1),groups=1,activation=None,use_bias=True,kernel_initializer=glorot_uniform,bias_initializer=zeros,kernel_regularizer=None,bias_regulariz…

dilation conv 和 deconv

最近工作要用到dilation conv,在此总结一下空洞卷积,并和deconv进行对比。 dilation conv 首先空洞卷积的目的是为了在扩大感受野的同时,不降低图片分辨率和不引入额外参数及计算量(一般在CNN中扩大感受野都需要使用s>1的con…

Halcon 形态学(膨胀(Dilation)、腐蚀(Erosion))

文章目录 1 形态学概念2 膨胀(Dilation) 算子介绍3 腐蚀(Erosion)算子介绍4 膨胀腐蚀 示例15 腐蚀膨胀 示例26 示例原图7 补充:结构元素概念1 形态学概念 图像的形态学处理是对图像的局部像素进行处理,用于从图像中提取有意义的局部图像细节。 通过改变局部区域的像素形态…

Torch 池化操作大全 MaxPool2d MaxUnpool2d AvgPool2d FractionalMaxPool2d LPPool2d AdaptivePool2d dilation详解

torch 池化操作 1 池化操作2 类型2.1 MaxPool2d()2.2 MaxUnPool2d()2.3 AvgPool2d()2.4 FractionalMaxPool2d()2.5LPPool2d()2.6AdaptiveMaxPool2d()2.7 AdaptiveAvgPool2d() 3 总结 自我学习记录,他人转载请注明出处 1 池化操作 作用: 提取图片重点特征…

nn.Conv2d中的dilation

参考链接:https://blog.csdn.net/jokerxsy/article/details/108614661 nn.Conv2d中的dilation dilation 1: dilation2:

nn.Conv1d\nn.Conv2d以及groups\dilation参数的理解

文章目录 nn.Conv1dnn.Conv2dnn.Conv2d中groups参数和dilation参数的理解groupsdilation 参考 nn.Conv1d 代码: nn.Conv1d(in_channels 16, out_channels 16, kernel_size (3,2,2), stride (2,2,1), padding [2,2,2])如果输入为: x torch.randn(10,16,30,32,34)则: 1…

剪胀角 angle of dilation

Abaqus选择库伦摩尔塑性模型的时候,需要选择摩擦角和剪胀角。摩擦角物理意义明确,但何为剪胀角?如何影响结果呢?(这两个问题,暂无统一解,Abaqus默认剪胀角最小是0.1) The angle of d…

3.TransposedConv2d实现 (含dilation)

[C 基于Eigen库实现CRN前向推理] 第三部分:TransposedConv2d实现 (含dilation) 前言:(Eigen库使用记录)第一部分:WavFile.class (实现读取wav/pcm,实现STFT)第二部分:Conv2d实现第三部分:Tran…

对卷积层dilation膨胀的作用的理解,caffe-ssd dilation Hole算法解析

先转一篇大佬的博客论文阅读笔记:图像分割方法deeplab以及Hole算法解析 下面是caffe-ssd的vgg16输出后的变化,减少了一个pooling,stride1,然后下一层采用了 dilation方法,作用按上面博客说是 既想利用已经训练好的模…

理解Dilation convolution

论文:Multi-scale context aggregation with dilated convolutions 简单讨论下dilated conv,中文可以叫做空洞卷积或者扩张卷积。首先介绍一下dilated conv诞生背景[4],再解释dilated conv操作本身,以及应用。 首先是诞生背景&a…

卷积膨胀 Dilation

参考:卷积的dilation操作 如果我们设置的dilation0的话,效果如图: 蓝色为输入,绿色为输出,可见卷积核为3*3的卷积核 如果我们设置的是dilation1,那么效果如图: 蓝色为输入,绿色为输出,卷积核仍…

卷积核膨胀(dilation)解析

本文转自http://blog.csdn.net/tangwei2014和https://blog.csdn.net/jiongnima/article/details/69487519,转载目的便于自己查看学习 第一位大神解析: deeplab发表在ICLR 2015上。论文下载地址:Semantic Image Segmentation with Deep Conv…

【DL】卷积膨胀 Dilation

Backto DeepLearning Index dilation dilation 是对 kernel 进行膨胀,多出来的空隙用 0 padding。用于克服 stride 中造成的 失真问题。 对应关系是 k d = ( k − 1 ) d + 1 k_{d} = (k -1)\times d + 1 kd​

Pytorch中dilation(Conv2d)参数详解

目录 一、Conv2d 二、Conv2d中的dilation参数 一、Conv2d 首先我们看一下Pytorch中的Conv2d的对应函数(Tensor通道排列顺序是:[batch, channel, height, width]): torch.nn.Conv2d(in_channels, out_channels, kernel_size, str…

Linux的入门

文章目录 1 Linux应用场景2 Linux的应用领域2.1 个人桌面的应用2.2 服务器领域2.3 嵌入式领域 3 Linux 介绍4 Linux 和 Unix 的关系4.1 Linux 的由来:4.2 Linux 与 Unix 的关系 5 安装 vm 和CentOS5.1 基本说明5.2 网络连接的理解 6 虚拟机克隆7 虚拟机快照8 虚拟机…

Linux 快速入门到实战【一】

一、操作系统概述 1. 计算机原理 ​ 现代计算机大部分都是基于冯.诺依曼结构,该结构的核心思想是将程序和数据都存放在计算机中,按存储器的存储程序首地址执行程序的第一条指令,然后进行数据的处理计算。 ​ 计算机应包括运算器、控制器、…

linux快速入门 --- 常用指令 学习

目录 为什么要学Linux? Linux的安装 安装 使用finalshell连接虚拟机 了解一下Linux的目录结构(不需要记忆) Linux中常用的命令(重点) Linux命令初体验--几个常用命令 Linux命令格式 显示指定目录下的内容 ls和…

Linux命令快速入门

Linux命令初体验----01几个常用命令 序号命令对应英文作用1lslist查看当前目录下的内容2pwdprint work directory查看当前所在目录3cd[目录名]change directory切换目录4touch[文件名]touch如果文件不存在,新建文件5mkdir[目录名]make directory创建目录6rm[文件名…

如何快速入门并轻松简单的学习Linux?

首先,写这篇文章的初衷是写给那些想学习linux,并真正想用它做些有意义事情的人。希望能帮助初学者找到正确的学习linux思维或者方向。 1、做好思想准备 如果你想系统的学习linux,你必须做好思想准备。如果你真正想系统的学习linux&#xff0c…