You need to enable JavaScript to run this app. 关于PyTorch中Tensor类grad_fn属性存储与调用机制的技术问询
优惠活动
大模型
产品
解决方案
定价
更多

关于PyTorch中Tensor类grad_fn属性存储与调用机制的技术问询

PyTorch Tensor grad_fn 运行机制拆解

日常观测到的反常现象

日常用PyTorch做带梯度追踪的计算时,通过运算生成的新张量会自带grad_fn属性。按照官方文档的描述,这个属性“引用了生成当前张量的对应运算”,但实际在Python环境下探查时,会遇到两个和直觉不符的结果:

  • 执行a = b + 2生成张量a后,a.grad_fn的类型为AddBackward0;用inspect.getmro(type(a.grad_fn))查看类继承链,会发现该类的唯一直接基类是object,不存在预期中的统一运算父类
  • 在PyTorch公开源码中直接检索AddBackward0这类类名,无法找到任何对应的Python层实现代码

核心疑问1:grad_fn 实际存储的内容是什么?反向传播流程中如何被调用?

文档中提到的“引用运算”,并不是指Python层持有一个纯Python实现的运算对象的引用,本质是指向PyTorch底层C++自动求导计算图节点的Python轻量代理句柄。
具体运行逻辑可以拆为两步:

  1. 前向计算时的节点构建
    当在Python层触发加法这类张量运算时,PyTorch会在C层即时为这个运算创建一个计算图节点。节点内部会完整保存反向传播需要的所有上下文:包括输入张量的弱引用、运算用到的常量值、张量的设备/形状信息,同时绑定提前注册好的、对应运算的反向计算逻辑(比如加法的反向逻辑是“上游梯度直接透传给两个输入分支”)。此时Python层拿到的grad_fn,只是这个C节点对外暴露的一个调试用代理,本身不承载任何计算逻辑。
  2. 反向传播时的调用流程
    当执行tensor.backward()触发求导时,整个计算过程完全由C层的autograd引擎驱动:引擎会从输出张量对应的节点出发,按照计算图的拓扑顺序遍历所有关联节点,直接在C层调用每个节点绑定的反向计算函数,传入上游梯度值、读取节点内部存储的上下文,计算出对应输入的梯度后继续向前传递。全程不会依赖Python层的方法调用,Python侧的grad_fn代理对象只是方便开发者查看计算图结构,不参与实际的梯度计算过程。

核心疑问2:为什么grad_fn对应的类没有统一公共父类?为什么源码中找不到其实现?

没有统一公共父类的原因

Python侧看到的AddBackward0这类类,根本不是提前在源码中定义好、有固定继承关系的Python类。这些类是C层自动求导模块在构建计算图节点时,动态生成的临时Python类型:生成过程中不会特意为所有这类节点绑定一个公共的Python层父类,因此通过MRO探查时,会直接看到类的最顶层基类就是object。
需要注意的是,C
层的所有自动求导节点确实有统一的抽象基类,但这个抽象关系只存在于C++运行时内部,完全不会暴露到Python的类继承体系中,自然无法通过Python侧的类探查工具看到。

源码中找不到类实现的原因

AddBackward0这个带数字后缀的类名,本身就是运行时动态生成的标识,不是静态写在源码里的固定类名:

  • 源码中存储的只是通用的加法运算的反向计算逻辑注册信息,没有任何一段代码直接定义AddBackward0这个类
  • 类名中的数字后缀,是运行时为同类型运算的不同实例化节点做的计数标记——比如你连续执行三次相同的加法运算,每次生成的grad_fn类名后缀会依次是0、1、2,这类命名完全是程序运行时临时拼接的,自然不可能在静态源码文件中检索到对应实现。

内容的提问来源于stack exchange,提问作者David Cian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.01 14:06:04