玩了半年dl,也有1000多小时的训练时间了,还没好好学习过优化器。
对上文的数学公式,加入了一些直观的pytorch代码,以便更好的理解
关于pytorch中的梯度计算:
csdn上的解释更加清晰明白的讲解了目标函数为什么需要是个标量。
叶节点保留梯度信息
尝试了如下代码:
import torch
x=list(range(10))
x=torch.tensor(x,requires_grad=True,dtype=torch.float)
y=x**2+2*x
print(x)
print(y)
print(y.requires_grad)
print(y.grad_fn)
g=torch.ones_like(y)
y.backward(g)
print(x.grad)
print(y.grad)
print(y.is_leaf)
x.grad.zero_()
输出:
tensor([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.], requires_grad=True)
tensor([ 0., 3., 8., 15., 24., 35., 48., 63., 80., 99.],
grad_fn=<AddBackward0>)
True
<AddBackward0 object at 0x000002984D637760>
tensor([ 2., 4., 6., 8., 10., 12., 14., 16., 18., 20.])
None
False
c:\Users\lg257\AppData\Local\Programs\Python\Python39\lib\site-packages\torch\_tensor.py:1104: UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won't be populated during autograd.backward(). If you indeed want the .grad field to be populated for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations. (Triggered internally at C:\actions-runner\_work\pytorch\pytorch\builder\windows\pytorch\build\aten\src\ATen/core/TensorBody.h:475.)
return self._grad
tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
我们虽然得到了x的梯度值,但是没啥用,因为x是输入,
对于函数y=x**2+2*x,相当于先做x*x,再做x*2,然后再做+操作。
我们的目标是调整w,所以w也得是一个torch变量。
要注意
x=torch.tensor([1,2,3])
w=torch.tensor([2,4,6])
w*x
结果是tensor([ 2, 8, 18]) =[w1*x1,w2*x2,w3*x3]
如果输入是4*4的图像,需要二分类,则w可以是4*1,得到x*w结果是4*1,可以对4*1的输出求和,然后和>0.5为1,否则为0,就是一个2分类了。这个过程中每一步的梯度,pytorch帮你完成了。如果是多层网络,则[(x*w1)*w2]*w3,如此就可以了括号代表输出
因为每一次backward后,grad都会清零。
# Backpropagation
optimizer.zero_grad()
loss.backward()
optimizer.step()
先清零,再反向传播(计算梯度),再由优化器调整w
所以每个batch都会调整w,dy,dx=y(t)-y(t-1),x(t)-x(t-1)这样来计算的。
从上面,我们也发现神经网络中的wx都是多元一次方程。?一个网络从输入到输出经过了多个一次方程,一次方程也成为线性方程,所以这个网络每次都是画直线来分类,如果引入激活函数的话,可以带来非线性。
有没有可能loss是一个二次方程或者三次方程呢?loss有必要是二次方程吗?值得思考下
- 根据历史梯度计算一阶动量和二阶动量:
- 计算当前时刻的下降梯度:
- 根据下降梯度进行更新:
所以最简单的sgd,不需要计算动量,直接用学习率算出dw就好了。没看过原论文,但我理解随机就是体现在每个batch更新一次w,因为输入带有随机性,所以梯度下降也就随机了。
sgd容易陷入局部最小值可以理解,为什么它收敛慢还不太明白。可能是因为sgd的随机性吧。想象以下,这个batch是朝这边跑的,下个batch又朝另一边跑了。
sgdm就是带惯性的sgd,
nag就不好理解了。
adam等我目前理解是每个batch的梯度累计起来算出均值和标准差,总的来说就是考虑多个batch的结果。sgdm的m其实也实现了考虑多个batch的结果。
以后再看论文吧。
发现这篇文章讲的更清楚
[论文阅读] 综述梯度下降优化算法 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/110104333
综述论文 原文
1609.04747.pdf (arxiv.org)https://arxiv.org/pdf/1609.04747.pdf