李沐- - -动手学深度学习笔记(第二章)

预备知识

2.4微积分

标量导数

亚导数

将导数扩展到不可微的函数,例如  y=|x| ,在x=0处斜率不唯一

将|x|导数分为三种情况:

梯度

我们可以连结一个多元函数对其所有变量的偏导数,以得到该函数的梯度(gradient)向量。

\nabla_{\mathbf{x}} f(\mathbf{x}) = \bigg[\frac{\partial f(\mathbf{x})}{\partial x_1}, \frac{\partial f(\mathbf{x})}{\partial x_2}, \ldots, \frac{\partial f(\mathbf{x})}{\partial x_n}\bigg]^\top

将导数扩展到向量

其中,当x是标量,y是标量,求导也为标量,即Y1

y是向量,x是标量,求导为向量,即Y3

当y是标量,x是向量,求导为向量,即Y2

y是向量, x是向量,求导为矩阵,即Y4

以Y2举个例子: 

其中,x 为列向量,对其求的导数是Y2为行向量,上图圆形线为等高线,在(x1,x2)切线上,做一个正交方向出来,方向值为(2,4),它和梯度一样,梯度和等高线是正交的,而且指向值变化最大的方向。

举个例子:

其中,sum(x)求导,则为全1的向量;<u,v> 内积;

 以Y3举个例子:

 以Y4举个例子:

其中,I为对角矩阵; 

假设x为n维向量,在微分多元函数时经常使用以下规则: 

2.5自动求导 

链式法则

标量链式法则

 向量链式法则

其中, (1,)(1,n)标量Xn维向量=n维向量;(1,k)(k,n)k维向量Xk*n矩阵=n维量;(m,k)(k,n)m*k矩阵Xk*n矩阵=m*n矩阵。

 举个例子:

自动求导

自动求导计算一个函数在指定值上的导数

其中,符号求导:对给定的一个函数,可以将其导数求出来;

           数值求导:任意给一个函数,不需要知道函数样子,通过数值去拟合导数。

计算图

将代码分解成操作子,即将其一步一步展开

将计算表示成一个无环图

 计算图实际上等价于用链式法则求导的过程,上图每个圈可以表示一个操作或输入

显示构造:Tensorflow/Theano/MXNet

隐式构造:PyTorch/MXNet

自动求导的两种模式

反向累积

 其中,先计算z关于b的导数,将b带入再计算z关于a的导数,最后计算z关于w的导数。

总结:

        前向:执行图,存储中间结果

        反向:从相反方向去执行图,去除不需要的枝(一些值的导数不需要的话),在计算中,需要拿来中间结果去用。

 假设我们想对函数y=2x^{T}x,关于列向量x求导

import torch
x=torch.arange(4.0)
x

 在我们计算y关于x的梯度之前,我们需要一个地方来存储梯度。

x.requires_grad_(True)#等价于‘x=torch.arange(4.0,require_grad=True)’
x.grad #默认值是None

xrequires_grad 属性设置为 True,这意味着 x 将参与梯度计算

现在来计算y

y=2*torch.dot(x,x)
y

输出结果:tensor(28., grad_fn=<MulBackward0>)

通过调用反向传播函数来自动计算y关于x的每个分量的梯度

y.backward()
x.grad

输出结果:tensor([ 0.,  4.,  8., 12.])

x.grad==4*x

输出结果:tensor([True, True, True, True])

计算x的另一个函数

#在默认情况下,pytorch会累积梯度,我们需要清除之前的值
x.grad.zero_()
y=x.sum()
y.backward()
x.grad

输出结果:tensor([1., 1., 1., 1.])

深度学习中,我们的目的不是计算微分矩阵,而是批量中每个样本单独计算的偏导数之和。

#对非标量调用‘backward’需要传入一个‘gradient’参数,该参数指定微分函数
x.grad.zero_()
y=x*x
#等价于y.backward(torch.ones(len(x)))
y.sum().backward()
x.grad

输出结果:tensor([0., 2., 4., 6.])

y = x * x:对于 x = [0., 1., 2., 3.]y 变成 [0^2, 1^2, 2^2, 3^2] = [0., 1., 4.,9]

y.sum() 是对 y 的所有元素求和,结果为 0 + 1 + 4 + 9 = 14。调用 backward() 来计算 yx 的梯度。对 y = x * x 求导数,∂y/∂x = 2 * x,所以 x.grad 应该为 2 * x

x.grad:反向传播后,x.grad 会存储 2 * x 的结果。

将某些计算移动到记录的计算图之外

x.grad.zero_()
y=x*x
u=y.detach()
z=u*x
z.sum().backward()
x.grad==u

使用 detach() 从计算图中分离出张量 y,这意味着 u 不会参与梯度计算。u 的值与 y 相同,但它不具有与 x 相关的梯度信息。 

输出结果:tensor([True, True, True, True])

x.grad.zero_()
y.sum().backward()
x.grad==2*x

输出结果:tensor([True, True, True, True])

即使构建函数的计算图需要通过Python控制流(例如,条件、循环或任意函数调用),我们任然可以计算得到的变量的梯度。

import torch
# 定义函数 f
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
a = torch.randn(3, requires_grad=True)  # 假设 a 是 1D 张量
# 调用函数 f
d = f(a)
# 如果 d 是非标量,先对其求和,反向传播只能用于标量张量。
d.sum().backward()
# 打印梯度
print(a.grad)

输出结果:tensor([2048., 2048., 2048.])


第二章相关知识完结,整个预备知识部分完结!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值