持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
前言
Hello!
非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~
自我介绍 ଘ(੭ˊᵕˋ)੭
昵称:海轰
标签:程序猿|C++选手|学生
简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国奖、省奖...已保研。
学习经验:扎实基础 + 多做笔记 + 多敲代码 + 多思考 + 学好英语!
唯有努力💪
知其然 知其所以然!
本文只记录感兴趣的部分
2.5. 自动微分
2.5.1. 标量变量的反向传播
求函数对列向量求导后的梯度
- 初始化向量
- 设置x可计算梯度
requires_grad: 如果需要为张量计算梯度,则为True,否则为False
- 计算
dot用来计算两个向量之间内积(对应元素相乘,再累加,最终得到一个标量)
grad_fn: grad_fn用来记录变量是怎么来的,方便计算梯度(比如这里便于使用反向传播计算梯度)
- 使用反向传播法计算梯度
理论上对求导后结果为 初始时 利用在时的梯度为 计算得出的结果和理论值一样
- 判断计算得出的结果和理论值是否一样
现在设,其中,求的梯度
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.])
解释:对求偏导,结果为1,同理,对求偏导,结果都为1
注意:在默认情况下,PyTorch会累积梯度
比如多次运行y.backward(),会有
- 第一次
- 第二次
- 第三次
解决办法:使用grad.zero_()清除梯度
这样多次运行,结果都是[1,1,1,1]
2.5.2. 非标量变量的反向传播
对求偏导(为一个向量)
说明:
- : 对应元素相乘,此时结果是一个非标量
x = [0, 1, 2, 3]===>x * x = [0, 1 * 1 , 2 * 2 , 3 * 3] = [0, 1, 4, 9]
为了求的偏导,则需要先对进行累加求和,再使用反向传播
利用
y = x * x对求导后,结果为x = [0,1,2,3]==>2x = [0,2,4,6]
注:这里还是有点不懂 ??? 以下为书中原话:
2.5.3. 分离计算
若不丢弃计算图中如何计算y的任何信息,也就是不使用detach()函数
等效于
此时z关于x求导,梯度为(此时z为非标量,需要先求和)
得到梯度为[0,3,12,27] ,与理论值 吻合
使用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的一个过程
希望对您有一点点帮助,如有错误欢迎小伙伴指正