动手学深度学习--课堂笔记 autograd

梯度与导数:

梯度是某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点出沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)

方向导数:对于多元函数来说,除了沿坐标轴方向上的导数,在非坐标轴方向上也可以求导数,这些导数就是方向导数。

导数用来反映某一函数的变化率,某一特定点的导数就是该点的“瞬间斜率”,即切线斜率。

所以,在单变量的实值函数中,梯度可简单理解为只是导数,或者说对于一个线性函数而言,梯度就是由线在某点的斜率。

autograd为Tensor上的所有操作提供自动微分,它是一个由运行定义的框架,这意味着以代码运行方式定义后向传播,并且每一次迭代都可能不同。

1、对函数y=2x\topx关于列向量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^{2} *x,z'=x^{2}

第一个结果:[0,1,2,3]-->[0,1,2^{2}*2,3^{2}*3]==[0,1,8,27]

第二个结果:[0,1,2,3]-->[0,1,2^{2},3^{2}]==[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范数,即\sqrt{​{x_{1}}^{2}+{x_{2}}^{2}+.....+{x_{n}}^{2}}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值