Back to Paddle

自动微分数据结构详解

.agents/skills/paddle-design-eager-graph/references/autograd-data-structs.md

3.4.08.4 KB
Original Source

自动微分数据结构详解

本文档完整列出 Paddle 动态图自动微分系统中所有核心数据结构的成员和作用,并描述它们之间的数据流关系。

数据流总览

phi::Tensor
  └─ autograd_meta_ (AutogradMeta)
       ├─ grad_           ← 存放该 Tensor 的梯度
       └─ grad_node_      → GradNodeBase (如 AddGradNode)
            ├─ bwd_in_meta_  [vector<GradSlotMeta>]  ← 输入 slot 元信息
            ├─ bwd_out_meta_ [vector<GradSlotMeta>]  ← 输出 slot 元信息
            │     └─ adj_edge_ (Edge)
            │          └─ grad_node_ → 后继 GradNodeBase
            ├─ TensorWrapper (保存前向 Tensor)
            └─ operator()    ← 执行反向计算

执行阶段:
  GradTensorHolder.buffer_[slot][rank] → 聚合梯度 → 传入 operator()

phi::Tensor

文件paddle/phi/api/include/tensor.h

Paddle 的统一 Tensor 接口,所有 Python 端 paddle.Tensor 底层对应一个 phi::Tensor

成员类型说明
impl_std::shared_ptr<phi::TensorBase>底层存储实现(DenseTensorSparseCsrTensor 等)
autograd_meta_std::unique_ptr<AbstractAutogradMeta>自动微分元信息,动态图模式下为 AutogradMeta
name_std::stringTensor 名称,调试用

关键方法

  • set_autograd_meta() / mutable_autograd_meta() — 设置/获取自动微分信息
  • defined() — 检查 impl_ 是否有效
  • initialized() — 检查底层存储是否已分配

AbstractAutogradMeta

文件paddle/phi/api/include/tensor.h

纯虚基类,仅定义接口,使 phi::Tensor 不依赖具体的自动微分实现。

cpp
class AbstractAutogradMeta {
public:
    virtual ~AbstractAutogradMeta() = default;
};

AutogradMeta

文件paddle/fluid/eager/autograd_meta.h

继承自 AbstractAutogradMeta,包含 Tensor 参与自动微分所需的全部信息。

