pytorch卷积层基础七问

技术

1,普通卷积层的参数数量该如何计算?

普通卷积的操作分成3个维度,在空间维度(H和W维度)是共享卷积核权重,滑窗相乘求和(融合空间信息),在输入通道维度是每一个通道使用不同的卷积核参数并对输入通道维度求和(融合通道信息),在输出通道维度操作方式是并行堆叠(多种),有多少个卷积核就有多少个输出通道。

普通卷积层的参数数量 = 输入通道数×卷积核尺寸(如3乘3)×输出通道数(即卷积核个数) + 输出通道数(考虑偏置时)

picture.image

2,卷积层的输出尺寸该如何计算?

卷积输出尺寸计算公式 o = (i + 2p -k‘)//s + 1

对空洞卷积 k' = d(k-1) + 1

o是输出尺寸,i 是输入尺寸,p是 padding大小, k 是卷积核尺寸, s是stride步长, d是空洞卷积dilation膨胀系数。

3,空洞卷积有什么作用?有什么缺点?

空洞卷积和普通卷积相比,空洞卷积可以在保持较小参数规模的条件下增大感受野,常用于图像分割领域。其缺点是可能产生网格效应,即有些像素被空洞漏过无法利用到,可以通过使用不同膨胀因子的空洞卷积的组合来克服该问题,参考文章:https://developer.orbbec.com.cn/v/blog\_detail/892

picture.image

4,什么是分组卷积,分组卷积有什么作用?

和普通卷积相比,分组卷积将输入通道分成g组,卷积核也分成对应的g组,每个卷积核只在其对应的那组输入通道上做卷积,最后将g组结果堆叠拼接。由于每个卷积核只需要在全部输入通道的1/g个通道上做卷积,参数量降低为普通卷积的1/g。分组卷积要求输入通道和输出通道数都是g的整数倍。参考文章:https://zhuanlan.zhihu.com/p/65377955

picture.image

5,什么是深度可分离卷积,和普通卷积相比深度可分离卷积有什么优点?

深度可分离卷积的思想是将融合空间信息和融合通道信息的操作在卷积中分成独立的两步完成。做法是先用g=m(输入通道数)的分组卷积逐通道作用融合空间信息,再用n(输出通道数)个1乘1卷积融合通道信息。其参数量为 (m×k×k)+ n×m, 相比普通卷积的参数量 m×n×k×k 显著减小。同时,由于深度可分离卷积融合空间信息与融合通道信息相互分离,往往还能比普通卷积取得更好的效果。picture.image

6,什么是转置卷积/反卷积?它有什么作用?

一般的卷积操作后会让特征图尺寸变小,但转置卷积(也被称为反卷积)可以实现相反的效果,即放大特征图尺寸。对两种方式理解转置卷积,第一种方式是转置卷积是一种特殊的卷积,通过设置合适的padding的大小来恢复特征图尺寸。第二种理解基于卷积运算的矩阵乘法表示方法,转置卷积相当于将卷积核对应的表示矩阵做转置,然后乘上输出特征图压平的一维向量,即可恢复原始输入特征图的大小。参考文章:https://zhuanlan.zhihu.com/p/115070523

picture.image

7,CV领域有哪些常用的上采样方法?

除了使用转置卷积进行上采样外,在图像分割领域更多的时候一般是使用双线性插值的方式进行上采样,该方法没有需要学习的参数,通常效果也更好,除了双线性插值之外,还可以使用最邻近插值的方式进行上采样,但使用较少。此外,还有一种上采样方法是反池化。使用也不多。

picture.image

代码演示1:卷积输出尺寸关系演示


        
          
import torch   
from torch import nn   
import torch.nn.functional as F   
  
# 卷积输出尺寸计算公式 o = (i + 2*p -k')//s  + 1   
# 对空洞卷积 k' = d(k-1) + 1  
# o是输出尺寸,i 是输入尺寸,ppadding大小, k 是卷积核尺寸, s是stride步长, d是dilation空洞参数  
  
inputs = torch.arange(0,25).view(1,1,5,5).float() # i= 5  
filters = torch.tensor([[[[1.0,1],[1,1]]]]) # k = 2  
  
outputs = F.conv2d(inputs, filters) # o = (5+2*0-2)//1+1 = 4  
outputs_s2 = F.conv2d(inputs, filters, stride=2)  #o = (5+2*0-2)//2+1 = 2  
outputs_p1 = F.conv2d(inputs, filters, padding=1) #o = (5+2*1-2)//1+1 = 6  
outputs_d2 = F.conv2d(inputs,filters, dilation=2) #o = (5+2*0-(2(2-1)+1))//1+1 = 3  
  
print("--inputs--")  
print(inputs)  
print("--filters--")  
print(filters)  
  
print("--outputs--")  
print(outputs,"\n")  
  
print("--outputs(stride=2)--")  
print(outputs_s2,"\n")  
  
print("--outputs(padding=1)--")  
print(outputs_p1,"\n")  
  
print("--outputs(dilation=2)--")  
print(outputs_d2,"\n")  
  
  

      

输出如下:


        
          
--inputs--  
tensor([[[[ 0.,  1.,  2.,  3.,  4.],  
          [ 5.,  6.,  7.,  8.,  9.],  
          [10., 11., 12., 13., 14.],  
          [15., 16., 17., 18., 19.],  
          [20., 21., 22., 23., 24.]]]])  
--filters--  
tensor([[[[1., 1.],  
          [1., 1.]]]])  
