nn.conv2d中的参数SAME和VALID

本文详细解析了卷积神经网络中Padding的作用及其在'Valid'和'Same'模式下的工作原理。通过实例说明了如何使用Padding处理输入数据,确保输出大小与输入一致,或按需求调整输出尺寸。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接:

https://blog.youkuaiyun.com/jasonzzj/article/details/53930074

http://blog.sina.com.cn/s/blog_53dd83fd0102x356.html

 

 

定义: 

Padding在卷积(convolution)和池化(pooling)中都会被用到。在tensorflow比如tf.nn.conv2d,tf.nn.max_pool都有这参数

 

Valid: 用过滤器在输入的矩阵中按步长移动时候,会把最后的不足部分的列和行抛弃;

Same: 先在输入矩阵上下各加个值为0的行,在左右各加个个值为0的列,也就是用0把原先的矩阵包裹一层,然后在移动的时候如果输入矩阵的列或者行长度不够,就用0来补齐

 

例子

看例子比较实际:
            以一维向量做例子

            输入(input)长度:13

            过滤器(Filter)长度:6

            步长(Stride)长度:5

 

 "VALID" = 不会增加padding:

   inputs: 1  2  3  4  5  6  7  8  9  10 11 (12 13)

               |_____________|                        (抛弃不要)

                                    |______________|

 

"SAME" = 会用0来做padding (如果步长是1的话,最终输出和输入一样大小):

           pad|                                                         |Pad

   inputs: 0|  1  2  3  4  5  6  7  8  9  10 11 12 13 |0  0

               |_____________|                   

                                    |______________|

                                                          |_______________|

Notes:

  • "VALID" 会但只会抛弃最右边的列或者是最下面的行.
  • "SAME" 水平方向首先会在左右各加一个零,如果最后不够的话,会在右边再加零补齐,以满足最后一次完整的移动。对于垂直方向也是同理。

 

最终输出的行列数计算方法

SAME:

  • out_height = ceil(float(in_height) / float(strides[1]))

    out_width = ceil(float(in_width) / float(strides[2]))

VALID:

  • out_height = ceil(float(in_height - filter_height + 1) / float(strides1))

    out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))

 

