news 2026/8/18 5:16:41

Python-pytorch-自动求导

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python-pytorch-自动求导

PyTorch 自动求导(Autograd)

🤖 什么是自动求导?

自动求导(Autograd)是 PyTorch 最核心的特性之一,它自动计算神经网络中所有参数的梯度,让你无需手动推导和实现反向传播。PyTorch 使用动态计算图——每次前向传播都构建一张新图,这意味着你可以使用 Python 原生的控制流(if/for/while),模型结构可以在每次迭代中改变。

🎯 核心概念:requires_grad

importtorch# 创建可求导的张量x=torch.tensor([1.0,2.0,3.0],requires_grad=True)print(x.requires_grad)# True# 或者事后设置x=torch.tensor([1.0,2.0,3.0])x.requires_grad_(True)# 原地修改(注意尾部 _)

requires_grad=True告诉 PyTorch:这个张量的所有运算都要被追踪,以便后续计算梯度。


📐 梯度计算基本流程

# 1. 定义变量(需要梯度)x=torch.tensor([2.0,3.0],requires_grad=True)# 2. 定义计算(构建计算图)y=x**2+3*x+1# y = x² + 3x + 1# dy/dx = 2x + 3# 3. 调用 backward() 计算梯度y.sum().backward()# y 是向量,需要转为标量# 4. 查看梯度print(x.grad)# tensor([7., 9.]) ← 2*2+3=7, 2*3+3=9 ✓

为什么需要.sum()backward()

backward()只能对标量调用。如果y是向量/矩阵,需要先将其转为标量(求和、求均值等)。

x=torch.randn(3,requires_grad=True)y=x*2# ❌ y.backward() ← 报错!y 是向量# ✅ y.sum().backward() ← 正确:先转为标量# ✅ y.mean().backward() ← 也可以取均值

🧮 梯度计算原理

x=torch.tensor([1.0,2.0,3.0],requires_grad=True)w=torch.tensor([0.5,0.3,0.2],requires_grad=True)b=torch.tensor(0.1,requires_grad=True)# 前向传播z=(x*w).sum()+b# 标量输出# 反向传播(自动计算 dz/dx, dz/dw, dz/db)z.backward()print(f'dz/dx:{x.grad}')# w = [0.5, 0.3, 0.2]print(f'dz/dw:{w.grad}')# x = [1.0, 2.0, 3.0]print(f'dz/db:{b.grad}')# 1.0

🔄 梯度累积与清零 ⭐

PyTorch 默认累加梯度(而非覆盖),这是为 RNN 等多步反向传播设计的。

x=torch.tensor([2.0],requires_grad=True)foriinrange(3):y=x**2y.backward()print(f'Step{i}: grad ={x.grad}')# Step 0: grad = [4.] ← 2*2# Step 1: grad = [8.] ← 累加!4 + 4# Step 2: grad = [12.] ← 再累加!8 + 4# 正确做法:每次迭代清空梯度x=torch.tensor([2.0],requires_grad=True)foriinrange(3):y=x**2y.backward()print(f'Step{i}: grad ={x.grad}')x.grad.zero_()# ← 清零!

在实际训练中,使用optimizer.zero_grad()一次性清空所有参数梯度。


🚫 禁用梯度追踪

torch.no_grad()— 禁用梯度计算

在推理、评估时使用,减少内存占用、加速计算。

x=torch.randn(10,requires_grad=True)# 方式一: with 语句(推荐)withtorch.no_grad():y=x*2print(y.requires_grad)# False# 方式二: 装饰器@torch.no_grad()defevaluate(model,data):returnmodel(data)

.detach()— 从计算图中分离

创建一个共享数据但不参与梯度计算的新张量。

x=torch.tensor([2.0],requires_grad=True)y=x**2# y = 4z=y.detach()# z 是 4,但不与 x 关联w=z**2# 与 x 无关,不会反向传播到 x

set_grad_enabled()— 条件控制

withtorch.set_grad_enabled(is_train):output=model(input)loss=loss_fn(output,target)

⛓️ 阻止对部分参数求导

# 方式一: requires_grad=Falsew=torch.randn(3,5,requires_grad=False)# 不更新b=torch.randn(5,requires_grad=True)# 更新# 方式二: 冻结模型层forparaminmodel.features.parameters():param.requires_grad=False# 冻结 backbone# 方式三: optimizer 只传部分参数optimizer=optim.Adam(filter(lambdap:p.requires_grad,model.parameters()),lr=1e-4)

📊 梯度信息查看与调试

x=torch.tensor([[1.0,2.0],[3.0,4.0]],requires_grad=True)y=(x**2).sum()y.backward()print(x.grad)# tensor([[2., 4.], [6., 8.]])# 梯度相关属性print(x.grad_fn)# None(叶子节点)print(y.grad_fn)# <SumBackward0> — y 是由 sum 得到的# 查看计算图print(x.is_leaf)# True(用户直接创建的)

叶子节点(leaf node):用户直接创建(而非运算结果)的张量。只有叶子节点的.grad会在backward()后被填充。


