经典机器学习方法(7)—— 卷积神经网络CNN

news2024/10/5 18:30:12
  • 参考:《动手学深度学习》第六章

  • 卷积神经网络(convolutional neural network,CNN)是一类针对图像数据设计的神经网络,它充分利用了图像数据的特点,具有适合图像特征提取的归纳偏置,因而在图像相关任务上,它可以用相比全连接网络更少的参数量取得更好的性能。基于 CNN 的模型已经在 CV 领域处于主导地位,当今几乎所有的图像识别、目标检测或语义分割相关的学术竞赛和商业应用都以这种方法为基础
  • 即使在通常使用循环神经网络的一维序列结构任务上(例如音频、文本和时间序列分析),卷积神经网络也越来越受欢迎。 通过对卷积神经网络一些巧妙的调整,它们也能在图结构数据和推荐系统中发挥作用
  • 本文介绍卷积神经网络的基础结构,不涉及任何先进模型和新架构

文章目录

  • 1. 从全连接层到卷积层
    • 1.1 不变性
    • 1.2 MLP 的局限性
    • 1.3 卷积
      • 1.3.1 卷积的数学定义
      • 1.3.2 互相关运算
    • 1.4 通道
  • 2. 图像卷积
    • 2.1 卷积核的特征提取能力
    • 2.2 学习卷积核
    • 2.3 特征映射和感受野
  • 3. 填充和步幅
    • 3.1 填充
    • 3.2 步幅
  • 4. 多输入多输出通道
    • 4.1 多输入通道
    • 4.2 多输出通道
    • 4.3 只作用在通道上的 1X1 卷积层
  • 5. 汇聚层
    • 5.1 最大汇聚层与平均汇聚层
    • 5.2 填充和步幅
    • 5.3 多个通道
  • 6. 卷积神经网络

1. 从全连接层到卷积层

  • 前文 经典机器学习方法(3)—— 多层感知机 我们训练 MLP 解决了图像分类问题。为了适配 MLP 的输入形式,我们直接把尺寸为 (1,28,28) 的原始图像数据拉平成 28x28 的一维数据,这种做法破坏了图像的空间结构信息,原本图像中相近像素之间具有相互关联性,这些性质并不能被 MLP 利用
  • MLP 适合处理表格数据,其中行对应样本,列对应特征,我们寻找的模式可能涉及特征之间的交互,但是我们不能预先假设任何与特征交互相关的先验结构,换句话说,MLP 不具有任何归纳偏置,其训练效率随数据维度上升而不断下降,最终导致模型不再实用

    考虑一个图像分类任务,每张图像具有百万级像素,这意味着 MLP 的每次输入都有 1 0 6 10^6 106 维度,一个将其降维到 1000 的全连接层将有 1 0 9 10^9 109 个参数,这几乎和 GPT1 的总参数量相当

1.1 不变性

  • 针对图像数据而言,一个设计良好的模型应当对图像的某些变换具有容忍性,这被称为模型的不变性
    1. 平移不变性:图像中的目标物体在发生平移后,模型仍然能有效识别。原始 CNN 可以通过局部连接权值共享这两个设计实现平移不变性
    2. 旋转不变性:图像中的目标物体在发生旋转后,模型仍然能有效识别。原始 CNN 不具备这种能力,需要通过数据增强(构造随机旋转的样本)和特定的网络结构(如旋转卷积和旋转不变池化)来实现
    3. 尺度不变性:图像中的目标物体在放大或缩小后,模型仍然能有效识别。原始 CNN 不具备这种能力,需要通过数据增强(构造随机缩放的样本)和特定的网络结构(如多尺度特征融合)来实现
  • 原始 CNN 仅具备平移不变性,它也常被称为空间不变性,为了实现这一点,模型应当具有以下归纳偏置
    1. 平移不变:不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对相同的图像区域具有相似的反应
    2. 局部原则:神经网络的前面几层应该只探索输入图像中的局部区域,而不过度在意图像中相隔较远区域的关系。最后通过聚合这些局部特征,在整个图像级别进行预测

