zoukankan      html  css  js  c++  java
  • 神经网络——一些简单的技术细节

    一. 前言

    最近开始搞自动驾驶感知部分,将之前的总结的资料和笔记调出来看看,顺便总结一下,留下记录。

    二. 神经网络介绍

    这里我们采用优达学城[1]上提供的例子,如下图所示。

                                                  图 1-1                                                      图 1-2                                                              图 1-3

    上图是根据grades和test的成绩来判断是否被大学录取,绿色的圆表示录取,红色的圆表示拒绝录取。

    从上图1-1可以看出,如果采用线性的方法区分红色和绿色,采用一条直线直线的效果不好(图1-2),所以需要用两条直线区分(图1-3)。

    例如,如果一个学成的test的成绩为1,grade的成绩为8,那么根据图1-3,该学生拒绝录取,即,该学生的成绩在蓝色线的上方,但却在黄色线的左侧,所以拒绝录取,可以如图2表示

                                                            图 2

    这里我们总结一下所有录取和拒绝录取的情况,根据图1-3可以分为四种情况,如下表

                                 表1

    test在黄线右侧 grade在蓝线上方 结果
    录取
    拒绝
    拒绝
    拒绝

    通过表1可以看出,图2是“AND”(“与”)的关系。图2就是一个简单神经网络。

    根据不同的场景,最后的关系可以是“OR”,“XOR”,甚至可以自定义逻辑关系等等。

    那么我们怎样判断test在黄线的右侧,grade在蓝线的上方呢?实际上就是我们接下来要聊的神经元(感知机)

    三. 感知机

    图2中, 中间的两个方框中的节点实际上就是感知机(神经元),他们构成了神经网络的基本单元,每个感知机按照输入决定数据的分类。

    那么,感知机是如何决定test在黄线的右侧,grade在蓝线的上方呢?事实上初始神经网络吧并不知道输入的test,或者grade在什么位置,即并不清楚图1-3的蓝线与黄线的位置,需要我们根据数据做出调整,这个过程就是“训练”。

    训练神经网络的过程,实际上就是在确定蓝线与黄线的位置。

    直线的方程在二维坐标系下可以写成:0 = w1 × x1 + w2 × x2 + b, 如果给出的x1与x2在直线的上方/右侧(上方与右侧等价),那么w1 × x1 + w2 × x2 + b > 0,否则<0。这里w1, w2, b就是神经网络中常用的权重,x1与x2分别代表图2中的test与grade数据。通过不停的带入test与grade数据,调整w1, w2, b训练整个神经网络。

    图2的两个感知机都包含了0 = w1 × x1 + w2 × x2 + b的一个线性方程。

    图2是针对二维坐标系的例子,如果是n维数据,那么可以写成和函数(summing function)

    最后感知机要把和函数转换成输出信号,这里即1与0(“真”与“假”)。通常通过激活函数(activation function)实现。常用到的激活函数

    我们常用的激活函数有:

    (1)单位阶跃函数:和函数小于 0,函数返回 0,如果和函数等于或者大于 0,函数返回 1。

    (2)sigmoid函数[2]

    (3)tanh函数

    (4)softmax函数[3]

    我们常采用sigmoid函数作为激活函数。

    这样我们就得到了我们简单的感知机模型,如下图所示:

    这里我们解决了神经网络每个节点的构成,接下来我们着重介绍,神经网络的训练方法,也就是权重的学习。

    四. 权重调整

    因为神经网络的初始随机权重不能满足我们的需求,所以我们需要通过正确的数据不断调整我们网络中的权重,这个过程就是训练

    目前训练采用的主流方法就是梯度下降,权重调整的目的是使目标函数的输出,趋近于真值。

    4.1 目标函数

    训练的目的就是通过带入真实数据调整权重,使输出趋近于真值。所以为了能够衡量,我们需要有一个指标来了解预测与实际的差别,也就是误差(真值与计算结果的差异)。一个普遍的指标是误差平方和 sum of the squared errors (SSE)

    举例一个单个感知机来解释(以下的推导过程都是基于单个感知机):

                                                  图3

    ŷ表示感知机输出,y表示真值。

    首先,我们想知道我们初始的感知机的输出与真值之间的误差,希望误差全部为正,便于累加,误差可以表示为

     ※※不采用绝对值的原因是,对于较大的误差可以通过平方放大其误差,从而带来放大惩罚值,同时采用平方的形式有利于我们后面的数学运算(求导)。

    上面的E仅仅代表了单个数据的误差,如果我们想要得到整体数据的误差,可以所有误差进行累计,即

    每一行的x和y的对应元素代表μ(x,y的上角标)。我们得到了整体数据的误差E,即误差平方和  (SSE)。ŷ是由激活函数得到,1/2方便计算导数,μ用于表示整体数据。比如

    这样针对权重wi 的优化目标函数E已经得到。从上式可以看出,E取决于权重wi 与输入 xiμ。如果E的值比较大,那么预测的结果比较差,如果E较小,那么预测的结果会比较好。所以我们希望E越小越好。

    这时我们要优化的所有函数可以表示为

    其中

    4.2 梯度下降[4]

    针对4.1节中提到的优化函数方法有很多,我们这里着重讲解梯度下降。实际上不需要了解梯度下降的数学细节,知道结果就好,因为好多工具帮大家实现了梯度下降,而且包含了很多方法[4]

    由于初始的E比较大,我们希望E变得越来越小,而且变小的速度还要够快,所以我们利用导数,来计算梯度下降对快的方向,下降的方向与导数相反。我们只需每次累加梯度下降的方向。如图4所示

                                            图4

    梯度下降的方法有很多,这里选用随机梯度下降SGD[4]。由于随机梯度下降的核心:用样本中的一个例子来近似我所有的样本,调整权重,所以导数只需求解单个样本即可,不需要包含∑符号。针对4.1的目标函数,采用链式求导法则有

    α为学习速率(learning rate),包含了方向(正负号),用来控制下降的速度。链式求导在下面要说到的反向传递也要用到,正因为有链式求导,神经网络的层数才可以增加,深度学习才可以方便调整参数。由于我们采用sigmoid函数作为激活函数f(h),sigmoid函数的导数为:f'(h) = f(h)(1 - f(h)) = ŷ(1 - ŷ)。

    为了表达简单,迭代过程化简为:

    δ实际上表示误差项,即用于衡量输出的误差。

    随机梯度下降SGD的过程pipeline表示为:

    • 权重步长设定为 0:Δw= 0
    • 对训练数据中的每一个样本:
      • 通过网络做正向传播,计算输出:ŷf(h)
      • 计算输出单元的误差项:δ
      • 更新权重步长:Δwi = Δwδxi更新输入对应权重
    • 更新权重:wi+1 = wαδxi
    • 重复上面迭代,直至迭代步数结束。

    上面的阐述仅仅围绕着神经网络中一个节点进行,单层多节点的神经网络类似,但是多层神经网络(深度学习)要复杂一些,涉及到神经网络核心——反向传播。

     4.3 反向传播

    我们已了解了使用梯度下降来更新单个节点权重,反向传播算法则是它的一个延伸。用以更新多层神经网络的参数,反向传播同样基于链式求导法则,。

    网络上有个一很不错的例子,我用这个例子[5]讲解一下反向传播。

     

    这个神经网络有两个输出,一层隐含层(两个节点),两个输入。

    第一层是输入层,包含两个神经元i1,i2,和截距项b1;第二层是隐含层,包含两个神经元h1,h2和截距项b2,第三层是输出o1,o2,每条线上标的wi是层与层之间连接的权重,激活函数同样使用sigmoid函数。

    初始值为:

    输入数据: i1=0.05, i2=0.10;

    输出数据: o1=0.01, o2=0.99;

    初始权重: w1=0.15, w2=0.20, w3=0.25, w4=0.30; w5=0.40, w6=0.45, w7=0.50, w8=0.55;

    目标:给出输入数据i1, i2(0.05和0.10),使输出尽可能与原始输出o1, o2(0.01和0.99)接近

    这里先列出了前向传播及目标函数的所有公式

    (上述公式建议从下往上看)其中,Etotal为总的误差,Eo1Eo2分别为两个输出的误差SSE,yo1yo2分别为两个目标输出,ŷo1ŷo2分别为神经网络输出,ŷh1ŷh2分别为两个隐藏层输出,w1~w8分别为要调整的权重,x1x2分别为两个输入。

    我们的目标通过通过输入调整参数w1~w8使得输出接近目标输出。根据我们在4.2节中发现核心实际上是得到每次迭代后的Δwi 

    那么根据4.2节的内容,从隐藏层到输出的参数Δw5w8,采用链式求导可以计算为

    δo实际上表示输出层误差项。

    到输出的权重更新完成后,接下来更新隐藏层权重,

    隐含层的权重更新,需要知道各隐藏层节点的误差对最终输出的影响。每层的输出是由两层间的权重决定的,两层之间产生的误差,按权重缩放后在网络中向前传播。既然我们知道输出误差,便可以用权重来反向传播到隐藏层的权重Δw1w4

     

    δoh实际上表示输出层误差项。

    讲反向传播采用类似随机梯度下降的方式,则反向传播的pipeline可以写成:

    • 随机设置初始权重
    • 对训练数据当中的每一个样本,
      • 让它正向传播通过网络,计算输出:ŷ 
      • 计算输出节点的误差项:δ
      • 误差传播到隐藏层的误差项:δoh
      • 更新权重步长:
        • 输出层节点权重更新:Δwo = Δwδŷ
        • 隐藏层节点权重更新:Δwh = Δwδŷh ;
        • 第一层节点权重更新:Δwi = Δwδxi ;
    • 更新权重:
      • wi+1 = wαΔw
    • 重复这个过程,直至迭代步数结束 

      

    ※※从这里可以看出,误差项是从输出层权重更新,逐层传播到隐藏层权重更新。

    ※※从公式同样可以看出,如果函数中的每个值都经过前向传播计算得到,实际上反向传播每个值的计算是相互独立的,这就为并行计算(GPU)提供了条件,这也就是深度学习为什么可以采用GPU计算的原因。

    ※※我们采用的误差项计算是通过sigmoid求导得到的,f'(h) = f(h)(1 - f(h)),从导数的公式可以看出,sigmoid的导数最大值为0.25,在求导过程中,数值会越来越小,对产生梯度消失。所以在深度学习采用如reLu等激活函数。

    参考资料

    [1] https://cn.udacity.com/

    [2] https://www.cnblogs.com/hgl0417/p/5902042.html

    [3] https://www.cnblogs.com/hgl0417/p/6670913.html

    [4] https://www.cnblogs.com/hgl0417/p/5893930.html

    [5] https://blog.csdn.net/weixin_38347387/article/details/82936585

  • 相关阅读:
    剑指offer4:重建二叉树(后序遍历)
    剑指offer3:从尾到头打印链表每个节点的值
    剑指offer2:C++实现的替换空格(字符中的空格替换为“%20”)
    tp5系统变量输出(可以用来传递搜索的参数)
    Ajax实现文件上传的临时垃圾文件回收策略
    php获取当天的开始时间和结束时间
    Think PHP递归获取所有的子分类的ID (删除当前及子分类)
    tp查找某字段,排除某字段,不用一次写那么多
    git-查看历史版本及回滚版本
    dedecms目录结构,非常全
  • 原文地址:https://www.cnblogs.com/hgl0417/p/11621941.html
Copyright © 2011-2022 走看看