🔧 retain_graph — 保留计算图

默认backward()后计算图被释放。如果需要对同一个输出多次调用backward()

x=torch.tensor([2.0],requires_grad=True)y=x**3# y = 8y.backward(retain_graph=True)print(x.grad)# 12 ← 3*2² = 12y.backward(retain_graph=True)print(x.grad)# 24 ← 累加到 12+12 = 24(注意梯度累加!)

⚠️ 绝大多数情况下不需要retain_graph=True。只在多任务学习、GAN 训练等少数场景用到。


🧪 高阶梯度

PyTorch 支持计算梯度的梯度(二阶导数)。

x=torch.tensor([2.0],requires_grad=True)y=x**3# y = x³# 一阶导: dy/dx = 3x² = 12grad1=torch.autograd.grad(y,x,create_graph=True)[0]print(grad1)# tensor([12.])# 二阶导: d²y/dx² = 6x = 12grad2=torch.autograd.grad(grad1,x)[0]print(grad2)# tensor([12.])

使用create_graph=True保留梯度计算图,以便计算更高阶导数。


⚠️ 常见错误与解决

错误原因解决
backward()报错输出不是标量.sum().mean()
gradNone没设requires_grad=True创建时设置或调用.requires_grad_()
grad值不对忘记清零,梯度累加每次迭代前optimizer.zero_grad()
内存不足保留了不必要的计算图torch.no_grad().detach()
inplace操作报错修改了需要梯度的叶子节点避免对需要梯度的张量做原地操作

📝 速查表

需求代码
启用梯度x = torch.tensor([1.], requires_grad=True)
反向传播loss.backward()
查看梯度x.grad
清零梯度x.grad.zero_()
禁用梯度with torch.no_grad():
分离张量x.detach()
冻结参数param.requires_grad = False
获取梯度值torch.autograd.grad(loss, x)
保留计算图loss.backward(retain_graph=True)
创建高阶图torch.autograd.grad(y, x, create_graph=True)

[[pytorch-总览|← 返回总览]]

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/18 5:13:56

多模态AI智能体记忆评估:WorldMemArena基准测试与工程实践

1. 项目缘起&#xff1a;当AI智能体开始“健忘”最近在折腾一个多模态AI智能体项目&#xff0c;遇到了一个让我头疼了好几天的问题。我的智能体在完成一个需要多步骤、跨模态&#xff08;比如先看一张图&#xff0c;再根据指令操作一个网页&#xff09;的复杂任务时&#xff0c…

作者头像 李华
网站建设 2026/8/18 5:13:15

DrawAI:基于智能体工作流实现光栅图像可编辑化的技术架构与实践

1. 从“不可编辑”到“可编辑”&#xff1a;一个被忽视的行业痛点在数字内容创作领域&#xff0c;我们每天都在与海量的光栅图像打交道。无论是设计师从客户那里收到的JPG产品图&#xff0c;还是运营从网上找到的PNG素材&#xff0c;亦或是摄影师拍摄的RAW文件转换后的TIFF&…

作者头像 李华
网站建设 2026/8/18 5:12:16

大模型记忆系统实战:从向量化存储到混合索引召回

1. 从“健忘”到“有记忆”&#xff1a;为什么大模型需要记忆系统如果你用过早期的ChatGPT&#xff0c;或者一些开箱即用的基础大模型&#xff0c;肯定遇到过这样的场景&#xff1a;你跟它聊了十几轮&#xff0c;详细讨论了一个项目的技术方案&#xff0c;然后你问它“我们刚才…

作者头像 李华
网站建设 2026/8/18 5:11:07

Java开发者必备:OpenJDK源码下载、构建与高效阅读全攻略

1. 为什么我们需要阅读JDK源码&#xff1f; 作为一名有几年经验的Java开发者&#xff0c;你可能已经熟练掌握了各种框架的使用&#xff0c;能快速搭建Spring Boot项目&#xff0c;也能处理日常的业务逻辑。但你是否曾有过这样的困惑&#xff1a;为什么 HashMap 的负载因子默…

作者头像 李华
网站建设 2026/8/18 5:10:21

涂鸦Wukong框架:如何用大模型与硬件抽象打造AI原生智能硬件?

1. 从“智能单品”到“AI原生硬件”&#xff1a;为什么我们需要新的开发框架&#xff1f;最近和几个做智能硬件的朋友聊天&#xff0c;大家都有一个共同的感受&#xff1a;现在的“智能硬件”越来越不“智能”了。很多产品&#xff0c;无非是在传统设备上加了个Wi-Fi模块&#…

作者头像 李华
网站建设 2026/8/18 5:09:55

基于LLM智能体的ROS 2系统架构自动化恢复方法

1. 项目缘起&#xff1a;当ROS 2系统变成“黑盒”在机器人软件开发的圈子里&#xff0c;ROS 2已经成了事实上的标准。但任何一个参与过大型、长期ROS 2项目的人&#xff0c;都或多或少经历过这样的痛苦&#xff1a;接手一个由前人开发、文档缺失、代码庞杂的系统时&#xff0c;…

作者头像 李华