# tensor的属性改为.requires_grad设置为true,它将开始追踪在其上的所有操作(这样就可以利用链式法则进行梯度传播)
# 完成计算后,可以调用.backward()来完成所有梯度计算,此Tensor的梯度将累积到.grad属性中
"""
注意:在y.backward()时,如果y是标量,则不需要为backward()传入任何参数;否则,需要传入一个与y同形的tensor
如果不想被继续追踪,可以调用.detach()将其从追踪记录中分离开来,这样就可以防止将来的计算被追踪,这样梯度就传不过去了,此外还可以
使用with torch.no_grad()将不想被追踪的操作代码块包裹起来,这种方法在评估模型的时候很常用
Function是另外一个很重要的类,tensor和function互相结合就可以构建一个记录有整个计算过程的有向无环图,每个tensor都有一个
.grad_fn()属性,该属性创建该tensor的function类,就是说该tensor是不是通过某些运算得到的,若是,则grad_fn返回一个与这些运算
相关的对象,否则为none
"""
# 创建一个tensor并设置requires_grad= True
import torch
x = torch.ones(2,2,requires_grad=True)
print(x)
"""
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
"""
print(x.grad_fn) # None
# 再做些运算得到
y = x + 2
print(y)
"""
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward0>)
"""
print(y.grad_fn) # <AddBackward0 object at 0x000001EEC0110BA8>
# 注意:x是直接创建的,所以它没有grad_fn,y是通过一个加法操作所创建的,所以它有一个grad_fn
# 像x这种直接创建的称为叶子节点,叶子节点对应的grad_fn是None
print(x.is_leaf,y.is_leaf) # True False
# 再来点复杂的操作
z = y * y * 3
out = z.mean()
print(z,out)
"""
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)
"""
# 通过.requires_grad_()来用in-place的方式改变requires_grad属性
a = torch.randn(2,2) # 默认requires_grad= False
a = ((a * 3) / (a - 1))
print(a.requires_grad) # False
a.requires_grad_(True)
print(a.requires_grad) # True
b = (a * a).sum()
print(b.grad_fn) # <SumBackward0 object at 0x000001AAA624D240>
# 梯度
# 因为out是一个标量,值为27,所以调用backward()时不需要指定求导变量
out.backward() # 等价于out.backward(torch.tensor(1.))
print(x.grad)
"""
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
"""
"""
例如:假设y由自变量x计算而来,w和y是同形的张量,则y.backward(w)的含义是:先计算1 = torch.sum(y * w),则1是一个标量,然后求1
对自变量x的导数
"""
x = torch.tensor([1.0,2.0,3.0,4.0],requires_grad=True)
y = 2 * x
z = y.view(2,2)
print(z)
print(y)
"""
tensor([[2., 4.],
[6., 8.]])
"""
# 现在y不是一个标量,所以在调用backward时需要传入一个和y同形的权重向量进行加权求和得到一个标量
v = torch.tensor([[1.0,0.1],[0.01,0.001]],dtype=torch.float)
z.backward(v)
print(x.grad) # tensor([2.0000, 0.2000, 0.0200, 0.0020])
# 注意:grad在反向传播的过程中是累加的,这意味着每一次运行着反向传播梯度都会累加之前的梯度,所以一般在反向传播之前需要把梯度
# 清零
# out2 = x.sum()
# out2.backward()
# print(x.grad)
"""
tensor([[5.5000, 5.5000],
[5.5000, 5.5000]])
"""
# out3 = x.sum()
# x.grad.data.zero_()
# out3.backward()
# print(x.grad)
"""
tensor([[1., 1.],
[1., 1.]])
"""
# 梯度中断
x = torch.tensor(1.0,requires_grad=True)
y1 = x ** 2
with torch.no_grad():
y2 = x ** 3
y3 = y1 + y2
print(x.requires_grad) # True
print(y1,y1.requires_grad) # tensor(1., grad_fn=<PowBackward0>) True
print(y2,y2.requires_grad) # tensor(1.) False
print(y3,y3.requires_grad) # tensor(2., grad_fn=<AddBackward0>) True
y3.backward()
print(x.grad) # tensor(2.),这里等于2是因为y2不能求导
# 如果我们想要修改tensor的数值,但是又不希望autograd记录,我们可以对tensor.data进行操作
x = torch.ones(1,requires_grad=True)
print(x.data) # 还是一个tensor ,tensor([1.])
print(x.data.requires_grad) # 但是已经独立于计算图之外,False
y = 2 * x
x.data *= 100
y.backward()
print(x) # 更改data的值也会影响tensor的值 # tensor([100.], requires_grad=True)
print(x.grad) # tensor([2.])
动手学习深度学习-梯度
最新推荐文章于 2024-07-11 01:00:00 发布