求导主要是有两种方式,第一种是符号求导,第二种是数值求导。

自动求导的内部其实是计算图,计算图是将代码分解成操作子,将计算表示成一个无环图。

计算图的显式构造:(mxnet)

计算图的隐式构造:(mxnet)


反向累计是比较常用的。

总结:
构造计算图
前向:执行图,存储中间结果(设置中间变量)
反向:从相反的方向执行图
去除不需要的枝

深度学习耗GPU资源体现在内存复杂度上面。因为求梯度时需要存储前面的结果。
- #自动求导
- import torch
- x=torch.arange(4.0) #requires_grad=True'''
- #x=tensor([0., 1., 2., 3.])
- x.requires_grad = True #计算y关于x的梯度之前需要存储梯度,等价于上句话的最后一个参数.
- #print(x.grad) #x.grad 默认值是none
- ########################################################################################
- #计算y
- y = 2 * torch.dot(x,x) #结果是个标量
- print('###################################################')
- print('torch.dot(x,x):\t',torch.dot(x,x))
- print('y:\t',y)
- y.backward() #通过反向传播函数自动计算y关于x每个分量的梯度
- print('x.grad:\t',x.grad)
- print('x.grad==4*x?\t',x.grad==4*x)
- print('###################################################')
- #在默认情况下,torch会累积梯度,所以需要对之前的值进行清零
- ########################################################################################
- x.grad.zero_() #下划线是指进行重写操作,也就是对x的梯度进行重写为0
- #print('x.grad:\t',x.grad)
- y=x.sum() #结果是个标量
- #print(y)
- y.backward()
- print('x.grad:\t',x.grad) #如果把16行注释,则结果是x.grad:tensor([ 1., 5., 9., 13.])
- #求和,梯度是1
- print('###################################################')
- ########################################################################################
- #在深度学习中,我们的目的不是计算微分矩阵,而是批量中每个样本单独计算的偏导数之和
- x.grad.zero_()
- y=x*x #结果是个向量
- y.sum().backward() #向量的求导转换成对标量求导(先求和再求导)
- print('x.grad:\t',x.grad)
- print('###################################################')
- ########################################################################################
- #将某些计算移动到记录的计算图之外,用于固定某些网络参数
- x.grad.zero_()
- y=x*x #结果是个向量
- u=y.detach() #把u做成常数,而非关于y的函数
- z=u*x #结果是个向量
- z.sum().backward() #向量的求导转换成对标量求导(先求和再求导)
- print('x.grad==u:\t',x.grad==u)
- x.grad.zero_()
- y.sum().backward()
- print('x.grad==2*x?\t',x.grad==2*x)
- print('###################################################')
- ########################################################################################
- #即使构建函数的计算图需要通过Python控制流(例如条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度
- def f(a):
- b = a * 2
- while b.norm() < 1000:
- b = b * 2
- if b.sum() > 0:
- c = b
- else:
- c = 100 * b
- return c
-
- a = torch.randn(size=(),requires_grad=True)
- d = f(a)
- d.backward()
- print('a.grad==d/a\t',a.grad==d/a)
- print('###################################################')
###################################################
torch.dot(x,x): tensor(14., grad_fn=)
y: tensor(28., grad_fn=)
x.grad: tensor([ 0., 4., 8., 12.])
x.grad==4*x? tensor([True, True, True, True])
###################################################
x.grad: tensor([1., 1., 1., 1.])
###################################################
x.grad: tensor([0., 2., 4., 6.])
###################################################
x.grad==u: tensor([True, True, True, True])
x.grad==2*x? tensor([True, True, True, True])
###################################################
a.grad==d/a tensor(True)
###################################################进程已结束,退出代码0