6-4 填充和步幅

news/2024/9/22 13:26:11/

请添加图片描述
在前面的例子 图6.2.1中,输入的高度和宽度都为 3 3 3,卷积核的高度和宽度都为 2 2 2,生成的输出表征的维数为 2 × 2 2\times 2 2×2。 正如我们在 6-2节中所概括的那样,假设输入形状为 n h × n w n_{h}\times n_{w} nh×nw,卷积核形状为 k h × k w k_{h}\times k_{w} kh×kw,那么输出形状将是 ( n h − k h + 1 ) × ( n w − k w + 1 ) (n_{h}-k_{h}+1)\times(n_{w}-k_{w}+1) (nhkh+1)×(nwkw+1)。 因此,卷积的输出形状取决于输入形状卷积核的形状

还有什么因素会影响输出的大小呢?本节我们将介绍填充(padding)步幅(stride)。假设以下情景:

  • 有时,在应用了连续的卷积之后,我们最终得到的输出远小于输入大小。这是由于卷积核的宽度和高度通常大于 1 1 1所导致的。比如,一个 240 × 240 240\times 240 240×240像素的图像,经过 10 10 10 5 × 5 5\times 5 5×5的卷积后,将减少到 200 × 200 200\times 200 200×200像素。如此一来,原始图像的边界丢失了许多有用信息。而填充是解决此问题最有效的方法
  • 有时,我们可能希望大幅降低图像的宽度和高度。例如,如果我们发现原始的输入分辨率十分冗余。步幅则可以在这类情况下提供帮助。

填充