成员类型说明
grad_paddle::Tensor该 Tensor 的梯度,backward() 后通过 .grad 访问
grad_node_std::shared_ptr<GradNodeBase>产生该 Tensor 的反向节点
out_slot_id_size_t该 Tensor 在 grad_node_ 输出中的 slot 索引
out_rank_size_t该 Tensor 在 slot 内的 rank 索引
stop_gradient_bool为 true 时不参与梯度计算(对应 Python Tensor.stop_gradient
persistable_bool是否为持久化 Tensor(模型参数等)
retain_grads_bool为 true 时即使是非叶节点也保留梯度

slot 和 rank 的含义:一个算子可能有多个输出(slot),每个输出可能是 Tensor 列表(rank 区分列表内位置)。out_slot_id_out_rank_ 记录该 Tensor 是 GradNode 第几个输出 slot 的第几个 Tensor。

GradNodeBase

文件paddle/fluid/eager/grad_node_info.h

反向图中的节点基类,每个前向算子对应一个具体的 GradNode 子类(如 AddGradNodeMatmulGradNode)。

成员类型说明
bwd_in_meta_std::vector<std::vector<GradSlotMeta>>反向输入的 meta 信息(对应前向输出)
bwd_out_meta_std::vector<std::vector<GradSlotMeta>>反向输出的 meta 信息(对应前向输入),含 adj_edge_
gradient_hooks_std::map<int, GradientHookFunc>注册的梯度 hook 函数
default_attr_map_paddle::framework::AttributeMap前向算子的属性(如 axis、keepdim 等)

关键虚方法

方法说明
operator()(vector<vector<Tensor>>&)纯虚。执行反向计算,输入为上游梯度,输出为下游梯度
ClearTensorWrappers()清理保存的前向 Tensor(retain_graph=false 时调用)
Copy()复制节点(GeneralGrad 中使用)

注意 bwd_in/out 的命名方向

  • bwd_in_meta_ 对应反向计算的输入(即前向算子的输出的梯度)
  • bwd_out_meta_ 对应反向计算的输出(即前向算子的输入的梯度),其中的 adj_edge_ 连接后继节点

GradSlotMeta

文件paddle/fluid/eager/grad_node_info.h

描述 GradNode 某个 slot 的元信息,同时通过 adj_edge_ 建立反向图的边。

成员类型说明
stop_gradient_bool该 slot 是否停止梯度
place_phi::PlaceTensor 所在设备
meta_phi::DenseTensorMeta前向 Tensor 的 shape/dtype/layout 等 meta
adj_edge_Edge连接到后继 GradNode 的边

Edge

文件paddle/fluid/eager/grad_node_info.h

反向图中的有向边,从当前 GradNode 的某个输出 slot 指向后继 GradNode 的某个输入 slot。

成员类型说明
grad_node_std::shared_ptr<GradNodeBase>后继 GradNode
in_slot_id_size_t在后继 GradNode 中对应的输入 slot 索引
in_rank_size_t在该 slot 内的 rank 索引

Edge 的方向理解:反向图中,梯度从 loss 流向叶节点。Edge 描述的是梯度的流向——从当前节点的输出连接到下一个节点的输入。

TensorWrapper

文件paddle/fluid/eager/tensor_wrapper.h

GradNode 中用于保存前向 Tensor 的包装器。反向计算通常需要前向的输入或输出值(如 y = relu(x) 的反向需要 x)。

成员类型说明
intermediate_tensor_paddle::Tensor保存的前向 Tensor(拼写沿用代码中的 intermediate)
no_need_buffer_bool为 true 时只保存 meta 信息,不保存数据(节省内存)
weak_grad_node_std::weak_ptr<GradNodeBase>弱引用前向 Tensor 的 GradNode,防止循环引用
inplace_version_snapshot_uint32_t保存时的 inplace 版本号,recover() 时校验是否被修改
packed_value_std::shared_ptr<void>pack hook 打包后的值(用于内存优化,如 offload 到 CPU)
unpack_hook_std::shared_ptr<UnpackHookBase>packed_value_ 配合的 unpack 回调

关键方法

  • recover() — 从 intermediate_tensor_ 恢复出 paddle::Tensor,同时检查 inplace 版本一致性
  • packed_value_ 非空,通过 unpack_hook_ 解包而非直接使用 intermediate_tensor_

weak_ptr 防循环引用:若 TensorWrapper 直接持有 shared_ptr<GradNodeBase>,会形成 GradNode → TensorWrapper → Tensor → AutogradMeta → GradNode 的循环引用,导致内存泄漏。使用 weak_ptr 打破循环。

GradTensorHolder

文件paddle/fluid/eager/grad_tensor_holder.h

反向执行阶段,每个待执行的 GradNode 都有一个对应的 GradTensorHolder,用于接收和聚合来自多条路径的上游梯度。

成员类型说明
buffer_std::vector<std::vector<paddle::Tensor>>二维 Tensor 容器,buffer_[slot_id][rank]

关键方法

方法说明
add(slot, rank, tensor)梯度聚合:若 buffer_[slot][rank] 为空则赋值,否则执行 Tensor 加法累加
Buffers()返回 buffer_ 引用,传入 GradNode::operator()
SetBufferSlotRankZeros(slot, rank)将指定位置设为零 Tensor

聚合场景:当一个 Tensor 被多个算子使用时(如 y = x + x),反向时两条路径的梯度需要累加到同一个 GradTensorHolder 中。

数据结构间的关系图

phi::Tensor ──owns──→ AutogradMeta
                         │
                    ┌────┘ grad_node_ (shared_ptr)
                    ▼
              GradNodeBase (如 AddGradNode)
                    │
         ┌─────────┼──────────┐
         ▼         ▼          ▼
   bwd_in_meta_  bwd_out_meta_  TensorWrapper
   (输入meta)   (输出meta)       │
                    │            └─ intermediate_tensor_
                    ▼            └─ weak_grad_node_ ──weak──→ GradNodeBase
              GradSlotMeta
                    │
                    └─ adj_edge_ (Edge)
                         │
                         └─ grad_node_ ──shared_ptr──→ 后继 GradNodeBase

构建阶段创建上述结构,执行阶段 GradTensorHolder 沿边传递和聚合梯度。