自学内容网 自学内容网

卷积神经网络的padding是什么?如何计算?


为什么需要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=2, kernel_size=2,stride=1,padding=[1,2],padding_mode='zeros',bias=False)

conv = nn.Conv2d(in_channels=2, out_channels=2, kernel_size=2,stride=1,bias=False)

conv.weight.data = torch.ones(2,2,2,2)
conv_padding.weight.data = torch.ones(2,2,2,2)

out11 = conv_padding(input)
out2 = conv(padded_input)
print(torch.equal(out11,out2))  # True
tensor([[[[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0.,  1.,  2.,  3.,  4.,  0.,  0.],
          [ 0.,  0.,  5.,  6.,  7.,  8.,  0.,  0.],
          [ 0.,  0.,  9., 10., 11., 12.,  0.,  0.],
          [ 0.,  0., 13., 14., 15., 16.,  0.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]],

         [[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0., 17., 18., 19., 20.,  0.,  0.],
          [ 0.,  0., 21., 22., 23., 24.,  0.,  0.],
          [ 0.,  0., 25., 26., 27., 28.,  0.,  0.],
          [ 0.,  0., 29., 30., 31., 32.,  0.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]]],


        [[[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0., 33., 34., 35., 36.,  0.,  0.],
          [ 0.,  0., 37., 38., 39., 40.,  0.,  0.],
          [ 0.,  0., 41., 42., 43., 44.,  0.,  0.],
          [ 0.,  0., 45., 46., 47., 48.,  0.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]],

         [[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0., 49., 50., 51., 52.,  0.,  0.],
          [ 0.,  0., 53., 54., 55., 56.,  0.,  0.],
          [ 0.,  0., 57., 58., 59., 60.,  0.,  0.],
          [ 0.,  0., 61., 62., 63., 64.,  0.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]]]])
import pdb;pdb.set_trace()
(Pdb) padded_input
tensor([[[[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0.,  1.,  2.,  3.,  4.,  0.,  0.],
          [ 0.,  0.,  5.,  6.,  7.,  8.,  0.,  0.],
          [ 0.,  0.,  9., 10., 11., 12.,  0.,  0.],
          [ 0.,  0., 13., 14., 15., 16.,  0.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]],

         [[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0., 17., 18., 19., 20.,  0.,  0.],
          [ 0.,  0., 21., 22., 23., 24.,  0.,  0.],
          [ 0.,  0., 25., 26., 27., 28.,  0.,  0.],
          [ 0.,  0., 29., 30., 31., 32.,  0.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]]],


        [[[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0., 33., 34., 35., 36.,  0.,  0.],
          [ 0.,  0., 37., 38., 39., 40.,  0.,  0.],
          [ 0.,  0., 41., 42., 43., 44.,  0.,  0.],
          [ 0.,  0., 45., 46., 47., 48.,  0.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]],

         [[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0., 49., 50., 51., 52.,  0.,  0.],
          [ 0.,  0., 53., 54., 55., 56.,  0.,  0.],
          [ 0.,  0., 57., 58., 59., 60.,  0.,  0.],
          [ 0.,  0., 61., 62., 63., 64.,  0.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]]]])

原文地址:https://blog.csdn.net/qq_44815135/article/details/143944711

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!