zoukankan      html  css  js  c++  java
  • 深度学习入门|第5章 误差反向传播法(二)

     误差反向传播法

    前言

    此为本人学习《深度学习入门》的学习笔记

    四、简单层的实现

    本节将用 Python 实现前面的购买苹果的例子。这里,我们把要实现的计算图的乘法节点称为“乘法层”(MulLayer),加法节点称为“加法层”(AddLayer)。

    1、乘法层的实现

    层的实现中有两个共通的方法(接口)forward() 和backward()forward() 对应正向传播,backward() 对应反向传播。

    实现乘法层。乘法层作为 MulLayer 类,其实现过程如下所示

    class MulLayer:
        def __init__(self):
            self.x = None
            self.y = None
    
        def forward(self, x, y):
            self.x = x
            self.y = y
            out = x * y
    
            return out
    
        def backward(self, dout):
            dx = dout * self.y # 翻转x和y
            dy = dout * self.x
    
            return dx, dy

    __init__() 中会初始化实例变量 x 和 y,它们用于保存正向传播时的输入值。forward() 接收 x 和 y 两个参数,将它们相乘后输出。backward() 将从上游传来的导数(dout)乘以正向传播的翻转值,然后传给下游。

    使用 MulLayer 实现前面的购买苹果的例子(2 个苹果和消费税)。

            

                        图 5-16 购买 2 个苹果

    使用这个乘法层的话,图 5-16 的正向传播可以像下面这样实现

     此外,关于各个变量的导数可由 backward() 求出。

    调用 backward() 的顺序与调用 forward() 的顺序相反。此外,要注意 backward() 的参数中需要输入“关于正向传播时的输出变量的导数”。比如,mul_apple_layer 乘法层在正向传播时会输出 apple_price,在反向传播时,则会将 apple_price 的导数 dapple_price 设为参数。

    2、加法层的实现

    class AddLayer:
        def __init__(self):
            pass
    
        def forward(self, x, y):
            out = x + y
            return out
    
        def backward(self, dout):
            dx = dout * 1
            dy = dout * 1
            return dx, dy

    加法层不需要特意进行初始化,所以 __init__() 中什么也不运行(pass 语句表示“什么也不运行”)。加法层的 forward() 接收 x 和 y 两个参数,将它们相加后输出。backward() 将上游传来的导数(dout)原封不动地传递给下游。

    使用加法层和乘法层,实现图 5-17 所示的购买 2 个苹果和 3 个橘子的例子。

          

                  图 5-17 购买 2 个苹果和 3 个橘子

    用 Python 实现图 5-17 的计算图的过程如下所示

    首先,生成必要的层,以合适的顺序调用正向传播的 forward() 方法。然后,用与正向传播相反的顺序调用反向传播的 backward() 方法,就可以求出想要的导数。

    五、激活函数层的实现

    将计算图的思路应用到神经网络中。把构成神经网络的层实现为一个类。先来实现激活函数的 ReLU 层和 Sigmoid 层。

    1、ReLU层

    激活函数 ReLU(Rectified Linear Unit)由下式(5.7)表示。

    通过式(5.7),可以求出 y 关于 x 的导数,如式(5.8)所示。

    在式(5.8)中,如果正向传播时的输入 x 大于 0,则反向传播会将上游的值原封不动地传给下游。反过来,如果正向传播时的 x 小于等于 0,则反向传播中传给下游的信号将停在此处。用计算图表示的话,如图 5-18 所示。

    实现 ReLU 层。在神经网络的层的实现中,一般假定 forward() 和backward() 的参数是 NumPy 数组。

      图 5-18 ReLU 层的计算图

    class Relu:
        def __init__(self):
            self.mask = None
    
        def forward(self, x):
            self.mask = (x <= 0)
            out = x.copy()
            out[self.mask] = 0
    
            return out
    
        def backward(self, dout):
            dout[self.mask] = 0
            dx = dout
    
            return dx

    Relu 类有实例变量 mask。这个变量 mask 是由 True/False 构成的 NumPy 数组,它会把正向传播时的输入 x 的元素中小于等于 0 的地方保存为 True,其他地方(大于 0 的元素)保存为 False

     2、Sigmoid层

    实现sigmoid函数,sigmoid函数由式(5.9)表示

    用计算图表示式子(5.9)的话,则如图5-19所示

    图 5-19 sigmoid 层的计算图(仅正向传播)

    图 5-19 中,除了“×”和“+”节点外,还出现了新的“exp”和“/”节点。“exp”节点会进行 y = exp(x) 的计算,“/”节点会进行 y=frac{1}{x} 的计算。

    如图 5-19 所示,式(5.9)的计算由局部计算的传播构成。

    下面我们就来进行图 5-19 的计算图的反向传播。这里,作为总结,我们来依次看一下反向传播的流程。

    步骤 1

    “/”节点表示 y=frac{1}{x},它的导数可以解析性地表示为下式。

    enter image description here

    根据式(5.10),反向传播时,会将上游的值乘以 -y^2(正向传播的输出的平方乘以 -1 后的值)后,再传给下游。计算图如下所示。

    {95%}

    步骤 2

    “+”节点将上游的值原封不动地传给下游。计算图如下所示。

    {95%}

    步骤 3

    “exp”节点表示 y = exp(x),它的导数由下式表示。

    frac{partial y}{partial x}=exp(x)quadquadquadquadquad(5.11)

    计算图中,上游的值乘以正向传播时的输出(这个例子中是 exp(-x))后,再传给下游。

    {95%}

    步骤 4

    “×”节点将正向传播时的值翻转后做乘法运算。因此,这里要乘以 -1。

    {95%}

    图 5-20 Sigmoid 层的计算图

  • 相关阅读:
    从屏幕截取一块区域,将其赋给imageView
    oc 中随机数的用法(arc4random() 、random()、CCRANDOM_0_1()
    UIPopoverController
    IOS-- UIView中的坐标转换
    TCP、UDP的区别
    TCP/IP协议简单介绍
    NSTimer类的使用
    UI基础-网络编程
    IOS面试中的一些问题
    iOS开发UI篇—UITabBarController简单介绍
  • 原文地址:https://www.cnblogs.com/zyqy/p/10816953.html
Copyright © 2011-2022 走看看