标题:基于卷积神经网络的图像分类:一个简单的CNN架构实现与训练
在深度学习领域,模型架构的设计对于模型的性能和计算效率至关重要。本文将介绍如何使用PyTorch库和Hugging Face的Transformers库来构建一个简单的卷积神经网络(CNN)模型,用于图像分类任务。我们将详细解释模型的架构和训练过程,并展示如何在CIFAR-10数据集上进行训练和评估。
1. 模型架构
1.1 卷积层
在图像分类任务中,卷积层是CNN的核心组件。卷积层通过滑动小的滤波器(kernel)来识别图像中的重复模式。本文中,我们定义了两个卷积层:self.conv1
和self.conv2
,分别有6个和16个输出通道,卷积核大小为3x3。
1.2 激活函数
在每个卷积层之后,我们使用ReLU激活函数。ReLU是一个非线性函数,能够引入非线性特性,使网络能够学习更复杂的特征。
1.3 池化层
池化层用于减小特征图的尺寸,减少参数数量,并且可以减少过拟合的风险。本文中,我们定义了两个池化层:self.pool1
和self.pool2
,池化窗口大小为2x2,步长为2。
1.4 全连接层
全连接层用于将特征图的输出转换为最终的分类结果。本文中,我们定义了三个全连接层:self.linear1
、self.linear2
和self.out
,输入特征数分别为576、120和84,输出类别数为10(CIFAR10有10个类别)。
1.5 模型总结
本文中的模型是一个简单的CNN架构,具有以下特点:
- 简化性:这是一个非常基础的模型,适合作为学习CNN架构的起点。
- 计算效率:由于模型的结构相对简单,它在计算上相对高效,适合于资源受限的环境。
- 可扩展性:模型可以很容易地通过添加更多的层或改变层的大小来扩展,以提高性能。
- 模块化:模型的各个部分(如卷积层、池化层和全连接层)可以独立地研究和改进。
2. 训练过程
2.1 数据加载与预处理
我们使用PyTorch的CIFAR10
数据集,并通过ToTensor
转换将图像数据转换为PyTorch张量。我们还定义了一个Compose
转换,用于组合多个转换。
2.2 模型实例化与训练
我们定义了一个名为ImageClassification
的类,该类继承自nn.Module
。在类的__init__
方法中,定义了一系列的网络层,包括卷积层、池化层和全连接层。在train
函数中,我们使用交叉熵损失函数和Adam优化器进行训练。
2.3 模型评估
我们定义了一个名为test07
的函数,用于在验证数据集上评估模型的性能。该函数使用DataLoader
加载验证数据集,并使用pipeline
进行情感分析。
3. 结论
本文介绍了一个简单的CNN架构,用于图像分类任务。我们详细解释了模型的架构和训练过程,并展示了如何在CIFAR-10数据集上进行训练和评估。通过调整模型架构和训练参数,可以进一步提高模型的性能。这个简单的模型是一个很好的起点,可以用来理解CNN的工作原理,并且可以作为基础模型,在实际应用中进行调整和优化。
from torchsummary import summary
import torch
import torch.nn as nn
from torchvision.datasets import CIFAR10
from torchvision.transforms import ToTensor
from torchvision.transforms import Compose
import torch.optim as optim
from torch.utils.data import DataLoader
import time
import matplotlib.pyplot as plt
from torchsummary import summary
from CNN_example.example_fenlei import create_dataset
BATCH_SIZE = 8
class ImageClassification(nn.Module):
# 定义网络结构
def __init__(self):
super(ImageClassification, self).__init__()
# 定义网络层:卷积层+池化层
# 第一个卷积层:输入通道数 3,输出通道数 6,步长 1,卷积核大小 3x3
self.conv1 = nn.Conv2d(3, 6, stride=1, kernel_size=3)
# 第一个池化层:池化窗口大小 2x2,步长 2
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
# 第二个卷积层:输入通道数 6,输出通道数 16,步长 1,卷积核大小 3x3
self.conv2 = nn.Conv2d(6, 16, stride=1, kernel_size=3)
# 第二个池化层:池化窗口大小 2x2,步长 2
self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
# 全连接层
# 第一个全连接层:输入特征数 576,输出特征数 120
self.linear1 = nn.Linear(576, 120)
# 第二个全连接层:输入特征数 120,输出特征数 84
self.linear2 = nn.Linear(120, 84)
# 输出层:输入特征数 84,输出类别数 10(CIFAR10 有 10 个类别)
self.out = nn.Linear(84, 10)
# 定义前向传播
def forward(self, x):
# 卷积+relu+池化
x = torch.relu(self.conv1(x))
x = self.pool1(x)
# 卷积+relu+池化
x = torch.relu(self.conv2(x))
x = self.pool2(x)
# 将特征图做成一个向量的形式:相当于特征向量
x = x.reshape(x.size(0), -1)
# 全连接层
x = torch.relu(self.linear1(x))
x = torch.relu(self.linear2(x))
# 返回输出结果
return self.out(x)
'''
todo 架构意义解释:
在深度学习中,模型架构的设计是非常关键的,它决定了模型能够处理的数据类型、模型的计算复杂度以及模型的性能。对于图像分类任务,常见的模型架构包括卷积神经网络(CNN)和循环神经网络(RNN)等。在这个特定的例子中,使用的是卷积神经网络(CNN)架构,这是因为 CNN 非常适合处理具有固定尺寸和连续空间的图像数据。
这个 `ImageClassification` 类定义了一个简单的 CNN 架构,它包含以下几个关键部分:
1. **卷积层**:`self.conv1` 和 `self.conv2`,用于捕捉图像的局部特征。卷积操作通过滑动一个小的滤波器(kernel)来识别图像中的重复模式。
2. **ReLU 激活函数**:在每个卷积层之后使用 ReLU 激活函数,它是一个非线性函数,能够引入非线性特性,使网络能够学习更复杂的特征。
3. **池化层**:`self.pool1` 和 `self.pool2`,用于减小特征图的尺寸,减少参数数量,并且可以减少过拟合的风险。池化操作通常使用最大池化(`nn.MaxPool2d`)或平均池化(`nn.AvgPool2d`)。
4. **全连接层**:`self.linear1`、`self.linear2` 和 `self.out`,用于将特征图的输出转换为最终的分类结果。全连接层在卷积神经网络的最后阶段使用,以实现分类任务。
5. **reshape 操作**:在将特征图转换为向量之前,使用了 `x.reshape(x.size(0), -1)`,这是为了将二维特征图转换为一维特征向量,以适应全连接层的输入要求。
这个模型的设计具有以下意义:
- **简化性**:这是一个非常基础的模型,适合作为学习 CNN 架构的起点。
- **计算效率**:由于模型的结构相对简单,它在计算上相对高效,适合于资源受限的环境。
- **可扩展性**:模型可以很容易地通过添加更多的层或改变层的大小来扩展,以提高性能。
- **模块化**:模型的各个部分(如卷积层、池化层和全连接层)可以独立地研究和改进。
在实际应用中,为了提高性能,通常会使用更复杂的模型架构,包括更多的层、更复杂的激活函数和更高级的优化技术。但是,这个简单的模型仍然是一个很好的起点,可以用来理解 CNN 的工作原理,并且可以作为基础模型,在实际应用中进行调整和优化。
'''
def train(model, train_dataset):
# 定义损失函数:交叉熵损失函数
criterion = nn.CrossEntropyLoss()
# 定义优化器:使用 Adam 优化器,学习率设置为 1e-3
optimizer = optim.Adam(model.parameters(), lr=1e-3)
# todo 损失函数 与优化器最重要 决定了训练的质量和时间 上来就要选型
# 定义训练的轮数
epoch = 20
# 循环遍历训练轮数
for epoch_idx in range(epoch):
# 创建数据加载器:使用训练数据集,批量大小为 BATCH_SIZE,打乱数据顺序
dataloader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
# 初始化样本数量和总损失
sam_num = 0
total_loss = 0.0
# 开始计时
start = time.time()
# 遍历数据加载器中的每个批次
for x, y in dataloader:
# 将输入图像 x 通过模型进行前向传播
output = model(x)
# 计算损失
loss = criterion(output, y)
# 清空优化器中的梯度
optimizer.zero_grad()
# 反向传播损失
loss.backward()
# 应用梯度更新模型参数
optimizer.step()
# 累加损失
total_loss += loss.item()
# 累加样本数量
sam_num += 1
# 打印当前轮数、平均损失和耗时
print('epoch: %2s loss: %.5f time: %.2fs' % (epoch_idx + 1, total_loss / sam_num, time.time() - start))
# 保存模型状态字典到文件
torch.save(model.state_dict(), 'data/image_classification.pth')
def test07(valid_dataset):
# 创建数据加载器:使用验证数据集,批量大小为 BATCH_SIZE,打乱数据顺序
dataloader = DataLoader(valid_dataset, batch_size=BATCH_SIZE, shuffle=True)
# 实例化模型
model = ImageClassification()
# 从文件中加载模型的状态字典,以便使用已经训练好的模型进行预测
model.load_state_dict(torch.load('data/image_classification.pth'))
# 将模型设置为评估模式,关闭梯度计算和 Dropout 等正则化层
# todo 作用: 将模型设置为评估模式是为了在评估模型时保持一致性和性能,避免由于训练相关的特性(如 Dropout 和 BatchNorm)对模型性能产生不利影响。
model.eval()
# 初始化正确预测的样本数量和总样本数量
total_correct = 0
total_samples = 0
# 遍历数据加载器中的每个批次
for x, y in dataloader:
# 使用模型进行前向传播,得到预测输出
output = model(x)
# 计算预测结果与真实标签的一致性
correct = (torch.argmax(output, dim=-1) == y).sum()
# 累加正确预测的样本数量
total_correct += correct.item()
# 累加总样本数量
total_samples += len(y)
# 打印模型的准确率
print('Acc: %.2f' % (total_correct / total_samples))
# 主函数
if __name__ == '__main__':
# 实例化模型
model = ImageClassification()
# 实例化数据集
train_dataset = create_dataset()
# 调用 train 函数进行训练
train(model, train_dataset)
# 数据集加载
train_dataset, valid_dataset = create_dataset()
# 模型实例化
model = ImageClassification()
# 模型预测
test07(valid_dataset)
标签:nn,卷积,self,神经网络,详解,CNN,import,模型
From: https://blog.csdn.net/qq_45003504/article/details/139585080