[PyTorch] 卷积函数 and 解卷积函数

卷积函数

注:
函数语法、参数介绍、shape、变量、Example,均转自 PyTorch 中文手册
说实话 PyTorch 中文手册 对于参数in_channelsout_channels的讲解还是不够详细。
所以我参考了另一篇博客 【PyTorch学习笔记】17:2D卷积,nn.Conv2d和F.conv2d 来讲解这两个参数的意义。

函数语法:

  • 一维
    class torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
  • 二维
    class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
  • 三维
    class torch.nn.Conv3d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

关于卷积层函数各参数的含义,详见Convolution arithmetic
,其动态图演示很形象。

参数介绍

  • in_channels(int) – 输入信号的通道
  • out_channels(int) – 卷积产生的通道
  • kerner_size(int or tuple) - 卷积核的尺寸
  • stride(int or tuple, optional) - 卷积步长
  • padding (int or tuple, optional)- 输入的每一条边补充0的层数
  • dilation(int or tuple, optional) – 卷积核元素之间的间距
  • groups(int, optional) – 从输入通道到输出通道的阻塞连接数
  • bias(bool, optional) - 如果bias=True,添加偏置

shape

  • 一维卷积层:
    输入: (N,Cin,Lin)
    输出: (N,Cout,Lout)
    输入输出的计算方式
    L o u t = f l o o r ( ( L i n + 2 p a d d i n g − d i l a t i o n ( k e r n e r l s i z e − 1 ) − 1 ) / s t r i d e + 1 ) L_{out}=floor((L_{in}+2padding-dilation(kernerl_size-1)-1)/stride+1) Lout=floor((Lin+2paddingdilation(kernerlsize1)1)/stride+1)

  • 二维卷积层:
    输入: (N,C_in,H_in,W_in)
    输出: (N,C_out,H_out,W_out)
    输入输出的计算方式
    H o u t = f l o o r ( ( H i n + 2 p a d d i n g [ 0 ] − d i l a t i o n [ 0 ] ( k e r n e r l s i z e [ 0 ] − 1 ) − 1 ) / s t r i d e [ 0 ] + 1 ) H_{out}=floor((H_{in}+2padding[0]-dilation[0](kernerl_size[0]-1)-1)/stride[0]+1) Hout=floor((Hin+2padding[0]dilation[0](kernerlsize[0]1)1)/stride[0]+1) W o u t = f l o o r ( ( W i n + 2 p a d d i n g [ 1 ] − d i l a t i o n [ 1 ] ( k e r n e r l s i z e [ 1 ] − 1 ) − 1 ) / s t r i d e [ 1 ] + 1 ) W_{out}=floor((W_{in}+2padding[1]-dilation[1](kernerl_size[1]-1)-1)/stride[1]+1) Wout=floor((Win+2padding[1]dilation[1](kernerlsize[1]1)1)/stride[1]+1)

  • 三维卷积层
    输入: (N,C_in,D_in,H_in,W_in)
    输出: (N,C_out,D_out,H_out,W_out)
    输入输出的计算方式
    D o u t = f l o o r ( ( D i n + 2 p a d d i n g [ 0 ] − d i l a t i o n [ 0 ] ( k e r n e r l s i z e [ 0 ] − 1 ) − 1 ) / s t r i d e [ 0 ] + 1 ) D_{out}=floor((D_{in}+2padding[0]-dilation[0](kernerl_size[0]-1)-1)/stride[0]+1) Dout=floor((Din+2padding[0]dilation[0](kernerlsize[0]1)1)/stride[0]+1) H o u t = f l o o r ( ( H i n + 2 p a d d i n g [ 1 ] − d i l a t i o n [ 2 ] ( k e r n e r l s i z e [ 1 ] − 1 ) − 1 ) / s t r i d e [ 1 ] + 1 ) H_{out}=floor((H_{in}+2padding[1]-dilation[2](kernerl_size[1]-1)-1)/stride[1]+1) Hout=floor((Hin+2padding[1]dilation[2](kernerlsize[1]1)1)/stride[1]+1) W o u t = f l o o r ( ( W i n + 2 p a d d i n g [ 2 ] − d i l a t i o n [ 2 ] ( k e r n e r l s i z e [ 2 ] − 1 ) − 1 ) / s t r i d e [ 2 ] + 1 ) W_{out}=floor((W_{in}+2padding[2]-dilation[2](kernerl_size[2]-1)-1)/stride[2]+1) Wout=floor((Win+2padding[2]dilation[2](kernerlsize[2]1)1)/stride[2]+1)

变量

  • weight(tensor) - 卷积的权重,大小是(out_channels, in_channels, kernel_size)
  • bias(tensor) - 卷积的偏置系数,大小是(out_channel

Example:

一维卷积层

m = nn.Conv1d(16, 33, 3, stride=2)
input = autograd.Variable(torch.randn(20, 16, 50))
output = m(input)

二维卷积层

# With square kernels and equal stride
m = nn.Conv2d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2))
# non-square kernels and unequal stride and with padding and dilation
 m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))
