在计算机视觉领域,卷积神经网络(CNN)凭借其强大的特征提取能力,成为图像分类任务的首选模型架构。本文将以猫狗图像二分类任务为例,深入讲解如何使用TensorFlow和Keras构建一个完整的CNN模型,涵盖数据预处理、模型构建、训练评估、模型保存与加载,以及单张图片预测等全流程。
本项目的训练模型和训练代码以及检测代码仓库:
https://github.com/zhouxy2003/cat_dog_detect.git
创作不易,如果能帮到你,希望给一个star⭐
cat_dog_detect/
├── main.py # 训练脚本,使用 dataset 中的数据训练 CNN 模型,并保存权重文件
├── detect.py # 检测脚本,加载模型权重并对新图像进行猫狗分类
├── cat_dog_detect.weights.h5 # 已训练好的模型权重文件(由 main.py 生成)
├── createCNN/ # 模型构建模块目录
├── dataset/ # 过大未提供可按照以下示例创建
一、数据预处理:为模型训练奠定基础
数据预处理是模型训练前的关键步骤,其核心目标是将原始图像数据转化为适合模型输入的格式,并通过数据增强技术提升数据的多样性,增强模型的泛化能力。数据集结构如下所示。
dataset
├── training_set
│ ├── cats
│ │ ├── cat_image_1.jpg
│ │ ├── cat_image_2.jpg
│ │ └──...
│ └── dogs
│ ├── dog_image_1.jpg
│ ├── dog_image_2.jpg
│ └──...
└── test_set
├── cats
│ ├── cat_image_3.jpg
│ ├── cat_image_4.jpg
│ └──...
└── dogs
├── dog_image_3.jpg
├── dog_image_4.jpg
└──...
1.1 图像增强:扩充数据集
在猫狗图像分类任务中,数据集的规模和多样性直接影响模型的性能。通过图像增强技术,可以在不增加额外数据采集成本的情况下,生成更多样化的训练样本。
train_datagen = ImageDataGenerator(
rescale=1./255, #像素归一化
shear_range=0.2, #改变图像形状
zoom_range=0.2, #进行缩放
horizontal_flip=True, #水平翻转
)
使用ImageDataGenerator
类进行图像增强,主要操作包括:
- 像素值归一化(
rescale
):将图像像素值从默认的[0, 255]区间缩放到[0, 1],这有助于加快模型的收敛速度,提高训练效率。 - 随机剪切变换(
shear_range
):对图像进行随机角度的剪切,模拟不同视角下的图像变化。 - 随机缩放(
zoom_range
):对图像进行随机比例的缩放,模拟目标在图像中远近不同的视觉效果。 - 随机水平翻转(
horizontal_flip
):以一定概率对图像进行水平翻转,增加样本的多样性,尤其适用于图像左右对称的场景。
1.2 创建数据生成器:批量加载数据
数据生成器负责从磁盘读取图像数据,并按照指定的参数进行预处理和批量加载。在训练过程中,数据生成器会自动从指定目录中读取图像,应用数据增强操作,并将图像和对应的标签以批次的形式输送给模型。
train_set = train_datagen.flow_from_directory(
directory='./dataset/training_set', #数据集路径
target_size=(64,64), #尺寸大小
batch_size=32, #每个批次大小
class_mode='binary' #分类模式:二分类
)
通过flow_from_directory
方法,我们可以方便地将图像数据组织成适合模型训练的格式,同时指定图像尺寸、批次大小和标签模式。
二、构建卷积神经网络:搭建模型架构
CNN的设计需要结合任务特点和数据特性,合理选择网络层数、卷积核大小、激活函数等参数。在猫狗图像分类任务中,我们采用经典的CNN架构,由卷积层、池化层、展平层和全连接层组成。结构图如下所示。
本项目的任务是进行猫🐱与狗🐕的识别,属于典型的二分类问题。在网络结构中,卷积层使用了ReLU激活函数(ReLU(x)=max(0, x))
,以引入非线性特性并加速收敛;在输出层,采用Sigmoid激活函数,将输出映射至[0,1]区间,以便进行二分类判别。
通过tf.keras
构建顺序模型添加每一层
CNN模型
├── 输入层 (图像输入)
├── 第一组卷积层
│ └── 卷积操作 (filters=32, kernel_size=(3,3), activation='relu')
├── 第一组池化层
│ └── 最大池化操作 (pool_size=(2,2), strides=(2,2))
├── 第二组卷积层
│ └── 卷积操作 (filters=32, kernel_size=(3,3), activation='relu')
├── 第二组池化层
│ └── 最大池化操作 (pool_size=(2,2), strides=(2,2))
├── 展平层
│ └── 将多维特征图展平为一维向量
├── 全连接层
│ └── 神经元 (units=128, activation='relu')
└── 输出层
└── 神经元 (units=1, activation='sigmoid')
2.1 卷积层与池化层:特征提取与降维
卷积层是CNN的核心组成部分,通过卷积核在图像上滑动,提取图像的局部特征。每个卷积层后通常会连接一个池化层,用于降低数据维度,减少计算量,同时保留重要特征。
我们构建了两组卷积层和池化层,通过调整卷积核数量和大小,逐步提取图像的高级语义特征。
2.2 展平层与全连接层:特征整合与分类决策
展平层将卷积层和池化层输出的三维特征图转化为一维向量,以便输入到全连接层。全连接层通过学习特征之间的复杂关系,输出最终的分类结果。
在输出层,我们使用sigmoid
激活函数,将输出值映射到[0, 1]区间,用于二分类任务的概率预测。
三、训练与评估模型:优化模型性能
模型训练是调整模型参数以最小化损失函数的过程,而模型评估则用于验证模型在新数据上的泛化能力。
3.1 编译模型:选择优化器和损失函数
在编译模型时,我们需要选择合适的优化器、损失函数和评估指标。对于二分类任务,通常使用binary_crossentropy
作为损失函数,adam
作为优化器,并选择accuracy
作为评估指标。
cnn.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
3.2 训练模型:迭代优化模型参数
通过fit
方法进行模型训练,指定训练数据集、验证数据集和训练轮数。在训练过程中,模型会根据损失函数的反馈不断调整参数,逐步提高分类准确率。使用的数据集约4000张图片。30轮后准确率可达90%左右。
cnn.fit(x=train_set, validation_data=test_set,epochs=30)
四、保存与加载模型权重:持久化模型
为了避免重复训练,我们可以将训练好的模型权重保存到文件中,并在需要时加载使用。这对于部署模型和后续优化非常重要。
cnn.save_weights('cat_dog_detect.weights.h5')
五、单张图片预测:应用模型进行推理
训练好的模型可以用于对单张图片进行预测。首先需要对图片进行预处理,使其格式与训练数据一致,然后输入模型进行预测,最后根据预测结果判断图片中的动物是猫还是狗。
cnn.load_weights('./cat_dog_detect.weights.h5')
test_image = image.load_img('./cod4.jpg', target_size=(64,64,3))
test_image = np.expand_dims(test_image, axis = 0)
result = cnn.predict(test_image)
这里解释一下参数含义:
target_size=(64,64,3)
:因为训练时对输入图像大小调整为64x64,颜色通道为3,即为彩色rgb.
axis = 0
: 我们在构建网络时,需多添加一个维度
Model: "sequential"
┌─────────────────────────────────┬────────────────────────┬───────────────┐
│ Layer (type) │ Output Shape │ Param # │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d (Conv2D) │ (None, 62, 62, 32) │ 896 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D) │ (None, 31, 31, 32) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D) │ (None, 29, 29, 32) │ 9,248 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D) │ (None, 14, 14, 32) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ flatten (Flatten) │ (None, 6272) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense) │ (None, 128) │ 802,944 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense) │ (None, 1) │ 129 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
shape如上所示。
我们该如何知道1代表🐱还是🐕呢,我们可以通过print(train_set.class_indices)
进行获取映射关系,其会将数据集的类别进行自动分类映射。
识别效果如下(图片取自网络,侵权联系删除谢谢):
总结与展望
通过本文的实践,我们完成了一个完整的猫狗图像分类项目,掌握了从数据预处理到模型部署的全流程。然而,这只是CNN应用的起点。希望可以帮您对cnn结果有所了解。
Enjoy Deep learning!🚀