1.2 MLP 的局限性

  • 设 MLP 的输入是二维图像 X ∈ R I × J \mathbf{X}\in\mathbb{R}^{I\times J} XRI×J,其隐藏表示为 H ∈ R I × J \mathbf{H}\in\mathbb{R}^{I\times J} HRI×J,用 [ X ] i , j {[\mathbf{X}]_{i, j} } [X]i,j [ H ] i , j {[\mathbf{H}]_{i, j} } [H]i,j 分别表示输入图像和隐藏表示中位置 ( i , j ) (i,j) (i,j) 处的像素

    注意,真实 MLP 中 X , H \mathbf{X,H} X,H 都应当是一维的,这里为了方便理解,认为无论输入还是隐藏表示都拥有二维空间结构

  • 设 MLP 的权重和偏置参数分别为 W , U \mathbf{W,U} W,U 全连接层可以表示为
    [ H ] i , j = [ U ] i , j + ∑ k ∑ l [ W ] i , j , k , l [ X ] k , l = [ U ] i , j + ∑ ∑ l [ V ] i , j , a , b [ X ] i + a , j + b (1) \begin{aligned} {[\mathbf{H}]_{i, j} } & =[\mathbf{U}]_{i, j}+\sum_{k} \sum_{l}[\mathbf{W}]_{i, j, k, l}[\mathbf{X}]_{k, l} \\ & =[\mathbf{U}]_{i, j}+\sum \sum^{l}[\mathbf{V}]_{i, j, a, b}[\mathbf{X}]_{i+a, j+b} \end{aligned} \tag{1} [H]i,j=[U]i,j+kl[W]i,j,k,l[X]k,l=[U]i,j+l[V]i,j,a,b[X]i+a,j+b(1) 其中从 W \mathbf{W} W V \mathbf{V} V 的转换只是形式上从绝对位置索引变成相对位置索引,即有 [ V ] i , j , a , b = [ W ] i , j , i + a , j + b [\mathbf{V}]_{i, j, a, b}=[\mathbf{W}]_{i, j, i+a, j+b} [V]i,j,a,b=[W]i,j,i+a,j+b,此处索引 a , b a,b a,b 通过正负偏移覆盖了整个图像。上式意味着:隐藏表示中任意给定位置 [ H ] i , j {[\mathbf{H}]_{i, j} } [H]i,j 处的隐藏值,可以通过在 X \mathbf{X} X 中以为 ( i , j ) (i,j) (i,j) 为中心对像素进行加权求和得到,加权使用的权重为 [ V ] i , j , a , b [\mathbf{V}]_{i, j, a, b} [V]i,j,a,b
  • 现在将 1.1 节的两个归纳偏置引入以上全连接层计算式中。
    1. 首先考虑平移不变性,这意味着检查对象在输入 X \mathbf{X} X 中的平移应导致隐藏表示 H \mathbf{H} H 中的平移,这意味着 V , U \mathbf{V,U} V,U 不能依赖于目标位置 ( i , j ) (i,j) (i,j),即 [ V ] i , j , a , b = [ V ] a , b [\mathbf{V}]_{i, j, a, b} = [\mathbf{V}]_{a, b} [V]i,j,a,b=[V]a,b,且 U \mathbf{U} U 是一个常数,这时 H \mathbf{H} H 的定义可以简化为
      [ H ] i , j = u + ∑ a ∑ b [ V ] a , b [ X ] i + a , j + b (2) [\mathbf{H}]_{i, j}=u+\sum_{a} \sum_{b}[\mathbf{V}]_{a, b}[\mathbf{X}]_{i+a, j+b} \tag{2} [H]i,j=u+ab[V]a,b[X]i+a,j+b(2) 机器学习领域中,以上运算被称为 卷积convolution,注意我们此时用系数 [ V ] a , b [\mathbf{V}]_{a, b} [V]a,b ( i , j ) (i,j) (i,j) 附近的像素 ( i + a , j + b ) (i+a,j+b) (i+a,j+b) 加权计算 [ H ] i , j [\mathbf{H}]_{i, j} [H]i,j由于 [ V ] a , b [\mathbf{V}]_{a, b} [V]a,b 不再依赖于目标位置,其参数量相比 [ V ] i , j , a , b [\mathbf{V}]_{i,j,a, b} [V]i,j,a,b 减少了很多,这就是利用归纳偏置提升模型效率的体现
    2. 进一步考虑局部性。局部原则说明我们不应用偏移 ( i , j ) (i,j) (i,j) 太远的信息计算隐藏值 [ H ] i , j [\mathbf{H}]_{i, j} [H]i,j,为此我们对偏移 a , b a,b a,b 的绝对值设置上限 △ \triangle H \mathbf{H} H 的定义进一步简化为
      [ H ] i , j = u + ∑ a = − Δ Δ ∑ b = − Δ Δ [ V ] a , b [ X ] i + a , j + b (3) [\mathbf{H}]_{i, j}=u+\sum_{a=-\Delta}^{\Delta} \sum_{b=-\Delta}^{\Delta}[\mathbf{V}]_{a, b}[\mathbf{X}]_{i+a, j+b} \tag{3} [H]i,j=u+a=ΔΔb=ΔΔ[V]a,b[X]i+a,j+b(3) 执行以上计算的神经网络层被称为 卷积层(convolutional layer),其中 V \mathbf{V} V 被称为 卷积核(convolution kernel)/滤波器(filter),亦或简单地称之为该卷积层的权重,通常该权重是可学习的参数
  • 我们通过引入归纳偏置将全连接层变成了卷积层,大幅降低了需要学习的权重 U , V \mathbf{U,V} U,V 的参数量,这并不是没有代价的。归纳偏置的引入其实限制了网络的表示能力,卷积层无法汇聚长跨度信息,也无法考虑目标的绝对位置信息
    • 当偏置与目标场景(图像数据)相符时,这种表示能力的限制是有益的,它相当于做了一个剪枝,避免了大量无用参数的训练,在不影响模型性能的情况下提升了训练效率
    • 当偏置与目标场景(图像数据)不符时,比如当图像不满足平移不变时,模型可能难以拟合我们的训练数据

