- 第五节:自动微分
Posted 海轰Pro
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了- 第五节:自动微分相关的知识,希望对你有一定的参考价值。
目录
前言
Hello!
非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~
自我介绍 ଘ(੭ˊᵕˋ)੭
昵称:海轰
标签:程序猿|C++选手|学生
简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国奖、省奖…已保研。
学习经验:扎实基础 + 多做笔记 + 多敲代码 + 多思考 + 学好英语!
唯有努力💪
知其然 知其所以然!
本文仅记录自己感兴趣的内容
2.5. 自动微分
2.5.1. 标量变量的反向传播
求函数 f ( x ) = 2 x T x f(x) = 2 x^Tx f(x)=2xTx对列向量 x x x求导后的梯度
- 初始化向量
x
x
x
- 设置x可计算梯度
requires_grad
: 如果需要为张量计算梯度,则为True,否则为False
- 计算
y
=
2
x
T
x
y = 2x^Tx
y=2xTx
dot用来计算两个向量之间内积(对应元素相乘,再累加,最终得到一个标量)
grad_fn
: grad_fn用来记录变量是怎么来的,方便计算梯度(比如这里便于使用反向传播计算梯度)
- 使用反向传播法计算梯度
理论上 f ( x ) = 2 x T x f(x) = 2 x^Tx f(x)=2xTx对 x x x求导后结果为 4 x 4x 4x
初始时 x = [ 0 , 1 , 2 , 3 ] x = [0,1,2,3] x=[0,1,2,3]
利用 x x x在 x = [ 0 , 1 , 2 , 3 ] x = [0,1,2,3] x=[0,1,2,3]时的梯度为 4 x = [ 0 , 4 , 8 , 12 ] 4x = [0, 4, 8, 12] 4x=[0,4,8,12]
计算得出的结果和理论值一样
- 判断计算得出的结果和理论值是否一样
现在设 y = x 1 + x 2 + x 3 + x 4 y = x_1 + x_2 + x_3 + x_4 y=x1+x2+x3+x4,其中 x = [ x 1 , x 2 , x 3 , x 4 ] x = [x_1, x_2, x_3, x_4] x=[x1,x2,x3,x4],求 x x x的梯度
import torch
x = torch.arange(4.0, requires_grad = True)
y = x.sum() # 相当于 x_1 + x_2 + ... + x_n = y
y.backward()
x.grad
# tensor([1., 1., 1., 1.])
解释:对 x 1 x_1 x1求偏导,结果为1,同理,对 x 2 、 x 3 、 x 4 x_2、x_3、x_4 x2、x3、x4求偏导,结果都为1
注意:在默认情况下,PyTorch会累积梯度
比如多次运行y.backward()
,会有
- 第一次
- 第二次
- 第三次
解决办法:使用grad.zero_()
清除梯度
这样多次运行,结果都是[1,1,1,1]
2.5.2. 非标量变量的反向传播
y = x ∗ x y = x * x y=x∗x 对 x x x求偏导( x x x为一个向量)
说明:
- y = x ∗ x y= x * x y=x∗x: 对应元素相乘,此时结果 y y y是一个非标量
x = [0, 1, 2, 3]
===>x * x = [0, 1 * 1 , 2 * 2 , 3 * 3] = [0, 1, 4, 9]
为了求 x x x的偏导,则需要先对 y y y进行累加求和,再使用反向传播
利用
y = x * x
对 x x x求导后,结果为 2 x 2 x 2x
x = [0,1,2,3]
==>2x = [0,2,4,6]
注:这里还是有点不懂 ??? 以下为书中原话:
2.5.3. 分离计算
若不丢弃计算图中如何计算y的任何信息,也就是不使用detach()
函数
y = x ∗ x u = y z = u ∗ x y = x * x\\\\ u = y\\\\ z = u * x y=x∗xu=yz=u∗x
等效于
z = x ∗ x ∗ x z = x * x * x z=x∗x∗x
此时z关于x求导,梯度为(此时z为非标量,需要先求和)
得到梯度为[0,3,12,27]
,与理论值
3
x
2
3 x^2
3x2 吻合
使用detach()
函数后
这里可以理解为:
u = y.detach()
使得u仅仅是一个向量[0,1,4, 9]z = u * x
, u仅仅作为一个常向量,对x求导,得到结果为u
总结:
- 不使用detach(), 那么y是由x计算出来的,也就是可以用x的算式进行替换
- 使用detach(), u仅仅表示一个向量,仅有y的值,其它信息都无
2.5.4. Python控制流的梯度计算
大概意思:
- f(a)函数是一个
分段函数
,其中每一段都是线性
的(直线) - 输入a的值不同,对应不同的线段(需要经过while循环、if-else等)
- 但是最后依
然是可以算出来x的梯度
,不受循环等的影响 - 比如经过多次循环、if-else, 得到的a与d的对应关系为 d = 1231 * a,梯度依然可以算出来为1231
- 也就是说
经过多次Python控制流(例如,条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度
练习
import numpy as np
import torch
from d2l import torch as d2l
x = torch.arange(-4.0, 4.0, 0.1, requires_grad = True)
x
y = torch.sin(x)
y.sum().backward()
x.grad == torch.cos(x)
y2 = x.grad
y2
y2_np = y2.numpy()
y2_np
x_np = x.detach().numpy()
x_np
def f(x):
return np.sin(x)
y1_np = f(x_np)
y1_np
d2l.plot(x_np, [y1_np, y2_np], 'x', 'f(x)', legend=['sin(x)', 'cos(x)'])
结语
学习资料:http://zh.d2l.ai/
文章仅作为个人学习笔记记录,记录从0到1的一个过程
希望对您有一点点帮助,如有错误欢迎小伙伴指正
以上是关于- 第五节:自动微分的主要内容,如果未能解决你的问题,请参考以下文章
第五节:从源码的角度理解各种Result(ActionResultJsonResultJavaScriptResult等)