pytorch函数zero_grad(),step()作用
假定现在有损失函数
\[\begin{equation*}
z=x^2+y^2
\end{equation*}
\]
先用手写梯度下降算法求该损失函数的极小值.这只是一个例子,其实能直接观察出来在(0,0)邻域内的极小值是0.但是为
了说明问题,还是要假装不知道极小值,手写梯度下降算法来算.
# coding: utf-8
def f_value(x, y):
return x * x + y * y
def grad(x, y):
return 2 * x, 2 * y
if __name__ == '__main__':
x = 5
y = 10
rate = 0.1
for i in range(10):
grad_value = grad(x, y)
print("x={:.4f},y={:.4f},value={:.4f}".format(x, y, f_value(x, y)))
print("x.grad={:.4f},y.grad={:.4f}".format(grad_value[0], grad_value[1]))
x -= grad_value[0] * rate
y -= grad_value[1] * rate
若不熟悉这个代码原理,可以查阅参考资料.这就是一个最简单的梯度下降算法的实现.中间打印了梯度以及损失
函数的值.运行结果如下:
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=4.0000,y=8.0000,value=80.0000
x.grad=8.0000,y.grad=16.0000
x=3.2000,y=6.4000,value=51.2000
x.grad=6.4000,y.grad=12.8000
x=2.5600,y=5.1200,value=32.7680
x.grad=5.1200,y.grad=10.2400
x=2.0480,y=4.0960,value=20.9715
x.grad=4.0960,y.grad=8.1920
x=1.6384,y=3.2768,value=13.4218
x.grad=3.2768,y.grad=6.5536
x=1.3107,y=2.6214,value=8.5899
x.grad=2.6214,y.grad=5.2429
x=1.0486,y=2.0972,value=5.4976
x.grad=2.0972,y.grad=4.1943
x=0.8389,y=1.6777,value=3.5184
x.grad=1.6777,y.grad=3.3554
x=0.6711,y=1.3422,value=2.2518
x.grad=1.3422,y.grad=2.6844
下面代码是用pytorch实现
# coding: utf-8
import torch
import torch.optim as optim
def run(x, y):
x = torch.tensor([x], requires_grad=True)
y = torch.tensor([y], requires_grad=True)
optimizer = optim.SGD([x, y], lr=0.1)
for i in range(10):
optimizer.zero_grad()
f_value = x * x + y * y
print("x={:.4f},y={:.4f},value={:.4f}".format(x.item(), y.item(), f_value.item()))
f_value.backward()
print("x.grad={:.4f},y.grad={:.4f}".format(x.grad.item(), y.grad.item()))
optimizer.step()
if __name__ == '__main__':
run(5.0, 10.0)
2个代码的运行结果一样.第2段代码pytorch的backward()函数帮我们求了梯度.不用再手算.要注意2点.
- optimizer.zero_grad()函数有什么用?
不讲什么高深的理论和猜测.直接把optimizer.zero_grad()注释了再运行.得到如下结果:
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=4.0000,y=8.0000,value=80.0000
x.grad=18.0000,y.grad=36.0000
x=2.2000,y=4.4000,value=24.2000
x.grad=22.4000,y.grad=44.8000
x=-0.0400,y=-0.0800,value=0.0080
x.grad=22.3200,y.grad=44.6400
x=-2.2720,y=-4.5440,value=25.8099
x.grad=17.7760,y.grad=35.5520
x=-4.0496,y=-8.0992,value=81.9963
x.grad=9.6768,y.grad=19.3536
x=-5.0173,y=-10.0346,value=125.8655
x.grad=-0.3578,y.grad=-0.7155
x=-4.9815,y=-9.9630,value=124.0769
x.grad=-10.3208,y.grad=-20.6415
x=-3.9494,y=-7.8989,value=77.9899
x.grad=-18.2196,y.grad=-36.4392
x=-2.1275,y=-4.2549,value=22.6305
x.grad=-22.4746,y.grad=-44.9491
对比有optimizer.zero_grad()与没有optimizer.zero_grad()的结果,可以发现,如果不执行optimizer.zero_grad函数.
每次求梯度的值是当前梯度再加上之前的梯度.pytorch为什么要这样设计api?梯度相加有什么实际使用场景?真没有遇到过.但目前可以
得到的结论是执行optimizer.zero_grad()求得的梯度是当前梯度,不执行optimizer.zero_grad()求得的梯度是当前梯度加上之
前的梯度.
2. optimizer.step()函数有什么用?
还按之前的思路,直接把optimizer.step()注释了,再运行代码,得到如下结果:
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
x=5.0000,y=10.0000,value=125.0000
x.grad=10.0000,y.grad=20.0000
这就很清楚了,不执行optimizer.step()梯度没有变,也就是不会执行反向传播算法,损失函数也不会变.