1.3 卷积

1.3.1 卷积的数学定义

  • 进一步讨论之前,首先明确一下以上提到的卷积运算。首先,数学中卷积本质是一个泛函积分公式,它将两个函数 f , g : R d → R f,g:\mathbb{R}^d\to\mathbb{R} f,g:RdR 映射到一个数,定义为
    ( f ∗ g ) ( x ) = ∫ f ( z ) g ( x − z ) d z (4) (f*g)(\mathbf{x}) = \int f(\mathbf{z})g(\mathbf{x-z})d\mathbf{z} \tag{4} (fg)(x)=f(z)g(xz)dz(4) 也就是说,卷积是当把一个函数“翻转”并移位 x \mathbf{x} x 时( g ( z ) → g ( − z ) → g ( x − z ) g(\mathbf{z})\to g(-\mathbf{z})\to g(\mathbf{x}-\mathbf{z}) g(z)g(z)g(xz) ),测量 f , g f,g f,g 之间的重叠。当自变量为离散对象时,积分就变成求和。例如,对于由索引为整数 Z \mathbb{Z} Z 的、平方可和的、无限维向量集合中抽取的向量,我们得到以下定义
    ( f ∗ g ) ( i ) = ∑ a f ( a ) g ( i − a ) (5) (f*g)(i) = \sum_a f(a)g(i-a) \tag{5} (fg)(i)=af(a)g(ia)(5) 进一步推广到二维张量的情况
    ( f ∗ g ) ( i , j ) = ∑ a ∑ b f ( a , b ) g ( i − a , j − b ) . (6) (f * g)(i, j)=\sum_{a} \sum_{b} f(a, b) g(i-a, j-b) . \tag{6} (fg)(i,j)=abf(a,b)g(ia,jb).(6) 注意这个 (6) 式本质和 1.2 节的 (3) 式是一样的,我们总是可以匹配两者间的符号
  • 下面给出两个例子,帮助读者直观理解卷积的物理含义
    • 如果一个系统输入 f 是不稳定的,消耗 g 是稳定的,那么可以用卷积求这个系统的存量。下面是一个吃饭的例子,图中 f , g f,g f,g 分别表示一个人的进食曲线和食物的消化曲线。 f ( t ) f(t) f(t) 表示在t时刻吃下的食物量, g ( t ) g(t) g(t) 表示吃下事物后 t t t 时刻食物量的比例值。左上图给出了这个人在 8/10/12 点吃下三种东西的量,左下图显示了 14 点时三种食物的消化剩余比例,右侧表格列举了 14 点时三种食物的剩余量,将其求和就是卷积运算,我们可以用卷积求取任意时刻此人肚子里剩余的实物总量
      在这里插入图片描述
      下图可视化了卷积中的 “翻转-平移” 操作
      在这里插入图片描述
      这种不稳定输入和稳定消耗的场景在信号与系统中经常用出现,一个典型场景是系统处理输入的最高速率有限,而每时每刻输入系统的信号量是不定的,这时就可以用卷积计算系统积压的未处理信息量
    • 卷积可以理解为影响因素的叠加,此时 f 表示影响源的强度,g 表示影响随时间或距离的缩放系数。一个例子是噪音的叠加,此时可以把 f f f 看作一条直路上各个坐标位置噪音源的强度, g g g 表示噪音随距离增加的衰减系数,则路上任意一点处的真实噪声强度也可以通过卷积计算。图像卷积可以看作这个例子的二维推广

1.3.2 互相关运算

  • 了解了卷积的数学定义后,回头看式 (3) 给出的图像卷积运算
    [ H ] i , j = u + ∑ a = − Δ Δ ∑ b = − Δ Δ [ V ] a , b [ X ] i + a , j + b [\mathbf{H}]_{i, j}=u+\sum_{a=-\Delta}^{\Delta} \sum_{b=-\Delta}^{\Delta}[\mathbf{V}]_{a, b}[\mathbf{X}]_{i+a, j+b} [H]i,j=u+a=ΔΔb=ΔΔ[V]a,b[X]i+a,j+b 现在尝试把它对应到 1.3.1 节的数学定义,这时原始图像 X \mathbf{X} X 相当于影响强度 f f f,卷积核 V \mathbf{V} V 相当于影响系数 g g g,忽略偏置 u u u,上式可改写为
    [ H ] i , j = ∑ a = − Δ Δ ∑ b = − Δ Δ g ( a , b ) f ( i + a , j + b ) [\mathbf{H}]_{i, j}=\sum_{a=-\Delta}^{\Delta} \sum_{b=-\Delta}^{\Delta} g(a, b) f(i+a, j+b) \\ [H]i,j=a=ΔΔb=ΔΔg(a,b)f(i+a,j+b) 再令 a ′ = i + a , b ′ = j + b a'=i+a, b'=j+b a=i+a,b=j+b,把相对位置改写成绝对位置,有
    [ H ] i , j = ∑ a ′ ∑ b ′ g ( a ′ − i , b ′ − j ) f ( a ′ , b ′ ) (7) [\mathbf{H}]_{i, j}=\sum_{a'} \sum_{b'} g(a'-i, b'-j) f(a', b') \tag{7} [H]i,j=abg(ai,bj)f(a,b)(7)
  • 将 (7) 式和标准卷积运算 ( f ∗ g ) ( i , j ) = ∑ a ∑ b g ( i − a , j − b ) f ( a , b ) (f * g)(i, j)=\sum_{a} \sum_{b} g(i-a, j-b) f(a, b) (fg)(i,j)=abg(ia,jb)f(a,b) 对比,可见 CNN 中的卷积并不是标准卷积,只有把卷积核水平和垂直翻转后才是标准卷积,准确地讲,CNN 中这种运算称为 互相关(cross-correlation) 运算。尽管如此,由于卷积核参数是从数据中学习到的,因此无论这些层执行严格的卷积运算还是互相关运算,卷积层的输出都不会受到影响

    为了与深度学习文献中的标准术语保持一致,我们将继续把“互相关运算”称为卷积运算