如上所述,在应用多层卷积时,我们常常丢失边缘像素。 由于我们通常使用小卷积核,因此对于任何单个卷积,我们可能只会丢失几个像素。 但随着我们应用许多连续卷积层,累积丢失的像素数就多了。
解决这个问题的简单方法即为填充(padding)在输入图像的边界填充元素(通常填充元素是 0 0 0。 例如,在 图6.3.1中,我们将 3 × 3 3\times 3 3×3输入填充 5 × 5 5\times 5 5×5,那么它的输出就增加为 4 × 4 4\times 4 4×4。阴影部分是第一个输出元素以及用于输出计算的输入和核张量元素: 0 × 0 + 0 × 1 + 0 × 2 + 0 × 3 = 0 0\times 0+0\times 1+0\times 2+ 0\times 3=0 0×0+0×1+0×2+0×3=0
请添加图片描述
通常,如果我们添加 p h p_{h} ph填充(大约一半在顶部,一半在底部)和 p w p_{w} pw填充(左侧大约一半,右侧一半),则输出形状将为:
( n h − k h + p h + 1 ) × ( n w − k w + p w + 1 ) (n_{h}-k_{h}+p_{h}+1)\times(n_{w}-k_{w}+p_{w}+1) (nhkh+ph+1)×(nwkw+pw+1)
这意味着输出的高度宽度将分别增加 p h p_{h} ph p w p_{w} pw
在许多情况下,我们需要设置 p h = k h − 1 p_{h}=k_{h}-1 ph=kh1 p w = k w − 1 p_{w}=k_{w}-1 pw=kw1使输入和输出具有相同的高度和宽度。 这样可以在构建网络时更容易地预测每个图层的输出形状。假设 k h k_{h} kh是奇数,我们将在高度的两侧填充 p h / 2 p_{h}/2 ph/2行。 如果 k h k_{h} kh是偶数,则一种可能性是在输入顶部填充 ⌈ p h / 2 ⌉ \lceil p_{h}/2 \rceil ph/2行,在底部填充 ⌊ p h / 2 ⌋ \lfloor p_{h}/2 \rfloor ph/2行。同理,我们填充宽度的两侧。

卷积神经网络中卷积核的高度和宽度通常为奇数,例如1、3、5或7选择奇数的好处是,保持空间维度的同时,我们可以在顶部和底部填充相同数量的行,在左侧和右侧填充相同数量的列

此外,使用奇数的核大小和填充大小也提供了书写上的便利。
对于任何二维张量 X X X,当满足:

  1. 卷积核的大小是奇数;
  2. 所有边的填充行数和列数相同;
  3. 输出与输入具有相同高度和宽度

则可以得出:输出 Y [ i , j ] Y[i, j] Y[i,j]是通过以输入 X [ i , j ] X[i, j] X[i,j]为中心,与卷积核进行互相关计算得到的

比如,在下面的例子中,我们创建一个高度和宽度为 3 3 3的二维卷积层,并在所有侧边填充 1 1 1个像素。给定高度和宽度为 8 8 8的输入,则输出的高度和宽度也是 8 8 8

卷积神经网络中,如果你创建了一个高度和宽度都为 3 3 3的二维卷积层,并在所有侧边填充 1 1 1个像素,然后用这个卷积层处理一个高度和宽度都为 8 8 8的输入,输出的高度和宽度仍然是 8 8 8。下面是为什么这样设置可以达到这个效果的解释:

卷积核尺寸:在这个例子中,卷积核(filter)的高度和宽度 k h = k w = 3 k_h = k_w = 3 kh=kw=3。这意味着每个卷积核覆盖了输入数据的 3 × 3 3 \times 3 3×3区域。

填充大小:为了确保输出尺寸与输入尺寸相同,我们使用了填充填充是在输入张量的边界添加额外的行和列,这里填充的尺寸 p h = p w = 2 p_h = p_w = 2 ph=pw=2。这意味着在输入的每一边(顶部、底部、左侧和右侧)都加上了一个像素的填充

输出尺寸的计算: 通常输出尺寸的公式是 ( n h − k h + p h + 1 ) × ( n w − k w + p w + 1 ) (n_{h} - k_{h} + p_{h} + 1) \times (n_{w} - k_{w} + p_{w} + 1) (nhkh+ph+1)×(nwkw+pw+1)。 在这个例子中,输入尺寸 n h = n w = 8 n_h = n_w = 8 nh=nw=8,卷积核尺寸 k h = k w = 3 k_h = k_w = 3 kh=kw=3填充 p h = p w = 2 p_h = p_w = 2 ph=pw=2。 代入公式得到输出尺寸为 $(8 - 3 + 2 + 1) \times (8 - 3 + 2 +

  1. = 8 \times 8$。
    保持尺寸相同通过添加等量的填充卷积操作可以在不改变数据的高度和宽度的情况下进行。这样做的好处是简化了网络结构的设计,因为你可以确保无论添加多少这种类型的层,输入与输出的尺寸都保持一致,这使得每层的输出都可以明确计算和预见

因此,通过在高度和宽度为 3 3 3的卷积层周围加上 1 1 1像素的填充(这里说的填充,是加在输入张量上的,周围加1,即为共加了 2 2 2行,加了 2 2 2),并处理高度和宽度为 8 8 8的输入,可以确保输出仍然保持 8 × 8 8 \times 8 8×8的尺寸,这有助于在设计深层网络时维持结构的一致性

import torch
from torch import nn# 为了方便起见,我们定义了一个计算卷积层的函数。
# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
# 接受两个参数:conv2d(一个卷积层对象)和 X(输入数据张量)
def comp_conv2d(conv2d, X):# 这里的(1,1)表示批量大小和通道数都是1X = X.reshape((1, 1) + X.shape)# 将输入张量 X 的形状重塑为 (1, 1, height, width)# 这里的 (1, 1) 分别表示批量大小和通道数都是 1# PyTorch 的卷积层通常期望输入的形状为 (batch_size, channels, height, width)。Y = conv2d(X)# conv2d 对象被应用于已调整形状的输入 X# conv2d 是一个卷积层,它执行卷积运算并输出结果 Y。return Y.reshape(Y.shape[2:]) # 省略前两个维度:批量大小和通道# 去除 Y 的前两个维度(批量大小和通道数),只保留高度和宽度,这样输出就是卷积结果的空间维度。# 请注意,这里每边都填充了1行或1列,因此总共添加了2行或2列
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
# 创建了一个 Conv2d 卷积层,具有 1 个输入通道和 1 个输出通道,卷积核大小为 3(3x3),并且在所有边界上填充了 1 个像素(这样做可以保持输入和输出的空间尺寸相同)。
# padding=1意思是在上下左右各填充一行!X = torch.rand(size=(8, 8))
# 生成一个形状为 (8, 8) 的张量,填充了 0 到 1 之间的随机数,代表一个 8x8 的图像数据。
comp_conv2d(conv2d, X).shape
# 使用定义好的 comp_conv2d 函数来计算卷积,并输出处理后的数据的形状。
# 由于卷积层使用了填充,输入和输出的形状应该是相同的,即 (8, 8)。

请添加图片描述
当卷积核的高度和宽度不同时,我们可以填充不同的高度和宽度,使输出和输入具有相同的高度和宽度。在如下示例中,我们使用高度为5,宽度为3的卷积核,高度和宽度两边的填充分别为2和1。

conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape

请添加图片描述
这个例子其实也说明了, p h p_{h} ph p w p_{w} pw在实际使用的时候可以分别设置不一样的

巧记

  • p h = k h − 1 p_{h}=k_{h}-1 ph=kh1 p w = k w − 1 p_{w}=k_{w}-1 pw=kw1
    p h p_{h} ph是指在高度上,在原始输入的上部和下部,一共添加了多少行
    p w p_{w} pw是指在宽度上,在原始输入的左边和右边,一共添加了多少行

  • nn.Conv2d中的padding=(x,y),这里的(x,y)指的是,在上部和下部分别添加x行,在左边和右边分别添加y列,padding参数的值是 p h p_{h} ph p w p_{w} pw的一半。

  • 输出形状计算公式: ( n h − k h + p h + 1 ) × ( n w − k w + p w + 1 ) (n_{h}-k_{h}+p_{h}+1)\times(n_{w}-k_{w}+p_{w}+1) (nhkh+ph+1)×(nwkw+pw+1)

  • 卷积神经网络中卷积核的高度和宽度通常为奇数


步幅

在计算互相关时,卷积窗口从输入张量的左上角开始,向下、向右滑动。 在前面的例子中,我们默认每次滑动一个元素。 但是,有时候为了高效计算或是缩减采样次数,卷积窗口可以跳过中间位置每次滑动多个元素

我们将每次滑动元素的数量称为步幅(stride)。到目前为止,我们只使用过高度或宽度为 1 1 1步幅,那么如何使用较大的步幅呢? 图6.3.2是垂直步幅 3 3 3,水平步幅 2 2 2的二维互相关运算。 着色部分是输出元素以及用于输出计算的输入和内核张量元素: 0 × 0 + 0 × 1 + 1 × 2 + 2 × 3 = 8 0\times 0+0\times 1+1\times2+2\times3=8 0×0+0×1+1×2+2×3=8 0 × 0 + 6 × 1 + 0 × 2 + 0 × 3 = 6 0\times0+6\times1+0\times2+0\times3=6 0×0+6×1+0×2+0×3=6

可以看到,为了计算输出中第一列的第二个元素和第一行的第二个元素,卷积窗口分别向下滑动三行和向右滑动两列。但是,当卷积窗口继续向右滑动两列时,没有输出,因为输入元素无法填充窗口(除非我们添加另一列填充)。
请添加图片描述
通常,当垂直步幅 s h s_{h} sh、水平步幅 s w s_{w} sw时,输出形状为:
请添加图片描述
请添加图片描述
下面,我们将高度和宽度的步幅设置为 2 2 2,从而将输出的高度和宽度减半。

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape

请添加图片描述

接下来,看一个稍微复杂的例子。

conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
comp_conv2d(conv2d, X).shape

请添加图片描述
为了简洁起见,当输入高度和宽度两侧的填充数量分别为 p h p_{h} ph p w p_{w} pw时,我们称之为填充 ( p h , p w ) (p_{h},p_{w}) (ph,pw)。当 p h = p w = p p_{h}=p_{w}=p ph=pw=p时,填充 p p p
同理,当高度和宽度上的步幅分别为 s h s_{h} sh s w s_{w} sw时,我们称之为步幅 ( s h , s w ) (s_{h},s_{w}) (sh,sw)。特别地,当 s h = s w = s s_{h}=s_{w}=s sh=sw=s时,我们称步幅 s s s
默认情况下,填充 0 0 0步幅 1 1 1
在实践中,我们很少使用不一致的步幅填充,也就是说,我们通常有 p h = p w p_{h}=p_{w} ph=pw s h = s w s_{h}=s_{w} sh=sw

小结

  • 填充可以增加输出的高度和宽度。这常用来使输出与输入具有相同的高和宽。

  • 步幅可以减小输出的高和宽,例如输出的高和宽仅为输入的高和宽的 1 / n 1/n 1/n
    n n n是一个大于 1 1 1的整数)。

  • 填充步幅可用于有效地调整数据的维度

请添加图片描述
可以通过统筹选择设置填充步幅,来将矩形的输入张量,转换为指定高宽比的输出张量


小trick

  • 一般来说,填充的目的是让输入张量和输出张量的形状一致
  • 通常来讲,步幅等于 1 1 1是最好的,如果不选步幅 1 1 1,一般是我们觉得计算量太大了,需要很多很多层才会使得我这个图片变得越来越小,我不想真的用很多层去做这个事情。通常来说步幅是取 2 2 2,每一次减半。步幅取多少,一般看我想把模型复杂度控制在什么程度
  • 步幅填充、核大小和通道数,都是一个神经网络架构的一部分,是我整个网络怎么设计的一部分。
  • 在实际情况中,我们一定是参照经典的网络结构做设计

http://www.ppmy.cn/news/1504148.html

相关文章

ts中any和unknomn有什么区别

在TypeScript(TS)中,any 和 unknown 都是顶级类型(top types),但它们在设计目的和安全性方面存在显著差异。 any 类型安全性:any 类型是TypeScript中一种特殊的类型,它表示可以是任…

OpenAI 发布全新 GPT-4o mini 模型用于取代 GPT-3.5

OpenAI已经弃用 GPT-3.5 模型,将使用 GPT-4o mini 模型取代它,这款模型如何?下面一起来了解一下。 GPT-4o mini 有消息称 OpenAI 准备放弃 GPT-3.5 模型转而使用 GPT-4o mini 模型取代,就在今天早上打开 ChatGPT 之后看&#xf…

设计模式15-门面模式

设计模式15-门面模式 "接口隔离"模式典型模式1. 适配器模式(Adapter Pattern)2. 装饰模式(Decorator Pattern)3. 桥接模式(Bridge Pattern)4. 代理模式(Proxy Pattern)5. …

Python零基础入门教程

Python零基础详细入门教程可以从以下几个方面进行学习和掌握: 一、Python基础认知 1. Python简介 由来与发展:Python是一种广泛使用的高级编程语言,由Guido van Rossum(吉多范罗苏姆)于1991年首次发布。Python以其简…

DB-Engines Ranking 2024年8月数据库排行

DB-Engines Ranking 2024年8月数据库排行 DB-Engines排名根据数据库管理系统的受欢迎程度进行排名。排名每月更新一次。 2024年8月,共有423个数据库进入排行。 排行榜 前15名趋势图 关系型数据库前 10 名 键值数据库前 10 名 文档数据库前 10 名 时序数据库前 10 …

一文弄清Java的四大引用及其两大传递

开场白 Hello大家好呀,我是CodeCodeBond✊最近在复习很多很多的基础知识,有了很多新的感悟~ 话不多说,直接发车✈ 四大引用 问题切入点 在学习 Thread线程利用ThreadLocalMap实现线程的本地内存(变量副本)的时候&…

C++——C++11

前言:本篇文章将分享一些C11版本所产生的一些新的技术以及对老版本的优化。 目录 一.C11简介 二.统一的列表初始化 1.{}初始化 2.std::initializer_list 三.右值引用和移动语义 1.左值引用和右值引用 2.两者的比较 (1)左值引用 &#…

Golang | Leetcode Golang题解之第315题计算右侧小于当前元素的个数

题目: 题解: var a, c []intfunc countSmaller(nums []int) []int {resultList : []int{}discretization(nums)c make([]int, len(nums) 5)for i : len(nums) - 1; i > 0; i-- {id : getId(nums[i])resultList append(resultList, query(id - 1))…