从零开始搭建Jupyter Notebook猫狗分类器
本次实战我们在Jupyter Notebook中完成了猫狗分类器的搭建、训练与评估,从数据预处理到模型优化,覆盖了图像分类任务的核心流程。猫狗分类看似简单,却是计算机视觉的重要基石。在此基础上,我们可以进一步探索更复杂的任务,比如多类别动物分类、目标检测、图像分割等。希望这篇博客能帮助你快速入门机器学习图像分类,动手试试吧!
前言
在计算机视觉领域,猫狗分类是经典的入门任务,既能帮助我们理解图像分类的核心逻辑,也能快速掌握深度学习框架的基础用法。今天,我们就来一步步在Jupyter Notebook中搭建一个猫狗分类器,无需复杂的环境配置,跟着步骤就能完成实战。
一、前期准备:环境与数据集
- 环境配置
本次实战基于Python环境,需要安装几个核心库: numpy 用于数值计算, pandas 辅助数据处理, matplotlib 用于图像可视化, tensorflow 或 pytorch 作为深度学习框架, opencv-python 用于图像预处理。
在Jupyter Notebook的单元格中,我们可以直接安装这些依赖:
!pip install numpy pandas matplotlib tensorflow opencv-python
运行依赖库安装代码后,Jupyter Notebook 单元格输出无 Error 报错,且能看到各库的下载、安装完成提示;导入库的代码执行后,无 ModuleNotFoundError 等导入错误,代表环境配置成功。
安装完成后,导入所有需要的库,这是代码编写的第一步:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
- 数据集准备
猫狗分类的公开数据集可以选择Kaggle的Dogs vs. Cats数据集,该数据集包含25000张标注好的猫狗图片,其中训练集20000张,测试集5000张。
下载数据集后,建议将其整理为如下目录结构,方便后续读取:
# 设置数据集根路径,根据自己的实际路径修改
DATA_ROOT = "./data"
# 训练集与测试集路径
TRAIN_DIR = os.path.join(DATA_ROOT, "train")
TEST_DIR = os.path.join(DATA_ROOT, "test")
# 设置随机种子,保证结果可复现
np.random.seed(42)
tf.random.set_seed(42)
random.seed(42) ```
# 二. 数据集准备
## 1.引入库
代码如下(示例):
```c
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
二、数据预处理:让模型“读懂”图像
图像数据不能直接输入模型,需要经过一系列预处理操作,包括图像读取、尺寸统一、归一化、数据增强等步骤。这一步的核心目标是减少噪声干扰,提升模型的泛化能力。
- 图像读取与尺寸统一
不同的图片尺寸不一,而神经网络的输入需要固定维度,因此我们需要将所有图像缩放至统一大小,比如 224×224 或 128×128 。同时,将图像转换为数组格式,并进行归一化处理——将像素值从 0-255 缩放到 0-1 之间,加快模型收敛速度。
# 定义图像预处理函数:读取、缩放、归一化
def preprocess_image(image_path, target_size=(224, 224)):
# 读取图像,cv2默认读取格式为BGR
img = cv2.imread(image_path)
# 将BGR格式转换为RGB格式(符合人眼视觉习惯与模型输入要求)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 缩放图像到目标尺寸
img = cv2.resize(img, target_size)
# 归一化:将像素值从0-255缩放到0-1区间,加速模型收敛
img = img / 255.0
return img
- 数据增强
训练集数据量有限时,数据增强是提升模型性能的关键技巧。我们可以通过随机翻转、旋转、裁剪、调整亮度等方式,生成更多“新”样本,避免模型过拟合。
# 设置数据增强策略,仅用于训练集,避免验证集和测试集数据泄露
train_datagen = ImageDataGenerator(
# 归一化
rescale=1./255,
# 随机水平翻转,增加样本多样性
horizontal_flip=True,
# 随机旋转±15度
rotation_range=15,
# 随机剪切,剪切强度0.1
shear_range=0.1,
# 随机缩放,缩放范围0.8-1.2倍
zoom_range=0.2,
# 随机宽度偏移
width_shift_range=0.1,
# 随机高度偏移
height_shift_range=0.1,
# 验证集划分比例
validation_split=0.2
)
# 测试集仅做归一化,不做数据增强
test_datagen = ImageDataGenerator(rescale=1./255)
- 构建数据加载器
为了高效地向模型输入数据,需要构建数据加载器,将预处理后的图像按批次传递给模型。同时,将数据集划分为训练集和验证集(通常按8:2的比例),用于监控模型的训练效果。
# 设置图像目标尺寸、批次大小
TARGET_SIZE = (224, 224)
BATCH_SIZE = 32
# 构建训练集数据加载器
train_generator = train_datagen.flow_from_directory(
TRAIN_DIR,
target_size=TARGET_SIZE,
batch_size=BATCH_SIZE,
# 二分类任务设置类别模式为binary
class_mode="binary",
# 选取训练集部分
subset="training",
# 打乱数据
shuffle=True,
seed=42
)
# 构建验证集数据加载器
val_generator = train_datagen.flow_from_directory(
TRAIN_DIR,
target_size=TARGET_SIZE,
batch_size=BATCH_SIZE,
class_mode="binary",
# 选取验证集部分
subset="validation",
shuffle=False,
seed=42
)
# 构建测试集数据加载器
test_generator = test_datagen.flow_from_directory(
TEST_DIR,
target_size=TARGET_SIZE,
batch_size=BATCH_SIZE,
class_mode="binary",
shuffle=False,
seed=42
)
三、模型搭建:选择合适的网络结构
对于图像分类任务,我们有两种选择:从零搭建简单卷积神经网络或使用预训练模型进行迁移学习。后者在小数据集上的效果更优,也是工业界的常用方法。以下代码为迁移学习代码:
def build_transfer_learning_model(input_shape=(224, 224, 3)):
# 加载预训练的VGG16模型,不包含顶层分类器,使用ImageNet权重
base_model = models.VGG16(weights="imagenet", include_top=False, input_shape=input_shape)
# 冻结特征提取层,训练时不更新权重
for layer in base_model.layers:
layer.trainable = False
# 构建自定义分类头
model = models.Sequential([
# 预训练特征提取层
base_model,
# 全局平均池化层,替代Flatten,减少参数量
layers.GlobalAveragePooling2D(),
# 全连接层
layers.Dense(256, activation="relu"),
# Dropout层防止过拟合
layers.Dropout(0.5),
# 二分类输出层
layers.Dense(1, activation="sigmoid")
])
return model
# 实例化迁移学习模型
transfer_model = build_transfer_learning_model()
# 打印模型结构
transfer_model.summary()
首次运行会自动下载 VGG16 预训练权重(单元格显示下载进度),随后生成transfer_model对象;summary()打印模型结构,包含 VGG16 的特征层和自定义分类头,示例输出中会显示 VGG16 的层(如block1_conv1),总参数量约 1400 万左右
四、模型训练:参数设置与训练过程
模型搭建完成后,需要设置训练参数并开始训练。关键参数包括优化器(如Adam、SGD)、损失函数(分类任务常用交叉熵损失)、学习率、训练轮数(epochs) 和批次大小(batch_size)。
- 模型编译
# 编译迁移学习模型
transfer_model.compile(
# 优化器:Adam,学习率0.001
optimizer=keras.optimizers.Adam(learning_rate=0.001),
# 损失函数:二分类交叉熵损失
loss=keras.losses.BinaryCrossentropy(),
# 评估指标:准确率
metrics=["accuracy"]
)
# 编译简单CNN模型
simple_cnn.compile(
optimizer=keras.optimizers.Adam(learning_rate=0.001),
loss=keras.losses.BinaryCrossentropy(),
metrics=["accuracy"]
)
2.开始训练
# 设置训练轮数
EPOCHS = 20
# 定义早停策略:当验证集损失连续3轮不下降时停止训练,防止过拟合
early_stopping = keras.callbacks.EarlyStopping(
monitor="val_loss",
patience=3,
restore_best_weights=True
)
# 训练迁移学习模型
history = transfer_model.fit(
train_generator,
# 每轮训练步数
steps_per_epoch=train_generator.samples // BATCH_SIZE,
# 验证集
validation_data=val_generator,
validation_steps=val_generator.samples // BATCH_SIZE,
# 训练轮数
epochs=EPOCHS,
# 回调函数
callbacks=[early_stopping]
)
- 训练过程可视化
def plot_training_history(history):
# 创建2个子图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 绘制准确率曲线
ax1.plot(history.history["accuracy"], label="Training Accuracy")
ax1.plot(history.history["val_accuracy"], label="Validation Accuracy")
ax1.set_title("Model Accuracy")
ax1.set_xlabel("Epoch")
ax1.set_ylabel("Accuracy")
ax1.legend(loc="lower right")
# 绘制损失曲线
ax2.plot(history.history["loss"], label="Training Loss")
ax2.plot(history.history["val_loss"], label="Validation Loss")
ax2.set_title("Model Loss")
ax2.set_xlabel("Epoch")
ax2.set_ylabel("Loss")
ax2.legend(loc="upper right")
# 显示图像
plt.tight_layout()
plt.show()
# 调用函数绘制曲线
plot_training_history(history)
五、模型评估与预测:检验分类效果
训练完成后,需要用测试集评估模型的最终性能,计算准确率、精确率、召回率等指标。同时,随机选取几张测试集图片,查看模型的分类结果。
- 模型评估
# 使用测试集评估模型性能
test_loss, test_acc = transfer_model.evaluate(test_generator)
print(f"Test Loss: {test_loss:.4f}")
print(f"Test Accuracy: {test_acc:.4f}")
- 单张图片预测
def predict_single_image(model, image_path, class_names=["cat", "dog"]):
# 预处理图像
img = preprocess_image(image_path)
# 增加批次维度,模型输入要求(batch_size, height, width, channels)
img = np.expand_dims(img, axis=0)
# 预测概率
pred_prob = model.predict(img)[0][0]
# 根据概率判断类别
pred_class = class_names[1] if pred_prob > 0.5 else class_names[0]
# 打印结果
print(f"Predicted Class: {pred_class}")
print(f"Prediction Probability: {pred_prob:.4f}")
# 显示图像
plt.imshow(plt.imread(image_path))
plt.title(f"Predicted: {pred_class}")
plt.axis("off")
plt.show()
# 测试单张图片,替换为自己的图片路径
predict_single_image(transfer_model, "./data/test/cat/cat_test.jpg")
predict_single_image(transfer_model, "./data/test/dog/dog_test.jpg")
六、优化与改进:让分类器更精准
- 调整模型结构:增加网络层数、更换预训练模型(如ResNet101比ResNet50更复杂)。
- 优化训练参数:调整学习率、批次大小、训练轮数,尝试不同的优化器。
- 增强数据预处理:增加更多数据增强方式,或使用注意力机制提升特征提取能力。
- 解决过拟合:添加Dropout层、L2正则化,或使用早停(Early Stopping)策略。
七、总结与展望
本次实战我们在Jupyter Notebook中完成了猫狗分类器的搭建、训练与评估,从数据预处理到模型优化,覆盖了图像分类任务的核心流程。
猫狗分类看似简单,却是计算机视觉的重要基石。在此基础上,我们可以进一步探索更复杂的任务,比如多类别动物分类、目标检测、图像分割等。
希望这篇博客能帮助你快速入门机器学习图像分类,动手试试吧!
更多推荐
所有评论(0)