1.4 通道

  • 以上讨论中,我们都把图像视为黑白的,即只有一个灰度通道,但是彩色图片都有 R/G/B 三个通道,某些特殊图像如光电图可能含有更多通道的信息,故大多数图像都是三维张量,其中前两个轴与像素的空间位置有关,第三轴可以看作每个像素的多维表示
  • 由于输入图像是三维的,我们的隐藏表示也最好采用三维张量。换句话说,对于每一个空间位置,我们想要采用一组而不是一个隐藏表示。因此,我们可以把隐藏表示想象为一系列具有二维张量的通道channel。 这些通道有时也被称为特征映射feature maps,因为每个通道都向后续层提供一组空间化的学习特征。 直观上可以想象在靠近输入的底层,一些通道专门识别边缘,而一些通道专门识别纹理
  • 为了支持输入 X \mathbf{X} X 和隐藏表示 H \mathbf{H} H 中的多个通道,我们将卷积公式调整如下
    [ H ] i , j , d = ∑ a = − Δ Δ ∑ b = − Δ Δ ∑ c [ V ] a , b , c , d [ X ] i + a , j + b , c [\mathrm{H}]_{i, j, d}=\sum_{a=-\Delta}^{\Delta} \sum_{b=-\Delta}^{\Delta} \sum_{c}[\mathbf{V}]_{a, b, c, d}[\mathbf{X}]_{i+a, j+b, c} [H]i,j,d=a=ΔΔb=ΔΔc[V]a,b,c,d[X]i+a,j+b,c

2. 图像卷积

  • 本节中,我们暂时忽略通道(第三维),看看卷积核是如何作用于二维图像数据,算出隐藏表示的。下面给出二维互相关运算的示意图,这里原始输入尺寸是 ( 3 , 3 ) (3,3) (3,3),卷积核尺寸 ( 2 , 2 ) (2,2) (2,2),滑动步长 ( 1 , 1 ) (1,1) (1,1)。(注意:将核函数上下左右翻转则是标准卷积运算)
    在这里插入图片描述
    卷积窗口从输入张量的左上角开始,从左到右、从上到下滑动。 当卷积窗口滑动到新一个位置时,包含在该窗口中的部分张量与卷积核张量进行按元素相乘,得到的张量再求和得到一个单一的标量值,由此我们得出了这一位置的输出张量值。输出的隐藏表示尺寸为输入尺寸 ( n h , n w ) (n_h,n_w) (nh,nw) 减去卷积核大小 ( k h , k w ) (k_h, 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) 稍后,我们将看到如何通过在图像边界周围填充零来保证有足够的空间移动卷积核,从而保持输出大小不变

2.1 卷积核的特征提取能力

  • 不同的卷积核可以对原始输入做出不同的处理,从而提取图像的各类特征。我们可以手工设计出提取水平特征和垂直特征的卷积核
    在这里插入图片描述
    类似地,还可以设计提取边缘特征和对图像进行一些处理的卷积核
    在这里插入图片描述

2.2 学习卷积核

  • 对于复杂的 CV 任务而言,手工设计的卷积核不一定是最合适的,注意到卷积核其实就是卷积层中的待学习权重,完全可以通过梯度下降方法通过数据驱动的形式自动学出来
  • 下面给出一个学习垂直边缘检查卷积核的简单示例,为简单起见,在此使用 pytorch 内置的二维卷积层并忽略偏置
    import torch
    from torch import nn
    
    # 构造一个二维卷积层,它具有1个输出通道和形状为(1,2)的卷积核
    conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=False)
    
    # 构造一个黑白图像
    X = torch.ones((6, 8))  # 初始化为全白
    X[:, 2:6] = 0           # 中间设置一块黑区域
    
    # 构造边缘检查结果
    Y = torch.zeros((6, 7))
    Y[:,1] = 1              # 1代表从白色到黑色的边缘
    Y[:,-2] = -1            # -1代表从黑色到白色的边缘
    
    # 这个二维卷积层使用四维输入和输出格式(批量大小、通道、高度、宽度),
    # 其中批量大小和通道数都为1
    X = X.reshape((1, 1, 6, 8))
    Y = Y.reshape((1, 1, 6, 7))
    lr = 3e-2  # 学习率
    
    for i in range(10):
        Y_hat = conv2d(X)
        l = (Y_hat - Y) ** 2
        conv2d.zero_grad()
        l.sum().backward()
        # 迭代卷积核
        conv2d.weight.data[:] -= lr * conv2d.weight.grad
        if (i + 1) % 2 == 0:
            print(f'epoch {i+1}, loss {l.sum():.3f}')
    
  • 训练结束后,观察学习到的卷积核
    conv2d.weight.data.reshape((1, 2))
    >>> tensor([[ 0.9910, -0.9936]])
    

