说明

  • 文章属于个人学习笔记内容,仅供学习和交流。
  • 内容参考《深度学习原理与实践》陈仲铭版和个人学习经历和收获而来。

卷积神经网络概述(Convolutional Neural Network,CNN)

  • 卷积神经网络是计算机视觉天梯的基石。
  • 卷积神经网络可以利用多层网络结构自动学习输入数据的深层特征,不同层次的网络可以学习到不同层次的特征。浅层网络层感知区域较小,可以学习到输入数据的局部域特征(如图像物体的颜色、集合形状);深层网络层具有较大的感知域,能够学习输入数据的抽象特征(如图像物体属性、轮廓特点、位置信息)。深层次抽象特征对图像中物体的大小位置和方向等局部域特征敏感度较低,提高了物体的识别率。所以,卷积神经网络常用于图像处理领域。

卷积神经网络的应用

  • 在图像处理任务上,卷积神经网络可以用来识别位移、缩放及物体形态扭曲的二维图形。CNN的网络模型中的特征是通过训练数据集进行图像特征学习,无需显式抽取特征;因为图像上同一特征面上的神经元权值相同,CNN模型可以并行训练,提高神经网络的训练效率。

图像分类与识别

  • 卷积神经网络在图像分类上一枝独秀,其中手写字体(HandWritten) 的识别率达到99.9%。 国外众多快递公司已经开始应用卷积神经网络模型识别快递单上的手写字体,尽最大可能地节约企业成本、提高自身的系统运作效率。
  • 使用神经网络可以对整体图像进行目标识别。 例如一张图片中的多个类别: 一只狗、 一栋房子、 一棵树等。

图像着色

  • 图像着色就是将灰度图像回复彩色的过程。
  • 使用改进的卷积神经网络模型提取输入图像的特征及其上下文信息来对图像进行着色。年代久远的纪录片可以真实还原当年的色彩,父母的老照片也终于可以还原出当年色彩艳丽的场景。

自然语言处理NLP

  • 卷积神经网络为图像而生,但应用不限于图像。
  • 使用卷积神经网络进行自然语言处理主要是针对语义分析和话题分类两大任务。网络模型共分为 4层,输入层是一个表示句子的矩阵,每一行代表一个单词向量,输入层后接一个卷积层和Pooling 层,最后是 Softmax 分类器作为输出层。该卷积神经网络模型在各个自然语言处理的公共数据集上的表现都出色。
    在这里插入图片描述

