计算图与自动微分

一、自动梯度计算

自动计算梯度的方法可以分为以下三类:数值微分、符号微分和自动微分。

1.1 数值微分(Numerical Differentiation)

数值微分使用数值的方法来计算函数 f ( x ) f(x) f(x)的导数,函数 f ( x ) f(x) f(x)的导数定义为:
f ′ ( x ) = lim ⁡ Δ x → 0 f ( x + Δ x ) − f ( x ) Δ x f^\prime(x)=\lim_{\Delta x \rightarrow 0} \frac{f(x+\Delta x) - f(x)}{\Delta x} f(x)=Δx0limΔxf(x+Δx)f(x)
要计算函数 𝑓(𝑥) 在点 𝑥 的导数,可以对 𝑥 加上一个很少的非零的扰动 Δ𝑥,通过上述定义来直接计算函数𝑓(𝑥)的梯度。如在编程中令 Δ x = 0.0001 \Delta x=0.0001 Δx=0.0001

数值微分方法非常容易实现,但

  • 很难找到一个合适的扰动Δ𝑥 ,若 Δ x \Delta x Δx过小,会有舍入误差;若过大,会增加截断误差。因此数值微分实用性不大。
  • 计算复杂度高,如果有N个参数,则每个参数都需要单独施加扰动,则计算数值微分的复杂度为 O ( N 2 ) O(N^2) O(N2)

1.2 符号微分(Symbolic Differentiation)

符号微分是一种基于符号计算的自动求导方法,符号计算也叫代数计算,是指用计算机处理处理带有变量的数学表达式,这里的变量被看作符号(symbols),一般不需要代入具体的值。符号计算的输入和输出都是书数学表达式,一般包括对数学表达式的化简、因式分解、微分、积分、解代数方程、求解常微分方程等运算。
使用Python中sympy库求函数导数:

import sympy

x = sympy.symbols('x')
func = x ** 2
func_derivative = sympy.diff(func)
print(func_derivative)
2*x

符号微分可以在编译时就计算梯度的数学表示,并进一步利用符号计算方
法进行优化.此外,符号计算的一个优点是符号计算和平台无关,可以在CPU或GPU 上运行.符号微分也有一些不足之处:

  • 1)编译时间较长,特别是对于循环,需要很长时间进行编译;
  • 2)为了进行符号微分,一般需要设计一种专门的语言来表示数学表达式,并且要对变量(符号)进行预先声明;
  • 3)很难对程序进行调试

1.3 自动微分(Automatic Differentiation,AD)

自动微分是一种可以对一个函数进行计算导数的方法,其基本原理是所有的数值计算可以分解为一些基本操作,包含±*/,和一些初等函数exp,log,sin,cos等(可以用计算图表示),然后利用链式法则来自动计算一个复合函数的梯度。

以函数 f ( x ; w , b ) f(x;w,b) f(x;w,b)为例,其中x为变量,w和b为参数。
f ( x ; w , b ) = 1 e − ( w x + b ) + 1 f(x;w,b)=\frac{1}{\text{e}^{-(wx+b)}+1} f(x;w,b)=e(wx+b)+11

1.3.1 计算图

计算图是数学运算的图形化表示.计算图中的每个非叶子节点表示一个基本操作,每个叶子节点为一个输入变量或常量。因此,将复合函数 f ( x ; w , b ) f(x;w,b) f(x;w,b)分解为一系列的基本操作,构成一个计算图,当x=1,w=0,b=0时, f ( x ; w , b ) f(x;w,b) f(x;w,b)的计算图如图所示。
在这里插入图片描述
其中红色数字代表变量实际取值。

1.3.2 正向传播

正向传播(forward propagation)是指对神经⽹络沿着从输⼊层到输出层的顺序,依次计算并存储模型的中间变量(包括输出),即对输入计算模型输出。

正向传播输入x=1,w=0,b=0,输出 f ( 1 ; 0 , 0 ) = 0.5 f(1;0,0)=0.5 f(1;0,0)=0.5

1.3.3 反向传播

反向传播(back-propagation)指的是计算神经⽹络参数梯度的⽅法。总的来说,反向传播依据
微积分中的链式法则,沿着从输出层到输⼊层的顺序,依次计算并存储⽬标函数有关神经⽹络各层的中间变量以及参数的梯度

从计算图可以看出,复合函数 f ( x ; w , b ) f(x;w,b) f(x;w,b)由6个基本函数 h i , 1 ≤ i ≤ 6 h_i, 1 \leq i \leq 6 hi,1i6组成。如下表所示,每个基本函数的导数都十分简单,可以通过规则来实现。

在这里插入图片描述