2.3 特征映射和感受野

  • 如 1.4 节所述,某个通道的卷积层输出有时被称为 特征映射/特征图feature map,因为它可以被视为一个输入映射到下一层的空间维度的转换器。 在卷积神经网络中,对于某一层的任意元素 x x x,其 感受野receptive field 是指在前向传播期间可能影响计算的所有元素(来自所有先前层)
  • 注意,感受野可能大于输入的实际大小。还是以本节开头的图为例
    在这里插入图片描述
    给定 2 × 2 2\times 2 2×2 卷积核,阴影输出元素值19的感受野是输入阴影部分的四个元素。现在设上图的输入和输出分别为 X , Y \mathbf{X,Y} X,Y,现在我们在其后附加一个卷积层,该卷积层以 Y \mathbf{Y} Y 为输入,输出单个元素 z z z
    1. z z z Y \mathbf{Y} Y 上的感受野包括 Y \mathbf{Y} Y 的所有四个元素
    2. z z z X \mathbf{X} X 上的感受野包括 X \mathbf{X} X 的所有九个输入元素
  • 因此,当一个特征图中的任意元素需要检测更广区域的输入特征时,我们可以构建一个更深的网络

3. 填充和步幅

  • 从以上第2节的例子可知,卷积的输出形状 ( 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) 取决于输入尺寸 ( n h , n w ) (n_h,n_w) (nh,nw) 和卷积核大小 ( k h , k w ) (k_h, k_w) (kh,kw),这种关系可能不够灵活,比如
    1. 有时在连续应用卷积之后,最终得到的输出远小于输入大小,原始图像许多的边界信息丢失了,填充padding 是解决此问题最有效的方法
    2. 有时原始的输入的分辨率可能过高了,我们希望大幅降低图像的宽度和高度,此时 步幅stride 可以提供帮助

3.1 填充

  • 卷积核尺寸大于 ( 1 , 1 ) (1,1) (1,1) 时,边界信息的丢失是不可避免的,虽然可能仅丢失了边缘的几个像素,但当多个卷积层堆叠时,累计丢失的像素就不可忽略的。填充padding 通过在输入图像边缘填充元素(通常填充0)来解决这个问题

    给出一个示例,原始输入尺寸为 ( 3 , 3 ) (3,3) (3,3),我们将其填充到 ( 5 , 5 ) (5,5) (5,5),使输出尺寸增加到 ( 4 , 4 ) (4,4) (4,4)
    在这里插入图片描述

  • 通常,如果我们添加 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,使输出和输入具有相同的尺寸,这样可以在构建网络时更容易地预测每个图层的输出形状
  • 卷积神经网络中卷积核的高度和宽度通常为奇数,好处是
    1. 我们可以在原始输入的上下、左右填充相同数量的行和列来保持空间维度
    2. 对于任何二维张量 X \mathbf{X} X,当所有边的填充行列数相同且输出保持空间维度时,输出 Y [ i , j ] \mathbf{Y}[i, j] Y[i,j] 是通过以输入 X [ i , j ] \mathbf{X}[i, j] X[i,j] 为中心,与卷积核进行互相关计算得到的
  • 下面给出两个例子
    1. 创建一个高度和宽度为3的二维卷积层,并在所有侧边填充1个像素(上下共填充2 / 左右共填充2)。给定高度和宽度为8的输入,则输出的高度和宽度也是8
      import torch
      from torch import nn
      
      # 为了方便起见,我们定义了一个计算卷积层的函数。
      # 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
      def comp_conv2d(conv2d, X):
          # 这里的(1,1)表示批量大小和通道数都是1
          X = X.reshape((1, 1) + X.shape)
          Y = conv2d(X)
          # 省略前两个维度:批量大小和通道
          return Y.reshape(Y.shape[2:])
      
      # 请注意,这里每边都填充了1行或1列,因此总共添加了2行或2列
      conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
      X = torch.rand(size=(8, 8))
      comp_conv2d(conv2d, X).shape
      
      >>> torch.Size([8, 8])
      
    2. 我们使用高度为 5,宽度为 3 的卷积核,高度和宽度两边的填充分别为2(共4)和1(共2)
      conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
      comp_conv2d(conv2d, X).shape
      
      >>> torch.Size([8, 8])
      

