卷积与转置卷积——pytorch

前言

在学习dcgan的时候,发现有段代码用到了转置卷积,看着他们维度计算部分有点迷糊,决定回忆一下。本来想着既然有人写了,那就不写了吧,后来想着反正以后搞cv,应该大概率需要到,还是复习一下吧。

书写本文时参考了
卷积输出尺寸和转置卷积输出尺寸的计算方式
卷积之后维度的计算



卷积

import torch
import torch.nn as nn

downsample = nn.Conv2d(16, 16, 3, stride=2, padding=1)
input = torch.randn((1, 16, 13, 13))
h = downsample(input)
print('h.size: ', h.size())
# h.size:  torch.Size([1, 16, 7, 7])

参数:
参考 pytorch 1.10 document nn.Con2d

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1,
 padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros,
 device=None, dtype=None)

在这里插入图片描述

更特殊的,如果是后两个维度一样,即 H i n = W i n H_{in}=W_{in} Hin=Win时,
H o u t = H i n − k + 2 × p s + 1 H_{out} = \frac{H_{in}-k+2\times p}{s}+1 Hout=sHink+2×p+1
即输出的维度为 ( N , C o u t , H o u t , H o u t ) (N, C_{out}, H_{out}, H_{out}) (N,Cout,Hout,Hout), 其中, H i n H_{in} Hin代表输出的图片输入宽或高(此时宽和高相等), k k k 代表kernel_size即filter的大小, p p p 代表padding的大小, s s s 代表stride的长度。



转置卷积

import torch
import torch.nn as nn

upsample = nn.ConvTranspose2d(16, 16, 3, stride=2, padding=1)
h = torch.randn((1, 16, 7, 7))
output = upsample(h)
print('output.size(): ', output.size())
# output.size():  torch.Size([1, 16, 13, 13])
torch.nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride=1,
padding=0, output_padding=0, groups=1, bias=True, dilation=1,
padding_mode='zeros', device=None, dtype=None)

在这里插入图片描述

H o u t = ( H i n − 1 ) × s t r i d e [ 0 ] − 2 × p a d d i n g [ 0 ] + d i l a t i o n [ 0 ] × ( k e r n e l _ s i z e [ 0 ] − 1 ) + o u t p u t _ p a d d i n g [ 0 ] + 1 H_{out}=(H_{in}−1)×stride[0]−2×padding[0]+dilation[0]\\ ×(kernel\_size[0]−1)+output\_padding[0]+1 Hout=(Hin1)×stride[0]2×padding[0]+dilation[0]×(kernel_size[0]1)+output_padding[0]+1
W o u t = ( W i n − 1 ) × s t r i d e [ 1 ] − 2 × p a d d i n g [ 1 ] + d i l a t i o n [ 1 ] × ( k e r n e l _ s i z e [ 1 ] − 1 ) + o u t p u t _ p a d d i n g [ 1 ] + 1 W_{out}=(W_{in}−1)×stride[1]−2×padding[1]+dilation[1]\\× (kernel\_size[1]−1)+output\_padding[1]+1 Wout=(Win1)×stride[1]2×padding[1]+dilation[1]×(kernel_size[1]1)+output_padding[1]+1

更特殊的,如果是后两个维度一样,即 H i n = W i n H_{in}=W_{in} Hin=Win时,
o u t = ( H − 1 ) × s − 2 × p   +   d × ( k − 1 ) + o p + 1 out = (H-1) \times s - 2 \times p~+~d \times(k-1) + op + 1 out=(H1)×s2×p + d×(k1)+op+1
即输出的维度为 ( N , C o u t , o u t , o u t ) (N, C_{out}, out, out) (N,Cout,out,out), 其中, H H H代表输出的图片输入宽或高(此时宽和高相等), k k k 代表kernel_size即filter的大小, p p p 代表padding的大小, s s s 代表stride的长度, o p op op 表示output_padding的大小, d(即dilation) controls the spacing between the kernel points。



小例子

例子1

通过公式手工计算输入输出的大小

import torch
import torch.nn as nn


# 仅作演示
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv = nn.Conv2d(3, 16, kernel_size=8, stride=4)
    
    def forward(self, x):
        return self.conv(x)


if __name__ == '__main__':
    # 模拟高为84, 宽为84的彩色图像
    # (batch_size, channel, height, width)
    x = torch.randn(1, 3, 84, 84)

    net = Net()
    y = net(x)
    print(y.shape) # torch.Size([1, 16, 20, 20])

我们定义一个函数

def cal_ouput_feature_map(width, kernel_size, stride, padding=0):
	return (width - kernel_size + 2 * padding) / stride + 1