input = autograd.Variable(torch.randn(20, 16, 50, 100))
output = m(input)

三维卷积层

# With square kernels and equal stride
m = nn.Conv3d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv3d(16, 33, (3, 5, 2), stride=(2, 1, 1), padding=(4, 2, 0))
input = autograd.Variable(torch.randn(20, 16, 10, 50, 100))
output = m(input)
参数in_channelsout_channels的意义(参考文首博客):

nn.Conv2d()为例(因为Conv2d用来处理图像问题,而且nn.的使用频率大于F.

in_channels指输入图像的通道数。
灰度图像in_channels1RGB图像的in_channels3(忽略alpha通道)。

out_channels直观理解是输入图像经过该卷积层之后的输出通道数。往深里说是“这个卷积核将输入图像从多少个通道 映射 到多少个通道上”。
而这个输出通道数,其实就是卷积核的种类数一种卷积核对应一个输出通道)。
对于卷积核的种类数的种类数,在后面的示例中会有更直观的体现。

再单独把计算输出维度(非通道)的公式拿出来(默认步长stride = 1)

  • 不加padding:out_size = in_size - kernel_size + 1
  • 加padding:out_size = in_size + 2*padding - kernel_size + 1

当步长stride2 时,把步长stride为 1 时的out_size2 即可。

基本用法的示例:

import torch
from torch import nn

"""2维的卷积层,用于图片的卷积"""
# 输入图像的通道数=1(灰度图像),卷积核的种类数=3
# 卷积核的shape是3乘3的,扫描步长为1,不加padding
layer = nn.Conv2d(1, 3, kernel_size=3, stride=1, padding=0)

"""要输入的原始图像"""
# 样本数=1,通道数=1,图像的shape是28乘28的
x = torch.rand(1, 1, 28, 28)

"""使用上面定义的卷积层layer和输入x,完成一次卷积的前向运算"""
out = layer.forward(x)
# 得到的还是1张图片,因为用了3种kernel所以输出的通道数变成3了
# 因为没加padding,原来28乘28的图像在3乘3卷积下得到的边长是28-3+1=26
print(out.shape)  # torch.Size([1, 3, 26, 26])

"""添加padding看看"""
# 这次使用padding为1.所以原始图像上下左右都加了一层0
layer = nn.Conv2d(1, 3, kernel_size=3, stride=1, padding=1)
print(layer.forward(x).shape)  # torch.Size([1, 3, 28, 28])

"""步长设置为2看看"""
# stride设置为2,也就是每次移动2格子(向上或者向右)
layer = nn.Conv2d(1, 3, kernel_size=3, stride=2, padding=1)
# 相当于每次跳1个像素地扫描,输出的Feature Map直接小了一半
print(layer.forward(x).shape)  # torch.Size([1, 3, 14, 14])

"""实际使用时,应该这样用!"""
out = layer(x)
print(out.shape)  # torch.Size([1, 3, 14, 14])

运行结果:

torch.Size([1, 3, 26, 26])
torch.Size([1, 3, 28, 28])
torch.Size([1, 3, 14, 14])
torch.Size([1, 3, 14, 14])

查看卷积层信息:

print(layer.weight)
print(layer.bias)
tensor([[[[ 0.1277, -0.1672,  0.1102],
          [ 0.3176,  0.0236,  0.2537],
          [ 0.0737,  0.0904,  0.0261]]],


        [[[ 0.0349, -0.2042,  0.1766],
          [-0.0938, -0.0470,  0.2011],
          [-0.2460,  0.0876,  0.3124]]],


        [[[-0.2361, -0.0971, -0.1031],
          [-0.0756, -0.3073,  0.3227],
          [-0.1951, -0.2395, -0.0769]]]], requires_grad=True)
          
Parameter containing:
tensor([ 0.0790, -0.3261,  0.0697], requires_grad=True)

解卷积函数(可近似视为)

  • 一维
    class torch.nn.ConvTranspose1d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True)
  • 二维
    class torch.nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True)
  • 三维
    torch.nn.ConvTranspose3d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True)

一维的解卷积操作、二维的转置卷积操作(transposed convolution operator,注意改视作操作可视作解卷积操作,但并不是真正的解卷积操作) 该模块可以看作是Conv1dConv2d、相对于其输入的梯度,有时(但不正确地)被称为解卷积操作

三维的转置卷积操作(transposed convolution operator,注意改视作操作可视作解卷积操作,但并不是真正的解卷积操作) 转置卷积操作将每个输入值和一个可学习权重的卷积核相乘,输出所有输入通道的求和。
该模块可以看作是Conv3d相对于其输入的梯度,有时(但不正确地)被称为解卷积操作

