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)
  • Python

  • MLTutorials

  • 卷积神经网络

  • 循环神经网络

  • Transformer

  • VisionTransformer

  • 扩散模型

  • 计算机视觉

  • PTM

  • MoE

  • LoRAMoE

  • LongTailed

  • 多模态

  • 知识蒸馏

  • PEFT

  • 对比学习

  • 小样本学习

  • 迁移学习

  • 零样本学习

  • 集成学习

  • Mamba

  • PyTorch

    • PyTorch概述

    • Tensors

      • Tensors
      • 自动求导
        • 自动求导
        • Autograd 简介
        • 2.2.1 梯度
      • AI硬件加速设备
      • tensor类型转换
      • tensor维度转换
      • 常见函数
      • tensor可视化为图片
    • 数据处理

    • 模型

    • 训练

    • 并行计算

    • 可视化

    • 实战

    • timm

    • Pytorch Lightning

    • 数据增强

    • 面经与bug解决

    • 常用代码片段

    • Reference
  • CL

  • CIL

  • 小样本类增量学习FSCIL

  • UCIL

  • 多模态增量学习MMCL

  • LTCIL

  • DIL

  • 论文阅读与写作

  • 分布外检测

  • GPU

  • 深度学习调参指南

  • AINotes
  • PyTorch
  • Tensors
Geeks_Z
2024-03-18
目录

自动求导

自动求导

PyTorch 中,所有神经网络的核心是autograd包。autograd 包为张量上的所有操作提供了自动求导机制。它是一个在运行时定义 ( define-by-run )的框架,这意味着反向传播是根据代码如何运行来决定的,并且每次迭代可以是不同的。

Autograd 简介

torch.Tensor是这个包的核心类。如果设置它的属性.requires_grad为True,那么它将会追踪对于该张量的所有操作。当完成计算后可以通过调用.backward(),来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad属性。

注意:在 y.backward() 时,如果 y 是标量,则不需要为 backward() 传入任何参数;否则,需要传入一个与 y 同形的 Tensor。

要阻止一个张量被跟踪历史,可以调用.detach()方法将其与计算历史分离,并阻止它未来的计算记录被跟踪。为了防止跟踪历史记录(和使用内存),可以将代码块包装在with torch.no_grad():中。在评估模型时特别有用,因为模型可能具有requires_grad = True 的可训练的参数,但是我们不需要在此过程中对他们进行梯度计算。

还有一个类对于autograd的实现非常重要:Function。Tensor和Function 互相连接生成了一个无环图 (acyclic graph),它编码了完整的计算历史。每个张量都有一个.grad_fn属性,该属性引用了创建Tensor自身的Function(除非这个张量是用户手动创建的,即这个张量的grad_fn是None )。下面给出的例子中,张量由用户手动创建,因此 grad_fn 返回结果是 None。

from __future__ import print_function
import torch
x = torch.randn(3,3,requires_grad=True)
print(x.grad_fn)
1
2
3
4
None
1

如果需要计算导数,可以在Tensor 上调用.backward()。如果Tensor 是一个标量(即它包含一个元素的数据),则不需要为backward()指定任何参数,但是如果它有更多的元素,则需要指定一个gradient参数,该参数是形状匹配的张量。

创建一个张量并设置requires_grad=True用来追踪其计算历史

x = torch.ones(2, 2, requires_grad=True)
print(x)
1
2
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
1
2

对这个张量做一次运算:

y = x**2
print(y)
1
2
tensor([[1., 1.],
        [1., 1.]], grad_fn=<PowBackward0>)
1
2

y是计算的结果,所以它有grad_fn属性。

print(y.grad_fn)
1
<PowBackward0 object at 0x000001CB45988C70>
1

对 y 进行更多操作

z = y * y * 3
out = z.mean()

print(z, out)
1
2
3
4
tensor([[3., 3.],
        [3., 3.]], grad_fn=<MulBackward0>) tensor(3., grad_fn=<MeanBackward0>)
1
2