上述例子我们知道图像宽度(计算高度时代入width位置即可)width为84, 卷积核kernel_size为8, 步长stride为4, padding未定义默认为0。于是y的shape可以调用cal_ouput_feature_map函数算出来.
(如果不整除,是向下取整

 y_w = cal_ouput_feature_map(84, 8, 4)
 print(y_w) # 20.0



例子2

例子来源:卷积输出尺寸和转置卷积输出尺寸的计算方式

import torch
import torch.nn as nn


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 3, 3, padding=1) #in, out, kernel
        self.conv2 = nn.Conv2d(3, 3, 3, padding=1)
        self.maxpooling = nn.MaxPool2d(2,2)
        self.trans_conv = nn.ConvTranspose2d(3, 32, 3, stride=2, padding=1)

    def forward(self, x):
        x = self.conv1(x)
        print("after conv1: ", x.size()) # [1, 3, 12, 12]
        x = self.conv2(x)
        print("after conv2: ", x.size()) # [1, 3, 12, 12]
        x = self.maxpooling(x)
        print("after maxpooling: ", x.size()) # [1, 3, 6, 6]
        x = self.trans_conv(x)
        print("after trans_conv: ", x.size()) # [1, 32, 11, 11]
        return x


model = Net()
x = torch.randn(1, 3, 12, 12)
print("input: ", x.size()) # [1, 3, 12, 12]
out = model(x)
print(out.size())
# torch.Size([1, 16, 11, 11])

这里也附带上计算转职卷积feature_map大小的函数

def cal_feature_map_transposed2d(width, kernel_size, stride, padding=0):
	dilation = 1
	return (width - 1) * stride - 2 * padding + dilation * (kernel_size - 1) + 1

另外超级喜欢One Dark Pro和Bracket Pair Colorizer两个vscode插件的高亮效果。

### 传统反卷积转置卷积的网络架构设计 #### 反卷积转置卷积的概念 反卷积(Deconvolution)通常被称为转置卷积(Transposed Convolution),它是一种通过学习的方式将低维度数据映射到维度空间的操作。这种操作广泛应用于图像生成、超分辨率重建以及语义分割等领域[^1]。 #### 转置卷积的核心机制 转置卷积的主要功能是对输入张量进行上采样,即将其扩展至更的空间分辨率。这一过程涉及填充零值并应用可训练的卷积核来恢复细节信息。具体而言,在标准卷积中,滤波器会压缩输入的空间大小;而在转置卷积中,则相反——滤波器的作用是放大输入的空间尺寸[^2]。 #### 网络架构的设计原则 在网络架构设计方面,传统的基于转置卷积的方法遵循以下几个核心要素: 1. **逐层结构** 使用一系列交替排列的标准卷积层和转置卷积层构建模型。每组转置卷积负责提升特征图的空间分辨率,而后续的标准卷积则进一步提取局部模式以增强表达能力。 2. **跳跃连接 (Skip Connections)** 类似于U-Net架构,为了更好地保留原始输入中的细粒度信息,可以在编码阶段保存中间特征,并将其传递给解码路径上的对应位置。这些额外的信息有助于提最终输出的质量。 3. **激活函数的选择** ReLU 或 LeakyReLU 常被用作隐藏层后的非线性变换单元,因为它们能够有效缓解梯度消失问题并促进更丰富的特征表示形成。然而,在最后一层之前可能需要采用 tanh 或 sigmoid 来约束像素值范围以便适配特定任务需求。 4. **批量标准化 (Batch Normalization)** 批量规范化技术可以帮助加速收敛速度并且稳定整个训练流程。特别是在深层网络当中引入 batch normalization 后往往可以获得更好的泛化性能。 以下是利用 PyTorch 编写的简单示例代码展示如何搭建一个基础版本包含转置卷积操作的神经网络框架: ```python import torch.nn as nn class TransposeConvModel(nn.Module): def __init__(self, input_channels=3, output_channels=3, num_filters=64): super(TransposeConvModel, self).__init__() # Encoder layers with regular convolutions and max pooling self.encoder = nn.Sequential( nn.Conv2d(input_channels, num_filters, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(num_filters), nn.ReLU(), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(num_filters, num_filters * 2, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(num_filters * 2), nn.ReLU() ) # Decoder layers using transposed convolution to upsample the feature maps self.decoder = nn.Sequential( nn.ConvTranspose2d(num_filters * 2, num_filters, kernel_size=2, stride=2), nn.BatchNorm2d(num_filters), nn.ReLU(), nn.ConvTranspose2d(num_filters, output_channels, kernel_size=3, stride=1, padding=1), nn.Tanh() # Output activation function depends on your task requirements. ) def forward(self, x): encoded_features = self.encoder(x) decoded_output = self.decoder(encoded_features) return decoded_output ``` 此段脚本定义了一个小型但完整的端到端处理管道,其中包含了两个主要组成部分:`encoder` 和 `decoder` 。前者逐步降低输入图片的空间尺度同时增加通道数获取层次抽象特性;后者借助转置卷积逆转上述趋势重新构造接近原形的新影像资料. #### 总结 综上所述,转置卷积作为深度学习领域内一种重要的工具,在诸多视觉相关项目里扮演着不可或缺的角色。合理规划好每一级之间的参数配置关系对于达成预期效果至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值