3.2 步幅

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

  • 我们将每次滑动元素的数量称为步幅stride,下图显示了垂直步幅为3,水平步幅为2的二维互相关运算。着色部分是输出元素以及用于输出计算的输入和内核张量元素
    在这里插入图片描述
    通常,当垂直步幅为 s h s_h sh、水平步幅为 s w s_w sw 时,输出形状为
    ⌊ ( n h − k h + p h + s h ) / s h ⌋ × ⌊ ( n w − k w + p w + s w ) / s w ⌋ . \left\lfloor\left(n_{h}-k_{h}+p_{h}+s_{h}\right) / s_{h}\right\rfloor \times\left\lfloor\left(n_{w}-k_{w}+p_{w}+s_{w}\right) / s_{w}\right\rfloor . (nhkh+ph+sh)/sh×(nwkw+pw+sw)/sw.

  • 下面给出一个例子,将高度和宽度的步幅设置为2,从而将输入的高度和宽度减半

    conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
    comp_conv2d(conv2d, X).shape
    
    >>> torch.Size([4, 4])
    
  • 为了简洁起见,我们称填充为 ( p h , p w ) (p_h,p_w) (ph,pw),步幅为 ( s h , s w ) (s_h, s_w) (sh,sw)。特别地,当 p h = p w = p p_h=p_w=p ph=pw=p 时,称填充为 p p p;当 s h = s w = s s_h=s_w=s sh=sw=s 时,步幅是 s s s默认情况下,填充为0,步幅为1。实践中我们很少使用不一致的步幅或填充

4. 多输入多输出通道

  • 以上 2/3 节都是基于单个输入输出通道进行讨论的,这使得我们可以将输入、卷积核和输出看作二维张量。当添加通道时,输入和输出都变成了三维张量,本节将更深入地研究具有多输入和多输出通道的卷积核

4.1 多输入通道

  • 当输入包含多个通道时,需要构造一个与输入数据具有相同输入通道数的卷积核,以便与输入数据进行互相关运算。设输入数据尺寸为 ( c i , n h , n w ) (c_i, n_h,n_w) (ci,nh,nw),需要卷积核尺寸为 ( c i , k h , k w ) (c_i, k_h, k_w) (ci,kh,kw),这可以看作 c i c_i ci 个相同尺寸的卷积核,它们分别与输入的各个通道数据进行互相关运算得到 c i c_i ci 个二维输出,最后把它们按位置求和得到最终输出。如下图所示
    在这里插入图片描述

4.2 多输出通道

  • 在 1.4 节我们提到过,每个通道都向后续层提供一组空间化的学习特征,在最流行的神经网络架构中,随着神经网络层数的加深,我们常会增加输出通道的维数,通过减少空间分辨率以获得更大的通道深度
  • 通道有点类似 Transformer 中的多个注意力头,直观地说,我们可以将每个通道看作对不同特征的响应,但多输出通道并不仅是学习多个单通道的检测器,因为每个通道不是独立学习的,而是为了共同使用而优化的
  • c i , c o c_i,c_o ci,co 分别表示输入和输出的通道数量,用 k h , k w k_h,k_w kh,kw 表示卷积核的高度和宽度,为了获得多个通道的输出,我们可以为每个输出通道创建一个形状为 ( c i , k h , k w ) (c_i, k_h, k_w) (ci,kh,kw) 的卷积核张量,这样卷积核的最终形状为 ( c o , c i , k h , k w ) (c_o, c_i, k_h, k_w) (co,ci,kh,kw)在互相关运算中,每个输出通道先获取所有输入通道,再以对应该输出通道的卷积核计算出结果

4.3 只作用在通道上的 1X1 卷积层

  • k h = k w = 1 k_h=k_w=1 kh=kw=1 时,卷积核只能输入一个空间位置的像素,这种卷积核不再能提取相邻像素间的相关特征,它唯一的计算发生在通道上,可以把 1x1 卷积看作在每个像素位置的所有通道上的全连接层,将 c i c_i ci 个输入转换为 c o c_o co 个输出,如下图所示
    在这里插入图片描述
  • 注意 1x1 卷积也是一个卷积层,故其跨像素的权重是一致的,权重维度为 c i × c o c_i\times c_o ci×co,再额外加上一个偏置

5. 汇聚层

  • 通常当我们处理图像时,我们希望逐渐降低隐藏表示的空间分辨率、聚集信息,这样随着我们在神经网络中层叠的上升,每个神经元对其敏感的感受野(输入)就越大。机器学习任务通常会跟全局图像的问题有关(例如,“图像是否包含一只猫呢?”),所以我们最后一层的神经元应该对整个输入的全局敏感,这需要我们逐渐聚合信息,生成越来越粗糙的映射
  • 现实中,随着拍摄角度的移动,任何物体几乎不可能发生在同一像素上,我们希望模型检查的底层特征(例如 2.1 节中讨论的边缘)保持某种程度上的平移不变性,前面介绍的卷积层相比全连接层已经具有更强的平移不变性了,汇聚层可以进一步增强模型的平移不变能力
  • 本节将介绍 汇聚/池化pooling 层,它具有双重目的
    1. 降低卷积层对位置的敏感性
    2. 降低对空间降采样表示的敏感性

