torch.nn.Conv2d详解
注意:这里展示的是本篇博文写时的版本最新的实现,但是后续会代码可能会迭代更新,建议对照 官方文档 进行学习。
首先看一下这个类的定义:
class Conv2d(_ConvNd):# 初始化函数,这里主要了解有哪些参数传进来就可以了def __init__(self,in_channels: int,out_channels: int,kernel_size: _size_2_t,stride: _size_2_t = 1,padding: _size_2_t = 0,dilation: _size_2_t = 1,groups: int = 1,bias: bool = True,padding_mode: str = 'zeros' # TODO: refine this type):#————————————————看到这就可以了————————————————————kernel_size = _pair(kernel_size)stride = _pair(stride)padding = _pair(padding)dilation = _pair(dilation)super(Conv2d, self).__init__(in_channels, out_channels, kernel_size, stride, padding, dilation,False, _pair(0), groups, bias, padding_mode)def _conv_forward(self, input, weight):if self.padding_mode != 'zeros':return F.conv2d(F.pad(input, self._reversed_padding_repeated_twice, mode=self.padding_mode),weight, self.bias, self.stride,_pair(0), self.dilation, self.groups)return F.conv2d(input, weight, self.bias, self.stride,self.padding, self.dilation, self.groups)# 前向传播计算def forward(self, input: Tensor) -> Tensor:return self._conv_forward(input, self.weight)
上面就是Cov2d这个类的源码实现,是不是感觉代码特别少?是不是突然对掌握它信心倍增!
从整体上来看:
Conv2d是一个类,它包含了做卷积运算所需要的参数(__init__函数),以及卷积操作(forward函数)。
再来看一下它的详细参数:
一共九个参数,一般用前三个就可以处理一般的任务:
in_channels
:输入通道数目out_channels
:输出通道数目kernel_size
:卷积核大小,如果输入是一个值,比如 333,那么卷积核大小就是 3×33 \times 33×3 ,如果不想卷积核宽和高相等,还可以输入tuple类型数据,比如: (3,5)(3, 5)(3,5)stride
:步长大小,跟上面卷积核参数一样,如果输入是一个值,比如 222 ,步长就是 2×22 \times 22×2 ,还可以输入元组 (2,1)(2, 1)(2,1) ,表示卷积核每次向右移动 111 个步长,向下移动 222 个步长。padding
:填充,参数表示在周围补0的情况。补0的方向为上、下、左、右四个方向。如果是输入是单个值,比如1,就是在上下左右四个方向补一圈0。如果输入是元组比如(2,1)
,表示在上下两个方向各补两行0,在左右两个方向各补一列0。dilation
:进行扩展卷积需要的参数。groups
:进行分组卷积需要的参数。(有需要自行深入了解)bias
:偏置,布尔类型,默认为True
,即增加一个学习的偏置项。padding_mode
:填充的模式,默认是zero
,还可以选择reflect
、replicate
、circular
。(有需要自行深入了解)
首先是关于输入通道数 in_channels
和输出通道数 out_channels
的解释:
如果对通道是什么还不太理解可以去看我的这篇博客:如何理解卷积神经网络中的通道(channel)
如果卷积核输入的是原始的图片,那么我们可以根据图片类型决定图片的输入通道数,如果是RGB图片, in_channels=3
,如果是灰度图像,in_channels=1
。输出通道数需要我们自己指定,具体指定多少需要根据经验。
如果是第二层或者更多层卷积,当前层的输入通道数就是上一层卷积的输出通道数,当前层的输出通道数需要自己指定。
关于卷积核的解释:
这里的卷积核参数只是指定卷积核的宽度和高度,对于多通道的卷积,代码内部会根据输入通道数初始化对应的卷积核数目,即:如果输入是3通道,那么就会有三个我们指定宽高的卷积核做相应的卷积操作。
关于步长的解释:
步长指的是卷积核在输入矩阵的上每次移动几步。移动方向由两个,向右或者向下。分别由两个值指定。
关于填充的解释:
填充的主要目的是为了充分利用输入图片的边缘信息。
关于为什么需要填充,可以参考这篇博客:CNN基础知识——卷积(Convolution)、填充(Padding)、步长(Stride)
关于扩张(dilation)参数的解释:
本质上就是扩大卷积核,比如将 3×33 \times 33×3 的扩大为 7×77 \times 77×7 的,然后对扩大的部分用0进行填充,
目的是扩大感受野,捕获多尺度上下文信息。
具体怎么扩张,详细请参考:
【1】如何理解扩张卷积(dilated convolution)
【2】总结-空洞卷积(Dilated/Atrous Convolution)
关于分组(group)的解释:
对于一般的卷积神经网络,假设通道数有100个,那么我们需要100个卷积核对这100个通道分别做卷积操作,然后求和,最后得到1个特征图。如果我们需要得到30个特征图,就需要30*100=3000个卷积核。参数量非常大。
而对于分组卷积,依然假设通道数有100个,我们分成两组,每组50个通道数,分别对每组单独做卷积操作,每组需要50个卷积核,总的卷积核数目没变,但是我们每组可以得到2个特征图。如果我们分成4组,每组25个通道数,最终可以得到4个特征图。
也就是说,我们在不增加参数量的情况下,得到了更多的特征图。这是分组的优势之一,对于分组的通道,我们可以在不同的GPU上并行训练,加速训练过程。
更详细的解释参考:
卷积网络基础知识—Group Convolution分组卷积
关于偏置项的解释:
这个项是个布尔类型值,如果为True,就会在训练的时候加上偏置项,反之,不会。默认是True。
关于填充模式的解释:
我们一般情况下对于填充的数据,默认是0。还可以选择常数填充、镜像填充、重复填充.。
常数填充就是指定一个常数值进行填充,如果为0,等价于零填充;
镜像填充是指对图像边缘进行镜像对称的填充;
重复填充指的是用图像边缘的像素值进行填充。
详细参考:PyTorch中的padding(边缘填充)操作
OK,到这里就对所有的参数解释完了。下面我们解释一下,经过一次卷积操作之后,图像形状如何进行变化。
图像形状的变化规则
卷积神经网络的输入: N,Cin,Hin,WinN,C_{in},H_{in},W_{in}N,Cin,Hin,Win
卷积神经网络的输出: N,Cout,Hout,WoutN,C_{out},H_{out},W_{out}N,Cout,Hout,Wout
其中, NNN 表示批处理的大小,即batch_size。CinC_{in}Cin 和 CoutC_{out}Cout 分别表示输入和输出通道数。 HinH_{in}Hin 和 WinW_{in}Win 表示输入图片的高和宽,以像素为单位。同理, HoutH_{out}Hout 和 WoutW_{out}Wout 表示输出图片的高和宽。
OK,我们来看一下输入输出是怎么变化的。
首先是batch_size,卷积神经网络并不会改变这个参数;然后是 CinC_{in}Cin 和 CoutC_{out}Cout 这两个参数是我们初始化的时候就指定的;实际上卷积神经网络改变的是图片的尺寸,图片尺寸变化公式为:
Hout=⌊Hin+2×padding⌊0⌋−dilation⌊0⌋×(kernel_size⌊0⌋−1)−1stride⌊0⌋+1⌋H_{out}=\lfloor \frac{H_{in} + 2 \times padding\lfloor 0 \rfloor - dilation \lfloor 0 \rfloor \times (kernel\_size\lfloor 0 \rfloor - 1)-1}{stride\lfloor 0 \rfloor} + 1 \rfloor Hout=⌊stride⌊0⌋Hin+2×padding⌊0⌋−dilation⌊0⌋×(kernel_size⌊0⌋−1)−1+1⌋
Wout=⌊Win+2×padding⌊1⌋−dilation⌊1⌋×(kernel_size⌊1⌋−1)−1stride⌊1⌋+1⌋W_{out}=\lfloor \frac{W_{in} + 2 \times padding\lfloor 1 \rfloor - dilation \lfloor 1 \rfloor \times (kernel\_size\lfloor 1 \rfloor - 1)-1}{stride\lfloor 1 \rfloor} + 1 \rfloor Wout=⌊stride⌊1⌋Win+2×padding⌊1⌋−dilation⌊1⌋×(kernel_size⌊1⌋−1)−1+1⌋
然后我们用一段代码测试一下:
import torch
import torch.nn as nn
# in_channels=16, out_channels=33, kernel_size=(3, 5)
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))
print(m)
# 我们随机构造输入数据
# N=20, C_in=16, H_in=50, W_in=100
# 对应上面说的 (N, C, H, W)
input = torch.randn(20, 16, 50, 100)
output = m(input)
print(output.shape)
结果:
Conv2d(16, 33, kernel_size=(3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))
torch.Size([20, 33, 26, 100])
上面的torch.size表示输出的形状:
batch_size=20batch\_size=20batch_size=20
out_channel=33out\_channel=33out_channel=33
Hout=26H_{out}=26Hout=26
Wout=100W_{out}=100Wout=100
我们带入数据实际计算一下:
Hout=⌊50+2×4−3×(3−1)−12+1⌋=26H_{out}= \lfloor \frac{50 + 2 \times 4 - 3 \times (3 - 1) - 1}{2} + 1\rfloor=26 Hout=⌊250+2×4−3×(3−1)−1+1⌋=26
Wout=⌊100+2×2−1×(5−1)−11+1⌋=100W_{out}=\lfloor \frac{100 + 2 \times 2 - 1 \times (5 - 1) - 1}{1} + 1 \rfloor = 100 Wout=⌊1100+2×2−1×(5−1)−1+1⌋=100
Conv2d中的权重和偏置项
最后我们有必要了解一下Conv2d的两个变量:
~Conv2d.weight
其形状为: (out_channels,in_channelsgroup,kernel_size[0],kernel_size[1])(out\_channels, \frac{in\_channels}{group},kernel\_size[0], kernel\_size[1])(out_channels,groupin_channels,kernel_size[0],kernel_size[1])
数据从 U(−k,k)\mathcal{U}(-\sqrt{k}, \sqrt{k})U(−k,k) 中取样,其中 k=groupsCin∗∏i=01kernel_size[i]k=\frac{groups}{C_{in}*\prod_{i=0}^1kernel\_size[i]}k=Cin∗∏i=01kernel_size[i]groups
~Conv2d.bias
其形状为: (out_channels)(out\_channels)(out_channels)
数据从 U(−k,k)\mathcal{U}(-\sqrt{k}, \sqrt{k})U(−k,k) 中取样,其中 k=groupsCin∗∏i=01kernel_size[i]k=\frac{groups}{C_{in}*\prod_{i=0}^1kernel\_size[i]}k=Cin∗∏i=01kernel_size[i]groups
还是上面的代码,我们可以查看这个卷积神经网络的权重和偏置的形状:
import torch
import torch.nn as nn
# in_channels=16, out_channels=33, kernel_size=(3, 5)
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))
print(m)
# 我们随机构造输入数据
# N=20, C_in=16, H_in=50, W_in=100
# 对应上面说的 (N, C, H, W)
input = torch.randn(20, 16, 50, 100)
output = m(input)
print(m.weight.shape)
print(m.bias.shape)
输出:
torch.Size([33, 16, 3, 5])
torch.Size([33])
torch.nn.Conv2d详解相关推荐
- PyTorch中的torch.nn.Parameter() 详解
PyTorch中的torch.nn.Parameter() 详解 今天来聊一下PyTorch中的torch.nn.Parameter()这个函数,笔者第一次见的时候也是大概能理解函数的用途,但是具体实 ...
- torch.nn.Linear详解
在学习transformer时,遇到过非常频繁的nn.Linear()函数,这里对nn.Linear进行一个详解. 参考:https://pytorch.org/docs/stable/_module ...
- torch.nn.MaxPool2d详解
注意:这里展示的是本篇博文写时的版本最新的实现,但是后续会代码可能会迭代更新,建议对照官方文档进行学习. 先来看源码: # 这个类是是许多池化类的基类,这里有必要了解一下 class _MaxPool ...
- nn.Conv2d详解
nn.Conv2d 是 PyTorch 中的一个卷积层,用于实现二维卷积操作.其主要参数有: in_channels:表示输入图像的通道数,也就是输入特征图的深度. out_channels:表示输出 ...
- torch.nn.parameter详解
:-- 目录: 参考: 1.parameter基本解释: 2.参数requires_grad的深入理解: 2.1 Parameter级别的requires_grad 2.2Module级别的requi ...
- Pytorch损失函数torch.nn.NLLLoss()详解
在各种深度学习框架中,我们最常用的损失函数就是交叉熵(torch.nn.CrossEntropyLoss),熵是用来描述一个系统的混乱程度,通过交叉熵我们就能够确定预测数据与真是数据之间的相近程度.交 ...
- Tensorflow(r1.4)API--tf.nn.conv2d详解
(一)函数简介 conv2d(input,filter,strides,padding,use_cudnn_on=True,data_format='NHWC',name=None) 1.参数: in ...
- conv2d的输入_pytorch1.0中torch.nn.Conv2d用法详解
Conv2d的简单使用 torch 包 nn 中 Conv2d 的用法与 tensorflow 中类似,但不完全一样. 在 torch 中,Conv2d 有几个基本的参数,分别是 in_channel ...
- pytorch之torch.nn.Conv2d()函数详解
文章目录 一.官方文档介绍 二.torch.nn.Conv2d()函数详解 参数详解 参数dilation--扩张卷积(也叫空洞卷积) 参数groups--分组卷积 三.代码实例 一.官方文档介绍 官 ...
- pytorch 笔记:torch.nn.Conv2d
1 基本用法 torch.nn,Conv2d(in_channels, out_channels, kernel_size, stride=1,padding=0, dilation=1, group ...
最新文章
- Rancher部署Traefik实现微服务的快速发现
- 里氏替换原则(Liskov Substitution Principle,LSP)
- Makedown 本地图片问题
- GetWindowText和GetDlgItemText的区别
- [bzoj4003][JLOI2015]城池攻占_左偏树
- 【转载保存】B+树索引原理以及应用案例
- 正则表达式基础知识,持续更新…
- 面试数据分析岗,怎么提升一倍成功率?让过来人给你支支招
- [BZOJ 4010] 菜肴制作
- 所有快捷方式失效的解决方法
- vasp和ms_武汉理工大学赵焱课题组开发脚本 MS建模一键获取VASP输入文件POSCAR
- 基于LineMod与ORK的三维物体识别与姿态估计
- Python之shp文件
- 2020年注册电气工程师基础考试大纲:公共基础(供配电、发输变电相同)
- Vue+UpLoad实现上传、点图预览、删除图片
- 平安性格测试题及答案_平安人寿做性格测试怎么?
- app开发都有哪些基本的开发语言选择?
- windows 组策略
- created与mounted执行顺序
- 暴涨375%超越ZOOM,Fastly靠“网络快递”成为华尔街新宠?