TensorFlow 基础训练循环(简化版+补全代码)
这份指南会把 TensorFlow 基础训练循环的核心步骤拆解开,用通俗的语言解释,同时补全原文中残缺的代码,所有例子和逻辑都和官方一致,确保你能跟着跑通、看懂。
核心思路
机器学习解决问题的核心步骤(原文核心流程):
- 准备训练数据(输入x和标签y);
- 定义模型(要学习的函数,比如线性模型y = x*W + b);
- 定义损失函数(衡量模型预测有多不准);
- 训练循环:用数据喂模型→算损失→调参数→重复;
- 评估结果(看模型学得怎么样)。
我们全程围绕「简单线性回归」展开------已知x和y,找到最合适的权重W和偏置b,让模型预测值接近真实值。
第一步:环境准备(直接复制运行)
python
import tensorflow as tf
import matplotlib.pyplot as plt
# 用来设置绘图颜色(原文自带,保持一致)
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
第二步:生成训练数据(模拟真实数据)
我们生成一条带噪音的直线数据,真实规律是 y = 3*x + 2(TRUE_W=3.0是斜率,TRUE_B=2.0是截距)。
python
# 真实的模型参数(我们要让模型学到这个值)
TRUE_W = 3.0
TRUE_B = 2.0
NUM_EXAMPLES = 201 # 201个数据点
# 生成x:从-2到2的均匀分布(共201个点)
x = tf.linspace(-2, 2, NUM_EXAMPLES)
x = tf.cast(x, tf.float32) # 转换为float32类型
# 真实的函数:y = 3x + 2
def f(x):
return x * TRUE_W + TRUE_B
# 给真实值加噪音(模拟现实中的数据误差)
noise = tf.random.normal(shape=[NUM_EXAMPLES]) # 正态分布噪音
y = f(x) + noise # 最终的训练标签y
# 可视化数据(看一眼生成的点)
plt.plot(x, y, '.', label="带噪音的训练数据")
plt.plot(x, f(x), 'r-', label="真实直线(y=3x+2)") # 真实规律
plt.legend()
plt.show()
运行后会看到:蓝色点是带噪音的训练数据,红色线是真实规律,我们的目标就是让模型学到这条红色线。
第三步:定义模型(用tf.Module封装参数)
模型是 y = x*w + b,用tf.Module封装权重w和偏置b(方便管理参数、后续保存)。
python
class MyModel(tf.Module):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# 初始化参数(w=5.0,b=0.0,原文固定初始化,实际中常用随机初始化)
self.w = tf.Variable(5.0) # 权重(要学习的参数)
self.b = tf.Variable(0.0) # 偏置(要学习的参数)
# 模型的计算逻辑:输入x,输出预测值y_pred = w*x + b
def __call__(self, x):
return self.w * x + self.b
# 创建模型实例
model = MyModel()
# 查看模型参数(tf.Module自动收集变量)
print("初始模型参数:", model.variables) # 输出:[w=5.0, b=0.0]
# 验证模型能正常运行(输入3.0,输出5.0*3.0+0.0=15.0)
assert model(3.0).numpy() == 15.0, "模型计算错误"
print("模型初始化验证通过!")
第四步:定义损失函数(衡量模型有多不准)
用「均方误差(MSE)」------计算预测值和真实值的平方差的平均值,值越小说明模型越准。
python
def loss(target_y, predicted_y):
# target_y:真实标签y;predicted_y:模型预测值
return tf.reduce_mean(tf.square(target_y - predicted_y)) # 平方差→求平均
训练前先看一眼初始模型的效果
python
# 绘制初始模型的预测结果
plt.plot(x, y, '.', label="带噪音的训练数据")
plt.plot(x, f(x), 'r-', label="真实直线(y=3x+2)")
plt.plot(x, model(x), 'g--', label="初始模型预测(w=5.0, b=0.0)")
plt.legend()
plt.show()
# 计算初始损失
initial_loss = loss(y, model(x)).numpy()
print(f"训练前的损失:{initial_loss:.6f}") # 初始损失会很大,因为参数不对
运行后会看到:绿色虚线是初始模型的预测,和红色真实线差很远,损失值也会比较大(大概几十)。
第五步:定义训练循环(核心!调参过程)
训练的本质是「用梯度下降调整参数w和b」,步骤:
- 用模型预测→算损失;
- 用梯度带(GradientTape)算损失对w、b的梯度;
- 按梯度调整参数(w和b往损失减小的方向变)。
补全原文残缺的训练函数
python
# 1. 单个训练步骤(更新一次参数)
def train(model, x, y, learning_rate):
# 开启梯度带:自动记录运算,方便后续求梯度
with tf.GradientTape() as t:
current_loss = loss(y, model(x)) # 计算当前损失
# 计算损失对w和b的梯度(dw:损失对w的导数,db:损失对b的导数)
dw, db = t.gradient(current_loss, [model.w, model.b])
# 调整参数:w = w - 学习率*dw(往损失减小的方向更更新)
model.w.assign_sub(learning_rate * dw) # assign_sub:自减操作
model.b.assign_sub(learning_rate * db)
# 2. 报告函数(打印每轮训练的参数和损失)
def report(model, current_loss):
return f"W = {model.w.numpy():1.2f}, b = {model.b.numpy():1.2f}, 损失={current_loss:2.5f}"
# 3. 完整训练循环(补全原文残缺的循环逻辑)
def training_loop(model, x, y, epochs=10, learning_rate=0.1):
# 记录参数变化(方便后续绘图)
weights_history = []
biases_history = []
for epoch in range(epochs):
# 执行一次训练(更新参数)
train(model, x, y, learning_rate)
# 记录当前参数
weights_history.append(model.w.numpy())
biases_history.append(model.b.numpy())
# 计算更新后的损失
current_loss = loss(y, model(x))
# 打印每轮结果
print(f"第 {epoch:2d} 轮:", report(model, current_loss))
return weights_history, biases_history
第六步:执行训练
python
# 重新创建模型(避免之前的参数影响,从零开始训练)
model = MyModel()
# 训练前的初始状态
initial_loss = loss(y, model(x)).numpy()
print("训练开始前:")
print(" ", report(model, initial_loss))
# 开始训练(10轮,学习率0.1)
weights_history, biases_history = training_loop(model, x, y, epochs=10, learning_rate=0.1)
运行后会看到:每轮训练后,w会逐渐接近3.0,b逐渐接近2.0,损失会越来越小(最后会降到1左右,因为有噪音)。
第七步:可视化训练过程(看参数怎么变化)
python
# 绘制w和b的变化趋势
epochs = range(10)
plt.plot(epochs, weights_history, 'b-', label='模型学到的w', color=colors[0])
plt.plot(epochs, [TRUE_W]*len(epochs), 'b--', label='真实w=3.0', color=colors[0])
plt.plot(epochs, biases_history, 'g-', label='模型学到的b', color=colors[1])
plt.plot(epochs, [TRUE_B]*len(epochs), 'g--', label='真实b=2.0', color=colors[1])
plt.xlabel('训练轮数')
plt.ylabel('参数值')
plt.legend()
plt.show()
# 绘制最终模型的预测效果
plt.plot(x, y, '.', label="带噪音的训练数据")
plt.plot(x, f(x), 'r-', label="真实直线(y=3x+2)")
plt.plot(x, model(x), 'g-', label="训练后模型预测")
plt.legend()
plt.show()
# 打印最终损失
final_loss = loss(y, model(x)).numpy()
print(f"\n训练后的最终损失:{final_loss:.6f}")
运行后会看到:
- 第一个图:模型的w和b逐渐逼近真实值(3.0和2.0);
- 第二个图:训练后的绿色线和红色真实线几乎重合,损失值大幅下降。
第八步:用Keras实现同样的模型(原文对比版)
Keras是TensorFlow的高层API,封装了训练循环,不用手动写梯度下降,更简洁。
补全原文Keras代码
python
# 1. 定义Keras模型(继承tf.keras.Model,本质还是tf.Module)
class MyModelKeras(tf.keras.Model):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# 初始化参数(和之前的手动模型一致)
self.w = tf.Variable(5.0)
self.b = tf.Variable(0.0)
# 计算逻辑(和手动模型一致)
def call(self, x):
return self.w * x + self.b
# 2. 方式1:复用之前的手动训练循环(Keras模型兼容手动训练)
print("=== 用手动训练循环训练Keras模型 ===")
keras_model1 = MyModelKeras()
initial_loss_keras = loss(y, keras_model1(x)).numpy()
print("训练前:", report(keras_model1, initial_loss_keras))
training_loop(keras_model1, x, y, epochs=10, learning_rate=0.1)
# 保存Keras模型权重(原文提到的功能)
keras_model1.save_weights("my_keras_checkpoint")
print("\nKeras模型权重已保存!")
# 3. 方式2:用Keras内置的fit()训练(不用写循环,更方便)
print("\n=== 用Keras内置fit()训练 ===")
keras_model2 = MyModelKeras()
# 编译模型:指定优化器、损失函数(Keras内置,不用手动写)
keras_model2.compile(
run_eagerly=False, # 开启图执行(默认开启,更快)
optimizer=tf.keras.optimizers.SGD(learning_rate=0.1), # 随机梯度下降(和手动一致)
loss=tf.keras.losses.mean_squared_error # 均方误差(和手动loss一致)
)
# 开始训练:fit(输入x, 标签y, 训练轮数, 批次大小)
# 批次大小设为201(和数据总数一致),和手动循环的"全量数据训练"一致
keras_model2.fit(x, y, epochs=10, batch_size=NUM_EXAMPLES)
# 验证Keras模型效果
final_loss_keras = loss(y, keras_model2(x)).numpy()
print(f"Keras内置fit训练后的损失:{final_loss_keras:.6f}")
Keras实现的核心区别
- 不用手动写梯度带和参数更新,
compile()指定优化器和损失,fit()自动完成训练; - 结果和手动实现几乎一致,只是Keras会打印更规范的训练日志;
- 支持直接保存权重(
save_weights()),后续可以加载继续训练。
核心知识点总结(不遗漏原文关键信息)
- tf.Module:封装模型参数和计算,方便管理变量、保存模型;
- tf.Variable:可训练的参数(w和b),梯度会自动追踪;
- GradientTape:自动记录运算,计算梯度(反向传播的核心工具);
- 梯度下降:通过调整参数(w = w - 学习率*dw)减小损失;
- Keras兼容性:Keras模型(tf.keras.Model)继承自tf.Module,既可以手动写循环训练,也可以用内置fit()快速训练;
- 批次训练:原文提到"数据通常按批次训练",本例用全量数据(batch_size=201),实际中常用32/64批次大小。
运行建议
- 按步骤复制代码,逐块运行(先跑数据生成,再跑模型定义,最后训练);
- 观察每一步的输出和图表,理解"参数怎么逼近真实值""损失怎么减小";
- 可以修改学习率(比如0.05或0.2)或训练轮数(比如20轮),看对训练效果的影响。
要不要我帮你整理一份完整可直接运行的代码文件?包含所有步骤,复制到Python环境就能跑通,还会标注关键注释。