#2.3自动求解梯度pytorch提供的是autograd包能够
# 根据输入和前向传播过程自动构建计算图
#并且执行反向传播
#2.3.1概念
#如果将Tensor中的 .requires_grad设置成为Ture,他就会开始追踪
#在其上的所有操作(这样就可以利用链式法则进行梯度传播了)
#完成计算后,可以调用.backward()完成所有的梯度计算。
#此Tensor放入梯度将累积到.grad()属性中
"""
如果不想被追踪,可以调用.detach()将其从追踪记录中分离出来
这样就可以防止将来的计算被追踪到,这样梯度就传不下去了
也可以用with.torch.no_grad()将不想被追踪的操作代码块包裹
起来,这种方法在评估模型的时候很有用,应为在评估模型时候我们并不需要计算可训练的参数(requires_grad=True)
的梯度
Tensor 和 Function互相结合就可以构建一个有记录有整个计算过程的
有向无环图(DAG)
每个Tensor都有一个.grad_fn属性,该属性即创建该Tensor的Function,也就是说Tensor
是不是通过某些运算得到的,如果是,则grad_fn返回一个与这些运算相关的对象,否则就返回None
"""
import torch
#创建一个Tensor并设置requires_grad=True
x = torch.ones(2,2,requires_grad=True)
print(x)
print(x.grad_fn)
#运算操作
y = x+2
print(y)
print(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)
#out是个标量
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)
b = (a*a).sum()
#b是单值的标量
print(b)
print(b.grad_fn)
'''
y = x+2
z = y*y*3
out = z.mean()
'''
#out是一个标量,所以调用backward()时不需要指定求导变量
out.backward()#等价于out.backward(torch.tensor(1.))
#看out关于x的梯度d(out)/dx
print(x.grad)
#在数学上如果函数值和自变量都是向量的函数y=f(x),
#那么y关于
#x的梯度就是一个雅克比矩阵J
#torch.autograd()这个包就是用来计算一些雅克比集镇的乘积的
#若v是一个标量函数l=g(y)的梯度
#再来反向传播一次,注意grad是累加的
out2 = x.sum()
out2.backward()
print(x.grad)
out3 = x.sum()
x.grad.data.zero_()
out3.backward()
print(x.grad)