文章目录
为什么需要padding?
1.Valid Padding(有效填充)
2.Same Padding(相同填充)
2.1.如何计算padding?
1. 计算总 padding
2. 分配 padding:
2.2.举例子
1. 步幅为 1 的 Same Padding
2. 步幅不为 1 的 Same Padding
3.F.pad()和卷积中的padding互相转换
1.torch.nn.functional.pad()函数
2.举例
为什么需要padding?
控制输出尺寸: 卷积操作通常会减少输入图像的尺寸。例如,使用3×3 卷积核时,边缘的像素不会像中间部分的像素一样得到处理(因为卷积核无法完全跨越边缘区域),导致输出图像的尺寸小于输入图像。通过适当的 padding,可以保持输入和输出尺寸相同,或者控制输出的尺寸。
保留边缘信息: 如果没有padding,卷积操作会丢失输入图像的边缘部分的信息。通过为输入图像添加零填充,卷积核可以处理这些边缘区域,从而保留更多的信息。
1.Valid Padding(有效填充)
定义:在卷积操作中没有额外的填充,也就是在卷积时不添加任何零填充。此时,输出图像的尺寸会小于输入图像,具体减少的大小取决于卷积核的尺寸和步幅。
输出尺寸:由于没有 padding,输出尺寸通常会小于输入尺寸,且与卷积核大小和步幅有关。
优点:计算效率较高,减少了不必要的计算。
缺点:会丢失图像的边缘信息。
2.Same Padding(相同填充)
定义:通过添加零填充来确保输出的尺寸与输入尺寸相同(在步幅为 1 时)。为了实现这一点,通常需要在输入的边缘添加一定数量的零。
输出尺寸:输入和输出尺寸相同(对于步幅为1的情况)。当步幅大于1时,输出尺寸会根据步幅的大小调整,但仍尽量保持输入和输出的比例相同。
优点:能够保留输入的边缘信息,适用于需要保持特征图大小不变的任务。
缺点:可能会引入一些零值,这对网络学习可能是无用的。
2.1.如何计算padding?
1. 计算总 padding
P_h = (H - 1) * S + K - H
P_w = (W - 1) * S + K - W
2. 分配 padding:
P_top = P_h // 2
P_bottom = P_h - P_top
P_left = P_w // 2
P_right = P_w - P_left
2.2.举例子
1. 步幅为 1 的 Same Padding
当stride = 1,dilation=1,卷积公式的输出为H_out = H_in+2p-k+1,要保证H_out = H_in,所以2p = k-1,p = (k-1)/2。假设输入尺寸是 5×5,卷积核大小是 3×3,步幅为 1。我们希望卷积操作后的输出尺寸与输入相同。计算padding:
import torch
import torch.nn as nn
# 定义输入数据(5x5)
input_data = torch.randn(1, 1, 5, 5) # Batch size = 1, Channels = 1, Height = 5, Width = 5
# 定义卷积层,kernel_size = 3, padding = 1 (为了使用same padding)
conv_layer = nn.Conv2d(1, 1, kernel_size=3, stride=1, padding=1)
# 输出卷积后的数据
output_data = conv_layer(input_data)
print(f'输入形状: {
input_data.shape}')
print(f'输出形状: {
output_data.shape}')
输入形状: torch.Size([1, 1, 5, 5])
输出形状: torch.Size([1, 1, 5, 5])
2. 步幅不为 1 的 Same Padding
根据公式推导得,P = (S(H-1)-H+K)/2,当S=2,上述例子为,P = floor[(8-4+3)/2]=3
import torch
import torch.nn as nn
# 定义输入数据(5x5)
input_data = torch.randn(1, 1, 5, 5) # Batch size = 1, Channels = 1, Height = 5, Width = 5
# 定义卷积层,kernel_size = 3, padding = 1 (为了使用same padding)
conv_layer = nn.Conv2d(1, 1, kernel_size=3, stride=2, padding=3)
# 输出卷积后的数据
output_data = conv_layer(input_data)
print(f'输入形状: {
input_data.shape}')
print(f'输出形状: {
output_data.shape}')
输入形状: torch.Size([1, 1, 5, 5])
输出形状: torch.Size([1, 1, 5, 5])
3.F.pad()和卷积中的padding互相转换
1.torch.nn.functional.pad()函数
torch.nn.functional.pad(input, pad, mode='constant', value=0)
参数说明
input (Tensor): 输入张量。
pad (tuple or int): 指定每个维度上的填充宽度。可以是一个整数或一个元组。
如果是整数,表示所有维度的两侧都填充相同的值。
如果是元组,元组的长度必须是输入张量维度的两倍。元组的形式为 (pad_left,pad_right, pad_top, pad_bottom, …),表示每个维度上的填充宽度。
mode (str, optional): 填充模式,默认为 ‘constant’。可选值有:
constant: 使用常数值填充,默认值为 0。
reflect: 使用边界元素的反射值填充。
replicate:使用边界元素的复制值填充。
circular: 使用循环方式填充。
value (float, optional): 当 mode 为 constant’时,指定填充的常数值,默认为 0。
2.举例
input = torch.arange(1, 65,dtype=torch.float).view(2, 2, 4, 4)
padded_input = F.pad(input, pad=[2, 2, 1, 1], mode='constant', value=0)
conv_padding = nn.Conv2d(in_channels=2, out_channels