tensorflow计算图的底层原理

要搞懂计算图的底层原理,核心是拆解它的 "三步走流程":构建图 → 优化图 → 执行图 。我们就用你之前的核心例子(a_regular_function 函数),一步步扒开底层到底做了什么------全程不脱离代码,每个底层操作都对应到具体函数逻辑。

先重申例子的核心运算(方便对照):

python 复制代码
def a_regular_function(x, y, b):
  x = tf.matmul(x, y)  # 运算1:矩阵乘法(x是2D张量,y是2D张量)
  x = x + b            # 运算2:加法(矩阵+标量,广播机制)
  return x

# 输入张量:x1(1×2)、y1(2×1)、b1(标量)
x1 = tf.constant([[1.0, 2.0]])
y1 = tf.constant([[2.0], [3.0]])
b1 = tf.constant(4.0)

一、先明确计算图的"底层组成单元"

计算图的本质是 "无状态的运算依赖图",底层由3个核心部分构成,对应例子拆解:

组成单元 通俗理解 例子中的具体对应
节点(Node) 一个"运算指令"(比如乘法、加法),是图的"操作单元" 2个节点:tf.matmul 节点、+ 节点
边(Edge) 节点间的"数据依赖",传递的是张量(Tensor) 3条边: 1. x1 → tf.matmul(输入边) 2. y1 → tf.matmul(输入边) 3. tf.matmul的输出 → +(中间边) 4. b1 → +(输入边) 5. +的输出 → 函数返回(输出边)
张量(Tensor) 边传递的数据(不可变),是图的"数据单元" 输入张量(x1、y1、b1)、中间张量(tf.matmul的结果)、输出张量(最终x)

简单说:计算图就是把"运算"和"数据依赖"用"节点-边"的结构固定下来,形成一份"不可修改的运算说明书"

二、计算图的底层三步骤(对应例子拆解)

当你调用 tf.function 包装后的函数时,底层会按以下三步执行(这就是"图执行"的核心):

第一步:构建图(Graph Construction)------ 扫描函数,画"运算说明书"

这一步的核心是:tf.function 不执行函数里的运算,只扫描其中的 TensorFlow 操作,记录"谁依赖谁",最终画出计算图

对应例子的构建过程:

  1. tf.function 会"读"a_regular_function 的代码,发现两个 TensorFlow 操作:tf.matmul+
  2. 分析依赖关系(谁必须在谁之前执行):
    • 要算 x + b,必须先拿到 tf.matmul(x, y) 的结果(因为 xtf.matmul 更新了);
    • 所以依赖顺序是:x1、y1 → tf.matmul → 中间结果 → +(b1) → 最终输出
  3. 按照这个依赖,创建计算图的节点和边:
    • 节点1:tf.matmul,标记输入为"x的占位、y的占位",输出为"中间矩阵";
    • 节点2:+,标记输入为"中间矩阵、b的占位",输出为"最终矩阵";
    • 边:连接 tf.matmul 的输出 → + 的输入,形成完整流程;
  4. 注意:这一步完全不做任何数值计算 !比如 tf.matmul(x1, y1) 不会真的算出 [[1*2 + 2*3]] = [[8.0]],只是记录"要做这个乘法",以及它的输入输出是什么。

关键细节:第一次调用 a_function_that_uses_a_graph(x1, y1, b1) 时,会触发这个"构建图"的过程(所以第一次调用稍慢,叫"热身");之后再调用时,会直接复用已构建好的图,不再重新扫描函数。

第二步:优化图(Graph Optimization)------ 给"运算说明书"瘦身提速

这是计算图的核心优势之一!TensorFlow 有一个专门的"优化器"(Graph Optimizer),会对第一步构建的原始图做"等价变形",目的是 减少运算次数、降低内存开销、适配硬件(CPU/GPU/TPU)

对应例子的优化过程(底层会做这些操作):

  1. 常量折叠(Constant Folding)
    • 例子中 y1[[2.0], [3.0]])和 b14.0)是常量张量,优化器会提前计算"常量相关的固定逻辑"------比如知道 y1 是固定的2×1矩阵,会在图中直接记录它的形状,避免执行时再解析;
    • 极端情况:如果 x 也是常量,优化器会直接把 tf.matmul(x, y) + b 的结果算出来,图中只剩下一个"输出常量"的节点(彻底省去运算)。
  2. 运算融合(Operator Fusing)
    • 原始图是"matmul → +"两个独立节点,优化器会把它们融合成一个"matmul + add"的复合节点;
    • 好处:减少节点间的张量传递开销(不用先把 matmul 的结果存到内存,再读出来做加法),GPU 执行时能一次性完成,速度更快。
  3. 形状推断(Shape Inference)
    • 优化器会提前推断所有张量的形状:x1(1×2) × y1(2×1) → 中间结果(1×1),再加上 b1(标量,广播成1×1),最终输出(1×1);
    • 好处:执行时不用再检查张量形状是否匹配,避免运行时错误,同时让硬件提前分配内存。

优化后的图,本质还是"做 matmul + add",但流程更精简、执行效率更高------这就是"图执行"比"即时执行"快的核心原因。

第三步:执行图(Graph Execution)------ 按优化后的"说明书"算结果

这一步才是真正做数值计算的阶段,底层流程是:

  1. 把输入张量(x1、y1、b1)"喂"给优化后的图的"输入占位"(对应第一步构建图时的"x占位、y占位、b占位");
  2. 硬件(CPU/GPU)按图的节点顺序(优化后的顺序,比如融合后的"matmul+add"节点)执行运算:
    • 先算 x1 × y1 = [[1*2 + 2*3]] = [[8.0]](matmul 部分);
    • 再算 8.0 + 4.0 = 12.0(add 部分);
  3. 把最终结果([[12.0]])从图的"输出边"返回。

关键对比:即时执行(普通函数)是"逐行解析→执行→解析→执行",每次调用都要重复解析和执行;而图执行是"一次构建+优化,多次复用执行" ------后续再调用 a_function_that_uses_a_graph(x2, y2, b2) 时,直接跳过第一步和第二步,只用把新的 x2、y2、b2 喂给已优化的图,直接执行第三步,速度极快。

三、用"对比表"看清底层差异(普通函数 vs tf.function)

为了让你更直观理解"底层做了什么",我们对比普通函数(即时执行)和 tf.function(图执行)的底层流程:

执行步骤 普通函数(a_regular_function) tf.function 包装后的函数(图执行)
每次调用时 1. 解析 tf.matmul(x, y) → 执行 → 得到结果; 2. 解析 x + b → 执行 → 得到结果; 3. 返回结果。 1. 第一次调用: - 扫描函数 → 构建图; - 优化图; - 执行图 → 返回结果; 2. 后续调用: - 直接复用优化后的图 → 执行 → 返回结果。
底层核心 无图,"边解析边执行",无优化 有图,"一次构建优化,多次执行",有多层优化
速度关键 每次都要解析操作,速度慢(尤其调用次数多) 复用图,跳过解析和优化,速度快(模型越大、调用越多,优势越明显)

四、总结:计算图的底层原理一句话概括

tf.function 包装函数后,底层会先 "扫描函数里的 TensorFlow 操作,按依赖关系构建原始计算图" ,再通过优化器 "给图瘦身提速(常量折叠、运算融合等)" ,最后 "用输入张量喂给优化后的图,执行运算并返回结果"------后续调用直接复用优化图,省去重复构建和解析的开销,这就是计算图的核心原理。

相关推荐
NAGNIP9 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab10 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab10 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP14 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年14 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼14 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS15 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区16 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈16 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang16 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx