当前位置: 首页 > news >正文

人工智能-python-深度学习-自动微分

自动微分:基础概念与应用

自动微分(Autograd)是现代深度学习框架(如PyTorch、TensorFlow)中的一个核心功能。它通过构建计算图并在计算图上自动计算梯度,简化了反向传播算法的实现。以下是自动微分的基本概念及其操作。


1. 基础概念

自动微分指的是通过跟踪计算图中的每一步计算,自动计算目标函数相对于模型参数的梯度。这些计算图是在每次前向传播时动态构建的。基于这个图,系统可以在反向传播时自动计算梯度,而不需要手动推导每个梯度。

1.1 张量

torch中一切皆为张量,属性requires_grad决定是否对其进行梯度计算。默认是False,如需计算梯度则设置为True

1.2 计算图

torch.autograd通过创建一个动态计算图来跟踪张良的操作,每个张量是计算图中的一个节点,节点之间的操作构成图的边。

在Pytorch中,当张量的requiers_grad=Ture时,Pytorch会自动跟踪与该张量相关的所有操作,并构建计算图。每个操作都会生成一个新的张量,并记录其依赖关系。当设置为True时,表示该张量在计算图中需要参与梯度计算,即在反向传播(Backpropagation)过程中惠子dog计算其梯度;当设置为False时,不会计算梯度。
例如
z=x∗yloss=z.sum()z = x * y\\loss = z.sum()z=xyloss=z.sum()
在上述代码中,x 和 y 是输入张量,即叶子节点,z 是中间结果,loss 是最终输出。每一步操作都会记录依赖关系:

z = x * y:z 依赖于 x 和 y。

loss = z.sum():loss 依赖于 z。

这些依赖关系形成了一个动态计算图,如下所示:

	  x       y\     /\   /\ /z||vloss

叶子节点

在 PyTorch 的自动微分机制中,叶子节点(leaf node) 是计算图中:

  • 由用户直接创建的张量,并且它的 requires_grad=True。
  • 这些张量是计算图的起始点,通常作为模型参数或输入变量。

特征:

  • 没有由其他张量通过操作生成。
  • 如果参与了计算,其梯度会存储在 leaf_tensor.grad 中。
  • 默认情况下,叶子节点的梯度不会自动清零,需要显式调用 optimizer.zero_grad() 或 x.grad.zero_() 清除。

如何判断一个张量是否是叶子节点?

通过 tensor.is_leaf 属性,可以判断一个张量是否是叶子节点。

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)  # 叶子节点
y = x ** 2  # 非叶子节点(通过计算生成)
z = y.sum()print(x.is_leaf)  # True
print(y.is_leaf)  # False
print(z.is_leaf)  # False

叶子节点与非叶子节点的区别

特性叶子节点非叶子节点
创建方式用户直接创建的张量通过其他张量的运算生成
is_leaf 属性TrueFalse
梯度存储梯度存储在 .grad 属性中梯度不会存储在 .grad,只能通过反向传播传递
是否参与计算图是计算图的起点是计算图的中间或终点
删除条件默认不会被删除在反向传播后,默认被释放(除非 retain_graph=True)

detach():张量 x 从计算图中分离出来,返回一个新的张量,与 x 共享数据,但不包含计算图(即不会追踪梯度)。

特点

  • 返回的张量是一个新的张量,与原始张量共享数据。
  • 对 x.detach() 的操作不会影响原始张量的梯度计算。
  • 推荐使用 detach(),因为它更安全,且在未来版本的 PyTorch 中可能会取代 data。
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x.detach()  # y 是一个新张量,不追踪梯度y += 1  # 修改 y 不会影响 x 的梯度计算
print(x)  # tensor([1., 2., 3.], requires_grad=True)
print(y)  # tensor([2., 3., 4.])

反向传播

使用tensor.backward()方法执行反向传播,从而计算张量的梯度。这个过程会自动计算每个张量对损失函数的梯度。例如:调用 loss.backward() 从输出节点 loss 开始,沿着计算图反向传播,计算每个节点的梯度。

梯度

计算得到的梯度通过tensor.grad访问,这些梯度用于优化模型参数,以最小化损失函数。

2. 计算梯度

2.1 标量梯度计算

标量梯度计算指的是计算标量(通常是损失函数)相对于模型参数的梯度。在深度学习中,常见的损失函数(如均方误差、交叉熵等)都是标量值。

import torch# 定义张量
x = torch.tensor(2.0, requires_grad=True)
y = x**2 + 3*x + 1  # 定义标量函数# 计算梯度
y.backward()  # 反向传播
print(x.grad)  # 输出x的梯度

为何需要标量梯度?

  • 在训练过程中,我们需要计算损失函数相对于各个参数的梯度,从而调整模型参数。标量梯度的计算是整个训练过程中优化模型的基础。
2.2 向量梯度计算

向量梯度计算用于计算多维向量函数相对于输入向量的梯度。例如,输出是一个向量时,我们希望计算每个分量的梯度。

# 定义张量
x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x**2  # 计算每个元素的平方# 计算梯度
y.backward(torch.tensor([1.0, 1.0]))  # 向量梯度计算
print(x.grad)  # 输出x的梯度

为何需要向量梯度?

  • 在多输入多输出的情况下,向量梯度计算能有效地描述每个输入对于输出的影响。
2.3 多标量梯度计算

在一些复杂的场景中,损失函数可能有多个标量输出。我们需要计算每个标量输出对参数的梯度。

