Python版本 :Python 3.12+
TensorFlow版本 :TensorFlow 2.16+ / Keras 3.0+
开发工具 :PyCharm 或 VS Code
操作系统:Windows / macOS / Linux (通用)
摘要:本讲从神经网络基础原理出发,系统讲解TensorFlow 2.16+与Keras 3.0的核心特性,通过CNN图像分类和RNN文本生成两个完整实战项目,帮助你掌握深度学习的核心技能与工程实践。
学习目标
完成本讲学习后,你将能够:
- 理解神经网络的前向传播与反向传播原理
- 掌握TensorFlow 2.16+与Keras 3.0的新特性
- 熟练使用三种API构建深度学习模型
- 实现CNN卷积神经网络进行图像分类
- 实现RNN/LSTM进行序列数据处理
- 应用数据增强、正则化、回调函数等训练技巧
- 掌握模型优化与部署方法
1. 神经网络基础原理
1.1 从生物神经元到人工神经元
| 生物神经元 | 人工神经元 |
|---|---|
| 树突(接收信号) | 输入特征 (x1, x2, ..., xn) |
| 细胞体(处理信号) | 加权求和 + 激活函数 |
| 轴突(输出信号) | 输出结果 |
| 突触(连接强度) | 权重 (w1, w2, ..., wn) |
一句话总结:人工神经元就是一个带权重的求和器,通过激活函数引入非线性。
1.2 前向传播:数据如何流动
输入层 → 隐藏层1 → 隐藏层2 → ... → 输出层
↓ ↓ ↓ ↓
特征 提取特征 抽象特征 预测结果
数学表达:
z = W·x + b # 线性变换
a = f(z) # 激活函数
1.3 反向传播:参数如何更新
反向传播是深度学习的核心算法,通过链式法则计算梯度:
1. 计算损失函数对输出的梯度
2. 从输出层向输入层逐层传播梯度
3. 使用优化器更新权重参数
python
# 梯度下降更新公式
W_new = W_old - learning_rate * ∂L/∂W
b_new = b_old - learning_rate * ∂L/∂b
1.4 激活函数对比
| 激活函数 | 公式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| ReLU | max(0, x) | 计算快、缓解梯度消失 | 神经元死亡 | 隐藏层默认选择 |
| Sigmoid | 1/(1+e^(-x)) | 输出范围(0,1) | 梯度消失 | 二分类输出层 |
| Tanh | (e^x - e(-x))/(ex + e^(-x)) | 零中心化 | 梯度消失 | RNN隐藏层 |
| Softmax | e(xi)/Σe(xj) | 多分类概率和为1 | 计算量大 | 多分类输出层 |
| Leaky ReLU | max(αx, x) | 解决ReLU死亡问题 | 需调α | 深度网络 |
2. TensorFlow 2.16+ 与 Keras 3.0 新特性
2.1 Keras 3.0:多后端架构
Keras 3.0是Keras的完全重写版本,支持在多个后端框架上运行:
┌─────────────────────────────────────────┐
│ Keras 3.0 API │
├─────────────────────────────────────────┤
│ TensorFlow │ JAX │ PyTorch │
│ Backend │ Backend │ Backend │
└─────────────────────────────────────────┘
主要优势:
- 一套代码,三个后端任选
- 性能优化:JAX后端训练速度提升显著
- 大模型训练支持:更好的分布式训练能力
2.2 TensorFlow 2.16+ 核心特性
| 特性 | 说明 |
|---|---|
| Eager Execution | 默认启用,代码直观、调试方便 |
| tf.function | 自动图执行,兼顾性能与灵活性 |
| Mixed Precision | 混合精度训练,显存减半、速度提升 |
| tf.data | 高性能数据管道,支持并行预处理 |
| tf.distribute | 分布式训练策略,多GPU/TPU支持 |
2.3 环境安装
bash
# 安装最新版TensorFlow(包含Keras 3.0)
pip install tensorflow==2.16.1
# 验证安装
python -c "import tensorflow as tf; print(tf.__version__)"
# 检查GPU可用性
python -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"
2.4 GPU内存配置
python
import tensorflow as tf
# 动态分配GPU内存(避免一次性占满)
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
try:
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
print(f"检测到 {len(gpus)} 个GPU,已启用动态内存分配")
except RuntimeError as e:
print(e)
3. TensorFlow基础:张量与自动微分
3.1 张量操作
python
import tensorflow as tf
import numpy as np
# 创建张量
scalar = tf.constant(3.14)
vector = tf.constant([1, 2, 3, 4, 5])
matrix = tf.constant([[1, 2, 3], [4, 5, 6]])
tensor_3d = tf.constant(np.random.rand(3, 4, 5))
print(f"标量: {scalar}")
print(f"向量形状: {vector.shape}, 维度: {vector.ndim}")
print(f"矩阵形状: {matrix.shape}")
print(f"3D张量形状: {tensor_3d.shape}")
# 张量运算
a = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)
b = tf.constant([[5, 6], [7, 8]], dtype=tf.float32)
# 元素级运算
c = a + b # 或 tf.add(a, b)
d = a * b # 元素乘法
# 矩阵乘法
e = tf.matmul(a, b)
# 转置与变形
f = tf.transpose(a)
g = tf.reshape(a, [4, 1])
print(f"矩阵乘法结果:\n{e}")
3.2 变量与自动微分
python
# 创建变量(可训练参数)
W = tf.Variable(tf.random.normal([3, 2]), name='weight')
b = tf.Variable(tf.zeros([2]), name='bias')
print(f"W形状: {W.shape}")
print(f"b形状: {b.shape}")
# 自动微分示例
x = tf.Variable(3.0)
with tf.GradientTape() as tape:
y = x ** 2 + 2 * x + 1
dy_dx = tape.gradient(y, x)
print(f"y = x^2 + 2x + 1 在 x=3 处的导数: {dy_dx}") # 2*3 + 2 = 8
# 多变量梯度
W = tf.Variable(tf.random.normal([2, 2]))
b = tf.Variable(tf.zeros([2]))
x = tf.constant([[1.0, 2.0]])
with tf.GradientTape() as tape:
y = tf.matmul(x, W) + b
loss = tf.reduce_mean(y ** 2)
gradients = tape.gradient(loss, [W, b])
print(f"W的梯度形状: {gradients[0].shape}")
print(f"b的梯度形状: {gradients[1].shape}")
4. 使用Keras构建神经网络
4.1 Sequential API(最简单)
适用于层堆叠的模型,代码最简洁:
python
from tensorflow import keras
from tensorflow.keras import layers
# 方法1:逐层添加
model = keras.Sequential(name='simple_mlp')
model.add(layers.Dense(64, activation='relu', input_shape=(784,)))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
# 方法2:列表传递(推荐)
model = keras.Sequential([
layers.Dense(64, activation='relu', input_shape=(784,)),
layers.Dropout(0.2),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')
], name='simple_mlp')
# 编译模型
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
model.summary()
4.2 Functional API(最灵活)
支持多输入、多输出、共享层:
python
# 输入层
inputs = keras.Input(shape=(784,), name='input')
# 隐藏层
x = layers.Dense(64, activation='relu', name='hidden_1')(inputs)
x = layers.Dropout(0.2)(x)
x = layers.Dense(64, activation='relu', name='hidden_2')(x)
# 输出层
outputs = layers.Dense(10, activation='softmax', name='output')(x)
# 创建模型
model = keras.Model(inputs=inputs, outputs=outputs, name='functional_mlp')
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=0.001),
loss='categorical_crossentropy',
metrics=['accuracy']
)
model.summary()
4.3 自定义模型类(最强大)
python
class CustomMLP(keras.Model):
def __init__(self, hidden_units=64, num_classes=10, dropout_rate=0.2):
super(CustomMLP, self).__init__()
self.dense1 = layers.Dense(hidden_units, activation='relu')
self.dropout = layers.Dropout(dropout_rate)
self.dense2 = layers.Dense(hidden_units, activation='relu')
self.output_layer = layers.Dense(num_classes, activation='softmax')
def call(self, inputs, training=False):
x = self.dense1(inputs)
x = self.dropout(x, training=training)
x = self.dense2(x)
return self.output_layer(x)
# 实例化模型
model = CustomMLP(hidden_units=128, num_classes=10)
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
4.4 三种API对比
| API类型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Sequential | 简单层堆叠 | 代码简洁、易读 | 不支持多输入/输出 |
| Functional | 复杂模型结构 | 灵活、支持任意拓扑 | 稍复杂 |
| 自定义类 | 需要自定义逻辑 | 完全可控、可复用 | 代码量最大 |
5. 卷积神经网络(CNN)详解
5.1 CNN核心组件
输入图像 → [卷积层 + 激活] → [池化层] → [卷积层 + 激活] → [池化层] → [全连接层] → 输出
↓ ↓
特征提取 降维压缩
| 组件 | 作用 | 常用参数 |
|---|---|---|
| Conv2D | 提取局部特征 | filters, kernel_size, strides, padding |
| MaxPooling2D | 降维、保留主要特征 | pool_size, strides |
| BatchNormalization | 加速训练、稳定收敛 | - |
| Dropout | 防止过拟合 | rate |
| Flatten | 展平为向量 | - |
5.2 卷积操作原理
输入特征图 (5x5) 卷积核 (3x3) 输出特征图 (3x3)
┌───┬───┬───┬───┬───┐ ┌───┬───┬───┐
│ 1 │ 1 │ 1 │ 0 │ 0 │ │ 1 │ 0 │ 1 │
├───┼───┼───┼───┼───┤ ├───┼───┼───┤ ┌───┬───┬───┐
│ 0 │ 1 │ 1 │ 1 │ 0 │ * │ 0 │ 1 │ 0 │ = │ 4 │ 3 │ 4 │
├───┼───┼───┼───┼───┤ ├───┼───┼───┤ ├───┼───┼───┤
│ 0 │ 0 │ 1 │ 1 │ 1 │ │ 1 │ 0 │ 1 │ │ 2 │ 4 │ 3 │
├───┼───┼───┼───┼───┤ └───┴───┴───┘ ├───┼───┼───┤
│ 0 │ 0 │ 1 │ 1 │ 0 │ │ 2 │ 3 │ 4 │
├───┼───┼───┼───┼───┤ └───┴───┴───┘
│ 0 │ 1 │ 1 │ 0 │ 0 │
└───┴───┴───┴───┴───┘
5.3 构建CNN模型
python
from tensorflow.keras import layers, models
def create_cnn_model(input_shape, num_classes):
"""
构建CNN图像分类模型
Args:
input_shape: 输入图像形状 (H, W, C)
num_classes: 分类类别数
"""
model = models.Sequential([
# 第一个卷积块
layers.Conv2D(32, (3, 3), padding='same', input_shape=input_shape),
layers.BatchNormalization(),
layers.ReLU(),
layers.Conv2D(32, (3, 3), padding='same'),
layers.BatchNormalization(),
layers.ReLU(),
layers.MaxPooling2D((2, 2)),
layers.Dropout(0.25),
# 第二个卷积块
layers.Conv2D(64, (3, 3), padding='same'),
layers.BatchNormalization(),
layers.ReLU(),
layers.Conv2D(64, (3, 3), padding='same'),
layers.BatchNormalization(),
layers.ReLU(),
layers.MaxPooling2D((2, 2)),
layers.Dropout(0.25),
# 第三个卷积块
layers.Conv2D(128, (3, 3), padding='same'),
layers.BatchNormalization(),
layers.ReLU(),
layers.MaxPooling2D((2, 2)),
layers.Dropout(0.25),
# 全连接层
layers.Flatten(),
layers.Dense(512),
layers.BatchNormalization(),
layers.ReLU(),
layers.Dropout(0.5),
layers.Dense(num_classes, activation='softmax')
])
return model
# 创建模型(以CIFAR-10为例)
model = create_cnn_model((32, 32, 3), 10)
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
model.summary()
5.4 数据增强
python
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 数据增强配置
data_augmentation = ImageDataGenerator(
rotation_range=20, # 随机旋转角度
width_shift_range=0.2, # 水平平移
height_shift_range=0.2, # 垂直平移
horizontal_flip=True, # 水平翻转
zoom_range=0.2, # 随机缩放
fill_mode='nearest', # 填充模式
brightness_range=[0.8, 1.2] # 亮度调整
)
# 使用示例
# model.fit(data_augmentation.flow(x_train, y_train, batch_size=32),
# epochs=50,
# validation_data=(x_test, y_test))
6. 循环神经网络(RNN)详解
6.1 RNN原理
RNN适用于序列数据(文本、时间序列等),具有记忆能力:
h_t-1 ───────┐
↓ │
┌──────┐ │
x_t → │ Cell │ → h_t → 输出
└──────┘ │
↑─────────┘
(循环连接)
6.2 RNN变体对比
| 类型 | 特点 | 适用场景 |
|---|---|---|
| SimpleRNN | 基础循环结构 | 简单序列 |
| LSTM | 长短期记忆,解决梯度消失 | 长序列、文本生成 |
| GRU | LSTM简化版,参数更少 | 中等长度序列 |
| Bidirectional | 双向处理 | 需要上下文理解 |
6.3 LSTM单元结构
遗忘门: f_t = σ(W_f · [h_t-1, x_t] + b_f)
输入门: i_t = σ(W_i · [h_t-1, x_t] + b_i)
候选状态: C̃_t = tanh(W_C · [h_t-1, x_t] + b_C)
细胞状态: C_t = f_t * C_t-1 + i_t * C̃_t
输出门: o_t = σ(W_o · [h_t-1, x_t] + b_o)
隐藏状态: h_t = o_t * tanh(C_t)
6.4 构建LSTM文本分类模型
python
def create_lstm_model(vocab_size, embedding_dim, max_length, num_classes):
"""
构建LSTM文本分类模型
Args:
vocab_size: 词汇表大小
embedding_dim: 词嵌入维度
max_length: 序列最大长度
num_classes: 分类类别数
"""
model = models.Sequential([
# 词嵌入层
layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
# LSTM层
layers.LSTM(128, return_sequences=True, dropout=0.2, recurrent_dropout=0.2),
layers.LSTM(64, dropout=0.2, recurrent_dropout=0.2),
# 全连接层
layers.Dense(64, activation='relu'),
layers.Dropout(0.5),
layers.Dense(num_classes, activation='softmax')
])
return model
# 双向LSTM(效果更好)
def create_bidirectional_lstm(vocab_size, embedding_dim, max_length, num_classes):
model = models.Sequential([
layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
layers.Bidirectional(layers.LSTM(128, return_sequences=True)),
layers.Bidirectional(layers.LSTM(64)),
layers.Dense(64, activation='relu'),
layers.Dropout(0.5),
layers.Dense(num_classes, activation='softmax')
])
return model
7. 实战一:CIFAR-10图像分类(CNN)
7.1 数据准备
python
import tensorflow as tf
from tensorflow.keras import layers, models
import matplotlib.pyplot as plt
import numpy as np
# 加载CIFAR-10数据集
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()
# 数据预处理
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
# 类别名称
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
'dog', 'frog', 'horse', 'ship', 'truck']
print(f"训练集形状: {x_train.shape}")
print(f"测试集形状: {x_test.shape}")
print(f"类别数: {len(class_names)}")
# 可视化样本
plt.figure(figsize=(12, 5))
for i in range(10):
plt.subplot(2, 5, i + 1)
plt.imshow(x_train[i])
plt.title(class_names[y_train[i][0]])
plt.axis('off')
plt.tight_layout()
plt.show()
7.2 构建改进版CNN
python
def create_advanced_cnn(input_shape=(32, 32, 3), num_classes=10):
"""构建更深层次的CNN模型"""
inputs = layers.Input(shape=input_shape)
# 数据增强层(内置在模型中)
x = layers.RandomFlip("horizontal")(inputs)
x = layers.RandomRotation(0.1)(x)
x = layers.RandomZoom(0.1)(x)
# 第一个卷积块
x = layers.Conv2D(32, 3, padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.Conv2D(32, 3, padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.MaxPooling2D(2)(x)
x = layers.Dropout(0.25)(x)
# 第二个卷积块
x = layers.Conv2D(64, 3, padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.Conv2D(64, 3, padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.MaxPooling2D(2)(x)
x = layers.Dropout(0.25)(x)
# 第三个卷积块
x = layers.Conv2D(128, 3, padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.MaxPooling2D(2)(x)
x = layers.Dropout(0.25)(x)
# 全局平均池化替代Flatten
x = layers.GlobalAveragePooling2D()(x)
# 全连接层
x = layers.Dense(256)(x)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(num_classes, activation='softmax')(x)
model = models.Model(inputs, outputs)
return model
model = create_advanced_cnn()
model.summary()
7.3 训练配置与回调函数
python
from tensorflow.keras import callbacks
# 回调函数配置
callbacks_list = [
# 早停:验证损失3轮不下降则停止
callbacks.EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True,
verbose=1
),
# 学习率衰减:验证损失平台期自动降低学习率
callbacks.ReduceLROnPlateau(
monitor='val_loss',
factor=0.5,
patience=5,
min_lr=1e-7,
verbose=1
),
# 模型检查点:保存最佳模型
callbacks.ModelCheckpoint(
'best_cifar10_model.keras',
monitor='val_accuracy',
save_best_only=True,
verbose=1
),
# TensorBoard日志
callbacks.TensorBoard(log_dir='./logs')
]
# 学习率调度器
initial_learning_rate = 0.001
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate,
decay_steps=1000,
decay_rate=0.9,
staircase=True
)
# 编译模型
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=lr_schedule),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
7.4 模型训练
python
# 划分验证集
from sklearn.model_selection import train_test_split
x_train_split, x_val, y_train_split, y_val = train_test_split(
x_train, y_train, test_size=0.1, random_state=42
)
# 训练模型
history = model.fit(
x_train_split, y_train_split,
batch_size=64,
epochs=100,
validation_data=(x_val, y_val),
callbacks=callbacks_list,
verbose=1
)
# 评估测试集
test_loss, test_accuracy = model.evaluate(x_test, y_test)
print(f"测试集准确率: {test_accuracy:.4f}")
7.5 训练过程可视化
python
# 绘制训练曲线
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 准确率曲线
axes[0].plot(history.history['accuracy'], label='训练准确率')
axes[0].plot(history.history['val_accuracy'], label='验证准确率')
axes[0].set_xlabel('Epoch')
axes[0].set_ylabel('Accuracy')
axes[0].set_title('准确率变化曲线')
axes[0].legend()
axes[0].grid(True)
# 损失曲线
axes[1].plot(history.history['loss'], label='训练损失')
axes[1].plot(history.history['val_loss'], label='验证损失')
axes[1].set_xlabel('Epoch')
axes[1].set_ylabel('Loss')
axes[1].set_title('损失变化曲线')
axes[1].legend()
axes[1].grid(True)
plt.tight_layout()
plt.show()
7.6 混淆矩阵与分类报告
python
from sklearn.metrics import confusion_matrix, classification_report
import seaborn as sns
# 预测
y_pred = model.predict(x_test)
y_pred_classes = np.argmax(y_pred, axis=1)
y_true = y_test.flatten()
# 混淆矩阵
cm = confusion_matrix(y_true, y_pred_classes)
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_names, yticklabels=class_names)
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.title('混淆矩阵')
plt.show()
# 分类报告
print(classification_report(y_true, y_pred_classes, target_names=class_names))
8. 实战二:IMDB情感分析(LSTM)
8.1 数据准备
python
# 加载IMDB数据集
vocab_size = 10000
max_length = 200
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.imdb.load_data(
num_words=vocab_size
)
# 填充序列
x_train = tf.keras.preprocessing.sequence.pad_sequences(
x_train, maxlen=max_length, padding='post', truncating='post'
)
x_test = tf.keras.preprocessing.sequence.pad_sequences(
x_test, maxlen=max_length, padding='post', truncating='post'
)
print(f"训练集形状: {x_train.shape}")
print(f"测试集形状: {x_test.shape}")
print(f"样本序列: {x_train[0][:20]}...")
8.2 构建Embedding + LSTM模型
python
def create_sentiment_model(vocab_size=10000, embedding_dim=128, max_length=200):
"""构建情感分析LSTM模型"""
model = models.Sequential([
# Embedding层:将整数序列映射为密集向量
layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
# 空间Dropout:对特征图进行Dropout
layers.SpatialDropout1D(0.2),
# 双向LSTM
layers.Bidirectional(layers.LSTM(128, return_sequences=True)),
layers.Bidirectional(layers.LSTM(64)),
# 全连接层
layers.Dense(128, activation='relu'),
layers.Dropout(0.5),
layers.Dense(1, activation='sigmoid') # 二分类
])
return model
model = create_sentiment_model()
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
model.summary()
8.3 训练与评估
python
# 回调函数
callbacks_list = [
callbacks.EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True),
callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=2)
]
# 训练
history = model.fit(
x_train, y_train,
batch_size=128,
epochs=20,
validation_split=0.2,
callbacks=callbacks_list
)
# 评估
test_loss, test_accuracy = model.evaluate(x_test, y_test)
print(f"测试集准确率: {test_accuracy:.4f}")
9. 模型训练与调优技巧
9.1 防止过拟合的方法
| 方法 | 实现方式 | 适用场景 |
|---|---|---|
| Dropout | layers.Dropout(0.5) | 全连接层后 |
| L2正则化 | kernel_regularizer=l2(0.001) | 权重约束 |
| 数据增强 | ImageDataGenerator / 内置层 | 图像任务 |
| 早停 | EarlyStopping回调 | 所有任务 |
| 批归一化 | BatchNormalization() | 卷积/全连接层后 |
python
# L2正则化示例
from tensorflow.keras import regularizers
layers.Dense(64, activation='relu',
kernel_regularizer=regularizers.l2(0.001))
9.2 学习率调度策略
python
# 1. 指数衰减
exponential_decay = tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate=0.001,
decay_steps=1000,
decay_rate=0.96,
staircase=True
)
# 2. 分段常数衰减
piecewise_decay = tf.keras.optimizers.schedules.PiecewiseConstantDecay(
boundaries=[1000, 2000],
values=[0.001, 0.0005, 0.0001]
)
# 3. 余弦退火
cosine_decay = tf.keras.optimizers.schedules.CosineDecay(
initial_learning_rate=0.001,
decay_steps=10000,
alpha=0.1 # 最小学习率 = alpha * initial_learning_rate
)
# 使用
optimizer = tf.keras.optimizers.Adam(learning_rate=cosine_decay)
9.3 混合精度训练
python
from tensorflow.keras import mixed_precision
# 设置混合精度策略
policy = mixed_precision.Policy('mixed_float16')
mixed_precision.set_global_policy(policy)
print(f"计算策略: {policy.name}")
print(f"变量类型: {policy.variable_dtype}")
print(f"计算类型: {policy.compute_dtype}")
# 构建模型时,输出层需要转回float32
outputs = layers.Dense(num_classes, activation='softmax', dtype='float32')(x)
9.4 分布式训练
python
# 多GPU训练策略
strategy = tf.distribute.MirroredStrategy()
print(f"可用GPU数量: {strategy.num_replicas_in_sync}")
with strategy.scope():
# 在策略范围内创建和编译模型
model = create_advanced_cnn()
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
# 训练(batch_size会自动分配到各GPU)
# model.fit(...)
10. 模型保存、加载与部署
10.1 模型保存格式对比
| 格式 | 扩展名 | 优点 | 适用场景 |
|---|---|---|---|
| Keras | .keras | 完整保存,推荐格式 | 通用保存 |
| SavedModel | 目录 | TensorFlow标准格式 | 生产部署 |
| HDF5 | .h5 | 兼容旧版本 | 向后兼容 |
| 仅权重 | .weights.h5 | 文件小 | 相同结构模型 |
10.2 保存与加载
python
# 保存完整模型(推荐.keras格式)
model.save('my_model.keras')
# 保存为SavedModel格式(用于TensorFlow Serving)
model.save('saved_model/my_model')
# 仅保存权重
model.save_weights('my_model.weights.h5')
# 加载完整模型
loaded_model = tf.keras.models.load_model('my_model.keras')
# 加载SavedModel
loaded_model = tf.keras.models.load_model('saved_model/my_model')
# 加载权重(需先创建相同结构模型)
model = create_advanced_cnn()
model.load_weights('my_model.weights.h5')
10.3 转换为TensorFlow Lite(移动端)
python
# 转换为TFLite
converter = tf.lite.TFLiteConverter.from_keras_model(model)
# 优化选项
converter.optimizations = [tf.lite.Optimize.DEFAULT]
# 量化(进一步减小模型体积)
converter.target_spec.supported_types = [tf.float16]
tflite_model = converter.convert()
# 保存
with open('model.tflite', 'wb') as f:
f.write(tflite_model)
print(f"TFLite模型大小: {len(tflite_model) / 1024:.2f} KB")
10.4 TensorFlow Serving导出
python
# 导出为SavedModel格式用于Serving
import os
export_path = './serving_models/my_model/1'
tf.saved_model.save(model, export_path)
print(f"模型已导出到: {export_path}")
# 使用以下命令启动TensorFlow Serving:
# docker run -p 8501:8501 \
# --mount type=bind,source=$(pwd)/serving_models,target=/models/my_model \
# -e MODEL_NAME=my_model -t tensorflow/serving
11. 避坑小贴士
11.1 常见错误与解决方案
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| OOM(显存不足) | batch_size过大 | 减小batch_size或使用梯度累积 |
| 损失不下降 | 学习率过大/梯度消失 | 降低学习率、更换激活函数、使用批归一化 |
| 验证损失持续上升 | 过拟合 | 增加Dropout、数据增强、早停 |
| 训练速度慢 | 数据加载瓶颈 | 使用tf.data优化、缓存预处理 |
| 模型预测结果一致 | 标签未one-hot/数据问题 | 检查标签编码、数据归一化 |
11.2 性能优化建议
python
# 1. 使用tf.data优化数据管道
dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
dataset = dataset.shuffle(buffer_size=10000)
dataset = dataset.batch(32)
dataset = dataset.prefetch(tf.data.AUTOTUNE) # 预取数据
# 2. 使用缓存(数据可放入内存时)
dataset = dataset.cache()
# 3. 使用@tf.function加速
tf_function_model = tf.function(model)
11.3 调试技巧
python
# 检查模型中间输出
layer_outputs = [layer.output for layer in model.layers[:5]]
activation_model = models.Model(inputs=model.input, outputs=layer_outputs)
activations = activation_model.predict(x_test[:1])
# 打印每层输出形状
for i, activation in enumerate(activations):
print(f"Layer {i}: {activation.shape}")
本章小结
本讲系统讲解了TensorFlow深度学习:
- 神经网络基础:前向传播、反向传播、激活函数原理
- TensorFlow 2.16+新特性:Keras 3.0多后端、混合精度、分布式训练
- Keras三种API:Sequential、Functional、自定义类
- CNN详解:卷积、池化、批归一化,CIFAR-10实战
- RNN/LSTM:序列建模原理,IMDB情感分析实战
- 训练技巧:回调函数、学习率调度、防止过拟合
- 模型部署:TFLite、SavedModel、TensorFlow Serving
本章内容到此结束,感谢阅读!如有疑问,欢迎在评论区留言讨论。