2 数学基础
自动求导
-
梯度
梯度是一个向量,表示函数在某一点的变化率最快的方向和大小。在梯度下降法中,梯度指的是目标函数在某一点的梯度向量。梯度下降法通过迭代的方式沿着梯度的反方向逐步更新参数,以最小化目标函数。梯度下降法的基本思想是,沿着梯度的反方向移动一小步,直到找到函数的最小值。 -
对函数y=2x^T*x,关于列向量求导。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65import torch
# 假设我们想对函数y=2x^T*x,关于列向量求导
x = torch.arange(4.0) # 范围为4。0.0~3.0
print(x)
# 存储梯度
x.requires_grad_(True) # 等价于‘x = torch.arange(4.0, requires_grad=True)’ 只有float类型的张量才能用此函数
x.grad # 默认值为None,用于访问梯度,函数放置于此,x的梯度
y = 2 * torch.dot(x, x) # 内积,a1*b1+a2*b2+a3*b3+..... ,grad_fn=<MulBackward0>隐式构造
print(y)
# 通过调用反向传播函数来自动计算y关于x每个分量的梯度
y.backward() # 求导 y=2x0^2+2x1^2+2x2^2+2x3^2对每一个分量求偏导等于4x0,4x1,4x2,4x3 即4*0,4*1,4*2,4*3
print(x.grad)
print(x.grad == 4 * x)
# 在默认情况下,pyTorch会累计梯度,我们需要清除之前的值
x.grad.zero_() # 梯度清零,变为最开始的tensor([0., 1., 2., 3.])
y = x.sum() # y=x0+x1+x2+x3
y.backward() # 分别求偏导,得tensor([1., 1., 1., 1.])
print(x.grad)
# 深度学习中,我们的目的不是计算微分矩阵,而是批量中每个样本单独计算的偏导数之和
x.grad.zero_() # 梯度清零,变为最开始的tensor([0., 1., 2., 3.])
y = x * x # 按元素分别相乘
# 等价于y.backward(torch.ones(len(x)))
y.sum().backward() # 求导 y=x0^2+x1^2+x2^2+x3^2对每一个分量求偏导
# 标量关于向量求导,得到的是一个向量;向量关于向量求导,得到的就是一个矩阵;这里是通过sum的形式转化成了标量,进行求导
print(x.grad) # 得:tensor([0., 2., 4., 6.])
# 将某些计算移动到记录的计算图之外
x.grad.zero_()
print(x.grad) # 得tensor([0., 0., 0., 0.])
y = x * x
u = y.detach() # detach 将变量转为常数,u就是一个常数
z = u * x
z.sum().backward() # 得tensor([True, True, True, True])
print(x.grad == u)
x.grad.zero_()
y.sum().backward()
print(x.grad == 2 * x)
# 即使构建函数得计算图需要通过Python控制流(例如,条件、循环或任意函数调用),我们仍计算得到的变量的梯度
def f(a):
b = a * 2
while b.norm() < 1000: # norm()用于计算张量 b 的默认 L2 范数
b = b * 2
if b.sum() > 0:
c = b
else:
c = b * 100
return c # 一直是增加系数
a = torch.randn(size=(), requires_grad=True) # 生成一个没有维度的张量,并且需要梯度计算
d = f(a)
d.backward() # d=f(a)=ka,梯度是k,k=d/a
print(a.grad == d / a) # 得tensor(True) -
显示计算:先给公式再给值;
隐式计算:先给值再给公式
评论

