梯度与导数:
梯度是某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点出沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)
方向导数:对于多元函数来说,除了沿坐标轴方向上的导数,在非坐标轴方向上也可以求导数,这些导数就是方向导数。
导数用来反映某一函数的变化率,某一特定点的导数就是该点的“瞬间斜率”,即切线斜率。
所以,在单变量的实值函数中,梯度可简单理解为只是导数,或者说对于一个线性函数而言,梯度就是由线在某点的斜率。
autograd为Tensor上的所有操作提供自动微分,它是一个由运行定义的框架,这意味着以代码运行方式定义后向传播,并且每一次迭代都可能不同。
1、对函数y=2x关于列向量x求导
1)生成一个向量
import torch x = torch.arange(4.0) print(x)
torch.arange(start,end,step):生成一维Tensor。开始默认为0;步长默认为1,可以不写;终值必须写
输出结果:
tensor([0., 1., 2., 3.])
2) 存储梯度(在求y关于x的梯度之前,需要一个地方存储梯度)
x.requires_grad_(True)#说明需要存梯度 x.grad#y关于x的导数存放在x.grad中
.requires_grad:设置为True,则开始跟踪针对tensor的所有操作
x.grad:表示可以访问梯度
3)计算y
y = 2 * torch.dot(x,x)#y=2x^2 print(y) y.backward()#调用backward()计算梯度 x.grad#求导完,将该张量的梯度积累到.grad属性中 print(x.grad) x.grad == 4 * x#求导知道函数的梯度为4x,通过存储在x.grad中的导数验证梯度是否正确
torch.dot(x,x):仅支持计算两个具有相同数量元素的1D张量的点积,可进行自动转置
输出结果:
tensor(28., grad_fn=<MulBackward0>) tensor([ 0., 4., 8., 12.])
第一个结果:28=2*(0*0+1*1+2*2+3*3)(dot:对应元素相乘累加,得到标量)
第二个结果:x=[0,1,2,3],而y'=4x,所以梯度为4x时,为[0,4,8,12]
对y=x1+x2+...+xn,求x的梯度
x.grad.zero_()#有累积的功能,所以要重写内容,清零 y=x.sum()#对输入的tensor数据的某一维度求和,即x1+x2+...+Xn print(y) y.backward()#反向传播求导,即x1'+x2'+...+xn'=1+1+...+1(偏导数之和) x.grad#访问梯度,梯度全为1 print(x.grad)
输出结果:
tensor(6., grad_fn=<SumBackward0>) tensor([1., 1., 1., 1.])
第一个结果:x1+x2+x3+x4=0+1+2+3=6
第二个结果:[x1',x2',x3',x4']=[1,1,1,1]
2、非标量变量的反向传播
1) 对函数y=x*x关于x求导
x.grad.zero_() y=x*x print(y) y.sum().backward() x.grad print(x.grad)
输出结果:
tensor([0., 1., 4., 9.], grad_fn=<MulBackward0>) tensor([0., 2., 4., 6.])
y=x*x,y'=2x.
[0,1,4,9]-->[0,2,4,6]
3、分离计算
x.grad.zero_() y=x*x u=y.detach()#停止tensor历史记录的跟踪,调用.detach(),将与计算历史记录分离,防止将来的计算被跟踪,即把y变成常数u,而不是关于x的函数。 z=u*x print(z) z.sum().backward() x.grad print(x.grad)
输出结果:
tensor([ 0., 1., 8., 27.], grad_fn=<MulBackward0>) tensor([0., 1., 4., 9.])
y=x*x,此时y变成常数,即z=
*x,z'=
第一个结果:[0,1,2,3]-->[0,1,
*2,
*3]==[0,1,8,27]
第二个结果:[0,1,2,3]-->[0,1,
,
]==[0,1,4,9]
4、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() a.grad == d / a
f(a)=k*a,k的值取决于a。
.norm():默认,L2范数,即
torch.rand(size,out=None,dtype=None,layout=torch.strided,device=None,requires_grad=False):
size:定义输出张量形状的整数序列,可以是数量可变的参数、列表、元组.size=()表示标量
out:输出张量
dtype:返回张量所需的数据类型,默认
layout:返回张量的期望布局,默认
device:返回张量的所需device,默认
requires_grad:是否保留计算中的梯度信息,默认值:False