TensorFlow/执行子图裁剪

从输出反向裁剪不参与本次执行的计算节点

TensorFlow 从本次请求的输出和目标操作出发,沿输入边做 BFS,只保留这些目标依赖的计算节点。

b305c24ad图处理与编译核验 2026-10-12
相关概念

工程问题#

一个计算图可能同时包含训练、评估和多个输出。本次只请求部分输出时,保留全部节点会把无关计算带入后续执行图;有副作用的目标操作又不能仅按输出张量判断。

实际实现#

子图重写先接入 feed、fetch,再把 fetch 节点和显式 target 合并为起点。PruneForReverseReachability 使用双端队列沿 in_nodes 扩展,在入队时标记节点;随后删除未访问的普通节点,并重新连接 source/sink 边。

处理流程#

  1. 重写本次 feed 与 fetch,并收集显式 target 操作
  2. 将目标集合入队并标记,沿输入边访问所有前驱
  3. 删除未标记的普通节点,保留内部 source/sink
  4. 修复 source/sink 控制边,交给后续执行图处理

源码片段#

固定版本 · 原文摘录
tensorflow/core/graph/subgraph.ccb305c24ad52cb249d4789a3377282257915d225c · L389–L401
查看原文件
389  // Add the fetch nodes, also updating "name_index".390  std::vector<Node*> fetch_nodes;391  if (!fetch_rewrites.empty()) {392    TF_RETURN_IF_ERROR(FetchOutputs(g, fetch_rewrites, &name_index,393                                    &fetch_nodes, &out_metadata->fetch_types));394  }395396  // Prune the graph to only compute what is needed for the fetch nodes and the397  // target nodes.398  if (!fetch_nodes.empty() || !target_node_names.empty()) {399    TF_RETURN_IF_ERROR(400        PruneForTargets(g, name_index, fetch_nodes, target_node_names));401  }
RewriteGraphForExecution / PruneForTargets

先添加 fetch 节点,再按 fetch 与 target 裁剪。本次执行子图的根来自请求,不是随意选择一个计算节点。

tensorflow/core/graph/subgraph.ccb305c24ad52cb249d4789a3377282257915d225c · L199–L217
查看原文件
199  std::unordered_set<const Node*> targets;200  for (Node* n : fetch_nodes) {201    if (!AddNodeToTargets(n->name(), name_index, &targets)) {202      absl::StrAppend(&not_found, n->name(), " ");203    }204  }205  for (const std::string& s : target_nodes) {206    if (!AddNodeToTargets(s, name_index, &targets)) {207      absl::StrAppend(&not_found, s, " ");208    }209  }210  if (!not_found.empty()) {211    return absl::NotFoundError(absl::StrCat(212        "PruneForTargets: Some target nodes not found: ", not_found));213  }214  PruneForReverseReachability(g, std::move(targets));215216  // Reconnect nodes with no outgoing edges to the sink node217  FixupSourceAndSinkEdges(g);
PruneForTargets

将输出和显式目标合为起点,核对名字有效后调用反向可达裁剪,最后修复特殊边。

tensorflow/core/graph/algorithm.ccb305c24ad52cb249d4789a3377282257915d225c · L224–L239
查看原文件
224  std::vector<bool> visited(g->num_node_ids());225  for (auto node : start) {226    visited[node->id()] = true;227  }228  std::deque<const Node*> queue(start.begin(), start.end());229  while (!queue.empty()) {230    const Node* n = queue.front();231    queue.pop_front();232    for (const Node* in : n->in_nodes()) {233      if (!visited[in->id()]) {234        visited[in->id()] = true;235        queue.push_back(in);236        VLOG(2) << "Reverse reach : " << n->name() << " from " << in->name();237      }238    }239  }
PruneForReverseReachability:BFS

visited 在入队前置位,共享前驱不会重复入队;遍历方向是输入节点,因此求的是目标的依赖闭包。

tensorflow/core/graph/algorithm.ccb305c24ad52cb249d4789a3377282257915d225c · L241–L253
查看原文件
241  // Make a pass over the graph to remove nodes not in "visited".242  bool any_removed = false;243  for (int i = 0; i < visited.size(); ++i) {244    if (!visited[i]) {245      Node* n = g->FindNodeId(i);246      if (n != nullptr && !n->IsSource() && !n->IsSink()) {247        g->RemoveNode(n);248        any_removed = true;249      }250    }251  }252  return any_removed;253}
PruneForReverseReachability:删除

删除所有未访问的普通节点,但保留内部 source 与 sink;不是只过滤最终输出列表。

片段保持固定提交的连续原文;完整源码与许可证保存在本地。每段说明交代所在分支,省略部分可通过出处查看。

收益与取舍#

工程分析

带来的收益

  • 保留集合直接对应目标节点的依赖闭包,支持共享前驱和有环图
  • 每条可达输入边只需检查一次;在标记数组初始化与全图删除扫描之外,遍历为 O(Vr + Er)

付出的代价

  • 标记数组按 num_node_ids 分配,删除扫描也按节点编号空间进行,不能把总成本只算在可达节点上
  • 裁剪依据图中的依赖和显式目标;遗漏副作用操作的 target 或控制依赖不会被算法自动补回

可比较的选择

反向 DFS也能求依赖闭包;需要栈而非队列,本题并不需要 BFS 的最短距离性质。

保留完整图省去裁剪分析,但失去按本次请求缩小执行子图的机会。

版本与适用范围#

对应固定提交的 tensorflow/core/graph 子图重写路径。它求反向可达集合,不执行拓扑排序,也不代表 eager 模式或 Grappler 的所有裁剪实现。

参考来源#

源码、官方文档与原始论文
01
TensorFlow · RewriteGraphForExecution / PruneForTargets

tensorflow/core/graph/subgraph.cc · RewriteGraphForExecution / PruneForTargets

源码b305c24ad52cb249d4789a3377282257915d225c
02
TensorFlow · PruneForReverseReachability:BFS

tensorflow/core/graph/algorithm.cc · PruneForReverseReachability:BFS

源码b305c24ad52cb249d4789a3377282257915d225c
03
TensorFlow · GraphExecutionState::PruneGraph

tensorflow/core/common_runtime/graph_execution_state.cc · GraphExecutionState::PruneGraph

源码b305c24ad52cb249d4789a3377282257915d225c

相关实现与比较#

4 个相关案例
9 个匹配案例