IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> CNN for CIFAR10 in C++(神经网络底层原理&算法,源代码介绍) -> 正文阅读

[人工智能]CNN for CIFAR10 in C++(神经网络底层原理&算法,源代码介绍)

Download Source Code

CNN for CIFAR10 in C++

在这里插入图片描述

Forward Pass

  1. Hidden Layer得到上一层的输出a’作为本层的输入,或Input Layer得到整个网络的输入。
  2. 当前层得到输入后首先经过线性计算(如Convolution Layer的卷积运算或Fully Connected Layer),得到Z。
  3. 线性运算的结果Z经过Activation Function(激活函数如Sigmoid、ReLU、tanh等),得到a。
  4. 激活函数的结果a最终作为本层输出并作为下一层的输入。

Backward Pass

总目标:求得Loss函数对本层Unknown Parameter的梯度(所有未知参数偏导数组成的向量), ? L ? W \frac{\partial L}{\partial W} ?W?L? ? L ? b \frac{\partial L}{\partial b} ?b?L?,然后对参数更新。如上图所示,W和b在线性运算中。我们首先想到,可以像做高数题那样,先通过网络计算出一个以W和b为未知数的Loss函数,然后分别对每一个Unknown Parameter求偏导,但这不是计算思维,带有大量未知参数的表达式计算机无法存储也难以计算偏导,于是出现了Backpropagation,它包括Forward Pass(先)和Backward Pass(后),那我们下面来看为求 ? L ? W \frac{\partial L}{\partial W} ?W?L? ? L ? b \frac{\partial L}{\partial b} ?b?L?,Backward Pass都做了哪些工作。

  1. 对于任意一层,我们首先假设, ? L ? a \frac{\partial L}{\partial a} ?a?L?是已知的。为什么可以作这样的假设?如果我们是在Output Layer,a就是整个网络的输出y,而y和Label可以得到Loss函数的表达式,用该表达式对y求偏导,再代入Forward Pass中求得的y和已知的label,就可以求得最后一层Loss对a的偏导,Backward Pass也正是从这里开始的。我们会逐步得到任意一层的 ? L ? a \frac{\partial L}{\partial a} ?a?L? ? L ? a \frac{\partial L}{\partial a} ?a?L?也叫作Backward Error。

  2. 有了 ? L ? a \frac{\partial L}{\partial a} ?a?L?,我们再求当前层的 ? L ? Z \frac{\partial L}{\partial Z} ?Z?L?,根据链式法则,显然我们需要 ? a ? Z \frac{\partial a}{\partial Z} ?Z?a?,这实际上就是Activation Function的导数,值得注意的是,求 ? a ? Z \frac{\partial a}{\partial Z} ?Z?a?需要Forward Pass中求得的当前层的Z的值。 ? L ? Z \frac{\partial L}{\partial Z} ?Z?L?也叫做Layer Error或Delta。

    [ ? L ? Z \frac{\partial L}{\partial Z} ?Z?L?= ? L ? a \frac{\partial L}{\partial a} ?a?L? * ? a ? Z \frac{\partial a}{\partial Z} ?Z?a?]

  3. 有了 ? L ? Z \frac{\partial L}{\partial Z} ?Z?L?,离我们的目标 ? L ? W \frac{\partial L}{\partial W} ?W?L? ? L ? b \frac{\partial L}{\partial b} ?b?L?更近了,显然我们需要 ? Z ? W \frac{\partial Z}{\partial W} ?W?Z? ? Z ? b \frac{\partial Z}{\partial b} ?b?Z?。我们先忽略 ? Z ? b \frac{\partial Z}{\partial b} ?b?Z?的计算,关注 ? Z ? W \frac{\partial Z}{\partial W} ?W?Z?。在全连接层中,Z = W * a;在卷积层中,因为Receptive Field和Parameter Sharing,W的某些部分与a的某些部分相乘得到Z,总之,W和a通过简单的乘加运算得到Z,因此 ? Z ? W \frac{\partial Z}{\partial W} ?W?Z?的结果就来自a。有了 ? Z ? W \frac{\partial Z}{\partial W} ?W?Z?,我们就可以更新W,W‘ = W - Learning Rate * ? L ? W \frac{\partial L}{\partial W} ?W?L? ? L ? W \frac{\partial L}{\partial W} ?W?L? ? L ? b \frac{\partial L}{\partial b} ?b?L?也叫dW、db。

    [ ? L ? W \frac{\partial L}{\partial W} ?W?L?= ? L ? Z \frac{\partial L}{\partial Z} ?Z?L? * ? Z ? W \frac{\partial Z}{\partial W} ?W?Z?]

  4. 既然得到了本层的 ? Z ? W \frac{\partial Z}{\partial W} ?W?Z?,那Backward Pass是否可以结束了?显然不可以,如果结束了,那该层的上一层怎么办呢?于是我们希望再次得到 ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?,上一层再继续重复1,2,3步骤,因为2中我们得到了 ? L ? Z \frac{\partial L}{\partial Z} ?Z?L?,显然我们需要 ? Z ? a ′ \frac{\partial Z}{\partial a'} ?a?Z?,与3类似, ? Z ? a ′ \frac{\partial Z}{\partial a'} ?a?Z?就来自于W, ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?也叫作Backward Error,至此我们可以对上一层继续Backward Pass。

    [ ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?= ? L ? Z \frac{\partial L}{\partial Z} ?Z?L? * ? Z ? a ′ \frac{\partial Z}{\partial a'} ?a?Z?]

值得注意的是:

  • Backward Pass过程中,需要Forward Pass中计算的Z和a,使用Z计算 ? a ? Z \frac{\partial a}{\partial Z} ?Z?a?进而[ ? L ? Z \frac{\partial L}{\partial Z} ?Z?L?= ? L ? a \frac{\partial L}{\partial a} ?a?L? * ? a ? Z \frac{\partial a}{\partial Z} ?Z?a?]得到Layer Error(Delta),使用上一层的a计算 ? Z ? a ′ \frac{\partial Z}{\partial a'} ?a?Z?进而[ ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?= ? L ? Z \frac{\partial L}{\partial Z} ?Z?L? * ? Z ? a ′ \frac{\partial Z}{\partial a'} ?a?Z?]得到Backward Error。因此Z和a需要在Forward Pass中保存下来。
  • 首先有本层的Backward Error,然后结合本层的Z和Activation Funtion获得本层的Layer Error,使用上一层的a和本层的Layer Error进行update,使用本层的Unknown Parameter和本层的Layer Error获得上一层的Backward Error(Maxpooling特殊)。
  • 无论是怎样的Layer,在当前层的Backward Error已知的情况下,求得Layer Error的过程都是根据激活函数,都是类似的[ ? L ? Z \frac{\partial L}{\partial Z} ?Z?L?= ? L ? a \frac{\partial L}{\partial a} ?a?L? * ? a ? Z \frac{\partial a}{\partial Z} ?Z?a?]。
  • 但不同的Layer得到 ? L ? W \frac{\partial L}{\partial W} ?W?L? ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?是有区别的,原因是 ? Z ? W \frac{\partial Z}{\partial W} ?W?Z? ? Z ? a ′ \frac{\partial Z}{\partial a'} ?a?Z?得到的方式不同,下面开始逐个介绍。

Convolution Layer Backward Pass

在卷积层中,上一层的输入Input a’是一个矩阵X(我们以单通道即1 channel为例),待更新的参数W叫做卷积核(Kernel或Filter,假设只有一个卷积核,卷积核的厚度应当等于输入通道数 = 1),输出是一个单通道矩阵O,我们通过上述的1,2操作,可以得到 ? L ? Z \frac{\partial L}{\partial Z} ?Z?L?,也就是 ? L ? O \frac{\partial L}{\partial O} ?O?L?。有下面公式:
? L ? F = C o n v o l u t i o n ( I n p u t ? X , ? L a y e r ? E r r o r ? ? L ? O ) \frac{\partial L}{\partial F} = Convolution(Input\ X,\ Layer\ Error\ \frac{\partial L}{\partial O}) ?F?L?=Convolution(Input?X,?Layer?Error??O?L?)

? L ? X = F u l l ? C o n v o l u t i o n ( 180 ° ? r o t a t e d ? F , ? L a y e r ? E r r o r ? ? L ? O ) \frac{\partial L}{\partial X} = Full\ Convolution(180°\ rotated\ F,\ Layer\ Error\ \frac{\partial L}{\partial O}) ?X?L?=Full?Convolution(180°?rotated?F,?Layer?Error??O?L?)

具体可见:How does Backpropagation work in a CNN?

在我的代码中并没有在卷积层的反向传播过程中使用卷积操作,因为没能准确地把握多通道,多核的情况,网上的例子大都是单通道和单核的,后续捋清楚了再更新代码。

这份代码中用的多层循环,因为都是加乘操作,O对X的偏导都来自Filter,O对Filter的偏导都来自X,通过循环找到待求导变量的系数累加,效率较低。

Pooling Layer Backward Pass

  1. 池化层没有Activation Funtion,因此Z = a, ? L ? Z \frac{\partial L}{\partial Z} ?Z?L? = ? L ? a \frac{\partial L}{\partial a} ?a?L?,即Backward Error = Layer Error。
  2. 池化层没有Unknown Parameters,因此不需要求 ? L ? W \frac{\partial L}{\partial W} ?W?L?
  3. 但池化层必须完成 ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?,求出上一层的Backward Error进行反向传播。
  4. 对于最大池化,得到 ? L ? Z \frac{\partial L}{\partial Z} ?Z?L? ? L ? a \frac{\partial L}{\partial a} ?a?L?后,求 ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?,a’的尺寸大于a,因此 ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?的尺寸要大于 ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L? ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?中,在a’被采样的位置的导数值与 ? L ? a \frac{\partial L}{\partial a} ?a?L?相等,其余位置为0。
  5. 对于平均池化,将 ? L ? a \frac{\partial L}{\partial a} ?a?L?的值平均到池化窗口中再填回到 ? L ? a ′ \frac{\partial L}{\partial a'} ?a?L?中即可。

具体可见:序号3

Fully Connected Layer Backward Pass

在这里插入图片描述

About Padding in Backward Pass

  1. Padding出现在Convolution Layer,当然Pooling Layer也可以Padding,但我的代码中没有考虑。
  2. 如果Forward Pass时有Padding,在求上一层的Backward Error的时候,求得的矩阵中是包含对Padding的Zero求导的,要先把这些Zero的偏导数求出来然后再去掉送给上一层。
  3. 如果Forward Pass时有Padding,在求dW(即对Filter求偏导)时,要把a’(即X)先Padding再与本层的Layer Error作相关操作。

the Neural Network Structure for CIFAR10在这里插入图片描述在这里插入图片描述

代码中在Convolution Layer和Fully Connected Layer后都加了一个Activation Funtion,卷积层加了ReLU,全连接层加了Sigmoid。

Process CIFAR10 Dataset For C++

CIFAR10的数据集文件是二进制文件,C++直接读取比较麻烦,我先用Pytoch的DataLoader将图片转化为Tensor直接存到文本文件中,C++只需要从文本文件中读RGB对应的数值即可。相关程序在CIFAR10_for_C++.py中。

Code structure

在这里插入图片描述

  1. Array2d用于全连接层,具有行、列属性,用一个vector存储全部值,将二维索引映射到一维;其中实现了向量的一些基本操作,如行点积,列点积。
  2. Array3d用于卷积层和池化层,具有宽、高、通道属性,用一个vector存储全部值,将三维索引映射到一维;其中实现了一些矩阵基本操作,加减乘除等。
  3. 三种层,Convolution Layer、Fully Connected Layer、Maxpooling Layer,每一层Compute函数和activate函数进行Forward Pass,通过gradient_L_to_Z函数来获取Layer Error,通过Backward函数计算上一层的Backward Error,通过Update函数更新Unknown Parameter(除了Maxpooling)。
  4. ReLU和Sigmoid不单独作为层,分别内置在Convolution Layer和Fully Connected Layer中。
  5. MSE和Cross Entropy是两个Loss Funtion,其中的start_backward函数计算Output Layer的Backward Error,由此开始反向传播过程。
  6. CNN负责将main声明的网络模型中的层衔接起来。train函数负责在训练集上训练,包括了正向和反向传播;Predict函数和test_accuracy函数共同在测试集上计算正确率,仅有正向传播过程。
  7. db_handler处理数据集,读取CIFAR10_for_C++.py处理后的文件。
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-11-28 11:16:07  更:2021-11-28 11:16:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 3:42:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码