5.1 最大汇聚层与平均汇聚层

  • 与卷积层类似,汇聚层运算符由一个固定形状的窗口组成,该窗口根据其步幅大小在输入的所有区域上滑动,为固定形状窗口(有时称为汇聚窗口)遍历的每个位置计算一个输出
  • 不同于卷积层中的输入与卷积核之间的互相关计算,汇聚层不包含参数。 相反,池运算是确定性的,通常有两种
    1. 最大汇聚层maximum pooling:计算汇聚窗口中所有元素的最大值
    2. 平均汇聚层average pooling:计算汇聚窗口中所有元素的平均值
  • 下图显示了最大汇聚层的处理过程
    在这里插入图片描述
    注意汇聚层的输入是卷积层的输出,我们可以假设上图中的输入 4 对应到原始图像输入上感受野的某个特征(随着层数叠加,感受野可以是较大的一片区间,特征也可以是高价的,比如鸟翅膀或猫尾巴),当原始图像输入发生少量平移时,以上汇聚层输入中的 4 可能偏移到左上角的 0 位置,最大汇聚层在这种情况下可以保持输出不变,这意味着更强的平移不变性

5.2 填充和步幅

  • 与卷积层一样,汇聚层也可以通过设置填充和步幅改变输出形状,pytorch 中语法如下
    # 定义卷积层,指定卷积核尺寸、填充和步幅
    conv2d = nn.Conv2D(1, kernel_size=(3, 5), padding=(0, 1), strides=(3, 4))
    
    # 定义最大池化层,指定汇聚窗口尺寸、填充和步幅
    pool2d = nn.MaxPool2d((2, 3), stride=(2, 3), padding=(0, 1))
    

5.3 多个通道

  • 在处理多通道输入数据时,汇聚层在每个输入通道上单独运算,而不是像卷积层一样在通道上对输入进行汇总,这意味着汇聚层的输出通道数与输入通道数相同
    import torch
    import numpy as np
    
    X = np.arange(16, dtype=np.float32).reshape((1, 1, 4, 4))
    X = np.concatenate((X, X + 1), 1)				# (1, 2, 4, 4)
    pool2d = nn.MaxPool2d(3, padding=1, stride=2)	# 由于汇聚层中没有参数,所以不需要调用初始化函数
    Y = pool2d(torch.tensor(X))                     # (1, 2, 2, 2)
    

6. 卷积神经网络

  • 一个完整的卷积神经网络通过交替堆叠卷积层和汇聚层提取图像特征,最后接全连接层调整维度,用于分类或回归任务。下面是经典 CNN 模型 LeNet 的结构图
    在这里插入图片描述
  • 考虑到篇幅问题,本文仅介绍 CNN 基础原理,各种经典模型的细节和 pytorch 实现将在后续其他文章介绍,链接将更新到此处。To be continue…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1850131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity核心

回顾 Unity核心学习的主要内容 项目展示 基础知识 认识模型制作流程 2D相关 图片导入设置相关 图片导入概述 参数设置——纹理类型 参数设置——纹理形状 参数设置——高级设置 参数设置——平铺拉伸 参数设置——平台设置(非常重要) Sprite Sprite Edit…

一个cmake版的C++项目代码模板,包含流水线、git以及代码格式化配置等支持CICD发布流程

本文给出快速构建C项目的代码仓库模板 ,简单却完整 主要包括: 编译脚本 打包上传脚本- 依赖拉取 代码格式化配置 git配置 流水线pipeline配置 使用这个模板 你只需要:将源文件放到模块目录下,并添加到cmake中即可 一、简…

今日头条屏幕适配深度剖析

基本概念 首先几个基本概念解释: ● dpi:该值代表的是一英寸上有多少个像素点,常见取值为120,160,240。一般这个值才叫做密度 在android里面获取的方法为 metrics.densityDpi; 屏幕尺寸/分辨率得出DPI,一个…

Spring Boot集成vaadin快速入门demo

1.什么是vaadin? Vaadin 是用于构建单页 Web 应用的流行 Java 框架。 它由一家专门从事富 Internet 应用设计和开发的芬兰公司开发。 估计有 15 万开发者使用 Vaadin。 它的开发始于 2002 年。 Vaadin 框架特性 以下是 Vaadin 特性的列表: 这是一个 J…

这周,接连两位程序员猝死...

这周接连发生了两起不幸的事。俩位程序员去世的消息,深感悲伤和惋惜。 6月17号下午,一位负责研发的女员工在虾皮研发中心办公室猝死,年仅 30 岁。 官方通告: 同一天,另一位科大讯飞的高级测试工程师在家突发不适离世…

修改文件的权限(linux篇)

