第24课:TensorFlow|图像分类实战训练【手写数字、日常图像分类完整项目】

文章目录

    • [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 图像分类项目的标准流程

  1. 数据获取与探索:了解类别分布、图像尺寸、数据量。
  2. 数据预处理:归一化、尺寸统一、数据增强(训练集)。
  3. 数据集划分:训练、验证、测试(通常6:2:2或8:1:1)。
  4. 模型设计:选择基线模型(简单CNN)或预训练模型。
  5. 训练配置:损失函数、优化器、评估指标、回调函数。
  6. 训练与调优:监控验证集性能,调整超参数。
  7. 评估与解释:混淆矩阵、错误分析。
  8. 模型导出与部署

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 基础作业

  1. 完成MNIST项目,使用classification_report输出精确率、召回率、F1分数。
  2. 修改CIFAR-10项目的CNN,将第一个卷积块的过滤器数量从32改为64,重新训练并对比准确率变化。
  3. 使用预训练的VGG16替代ResNet50,在CIFAR-10上进行迁移学习,比较两者性能。

7.3 进阶实操作业

任务:在自定义图像数据集上实现分类器

要求:

  • 收集或下载一个图像分类数据集(至少3个类别,每类至少200张图片)。可以使用Kaggle数据集或自己拍照。
  • 使用image_dataset_from_directory加载数据,划分训练/验证/测试集。
  • 构建一个CNN模型(可使用数据增强和迁移学习两种方法),训练并达到80%以上测试准确率。
  • 实现模型集成(至少两个不同结构的模型)进一步提升准确率。
  • 撰写简短报告,记录实验过程、准确率曲线和混淆矩阵。

7.4 思考拓展题

  1. 在实际工业场景中,如果类别严重不平衡(例如99%负例,1%正例),准确率指标不再适用。你会采用哪些评估指标和训练策略?

  2. 当数据集非常小(例如每类只有几十张图片)时,数据增强和迁移学习哪个更重要?为什么?

  3. 模型集成虽然能提升准确率,但会成倍增加推理时间。有哪些轻量级集成方法(如快照集成、知识蒸馏)可以在不显著增加推理成本的情况下获得集成效果?


下一课预告:CNN网络调优技巧------我们将深入探讨卷积核选型、步距填充、网络层数优化等高级技巧,以及如何使用可视化工具分析网络内部特征。


🔗《TensorFlow2.x: 深度学习入门到高阶实战教程》系列课程导航

去订阅

第一部分:基础入门(1-10 课)

第二部分:神经网络核心(11-25 课)

第三部分:进阶网络与框架高阶(26-40 课)

第四部分:企业实战与项目落地(41-50 课)
🌟 感谢您耐心阅读到这里!

💡 如果本文对您有所启发欢迎:

👍 点赞📌 收藏 📤 分享给更多需要的伙伴。

🗣️ 期待在评论区看到您的想法, 共同进步。

🔔 关注我,持续获取更多干货内容~

🤗 我们下篇文章见~

相关推荐
Herlie1 小时前
2026,当AI不再是“玩具”:01Agent如何终结内容创作的“碎片化时代”?
人工智能
2601_967659881 小时前
AI重构流量入口,本地GEO服务正在成为一门新生意
人工智能
是翎1 小时前
Vibe Coding零基础入门:六步工作流拆解
大数据·人工智能·学习·机器学习·数据挖掘
residual_fan1 小时前
特征级SMOTE(Feature-level SMOTE)论文分享
人工智能·算法·数据挖掘·数据分析
仙魁XAN1 小时前
【Codex + Deepseek】第 2 篇:什么是 vibe coding:自然语言驱动开发的真实含义
人工智能·codex·deepseek·vibe coding
财复视界1 小时前
光智科技全景透视:一家被“光学元件”标签遮蔽的稀散金属材料平台
大数据·人工智能·科技
黑科技工坊1 小时前
2026年口碑载道:铝面板定制供应商优选指南
大数据·人工智能·python
ai小陈1 小时前
PyTorch实验可复现实战:随机种子、依赖锁定与配置归档
人工智能·pytorch·python·深度学习·ai·gpu算力
喜欢睡觉1 小时前
从"堵车"到"水管":一文搞懂 SSE 流式输出与大模型结构化解析
人工智能