整个复合函数 f ( x ; w , b ) f(x;w,b) f(x;w,b)关于参数 w w w b b b的导数可以通过计算图上的节点 f ( x ; w , b ) f(x;w,b) f(x;w,b)与参数 w w w b b b之间路径上所有的导数连乘得到,即
在这里插入图片描述
∂ f ( x ; w , b ) ∂ w = ∂ f ( x ; w , b ) ∂ h 6 ∂ h 6 ∂ h 5 ∂ h 5 ∂ h 4 ∂ h 4 ∂ h 3 ∂ h 3 ∂ h 2 ∂ h 2 ∂ h 1 ∂ h 1 ∂ w = 1 × − 1 h 5 2 × 1 × e h 3 × − 1 × 1 × x = 0.25 \begin{align} \frac{\partial f(x;w,b)}{\partial w} &=\frac{\partial f(x;w,b)}{\partial h_6} \frac{ \partial h_6}{\partial h_5} \frac{\partial h_5}{\partial h_4} \frac{\partial h_4}{\partial h_3} \frac{\partial h_3}{\partial h_2} \frac{\partial h_2}{\partial h_1} \frac{\partial h_1}{\partial w} \\ &=1 \times -\frac{1}{h_5^2} \times 1 \times \text{e}^{h_3} \times-1 \times 1 \times x\\ &= 0.25 \end{align} wf(x;w,b)=h6f(x;w,b)h5h6h4h5h3h4h2h3h1h2wh1=1×h521×1×eh3×1×1×x=0.25

如果函数和参数之间有多条路径,可以将这多条路径上的导数再进行相加,得到最终的梯度.

1.3.4 计算图构建方式

计算图按构建方式可以分为

  • 动态计算图:在程序运行时动态构建,不容易优化,当不同输入的网络结构不一致时,难以并行计算,但是灵活性比较高.
  • 静态计算图:在编译时构建计算图,计算图构建好之后在程序运行时不能改变,在构建时可以进行优化,并行能力强,但灵活性比较差.

参考:

  • https://www.bilibili.com/video/BV1PF411h7Ew/?spm_id_from=333.337.search-card.all.click&vd_source=52f9eb63aa834f8c039c3dedc7463736
  • 《动手学深度学习》
  • 《神经网络与深度学习》
  • 《深度学习入门—基于Python的理论与实现》
  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
今年的华为开发者大会 HDC 2020 上,除了**昇腾、鲲鹏等自研芯片硬件平台**之外,最令人期待的就是**深度学习框架 MindSpore 的开源**了。今天上午,华为 MindSpore **首席科学家陈雷**在活动中宣布这款产品正式开源,我们终于可以在开放平台上一睹它的真面目。 本文是根据机器之心报道的MindSpore 的开源介绍而整理的.md笔记 作为一款支持**端、边、云独立/协同的统一训练和推理框架,华为希望通过这款完整的软件堆栈,实现**一次性算子开发、一致的开发和调试体验**,以此帮助开发者实现**一次开发,应用在所有设备上平滑迁移**的能力。 三大创新能力:新编程范式,执行模式和协作方式 由**自动微分自动并行、数据处理**等功能构成 开发算法即代码、运行高效、部署态灵活**的**特点**, 三层核心:从下往上分别是**后端运行时、计算引擎及前端表示层**。 最大特点:采用了业界最新的 **Source-to-Source 自动微分**,它能**利用编译器及编程语言的底层技术**,进一步**优化以支持更好的微分表达**。主流深度学习框架中主要有**三种自动微分技术,才用的不是静态计算、动态计算,而是基于**源码**转换:该技术源以**函数式编程框架**为基础,以**即时编译(JIT)**的方式**在<u>中间表达</u>(编译过程中程序的表达形式)上做自动微分变换**,支持**<u>复杂控制流场景、高阶函数和闭包</u>**。 MindSpore 主要概念就是张量、算子、单元和模型 其代码有两个比较突出的亮点:计算的调整,动态与静态可以一行代码切换;自动并行特性,我们写的串行代码,只需要多加一行就能完成自动并行。
神经网络的输出是张量时,我们仍然可以使用自动微分计算梯度。在深度学习框架中,如PyTorch和TensorFlow,都提供了针对张量的自动微分功能。 要使用自动微分计算张量的梯度,需要将张量设置为需要梯度追踪的状态。在PyTorch中,可以通过将张量包装在`torch.Tensor`的`requires_grad=True`参数中来实现。在TensorFlow中,可以通过将张量包装在`tf.Variable`中来实现。 一旦张量被设置为需要梯度追踪的状态,我们可以执行前向传播操作,然后通过调用`.backward()`方法进行反向传播。这将自动计算出张量相对于计算中所有相关参数的梯度。 例如,在PyTorch中,可以按照以下方式计算张量相对于某个损失函数的梯度: ```python import torch # 创建一个需要梯度追踪的张量 x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True) # 进行前向传播操作 y = torch.sum(x ** 2) # 反向传播计算梯度 y.backward() # 访问梯度 print(x.grad) ``` 类似地,在TensorFlow中,可以按照以下方式计算张量相对于某个损失函数的梯度: ```python import tensorflow as tf # 创建一个需要梯度追踪的张量 x = tf.Variable([1.0, 2.0, 3.0], dtype=tf.float32) # 进行前向传播操作 with tf.GradientTape() as tape: y = tf.reduce_sum(x ** 2) # 计算梯度 grads = tape.gradient(y, x) # 访问梯度 print(grads) ``` 通过这种方式,我们可以计算张量的梯度,并使用梯度来进行模型参数的更新和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值