深度学习-CNN案例_图像分类

CIFAR-10数据集5万张训练图像、1万张测试图像、10个类别、每个类别有6k个图像,图像大小32×32×3。下图列举了10个类,每一类随机展示了10张图片:

CNN搭建流程

案例:
    演示CNN的综合案例,图像分类

回顾:深度学习项目的步骤
    1.准备数据集.
        这里我们用的时候 计算机视觉模块 torchvision 自带的 CIFAR10数据集,包含6W张(32,32,3)的图片,5W张训练集,1W张测试集,10个分类,每个分类6K张图片
        需要单独安装一下torchvison 包,即pip install torchvision
    2. 搭建(卷积)神经网络
    3.模型训练
    4.模型测试
卷积层:
    提取图像的局部特征 ——>特征图(Feature Map),计算方式: N = math.floor(W-F+2P)//S  + 1
池化层:
    降维:有最大池化 和 平均池化
    池化只在HW上做调整,通道上不改变

导包

import torch
import torch.nn as nn
from torchvision.datasets import CIFAR10
from torchvision.transforms import ToTensor  # pip install torchvision -i https://mirrors.aliyun.com/pypi/simple/
import torch.optim as optim
from torch.utils.data import DataLoader
import time
import matplotlib.pyplot as plt
from torchsummary import summary

# 每批次样本数
BATCH_SIZE = 8

1. 准备数据集合

def create_dataset():
    # 1. 获取数据集
    # 参1:数据集路径;参2:是否是训练集;参3:数据预处理——>张量数据;参4:是否联网下载(若没有就会联网)
    train_dataset = CIFAR10(root='./data', train=True,transform=ToTensor(), download=True)
    # 2. 获取测试集
    test_dataset = CIFAR10(root='./data', train=False,transform=ToTensor(), download=True)
    # 3. 返回数据集
    return train_dataset, test_dataset

2. 搭建(卷积)神经网络

class ImageModel(nn.Module):
    # 1. 初始化父类成员,搭建神经网络
    def __init__(self):
        # 1.1 初始化父类成员
        super().__init__()
        # 1.2 搭建神经网络
        # 第1个卷积层. 输入3通道,输出6通道,卷积核大小3,步长1,填充0
        self.conv1 = nn.Conv2d(3,6,3,1,0)
        # 第1个池化层,窗口大小2*2,步长2,填充0
        self.pool1 = nn.MaxPool2d(2,2,0)

        # 第2个卷积层. 输入6通道,输出16通道,卷积核大小3*3,步长1,填充0
        self.conv2 = nn.Conv2d(6,16,3,1,0)
        # 第2个池化层,窗口大小 2*2,步长2,填充0
        self.pool2 = nn.MaxPool2d(2,2,0)

        # 第1个隐藏层(全连接层);输入576,输出120
        self.linear1 = nn.Linear(576,120)
        # 第2个隐藏层(全连接层);输入120,输出84
        self.linear2 = nn.Linear(120, 84)
        # 第3个隐藏层(全连接层);输入84,输出10
        self.output = nn.Linear(84, 10)

        # 2. 定义前向传播
    def forward(self,x):
        # 第1层,卷积层(加权求和) + 激励层(激活函数) + 池化层(降维)
        x = self.pool1(torch.relu(self.conv1(x)))

        # 第2层,卷积层(加权求和) + 激励层(激活函数) + 池化层(降维)
        x = self.pool2(torch.relu(self.conv2(x)))

        # 细节:全连接层只能处理二维数据,因此要对数据进行拉平(8,16,6,6)——>(8,576)
        # 参1:样本数(行数),参2:列数(特征数),-1表示自动计算; 8行576列
        x = x.reshape(x.size(0),-1)

        # 第3层:全连接层(加权求和) + 激励层(激活函数)
        x = torch.relu(self.linear1(x))

        # 第4层:全连接层(加权求和) + 激励层(激活函数)
        x = torch.relu(self.linear2(x))
        # 第5层,全连接层(加权求和)——>输出层
        return self.output(x)  # 后续用 多分类交叉熵损失函数CrossEntropyLoss = softmax()激活函数 + 损失计算

3. 模型训练

