
文章目录
-
- [1. 课前导读](#1. 课前导读)
-
- [1.1 本节课学习目标](#1.1 本节课学习目标)
- [1.2 知识重难点](#1.2 知识重难点)
- [1.3 学习前置条件](#1.3 学习前置条件)
- [1.4 学完可掌握能力](#1.4 学完可掌握能力)
- [1.5 行业应用场景](#1.5 行业应用场景)
- [2. 核心理论精讲](#2. 核心理论精讲)
-
- [2.1 图像分类项目的标准流程](#2.1 图像分类项目的标准流程)
- [2.2 数据增强策略选择](#2.2 数据增强策略选择)
- [2.3 迁移学习原理与微调](#2.3 迁移学习原理与微调)
- [2.4 模型集成](#2.4 模型集成)
- [2.5 超参数调优策略](#2.5 超参数调优策略)
- [3. 环境搭建与工具配置](#3. 环境搭建与工具配置)
- [4. 代码实战教学](#4. 代码实战教学)
-
- [4.1 项目一:MNIST手写数字识别(完整流程)](#4.1 项目一:MNIST手写数字识别(完整流程))
-
- [4.1.1 数据加载与探索](#4.1.1 数据加载与探索)
- [4.1.2 数据预处理](#4.1.2 数据预处理)
- [4.1.3 构建CNN模型(LeNet风格)](#4.1.3 构建CNN模型(LeNet风格))
- [4.1.4 训练配置与回调](#4.1.4 训练配置与回调)
- [4.1.5 评估与可视化](#4.1.5 评估与可视化)
- [4.2 项目二:CIFAR-10日常物体分类(进阶技巧)](#4.2 项目二:CIFAR-10日常物体分类(进阶技巧))
-
- [4.2.1 数据加载与增强](#4.2.1 数据加载与增强)
- [4.2.2 构建深层CNN(带BN和Dropout)](#4.2.2 构建深层CNN(带BN和Dropout))
- [4.2.3 训练与回调配置](#4.2.3 训练与回调配置)
- [4.2.4 评估与结果分析](#4.2.4 评估与结果分析)
- [4.2.5 迁移学习:使用预训练ResNet50](#4.2.5 迁移学习:使用预训练ResNet50)
- [4.2.6 模型集成(简单投票)](#4.2.6 模型集成(简单投票))
- [5. 案例实操演练](#5. 案例实操演练)
-
- [5.1 项目结构](#5.1 项目结构)
- [5.2 超参数调优实验](#5.2 超参数调优实验)
- [5.3 最终模型训练与导出](#5.3 最终模型训练与导出)
- [6. 常见坑点与排错总结](#6. 常见坑点与排错总结)
-
- [6.1 数据预处理坑点](#6.1 数据预处理坑点)
- [6.2 模型训练坑点](#6.2 模型训练坑点)
- [6.3 迁移学习坑点](#6.3 迁移学习坑点)
- [6.4 评估与解释坑点](#6.4 评估与解释坑点)
- [7. 知识点总结 + 课后作业](#7. 知识点总结 + 课后作业)
-
- [7.1 核心知识点梳理](#7.1 核心知识点梳理)
- [7.2 基础作业](#7.2 基础作业)
- [7.3 进阶实操作业](#7.3 进阶实操作业)
- [7.4 思考拓展题](#7.4 思考拓展题)
- [🔗《TensorFlow2.x: 深度学习入门到高阶实战教程》系列课程导航](#🔗《TensorFlow2.x: 深度学习入门到高阶实战教程》系列课程导航)
1. 课前导读
1.1 本节课学习目标
- 完成两个完整的图像分类项目:MNIST手写数字识别、CIFAR-10日常物体分类。
- 掌握图像分类项目的标准流程:数据探索、预处理、模型设计、训练、评估、调优。
- 学会使用混淆矩阵、分类报告等工具分析模型错误。
- 掌握提升CNN分类性能的实用技巧:数据增强、批归一化、学习率调度、早停、模型集成。
- 能够使用预训练模型(如AlexNet、ResNet)进行迁移学习,提升小数据集上的性能。
- 完成模型的保存与加载,用于后续部署。
1.2 知识重难点
| 类别 | 内容 |
|---|---|
| 重点 | 完整项目的工程实现(数据流水线、模型定义、训练回调);迁移学习微调技巧;模型集成(投票/平均) |
| 难点 | 数据增强与验证集/测试集的正确使用;超参数搜索策略(Grid/Random Search);集成学习的权重选择 |
| 易混淆点 | 迁移学习中"特征提取"与"微调"的区别;早停与模型检查点的最佳实践;类别不平衡的处理 |
1.3 学习前置条件
- 已掌握CNN的基本原理和TensorFlow搭建CNN的方法(第21-23课)。
- 熟悉
tf.data数据流水线(第16课)。 - 了解回调函数(第17课)和模型保存(第20课)。
1.4 学完可掌握能力
- 独立完成图像分类项目,从数据到可部署模型。
- 运用多种技巧提升模型准确率,解决过拟合/欠拟合问题。
- 使用迁移学习快速获得高性能模型,减少训练时间。
- 评估模型并解释其错误模式,指导下一步改进。
1.5 行业应用场景
- 手写识别:支票识别、邮政编码识别。
- 物体分类:电商图像自动标注、安防监控场景识别。
- 医疗图像:X光片分类、皮肤病变分类。
- 工业质检:产品缺陷分类。
2. 核心理论精讲
2.1 图像分类项目的标准流程
- 数据获取与探索:了解类别分布、图像尺寸、数据量。
- 数据预处理:归一化、尺寸统一、数据增强(训练集)。
- 数据集划分:训练、验证、测试(通常6:2:2或8:1:1)。
- 模型设计:选择基线模型(简单CNN)或预训练模型。
- 训练配置:损失函数、优化器、评估指标、回调函数。
- 训练与调优:监控验证集性能,调整超参数。
- 评估与解释:混淆矩阵、错误分析。
- 模型导出与部署。
2.2 数据增强策略选择
对于小数据集,数据增强可显著提升泛化能力。常见策略:
- 几何变换:随机翻转(水平)、随机旋转(±15°)、随机缩放、随机裁剪。
- 颜色变换:亮度、对比度、饱和度调整。
- 噪声:高斯噪声、随机擦除。
在TensorFlow中,可使用tf.image或Keras的预处理层(RandomFlip, RandomRotation等)。注意:验证集和测试集只做归一化,不做随机增强。
2.3 迁移学习原理与微调
迁移学习:在大型数据集(如ImageNet)上预训练模型,然后在小数据集上微调。两种策略:
- 特征提取:冻结预训练模型的卷积基,只训练新添加的分类器。适合目标数据集与源数据集相似且数据量小时。
- 微调:解冻部分顶层卷积层,以较小学习率继续训练。适合数据量中等以上时。
在TensorFlow中,可通过tf.keras.applications加载预训练模型(VGG16、ResNet50等)。
2.4 模型集成
集成多个独立训练的模型可降低方差,提升准确率。常见集成方法:
- 投票法:多个模型对同一输入预测,取多数类(分类)或平均(回归)。
- 加权平均:根据验证集性能为每个模型分配权重。
- 堆叠:使用元学习器组合基模型输出。
在深度学习中,集成可在训练阶段(不同的随机种子、不同的数据划分)或通过快照集成(Snapshots)实现。
2.5 超参数调优策略
- 手动调优:根据经验调整学习率、batch size、网络深度等。
- 网格搜索:遍历少量超参数组合,计算量大。
- 随机搜索:随机采样,效率更高。
- 贝叶斯优化:使用高斯过程建模,迭代优化。
对于深度学习,更常用的是学习率调度和自适应优化器(Adam)减少调参负担。
3. 环境搭建与工具配置
沿用第23课环境。需安装scikit-learn用于混淆矩阵和分类报告。
bash
conda activate tf213
pip install scikit-learn matplotlib
创建项目目录结构:
image_classification/
├── mnist_project/
│ ├── mnist_train.py
│ └── models/
└── cifar_project/
├── cifar_train.py
├── models/
└── logs/
导入通用模块:
python
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix, classification_report
import os
import datetime
4. 代码实战教学
4.1 项目一:MNIST手写数字识别(完整流程)
4.1.1 数据加载与探索
python
# 加载MNIST
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
print(f"Train: {x_train.shape}, Test: {x_test.shape}")
print(f"Classes: {np.unique(y_train)}")
# 可视化样本
plt.figure(figsize=(10,5))
for i in range(10):
plt.subplot(2,5,i+1)
plt.imshow(x_train[i], cmap='gray')
plt.title(f'Label: {y_train[i]}')
plt.axis('off')
plt.show()
4.1.2 数据预处理
python
# 归一化并增加通道维度
x_train = x_train.reshape(-1, 28, 28, 1).astype(np.float32) / 255.0
x_test = x_test.reshape(-1, 28, 28, 1).astype(np.float32) / 255.0
# 标签转为one-hot(也可使用sparse categorical crossentropy,这里选择one-hot便于后续混淆矩阵)
y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)
# 划分验证集(从训练集中取10%)
from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size=0.1, random_state=42)
print(f"Train: {x_train.shape}, Val: {x_val.shape}, Test: {x_test.shape}")
4.1.3 构建CNN模型(LeNet风格)
python
def build_mnist_cnn():
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28,28,1)),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(10, activation='softmax')
])
return model
mnist_model = build_mnist_cnn()
mnist_model.summary()
4.1.4 训练配置与回调
python
# 学习率调度
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate=0.001,
decay_steps=1000,
decay_rate=0.9,
staircase=True
)
mnist_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=lr_schedule),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 回调:早停、模型检查点、TensorBoard
callbacks = [
tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True),
tf.keras.callbacks.ModelCheckpoint('models/mnist_best.h5', monitor='val_accuracy', save_best_only=True),
tf.keras.callbacks.TensorBoard(log_dir='logs/mnist/' + datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
]
history = mnist_model.fit(x_train, y_train, batch_size=128, epochs=30,
validation_data=(x_val, y_val), callbacks=callbacks, verbose=1)
4.1.5 评估与可视化
python
# 加载最佳模型
mnist_model.load_weights('models/mnist_best.h5')
test_loss, test_acc = mnist_model.evaluate(x_test, y_test, verbose=0)
print(f"Test accuracy: {test_acc:.4f}")
# 混淆矩阵
y_pred = mnist_model.predict(x_test)
y_pred_class = np.argmax(y_pred, axis=1)
y_true = np.argmax(y_test, axis=1)
cm = confusion_matrix(y_true, y_pred_class)
plt.figure(figsize=(8,6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.title('MNIST Confusion Matrix')
plt.show()
# 错误分析:找出预测错误的样本
incorrect = np.where(y_pred_class != y_true)[0]
print(f"Total incorrect: {len(incorrect)}")
# 展示前9个错误样本
plt.figure(figsize=(10,10))
for i, idx in enumerate(incorrect[:9]):
plt.subplot(3,3,i+1)
plt.imshow(x_test[idx].reshape(28,28), cmap='gray')
plt.title(f'True: {y_true[idx]}, Pred: {y_pred_class[idx]}')
plt.axis('off')
plt.show()
4.2 项目二:CIFAR-10日常物体分类(进阶技巧)
4.2.1 数据加载与增强
python
# 加载CIFAR-10
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()
x_train = x_train.astype(np.float32) / 255.0
x_test = x_test.astype(np.float32) / 255.0
y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)
# 再次划分验证集
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size=0.1, random_state=42)
# 数据增强(使用Keras预处理层)
data_augmentation = tf.keras.Sequential([
tf.keras.layers.RandomFlip("horizontal"),
tf.keras.layers.RandomRotation(0.1),
tf.keras.layers.RandomZoom(0.1),
])
def augment(x, y):
x = data_augmentation(x)
return x, y
# 创建tf.data流水线
batch_size = 64
train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_ds = train_ds.shuffle(50000).batch(batch_size).map(augment, num_parallel_calls=tf.data.AUTOTUNE).prefetch(tf.data.AUTOTUNE)
val_ds = tf.data.Dataset.from_tensor_slices((x_val, y_val)).batch(batch_size).prefetch(tf.data.AUTOTUNE)
test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(batch_size).prefetch(tf.data.AUTOTUNE)
4.2.2 构建深层CNN(带BN和Dropout)
python
def build_cifar_cnn():
model = tf.keras.Sequential([
# Block 1
tf.keras.layers.Conv2D(32, (3,3), padding='same', input_shape=(32,32,3)),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.Conv2D(32, (3,3), padding='same'),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Dropout(0.2),
# Block 2
tf.keras.layers.Conv2D(64, (3,3), padding='same'),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.Conv2D(64, (3,3), padding='same'),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Dropout(0.3),
# Block 3
tf.keras.layers.Conv2D(128, (3,3), padding='same'),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.Conv2D(128, (3,3), padding='same'),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Dropout(0.4),
# 分类头
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(256, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(10, activation='softmax')
])
return model
cifar_model = build_cifar_cnn()
cifar_model.summary()
4.2.3 训练与回调配置
python
# 学习率调度:ReduceLROnPlateau + CosineDecay
lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6)
early_stop = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)
checkpoint = tf.keras.callbacks.ModelCheckpoint('models/cifar_best.h5', monitor='val_accuracy', save_best_only=True)
tensorboard = tf.keras.callbacks.TensorBoard(log_dir='logs/cifar/' + datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
cifar_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
history = cifar_model.fit(train_ds, validation_data=val_ds, epochs=100,
callbacks=[lr_scheduler, early_stop, checkpoint, tensorboard], verbose=1)
4.2.4 评估与结果分析
python
# 加载最佳模型
cifar_model.load_weights('models/cifar_best.h5')
test_loss, test_acc = cifar_model.evaluate(test_ds, verbose=0)
print(f"CIFAR-10 Test Accuracy: {test_acc:.4f}")
# 混淆矩阵
y_true = []
y_pred = []
for x_batch, y_batch in test_ds:
y_true.extend(np.argmax(y_batch.numpy(), axis=1))
y_pred.extend(np.argmax(cifar_model.predict(x_batch, verbose=0), axis=1))
cm = confusion_matrix(y_true, y_pred)
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
plt.figure(figsize=(10,8))
sns.heatmap(cm, annot=True, fmt='d', xticklabels=class_names, yticklabels=class_names, cmap='Blues')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.title('CIFAR-10 Confusion Matrix')
plt.show()
4.2.5 迁移学习:使用预训练ResNet50
python
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.applications.resnet50 import preprocess_input
# 由于ResNet50输入要求224x224,需调整尺寸
def preprocess_resnet(image, label):
image = tf.image.resize(image, (224,224))
image = preprocess_input(image)
return image, label
# 加载预训练模型(不包括顶层)
base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(224,224,3))
base_model.trainable = False # 冻结
# 构建新模型
inputs = tf.keras.Input(shape=(32,32,3))
x = tf.keras.layers.Resizing(224,224)(inputs)
x = preprocess_input(x) # 注意:preprocess_input期望批处理,可在map中做
# 更好的做法:在Dataset的map中做预处理
# 重写数据处理
def preprocess_resnet_map(image, label):
image = tf.image.resize(image, (224,224))
image = tf.keras.applications.resnet50.preprocess_input(image)
return image, label
train_ds_resnet = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_ds_resnet = train_ds_resnet.map(preprocess_resnet_map, num_parallel_calls=tf.data.AUTOTUNE).batch(32).prefetch(1)
val_ds_resnet = tf.data.Dataset.from_tensor_slices((x_val, y_val)).map(preprocess_resnet_map).batch(32).prefetch(1)
test_ds_resnet = tf.data.Dataset.from_tensor_slices((x_test, y_test)).map(preprocess_resnet_map).batch(32).prefetch(1)
base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(224,224,3))
base_model.trainable = False
x = base_model.output
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dense(256, activation='relu')(x)
x = tf.keras.layers.Dropout(0.5)(x)
outputs = tf.keras.layers.Dense(10, activation='softmax')(x)
transfer_model = tf.keras.Model(inputs=base_model.input, outputs=outputs)
transfer_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
history_transfer = transfer_model.fit(train_ds_resnet, validation_data=val_ds_resnet, epochs=20, verbose=1)
test_acc_transfer = transfer_model.evaluate(test_ds_resnet, verbose=0)[1]
print(f"ResNet50 transfer learning test accuracy: {test_acc_transfer:.4f}")
4.2.6 模型集成(简单投票)
python
# 假设我们有cifar_model和transfer_model两个模型,对同一测试集预测
def ensemble_predict(models, dataset):
preds = []
for model in models:
pred = model.predict(dataset, verbose=0)
preds.append(pred)
# 平均概率
avg_pred = np.mean(preds, axis=0)
return np.argmax(avg_pred, axis=1)
# 使用验证集或测试集
models = [cifar_model, transfer_model]
y_ensemble = ensemble_predict(models, test_ds_resnet) # 注意两个模型的预处理需统一
# 若cifar_model未使用resize,需单独处理。这里简化为相同数据源
print("Ensemble done.")
5. 案例实操演练
案例:从零开始完成CIFAR-10项目并达到90%以上准确率
本案例综合上述代码,加入更细致的调优和训练。
5.1 项目结构
创建cifar10_full.py,包含以下函数:
load_and_preprocess(): 加载数据,划分验证集,创建增强流水线。build_model(): 构建深层CNN(可调深度和宽度)。train_model(): 配置回调,训练模型。evaluate_model(): 输出混淆矩阵和分类报告。main(): 串联上述步骤。
5.2 超参数调优实验
使用随机搜索尝试不同学习率、dropout率、卷积核数量。
python
# 简单随机搜索示例
import itertools
learning_rates = [0.001, 0.0005, 0.0001]
dropout_rates = [0.3, 0.5, 0.7]
best_acc = 0
best_params = {}
for lr, dr in itertools.product(learning_rates, dropout_rates):
print(f"Testing lr={lr}, dropout={dr}")
model = build_cifar_cnn(dropout_rate=dr)
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=lr), ...)
history = model.fit(train_ds, validation_data=val_ds, epochs=20, verbose=0)
val_acc = max(history.history['val_accuracy'])
if val_acc > best_acc:
best_acc = val_acc
best_params = {'lr': lr, 'dropout': dr}
print(f"Best: {best_params}, val_acc={best_acc:.4f}")
5.3 最终模型训练与导出
python
# 使用最佳超参数重新训练完整epoch
best_model = build_cifar_cnn(dropout_rate=best_params['dropout'])
best_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=best_params['lr']),
loss='categorical_crossentropy', metrics=['accuracy'])
best_model.fit(train_ds, validation_data=val_ds, epochs=100, callbacks=callbacks)
best_model.save('models/cifar10_final.h5')
6. 常见坑点与排错总结
6.1 数据预处理坑点
- 坑1:将数据增强应用到验证集,导致验证指标不稳定且偏低。确保只对训练集增强。
- 坑2 :迁移学习时,预训练模型的输入尺寸与当前数据集不匹配,需调整尺寸(
tf.image.resize)并使用对应的预处理函数(如preprocess_input)。 - 坑3 :类别不平衡(CIFAR-10相对平衡,但自定义数据可能不平衡),应使用
class_weight或过采样/欠采样。
6.2 模型训练坑点
- 坑4:深层CNN在CIFAR-10上训练不足(epoch少),准确率低。使用早停可自动决定epoch数,但初始建议50以上。
- 坑5:梯度爆炸/消失,尤其在深层网络中。添加BatchNormalization可缓解。
- 坑6:Dropout率过高(>0.7)导致欠拟合,过低无效。建议卷积层后0.2-0.4,全连接层0.5。
6.3 迁移学习坑点
- 坑7 :忘记冻结预训练模型,导致训练初期预训练权重被破坏。设置
base_model.trainable=False,微调时再解冻。 - 坑8:微调时学习率过大,破坏预训练特征。微调阶段应使用较小学习率(如1e-5)。
6.4 评估与解释坑点
-
坑9 :混淆矩阵中类别名称顺序与模型输出顺序不一致,导致错误分析。应确保
class_names与one-hot编码索引一致。 -
坑10:测试集上的指标与验证集差异大,可能因验证集划分不具有代表性。使用交叉验证或增大验证集比例。
7. 知识点总结 + 课后作业
7.1 核心知识点梳理
- 图像分类流程:数据加载、预处理、增强、模型搭建、训练、评估、导出。
- 数据增强:随机翻转、旋转、缩放、亮度调整,有效提升泛化。
- 正则化技巧:BatchNormalization、Dropout、早停。
- 迁移学习:使用预训练模型(ResNet等)作为特征提取器或微调。
- 模型集成:多个模型投票/平均,提升鲁棒性。
- 超参数调优:学习率、dropout率、网络深度等对性能的影响。
7.2 基础作业
- 完成MNIST项目,使用
classification_report输出精确率、召回率、F1分数。 - 修改CIFAR-10项目的CNN,将第一个卷积块的过滤器数量从32改为64,重新训练并对比准确率变化。
- 使用预训练的VGG16替代ResNet50,在CIFAR-10上进行迁移学习,比较两者性能。
7.3 进阶实操作业
任务:在自定义图像数据集上实现分类器
要求:
- 收集或下载一个图像分类数据集(至少3个类别,每类至少200张图片)。可以使用Kaggle数据集或自己拍照。
- 使用
image_dataset_from_directory加载数据,划分训练/验证/测试集。 - 构建一个CNN模型(可使用数据增强和迁移学习两种方法),训练并达到80%以上测试准确率。
- 实现模型集成(至少两个不同结构的模型)进一步提升准确率。
- 撰写简短报告,记录实验过程、准确率曲线和混淆矩阵。
7.4 思考拓展题
-
在实际工业场景中,如果类别严重不平衡(例如99%负例,1%正例),准确率指标不再适用。你会采用哪些评估指标和训练策略?
-
当数据集非常小(例如每类只有几十张图片)时,数据增强和迁移学习哪个更重要?为什么?
-
模型集成虽然能提升准确率,但会成倍增加推理时间。有哪些轻量级集成方法(如快照集成、知识蒸馏)可以在不显著增加推理成本的情况下获得集成效果?
下一课预告:CNN网络调优技巧------我们将深入探讨卷积核选型、步距填充、网络层数优化等高级技巧,以及如何使用可视化工具分析网络内部特征。
🔗《TensorFlow2.x: 深度学习入门到高阶实战教程》系列课程导航
第一部分:基础入门(1-10 课)
第二部分:神经网络核心(11-25 课)
第三部分:进阶网络与框架高阶(26-40 课)
第四部分:企业实战与项目落地(41-50 课)
🌟 感谢您耐心阅读到这里!💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~