深度学习-04-数值的微分


深度学习-04-数值的微分

本文是《深度学习入门2-自製框架》 的学习笔记,记录自己学习心得,以及对重点知识的理解。如果内容对你有帮助,请支持正版,去购买正版书籍,支持正版书籍不仅是尊重作者的辛勤劳动,也是鼓励更多优秀作品问世。

当前笔记内容主要为:步骤4 数值的微分 章节的相关理解。

书籍总共分为5个阶段,每个阶段分很多步骤,最终是一步一步实现一个深度学习框架。例如前两个阶段为:

第 1 阶段共包括 10 个步骤 。 在这个阶段,将创建自动微分的机制
第 2 阶段,从步骤11-24,该阶段的主要目标是扩展当前的 DeZero ,使它能够执行更复杂的计算 ,使它能 够处理接收多个输入的函数和返回多个输出的函数


1.什么是导数


经过上面几节的学习及开发,我们已经有了变量 Variable,函数Function,复合函数的定义,接下来我们学习导数及微分。
先复习高数以及高中的导数,然后实现一种数值微分的方法来求导,最后我们实现一种替代数值微分的更高效算法-反向传播算法。

什么是导数
导数是微积分中的一个基本概念,它描述了函数在某一点的变化率。更准确地说,导数是函数在该点附近的变化量与自变量变化量之比的极限。

导函数定义

导函数是函数的导数在自变量取值范围内所形成的函数。换句话说,导函数就是将导数的概念推广到整个定义域,形成一个新的函数。
更精确定义:设函数 
𝑓(𝑥)在定义域D内可导,则其导函数 𝑓′(𝑥)是一个定义在 𝐷上的函数,其对应于 𝑥的函数值为 𝑓(𝑥)在 𝑥 处的导数。    
    

2.数值微分的实现


由于计算机不能处理极限值,所以我们在计算极限时都是采用的逼近的方法,例如设定 h = 0.0001(1e-4) 这种非常小的数值来计算导数,可想而知这种方法是一种近似的方法。这种方法包括误差。解决方法之一就是使用中心差分近似。中心差分近似不是使用f(x)与 f(x+h) 而是使用f(x-h) 与f(x+h) 的差。
 

前向差分近似:x,x+h 两点的斜率,f(x) ,f(x+h)
中心差分近似: x-h,x+h 两点的斜率,f(x-h), f(x+h)


相关定理已经证明结论有(使用泰勒展开式进行证明),中心差分近似相比前向差分近似实际产生的误差更小。

代码实现如下:

import numpy as np
from step01 import *
from step02_1 import *

def numerical_diff(f,x,eps=1e-4):
    x0 = Variable(x.data -eps)
    x1 = Variable(x.data +eps)
    y0= f(x0)
    y1 = f(x1)
    return (y1.data -y0.data)/(2*eps)

验证y=x^2 在x =0, x=2 处的斜率


if __name__ == '__main__':
    A = Square()
    x = Variable(np.array(0))  # y = x^2 在x = 0 的斜率= 0.0
    diff = numerical_diff(A, x)
    print(diff)

    x = Variable(np.array(2))  # y = x^2 在x = 0 的斜率= 4.0
    diff = numerical_diff(A, x)
    print(diff)

输出结果

C:\Python\Python39-32\python.exe D:/pyworkspace/dezero-01/step04.py
0.0
4.000000000004

3.复合函数的导数

我们考虑复合函数求导,我们看下函数y= (exp(x^2))^2的导数怎么计算dy/dx ,代码

def f(x):
    A = Square()
    B = Exp()
    C = Square()

    return C(B(A(x)))
    
# 使用 
# 复合函数求导
x = Variable(np.array(0.5))
dy = numerical_diff(f, x)
print(dy)

执行结果:

3.2974426293330694


上面的代码,由于在python的特点,函数Function 也是对象,所以可以传递给其函数。上述结果说明,在x=0.5 处,x变化一点点,就会导致 y 变化3.297倍,这就是斜率,变化率。

现在我们已经成功实现了"自动"求导 。 只要用代码来定义要完成的计 算(例子函数 f) ,程序就会自动求山导数。使用此方法,要函数可微,无论复杂的函数都可以计算出来。但是数值微分计算存在一定的问题。


4.数值微分存在的问题

首先,数值微分结果存在误差(主要为精度丢失)。多数case 下,误差很小,有些case 误差很大。中心差分近似计算方法计算的是同数量级直之间的差,但是由于精度丢失,会出现计算结果出现位数减少的情况。


举例:
    1.234 - 1.233 = 0.001 有效位数为1位
本来可能是 1.234 - 1.233... = 0.001434... 之类的结果。误差也会发生在数值微分差值计算中。

其次,数值微分一个严重的问题是,计算成本高。在求多个变量是,程序需要计算每个变量的导数。有些神经网络包括几百万个参数以上变量,通过数值微分计算不现实。
解决上面问题,我们需要 反向传播。

数值微分可以轻松实现,并能计算出大体正确的数值。 而反向传播是一 种复杂的算法,实现时容易出现 bug。

可以使用数值微分法计算处的结果检验反向传播的实现是否正确。这种方法叫做 梯度检验(gradient checking)

下一节,我们介绍反向传播算法相关理论及实现。


5.项目代码
'''
step03.py
函数的连续调用

'''

import numpy as np
from step01 import *
from step02_1 import *
from step03 import *


def numerical_diff(f,x,eps=1e-4):
    x0 = Variable(x.data -eps)
    x1 = Variable(x.data +eps)
    y0= f(x0)
    y1 = f(x1)
    return (y1.data -y0.data)/(2*eps)

def f(x):
    A = Square()
    B = Exp()
    C = Square()

    return C(B(A(x)))


if __name__ == '__main__':
    A = Square()
    x = Variable(np.array(0))  # y = x^2 在x = 0 的斜率= 0.0
    diff = numerical_diff(A, x)
    print(diff)

    x = Variable(np.array(2))  # y = x^2 在x = 0 的斜率= 0.0
    diff = numerical_diff(A, x)
    print(diff)

    # 复合函数求导
    x = Variable(np.array(0.5))
    dy = numerical_diff(f, x)
    print(dy)

输出结果:

C:\Python39-32\python.exe D:/pyworkspace/dezero-01/step04.py
0.0
4.000000000004
3.2974426293330694

我们可以看到 y=x^2 平方函数在x=0 处的导数是0,通过高中数学知识,我们知道此结果是正确的。

6.总结

本节介绍数值微分概念及计算,以及分析了数值微分的缺点。

  • 37
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值