其他笔记在专栏 深度学习 中。
(1)优化(optimization):用模型拟合观测数据的过程;
(2)泛化(generalization):数学原理和实践者的智慧,能够指导我们生成出有效性超出用于训练的数据集本身的模型。
梯度是一个向量,其分量是多变量函数相对于其所有变量的偏导数。
如果需要为张量计算梯度,则设置requires_grad=True。
创建一个Tensor并设置requires_grad=True(注意这里只能是Tensor而不是tensor,关于这两者的区别前面的文章已经提过了):
import torch
x = torch.ones(2, 2, requires_grad=True) #需要一个地方来存储梯度,等同于x = torch.ones(2, 2),x.reequires_grad_(True)
print(x)
print(x.grad_fn)
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
None
上面的代码中:
y = x + 2
print(y)
print(y.grad_fn)
print(y.is_leaf)
tensor([[3., 3.],
[3., 3.]], grad_fn=)
False
再来点更复杂的运算:
z = y * y * 2
out = z.mean() #求平均数
print(z)
print(out)
tensor([[18., 18.],
[18., 18.]], grad_fn=)
tensor(18., grad_fn=)
还可以通过.requires_grad_()来用in-place的方式改变requires_grad属性:
x = torch.randn(2, 2) # 缺失情况下默认 requires_grad = False
print(x, x.grad_fn, x.requires_grad)
y = ((x * 3) / (x - 1))
print(y, y.grad_fn, y.requires_grad)
tensor([[ 1.8788, -0.7913],
[ 0.7268, -0.1690]]) None False
tensor([[ 6.4139, 1.3252],
[-7.9830, 0.4337]]) None False
上面的代码中,默认了requires_grad = False,所以出来的.grad_fn结果全是None,现在改变requires_grad属性:
x.requires_grad_(True) #这一步也可以写成x.requires_grad = True,结果一样
print(x, x.grad_fn, x.requires_grad)
z = (x * x).sum()
print(z, z.grad_fn, z.requires_grad)
tensor([[ 1.8788, -0.7913],
[ 0.7268, -0.1690]], requires_grad=True) None True
tensor(4.7128, grad_fn=) True
这里的反向传播实际上就和我求导的顺序一致。
x = torch.arange(4.0)
x.requires_grad_(True)
x, x.grad, 3 * x * x
(tensor([0., 1., 2., 3.], requires_grad=True),
None,
tensor([ 0., 3., 12., 27.], grad_fn=))
y = (3 * x * x).mean()
print(y)
tensor(10.5000, grad_fn=)
y.backward()
print(x.grad)
print(x.grad == 3/2 * x)
tensor([0.0000, 1.5000, 3.0000, 4.5000])
tensor([True, True, True, True])
y = x.sum()
y.backward()
x, y, x.grad
(tensor([0., 1., 2., 3.], requires_grad=True),
tensor(6., grad_fn=),
tensor([1.0000, 2.5000, 4.0000, 5.5000]))
从上面的x.grad可以看出,在默认情况下,PyTorch会累积梯度,本来dy/dx=tensor([1., 1., 1., 1.]),但是由于累积了上面的dy/dx=tensor([0.0000, 1.5000, 3.0000, 4.5000]),使得我们现在得出的x.grad=tensor([1.0000, 2.5000, 4.0000, 5.5000])),也就是两个x.grad累加了起来。
这是不好的,我们一般需要用x.grad.zero_()来清楚之前的值:
x.grad.zero_()
y = x.sum()
y.backward()
x.grad
tensor([1., 1., 1., 1.])