本文参考了官方文档及各个大佬的博客
在神经网络模型中需要对参数求导更新,pytorch中Autograd包为张量上的所有操作提供了自动求导机制。它是一个在运行时定义(define-by-run)的框架,这意味着反向传播是根据代码如何运行来决定的,并且每次迭代可以是不同的。
本文涉及:
Tensor属性:.grad,.grad_fn, .requires_grad
Tensor函数:.backward(),.detach(),,retain_grad()
函数:.zero_grad()
求梯度函数backward()的参数gradient
Autograd包中torch.Tensor类,有个 .requires_grad
属性,当这个属性为True时,它往后的历史(它参与的计算过程)就回被追踪。
x = torch.ones(2, 2, requires_grad=True)
print(x)
#输出为
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
当一个Tensor经历过一次运算后,它就具有了.grad_fn
属性,该属性引用了创建 Tensor
自身的Function
(运算,如y=x+2),当Tensor由用户直接创建(如:x=2),那么这个Tensor的 grad_fn属性
是 None
。
x=torch.randn(2,2,requires_grad=True)
print(x.grad_fn)
#输出为None
y=x*x+3
print(y.grad_fn)
#输出为
print(y)
#输出为
#tensor([[3.4549, 3.3672],
# [8.2812, 3.3056]], grad_fn=)
.requires_grad
属性为True时,通过调用.backward()就可以自动求导,这个张量的所有梯度将会自动累加到.grad
属性上,要想梯度不被累加到.grad
属性上,在神经网络模型中,可以通过调用.zero_grad()将模型所有参数梯度清零。(Tensor不具有.zero_grad())。下面有2个例子
x=torch.randn(2,requires_grad=True)
y=x*x+3
out=y.mean()
out.backward()
print(x.grad)
#输出 tensor([0.0038, 1.2940])
x=torch.randn(2,requires_grad=True)
y=x*x+3
gradient=torch.tensor([0.1, 1.0], dtype=torch.float)
y.backward(gradient)
print(x.grad)
##输出为 tensor([-0.1502, 2.4981])
例子中gradient中参数的解释:
当输入(x)是向量,输出(y)是标量时,在x上的梯度是一个向量,这时不需要gradient参数。 当输入(x)是向量,输出(y)是向量时,y在x上的梯度是一个雅可比矩阵。torch.autograd
不能直接计算完整的雅可比矩阵,但是如果我们只想要雅可比向量积,只需将这个向量(gradient)作为参数传给 backward()。
上面代码就是一个求雅可比向量积的例子。下面是官方文档对.backward(gradient)的具体数学解释。
如果现在有计算y=x*x+3,z=y*y+2,out=z.mean(),调用.backward()后,只能保存叶子结点x的梯度,无法保存非叶子节点z的梯度。想要保存非叶子节点的梯度需要调用.retain_grad()函数。下面有个例子。
x=torch.randn(2,requires_grad=True)
y=x*x+3
y.retain_grad()
z=y*y+2
out=z.mean()
out.backward()
print(y.grad)
#输出为 tensor([3.8569, 3.0063])
阻止张量历史被追踪方法:
1.调用 .detach()
方法将其与计算历史分离,并阻止它未来的计算记录被跟踪。
2.将代码块包装在 with torch.no_grad():
中。
以上加有个人理解,如有错误,感谢指正