<think>我们正在讨论PyTorch中的nn.Conv2d层。这个层实现了二维卷积,通常用于处理图像数据。 参数包括: in_channels (int): 输入图像的通道数(例如,RGB图像为3,灰度图为1) out_channels (int): 卷积产生的输出通道数(即卷积核的数量) kernel_size (int or tuple): 卷积核的大小。可以是单个整数(表示正方形卷积核)或一个元组(如(height, width)) stride (int or tuple, optional): 卷积的步幅。默认为1。 padding (int, tuple or str, optional): 输入数据边界填充的层数。默认为0(无填充)。也可以设置为字符串,如"same"或"valid"(PyTorch 1.9.0及以上版本支持)。 padding_mode (string, optional): 填充模式。可选值有'zeros', 'reflect', 'replicate'或'circular'。默认为'zeros'。 dilation (int or tuple, optional): 卷积核元素之间的间距(膨胀卷积)。默认为1(常规卷积)。 groups (int, optional): 控制输入输出之间的连接。当groups=1时,所有输入连接到所有输出(标准卷积);当groups=in_channels时,每个输入通道与自己的滤波器组卷积(深度可分离卷积)。 bias (bool, optional): 如果为True,则向输出添加可学习的偏置。默认为True。 下面我们通过一个代码示例来说明这些参数的使用,并解释其意义。</think>### `nn.Conv2d` 参数详解 #### 核心参数定义(PyTorch实现) ```python import torch.nn as nn # 基本使用示例 conv_layer = nn.Conv2d( in_channels=3, # 输入通道数 out_channels=64, # 输出通道数 kernel_size=3, # 卷积核尺寸 stride=1, # 滑动步长 padding=1, # 边缘填充 dilation=1, # 膨胀率 groups=1, # 分组卷积 bias=True, # 是否使用偏置项 padding_mode='zeros' # 填充模式 ) ``` #### 参数意义及作用对照表 | 参数 | 数据类型 | 默认值 | 作用说明 | 典型取值 | |------|----------|--------|----------|----------| | **in_channels** | int | 必填 | 输入特征图的通道数 | 3(RGB), 1(灰度), 256(特征图) | | **out_channels** | int | 必填 | 卷积核数量/输出特征图通道数 | 64, 128, 256 | | **kernel_size** | int/tuple | 必填 | 卷积核的空间尺寸 | 3, (3,3), (5,1) | | **stride** | int/tuple | 1 | 卷积核滑动步长(下采样控制) | 1, 2(下采样), (2,1) | | **padding** | int/tuple/str | 0 | 输入边缘填充像素数 | 0, 1, "same" | | **dilation** | int/tuple | 1 | 卷积核元素间距(空洞卷积) | 1, 2(扩大感受野) | | **groups** | int | 1 | 输入输出通道的分组数 | 1, in_channels(深度可分离卷积) | | **bias** | bool | True | 是否添加可学习偏置项 | True, False | | **padding_mode** | str | 'zeros' | 填充区域的数值填充方式 | 'zeros', 'reflect', 'replicate' | --- #### 关键参数可视化说明 ```python import matplotlib.pyplot as plt import torch def visualize_conv_params(): # 创建模拟输入 (1通道, 5x5图像) input = torch.tensor([[ [1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15], [16,17,18,19,20], [21,22,23,24,25] ]]).float() # 参数效果对比 fig, axs = plt.subplots(2, 3, figsize=(15,10)) # 基础卷积 (kernel_size=3, stride=1, padding=0) conv_basic = nn.Conv2d(1,1, kernel_size=3, bias=False) conv_basic.weight.data = torch.ones_like(conv_basic.weight) # 设权重为1 output_basic = conv_basic(input.unsqueeze(0)) # 带填充卷积 (padding=1) conv_pad = nn.Conv2d(1,1, kernel_size=3, padding=1, bias=False) conv_pad.weight.data = torch.ones_like(conv_pad.weight) output_pad = conv_pad(input.unsqueeze(0)) # 步长为2 (stride=2) conv_stride = nn.Conv2d(1,1, kernel_size=3, stride=2, bias=False) conv_stride.weight.data = torch.ones_like(conv_stride.weight) output_stride = conv_stride(input.unsqueeze(0)) # 空洞卷积 (dilation=2) conv_dil = nn.Conv2d(1,1, kernel_size=3, dilation=2, bias=False) conv_dil.weight.data = torch.ones_like(conv_dil.weight) output_dil = conv_dil(input.unsqueeze(0)) # 可视化 axs[0,0].imshow(input.squeeze(), cmap='viridis') axs[0,0].set_title(f"输入尺寸: {tuple(input.shape)}") axs[0,1].imshow(output_basic.detach().squeeze(), cmap='plasma') axs[0,1].set_title(f"基础卷积\n输出尺寸: {tuple(output_basic.shape[2:])}") axs[0,2].imshow(output_pad.detach().squeeze(), cmap='plasma') axs[0,2].set_title(f"带填充(padding=1)\n输出尺寸: {tuple(output_pad.shape[2:])}") axs[1,0].imshow(output_stride.detach().squeeze(), cmap='plasma') axs[1,0].set_title(f"步长=2\n输出尺寸: {tuple(output_stride.shape[2:])}") axs[1,1].imshow(output_dil.detach().squeeze(), cmap='plasma') axs[1,1].set_title(f"空洞卷积(dilation=2)\n输出尺寸: {tuple(output_dil.shape[2:])}") plt.tight_layout() plt.savefig('conv_params_visualization.jpg') plt.show() visualize_conv_params() ``` #### 输出特征图尺寸计算公式 $$ \text{输出尺寸} = \left\lfloor \frac{\text{输入尺寸} + 2 \times \text{padding} - \text{dilation} \times (\text{kernel\_size} - 1) - 1}{\text{stride}} + 1 \right\rfloor $$ **计算示例**: ```python def calc_output_size(H_in, W_in, conv_params): H_out = (H_in + 2*conv_params['padding'][0] - conv_params['dilation'][0]*(conv_params['kernel_size'][0]-1)-1 ) // conv_params['stride'][0] + 1 W_out = (W_in + 2*conv_params['padding'][1] - conv_params['dilation'][1]*(conv_params['kernel_size'][1]-1)-1 ) // conv_params['stride'][1] + 1 return (H_out, W_out) # 示例:输入224x224,使用3x3卷积,padding=1, stride=1 print(calc_output_size(224, 224, {'kernel_size':(3,3), 'padding':(1,1), 'stride':(1,1), 'dilation':(1,1)})) # 输出: (224, 224) → 尺寸保持不变 ``` #### 高级应用场景 1. **深度可分离卷积** (MobileNet) ```python # 深度卷积 (逐通道卷积) depthwise = nn.Conv2d(256, 256, kernel_size=3, groups=256, padding=1) # 点卷积 (1x1卷积) pointwise = nn.Conv2d(256, 512, kernel_size=1) ``` 2. **空洞卷积** (DeepLab) ```python # 扩大感受野而不增加参数量 atrous_conv = nn.Conv2d(512, 512, kernel_size=3, dilation=4, padding=4) ``` 3. **非对称卷积** (Inception) ```python # 分解为1x33x1卷积 conv1x3 = nn.Conv2d(256, 256, kernel_size=(1,3), padding=(0,1)) conv3x1 = nn.Conv2d(256, 256, kernel_size=(3,1), padding=(1,0)) ``` > **性能注意**:使用`groups>1`可减少75%参数计算量,但会略微降低精度
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值