35 TensorFlow 基础与自动微分机制

一、核心目标

  通过一个简单的二次损失函数优化问题,演示 TensorFlow 程序的基本结构,并揭示其如何自动完成:

  • 前向计算(定义损失函数)
  • 反向传播(自动求导)
  • 参数更新(优化器)

  从而为训练复杂神经网络打下基础。


二、示例问题:最小化一个二次损失函数

  给定损失函数:

$$
J(w) = w^2 - 10w + 25 = (w - 5)^2
$$

  显然,当 $w = 5$ 时,$J(w)$ 取得最小值 0。

💡 关键思想:即使我们不知道解析解,也可以用 TensorFlow 自动通过梯度下降找到最优 $w$。


三、TensorFlow 程序基本结构(TF 1.x 风格)

⚠️ 注意:本课程使用的是 TensorFlow 1.x 的静态图(Session + Placeholder)模式,与 TF 2.x 的 Eager Execution 不同,但原理相通。

1. 导入库

import numpy as np
import tensorflow as tf

2. 定义可训练参数(变量)

w = tf.Variable(0.0, dtype=tf.float32)
  • tf.Variable​ 表示需要被优化的参数(如神经网络权重)。
  • 初始值设为 0。

3. 定义损失函数(前向计算)

  两种写法等价:

  写法一(显式调用 TF 操作)

cost = tf.add(tf.add(w**2, tf.multiply(-10.0, w)), 25.0)

  写法二(运算符重载,更简洁)

cost = w**2 - 10.0 * w + 25.0

✅ TensorFlow 对 +​, -​, *​, ** 等运算符进行了重载,使代码更接近数学表达。

4. 定义优化器与训练操作

train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)
  • 学习率 $\alpha = 0.01$

  • minimize(cost) 自动:

    • cost​ 关于所有 tf.Variable 求梯度
    • 执行参数更新:$w := w - \alpha \cdot \frac{\partial J}{\partial w}$

5. 初始化与执行(Session 机制)

init = tf.global_variables_initializer()
with tf.Session() as session: # 推荐使用 with 结构,自动管理资源
session.run(init)
print("初始 w =", session.run(w)) # 输出: 0.0

# 执行一次梯度下降
session.run(train)
print("一步后 w =", session.run(w)) # 输出: 0.1

# 执行 1000 次迭代
for _ in range(1000):
session.run(train)
print("1000 步后 w =", session.run(w)) # 输出 ≈ 4.99999

🔁 关键点session.run(train) 才真正触发一次优化步骤。


四、引入训练数据:使用 tf.placeholder

  现实中的损失函数依赖于训练数据(如 $x, y$)。TensorFlow 使用 placeholder 占位符来表示“稍后输入的数据”。

1. 定义占位符

x = tf.placeholder(tf.float32, [3, 1])  # 形状为 (3,1) 的输入数据

2. 将损失函数参数化

  将原损失函数的系数(1, -10, 25)替换为来自 x 的数据:

$$
J(w; x) = x[0][0] \cdot w^2 + x[1][0] \cdot w + x[2][0]
$$

  对应代码:

cost = x[0][0] * w**2 + x[1][0] * w + x[2][0]

3. 准备实际数据并“喂入”(feed)

coefficients = np.array([[1.], [-10.], [25.]])  # 对应 (w-5)^2
# 或改为 [[1.], [-20.], [100.]] 对应 (w-10)^2

# 在 run 时通过 feed_dict 传入
session.run(train, feed_dict={x: coefficients})

🧠 核心机制feed_dict 允许在每次运行时动态传入不同的 mini-batch 数据,这是训练神经网络的关键。


五、TensorFlow 的核心优势:自动微分与计算图

1. 计算图(Computation Graph)

  • 当你写 cost = w**2 - 10*w + 25​ 时,TensorFlow 并不立即计算数值,而是构建一个符号计算图
  • 图中节点表示操作(如平方、乘法、加法),边表示数据流。

2. 自动微分(Automatic Differentiation)

  • TensorFlow 内置了所有基本操作(add​, multiply​, pow​ 等)的反向传播规则(梯度函数)

  • 调用 minimize() 时,系统自动:

    • cost 节点反向遍历计算图
    • 应用链式法则计算 $\frac{\partial J}{\partial w}$
    • 更新 w

你只需定义前向传播,反向传播全自动完成!

3. 优化器灵活切换

  只需修改一行代码即可更换优化算法:

# 梯度下降
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)

# Adam 优化器(通常更快更稳)
train = tf.train.AdamOptimizer(0.01).minimize(cost)

六、编程习惯与最佳实践

写法 说明
with tf.Session() as sess: 推荐:自动关闭 Session,避免资源泄漏
tf.global_variables_initializer() 必须显式初始化所有 Variable
使用 feed_dict 传入数据 适用于 placeholder,支持 mini-batch

七、总结:TensorFlow 编程范式(TF 1.x)

  1. 定义变量tf.Variable)→ 可训练参数
  2. 定义占位符tf.placeholder)→ 输入数据
  3. 构建计算图(用 TF 操作定义损失函数)
  4. 选择优化器.minimize(loss)
  5. 启动 Session,初始化变量
  6. 循环执行session.run(train_op, feed_dict={...})

这一范式可无缝扩展到深层神经网络:只需将 cost 替换为复杂的网络输出 + 损失函数(如交叉熵),其余结构几乎不变。


八、延伸思考(现代 TF 2.x 对比)

  虽然本课程使用 TF 1.x,但 TF 2.x 默认启用 Eager Execution,无需 Session 和 Placeholder,代码更像普通 Python:

import tensorflow as tf

w = tf.Variable(0.0)
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

for _ in range(1000):
with tf.GradientTape() as tape:
cost = w**2 - 10*w + 25
grads = tape.gradient(cost, [w])
optimizer.apply_gradients(zip(grads, [w]))

  但自动微分的核心思想完全一致:你定义前向,框架处理反向。


✅ 学习要点回顾

概念 说明
tf.Variable 表示模型参数,会被优化器更新
tf.placeholder 表示外部输入数据(TF 1.x)
feed_dict 向 placeholder 传入实际数据
计算图 符号化表示计算流程,支持自动求导
自动微分 框架自动计算梯度,无需手动推导
优化器 一行代码切换 GD / Adam / RMSProp 等
Session TF 1.x 中执行计算的上下文环境