🌞欢迎来到Pytorch的世界
🌈博客主页:卿云阁💌欢迎关注🎉点赞👍收藏⭐️留言📝
🌟本文由卿云阁原创!
📆首发时间:🌹2024年2月21日🌹
✉️希望可以和大家一起完成进阶之路!
🙏作者水平很有限,如果发现错误,请留言轰炸哦!万分感谢!
目录
普通卷积
黑白图像中的卷积
填充
步长为3
计算公式
多维卷积
多个卷积核
卷积的三种模式
Pytorch卷积层原理和示例
nn.conv1d
nn.conv2d
深度可分离卷积
普通卷积
黑白图像中的卷积
填充
步长为3
计算公式
多维卷积
多个卷积核
卷积的三种模式
深度学习框架中通常会实现三种不同的卷积模式,分别是 SAME、VALID、FULL。这三种模式的核心区别在于卷积核进行卷积操作的移动区域不同,进而导致输出的尺寸不同。我们以一个例子来看这三种模式的区别,输入图片的尺寸是 5×5 ,卷积核尺寸是 3×3 ,stride 取 1。
- FULL 模式
FULL 模式下卷积核从与输入有一个点的相交的地方就开始卷积。如下图所示,蓝框的位置就是卷积核第一个卷积的地方,灰色部分是为了卷积能够正常进行的 padding(一般填 0)。因此 FULL 模式下卷积核移动区域最大,卷积后输出的尺寸也最大。
- VALID 模式
VALID 模式与 FULL 模式相反,在整个卷积核与输入重叠的地方才开始卷积操作,因此不需要 padding,输出的尺寸也最小。
- SAME 模式
SAME 模式是最常用的一种模式,SAME 的意思是卷积后输出的尺寸与输入尺寸保持一致(假定 stride 为 1)。通过将卷积核的中心与输入的第一个点进行对齐确定卷积核起始位置,然后补齐对应 padding 即可。如下图所示,可以看到卷积输出的尺寸与出入保持一致。
SAME 模式下当卷积核边长为偶数时,可以通过在其中一边增加多一行(列)padding,即不对称的 padding 实现输出尺寸与输入尺寸保持一致,如下图所示(卷积核尺寸为 2×2 )
以上三种模式区别在于卷积核进行卷积操作的移动区域不同,其实是确定了所需的 padding。各种模式 padding 计算如下:
def get_padding(inputs, ks, mode="SAME"):"""Return padding list in different modes.params: inputs (input array)params: ks (kernel size) [p, q]return: padding list [n,m,j,k]"""pad = Noneif mode == "FULL":pad = [ks[0] - 1, ks[1] - 1, ks[0] - 1, ks[1] - 1]elif mode == "VALID":pad = [0, 0, 0, 0]elif mode == "SAME":pad = [(ks[0] - 1) // 2, (ks[1] - 1) // 2,(ks[0] - 1) // 2, (ks[1] - 1) // 2]if ks[0] % 2 == 0:pad[2] += 1if ks[1] % 2 == 0:pad[3] += 1else:print("Invalid mode")return pad
确定了输入尺寸、卷积核尺寸、padding 以及 stride,输出的尺寸就被确定下来,可以由以下公式计算。
Pytorch卷积层原理和示例
nn.conv1d
conv1d是一维卷积,它和conv2d的区别在于只对宽度进行卷积,对高度不卷积。
函数定义:
torch.nn.functional.conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
参数说明:
- input:输入的Tensor数据,格式为(batch,channels,W),三维数组,第一维度是样本数量,第二维度是通道数或者记录数。三维度是宽度。
- weight:卷积核权重,也就是卷积核本身。是一个三维数组,(out_channels, in_channels/groups, kW)。out_channels是卷积核输出层的神经元个数,也就是这层有多少个卷积核;in_channels是输入通道数;kW是卷积核的宽度。
- bias:位移参数,可选项,一般也不用管。
- stride:滑动窗口,默认为1,指每次卷积对原数据滑动1个单元格。
- padding:是否对输入数据填充0。Padding可以将输入数据的区域改造成是卷积核大小的整数倍,这样对不满足卷积核大小的部分数据就不会忽略了。通过padding参数指定填充区域的高度和宽度,默认0(就是填充区域为0,不填充的意思)
- dilation:卷积核之间的空格,默认1。
- groups:将输入数据分组,通常不用管这个参数,没有太大意义。
代码:
import torch from torch.autograd import Variable import torch.nn as nn import torch.nn.functional as Fa=range(16) x = Variable(torch.Tensor(a)) ''' a: range(0, 16) x: tensor([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13.,14., 15.]) '''x=x.view(1,1,16) ''' x variable: tensor([[[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15.]]]) '''b=torch.ones(3) b[0]=0.1 b[1]=0.2 b[2]=0.3 weights = Variable(b) weights=weights.view(1,1,3) ''' weights: tensor([[[0.1000, 0.2000, 0.3000]]]) '''y=F.conv1d(x, weights, padding=0) ''' y: tensor([[[0.8000, 1.4000, 2.0000, 2.6000, 3.2000, 3.8000, 4.4000, 5.0000, 5.6000, 6.2000, 6.8000, 7.4000, 8.0000, 8.6000]]]) '''
nn.conv2d
函数定义
nn.Conv2d(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True))
参数:
- in_channel: 输入数据的通道数,例RGB图片通道数为3;
- out_channel: 输出数据的通道数,这个根据模型调整;
- kennel_size: 卷积核大小,可以是int,或tuple;kennel_size=2,意味着卷积大小(2,2), kennel_size=(2,3),意味着卷积大小(2,3)即非正方形卷积
- stride:步长,默认为1,与kennel_size类似,stride=2,意味着步长上下左右扫描皆为2, stride=(2,3),左右扫描步长为2,上下为3;
- padding: 零填充
代码
import torch import torch.nn as nn from torch.autograd import Variabler = torch.randn(5, 8, 10, 5) # batch, channel , height , width print(r.shape)r2 = nn.Conv2d(8, 14, (3, 2), (2,1)) # in_channel, out_channel ,kennel_size,stride print(r2)r3 = r2(r) print(r3.shape)
torch.Size([5, 8, 10, 5]) Conv2d(8, 14, kernel_size=(3, 2), stride=(2, 1)) torch.Size([5, 14, 4, 4])
深度可分离卷积
论文:《Xception: Deep Learning with Depthwise Separable Convolutions》
代码:API逐深度卷积
不同于原始卷积,深度卷积是一个卷积核负责一个通道,独立地在每个通道上进行空间卷积。因此,深度卷积的输出特征图数量等于输入特征图数量,无法进行有效的维度扩展。
逐点卷积
由于一个特征图仅被一个滤波器卷积,无法有效的利用不同通道在相同空间位置上的特征信息,由此加入了逐点卷积。点卷积主要是要1×1卷积构成,负责将深度卷积的输出按通道投影到一个新的特征图上。
重复多次1x1的卷积操作(如下图为128次),则最后便会得到一个深度的卷积结果。
代码实现:
class DeepWise_PointWise_Conv(nn.Module):def __init__(self, in_ch, out_ch):super(DeepWise_PointWise_Conv, self).__init__()# 深度卷积层(Depthwise Convolution)self.depth_conv = nn.Conv2d(in_channels=in_ch, # 输入通道数out_channels=in_ch, # 输出通道数,每个输入通道对应一个输出通道kernel_size=3, # 卷积核大小,这里是3x3的深度卷积核stride=1, # 步长padding=1, # 填充groups=in_ch # 输入通道数等于组数,每个输入通道分配一个卷积核)# 点卷积层(Pointwise Convolution)self.point_conv = nn.Conv2d(in_channels=in_ch, # 输入通道数,这里等于深度卷积层的输出通道数out_channels=out_ch, # 输出通道数,决定了最终的特征图数量kernel_size=1, # 卷积核大小为1x1,即点卷积stride=1, # 步长padding=0, # 无填充groups=1 # 输入通道数等于组数,每个输入通道独享一个卷积核)def forward(self, input):# 深度卷积out = self.depth_conv(input)# 点卷积out = self.point_conv(out)return out
#将普通卷积替换成深度可分离卷积 nn.Conv2d(32,128,kernal_size=3,stride=1,padding=1)DepthWiseConv(32,128)