def train(train_dataset,test_dataset):
    # 1.创建数据加载器;
    # shuffle=True 一句话作用:每个 epoch 开始时,把整个数据集样本顺序彻底打乱
    dataloader = DataLoader(train_dataset,batch_size=BATCH_SIZE,shuffle=True)

    # 2.创建模型对象
    model = ImageModel()

    # 3.创建损失函数对象
    criterion = nn.CrossEntropyLoss()  # 多分类交叉熵损失函数 = softmax()激活函数 + 损失计算
    # 4. 创建优化器对象
    optimizer = optim.Adam(model.parameters(),lr=0.001)
    # 5. 循环遍历epoch,开始每轮的训练动作
    # 5.1 定义变量,记录训练的总轮数
    epochs = 10 # 训练的总轮数,10轮
    # 5.2 遍历,完成每轮的 所有批次的 训练动作
    for epoch_idx in range(epochs):
        # 5.2.1 定义变量,记录总损失,总样本数据量,预测正确样本个数,训练(开始)时间
        total_loss,total_samples,total_correct,start = 0,0,0,time.time()
        # 5.2.2 遍历数据加载器,获取到每批次的数据
        for x,y in dataloader:
            # 切换训练模式
            model.train()
            # 5.2.4 模型预测
            y_pred = model(x)
            # 5.2.5 计算损失
            loss = criterion(y_pred,y)
            # 5.2.6 梯度清零+反向传播+参数更新
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            # 5.2.7 统计预测正确的样本个数
            # print(y_pred) # 批次中,每张图 每个分类的 预测概率
            # # argmax() 返回最大值对应的索引,作为该图片的预测分类
            # print(torch.argmax(y_pred,dim=-1))
            # print((torch.argmax(y_pred,dim=-1) == y).sum()) # 预测正确的样本个数
            total_correct += (torch.argmax(y_pred,dim=-1) == y).sum()

            # 5.2.8 统计当前批次的总损失.
            total_loss += loss.item() * len(y) # [第一批总损失+第二批总损失+...]
            # 5.2.9 统计当前批次的总样本个数
            total_samples += len(y)
            # break 每轮只训练1批,提高训练效率,只有测试会这么写,实际开发绝不要这么做
        # 5.2.10 走这里,说明一轮训练完毕,打印该轮的训练信息
        print(f'epoch:{epoch_idx+1},loss:{total_loss/total_samples:.5f},acc:{total_correct/total_samples:.5f},time:{time.time()-start:.5f}')
        # break 这里写break 意味着只训练一轮
    # 6. 保存模型
    torch.save(model.state_dict(),'image_model.pth')

4. 模型测试

def evaluate(test_dataset):
    # 1. 创建测试集数据加载器
    dataloader = DataLoader(test_dataset,batch_size=BATCH_SIZE,shuffle=True)
    # 2. 创建模型对象
    model = ImageModel()
    # 3. 加载模型参数
    model.load_state_dict(torch.load('image_model.pth')) # pickle文件
    # 4.定义变量,统计预测正确的样本个数与总样本个数
    total_correct,total_samples = 0,0
    # 5. 遍历数据加载器,获取到每批次的数据
    for x,y in dataloader:
        # 5.1 切换模型模式
        model.eval()
        # 5.2 模型预测
        y_pred = model(x) # 这一步输出的是一个原始的logic值,而不是0-1的概率
        # 5.3 因为训练的时候用了CrossEntropyLoss,所以搭建神经网络的时候没有加softmax()激活函数,这里要用argmax()来模拟;
        # argmax()函数功能: 返回最大值对应的索引,充当——>该图片的预测分类.
        y_pred = torch.argmax(y_pred,dim=-1) # -1表示行
        # 5.4 统计预测正确的样本个数
        total_correct += (torch.argmax(y_pred,dim=-1) == y).sum()
        # 5.5 统计总样本个数
        total_samples += len(y)

    # 6. 打印正确率
    print(f'ACC:{total_correct/total_samples:.2f}')

5.测试

if __name__ == '__main__':
    # # 1. 获取数据集
    train_dataset, test_dataset = create_dataset()
    # print(f'训练集:{train_dataset.data.shape},测试集:{test_dataset.data.shape}')
    # print(f'数据集类别:{train_dataset.class_to_idx}') #
    #
    # # 图像展示:
    # plt.figure(figsize=(2,2))
    # plt.imshow(train_dataset.data[1111]) # 索引是11的图像
    # plt.title(train_dataset.targets[1111])
    # plt.show()
    # 2.搭建神经网络
    model = ImageModel()
    # 查看模型参数
    # 参1:模型;参2:输出维度(CHW,通道,高,宽),参3:批次大小
    # summary(model,(3,32,32),batch_size=BATCH_SIZE)

    # 3. 模型训练
    # train(train_dataset,test_dataset)
    # 4. 模型评估
    evaluate(test_dataset)
posted @ 2026-07-23 16:43  王新文  阅读(2)  评论(0)    收藏  举报