.requires_grad_(...)原地改变了现有张量的requires_grad标志。如果没有指定的话,默认输入的这个标志是False。

a = torch.randn(2, 2) # 缺失情况下默认 requires_grad = False
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
1
2
3
4
5
6
7
False
True
<SumBackward0 object at 0x000001CB4A19FB50>
1
2
3

2.2.1 梯度

现在开始进行反向传播,因为out 是一个标量,因此out.backward()和out.backward(torch.tensor(1.)) 等价。

out.backward()
1

输出导数d(out)/dx

print(x.grad)
1
tensor([[3., 3.],
        [3., 3.]])
1
2

数学上,若有向量函数y→=f(x→),那么 y→ 关于 x→ 的梯度就是一个雅可比矩阵: J=(∂y1∂x1⋯∂y1∂xn⋮⋱⋮∂ym∂x1⋯∂ym∂xn) 而torch.autograd 这个包就是用来计算一些雅可比矩阵的乘积的。例如,如果 v 是一个标量函数 l=g(y→) 的梯度: v=(∂l∂y1⋯∂l∂ym) 由链式法则,我们可以得到: vJ=(∂l∂y1⋯∂l∂ym)(∂y1∂x1⋯∂y1∂xn⋮⋱⋮∂ym∂x1⋯∂ym∂xn)=(∂l∂x1⋯∂l∂xn)

注意:grad 在反向传播过程中是累加的(accumulated),这意味着每一次运行反向传播,梯度都会累加之前的梯度,所以一般在反向传播之前需把梯度清零。

# 再来反向传播⼀一次,注意grad是累加的
out2 = x.sum()
out2.backward()
print(x.grad)

out3 = x.sum()
x.grad.data.zero_()
out3.backward()
print(x.grad)
1
2
3
4
5
6
7
8
9
tensor([[4., 4.],
        [4., 4.]])
tensor([[1., 1.],
        [1., 1.]])
1
2
3
4

现在我们来看一个雅可比向量积的例子:

x = torch.randn(3, requires_grad=True)
print(x)

y = x * 2
i = 0
while y.data.norm() < 1000:
    y = y * 2
    i = i + 1
print(y)
print(i)
1
2
3
4
5
6
7
8
9
10
tensor([-0.9332,  1.9616,  0.1739], requires_grad=True)
tensor([-477.7843, 1004.3264,   89.0424], grad_fn=<MulBackward0>)
8
1
2
3

在这种情况下,y不再是标量。torch.autograd 不能直接计算完整的雅可比矩阵,但是如果我们只想要雅可比向量积,只需将这个向量作为参数传给backward:

v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)

print(x.grad)
1
2
3
4
tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])
1

也可以通过将代码块包装在with torch.no_grad(): 中,来阻止 autograd 跟踪设置了.requires_grad=True的张量的历史记录。

print(x.requires_grad)
print((x ** 2).requires_grad)

with torch.no_grad():
    print((x ** 2).requires_grad)
1
2
3
4
5
True
True
False
1
2
3

如果我们想要修改 tensor 的数值,但是又不希望被 autograd 记录(即不会影响反向传播), 那么我们可以对 tensor.data 进行操作。

x = torch.ones(1,requires_grad=True)

print(x.data) # 还是一个tensor
print(x.data.requires_grad) # 但是已经是独立于计算图之外

y = 2 * x
x.data *= 100 # 只改变了值,不会记录在计算图,所以不会影响梯度传播

y.backward()
print(x) # 更改data的值也会影响tensor的值
print(x.grad)
1
2
3
4
5
6
7
8
9
10
11
tensor([1.])
False
tensor([100.], requires_grad=True)
tensor([2.])
1
2
3
4
#PyTorch
上次更新: 2025/06/25, 11:25:50
Tensors
AI硬件加速设备

← Tensors AI硬件加速设备→

最近更新
01
帮助信息查看
06-08
02
常用命令
06-08
03
学习资源
06-07
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Geeks_Z | MIT License
京公网安备 11010802040735号 | 京ICP备2022029989号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式