1、为什么有自动微分这个操作?
求导是深度学习的关键步骤,训练一个神经网络都涉及求梯度这个环节。而为了加速导数的计算,深度学习框架都会通过自动计算导数来加速求导。设计好一个模型之后,系统会创建一个计算图,反向传播运算时,自动微分系统跟踪整个系统的计算图,填充对每个参数的偏导数。(以下代码在一个main函数里,进行分段解释)
2、pytorch自动微分代码解释
2.1、y是标量计算关于x的梯度
import torch
if __name__ == "__main__":
x=torch.arange(4.0)
print("x:",x)
x.requires_grad_(True)
print("\n#**********************y是标量计算关于x的梯度***************************#\n")
print("x.grad:",x.grad) #初始化时x.grad是none
y= 2*torch.dot(x,x) # 相当于函数y=2*x^2 dot:是点积:对应元素相乘求和=28,这里y是标量值
print("y:",y) #y: tensor(28., grad_fn=<MulBackward0>)
#由于之前设置了x带梯度信息,之类会打印grad_fn=<MulBackward0>,表示该函数反向传播时会进行梯度运算
y.backward() #y对x求导后是4x,x的对应数据带入得到
print("y=2*x^2,x.grad:",x.grad)#x.grad: tensor([ 0., 4., 8., 12.])
print(x.grad==4*x) #发现x.grad的确是等于4x
#注意在一次计算梯度时要清零梯度否则梯度会累计
x.grad.zero_()
y=sum(x) #y是个标量值,函数相当于y=x,对x求导,结果是1,分别带入,x.grad: tensor([1., 1., 1., 1.])
y.backward()
print("y=x,x.grad:", x.grad)
2.2、y是向量计算关于x的梯度
print("\n# **********************y是向量,计算关于x的梯度***************************#\n")
x.grad.zero_()
y=x*x
gradient = torch.ones_like(x) #torch.ones(len(x)) 也是一样创建一个shape和x相同的全1矩阵
print("y:",y)
y.backward(gradient) #计算y关于x的梯度时,就会分别计算关于x每个参数梯度,在用这些值乘上输入的gradient矩阵,更新x.grad
#y.sum().backward()也是一样的效果
print("y=x*x,x.grad:", x.grad)
2.3、分离计算概念
y=f(x) ,y是关于x的函数,u=y,z=ux,由于某种原因计算z对x求导时,需要把u当成常数来看待
所以采用u=y.detach(),让u移动到计算图之外,则会视为一个常数。
print("\n#**********************分离计算**********************#\n")
x.grad.zero_()
y=x*x
y = x * x
u = y.detach()
z = u * x
z.sum().backward()
print(x.grad == u)