第6章:TensorFlow/Keras 实现与训练 | Chapter 6: TensorFlow/Keras Implementation
阶段定位 | Stage: 第二阶段 — 神经网络与进阶算法 预计学时 | Duration: 3~4 小时
---
学习目标 | Learning Objectives
中文:
- 掌握 Keras Sequential API 的基本用法
- 理解
model.compile中 optimizer、loss、metrics 的含义 - 能对比 NumPy 手写与框架实现的效率差异
- 理解
model.fit返回的 history 对象及其可视化 - 掌握模型保存/加载和基本推理流程
English:
- Master basic Keras Sequential API usage
- Understand optimizer, loss, and metrics in
model.compile - Compare efficiency between NumPy from-scratch and framework implementation
- Understand the history object from
model.fitand its visualization - Master model save/load and basic inference pipeline
---
6.1 框架 vs 手写 | Framework vs From-Scratch
中文解释
为什么需要框架?
| 方面 | NumPy 手写 | TensorFlow/PyTorch |
|---|---|---|
| 自动求导 | 手动推导 + 实现 | 自动微分(Autograd) |
| GPU 加速 | 不支持 | 原生支持 CUDA |
| 工程化 | 自己管理维度、保存、部署 | 内置模型保存、Serving、量化 |
| 调试 | 容易 | 需要学习工具(TensorBoard) |
| 学习价值 | 极高(理解原理) | 高(工程实践) |
学习路径建议
NumPy 手写 → TensorFlow/Keras 快速验证 → PyTorch 研究/生产- 手写:理解梯度、维度、前向/反向传播
- Keras:快速搭建、调参、验证想法
- PyTorch:动态图、自定义研究、工业部署
English Explanation
Why use frameworks?
- Automatic differentiation (no manual gradient derivation)
- Native GPU acceleration (CUDA)
- Built-in model saving, serving, quantization
- Production-ready tooling
Learning path:
NumPy (understand principles) → Keras (rapid prototyping) → PyTorch (research/production)---
6.2 Keras 核心 API | Keras Core API
中文解释
Sequential 模型
最简单的模型类型:层按顺序堆叠。
python
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
model = Sequential([
Dense(25, activation='relu', input_shape=(20,)),
Dense(15, activation='relu'),
Dense(1, activation='sigmoid')
])层参数解析
| 参数 | 含义 |
|---|---|
units | 神经元数量 = 输出维度 |
activation | 激活函数:relu, sigmoid, tanh, softmax |
input_shape | 第一层必需:输入特征的维度 |
name | 层的名称(可选,调试有用) |
编译模型
python
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)| 参数 | 选项 | 适用场景 |
|---|---|---|
optimizer | 'sgd', 'adam', 'rmsprop', 'adamw' | 默认 Adam;大规模 CV 用 SGD+Momentum |
loss | 'mse', 'binary_crossentropy', 'categorical_crossentropy' | 回归/二分类/多分类 |
metrics | 'accuracy', 'precision', 'recall', 'auc' | 监控指标 |
训练模型
python
history = model.fit(
X_train, y_train,
epochs=20,
batch_size=32,
validation_split=0.1,
verbose=1
)| 参数 | 含义 |
|---|---|
epochs | 遍历完整训练集的次数 |
batch_size | 每步更新的样本数 |
validation_split | 从训练集中划出多少比例做验证 |
verbose | 0=静默, 1=进度条, 2=每 epoch 一行 |
English Explanation
Model Compilation:
python
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])Training:
python
history = model.fit(X_train, y_train, epochs=20, batch_size=32, validation_split=0.1)---
6.3 完整实现:Keras 神经网络训练
代码案例
python
import numpy as np
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
np.random.seed(42)
tf.random.set_seed(42)
# ========== 1. 生成数据 ==========
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2,
n_informative=15, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"训练集: {X_train.shape}, 测试集: {X_test.shape}")
# ========== 2. 构建模型 ==========
model = Sequential([
Dense(25, activation='relu', input_shape=(20,), name='hidden1'),
Dense(15, activation='relu', name='hidden2'),
Dense(1, activation='sigmoid', name='output')
])
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
print("\n模型结构:")
model.summary()
# 计算总参数量
print(f"\n总参数量: {model.count_params()}")
print("对比 NumPy 手写:你需要手动管理 W1(25×20), b1(25), W2(15×25), b2(15), W3(1×15), b3(1)")
# ========== 3. 训练 ==========
print("\n开始训练...")
history = model.fit(
X_train, y_train,
epochs=20,
batch_size=32,
validation_split=0.1,
verbose=0
)
# ========== 4. 评估 ==========
loss, acc = model.evaluate(X_test, y_test, verbose=0)
print(f"\n测试集 Loss: {loss:.4f}")
print(f"测试集准确率: {acc:.4f}")
# ========== 5. 训练过程可视化 ==========
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# 损失曲线
axes[0].plot(history.history['loss'], label='Train Loss')
axes[0].plot(history.history['val_loss'], label='Val Loss')
axes[0].set_xlabel('Epoch')
axes[0].set_ylabel('Loss')
axes[0].set_title('Loss Curve')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# 准确率曲线
axes[1].plot(history.history['accuracy'], label='Train Acc')
axes[1].plot(history.history['val_accuracy'], label='Val Acc')
axes[1].set_xlabel('Epoch')
axes[1].set_ylabel('Accuracy')
axes[1].set_title('Accuracy Curve')
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('ch06_training_history.png')
print("\n训练历史已保存到 ch06_training_history.png")
# ========== 6. 单样本推理 ==========
sample = X_test[0:1]
pred_prob = model.predict(sample, verbose=0)[0, 0]
pred_class = 1 if pred_prob >= 0.5 else 0
print(f"\n单样本推理:")
print(f" 预测概率: {pred_prob:.4f}")
print(f" 预测类别: {pred_class}")
print(f" 真实类别: {y_test[0]}")
# ========== 7. 模型保存与加载 ==========
model.save('ch06_model.keras')
print("\n模型已保存到 ch06_model.keras")
# 加载
loaded_model = tf.keras.models.load_model('ch06_model.keras')
loaded_pred = loaded_model.predict(sample, verbose=0)[0, 0]
print(f"加载后预测概率: {loaded_pred:.4f} (应与保存前一致)")典型输出:
模型结构:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
hidden1 (Dense) (None, 25) 525
hidden2 (Dense) (None, 15) 390
output (Dense) (None, 1) 16
=================================================================
Total params: 931
Trainable params: 931
测试集 Loss: 0.2345
测试集准确率: 0.9100
单样本推理:
预测概率: 0.8765
预测类别: 1
真实类别: 1---
6.4 训练诊断:History 对象 | Training Diagnostics
中文解释
model.fit 返回的 history 包含每 epoch 的所有指标:
python
history.history = {
'loss': [0.69, 0.45, 0.32, ...], # 训练损失
'accuracy': [0.52, 0.78, 0.85, ...], # 训练准确率
'val_loss': [0.70, 0.48, 0.35, ...], # 验证损失
'val_accuracy': [0.51, 0.75, 0.83, ...] # 验证准确率
}四种典型曲线:
| 训练损失 | 验证损失 | 诊断 | 对策 |
|---|---|---|---|
| 下降 | 下降 | 正常训练 | 继续 |
| 下降 | 上升 | 过拟合 | 早停、正则化、更多数据 |
| 持平 | 持平 | 欠拟合 | 增大模型、训练更久、调学习率 |
| 震荡 | 震荡 | 学习率太大 | 减小学习率 |
早停(Early Stopping)
监控验证损失,连续 N 个 epoch 不下降就停止训练:
python
from tensorflow.keras.callbacks import EarlyStopping
early_stop = EarlyStopping(
monitor='val_loss',
patience=5, # 连续 5 个 epoch 不改善就停
restore_best_weights=True # 恢复最优权重
)
model.fit(..., callbacks=[early_stop])English Explanation
Four typical curve patterns:
- Train↓ Val↓ → normal, continue
- Train↓ Val↑ → overfitting, early stopping / regularization
- Train→ Val→ → underfitting, bigger model / longer training
- Train~ Val~ → learning rate too high, decrease LR
---
6.5 常见误区 | Common Pitfalls
1. 在测试集上调参
错误: 用测试集准确率来选择模型、调整超参数。 正确: 只用验证集调参,测试集仅在最终评估时使用一次。
2. 忽视数据预处理
Keras 不会自动做特征缩放。如果输入特征尺度差异大,训练会极慢或不收敛。务必先标准化:
python
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test) # 用训练集的 scaler!3. Batch Size 与 GPU 内存
Batch size 不是越小越好。在 GPU 上,batch size 太小(如 1, 2)会导致 GPU 利用率极低,训练反而更慢。通常 32, 64, 128 是甜点。
---
本章总结 | Chapter Summary
中文:
- Keras Sequential 是最简单的模型构建方式
compile配置优化器、损失函数、监控指标fit返回 history,包含训练和验证的完整历史- 通过 loss/accuracy 曲线诊断:过拟合、欠拟合、学习率问题
- Early Stopping 是防止过拟合的实用技巧
- 数据预处理(缩放)在框架中不会自动完成,必须手动处理
English:
- Keras Sequential is the simplest model building API
compileconfigures optimizer, loss, and metricsfitreturns history with complete training/validation records- Diagnose via curves: overfitting, underfitting, learning rate issues
- Early Stopping prevents overfitting practically
- Data preprocessing (scaling) is not automatic — must be done manually
---
课后练习 | Homework
- 框架对比:用相同数据,分别用 Keras 和 PyTorch 训练一个两层网络。对比代码量、训练速度、最终准确率。
- 学习率实验:在 Keras 中使用
Adam(learning_rate=...),分别尝试 0.1, 0.01, 0.001, 0.0001。画出四条验证损失曲线。
- 早停调参:用
EarlyStopping,分别尝试patience=3, 5, 10。观察对最终测试集准确率的影响。
- Batch Size 对比:固定总训练步数,对比 batch_size=8, 32, 128, 512 的训练时间和最终准确率。
- 自定义 Metric:实现一个 F1-score metric 并传入
model.compile(metrics=[...])。对比它与 accuracy 在类别不平衡数据上的差异。