注意
由于内核的大小,输入的最后的一些列的数据可能会丢失。因为输入和输出不是完全的互相关。因此,用户可以进行适当的填充(padding操作)。

参数

  • in_channels(int) – 输入信号的通道数
  • out_channels(int) – 卷积产生的通道
  • kernel_size(int or tuple) - 卷积核的大小
  • stride(int or tuple, optional) - 卷积步长
  • padding(int or tuple, optional) - 输入的每一条边补充0的层数
  • output_padding(int or tuple, optional) - 输出的每一条边补充0的层数
  • dilation(int or tuple, optional) – 卷积核元素之间的间距
  • groups(int, optional) – 从输入通道到输出通道的阻塞连接数
  • bias(bool, optional) - 如果bias=True,添加偏置

shape:

  • 一维解卷积
    输入: (N,C_in,L_in)
    输出: (N,C_out,L_out)
    L o u t = ( L i n − 1 ) s t r i d e − 2 p a d d i n g + k e r n e l s i z e + o u t p u t p a d d i n g L_{out}=(L_{in}-1)stride-2padding+kernel_size+output_padding Lout=(Lin1)stride2padding+kernelsize+outputpadding
  • 二维转置卷积
    输入: (N,C_in,H_in,W_in)
    输出: (N,C_out,H_out,W_out)
    H o u t = ( H i n − 1 ) s t r i d e [ 0 ] − 2 p a d d i n g [ 0 ] + k e r n e l s i z e [ 0 ] + o u t p u t p a d d i n g [ 0 ] H_{out}=(H_{in}-1)stride[0]-2padding[0]+kernel_size[0]+output_padding[0] Hout=(Hin1)stride[0]2padding[0]+kernelsize[0]+outputpadding[0] W o u t = ( W i n − 1 ) s t r i d e [ 1 ] − 2 p a d d i n g [ 1 ] + k e r n e l s i z e [ 1 ] + o u t p u t p a d d i n g [ 1 ] W_{out}=(W_{in}-1)stride[1]-2padding[1]+kernel_size[1]+output_padding[1] Wout=(Win1)stride[1]2padding[1]+kernelsize[1]+outputpadding[1]
  • 三维转置卷积
    输入: (N,C_in,H_in,W_in)
    输出: (N,C_out,H_out,W_out)
    D o u t = ( D i n − 1 ) s t r i d e [ 0 ] − 2 p a d d i n g [ 0 ] + k e r n e l s i z e [ 0 ] + o u t p u t p a d d i n g [ 0 ] D_{out}=(D_{in}-1)stride[0]-2padding[0]+kernel_size[0]+output_padding[0] Dout=(Din1)stride[0]2padding[0]+kernelsize[0]+outputpadding[0] H o u t = ( H i n − 1 ) s t r i d e [ 1 ] − 2 p a d d i n g [ 1 ] + k e r n e l s i z e [ 1 ] + o u t p u t p a d d i n g [ 0 ] H_{out}=(H_{in}-1)stride[1]-2padding[1]+kernel_size[1]+output_padding[0] Hout=(Hin1)stride[1]2padding[1]+kernelsize[1]+outputpadding[0] W o u t = ( W i n − 1 ) s t r i d e [ 2 ] − 2 p a d d i n g [ 2 ] + k e r n e l s i z e [ 2 ] + o u t p u t p a d d i n g [ 2 ] W_{out}=(W_{in}-1)stride[2]-2padding[2]+kernel_size[2]+output_padding[2] Wout=(Win1)stride[2]2padding[2]+kernelsize[2]+outputpadding[2]

变量:

  • weight(tensor) - 卷积的权重,大小是(in_channels, in_channels,kernel_size)
  • bias(tensor) - 卷积的偏置系数,大小是(out_channel)

Example:

二维

# With square kernels and equal stride
m = nn.ConvTranspose2d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.ConvTranspose2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2))
input = autograd.Variable(torch.randn(20, 16, 50, 100))
output = m(input)
# exact output size can be also specified as an argument
input = autograd.Variable(torch.randn(1, 16, 12, 12))
downsample = nn.Conv2d(16, 16, 3, stride=2, padding=1)
upsample = nn.ConvTranspose2d(16, 16, 3, stride=2, padding=1)
h = downsample(input)
h.size()
# torch.Size([1, 16, 6, 6])
output = upsample(h, output_size=input.size())
output.size()
# torch.Size([1, 16, 12, 12])

三维

# With square kernels and equal stride
m = nn.ConvTranspose3d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv3d(16, 33, (3, 5, 2), stride=(2, 1, 1), padding=(0, 4, 2))
input = autograd.Variable(torch.randn(20, 16, 10, 50, 100))
output = m(input)
  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值