1.在yl用户下创建一个demo.txt文件 [rootlocalhost ~]# su yl [yllocalhost root]$ cd [yllocalhost ~]$ cd Desktop/ [yllocalhost Desktop]$ ls [yllocalhost Desktop]$ vim demo.txt 填入一些信息进行保存 2.查看文件信息以及所对应的组 [yllocalhost Desktop]$ ll 总用量…

一颗B+树可以存储多少数据?

一、前言 这个问题,非常经典,考察的点很多: 比如: 1、操作系统存储的单元,毕竟mysql也是运行在操作系统之上的应用。 2、B树是针对Mysql的InnoDB存储引擎,所以要理解InnoDb的最小存储单元,页&…

解两道四年级奥数题(等差数列)玩玩

1、1~200这200个连续自然数的全部数字之和是________。 2、2,4,6,……,2008这些偶数的所有各位数字之和是________。 这两道题算易错吧,这里求数字之和,比如124这个数的全部数字之和是1247。 …

【yolov8语义分割】跑通:下载yolov8+预测图片+预测视频

1、下载yolov8到autodl上 git clone https://github.com/ultralytics/ultralytics 下载到Yolov8文件夹下面 另外:现在yolov8支持像包一样导入,pip install就可以 2、yolov8 语义分割文档 看官方文档:主页 -Ultralytics YOLO 文档 还能切…

使用 DISPATCHERS 进行 Blueprint 之间的通信

文章目录 初始准备DISPATCHERS 的创建和绑定实现效果 初始准备 首先 UE5 默认是不提供 静态网格体编辑器也就是 Modeling Mode 的,这里需要从插件中添加 Modeling Tools Editor Mode 进入 Modeling Mode 模式,创建一个正方体 然后利用 PolyGroup Edit 和…

告别手抖尴尬!教你轻松缓解手部震颤的小秘诀!

在我们的日常生活中,手抖这个现象可能并不罕见。不论是因为紧张、疲劳还是某些健康问题,手抖都会给我们的生活带来诸多不便。今天,就让我们一起探讨如何缓解手部震颤,让你告别手抖的尴尬! 一、手抖的成因及影响 手抖&…

定点计算与浮点计算在MCU上的较量:以电机控制系统算法实现为例

在嵌入式系统尤其是电机控制算法的实现过程中,定点计算与浮点计算的选取始终是一个重要议题。电机控制系统对实时性和计算效率有着极高要求,而MCU(微控制器)作为其核心处理器,其计算模式的选择直接影响整个系统的性能。…

pycharm中的使用技巧

1、更改主题:找到设置,然后更改主题 点击选择自己喜欢的主题,然后就可以更改主题了 2、设置字体的快捷键 找到设置,如下: 找到increase,如下: 右键选择,增加字体快捷键 按住ctrl滑轮…

压缩包文件密码破解软件 Ziperello 下载及使用教程

使用 Ziperello https://qweree.cn/index.php/416/ 对加了密码的压缩包进行密码破解,教程如下: 第一步,双击运行 Ziperello双击我打开程序.exe,如下图: 第二步,打开一个加了密的 ZIP 压缩包,再…

LCR 142.训练计划IV

1.题目要求: /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ int compare(const void* a,const void* b) {return (*(int*)a - *(int*)b); } struct ListNode* trainningPlan(struct ListNode* l1, struct Li…

Linux驱动开发笔记(十三)Sysfs文件系统

文章目录 前言一、Sysfs1.1 Sysfs的引入1.2 Sysfs的目录结构1.2 Sysfs的目录详解1.2.1 devices1.2.2 bus1.2.3 class1.2.4 devices、bus、class目录之间的关系1.2.5 其他子目录 二、Sysfs使用2.1 核心数据结构2.2 相关函数2.2.1 kobject_create_and_add2.2.2 kobject_put()2.2.…

转让5000万内资融资租赁公司变更需要的条件和变更时间

我们现在有一家陕西的融资租赁公司公司是非常干净的非常适合接手后直接开展业务如果北京的不能够变更了我们这边还有渠道可以变更现在能做的越来越少了,详情流程致电咨询或者来我们公司面谈。 现成融资租赁公司转让: 1、公司名称:陕西xxX融资…

【龙晰 离线安装openssl-devel】openssl-devel rpm 离线安装 需要下载哪些安rpm 包

进入龙晰镜像源地址下载 http://mirrors.openanolis.cn/anolis/8/BaseOS/x86_64/os/Packages/(base) [rootAI lib64]# yum install openssl-devel Last metadata expiration check: 14:03:32 ago on Fri 21 Jun 2024 07:26:56 AM CST. Dependencies resolved. Package …

Linux扩展lvm分区实践 -- 使用其他磁盘的空间

如图,根分区900G,计划将另一块磁盘sdb分出1T来给根分区 步骤 1:创建新的分区 sudo fdisk /dev/sdb输入 n 创建一个新分区 然后选择分区类型,输入p 设置起始扇区(默认),然后设置分区大小&…

nginx启动之后任务管理器里面没有nginx进程

原因1:确保你的nginx文件夹里面只包含英文路径!绝对不能有中文! 原因2: 到conf\nginx.conf里面查看端口和IP地址是否正确设置,ip地址有无正确输入