x = torch.tensor([2.0, 3.0], requires_grad=True)
y1 = x[0]**2 + 3*x[0] + 1
y2 = x[1]**3 + 2*x[1] - 5
y = y1 + y2  # 多标量函数y.backward()  # 计算梯度
print(x.grad)

为何需要多标量梯度?

  • 多标量梯度有助于处理多任务学习中的梯度计算,特别是当每个任务有不同的损失函数时。
2.4 多向量梯度计算

当输出是多个向量时,我们通常需要计算每个向量对每个输入的梯度。比如在生成对抗网络(GAN)或多任务学习中,常见这种情况。

x = torch.tensor([1.0, 2.0], requires_grad=True)
y1 = x[0]**2 + 3*x[0]
y2 = x[1]**3 + 2*x[1]grad_outputs = torch.tensor([1.0, 1.0])  # 指定多个输出梯度
y1.backward(grad_outputs)  # 分别计算y1和y2的梯度

为何需要多向量梯度?

  • 计算多个输出的梯度可以帮助我们进行多维度的优化,尤其是在复杂的网络结构中,多个输出有助于提高模型的多样性和鲁棒性。

3. 梯度上下文控制

在深度学习中,常常需要控制梯度计算的上下文,以节省内存或者针对性地优化某些参数。

3.1 控制梯度计算

我们可以通过torch.no_grad()with torch.set_grad_enabled(False)来临时停止梯度计算,这对于不需要计算梯度的操作(例如推理阶段)非常有用。

with torch.no_grad():y = x * 2  # 在此块中,不会计算梯度

为何控制梯度计算?

  • 在推理阶段,我们不需要梯度,这样可以节省计算资源和内存。
3.2 累计梯度

在某些情况下,梯度计算需要分多个小批次进行累计。例如,使用小批次训练时,梯度会在每个小批次上累加。

optimizer.zero_grad()  # 清空之前的梯度
y.backward()  # 累计梯度
optimizer.step()  # 更新参数

为何累计梯度?

  • 累计梯度可以使得模型在小批次上进行优化,而不丢失总体梯度信息,适用于大规模数据的训练。
3.3 梯度清零

在每次更新前,我们需要清空之前计算的梯度,否则它会在下一步的计算中累加。

optimizer.zero_grad()  # 清除上次计算的梯度

为何清零梯度?

  • 防止梯度计算的累积影响下一次计算,确保每次计算梯度时的准确性。

4. 案例分析

4.1 求函数最小值

通过计算梯度并使用优化算法(如梯度下降),我们可以找到函数的最小值。

x = torch.tensor(2.0, requires_grad=True)
for _ in range(100):y = x**2 + 3*x + 1y.backward()with torch.no_grad():x -= 0.1 * x.grad  # 使用梯度更新xx.grad.zero_()  # 清空梯度

为何使用梯度下降求解最小值?

  • 通过不断调整参数,沿着梯度方向前进,直到收敛到函数的最小值。
4.2 函数参数求解

如果已知函数并希望通过梯度来求解某些未知参数,可以使用反向传播来更新这些参数。

def func(x):return x**2 - 4*x + 3x = torch.tensor(3.0, requires_grad=True)
for i in range(100):y = func(x)y.backward()x.data -= 0.1 * x.gradx.grad.zero_()

为何求解函数参数?

  • 在机器学习中,模型的参数通过梯度计算来优化,进而提高模型的性能。

结论

自动微分的引入让深度学习框架大大简化了梯度计算过程。通过自动计算标量、向量梯度以及控制梯度的计算上下文,开发者可以专注于模型设计而非手动推导梯度公式。


http://www.dtcms.com/a/348454.html

相关文章:

  • MySQL數據庫開發教學(二) 核心概念、重要指令
  • Run-Command:高效便捷的命令行工具
  • 46.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--扩展功能--集成网关--网关集成日志
  • ArticulateX:通过发音器官空间实现端到端单语语音翻译的突破
  • Vue vs React:前端框架的差异与选择
  • LabVIEW调用MATLAB 的分形生成
  • AMD KFD驱动分析系列0:HSA(异构系统架构)驱动概览
  • 海盗王3.0客户端从32位升级64位之路
  • Redis如何高效安全的遍历所有key?
  • 音视频学习(五十五):H264中的profile和level
  • DAY 55 序列预测任务介绍
  • 基于深度学习的餐盘清洁状态分类
  • 【Protues仿真】基于AT89C52单片机的温湿度测量
  • Linux的线程概念与控制
  • 高并发内存池(1)-定长内存池
  • 阿里开源通义万相Wan2.2:视频生成技术的革命性突破
  • MR椎间盘和腰椎分割项目:基于深度学习的医学图像分析
  • Linux系统之Centos7安装cockpit图形管理界面
  • 项目学习总结(5)
  • python---构造函数、析构函数
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘gunicorn’问题
  • 【springboot 技术代码】集成mongodb 详细步骤
  • localhost和127.0.0.1的区别
  • 界面规范7-可左右拖动的分割条
  • MATLAB GUI 设计入门:用 Guide 工具快速搭建交互界面
  • React Hooks useEffect的使用
  • React 18+ 并发模式异常
  • Linux服务测试题(DNS,NFS,DHCP,HTTP)
  • pytorch线性回归(二)
  • ⭐CVPR2025 病理分析全能模型 CPath-Omni 横空出世