PyTorch C++ Autograd 梯度计算完全指南:backward 与 grad 函数深入解析

发布时间:2026/9/8 23:28:04
PyTorch C++ Autograd 梯度计算完全指南:backward 与 grad 函数深入解析 PyTorch C Autograd 梯度计算完全指南backward 与 grad 函数深入解析【免费下载链接】pytorchTensors and Dynamic neural networks in Python with strong GPU acceleration项目地址: https://gitcode.com/GitHub_Trending/py/pytorch梯度计算是 PyTorch C 前端中最核心的能力之一。本文将系统讲解 torch::autograd::backward 与 torch::autograd::grad 两个高层梯度计算函数的完整签名、参数语义与底层实现原理并演示 Tensor 上内置的backward()、.grad()、.detach()、.requires_grad_()等方法在自动微分Automatic Differentiation流程中的实际用法。读完本文你能够在纯 C 环境下完成前向图构建、反向传播、梯度清零、高阶导数计算等常见训练与调试任务并对链式法则背后的 Jacobian-vector product雅可比向量积机制形成源码级认知。梯度计算概览C 前端中的自动微分PyTorch 为张量计算提供了自动求导能力它会在 Tensor 上记录所有算子操作构建一张有向无环的计算图随后通过反向传播backpropagation自动计算图中各节点相对于叶子张量的梯度。与 Python 端的torch.autograd.backward/torch.autograd.grad相对应纯 C 环境可暴露给 C API 与 TorchScript提供了两个顶层函数torch::autograd::backward(...)对给定张量执行反向传播并把梯度累加到叶子张量的.grad中torch::autograd::grad(...)计算输出关于指定输入的梯度并作为返回值返回不写回.grad。从源码注释可以看到torch/csrc/autograd/autograd.cpp这份 C 实现复刻了torch/autograd/__init__.py与torch._C._EngineBase.run_backward中的既有逻辑是一个不依赖 Python 的纯 C 自动微分入口二者必须长期保持语义一致。在 Autograd 索引文档 中官方给出了使用场景定位训练神经网络梯度自动计算、为特殊算子实现自定义反向传播、以及需要细粒度控制梯度计算过程时都应使用这一套 C 自动微分设施。torch::autograd::backward向叶子累加梯度函数签名与完整参数表backward的完整声明位于 torch/csrc/autograd/autograd.hvoid torch::autograd::backward( const variable_list tensors, const variable_list grad_tensors {}, std::optionalbool retain_graph std::nullopt, bool create_graph false, const variable_list inputs {});参数类型默认值语义tensorsvariable_list—必填需要求导的输出张量即被微分函数的结果。grad_tensorsvariable_list{}Jacobian-vector product 中的向量通常是对应张量的预计算梯度长度须与tensors匹配。retain_graphstd::optionalboolstd::nullopt为false时反向计算结束后用于求梯度的计算图会被释放默认取create_graph的值。create_graphboolfalse为true时构造导数图从而允许计算更高阶导数。inputsvariable_list{}只针对这些输入把梯度累加到at::Tensor::grad其余张量被忽略为空时累加到所有用于计算tensors的叶子张量。语义细节backward计算的是给定张量关于图叶子graph leaves的梯度之和整个图用链式法则求导若tensors中存在非标量数据元素多于一个且需要梯度的张量则计算 Jacobian-vector product此时必须额外提供grad_tensors。它应是长度匹配的序列保存 JVP 中的向量通常是被微分函数输出关于对应张量的梯度对不需要梯度的张量可用torch::Tensor()未定义张量占位。该函数把梯度累加到叶子张量上因此多次调用前通常需要先将.grad清零对应 Python 中的optimizer.zero_grad()/grad.zero_()语义。传入inputs时梯度只会被累加到这些输入上当某个输入不是叶子时当前实现仍会调用其grad_fn虽然严格来说不必如此这是官方明确标注的实现细节用户不应依赖该行为参见 autograd.h 中的注释。核心示例#include torch/torch.h auto x torch::randn({2, 2}, torch::requires_grad()); auto y x * x; auto z y.sum(); // 计算梯度 z.backward(); std::cout x.grad() std::endl; // dz/dx 2x被写入 x.grad()torch::autograd::grad返回梯度而非累加grad的声明同样位于 autograd.htorch::autograd::variable_list grad( const variable_list outputs, const variable_list inputs, const variable_list grad_outputs {}, std::optionalbool retain_graph std::nullopt, bool create_graph false, bool allow_unused false);参数类型默认值语义outputsvariable_list—必填被微分函数的输出。inputsvariable_list—必填需要返回梯度的输入梯度返回而不累加进at::Tensor::grad。grad_outputsvariable_list{}JVP 中的向量通常是对应每个输出的梯度未定义张量可占位语义同backward的grad_tensors。retain_graphstd::optionalboolstd::nullopt同backward默认取create_graph的值。create_graphboolfalse构造导数图以便计算更高阶导数。allow_unusedboolfalse为false时如果指定了未参与计算outputs的输入其梯度恒为零会报错为true则容忍此情况。语义要点与示例grad计算并返回输出关于输入的梯度之和其中grad_outputs长度应与outputs匹配某输出若不requires_grad其梯度可用torch::Tensor()表示。grad与backward最本质的区别在于它不修改任何张量的.grad而是把结果以variable_list形式返回因此非常适合在无需持有参数对象的工具函数或分析代码中使用#include torch/torch.h auto x torch::randn({2, 2}, torch::requires_grad()); auto y x * x; auto z y.sum(); // 用 grad() 针对特定输出-输入对求梯度不会写回 x.grad() auto grads torch::autograd::grad({z}, {x}); std::cout grads[0] std::endl; // 2xTensor 内置的梯度相关方法除顶层函数外torch::Tensor自身还提供一组梯度计算方法。文档在 gradient.md 中给出的用法可扩展如下// 启用梯度追踪 auto x torch::randn({2, 2}).requires_grad_(true); // 检查该张量是否要求梯度 bool needs_grad x.requires_grad(); // backward 之后访问梯度 auto grad x.grad(); // 从计算图中分离出来detach 后共享数据但不参与反向传播 auto x_detached x.detach();配合标量输出的便捷反向调用最常用的组合是auto loss model-forward(input); // 某种标量损失 loss.backward(); // 自动将梯度累加到所有叶子模型参数 for (auto p : model-parameters()) p.grad().zero_(); // 下一轮前清零从实现上看这些方法最终汇聚到at::Tensor的 autograd hooks。在 torch/csrc/autograd/variable.h 中定义的VariableHooks实现at::impl::VariableHooksInterface提供了_backward、requires_grad_、retain_grad、retains_grad、grad_fn、is_leaf、is_view、set_data等一系列回调——Tensor::backward()、.grad()、.detach()、.is_leaf()等在 dispatch 层即通过这些 hooks 落到 autograd 运行时。其中Variable的requires_grad()返回requires_grad_ || grad_fn_variable.h即一个非叶子中间张量即便其标志位为假只要存在grad_fn也会被视为参与求导。在不需要梯度的推理阶段应使用torch::NoGradGuard关闭梯度记录对应 Python 的with torch.no_grad()torch::NoGradGuard no_grad; // 进入该作用域后不构建计算图 auto result model-forward(input); // 不计算梯度源码级原理backward 与 grad 的内部执行流程两份高层 API 的实现集中在 torch/csrc/autograd/autograd.cpp可拆解为三个步骤。1. _make_grads构造种子梯度backward与grad都会首先调用静态函数_make_gradsautograd.cpp把用户输入规范化为参与反向的梯度序列其行为包括grad_outputs为空时对每个requires_grad()的输出做两条TORCH_CHECK校验输出必须为标量output.numel() 1否则报grad can be implicitly created only for scalar outputs且数据类型必须是浮点类型否则报grad can be computed only for real scalar outputs...通过后用at::ones_like生成全 1 种子梯度。grad_outputs非空时先校验num_tensors num_gradients随后逐元素处理未定义的grad_output走与上面相同的隐式创建逻辑已定义者直接沿用但若输出为复数则校验grad_output与output的复数属性一致要求 dtype 匹配。这段逻辑解释了为什么对非标量tensors调用backward()不传grad_tensors会报错——必须显式给出与输出同形状的grad_tensors作为向量。2. run_backward把任务交给求导引擎规范化的梯度随后进入run_backwardautograd.cpp确定根节点roots对每个输出调用impl::gradient_edge(output)取其梯度边并校验该边确有grad_fn否则报element ... of tensors does not require grad and does not have a grad_fn。确定输出边output_edges当显式传入inputs时为每个输入定位其grad_fn无则退回try_get_grad_accumulatorbackward因accumulate_grad true还会对输入调用retain_grad()以便反向时写入.grad对计算图中不可达的输入用Identity节点占位参见源码中的NOTE [ Autograd Unreachable Input ]。调用引擎以Engine::get_default_engine().execute(roots, grad_outputs, keep_graph, create_graph, accumulate_grad, output_edges)真正执行反向传播。未使用输入检查仅当非空inputs且allow_unused false时校验grad_inputs[i].defined()对未参与图的输入报错并提示设置allow_unused true。3. backward 与 grad 的分流两个公开函数autograd.cpp的差别在run_backward的调用参数上一目了然backwardretain_graph缺省时回退为create_graph调用run_backward(..., /*allow_unused*/true, /*accumulate_grad*/true)把梯度累加到叶子。grad同样回退retain_graph但以allow_unused的显式传入值、accumulate_grad false调用因此梯度只返回、不累加。参数选型的工程要点结合文档与上述实现可归纳出以下工程性结论默认值语义均有源码依据非标量输出的 JVP 规则只要tensors/outputs中有非标量且requires_grad()的张量就必须按序提供与其等长的grad_tensors/grad_outputs对不参与求导的输出可用torch::Tensor()占位_make_grads会为其自动回退到隐式创建分支。retain_graph与create_graph的联动二者缺省时retain_graph取create_graph的值。由于默认create_graph false意味着常规一次反向后计算图即被释放如需多次backward()例如共享中间结果的多个损失才显式传retain_graph true——官方提醒大多数情况下应通过把中间结果作为输入单独调用grad()等更高效的方式规避而不是无脑保留整张图。inputs参数与内存效率backward传入inputs可把反向裁剪到仅关注这些输入的梯度其余张量被忽略仅在计算路径上被回溯run_backward只会为其构造 output edges。清空梯度backward采用累加语义训练循环中应在每轮迭代前对.grad清零例如param.grad().zero_()语义对应 Python 训练循环的optimizer.zero_grad()。高阶导数把create_graph置true会构造导数图从而支持二阶及以上的导数计算double backward代价是额外的图内存开销。推理模式非训练场景务必用torch::NoGradGuard或等价机制关闭自动微分图的构建避免不必要的内存与算力开销。参考与延伸阅读本主题原文docs/cpp/source/api/autograd/gradient.mdAutograd 模块总览与使用时机docs/cpp/source/api/autograd/index.md函数声明与逐参数文档torch/csrc/autograd/autograd.h纯 C 实现_make_grads/run_backward/backward/gradtorch/csrc/autograd/autograd.cppTensor 方法背后的 autograd hooksVariableHookstorch/csrc/autograd/variable.h自定义反向传播与求导模式扩展docs/cpp/source/api/autograd/custom_functions.md、docs/cpp/source/api/autograd/modes.md【免费下载链接】pytorchTensors and Dynamic neural networks in Python with strong GPU acceleration项目地址: https://gitcode.com/GitHub_Trending/py/pytorch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询