--outputs--  
tensor([[[[12., 16., 20., 24.],  
          [32., 36., 40., 44.],  
          [52., 56., 60., 64.],  
          [72., 76., 80., 84.]]]])   
  
--outputs(stride=2)--  
tensor([[[[12., 20.],  
          [52., 60.]]]])   
  
--outputs(padding=1)--  
tensor([[[[ 0.,  1.,  3.,  5.,  7.,  4.],  
          [ 5., 12., 16., 20., 24., 13.],  
          [15., 32., 36., 40., 44., 23.],  
          [25., 52., 56., 60., 64., 33.],  
          [35., 72., 76., 80., 84., 43.],  
          [20., 41., 43., 45., 47., 24.]]]])   
  
--outputs(dilation=2)--  
tensor([[[[24., 28., 32.],  
          [44., 48., 52.],  
          [64., 68., 72.]]]])   

      

代码演示2:卷积层参数数量演示


        
          
import torch   
from torch import nn   
  
features = torch.randn(8,64,128,128)  
print("features.shape:",features.shape)  
print("\n")  
  
#普通卷积  
print("--conv--")  
conv = nn.Conv2d(in_channels=64,out_channels=32,kernel_size=3)  
conv_out = conv(features)  
print("conv\_out.shape:",conv_out.shape)   
print("conv.weight.shape:",conv.weight.shape)  
print("\n")  
  
#分组卷积  
print("--group conv--")  
conv_group = nn.Conv2d(in_channels=64,out_channels=32,kernel_size=3,groups=8)  
group_out = conv_group(features)  
print("group\_out.shape:",group_out.shape)   
print("conv\_group.weight.shape:",conv_group.weight.shape)  
print("\n")  
  
#深度可分离卷积  
print("--separable conv--")  
depth_conv = nn.Conv2d(in_channels=64,out_channels=64,kernel_size=3,groups=64)  
oneone_conv = nn.Conv2d(in_channels=64,out_channels=32,kernel_size=1)  
separable_conv = nn.Sequential(depth_conv,oneone_conv)  
separable_out = separable_conv(features)  
print("separable\_out.shape:",separable_out.shape)   
print("depth\_conv.weight.shape:",depth_conv.weight.shape)  
print("oneone\_conv.weight.shape:",oneone_conv.weight.shape)  
print("\n")  
  
#转置卷积  
print("--conv transpose--")  
conv_t = nn.ConvTranspose2d(in_channels=32,out_channels=64,kernel_size=3)  
features_like = conv_t(conv_out)  
print("features\_like.shape:",features_like.shape)  
print("conv\_t.weight.shape:",conv_t.weight.shape)  
  

      

输出如下:


        
          
features.shape: torch.Size([8, 64, 128, 128])  
  
  
--conv--  
conv_out.shape: torch.Size([8, 32, 126, 126])  
conv.weight.shape: torch.Size([32, 64, 3, 3])  
  
  
--group conv--  
group_out.shape: torch.Size([8, 32, 126, 126])  
conv_group.weight.shape: torch.Size([32, 8, 3, 3])  
  
  
--separable conv--  
separable_out.shape: torch.Size([8, 32, 126, 126])  
depth_conv.weight.shape: torch.Size([64, 1, 3, 3])  
oneone_conv.weight.shape: torch.Size([32, 64, 1, 1])  
  
  
--conv transpose--  
features_like.shape: torch.Size([8, 64, 128, 128])  
conv_t.weight.shape: torch.Size([32, 64, 3, 3])  

      

代码演示3:上采样层


        
          
import torch   
from torch import nn   
  
inputs = torch.arange(1, 5, dtype=torch.float32).view(1, 1, 2, 2)  
print("inputs:")  
print(inputs)  
print("\n")  
  
nearest = nn.Upsample(scale_factor=2, mode='nearest')  
bilinear = nn.Upsample(scale_factor=2,mode="bilinear",align_corners=True)  
  
print("nearest(inputs):")  
print(nearest(inputs))  
print("\n")  
print("bilinear(inputs):")  
print(bilinear(inputs))   
  

      

输出如下:


        
          
inputs:  
tensor([[[[1., 2.],  
          [3., 4.]]]])  
  
  
nearest(inputs):  
tensor([[[[1., 1., 2., 2.],  
          [1., 1., 2., 2.],  
          [3., 3., 4., 4.],  
          [3., 3., 4., 4.]]]])  
  
  
bilinear(inputs):  
tensor([[[[1.0000, 1.3333, 1.6667, 2.0000],  
          [1.6667, 2.0000, 2.3333, 2.6667],  
          [2.3333, 2.6667, 3.0000, 3.3333],  
          [3.0000, 3.3333, 3.6667, 4.0000]]]])  

      

公众号后台回复关键词:pytorch,获取本文源代码和Bilibili吃货本货视频讲解。【注:本文节选自《eat pytorch in 20 days》当中的《 5-2,模型层》 中的第2部分。】

picture.image

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
抖音连麦音画质体验提升与进阶实践
随着互娱场景实时互动创新玩法层出不穷,业务伙伴对 RTC「体验」和「稳定」的要求越来越高。火山引擎 RTC 经历了抖音 6 亿 DAU 的严苛验证和打磨,在架构设计、音画质提升、高可靠服务等方面沉淀了丰富的经验,本次演讲将和大家分享火山引擎 RTC 在直播连麦等场景中的技术优化及其带来的新玩法。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论