深度学习笔记3:矩阵计算和自动求导

本文深入探讨了导数的概念,包括标量导数、亚导数和梯度,解释了它们在多变量函数中的作用。梯度是函数变化最大的方向,并且在向量和矩阵计算中有所扩展。介绍了链式法则及其在自动求导中的应用,展示了如何通过计算图进行反向传播来高效地求解导数。在深度学习中,自动求导用于计算模型参数的梯度,对于训练至关重要。文章还对比了前向累积和反向累积两种模式的优缺点,并通过实例展示了PyTorch中自动求导的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

矩阵计算

核心:如何求导数

标量导数

在这里插入图片描述

导数是切线的斜率

在这里插入图片描述

亚导数

不可微的函数

在这里插入图片描述

在这里插入图片描述

梯度

将导数拓展到向量

在这里插入图片描述

1:标量 2:向量 3:向量 4:矩阵

  • 圈 2 表示:

在这里插入图片描述

例子:(梯度的方向是变化最大的方向)在这里插入图片描述

  • 圈 3 表示:

在这里插入图片描述

  • 圈 4 表示:(拆分看)

在这里插入图片描述

在这里插入图片描述

拓展到矩阵

在这里插入图片描述

  • 由 1 和 2 说明:如果向量、矩阵在分子,那行和列不会变化;如果是在分母,则要转置。
  • 4 和 3 可以由 2 和 1 得来
  • 5 是一个思维张量,(m,l,k,n)矩阵 y 在分子,前两项的行列不变,矩阵 x 在分母,后两项要发生转置

链式法则和自动求导

在这里插入图片描述

小结

  • 导数可以被解释为函数相对于其变量的瞬时变化率,它也是函数曲线的切线的斜率。
  • 梯度是一个向量,其分量是多变量函数相对于其所有变量的偏导数。
  • 链式法则使我们能够微分复合函数。

自动求导

向量链式法则

  • 标量链式法则

在这里插入图片描述

  • 拓展到向量

在这里插入图片描述

例子1:(向量)

在这里插入图片描述

例子2:(矩阵)

在这里插入图片描述

自动求导

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

它有别于:

  • 符号求导

在这里插入图片描述

  • 数值求导

在这里插入图片描述

计算图

  • 将代码分解成操作子

  • 将计算表示成一个五环图

在这里插入图片描述

  • 显示构造(Tensorflow/Theano/MXNet)

在这里插入图片描述

  • 隐式构造( PyTorch/MXNet)

在这里插入图片描述

自动求导的两种模式

在这里插入图片描述

在这里插入图片描述

反向累计总结

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

在这里插入图片描述

复杂度

反向累积:

  • 计算复杂度:O(n),n是操作子个数(通常正向和方向的代价类似)
  • 内存复杂度:O(n),因为需要存储正向的所有中间结果

正向累积:

  • O(n)计算复杂度用来计算一个变量的梯度
  • O(1)内存复杂度

代码实现(自动求导):

假设我们想对函数y=2xx关于列向量x求导

import torch

x = torch.arange(4.0)
x

结果:tensor([0., 1., 2., 3.])

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

x.requires_grad_(True)
x.grad

计算y

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

结果:tensor(28., grad_fn=)

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

y.backward()
x.grad

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

x.grad == 4 * x

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

现在让我们计算x的另一个函数

x.grad.zero_() ##清除x的梯度值,也就是重新赋值为0
y = x.sum()
y.backward()
x.grad

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

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

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

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

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

x.grad.zero_()
y = x * x
u = y.detach() #与clone差不多,但有区别
z = u * x

z.sum().backward()
x.grad == u

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

tensor.detach():

返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad。

注意:使用detach返回的tensor和原始的tensor共同一个内存,即一个修改另一个也会跟着改变。

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

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

即使构建函数的计算图需要通过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

结果:tensor(True)

隐式构造比显式构造在控制流上做得好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值