2025-03-19 09:29:17 +08:00

420 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 深度学习的实现
## 在TensorFlow中实现
```python
import numpy as np
import tensorflow as tf
from keras import layers, models
from keras.datasets import mnist
from keras.utils import to_categorical
# 加载MNIST数据集
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# 数据预处理
train_images = train_images.reshape((60000, 28 * 28)).astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28)).astype('float32') / 255
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
# 定义模型
model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(28 * 28,)))
model.add(layers.Dense(10, activation='softmax')) # 注意这里需要指定输出层的神经元数量
# 编译模型
optimizer = tf.keras.optimizers.Adam() # 正确的导入方式
loss = 'categorical_crossentropy'
metrics = ['accuracy']
model.compile(optimizer=optimizer, loss=loss, metrics=metrics)
# 训练模型
model.fit(train_images, train_labels, epochs=5, batch_size=32)
# 评估模型
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f"Test accuracy: {test_acc}")
# 保存模型
model.save('my_model.h5')
```
### 在TensorFlow中实现深度学习需要以下步骤
`数据准备 → 模型定义 → 编译 → 训练(自动/自定义) → 评估 → 保存/部署`
### 模型的定义
- 在深度学习中模型定义Model Definition 是构建神经网络的核心步骤,目的是明确模型的结构和数据流动方式。它决定了神经网络由哪些层组成、层与层之间如何连接,以及每层的计算逻辑。可以类比为设计一栋建筑的蓝图,需要明确房间(层)的布局、连接方式(数据流)和每个房间的功能(层的计算规则)。
- 模型定义的三个核心问题
- 模型的结构是什么?
- 有多少层?每一层的类型(全连接层、卷积层等)是什么?
- 层之间如何连接?
- 是简单的线性堆叠如Sequential模型还是存在分支、跳跃连接等复杂拓扑
- 每层具体做什么?
- 每层的参数(如神经元数量、滤波器大小)、激活函数、正则化方法等。
- TensorFlow尤其是其高层 API `tf.keras`)提供了多种定义模型的方法。
- Sequential模型适用于简单的线性堆叠结构即每一层直接连接到下一层。
```python
import tensorflow as tf
from tensorflow.keras import layers, models
# 定义模型
model = models.Sequential() #创建了一个Sequential模型。Sequential模型允许我们一层一层地构建网络每层都是顺序堆叠的。
model.add(layers.Dense(64, activation='relu', input_shape=(784,)))
#添加第一个全连接层Dense到模型中该层有64个神经元。使用的激活函数是ReLURectified Linear Unit它是一种常用的非线性激活函数。指定输入数据的形状。这里假设输入数据是784个特征这对应于一个28x28像素的图像展平后的结果。
model.add(layers.Dense(64, activation='relu'))
#添加第二个全连接层这个层同样有64个神经元并且使用ReLU激活函数。由于这是第二个层不需要指定输入形状因为它自动从上一层获取。
model.add(layers.Dense(10, activation='softmax'))
#最后一个全连接层这个层有10个神经元通常用于分类任务每个神经元对应一个类别。使用softmax激活函数它将神经元的输出转换为概率分布总和为1。它可以解释为每个类别的预测概率。
```
- 函数式API适用于更复杂的模型结构如非顺序的层连接、共享层、多输入多输出模型等。
- 适用场景:复杂模型(多输入/输出、分支、跳跃连接、共享层)。
- 特点:显式定义输入和输出,灵活构建层间连接关系。
- 代码示例(多输入模型):
```python
# 定义输入层
input1 = tf.keras.Input(shape=(32,), name="input_1")
input2 = tf.keras.Input(shape=(64,), name="input_2")
# 合并两个输入
concatenated = tf.keras.layers.Concatenate()([input1, input2])
# 定义中间层
x = tf.keras.layers.Dense(128, activation='relu')(concatenated)
x = tf.keras.layers.Dropout(0.5)(x)
# 定义输出层
output = tf.keras.layers.Dense(1, activation='sigmoid')(x)
# 创建模型
model = tf.keras.Model(inputs=[input1, input2], outputs=output)`
```
- 子类化API适用于需要完全控制模型结构和训练过程的场景可以自定义前向传播逻辑和训练循环。
- 适用场 景:需要完全自定义的模型(如动态计算图、自定义前向逻辑)。
- 特点:通过继承 tf.keras.Model 类,自由定义前向传播逻辑。适用于需要高度自定义的模型结构。
- 代码示例(自定义模型):
```python
class CustomModel(tf.keras.Model):
def __init__(self):
super().__init__()
# 定义层
self.dense1 = tf.keras.layers.Dense(64, activation='relu')
self.dropout = tf.keras.layers.Dropout(0.2)
self.dense2 = tf.keras.layers.Dense(10, activation='softmax')
def call(self, inputs, training=False):
# 自定义前向传播逻辑
x = self.dense1(inputs)
if training: # 仅在训练时使用Dropout
x = self.dropout(x)
return self.dense2(x)
# 实例化模型并构建
model = CustomModel()
model.build(input_shape=(None, 784)) # 指定输入形状
```
- 优点:
- 完全控制模型逻辑(如条件分支、循环操作)。
- 支持动态计算(如根据输入数据调整结构)。
- 缺点:
- 代码复杂度高,需手动管理层和参数。
- 模型结构不易可视化如model.summary()需先调用build
- 中间层都有不同的类型,例如:
- Dense层全连接层每个神经元与前一层的所有神经元相连。
- Dropout层在训练过程中随机丢弃一部分神经元以防止过拟合。
- Flatten层将输入展平为一维向量通常用于从卷积层到全连接层的转换。
- Conv2D层二维卷积层用于处理图像数据。
- MaxPooling2D层最大池化层用于降低特征图的维度。
- BatchNormalization层批量归一化层用于加速训练并提高模型的稳定性。
- Activation层激活函数层用于引入非线性变换。
- activation里面指的是使用什么激活函数比如relu、sigmoid、softmax等
| 任务类型 | 推荐激活函数 | 理由 |
|------------------|----------------|--------------------------------|
| 二分类输出层 | Sigmoid、Softmax | 输出概率形式。 |
| 多分类输出层 | Softmax | 强制归一化为概率分布。 |
| 隐藏层(通用) | ReLU、Leaky ReLU、Swish | 平衡性能与计算效率。 |
| RNN/序列模型 | Tanh、ELU | 稳定梯度传播,缓解长程依赖问题。|
| 需要平滑输出 | Softsign、Softmax | 输出连续且可解释。 |
| 嵌入式设备 | Hard Sigmoid、ReLU6 | 计算快速,硬件友好。 |
详情请见[激活函数](激活函数.md)
### 模型的编译
- 在TensorFlow中编译阶段的核心API是 tf.keras.Model.compile(),它允许你配置模型的训练参数。
- **1.核心APImodel.compile()**
```python
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
loss = SparseCategoricalCrossentropy(from_logits=True)
model.compile(
optimizer=optimizer,
loss=loss,
metrics=['accuracy'], #模型评估时使用的指标列表,在 model.fit() 的输出中,会实时显示这些指标的训练/验证值。model.evaluate() 会返回所有指标的值。
# 其他可选参数
)
```
| 参数 | 说明 |
| ------------ | ------------------------------------------------ |
| optimizer | 优化器对象(字符串或实例),控制梯度下降策略。 |
| loss | 损失函数(字符串、可调用对象或损失类实例)。 |
| metrics | 评估指标列表(字符串、可调用对象或指标类实例)。 |
| loss_weights | 字典或列表,为不同输出指定损失权重。 |
| run_eagerly | 布尔值启用急切执行模式默认False。 |
- **2.优化器optimizer**
- 优化器决定了模型如何更新其参数以最小化损失函数。具体请见[优化器](Tensorflow的优化器.md)。
- **3.损失函数loss**
- 损失函数衡量模型预测值与真实值之间的差异。具体请见[损失函数](Tensorflow的损失函数.md)。
### 模型的训练
- 在TensorFlow中训练深度学习模型的核心API可分为以下几类
#### **1. 自动训练 API**
- **`model.fit()`**
- **作用**: 简化训练流程,自动处理数据迭代、前向传播、反向传播和参数更新。
- **示例**:
```python
model.fit(train_dataset, epochs=10, validation_data=val_dataset,
callbacks=[TensorBoard(log_dir='./logs')])
```
- **关键参数**: `epochs`, `batch_size`, `validation_split`, `callbacks`。
1. `epochs`(训练轮数)**
- **定义**: 每次遍历全部训练数据称为一个 Epoch。
- **目的**: 控制模型的学习次数,防止欠拟合(训练不足)或过拟合(训练过度)。
- **调整策略**
- **推荐范围**:
- 初期实验: `5~50`(根据数据量调整)。
- 复杂任务(如 ImageNet: `100~300`。
- **注意**:
- 数据量小时(如 MNIST`epochs=10~20` 可能已过拟合。
- 使用 **早停回调**`EarlyStopping`)动态终止训练。
- 示例:
```python
model.fit(..., epochs=100, callbacks=[EarlyStopping(patience=10)])
```
**“数据不够正则来凑模型太深Dropout 伺候早停法防过拟Epoch 要看数据够不够!”**
2. `batch_size`(批量大小
- **定义**: 每次梯度更新使用的样本数量。
- **影响**:
- **内存消耗**: `batch_size` 越大,占用的 GPU/TPU 内存越多。
- **收敛速度**: 较大的 `batch_size` 可能加速训练,但梯度更新更粗糙。
- **泛化性能**: 小批量(如 32~128通常泛化效果更好。
- **默认值**
- `32`
- **调整策略**
- **硬件限制**:
- GPU 内存充足时,可尝试 `batch_size=256` 或更大。
- 内存不足时,降低至 `batch_size=16` 或 `32`。
- **经验规则**:
- **小批量**: `32~128`(适合大多数场景,平衡速度与泛化)。
- **大批量**: `256~1024`(需搭配学习率调整,如线性 warmup
- **示例**:
```python
model.fit(..., batch_size=64) # 使用 64 个样本更新一次权重
```
- ##### **高级技巧**
- **动态调整**: 使用 `tf.data.Dataset` 的 `prefetch` 和 `cache` 加速数据管道。
3. `validation_split`(验证集划分比例)**
- **功能**: 在训练数据中按比例自动划分验证集,无需手动拆分 `X_train` 和 `y_train`。
- **默认值**: `0.0`(不划分验证集)。
- **调整策略**
- **推荐值**:
- `0.1`~`0.2`(常用 20% 数据作为验证集)。
- **适用场景**:
- **小型数据集**: 避免划分过多验证数据导致训练不足。
- **大型数据集**: 可结合 `validation_data` 参数指定独立验证集。
- **示例**:
```python
model.fit(..., validation_split=0.2) # 20% 训练数据作为验证集
```
4. `callbacks`(回调函数列表)**
- **功能**: 在训练过程中插入自定义操作(如保存模型、监控指标、动态调整参数)。
- **默认值**: `None`(不启用任何回调)。
- **常用回调及场景**
| 回调类 | 作用 | 示例代码 |
|-----------------------|---------------------------------------|-------------------------------------------|
| `ModelCheckpoint` | 保存最佳模型 | `ModelCheckpoint('best_model.keras', save_best_only=True)` |
| `EarlyStopping` | 根据验证指标提前终止训练 | `EarlyStopping(monitor='val_loss', patience=3)` |
| `TensorBoard` | 可视化训练过程 | `TensorBoard(log_dir='./logs')` |
| `ReduceLROnPlateau` | 动态降低学习率(当指标不再提升时) | `ReduceLROnPlateau(factor=0.1, patience=2)` |
| `CSVLogger` | 记录训练日志到 CSV 文件 | `CSVLogger('training.log')` |
- **自定义回调**
- **实现方式**: 继承 `tf.keras.callbacks.Callback` 类并重写 `on_epoch_end` 等方法。
```python
class CustomCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs=None):
print(f"Epoch {epoch}: Custom action here")
```
- **参数综合配置示例**
```python
model.fit(
train_dataset,
epochs=100,
batch_size=64,
validation_split=0.2,
callbacks=[
EarlyStopping(monitor='val_loss', patience=10),
ModelCheckpoint('best_model.keras', save_best_only=True),
TensorBoard(log_dir='./logs')
]
)
```
---
#### **2. 自定义训练控制**
- 自定义训练控制的核心逻辑
- 1. 继承 tf.keras.Model 类
- Keras 的 Model 类封装了神经网络的前向传播、损失计算、梯度更新等核心逻辑。通过继承它,保留这些自动化功能,同时插入自定义代码。
- ​关键方法:
- `__init__`: 初始化模型结构(如层)。
- `call(self, inputs, training=None)`: 定义前向传播逻辑。
- `train_step(self, data)`: 重写此方法以控制单步训练流程。
- 2. 重写 train_step 方法
- ​默认行为:
```txt
1. 执行前向传播self.call()
2. 计算损失self.compiled_loss
3. 记录梯度tf.GradientTape
4. 应用优化器self.optimizer.apply_gradients
5. 更新指标self.metrics.update_state
```
- ​自定义点:
- 在重写时,可以插入额外操作(如梯度裁剪、动态权重更新、自定义损失计算)。
---
#### **3. 分布式训练**
- **`tf.distribute` 模块**
- **作用**: 在多设备GPU/TPU或多节点上并行训练。
- **常用策略**:
◦ `MirroredStrategy`: 单机多GPU同步训练。
```python
strategy = tf.distribute.MirroredStrategy()
with strategy.scope():
model = build_model()
```
◦ `MultiWorkerMirroredStrategy`: 多机多GPU异步训练。
---
#### **4. 高级训练工具**
- **`tf.keras.callbacks`**
- **作用**: 在训练过程中注入额外操作(如保存模型、早停、可视化)。
- **常用回调类**:
◦ `ModelCheckpoint`: 保存最佳模型。
◦ `EarlyStopping`: 根据验证指标提前终止训练。
◦ `TensorBoard`: 可视化训练过程。
- **示例**:
- ```python
callbacks = [
ModelCheckpoint('best_model.keras', save_best_only=True),
EarlyStopping(monitor='val_loss', patience=3)
]
```
#### **5. 数据管道优化**
- **`tf.data.Dataset` API**
- **作用**: 高效加载和处理数据,支持并行数据预处理和缓存。
- **常用方法**:
◦ `map()`: 并行应用数据转换函数。
◦ `shuffle()`: 打乱数据顺序。
◦ `batch()`: 分批次处理数据。
- **示例**:
- ```python
dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
dataset = dataset.shuffle(buffer_size=10000).batch(32).prefetch(tf.data.AUTOTUNE)
```
---
#### **总结表**
| **API** | **用途** | **典型场景** |
|------------------------|------------------------------|--------------------------------|
| `model.fit()` | 自动训练流程 | 快速原型开发 |
| `model.train_step()` | 自定义单步训练逻辑 | 特殊损失函数或梯度操作 |
| `tf.distribute` | 多设备/多节点分布式训练 | 大规模模型或硬件资源充足的环境 |
| `tf.keras.callbacks` | 训练过程增强 | 模型保存、早停、可视化 |
| `tf.data.Dataset` | 数据加载与预处理 | 高效数据管道构建 |
### 模型的评估
#### **1. 核心评估API**
##### **(1) `model.evaluate()`**
- **功能**:对模型在指定数据集上的性能进行综合评估。
- **示例**
```python
# 假设 model 是已编译的模型test_dataset 是测试数据集
results = model.evaluate(test_dataset, verbose=2)
print(f"Test loss: {results[0]}, Test accuracy: {results[1]}")
```
- **参数**
- `x`/`y`:输入数据和标签(适用于小批量数据)。
- `dataset``tf.data.Dataset`对象(推荐大数据集)。
- `callbacks`训练回调函数如TensorBoard
- `verbose`:控制输出详细程度。
---
#### **2. 预定义评估指标**
TensorFlow内置了多种评估指标可直接在模型编译或单独调用中使用。
##### **(1) 在模型编译中添加指标**
```python
from tensorflow.keras import metrics
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=[metrics.Accuracy(), metrics.Precision(name='precision'), metrics.Recall(name='recall')]
)
```
- **常用指标**
- `Accuracy`(准确率)
- `Precision`(精确率)
- `Recall`(召回率)
- `AUC`ROC曲线下面积
- `MeanSquaredError`(均方误差)
##### **(2) 单独计算指标**
通过`tf.keras.metrics`动态计算指标:
```python
# 计算预测结果
predictions = model.predict(test_dataset, verbose=0)
# 计算准确率
accuracy = metrics.Accuracy()
accuracy.update_state(y_true, y_pred)
print(f"Custom Accuracy: {accuracy.result().numpy()}")
```
#### Keras 是什么?
- Keras 是一个高级神经网络API最初由 François Chollet 于2015年独立开发旨在简化深度学习模型的构建和训练过程。2017年TensorFlow 官方将其整合为 tf.keras成为 TensorFlow 的核心高阶接口。他的优势是:
- 提供直观的接口(如 Sequential 和 Functional API无需手动编写复杂的前向传播或反向传播代码。
- 内置大量预训练模型和预训练权重,方便迁移学习和微调。
- 支持多种硬件加速,包括 GPU 和 TPU。
- 模型训练和评估的代码简洁易读,便于调试和优化。
#### Keras 的核心概念
- 模型Model神经网络的基本结构可以是顺序模型Sequential或函数式模型Functional
-Layer神经网络的基本单元如全连接层Dense、卷积层Conv2D、池化层MaxPooling2D等。
- 激活函数Activation Function引入非线性如 ReLU、sigmoid、softmax 等。
- 损失函数Loss Function衡量模型预测与真实值之间的差异如均方误差MSE、交叉熵Cross-Entropy等。
- 优化器Optimizer调整模型参数以最小化损失函数如 SGD、Adam、RMSprop 等。