1. 简介
autograd能对所有的张量的运算求导。是一种define-by-run的框架,也就是说,返向传播的过程是根据你的code的情况来确定的,每次迭代都可能不同(不太理解)
The autograd
package provides automatic differentiation for all operations on Tensors. It is a define-by-run framework, which means that your backprop is defined by how your code is run, and that every single iteration can be different.
2. 关于Tensor
Tensor的重要属性
requires_grad: 这个属性决定了这个张量能不能求导, 如果这个属性为True,那接下来和它有关的张量的属性:
grad_fn 的值不为None,这个属性会记录下一个张量是如何由它运算得到的,例如:
a = torch.rand(3, 3, requires_grad=False)
b = a*a
print(b.grad_fn)
a = torch.rand(3, 3, requires_grad=True)
b = a*a
print(b.grad_fn)
两次的输出会不一样:
第一次,a的reqiures_grad为False,也就是说,以后我们不会对它求导,根据链式法则,就没有必要记录它的下家怎么计算的,grad_fn值为None。第二次则相反.
在训练完模型用来test的时候,一般会把参数的requires_grad属性都设为False
Tensor无意发现一个很好玩的,你可以任意给它添加属性:例如:
import torch
a = torch.rand(3, 3)
a.mom = "jpzhang"
然后你在它的属性里面可以发现它多了一个属性
3. 关于求导
3.1 如何得到导数:
根据前面说的,如果一个Tensor的requires_grad属性为True的话,就可以对它求导,主要通过调用两个函数:backward, grad.例如:
x = torch.ones((2, 2), requires_grad=True)
y = x+2
z = 3*y*y
out = z.mean()
print(out.backward())
print(x.grad)
print(z.backward())
print(x.grad)
得到的答案为4.5,计算过程如下:
需要注意一下的是,必须要先调用out.backward()求出所有的对于out的Tensor的导数(且这个Tensor的requires_grad属性要为True),然后才能通过x.grad()来查看求得的导数是多少,否则x.grad()的输出会是None.
3.2 对于输出不是标量的情况:
上面的out因为求了一个均值,输出是标量,所以可以直接调用函数out.backward(),括号里没有其他参数。但如果我们调用函数y.backward(),输出会报错:
需要改成y.backward(tensor.ones(2, 2))或者其他tensor,但shape要和y一样
比如:
import torch
x = torch.ones((2, 2), requires_grad=True)
y = x+2
y.detach()
z = 3*y*y
out = z.mean()
print(z.backward(2*torch.ones(2, 2)))
print(x.grad)
print(y.grad)
你会发现求得的导数乘了你在z.backward()函数中给的系数
至于为什么要这么做,不知道。。。。
和求导的机制有关吗?
这是因为在autograd在计算导数的时候是通过就算雅克比矩阵来实现的:
如果。。。
3.3 如果某个变量不要求导:
对于叶子变量,也就是像上面定义的x,可以直接用x.requires_grad = True来设置,但对于非叶子变量,例如上面的y, 要用detach()函数.
例如:
x = torch.ones((2, 2), requires_grad=True)
y = x+2
y.detach()
z = 3*y*y
out = z.mean()
print(out.backward())
print(x.grad)
print(y.grad)