基于XC7Z100+OV5640(DSP接口)YOLO人脸识别前向推理过程(部分2)

发布时间 2023-06-09 19:28:22作者: 李白的白

认识神经网络

1. 认识神经网络中的神经元

  • 神经网络是模仿生物神经网络的结构和功能的数学模型或计算模型,由大量的节点或称神经元相互连接构成。
  • 神经元是神经网络的基本成分,它接收来自其他神经元的输入信号,通过权重、偏置和激活函数来产生输出信号。
  • 权重(weight)是表示输入信号的重要性的参数,偏置(bias)是表示神经元被激活的容易程度的参数,激活函数(activation function)是决定输出结果的非线性函数,表示如何激活输入信号的总和,有不同的形式和作用。
  • 神经元的工作原理可以用以下公式表示:

\[y = h(\sum_{i=1}^n w_ix_i + b) \]

\[a = \sum_{i=1}^n w_ix_i + b \]

\[y = h(a) \]

其中:

  • \(x_i\) 是第 \(i\) 个输入信号
  • \(w_i\) 是第 \(i\) 个输入信号对应的权重,表示输入信号的重要性
  • \(b\)偏置(相当于负阈值),表示神经元被激活的容易程度
  • \(a\) 是输入信号的加权求和,也称为中间变量或净输入
  • \(h\) 是激活函数,决定如何激活输出信号,可以是线性或非线性函数
  • \(y\) 是输出信号(是神经元的输出)
  • \(n\) 是输入信号的个数

2. 认识神经网络的结构

神经网络

  • 神经网络是由大量的节点(或称神经元)相互连接构成的运算模型,模拟生物神经网络的结构和功能
  • 神经网络可以分为不同的层次和类型,根据不同的任务和数据进行设计和训练
  • 神经网络可以用于解决人工智能领域的常见问题,如图像识别、语音识别、自然语言处理等

层次

  • 神经网络通常由以下三种层次组成:
    • 输入层(input layer):负责接收输入数据,如图像、文本、声音等
    • 隐藏层(hidden layer):位于输入层之后,输出层之前的一层或多层,负责对输入数据进行特征提取和变换,通常不对用户展示
    • 输出层(output layer):负责输出神经网络的计算结果,如分类标签、预测值等
  • 神网络中每一层都由若干个节点组成,每个节点都与下一层的全部节点有连接(称为全连接),每个连接都有对应的权重和偏置
  • 神网络中每一层都有一个激活函数,用于处理每个节点的输出信号
  • 神网络中层数的计算不包括输入层,只从隐藏层开始算起,如果有三个以上的层(包含输出层),则称为深度神经网络

类型

  • 根据不同的结构和功能,神经网络可以分为不同的类型,以下是一些常见的类型:
    • 前馈神经网络:数据只在一个方向上流动,即从输入到输出,不形成回路或循环,是最基本和常见的神经网络类型
    • 卷积神经网络:利用卷积运算来提取图像等数据中的局部特征,适用于图像识别、模式识别等计算机视觉任务
    • 循环神经网络:利用反馈回路来处理时间序列数据,能够记忆之前的状态,并影响后续输出,适用于语音识别、文本生成等自然语言处理任务

2.1 以儿童自闭症诊断为例

自闭症:一种发育障碍性疾病,主要表现为社交障碍、语言障碍和刻板行为。自闭症的原因尚不明确,可能与遗传、环境、脑部异常等因素有关。自闭症没有根治的方法,但可以通过早期干预和康复训练来改善症状。
  • 以一个儿童自闭症诊断的例子来说明神经网络的结构,包括三个层次:

    • 输入层(input layer):接收样本信息,如儿童的社交、语言、刻板行为等指标

    • 隐藏层(hidden layer):在输入层之后,输出层之前的层,可以有多个,不对用户展示,对输入信号进行加权求和和激活函数处理,如儿童自闭症的三大症状

    • 输出层(output layer):输出神经网络的计算结果,如儿童自闭症的诊断结果

    • 全连接(fully connected):表示每一层的每一个节点都和下一层的全部节点有连接的神经网络,简称 FC

计算神经网络的层数(layer number),不包括输入层,只从隐藏层开始算起

  • 假设有三个影响儿童自闭症诊断的因素:社交障碍、语言障碍和刻板行为。每个因素都有一个值表示其严重程度。
  • 假设有一个简单的神经网络来对儿童自闭症进行诊断。它有三个输入节点分别对应三个因素,三个隐藏节点分别对应三大症状,一个输出节点表示诊断结果。
  • 假设每个节点都使用 sigmoid 函数作为激活函数。sigmoid 函数可以用以下公式表示:

\[h(x) = \frac{1}{1 + e^{-x}} \]

它可以将任意实数映射到 \((0,1)\) 区间内。

  • 假设每个连接都有一个权重值,每个隐藏节点和输出节点都有一个偏置值。这些值可以通过训练数据来学习和调整。
  • 假设有一个儿童的信息如下:社交障碍值为 0.8,语言障碍值为 0.6,刻板行为值为 0.7。那么神经网络的正向传播计算过程如下:

2.1.1 计算隐藏层

  • 对于第一个隐藏节点 \(A_1\),它接收三个输入信号 \(x_1 = 0.8, x_2 = 0.6, x_3 = 0.7\) 和对应的权重 \(w_{11}^{(1)}, w_{12}^{(1)}, w_{13}^{(1)}\)。它还有一个偏置 \(b_1^{(1)}\)。它先计算一个中间变量 \(z_1^{(1)}\)

\[z_1^{(1)} = w_{11}^{(1)}x_1 + w_{12}^{(1)}x_2 + w_{13}^{(1)}x_3 + b_1^{(1)} \]

然后它用激活函数 \(h\) 来计算输出信号 \(a_1^{(1)}\)

\[a_1^{(1)} = h(z_1^{(1)}) = \frac{1}{1 + e^{-z_1^{(1)}}} \]

  • 对于第二个隐藏节点 \(A_2\) 和第三个隐藏节点 \(A_3\) 的计算过程类似,只是用相应的权重和偏置替换即可。最后得到三个输出信号 \(a_1^{(1)}, a_2^{(1)}, a_3^{(1)}\)

2.1.2 计算输出层

  • 对于输出节点 \(Y\),它接收三个输入信号 \(a_1^{(1)}, a_2^{(1)}, a_3^{(1)}\) 和对应的权重 \(w_{11}^{(2)}, w_{12}^{(2)}, w_{13}^{(2)}\)。它还有一个偏置 \(b_1^{(2)}\)。它先计算一个中间变量 \(z_1^{(2)}\)

\[z_1^{(2)} = w_{11}^{(2)}a_1^{(1)} + w_{12}^{(2)}a_2^{(1)} + w_{13}^{(2)}a_3^{(1)} + b_1^{(2)} \]

然后它用激活函数 \(h\) 来计算输出信号 \(y\)

\[y = h(z_1^{(2)}) = \frac{1}{1 + e^{-z_1^{(2)}}} \]

  • 最后得到输出信号 \(y\) 的值,在 \((0, 0.5)\) 区间内表示没有自闭症,在 \((0.5, 0)\) 区间内表示有自闭症。

3. 认识神经网络的正向传播计算过程

正向传播(forward propagation)

  • 正向传播是指从输入到输出方向进行数据流动和计算的过程

    • 从输入层到输出层依次进行加权求和和激活函数处理,得到最终输出结果
  • 正向传播分为三个步骤:加权求和、激活函数、输出结果

  • 以儿童自闭症诊断为例,介绍正向传播的计算过程

  • 第一步:加权求和

    • 对于隐藏层中的每个节点,将输入信号和权重相乘,然后加上偏置,得到一个中间变量 $$Z$$
    • 对于输出层中的每个节点,将隐藏层的输出信号和权重相乘,然后加上偏置,得到一个中间变量 $$Z$$
    • 计算公式为 $$Z_j^{(l)} = \sum_{i=1}^n w_{ij}^{(l)} x_i^{(l)} + b_j^{(l)}$$
      • 其中 $$Z_j^{(l)}$$ 是第 $$l$$ 层第 $$j$$ 个节点的中间变量,
      • \[w_{ij}^{(l)}$$ 是第 $$l$$ 层第 $$i$$ 个节点到第 $$j$$ 个节点的权重, \]

      • \[b_j^{(l)}$$ 是第 $$l$$ 层第 $$j$$ 个节点的偏置 \]

    • 对于每个节点,将中间变量 $$Z$$ 输入到激活函数中,得到输出信号 $$A$$
    • 激活函数可以有不同的形式,比如 sigmoid 函数、tanh 函数、ReLU 函数等
    • 计算公式为 $$A_j^{(l)} = f(Z_j^{(l)})$$
      • 其中 $$A_j^{(l)}$$ 是第 $$l$$ 层第 $$j$$ 个节点的输出信号或下一层的输入信号,
      • \[f$$ 是激活函数 \]

    • 对于输出层中的每个节点,将输出信号作为最终结果返回给用户
    • 输出结果可以是二分类、多分类或回归等不同类型

反向传播和梯度下降

  • 反向传播和梯度下降是神经网络进行训练和优化的过程,从输出层到输入层反向传递误差,并根据成本函数和学习率调整权重和偏置³⁴。
  • 反向传播可以用以下公式表示:

\[\delta^{(L)} = \nabla_a C \odot f'(z^{(L)}) \]

\[\delta^{(l)} = ((W^{(l)})^\top \delta^{(l+1)}) \odot f'(z^{(l)}) \]

其中:

  • \(\delta^{(l)}\) 是第 \(l\) 层的误差(敏感度)

  • \(\nabla_a C\) 是成本函数对输出层激活值的偏导数

  • \(\odot\) 是哈达玛积(对应元素相乘)

  • \(f'\) 是激活函数的导数

  • 梯度下降可以用以下公式表示:

\[W^{(l)} = W^{(l)} - \eta \frac{\partial C}{\partial W^{(l)}} = W^{(l)} - \eta \delta^{(l+1)} (a^{(l)})^\top \]

\[b^{(l)} = b^{(l)} - \eta \frac{\partial C}{\partial b^{(l)}} = b^{(l)} - \eta \delta^{(l+1)} \]

其中:

  • \(\eta\) 是学习率(步长)

  • \(\frac{\partial C}{\partial W^{(l)}}\)\(\frac{\partial C}{\partial b^{(l)}}\) 是成本函数对权重和偏置的偏导数

  • 反向传播(back propagation)和梯度下降(gradient descent)可以用于监督学习或标记数据集来训练算法,并最小化成本函数,提高准确性。

认识卷积神经网络

卷积神经网络的简介

  • 卷积神经网络(Convolutional Neural Network,简称CNN)是一种能够在保留图像原有空间关系的前提下进行运算的神经网络

  • CNN的简称有时也写作CN,大家以后看到文章里面提到CN时,要知道它指的是卷积神经网络

  • CNN相比于第一章讲的普通神经网络,主要多了卷积层和池化层这两种结构

  • CNN的连接顺序一般是卷积层-激活函数-池化层-全连接层-输出层,其中池化层有时会被省略

  • 卷积神经网络的结构和组成

    • 卷积神经网络由输入层、卷积层、激活函数、池化层、全连接层、输出层等组成

      • 输入层:接收图像数据,将其展开成一维向量

      • 卷积层:使用卷积核对输入数据进行卷积运算,提取特征

      • 激活函数:对卷积层的输出进行非线性变换,增加模型的表达能力

      • 池化层:对激活函数的输出进行降采样,减少参数和计算量,防止过拟合

      • 全连接层:将池化层的输出连接到输出层,进行分类或回归等任务

      • 输出层:根据任务的不同,使用不同的激活函数和损失函数,输出预测结果

    • 卷积神经网络可以有多个卷积层和池化层,它们之间的连接顺序一般是卷积层-激活函数-池化层

    • 卷积神经网络的结构示意图如下:

      输入层 -> 卷积层 -> 激活函数 -> 池化层 -> ... -> 全连接层 -> 输出层
      
  • 卷积运算的过程和概念

    • 卷积运算是卷积层的主要运算,它是一种滤波器运算,可以提取图像的特征

    • 卷积运算的过程是用一个卷积核(也叫滤波器或权重矩阵)在输入数据上滑动,并对应位置相乘再求和,得到输出数据的一个元素,然后重复这个过程直到覆盖所有输入数据

    • 卷积运算涉及到以下几个概念:

      • 步长(stride)

        • 步长是指卷积核在输入数据上滑动时每次移动的距离,常用的步长是 1 或 2
        • 步长越大,输出数据的尺寸越小,反之亦然
      • 填充(padding)

        • 填充是指在输入数据的边缘添加一些额外的元素(通常是 0),以保持输出数据和输入数据的尺寸一致或减少尺寸缩小的幅度
        • 填充可以避免边缘信息的丢失,也可以调整输出数据的尺寸以适应后续层的需要
      • 通道(channel)

        • 通道是指输出数据体的通道数量,它取决于卷积核的数量,每个卷积核对应一个通道
        • 通道越多,输出数据包含的特征越多,反之亦然

激活函数的作用

  • 激活函数是一种非线性函数,可以增加神经网络的非线性拟合能力,使其能够处理复杂的问题
  • 激活函数有多种选择,如Sigmoid、Tanh、ReLU等,其中ReLU函数最常用,因为它具有梯度不饱和、稀疏激活和计算速度快等优点
  • ReLU函数的公式是$$f(x) = max(0,x)$$,它的图像是一个折线,当x小于0时,输出为0;当x大于0时,输出为x本身
  • Sigmoid函数:\(f(x) = \frac{1}{1+e^{-x}}\),具有输出范围有限、导数容易求等优点
  • Tanh函数:\(f(x) = \frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}\),具有零均值、导数容易求等优点

池化层的操作

  • 池化层的主要操作是池化操作,它是一种降采样操作,可以减少数据量和参数量,防止过拟合
  • 池化操作的过程是将一个池化核(也叫窗口或感受野)在输入图像上滑动,并从每个窗口内选取一个代表值作为输出图像的一个像素值
  • 池化运算的过程是:用一个小矩阵(称为池化窗口或池化核)在一个大矩阵(称为输入数据或特征图)上滑动,并对应区域进行某种操作(如求最大值或平均值),得到一个新矩阵(称为输出数据或特征图)
  • 池化运算涉及两个重要概念:池化尺寸和池化步长
    • 池化尺寸(pooling size)是指池化窗口或池化核的大小,常用的池化尺寸是 2x2 或 3x3
    • 池化步长(pooling stride)是指池化窗口在输入数据上滑动时每次移动的距离,常用的池化步长与池化尺寸相同
  • 池化操作有两种常用的方式:
    • 最大值池化(max pooling):选取窗口内的最大值作为代表值(最大值池化是一种常用的池化运算,它可以保留最显著的特征而抑制噪声)
    • 平均值池化(average pooling):选取窗口内的平均值作为代表值

YOLOv3-Tiny网络结构与前向计算过程简介

YOLOv3-Tiny是一种轻量级的目标检测算法,它由23层网络构成,包括卷积层、池化层、路由层、上采样层和YOLO层。YOLO层是最终输出特征图的层,它有两个尺度,分别是13x13和26x26,每个网格可以预测3个边界框,共有80个类别。YOLO层的输出格式是k*(1+c+4),其中k是预测框的数量,1是置信度,c是类别概率,4是边界框的位置参数。在前向计算过程中,网络会对输入图像进行多次卷积、池化、路由和上采样操作,以提取特征并降低维度。在YOLO层输出后,还需要进行非极大值抑制(NMS)操作,以消除冗余的边界框,并保留得分最高的那个。

  • 网络结构

    这是YOLOv3-Tiny模型的整体架构,由不同类型的层组成,每一层都有自己的功能和参数。网络结构决定了模型的性能和复杂度。

    • 24层,主要是卷积层和最大值池化层
    • 两个YOLO层,分别在第16层和第23层
    • 两个路由层,分别在第17层和第20层
    • 一个上采样层,在第19层
  • 前向计算过程

    这是模型在接收输入图像数据后,经过各个层的处理,最终输出特征图的过程。前向计算过程反映了模型的逻辑和流程。

    输入图像为416x416x3的彩色图像,经过卷积层和池化层后,到达第15层时,输出为13x13x256的特征图。

    第16层是第一个yolo层,输出为13x13x255的特征图。

    第17层是路由层,将第13层的输出引到第18层。

    第19层是上采样层,将输入数据扩大两倍,输出为26x26x128的特征图。

    第20层是路由层,将第19层和第8层的输出拼接起来,输出为26x26x384的特征图。

    第21和22层是卷积层,最后第23层是第二个yolo层,输出为26x26x255的特征图。

    • 输入图像数据:\(416*416*3\)

      这是模型需要处理的原始数据,通常是彩色图片,有三个通道\((R,G,B)\),每个通道有\(416*416\)个像素值。输入图像数据决定了模型可以识别的物体类型和场景范围。

    • 卷积操作:使用\(3*3\)的卷积核,步长为1,填充为1,没有偏置

      这是模型中最基本和最重要的操作,通过使用一定数量和尺寸的卷积核,在输入数据上进行滑动窗口式的乘加运算,提取出不同的特征。卷积操作可以增强模型的表达能力和泛化能力。

      卷积层多通道计算的过程如下:

      卷积层多通道计算是指当输入图像或特征图有多个通道时,如 RGB 彩色图像有三个通道,卷积层如何对其进行卷积运算。卷积层多通道计算的基本原理是:

      • 卷积核的通道数必须和输入图像或特征图的通道数相同,例如,如果输入是 3 通道的 RGB 图像,那么卷积核也必须是 3 通道的。
      • 卷积核在每个通道上分别对输入图像或特征图进行卷积运算,然后将每个通道上的卷积结果相加,得到一个单通道的输出特征图。
      • 卷积层可以有多个卷积核,每个卷积核都会产生一个单通道的输出特征图,最终将这些输出特征图堆叠起来,形成一个多通道的输出特征图。
      • 卷积层的输出特征图的通道数等于卷积核的个数,例如,如果卷积层有 10 个卷积核,那么输出特征图就有 10 个通道。

      举例说明,假设输入图像是一个 $553 $的矩阵,表示一个 \(5*5\)\(RGB\) 图像,其中每个元素是一个三元组,表示$ R、G、B$ 三个通道上的像素值。假设卷积核是一个$ 333$ 的矩阵,表示一个 \(3*3\)\(RGB\) 卷积核,其中每个元素也是一个三元组,表示$R、G、B $三个通道上的权重值。假设步长为 1,填充为 0。那么卷积层多通道计算的过程如下:

      • 首先,在输入图像上取一个与卷积核尺寸相同的区域,即一个$ 333$的矩阵。然后将这个区域和卷积核在每个通道上对应位置相乘,并将乘积相加。例如,第一个位置上的计算为 \((1,2,3) * (0.1,0.2,0.3) = 0.1 + 0.4 + 0.9 = 1.4\)。这样得到一个单一的数值作为输出特征图的第一个元素。
      • 然后,在输入图像上沿着水平方向移动一个步长(即一格),取另一个与卷积核尺寸相同的区域,并重复上述计算过程。例如,第二个位置上的计算为 \((2,3,4) * (0.1,0.2,0.3) = 0.2 + 0.6 + 1.2 = 2\)。这样得到输出特征图的第二个元素。
      • 继续在输入图像上沿着水平方向移动步长,并重复计算过程,直到到达输入图像的右边界。这样得到输出特征图的第一行。
      • 然后,在输入图像上沿着垂直方向移动一个步长(即一格),并回到左边界,取另一个与卷积核尺寸相同的区域,并重复上述计算过程。这样得到输出特征图的第二行。
      • 继续在输入图像上沿着垂直方向移动步长,并重复计算过程,直到到达输入图像的下边界。这样得到输出特征图的最后一行。
      • 最终得到一个 $3*3 $的矩阵作为输出特征图。

      如果卷积层有多个卷积核,则对每个卷积核都重复上述计算过程,并将每个输出特征图堆叠起来作为最终输出特征图。例如,如果有两个卷积核,则最终输出特征图是一个 332 的矩阵。

    • 池化层:对输入数据进行降采样操作,用一个固定大小的窗口在数据上滑动,取最大值或平均值作为输出

      • \[output = maxpool(x) \quad or \quad output = avgpool(x) \]

      • 其中\(x\)是输入数据
      • 例如:输入数据为4x4的矩阵,池化窗口为2x2的矩阵,步长为2,则输出数据为2x2的矩阵
    • 卷积层:对输入数据进行滑动窗口操作,用卷积核与数据相乘再累加,得到输出特征图

      • \[output = \sum_{i=1}^{n} x_i * w_i + b \]

      • 其中\(x_i\)是输入数据,\(w_i\)是卷积核参数,\(b\)是偏置项(可选),\(n\)是通道数
      • 例如:输入数据为5x5x3的矩阵,卷积核为3x3x3的矩阵,步长为1,无填充,则输出数据为3x3x1的矩阵
    • 路由层:对输入数据进行拼接操作,将不同层的数据按照通道维度连接起来,得到输出

      • \[output = concat(x_1, x_2, ..., x_n) \]

      • 其中\(x_1, x_2, ..., x_n\)是不同层的输入数据
      • 例如:输入数据为两个26x26x128的矩阵,则输出数据为26x26x256的矩阵
    • yolo层:对输入数据进行目标检测操作,将每个网格单元分配给不同的预测框,并计算置信度、类别概率和位置信息,得到输出

      • \[output = yolo(x) \]

      • 其中\(x\)是输入数据

      • 输出格式为k*(1+4+C),其中k是预测框的数量,1是置信度,4是位置信息(中心坐标、宽度、高度),C是类别数量

    • 上采样层:对输入数据进行放大操作,用一个固定比例将数据中的每个元素复制到相邻位置,得到输出

      • \[output = upsample(x, scale) \]

      • 其中\(x\)是输入数据,\(scale\)是放大比例
      • 例如:输入数据为2x2的矩阵,放大比例为2,则输出数据为4x4的矩阵
    • 批归一化:对每个卷积层的输出进行归一化处理,提高训练效率和稳定性

      仅供了解,真正实现时会将BN参数与卷积层合并

      批归一化(Batch Normalization):在每个卷积层之后,对输入数据进行归一化处理,减少内部协变量偏移,加快收敛速度,提高泛化能力。具体公式为:$$y_i=\gamma \frac{x_i-\mu_\beta}{\sqrt{\sigma_\beta^2+\epsilon}}+\beta$$

      其中:

      \(x_i\)是输入数据,

      \(y_i\)是输出数据,

      \(\mu_\beta\)\(\sigma_\beta^2\)是输入数据的均值和方差(在训练时自动计算),

      \(\gamma\)\(\beta\)是可学习的权重和偏置参数(在训练后提供),

      \(\epsilon\)是一个很小的值(防止除0)。

      这是模型中常用的一种技术,通过对每个卷积层的输出进行归一化处理,使其均值为0,方差为1,减少内部协变量偏移,提高训练效率和稳定性。批归一化可以加速模型的收敛速度和防止过拟合。

    • 激活函数:使用Leaky ReLU函数,避免梯度消失问题

      Leaky ReLU激活函数:在每个卷积层之后(除了最后一个),对输入数据进行非线性变换,增加网络的表达能力。具体公式为:$$f(x)=\begin{cases} x & \text{if } x>0 \ 0.01x & \text{otherwise} \end{cases}$$其中\(x\)是输入数据,\(f(x)\)是输出数据。

      这是模型中必不可少的一种函数,通过对每个卷积层的输出进行非线性变换,增加模型的非线性能力,使其可以拟合更复杂的函数。激活函数可以提高模型的拟合能力和灵活性。

    • 最大值池化:使用2*2的池化核,步长为2,降低数据尺寸和特征数量

      这是模型中常用的一种操作,通过使用一定尺寸的池化核,在输入数据上进行滑动窗口式的取最大值运算,降低数据尺寸和特征数量,减少计算量和内存消耗。最大值池化可以压缩数据和提取显著特征。

    • 路由层:将某一层的输出直接引到另一层作为输入,增加特征多样性

      路由层(Route Layer):在网络中有两个路由层,分别在第17层和第20层。路由层的作用是将某些层的输出引到另外一些层作为输入,相当于一个导线。例如,在第17层时,将第13层的输出引到第18层;在第20层时,将第19层和第8层的输出拼接起来。

      这是YOLOv3-Tiny模型中特有的一种层,通过将某一层的输出直接引到另一层作为输入,增加特征多样性和丰富性。路由层可以实现特征融合和跨层连接。

    • 上采样层(Upsample):将输入数据的尺寸放大两倍,增加数据量和特征分辨率

      上采样层是一种用于增加输入数据的尺寸的层,通常用于卷积神经网络中的图像处理。它的作用是将输入数据中的每个像素或特征图复制多次,从而扩大数据的高度和宽度。上采样层可以有不同的方法,例如最近邻插值、双线性插值、反卷积等。上采样层的目的是恢复数据的细节,或者与下采样层(如最大池化层)配合实现特征融合。

      举例来说,如果我们有一个 2x2 的输入数据,如下所示:

      1 2
      3 4

      如果我们使用一个上采样层,将其尺寸放大两倍,即 size=(2,2),那么输出数据就会变成 4x4 的,如下所示:

      1 1 2 2
      1 1 2 2
      3 3 4 4
      3 3 4 4

      上采样层(Upsample Layer):在网络中只有一个上采样层,在第19层。上采样层的作用是将输入数据扩大一定倍数,相当于一个放大镜。

      这是YOLOv3-Tiny模型中特有的一种层,通过将输入数据的尺寸放大两倍,增加数据量和特征分辨率。上采样层可以恢复数据细节和提高检测精度。

    • YOLO层:输出最终的特征图,包含预测框的位置、置信度和类别信息

      yolo层(Yolo Layer):在网络中有两个yolo层,分别在第16层和第23层。yolo层的作用是将输入特征图转换为目标检测的输出,包括边界框的位置、置信度和类别概率。具体公式为:$$b_x=\sigma(t_x)+c_x$$ $$b_y=\sigma(t_y)+c_y$$ $$b_w=p_we^{t_w}$$ $$b_h=p_he^{t_h}$$ $$p_o=\sigma(t_o)$$ $$p_c=\frac{e{t_c}}{\sum_{j=0}{C-1}e^{t_j}}$$其中\(b_x,b_y,b_w,b_h\)是边界框的中心坐标和宽高,\(p_o\)是置信度,\(p_c\)是类别概率,\(t_x,t_y,t_w,t_h,t_o,t_c\)是网络输出的原始值,\(\sigma\)是sigmoid函数,\(c_x,c_y\)是网格单元的左上角坐标,\(p_w,p_h\)是预设的边界框的宽高,\(C\)是类别数。

      yolo层的输出格式为\(k\times(1+C+4)\),其中\(k\)是每个网格单元预测的边界框数。

      这是YOLOv3-Tiny模型中最核心的一种层,通过将输入数据划分为多个小区域,并在每个区域内预测多个候选框及其位置、置信度和类别信息。YOLO层可以实现端到端的物体检测。

    • 非极大值抑制(Non-Maximum Suppression):在网络输出后,为了消除冗余的边界框,需要进行非极大值抑制。

      非极大值抑制的思想是:如果有多个边界框都对应同一个物体,那么只选出得分最高的那个边界框,剩下的边界框就会被丢弃掉。得分是指所属类别的概率乘以预测边界框是否包含目标物体的置信度。
      

      非极大值抑制的具体步骤如下:

      • 对于每个类别,按照得分从高到低排序所有的边界框。
      • 选择得分最高的边界框作为参考框,并将其保留。
      • 计算其他边界框与参考框的交并比(Intersection over Union),如果大于某个阈值(例如0.5),则认为它们重叠过多,将其删除。
      • 重复上述步骤,直到所有的边界框都被处理完毕。
      • 对于其他类别,重复上述过程。

YOLOv3-Tiny BN层与Conv层融合

  • 主要内容
    • 介绍了 YOLOv3-Tiny 网络中 BN 层(批归一化层)与 Conv 层(卷积层)融合的原理和代码实现
    • BN 层是一种用于加速神经网络训练和提高泛化能力的方法,它通过对每个批次的数据进行归一化处理,减少了内部协变量偏移
    • Conv 层是一种用于提取图像特征的方法,它通过对输入数据进行滑动窗口卷积操作,得到不同卷积核对应的特征图
    • BN 层与 Conv 层融合是一种优化技术,它通过将 BN 层的参数融合到 Conv 层的权重和偏置中,减少了计算量和内存占用
    • 通过推导 BN 层和 Conv 层的公式,得到融合后的新公式,其中新权重等于原权重乘以伽马除以方差的平方根,新偏置等于原偏置加上 beta 减去均值乘以伽马除以方差的平方根
    • 通过 Python 代码实现了 BN 层与 Conv 层融合的过程,主要使用了 markmap-lib 和 markmap-view 这两个库,分别用于转换 markdown 数据和渲染思维导图
    • 还介绍了量化类功能,即将浮点数权重转换为整数权重,以便进行 INT8 的量化操作,提高模型在移动设备上的运行效率
  • BN层与Conv层融合的原理

    • BN层的公式和参数

      BN层的公式:\(y = \gamma \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} + \beta\)

      • \(x\)是输入,\(y\)是输出,\(\mu\)是均值,\(\sigma^2\)是方差,\(\epsilon\)是防止除零的小数,\(\gamma\)\(\beta\)是权重和偏置
      • \(\mu\)\(\sigma^2\)是训练后得到的结果,\(\gamma\)\(\beta\)是BN层的参数
      • BN层是一种归一化层,它可以提高模型的训练速度和泛化能力
      • BN层的输入和输出之间的关系由四个参数决定:伽马(gamma)、贝塔(beta)、均值(mu)和方差(sigma)
      • 伽马和贝塔可以看作是BN层的权重和偏置,均值和方差是在训练完成后得到的统计量
    • Conv层的公式和参数

      Conv 层的公式:\(y = w * x + b\) ,其中 \(w\) 是权重(卷积核),\(x\) 是输入(特征图),\(b\) 是偏置(YOLOv3-Tiny 中没有使用),\(*\) 是卷积操作

      • Conv层是一种卷积层,它可以提取图像中的特征
      • Conv层的输出由权重(w)和输入(x)的乘积加上偏置(b)得到
      • 在YOLOv3-Tiny网络中,Conv层没有使用偏置
    • BN层与Conv层的融合方法

      BN层与卷积层融合的公式:\(y = (\gamma / \sqrt{\sigma^2 + \epsilon}) * (w * x) + (\beta - \gamma * \mu / \sqrt{\sigma^2 + \epsilon})\)

      • 可以看成新的卷积层:\(y = w' * x + b'\)
      • \(w' = \gamma / \sqrt{\sigma^2 + \epsilon} * w\)
      • \(b' = \beta - \gamma * \mu / \sqrt{\sigma^2 + \epsilon}\)
      • 融合后可以减少计算量,提高速度
      • BN层与Conv层的融合是将BN层的参数融合到Conv层的权重和偏置中,从而简化计算过程
      • 融合后的公式可以表示为一个新的权重(W')和一个新的偏置(b')与输入(x)的乘积加和
      • 可以看成新的卷积层,权重为\(\frac{\gamma}{\sqrt{\sigma^2+\epsilon}}w\),偏置为\(\beta-\frac{\gamma\mu}{\sqrt{\sigma^2+\epsilon}}\)
    • BN层与Conv层融合的好处

      • 简化计算过程,提高运行速度
      • 减少参数数量,节省内存空间
  • Python代码里的实现方法

    • 调用YOLOv3-Tiny网络并加载模型文件
    • 定义一个新的网络类并进行转换,以便进行量化操作(后面会讲)
    • 设置哪些层需要进行融合,例如 layer0.conv 和 layer0.bn
    • 打印融合前后的网络结构和参数,观察变化
    • 融合后的网络结构中,BN层变成了Identity层,相当于直通操作
    • 融合后的网络参数中,Conv层有了偏置,相当于融合了BN层的参数

根据网页搜索结果,我尝试用中文详细解释YOLOv3-Tiny BN层与Conv层融合,并举例说明:

YOLOv3-Tiny是一个轻量级的目标检测模型,它的网络结构包含了卷积层(convolutional)、池化层(maxpool)、路由层(route)、上采样层(upsample)和输出层(yolo)。其中,每个卷积层之后都有一个批量归一化层(batch normalization,BN),用于加速收敛、提高泛化能力和防止梯度消失。BN层的作用是对每个batch中的样本进行归一化处理,使其均值为0,方差为1,并且加上一个放缩系数和平移系数,这两个系数是可学习的参数。

BN层与Conv层融合的原理是利用线性代数的性质,将两个线性变换合并成一个线性变换。具体来说,假设Conv层的输出为y,BN层的输出为z,那么有:

\[y = W_{conv}x + b_{conv} \\ z = \gamma \frac{y - \mu}{\sqrt{\sigma^2 + \epsilon}} + \beta \]

其中,\(W_{conv}\)\(b_{conv}\)是Conv层的权重和偏置,\(\gamma\)\(\beta\)是BN层的放缩系数和平移系数,\(\mu\)\(\sigma^2\)是BN层计算的均值和方差,\(\epsilon\)是一个很小的数,防止分母为0。将两个式子合并,可以得到:

\[z = (\gamma \frac{W_{conv}}{\sqrt{\sigma^2 + \epsilon}})x + (\gamma \frac{b_{conv} - \mu}{\sqrt{\sigma^2 + \epsilon}} + \beta) \]

可以看出,这相当于一个新的Conv层,其权重和偏置为:

\[W' = \gamma \frac{W_{conv}}{\sqrt{\sigma^2 + \epsilon}} \\ b' = \gamma \frac{b_{conv} - \mu}{\sqrt{\sigma^2 + \epsilon}} + \beta \]

这样就可以用一个新的Conv层代替原来的Conv层和BN层,减少计算量和内存占用。需要注意的是,这种融合只能在模型推理阶段进行,在模型训练阶段不能把BN和Conv层合并,因为需要学习的是Conv层中卷积核的参数,而把二者合并实际上就是直接在卷积核上加了一个线性运算,在参数更新的过程中BN层不会给模型带来额外的信息,相当于没有BN的存在。

举例说明:假设有一个Conv层和一个BN层,Conv层的输出通道数为16,输入通道数为3,卷积核大小为3x3,没有偏置。那么Conv层的权重矩阵\(W_{conv}\)的维度为(16, 3, 3, 3),BN层的放缩系数\(\gamma\)、平移系数\(\beta\)、均值\(\mu\)、方差\(\sigma^2\)都是长度为16的向量。如果要将这两个层融合成一个新的Conv层,那么需要先将\(W_{conv}\)转换为(16, 27)的矩阵(即将每个卷积核展平为长度为27的向量),然后计算新的权重矩阵\(W'\)和偏置向量\(b'\)

\[W' = diag(\gamma) \frac{W_{conv}}{\sqrt{\sigma^2 + \epsilon}} \\ b' = diag(\gamma) \frac{-\mu}{\sqrt{\sigma^2 + \epsilon}} + \beta \]

其中diag(\(\gamma\))表示以\(\gamma\)为对角元素的对角矩阵。最后再将\(W'\)转换回(16, 3, 3, 3)的维度即可。

量化后的定点运算原理

  • 量化:把浮点数转换成定点数的过程
  • 定点数:一种用固定位数表示小数的方法
  • 浮点数:一种用科学计数法表示小数的方法
  • 量化的目的:减少计算量和内存占用,提高运算速度和效率

量化后的定点运算公式

  • 假设S是浮点数,Q是变换系数,C是定点数,Z是零点
  • 量化公式:$$S = Q \times (C - Z)$$
  • 反量化公式:$$C = \frac{S}{Q} + Z$$
  • Q和Z可以根据不同的量化方法和范围进行选择

量化后的定点乘法运算

  • 假设R1和R2是两个浮点数,R3是它们的乘积
  • 假设S1,S2,S3是它们对应的变换系数,Q1,Q2,Q3是它们对应的定点数,Z1,Z2,Z3是它们对应的零点
  • 浮点乘法运算:$$R3 = R1 \times R2$$
  • 定点乘法运算:$$Q3 = Q1 \times Q2 \times M + Z3$$
  • 其中M是一个系数,用来调整定点乘法的结果和浮点乘法的结果之间的差异
  • M可以表示为:$$M = \frac{S1 \times S2}{S3} = 2^{-n} \times M_0$$
  • 其中n是一个非负整数,M0是一个介于0.5和1之间的小数
  • 这样表示M的好处是可以通过位移操作来实现除以或乘以2的n次方

量化后的定点加法运算

  • 假设R1和R2是两个浮点数,R3是它们的和
  • 假设S1,S2,S3是它们对应的变换系数,Q1,Q2,Q3是它们对应的定点数,Z1,Z2,Z3是它们对应的零点
  • 浮点加法运算:$$R3 = R1 + R2$$
  • 定点加法运算:$$Q3 = Q1 + Q2 + Z3 - Z1 - Z2$$
  • 注意:如果R1和R2有不同的变换系数或零点,需要先对齐它们再进行加法运算

量化后的定点卷积运算

  • 假设R1是输入数据,R2是卷积权重,B是偏置项,R3是卷积输出
  • 假设S1,S2,S3,Bs是它们对应的变换系数,Q1,Q2,Q3,Bq是它们对应的定点数,Z1,Z2,Z3,Bz是它们对应的零点
  • 浮点卷积运算:$$R3 = R1 \times R2 + B$$
  • 定点卷积运算:$$Q3 = Q1 \times Q2 \times M + Bq + Z3 - Z1 \times Q2 - Z2 \times Q1$$
  • 其中M是一个系数,用来调整定点乘法的结果和浮点乘法的结果之间的差异
  • M可以表示为:$$M = \frac{S1 \times S2}{S3} = 2^{-n} \times M_0$$
  • 其中n是一个非负整数,M0是一个介于0.5和1之间的小数
  • Bq是偏置项的定点数,可以表示为:$$Bq = \frac{B}{S1 \times S2}$$
  • Bs是偏置项的变换系数,可以表示为:$$Bs = S1 \times S2$$
  • Bz是偏置项的零点,可以设为0

量化后的定点激活运算

  • 假设R是卷积输出,A是激活输出
  • 假设S是卷积输出的变换系数,Q是卷积输出的定点数,Z是卷积输出的零点
  • 假设Sa是激活输出的变换系数,Qa是激活输出的定点数,Za是激活输出的零点
  • 浮点激活运算:$$A = f(R)$$
  • 其中f是一个激活函数,如ReLU或Sigmoid
  • 定点激活运算:$$Qa = f(Q) + Za - Z$$
  • 其中f是一个查找表函数,根据不同的激活函数和量化范围进行预计算和存储