Geeks_Z の Blog Geeks_Z の Blog
首页
  • 学习笔记

    • 《HTML》
    • 《CSS》
    • 《JavaWeb》
    • 《Vue》
  • 后端文章

    • Linux
    • Maven
    • 汇编语言
    • 软件工程
    • 计算机网络概述
    • Conda
    • Pip
    • Shell
    • SSH
    • Mac快捷键
    • Zotero
  • 学习笔记

    • 《数据结构与算法》
    • 《算法设计与分析》
    • 《Spring》
    • 《SpringMVC》
    • 《SpringBoot》
    • 《SpringCloud》
    • 《Nginx》
  • 深度学习文章
  • 学习笔记

    • 《PyTorch》
    • 《ReinforementLearning》
    • 《MetaLearning》
  • 学习笔记

    • 《高等数学》
    • 《线性代数》
    • 《概率论与数理统计》
  • 增量学习
  • 哈希学习
GitHub (opens new window)

Geeks_Z

AI小学生
首页
  • 学习笔记

    • 《HTML》
    • 《CSS》
    • 《JavaWeb》
    • 《Vue》
  • 后端文章

    • Linux
    • Maven
    • 汇编语言
    • 软件工程
    • 计算机网络概述
    • Conda
    • Pip
    • Shell
    • SSH
    • Mac快捷键
    • Zotero
  • 学习笔记

    • 《数据结构与算法》
    • 《算法设计与分析》
    • 《Spring》
    • 《SpringMVC》
    • 《SpringBoot》
    • 《SpringCloud》
    • 《Nginx》
  • 深度学习文章
  • 学习笔记

    • 《PyTorch》
    • 《ReinforementLearning》
    • 《MetaLearning》
  • 学习笔记

    • 《高等数学》
    • 《线性代数》
    • 《概率论与数理统计》
  • 增量学习
  • 哈希学习
GitHub (opens new window)
  • 深度学习理论一文搞透pytorch中的tensorautograd反向传播和计算图

    • 前言
      • 1.前向传播、反向传播和计算图
        • 1.1前向传播和反向传播
          • 1.2计算图
            • 2.Pytorch中的Tensor
              • requires_grad
                • grad
                  • grad_fn
                    • is_leaf
                      • 3.链式求导法则和雅克比矩阵
                        • 3.1链式求导法则
                          • 3.1.1复合函数的链式法则
                          • 3.1.2神经网络中的链式法则
                        • 3.2Jacobian雅克比矩阵
                          • 4.动态计算图和Autograd原理
                            • Autograd
                              • 反向传播计算图
                                • 静态计算图vs动态计算图
                                  • 总结说明
                                    • 参考资料
                                    Geeks_Z
                                    2024-12-09
                                    AINotes PyTorch
                                    目录

                                    深度学习理论一文搞透pytorch中的tensorautograd反向传播和计算图

                                    【深度学习理论】一文搞透pytorch中的tensor、autograd、反向传播和计算图

                                    Author: [Lyon]

                                    Link: [https://zhuanlan.zhihu.com/p/145353262]

                                    前言

                                    本文的主要目标:
                                    一遍搞懂反向传播的底层原理,以及其在深度学习框架pytorch中的实现机制。当然一遍搞不定两遍三遍也差不多了~ 这样以后,面试时被问到反向传播、tensor、计算图和autograd的底层原理,你不会慌~当然,我们的主要目的,在于能从底层大致理解整个深度学习框架的设计原理,实现方式,这样在模型训练和优化时,能做到心中有谱!

                                    本文主要内容:

                                    • 1.前向传播、反向传播和计算图
                                    • 2.pytorch中的Tensor
                                    • 3.链式求导法则和Jacobian雅克比矩阵
                                    • 4.pytorch中的Autograd的机制和底层原理

                                    原文发表于语雀文档:

                                    【深度学习理论】一文搞透pytorch中的tensor、autograd、反向传播和计算图 · 语雀 (opens new window)


                                    1.前向传播、反向传播和计算图

                                    1.1前向传播和反向传播

                                    随着各种深度神经网络的兴起,各种深度学习框架也是层出不穷,caffe,pytorch,tensorflow,mxnet,那么**这些深度学习框架,帮我们解决了哪些问题呢 ?**以简单的深度神经网络为例,为了完成loss的优化,我们不断以mini-batch的数据送入模型网络中进行以下迭代过程,最终优化网络达到收敛:

                                    • 1.mini-batch送入网络进行前馈/前向传播后输出的预测值,同真实值/label对比后用loss函数计算出此次迭代的loss
                                    • 2.loss进行反向传播,送入神经网络模型中之前的每一层,以更新weight矩阵和bias

                                    可见,模型训练的重点过程就两点:前向传播和反向传播,而其中前向传播就是一系列的矩阵+激活函数等的组合运算,比较简单直观;反向传播就稍显复杂了,如果我们不用深度学习框架,单纯的使用numpy也是可以完成大多数的模型训练,因为模型的训练本质上也就是一系列的矩阵运算,不过我们需要自己写方法以进行复杂的梯度计算和更新。(仅仅使用numpy训练模型,速度和效率肯定不如框架,且numpy不可以使用GPU加深计算)

                                    **深度学习框架,帮助我们解决的核心问题就是反向传播时的梯度计算和更新,**当然,它们的功能远不止这些,像各种方便的loss函数:交叉熵,MSE均方损失...;各种优化器:sgd,adam...;GPU并行计算加速等;模型的保存恢复可视化等等。

                                    1.2计算图

                                    在深度学习框架中,反向传播的计算依赖于autograd自动微分机制(这里说的自动微分,即指求导/梯度)。而autograd实现的基础,有以下两个部分:

                                    • 1.数学基础——链式求导法则和雅克比矩阵
                                    • 2.底层结构基础——由Tensor张量为基础构成的计算图模型(DAG有向无环图)。

                                    在pytorch和tensorflow中,底层结构都是由tensor组成的计算图,**虽然框架代码在实际autograd自动求梯度的过程中,并没有显示地构造和展示出计算图,不过其计算路径确实是沿着计算图的路径来进行的。**所以,为了方便理解,我们需要了解计算图的概念。

                                    **计算图,即用图的方式来表示计算过程。**这里先看一个简单的计算图:设x,y,z都是shape(3,4)的矩阵,a,b,c分别表示了一系列的矩阵运算过程。a = x ×y;b = a + z;c = np.sum(b)整个运算过程,我们可以用numpy表示如下:
                                    numpy表示

                                    # numpy
                                    import numpy as np
                                    np.random.seed(0)
                                    
                                    N, D = 3, 4
                                    
                                    x = np.random.randn(N, D)
                                    y = np.random.randn(N, D)
                                    z = np.random.randn(N, D)
                                    
                                    a = x * y
                                    b = a + z
                                    c = np.sum(b)
                                    
                                    1
                                    2
                                    3
                                    4
                                    5
                                    6
                                    7
                                    8
                                    9
                                    10
                                    11
                                    12
                                    13

                                    上述的计算过程,我们可以用计算图表示:

                                    图片来源:http://cs231n.stanford.edu/slides/2019/cs231n_2019_lecture06.pdf (opens new window)

                                    如上,蓝绿色的一个个节点构成了一个计算图,节点里的内容是变量或者计算符,这就是一个简单的计算图。同样的计算过程,也可以用pytorch中的tensor来表示:
                                    pytorch表示

                                    import torch
                                    x = torch.randn(N, D, requires_grad=True)
                                    y = torch.randn(N, D)
                                    z = torch.randn(N, D)
                                    
                                    a = x * y
                                    b = a + z
                                    c = torch.sum(b)
                                    
                                    1
                                    2
                                    3
                                    4
                                    5
                                    6
                                    7
                                    8

                                    如果用numpy表示,我们为了求出所有元素的梯度,需要以下几步:

                                    grad_c = 1.0
                                    grad_b = grad_c * np.ones((N, D))
                                    grad_a = grad_b.copy()
                                    grad_z = grad_b.copy()
                                    grad_x = grad_a * y
                                    grad_y = grad_a * x
                                    
                                    1
                                    2
                                    3
                                    4
                                    5
                                    6

                                    而这只是一个很简单的情形,当我们面对复杂的神经网络时,仅依靠简单的numpy手动显示地计算梯度,是复杂度爆炸的且无法完成的事情!这时,框架的好处就体现出来了。基于计算图的数据结构使得pytorch可以应对复杂的神经网络,能方便地利用autograd机制来自动求导,这里只需一个.backward()即可自动求出标量对所有变量的梯度,并将梯度值存在各个变量tensor节点中,只需.grad即可读取:

                                    c.backward()
                                    print(x.grad)
                                    
                                    # 输出
                                    tensor([[-1.1826e+00, -1.9904e-01,  1.6238e+00,  8.1178e-04],
                                           [-7.6080e-01,  7.8881e-02,  2.1591e+00,  3.8564e-01],
                                           [ 4.7460e-01, -3.8614e-01,  1.5341e-01, -6.5654e-01]])
                                    
                                    1
                                    2
                                    3
                                    4
                                    5
                                    6
                                    7

                                    当然计算图的表示方式也是多种多样的,譬如w = x+y+z_就可以用下面两种计算图来表示,表达的意思相同:

                                    图片来源:https://zhuanlan.zhihu.com/p/69175484 (opens new window)

                                    下面,我们来看一个pytorch中的简单计算图:

                                    图片来源:https://towardsdatascience.com/pytorch-autograd-understanding-the-heart-of-pytorchs-magic-2686cd94ec95 (opens new window)

                                    该计算图表示了pytorch中的计算过程:x = 1.0 y = 2.0 z = x × y。其中,紫色节点为计算符;绿色节点为Tensor张量,框中存储的data,grad,is_leaf等为Tensor的部分属性;

                                    data:存放的是该张量的数据;
                                    requires_grad: 用于判断该tensor是否需要被跟踪,用以计算梯度,默认为False;
                                    grad:初始为None;requires_grad = False时为None,否则当某out节点调用out.backward()时,生成新tensor节点,存放计算后的∂out/∂x梯度值,梯度值不会自动清空(下次调用out.backward()时可累积)
                                    **grad_fn:**反向传播时,用来计算梯度的函数;
                                    **is_leaf:**表明该tensor是否为叶子节点

                                    2.Pytorch中的Tensor

                                    上面例子中的计算图,简单介绍了Tensor,实际上Tensor张量就是pytorch中构建计算图的基础,而计算图又构成了前向/反向传播的结构基础。

                                    在Pytorch中,Tensor类在python代码中有定义,其中的很多方法实现是调用底层的c++完成的,不过我们还是可以看一下其定义,大致了解下这个类中有哪些类变量和方法。

                                    class Tensor:
                                        requires_grad: _bool = ...
                                        grad: Optional[Tensor] = ...
                                        data: Tensor = ...
                                        names: List[str] = ...
                                        @property
                                        def dtype(self) -> _dtype: ...
                                        @property
                                        def shape(self) -> Size: ...
                                        @property
                                        def device(self) -> _device: ...
                                        @property
                                        def T(self) -> Tensor: ...
                                        @property
                                        def grad_fn(self) -> Optional[Any]: ...
                                        @property
                                        def ndim(self) -> _int: ...
                                        @property
                                        def layout(self) -> _layout: ...
                                    
                                        def __abs__(self) -> Tensor: ...
                                        def __add__(self, other: Any) -> Tensor: ...
                                        @overload
                                        def __and__(self, other: Number) -> Tensor: ...
                                        @overload
                                        def __and__(self, other: Tensor) -> Tensor: ...
                                        @overload
                                        def __and__(self, other: Any) -> Tensor: ...
                                        def __bool__(self) -> builtins.bool: ...
                                        def __div__(self, other: Any) -> Tensor: ...
                                            ...
                                            ...
                                    
                                    1
                                    2
                                    3
                                    4
                                    5
                                    6
                                    7
                                    8
                                    9
                                    10
                                    11
                                    12
                                    13
                                    14
                                    15
                                    16
                                    17
                                    18
                                    19
                                    20
                                    21
                                    22
                                    23
                                    24
                                    25
                                    26
                                    27
                                    28
                                    29
                                    30
                                    31
                                    32

                                    Tensor类很长,有很多类变量和方法,譬如**:requires_grad、grad、data、is_leaf...**

                                    类中还有很多@property注解表示的方法,譬如表示数据类型的dtype、表示张量形状的shape、表示张量使用设备类型的device和表示张量梯度计算函数的grad_fn....这些类方法可以当做属性被'.'调用,如:tensor.device;而无注解的正常方法是通过方法调用,如tensor.tolist()。

                                    tensor = torch.tensor(3.0, requires_grad=True)
                                    print(tensor.requires_grad)
                                    print(tensor.data)
                                    # True
                                    # tensor(3.)
                                    print(tensor.shape)
                                    print(tensor.device)
                                    print(tensor.grad_fn)
                                    # torch.Size([])
                                    # cpu
                                    # None
                                    print(tensor.tolist())
                                    # 3.0
                                    
                                    1
                                    2
                                    3
                                    4
                                    5
                                    6
                                    7
                                    8
                                    9
                                    10
                                    11
                                    12
                                    13

                                    根据https://pytorch.org/docs/stable/tensors.html (opens new window)的描述,我们看几个比较重要的变量/方法的含义:

                                    • dtype 该张量存储的值类型,可选类型见:torch.``dtype
                                    • device 该张量存放的设备类型,cpu/gpu
                                    • data 该张量节点存储的值;
                                    • requires_grad 表示autograd时是否需要计算此tensor的梯度,默认False;
                                    • grad 存储梯度的值,初始为None
                                    • grad_fn 反向传播时,用来计算梯度的函数;
                                    • is_leaf 该张量节点在计算图中是否为叶子节点;

                                    requires_grad

                                    Tensor类变量,布尔值,表示autograd时是否需要计算此tensor的梯度,默认False;用https://pytorch.org/docs/stable/notes/autograd.html#how-autograd-encodes-the-history (opens new window)上的话描述:requires_grad允许从梯度计算中细粒度地排除子图,并可以提高计算效率。
                                    这里需要注意一点,某个操作/tensor构成的模型中,只要有单个输入需要记录梯度(requires_grad=True),则该操作/模型的输出也必然需要记录梯度(否则梯度是无法传递到该tensor上的)。当且仅当某个操作/模型上所有的输入都无需记录梯度时,输出才可以不记录梯度,设置为requires_grad=False。
                                    例子:

                                    >>> y = torch.randn(5, 5)  # requires_grad=False by default
                                    >>> z = torch.randn((5, 5), requires_grad=True)
                                    >>> a = x + y
                                    >>> a.requires_grad
                                    False
                                    >>> b = a + z
                                    >>> b.requires_grad
                                    True
                                    
                                    1
                                    2
                                    3
                                    4
                                    5
                                    6
                                    7
                                    8

                                    实际应用中,requires_grad有什么用呢?以目标检测为例,通常我们在迁移学习的时候往往采取以下方式:
                                    用预训练的(如ImageNet上)过的基础网络(如VGG/ResNet)做backbone,用作特征提取;基础网络后面接多层卷积网络/全连接层用于特征分类和box回归;训练时冻结backbone骨干网络的权重,不对其进行反向传播,于是我们需要将backbone网络的所有层和参数设置requires_grad = False。

                                    def frozen_basenet(base_net):
                                        for param in base_net.parameters():
                                                param.requires_grad = False
                                    
                                    1
                                    2
                                    3

                                    grad

                                    Tensor类变量,该变量表示梯度,初始为None;当self第一次调用backward()计算梯度时,生成新tensor节点,存储该属性存放梯度值,且当下次调用backward()时,梯度值可累积。(也可以设置清空)

                                    grad_fn

                                    Tensor类属性方法,反向传播时,用来计算梯度的函数

                                    is_leaf

                                    Tensor类变量,布尔值,标记该tensor是否为叶子节点

                                    • 按照惯例,所有requires_grad=False的Tensors都为叶子节点;
                                    • 所有用户显示初始化的Tensors也为叶子节点;

                                    且当用户显示初始化时,如x = torch.tensor(1.0)或x = torch.randn(1,1)方式,表明该tensor不是由各种操作(operation)的结果隐式生成的,故其为叶子节点。
                                    例如:

                                    # 用户显示初始化
                                    >>> a = torch.rand(10, requires_grad=True)
                                    >>> a.is_leaf
                                    True
                                    
                                    # 使用.cuda()后,机器隐式地将cpu类型的tensor转换为了cuda类型的tensor
                                    # 且其requires_grad=True故非叶子节点
                                    >>> b = torch.rand(10, requires_grad=True).cuda()
                                    >>> b.is_leaf
                                    False
                                    
                                    # c是有操作符 + 隐式生成的tensor,且requires_grad=True,故非叶子节点
                                    >>> c = torch.rand(10, requires_grad=True) + 2
                                    >>> c.is_leaf
                                    False
                                    
                                    1
                                    2
                                    3
                                    4
                                    5
                                    6
                                    7
                                    8
                                    9
                                    10
                                    11
                                    12
                                    13
                                    14
                                    15

                                    3.链式求导法则和雅克比矩阵

                                    3.1链式求导法则

                                    链式法则是https://baike.baidu.com/item/微积分/6065 (opens new window)中的https://baike.baidu.com/item/求导 (opens new window)法则,用于求一个复合函数的导数,是在微积分的求导运算中一种常用的方法。复合函数的导数将是构成复合这有限个函数在相应点的 导数的乘积,就像锁链一样一环套一环,故称链式法则。

                                    3.1.1复合函数的链式法则

                                    这里给出wiki上的一个例子:
                                    求函数 f(x)=(x2+1)3 的导数。

                                    解答:
                                    我们可以直接暴力破解硬求导,也可以构造复合函数,利用链式求导法则来求导,设:
                                    g(x)=x2+1
                                    h(g)=g3→h(g(x))=g(x)3.

                                    则原函数可表示为 f(x)=h(g(x)) ,应用链式法则后有:

                                    f′(x)=h′(g(x))=∂h∂x=∂h∂g∗∂g∂x=3(g(x))2(2x)=3(x2+1)2(2x)=6x(x2+1)2.

                                    3.1.2神经网络中的链式法则

                                    以上是简单的数学公式中链式求导法则的应用,下面我们看一个简单的神经网络模型中的例子:

                                    一个神经网络中有5个神经元a,b,c,d,L;其中w1~w4为权重矩阵,L为输出。满足以下计算关系:
                                    b=w1∗a
                                    c=w2∗a
                                    d=w3∗b+w4∗c
                                    L=10−d

                                    组成的前向计算图如下:

                                    图片来源:https://blog.paperspace.com/pytorch-101-understanding-graphs-and-automatic-differentiation/ (opens new window)

                                    求L对w1的偏导?L对a的偏导?

                                    解答:
                                    L对w1的偏导 ${\partial L \over \partial w_1 } = {\partial L \over \partial d } {\partial d \over \partial b } {\partial b \over \partial w_1 } $

                                    L对a的偏导 ${\partial L \over \partial a } = {\partial L \over \partial d } {\partial d \over \partial b } {\partial b \over \partial a } + {\partial L \over \partial d } {\partial d \over \partial c } {\partial c \over \partial a } $

                                    实际上,在pytorch的神经网络模型中,通过反向传播来更新weight和bias的梯度时,计算过程就类似如下的计算图:

                                    图片来源:https://blog.paperspace.com/pytorch-101-understanding-graphs-and-automatic-differentiation/ (opens new window)

                                    我们通过雅克比矩阵,即可表示所有L对所有权重的偏导: J=[∂L∂w1,∂L∂w2,∂L∂w3,∂L∂w4]

                                    实际上,pytorch计算L对w1的偏导时,正是沿着反向传播计算图的路径执行的:
                                    ${\partial L \over \partial w_1 } = {\partial L \over \partial d } {\partial d \over \partial b } {\partial b \over \partial w_1 } $
                                    先求L对d的偏导数,再求d对b的偏导,然后求b对w1的偏导,最后乘积即为所求。

                                    3.2Jacobian雅克比矩阵

                                    百度百科:

                                    在向量微积分中,Jacobian雅可比https://baike.baidu.com/item/矩阵/18069 (opens new window)是一阶https://baike.baidu.com/item/偏导数/5536984 (opens new window)以一定方式排列成的矩阵,其行列式称为https://baike.baidu.com/item/雅可比行列式/4709261 (opens new window)。雅可比矩阵的重要性在于它体现了一个可微https://baike.baidu.com/item/方程/6306 (opens new window)与给出点的最优线性逼近。因此,雅可比矩阵类似于多元函数的导数。
                                    https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant (opens new window):

                                    在矢量运算中,雅克比矩阵是基于函数对所有变量一阶偏导数的数值矩阵,当输入个数 = 输出个数时又称为雅克比行列式。
                                    假设f: ℝ_n_ → ℝ_m 是一个函数,其每个一阶偏导数都存在且属于ℝ_n。函数以x ∈ ℝ_n_ 为输入,以向量 f(x) ∈ ℝ_m_为输出。则f的Jacobian矩阵定义为m×n矩阵,表达如下:

                                    4.动态计算图和Autograd原理

                                    Autograd

                                    在熟悉了计算图、链式求导法则、雅克比矩阵的概念后,我们现在来看下反向传播在pytorch中的核心底层原理——Autograd和动态计算图。Autograd简而言之就是反向的自动微分(求偏导)系统。其实现的基础依赖于两点,前面也说过:

                                    • 1.数学基础——链式求导法则和雅克比矩阵
                                    • 2.底层结构基础——由Tensor张量为基础构成的计算图模型(DAG有向无环图)。

                                    以下内容概况自官方文档:https://pytorch.org/docs/stable/notes/autograd.html#how-autograd-encodes-the-history (opens new window)

                                    在用户用Tensor节点定义网络模型时,对Tensor的所有操作(包括tensor之间的关系,tensor的值的改变等)将被记录跟踪,形成一个概念上的前向传播的有向无环图DAG,在图中,输入tensor作为叶子节点,输出tensor作为根节点。反向传播autograd计算梯度时,从根节点开始遍历这些tensors来构造一个反向传播梯度的计算图模型,将计算得到的梯度值更新到上一层的节点,并重复此过程直至所有required=True的tensor变量都得到更新。此过程是从输出到输入节点一层层更新梯度,故称为反向传播。这一层层地求导过程,即隐式地利用了链式法则,最终各个变量的梯度值得以更新,故此过程形象地称为autograd。

                                    有的学习资料里也称为autometic dierentiation(自动分化)或auto di,不过实在不如autograd简洁

                                    反向传播计算图

                                    从输出节点(根)遍历tensors,使用了栈结构,每个tensor梯度计算的具体方法存放于tensor节点的grad_fn属性中,依据此构建出包含梯度计算方法的反向传播计算图。

                                    静态计算图vs动态计算图

                                    静态计算图
                                    理论上神经网络模型定义好以后就无需更改,当计算图构建好以后,在一轮轮的前向传播/反向传播迭代中可以重复使用此计算图,只不过将计算的梯度值不断更新到每个变量节点处即可,这种方式称为静态计算图,而早期的tensorflow采用的就是静态计算图的方式。
                                    动态计算图
                                    什么是动态计算图 ?和静态图相反,pytorch在设计中采取了动态计算图的方式,即反向传播的计算图是动态更新的。每一轮反向传播开始时(前向传播结束后)都会动态的重新构建一个计算图,当本次反向传播完成后,计算图再次销毁。这种动态更新的方式允许用户在迭代过程中更改网络的形状和大小。
                                    个人简单理解:
                                    理论上静态图,更节省内存,速度更快;动态图更灵活自由,不过牺牲了部分速度和内存空间。但实际并不一定,因为深度学习框架不仅仅是计算图,还涉及到其他代码和底层优化,所以究竟是哪种更好,需要自行判断~

                                    总结说明

                                    1.在pytorch的代码实现层面,并没有显示地构造出反向传播的计算图模型,而是从遍历根节点开始就开始了节点遍历+梯度计算/更新的同步过程(并不是等构建完成了计算图才开始节点的梯度计算和更新,而是一边遍历节点一边更新和计算梯度)。当所有节点都更新完成后,从路径上看,节点遍历和梯度更新的顺序,恰恰是沿着概念上的反向传播计算图来进行的。

                                    2.在代码实现层面,并没有显示地利用链式求导法则的公式,进行梯度计算。而是同样,通过一层层节点的遍历和梯度计算,隐式的利用了链式求导的法则(见3.1.2);同样,并没有显示地计算雅克比矩阵,而是矩阵运算时,无意形成的Jacobian。

                                    3.深度学习框架的核心,即tensor和计算图,基于此结构,我们可以方便地利用链式法则对各个变量更新梯度。上面说过,如果不利用诸如pytorch、tensorflow之类的框架,纯python+numpy开发一个可以autograd的框架是很复杂的,不过复杂归复杂,也是可以实现的——github:

                                    https://github.com/hips/autograd (opens new window)


                                    参考资料

                                    知乎:
                                    https://zhuanlan.zhihu.com/p/69175484 (opens new window)
                                    https://zhuanlan.zhihu.com/p/69294347 (opens new window)
                                    官方文档:
                                    https://pytorch.org/docs/stable/tensors.html (opens new window)
                                    https://pytorch.org/docs/stable/notes/autograd.html#how-autograd-encodes-the-history (opens new window)
                                    博客:
                                    https://blog.paperspace.com/pytorch-101-understanding-graphs-and-automatic-differentiation/ (opens new window)
                                    https://towardsdatascience.com/pytorch-autograd-understanding-the-heart-of-pytorchs-magic-2686cd94ec95 (opens new window)
                                    课程:
                                    http://cs231n.stanford.edu/slides/2019/cs231n_2019_lecture06.pdf (opens new window)


                                    本文如有理解上的错误,欢迎各路大佬批评指正,交流学习~
                                    有收获的话,动动小手 ☞ 点个赞再走:)

                                    上次更新: 2025/04/02, 12:03:38
                                    最近更新
                                    01
                                    Recent Advances of Multimodal Continual Learning A Comprehensive Survey
                                    03-30
                                    02
                                    When Continue Learning Meets Multimodal Large Language Model A Survey
                                    03-30
                                    03
                                    CosineLinear
                                    03-30
                                    更多文章>
                                    Theme by Vdoing | Copyright © 2022-2025 Geeks_Z | MIT License
                                    京公网安备 11010802040735号 | 京ICP备2022029989号-1
                                    • 跟随系统
                                    • 浅色模式
                                    • 深色模式
                                    • 阅读模式