卷积神经网络的结构

  • 卷积神经网络主要由输入层、卷积层、下来样层、全连接层、输出层构成。
    在这里插入图片描述
  • 卷积神经网络的简单示例模型,该卷积神经网络的网络层从左到右分别为:输入层、第一个卷积层、第一个下采样层、第二个卷积层、第二个下采样层、全连接层、输出层。

  1. 假设上图中的输入图像为灰度图A,对应图像矩阵表示为 ( 1 , w , h ) (1,w,h) (1,w,h),1 为单通道,w和h对应输入图像的长和高。首先把灰度图A作为输入层,然后接一个卷积层。第一个卷积层对输入的图像进行卷积操作后,得到3个特征图(Feature Map),每个特征图对应一个卷积核,此时网络模型中的数据存储结构变成(3,w,h)。因此3个特征图组成的矩阵也被称为“特征矩阵”,3代表特征矩阵的深度。
  • 卷积层操作产生多少个特征图是自由设定的,也被称为超参数(Hyper-Parameters)。
  1. 第一个卷积层后接的是下采样层(Pooling层),Pooling 层对输入的 3 个特征图(特征矩阵〉进行下来样操作, 得到3个更小的特征矩阵 ( 3 , w / 2 , h / 2 ) (3,w/2, h/2) (3,w/2,h/2)。接下来到第二个卷积层,卷积操作之后产生5个特征图 ( 5 , w / 2 , h / 2 ) (5,w/2, h/2) (5,w/2,h/2)。然后再接一个Pooling 层,对 5 个特征图进行下采样操作,得到5个更小的特征图 ( 5 , w / 4 , h / 4 ) (5, w/4,h/4) (5,w/4,h/4)
  • 一般对图像进行下来样操作得到的特征图为输入Pooling层特征图的一半。
  1. 在第二个Pooling 层后面接的是两个全连接层。第一个全连接层的每个神经元与上一层的 5 个特征图中每个神经元(每个像素)进行全连接。 下一个全连接层同样与上一层的每个神经元进行全连接。
  2. 在整个网络的最后一层是输出层(Softmax 层〉,对全连接后的特征向量进行计算, 得到分类评分值。与普通神经网络类似,卷积神经网络模型中的卷积核都是通过对输入数据集经过梯度下降算法训练得到的。

卷积神经网络中的数据流动

  • 该图为上图卷积神经网络的数据流动图。
    在这里插入图片描述
  1. 输入层(Input Layer):假设输入图像为 [ 1 , 32 , 32 ] [1,32,32] [1,32,32]的彩色图。
  2. 卷积层(Convolutinon Layer):对输入卷积层的图像或者特征图进行卷积操作, 输出卷积后的特征图。第一个卷积层有3 个卷积核,因此卷积操作后得到的特征矩阵为 [ 3 , 32 , 32 ] [3, 32, 32] [3,32,32],第二个卷积层有5个卷积核, 同理卷积操作后得到的特征矩阵为 [ 5 , 32 , 32 ] [5, 32, 32] [5,32,32]
  3. 下采样层(Polling Layer):Pooling 层对传入的图像在空间维度上进行下采样操作(使输入的特征图长和宽均变为原来的一半),第一次卷积层后得到 [ 3 , 32 , 32 ] [3, 32, 32] [3,32,32]大小的特征矩阵作为Pooling 层的输入,输出 口 [ 3 , 16 , 16 ] [3,16,16] [3,16,16]大小的特征矩阵, 再经过第二个 Pooling 层后输出
    则变成 [ 5 , 8 , 8 ] [5,8,8] [5,8,8]大小的特征矩阵。
  4. 全连接层(Fully Connected Layer):全连接层与普通神经网络一样,每个神经元都与输入的所有神经元相互连接,然后经过激活函数进行计算。最后 Pooling 层得到 [ 5 , 8 , 8 ] [5,8,8] [5,8,8]的特征向量,即一共有 5 × 8 × 8 = 320 5×8×8=320 5×8×8=320个神经元,假设全连接层的神经元为 100 100 100,那么全连接产生 320 × 100 = 32000 320 × 100=32000 320×100=32000条连接线,后面的全连接层与ANN 类似。
  5. 输出层(Output Layer):输出层(分类层)会输出每个类别的预测概率。例如,对于分类选项(鸡扒、鸡腿、鸡翅),输出可能是概率矩阵 [0.9, 0.1, 0],系统会选择概率最高的“鸡扒”作为最终预测结果。

  • 总结:卷积神经网络模型逐层对图像的每一个像素值进行计算, 到最后经过卷积神经网络模型后,输出分类评分值。

CNN与ANN的关系

  • CNN与ANN内部实现原理都是由神经元模型组成的神经网络。
  • 人工神经网络使用全排列的方式,神经元按照一维进行排列。卷积神经网络每层神经元都是按照三维排列,每层有长、宽、高。长和宽表示输入图像矩阵的长度和宽度,高代表该层网络的高度。

  • 卷积神经网络的网络结构中,卷积层后接 P o o l i n g Pooling Pooling层。输入为 4 × 4 4×4 4×4大小的图像矩阵,卷积层参数为 ( p a d d i n g = s a m e , k e r n e l = 2 ) (padding=same,kernel=2) (padding=same,kernel=2),卷积层后输出特征矩阵大小为 [ 2 , 4 , 4 ] [2,4,4] [2,4,4]。(卷积层有n个卷积核对应输出有n个特征图)
    在这里插入图片描述
  • 假设卷积层输入为一张4×4大小的图像矩阵(对应输入神经元有 16 (4×4)个〉,设定卷积核为2,经过卷积操作后产生2个4×4大小的特征图(对应输出特征神经元有32(2×4×4)个)。其中,卷积核大小为3×3(一个卷积核由9个神经元组合而成),即对应的权重参数连接线有18(2×3×3)条,输入神经元与特征神经元连接线均带有权值参数 w i w_i wi和偏置 b i b_i bi,而该权值参数则由卷积核组成。

  • 卷积神经网络的网络模型的卷积层和全连接层中的权重参数经过梯度下降算法(SGD)进行训练得到,最终使得卷积神经网络计算出的分类概率能和训练集中的图像标签吻合。

卷积操作

  • 卷积操作就是图像处理技术中的过滤操作,卷积核(ConvolutionKerne)又称滤波器。卷积神经网络的卷积核内容则是通过梯度下降算法 SGD)训练得到。

Padding 操作

  • 卷积操作时会造成在图像边界卷积造成图像信息丢失的问题,Padding操作有助于解决边界卷积问题。
  • Padding操作可以分为Same Padding、Valid Padding和自定义Padding 3种方法。
    • Same Padding是根据卷积核大小,对输入图像矩阵进行边界补充(一般填充零值),使得卷积后得到的特征矩阵与输入矩阵大小一致。避免边界信息被忽略,把边界信息纳入神经网络的计算范围内,否则随着神经网络层的深入,图像边缘信息的损失也会逐渐增大。
    • Valid Padding实际上不需要进行Padding操作
    • 自定义Padding生成的特征图大小根据下式计算而来。
      o u t p u t h = ( i n p u t h + 2 × p a d d i n g h − k e r n e l h ) / s t r i d e + 1 o u t p u t w = ( i n t p u t w + 2 × p a d d i n g w − k e r n e l w ) / s t r i d e + 1 o u t p u t 为输出矩阵, i n p u t 为输入矩阵, p a d d i n g 为边界填充数量 k e r n e l 为卷积核大小, s t r i d e 为步长大小, w 为操作矩阵的宽, h 为操作矩阵的长 output_h=(input_h+2\times padding_h - kernel_h)/stride+1 \\ output_w=(intput_w+2\times padding_w - kernel_w)/stride+1 \\ output为输出矩阵,input为输入矩阵,padding为边界填充数量 \\ kernel为卷积核大小,stride为步长大小,w为操作矩阵的宽,h为操作矩阵的长 outputh=(inputh+2×paddinghkernelh)/stride+1outputw=(intputw+2×paddingwkernelw)/stride+1output为输出矩阵,input为输入矩阵,padding为边界填充数量kernel为卷积核大小,stride为步长大小,w为操作矩阵的宽,h为操作矩阵的长

  • Padding操作的两种主要方式,如图(a)输入 5 × 5 5\times 5 5×5的图像矩阵。卷积核大小为 3 × 3 3\times 3 3×3。Same Padding方法设置padding参数为 1 1 1,使卷积的输出与输入矩阵大小一致。图(b) V a l i d P a d d i n g Valid Padding ValidPadding方法设置 p a d d i n g padding padding参数为 0 0 0,使得输出特征矩阵比输入矩阵要小。

在这里插入图片描述

  • 一般默认卷积操作中使用 Same Padding 方法。通过对输入图像矩阵的边缘填充零像素值,使得输入的图像经过卷积后得到的特征矩
    阵大小与输入的原图大小一致。

滑动窗口卷积操作

  • 卷积操作:原始输入为一张图像,通过一个卷积核在输入图像上进行滑动,对滑动窗口与卷积核进行数值运算后,卷积后输出的为特征图。
  • 假设一个卷积核窗口在输入图像上滑动,滑动窗口每次移动的步长为 stride,那么每次滑动窗口后,把求得的值按照空间顺序组成一个特征图。该特征图的边长分别为:
    f e a t u r e m a p w = ( i m g w − k e r n e l w ) / s t r i d e + 1 f e a t u r e m a p w = ( i m g w − k e r n e l h ) / s t r i d e + 1 f e a t u r e m a p 为特征图矩阵的大小, i m g 为输入图像大小 k e r n e l 为卷积核大小, s t r i d e 为步长大小, w 为矩阵的宽, h 为矩阵的长。 feature map_w = (img_w - kernel_w) / stride +1 \\ feature map_w =(img_w - kernel_h) / stride+1 \\ feature map为特征图矩阵的大小,img为输入图像大小 \\ kernel为卷积核大小,stride为步长大小,w为矩阵的宽,h为矩阵的长。 featuremapw=(imgwkernelw)/stride+1featuremapw=(imgwkernelh)/stride+1featuremap为特征图矩阵的大小,img为输入图像大小kernel为卷积核大小,stride为步长大小,w为矩阵的宽,h为矩阵的长。
    在这里插入图片描述
    在这里插入图片描述

网络卷积层操作

  • 在第 l l l层网络有 C C C个特征图作为输入,该卷积层有 k k k个卷积核,如何进行卷积操作产生 k k k个输出特征矩阵?
  • 假设在第 l l l层卷积层输入为C个特征图,即该层输入C个矩阵,C个矩阵的大小均为 W × H W \times H W×H,可以得到一个 C × ( W × H ) C \times (W \times H) C×(W×H)的特征张量, C C C又称为输入矩阵的深度。该层设定有 C o u t Cout Cout K × K K \times K K×K大小卷积核,在使用 S a m e P a d d i n g Same Padding SamePadding的情况下将会产生 C o u t Cout Cout个大小为 W × H W \times H W×H的特征图作为输出,即可得到 C o u t × ( W × H ) Cout \times (W \times H) Cout×(W×H)的特征张量作为输出。

在这里插入图片描述

  • 多层卷积操作类似于神经元的基本求和公式 z = ∑ w x + b z=\sum wx+b z=wx+b,卷积神经网络中 w w w对应单个卷积核, x x x为对应输入矩阵的不同数据窗口, b b b为该卷积核的偏置。这相当于卷积核与一个个数据窗口相乘求和后(矩阵内积计算),加上偏置b得到输出结果。
    z = x 11 ⊙ w 1 + w 21 ⊙ w 1 + b = ( x 11 + x 21 ) ⊙ w 1 + b \begin{align*} z &=x_{11} \odot w_1+w_{21} \odot w_1+b \\ &=(x_{11}+x_{21}) \odot w_1+b \end{align*} z=x11w1+w21w1+b=(x11+x21)w1+b

矩阵快速卷积

  • 卷积操作是在图像中通过滑动窗口,逐像素进行矩阵计算,会耗费大量的计算资源去寻址和修改内存数据。可以转化为矩阵后进行快速计算。矩阵操作能在计算机中快速运算并且方便移植到 GPU 中,在实际生产环境中可以通过两步来完成卷积操作:
  1. 使用Image to column ( Im2col)算法把输入图像和卷积核转换成为规定的矩阵排列方式。
  2. 使用GEMM算法对转换后的两个矩阵进行相乘,得到卷积结果。

Im2col算法

  1. 图像的Im2col操作:假设输入的图像大小为 C × H × W C \times H \times W C×H×W(其中H为图像的长, W W W为图像的宽, C C C为图像的深度)。卷积核的大小为 K × K K \times K K×K,那么对应输入图像中一个卷积窗口可以表示为 C × ( K × K ) C \times (K \times K) C×(K×K)的向量,即对输入图像中的某位置的数据按照卷积窗口进行从新排列,得到 C × ( K × K ) C\times (K \times K) C×(K×K)的特征向量。以步长为 1 ( s t r i d e = 1 ) 1 (stride=1) 1(stride=1 从输入图像的左上角开始对原图进行特征转换,最终得到特征图大小为 ( H × W ) × ( C × K × K ) (H \times W)\times (C \times K \times K) (H×W)×(C×K×K)
    在这里插入图片描述
  2. 卷积核的Im2col操作:假设有 C o u t Cout Cout个卷积核,每个卷积核大小为 C × ( K × K ) C\times (K \times K) C×(K×K) ,把卷积核进行矩阵变换,得到单个卷积核的尺寸为 C × ( K × K ) C \times (K\times K) C×(K×K)。依此类推,最终得到 C o u t × ( C × K × K ) Cout \times (C \times K \times K) Cout×(C×K×K) 大小的过滤矩阵(Filter Matrix)。
    在这里插入图片描述

  • 代码实现
import numpy as np

def get_im2col_indices(x_shape, field_height, field_width, padding=1, stride=1):
    # 解析输入张量的形状 (batch_size: 批次大小, channel: 通道数, height: 高度, width: 宽度)
    batch_size, channel, height, width = x_shape

    # 确保经过填充后的图像尺寸可以被卷积核滑动整除,否则抛出异常
    assert (height + 2 * padding - field_height) % stride == 0
    assert (width + 2 * padding - field_width) % stride == 0

    # 计算输出特征图的高度和宽度
    out_height = int((height + 2 * padding - field_height) / stride + 1)  # 输出高度
    out_width = int((width + 2 * padding - field_width) / stride + 1)    # 输出宽度

    # 构建卷积核在垂直方向上的起始索引 i0
    i0 = np.repeat(np.arange(field_height), field_width)  # 每个高度索引重复 field_width 次
    i0 = np.tile(i0, channel)  # 在通道维度上复制 channel 次

    # 构建卷积核在垂直方向上的滑动步长索引 i1
    i1 = stride * np.repeat(np.arange(out_height), out_width)  # 每个 out_height 索引重复 out_width 次,并乘以步长

    # 构建卷积核在水平方向上的起始索引 j0
    j0 = np.tile(np.arange(field_width), field_height)  # 每个宽度索引循环 field_height 次

    # 构建卷积核在水平方向上的滑动步长索引 j1
    j1 = stride * np.tile(np.arange(out_width), out_height)  # 每个 out_width 索引循环 out_height 次,并乘以步长

    # 将 i0 和 i1 结合,生成所有可能的垂直索引位置
    i = i0.reshape(-1, 1) + i1.reshape(1, -1)

    # 将 j0 和 j1 结合,生成所有可能的水平索引位置
    j = j0.reshape(-1, 1) + j1.reshape(1, -1)

    # 构建通道索引 k,每个通道对应 field_height * field_width 个位置
    k = np.repeat(np.arange(channel), field_height * field_width).reshape(-1, 1)

    # 返回通道、垂直、水平索引三元组,用于后续提取图像块
    return k, i, j

def im2col_indices(x, field_height, field_width, padding=1, stride=1):
    # 获取输入张量的通道数 C
    C = x.shape[1]

    # 对输入张量进行零填充,扩展其边界,以便处理边缘区域
    x_padded = np.pad(x, ((0, 0), (0, 0), (padding, padding), (padding, padding)), mode='constant')

    # 调用 get_im2col_indices 函数获取所有需要提取的图像块的索引
    k, i, j = get_im2col_indices(x.shape, field_height, field_width, padding, stride)

    # 根据索引从填充后的输入张量中提取图像块,并将其展平成二维矩阵
    cols = x_padded[:, k, i, j]

    # 调整矩阵形状,使其适合后续的矩阵运算(如卷积转换为矩阵乘法)
    cols = cols.transpose(1, 2, 0).reshape(C * field_height * field_width, -1)

    # 返回最终的图像块矩阵
    return cols

GEMM算法

  • 一般矩阵乘法(General Matrix Matrix Multiply, GEMM)将由卷积核产生的过滤矩阵乘以原图产生的特征图矩阵(Feature Matrix)的转置,得到大小为 C o u t × ( H × W ) Cout \times (H \times W) Cout×(H×W)的输出特征图矩阵。
    f e a t u r e m a p = F i l t e r M a t r i x ⋅ F e a t u r e M a t r i x T = [ ( C o u t × ( C × H × W ) ) ] ∗ [ ( ( C × H × W ) × ( H × W ) ) ] = C o u t × H × W \begin{align*} feature map &=Filter Matrix \cdot Feature Matrix^T \\ &=[(Cout\times (C \times H \times W))]^\ast [((C \times H \times W)\times(H \times W))] \\ &=Cout\times H \times W \end{align*} featuremap=FilterMatrixFeatureMatrixT=[(Cout×(C×H×W))][((C×H×W)×(H×W))]=Cout×H×W
  • 假设卷积核为 2 × 2 2×2 2×2的矩阵,输入原图像Image为 3 × 3 3×3 3×3的单通道矩阵。边界扩展为0,滑动步长为1( p a d d i n g = 0 , s t i d e = 1 , c = 1 , w = 3 , h = 3 , k = 2 padding=0,stide=1,c=1,w=3,h=3,k=2 padding=0,stide=1,c=1,w=3,h=3,k=2)。因此过滤矩阵的长宽w、 h均减少了1,经过Im2col变换后特征图矩阵的大小为 ( 2 × 2 ) × ( 1 × 2 × 2 ) (2 \times 2) \times (1 \times 2 \times 2) (2×2)×(1×2×2)
    Image = [ 3 2 1 0 1 2 3 1 1 ] ⇒ Feature Matrix = [ 3 2 0 1 2 1 1 2 0 1 1 3 1 2 1 1 ] \text{Image} = \begin{bmatrix}3 & 2 & 1 \\ 0 & 1 & 2 \\ 3 & 1 & 1\end{bmatrix} \Rightarrow \text{Feature Matrix} = \begin{bmatrix}3 & 2 & 0 & 1 \\ 2 & 1 & 1 & 2 \\ 0 & 1 & 1 & 3 \\ 1 & 2 & 1 & 1\end{bmatrix} Image= 303211121 Feature Matrix= 3201211201111231
  • 假设有2个大小均为2×2 的卷积核A、 B ( c o u t = 2 , c = 1 , k = 2 ) (cout=2, c=1, k=2) (cout=2,c=1,k=2),因此过滤矩阵大小为 2 × ( 1 × 2 × 2 ) 2 \times (1\times 2 \times 2) 2×(1×2×2)
    A = [ 0 1 1 2 ] , B = [ 2 1 1 3 ] ⇒ Filter Matrix = [ 0 1 1 2 2 1 1 3 ] A = \begin{bmatrix}0 & 1 \\ 1 & 2\end{bmatrix}, \quad B = \begin{bmatrix}2 & 1 \\ 1 & 3\end{bmatrix} \Rightarrow \text{Filter Matrix} = \begin{bmatrix}0 & 1 & 1 & 2 \\ 2 & 1 & 1 & 3\end{bmatrix} A=[0112],B=[2113]Filter Matrix=[02111123]
  • 输出的特征矩阵C为 C = Filter Matrix ⋅ Feature Matrix T C = \text{Filter Matrix} \cdot \text{Feature Matrix}^T C=Filter MatrixFeature MatrixT
    C = [ 0 1 1 2 2 1 1 3 ] × [ 3 2 0 1 2 1 1 2 0 1 1 3 1 2 1 1 ] ⇒ [ [ 0 1 1 2 ] [ 2 1 1 3 ] ] \begin{aligned} C&= \begin{bmatrix}0 & 1 & 1 & 2 \\ 2 & 1 & 1 & 3\end{bmatrix} \times \begin{bmatrix}3 & 2 & 0 & 1 \\ 2 & 1 & 1 & 2 \\ 0 & 1 & 1 & 3 \\ 1 & 2 & 1 & 1\end{bmatrix} \\ &\Rightarrow \begin{bmatrix}\begin{bmatrix}0 & 1 \\ 1 & 2\end{bmatrix} & \begin{bmatrix}2 & 1 \\ 1 & 3\end{bmatrix}\end{bmatrix} \end{aligned} C=[02111123]× 3201211201111231 [[0112][2113]]
  • 特征矩阵C中的 [ 0 1 1 2 ] \begin{bmatrix}0 & 1 \\ 1 & 2\end{bmatrix} [0112] [ 2 1 1 3 ] \begin{bmatrix}2 & 1 \\ 1 & 3\end{bmatrix} [2113]分别为输出的两个特征图。

CNN三大核心思想

核心思想概述

  • 卷积神经网络的三个核心思想是局部感知、权值共享、下采样技术。卷积神经网络的三大核心思想使得卷积神经网络能够提取图像物体的高维特征,感知图像中更丰富的信息。同时,经过权值共享和下来样操作,进一步减少网络的参数, 让卷积神经网络模型能够在规定时间内和有限的内存硬件下完成计算。
  • 卷积神经网络能够用自身独特的方式避免传统神经网络所引起的问题,其优点如下:

  1. 局部感知:每一个神经元节点不再与下一层的所有神经元节点相连接(全连接的方式),只与下一层的部分神经元进行连接。
  2. 权值共享: 一组连接可以共享同一个权重参数,或者多组连接共享同一个卷积核,不再是每条连接都有自己的权重。
  3. 下采样 Pooling :通过 Pooling 技术对输入的数据进行下来样压缩操作,减少输出节点。

  • 卷积神经网络通过局部感知和权值共享,保留像素间关联信息,并且大大减少所需参数的数量。通过Pooling 技术,进一步缩减网络参数数量,提高模型的鲁棒性,让模型可以持续地扩展深度,继续增加隐层。因此“局部感知、权值共享、下来样”被誉为卷积神经网络的三大核心思想。

局部感知

  • 图像中的空间关系通常表现为局部像素联系紧密,而远距离像素相关性较弱。因此,无需全局感知,只需逐层提取局部信息。随着网络加深,图像尺寸逐渐缩小,特征提取从局部到全局,最终综合得到图像的全局表征。
  • 图(a)展示了传统全连接神经网络,所有像素(每个像素对应一个神经元)与下一层的每个神经元相连,导致参数量巨大。而图(b)展示了卷积神经网络(CNN)的局部连接方式:每个隐层神经元仅与输入图像的局部区域(即感受野,对应卷积核大小)相连,显著减少了网络参数。这种稀疏连接方式既保留了空间局部性,又提升了计算效率。
    在这里插入图片描述
  • 由于每一层的输入图像和卷积核大小都不一样,因此会产生不同的感知区域,向下扩展网络的深度。另外,不同的感知区域能够感知图像中不同的纹理特征,从而随着卷积网络层的增加而获得更高维的图像特征。

权值共享

  • 权值共享是 CNN 的核心机制之一,它通过复用卷积核参数,实现:
    • ✅ 参数高效(减少冗余权重):如果一个卷积核(如 C)在图像的某个区域(如窗口 A)能检测到某种纹理或边缘特征,那么它在其他具有相似特征的区域(如窗口 B)同样适用。因此,无需为每个位置训练不同的卷积核,而是共享同一个卷积核,在整个图像上滑动检测相同模式的特征。
    • ✅ 特征复用(同一模式在不同位置检测):使得一个卷积核的权重矩阵(如 3×3 或 5×5)在整个图像上复用,极大减少参数量(例如,一个 3×3 卷积核仅需 9 个参数,而不是数百万个)。
    • ✅ 平移不变性(适应目标位置变化):由于同一个卷积核检测相同特征,无论目标出现在图像的哪个位置(如边缘、纹理、物体部分),网络都能识别,从而增强模型对平移变化的鲁棒性。
      在这里插入图片描述

下采样 Pooling

  • 在卷积神经网络中,输入给卷积层的图像可能很大,实际上并没有必要对原图进行操作,可以采用下采样(Pooling)技术,对输入的图像进行压缩,减少输出的总像素。
  • Pooling技术的优势:
  1. 减少过度拟合的可能性, 当网络中权重参数过多时,很容易在训练阶段造成过度拟合。
  2. 缩减图像尺寸,减少计算量,提升计算速度。
  3. 进一步提取图像高维的统计特征。

  • 常用的Pooling方法有如下两种:
  1. 最大池化(Max Pooling):取Pooling 窗口的最大值作为Pooling 特征。
  2. 均值池化(Mean Pooling):取Pooling 窗口的均值作为Pooling 特征。
    在这里插入图片描述
  • Max Pooling代码示例
import numpy as np

def max_pool_forward(x, pool_param):
    (N, C, H, W) = x.shape  # 获取输入矩阵的大小
    height = pool_param['height']  # Pooling 窗口高度
    width = pool_param['width']  # Pooling 窗口宽度
    stride = pool_param['stride']  # Pooling窗口滑动步长

    H_prime = 1 + (H - height) // stride  # 向下滑动的次数,也为 pooling 输出的高度
    W_prime = 1 + (W - width) // stride  # 向右滑动的次数,也为 pooling 输出的宽度

    out = np.zeros((N, C, H_prime, W_prime))  # 定义输出矩阵

    # 遍历 batch
    for n in range(N):
        for h in range(H_prime):
            for w in range(W_prime):
                h1 = h * stride  # (h1, w1) 为 pooling 窗口左上角第一个点
                w1 = w * stride
                h2 = h * stride + height
                w2 = w * stride + width  # (h2, w2) 为 pooling 窗口最后一个点
                window = x[n, :, h1:h2, w1:w2]  # 获得当前 pooling 窗口
                win_l = window.reshape((C, height * width))
                out[n, :, h, w] = np.max(win_l, axis=1)

    return out


# 测试
np.random.seed(8)
x = np.random.randint(5, size=(1, 1, 4, 4))  # 随机产生一个 [1, 1, 4, 4] 的矩阵
pool_param = {'height': 2, 'width': 2, 'stride': 2}

out = max_pool_forward(x, pool_param)
print("Input:\n", x)
print("Output:\n", out)
Input:
 [[[[3 4 1 1]
   [2 0 3 0]
   [0 4 1 3]
   [2 3 4 1]]]]
Output:
 [[[[4. 3.]
   [4. 4.]]]]
Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