深度学习:图像分类任务的卷积神经网络及完整代码实现

news2024/9/25 4:27:21

摘要

本实验旨在构建并训练一个卷积神经网络(CNN)模型,用于图像分类任务。实验中使用了PyTorch框架,并在GPU(或MPS,如果可用)上执行训练和测试。实验结果表明,所构建的CNN模型在训练集和测试集上均取得了良好的性能。图像分类是计算机视觉领域中的一个基础任务,旨在识别图像中的主要对象。卷积神经网络(CNN)因其在图像处理任务中的卓越性能而广泛使用。本实验通过构建一个简单的CNN模型来解决图像分类问题。

方法

数据集

实验使用了自定义的数据集,数据集包含图像路径和对应的标签。数据集被分为训练集和测试集。

数据预处理

使用torchvision.transforms对图像进行预处理,包括调整图像大小到256x256像素,并将图像转换为Tensor。

# 数据预处理转换
data_transforms = {
    'train': transforms.Compose([
        transforms.Resize([256, 256]),  # 调整图像大小
        transforms.ToTensor(),  # 将图像转换为Tensor
    ]),
    'valid': transforms.Compose([
        transforms.Resize([256, 256]),  # 调整图像大小
        transforms.ToTensor(),  # 将图像转换为Tensor
    ])
}

自定义数据集

# 自定义数据集类,继承自PyTorch的Dataset类
class data1(Dataset):
    def __init__(self, file_path, transform=None):
        self.file_path = file_path  # 文件路径,假设是一个文本文件,每行包含图像路径和标签
        self.imgs = []  # 存储图像路径的列表
        self.labels = []  # 存储标签的列表
        self.transform = transform  # 预处理和数据增强的transform

        # 打开文件并读取数据
        with open(self.file_path) as f:
            # 对文件中的每一行进行处理
            samples = [x.strip().split(' ') for x in f.readlines()]
            for img_path, label in samples:
                self.imgs.append(img_path)  # 将图像路径添加到imgs列表
                self.labels.append(label)  # 将标签添加到labels列表

    def __len__(self):
        # 返回数据集中的样本数
        return len(self.imgs)

    def __getitem__(self, idx):
        # 根据索引idx获取一个样本
        image = Image.open(self.imgs[idx])  # 打开图像文件
        if self.transform:  # 如果定义了transform
            image = self.transform(image)  # 应用transform到图像上
        label = self.labels[idx]  # 获取对应的标签
        label = torch.from_numpy(np.array(label, dtype=np.int64))  # 将标签转换为整数类型的Tensor
        return image, label  # 返回图像和标签

创建数据加载器

# 创建训练数据的数据加载器
train_dataloader = DataLoader(
    training_data,  # 训练数据集实例
    batch_size=64,   # 每个批次的样本数量
    shuffle=True     # 是否在每个epoch开始时打乱数据
)

# 创建测试数据的数据加载器
test_dataloader = DataLoader(
    test_data,  # 测试数据集实例
    batch_size=64,  # 每个批次的样本数量
    shuffle=True     # 是否在每个epoch开始时打乱数据
)

选择设备

# 选择设备
device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
print(f"{device}")

定义CNN模型

# 定义CNN模型类,继承自PyTorch的nn.Module
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()  # 调用父类构造函数
        # 定义第一个卷积层,输入通道为3(RGB图像),输出通道为16,卷积核大小为5,步长为1,填充为2
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=16, kernel_size=5, stride=1, padding=2),
            nn.ReLU(),  # ReLU激活函数
            nn.MaxPool2d(kernel_size=2),  # 最大池化层,池化窗口大小为2
        )
        # 定义第二个卷积层,输入通道为16,输出通道为32,卷积核大小为5,步长为1,填充为2
        self.conv2 = nn.Sequential(
            nn.Conv2d(16, 32, 5, 1, 2),
            nn.ReLU(),  # ReLU激活函数
            nn.Conv2d(32, 32, 5, 1, 2),  # 另一个卷积层,增加深度但保持通道数不变
            nn.ReLU(),  # ReLU激活函数
            nn.MaxPool2d(2),  # 最大池化层,池化窗口大小为2
        )
        # 定义第三个卷积层,输入通道为32,输出通道为128,卷积核大小为5,步长为1,填充为2
        self.conv3 = nn.Sequential(
            nn.Conv2d(32, 128, 5, 1, 2),
            nn.ReLU(),  # ReLU激活函数
        )
        # 定义一个全连接层,输入特征数为128*64*64(这需要根据实际的输入图像尺寸和卷积层的输出尺寸来调整),输出特征数为20(假设有20个类别)
        self.out = nn.Linear(128 * 64 * 64, 20)

    def forward(self, x):
        # 定义前向传播过程
        x = self.conv1(x)  # 通过第一个卷积层
        x = self.conv2(x)  # 通过第二个卷积层
        x = self.conv3(x)  # 通过第三个卷积层
        x = x.view(x.size(0), -1)  # 展平特征图,准备输入到全连接层
        output = self.out(x)  # 通过全连接层得到输出
        return output

# 实例化模型
model = CNN()

# 将模型移动到指定的设备(如GPU或CPU)
model = model.to(device)

定义训练函数

# 定义训练函数
def train(dataloader, model, loss_fn, optimizer):
    model.train()
    batch_size_num = 1
    for x, y in dataloader:
        x, y = x.to(device), y.to(device)
        pred = model(x)  # 使用model(x)而不是model.forward(x)
        loss = loss_fn(pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        loss_value = loss.item()
        print(f"{loss_value} {batch_size_num}")
        batch_size_num += 1

定义测试函数

# 定义测试函数
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    model.eval()
    test_loss, correct = 0, 0
    with torch.no_grad():
        for x, y in dataloader:
            x, y = x.to(device), y.to(device)
            pred = model(x)  # 使用model(x)而不是model.forward(x)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct /= size
    print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}")

定义损失函数和优化器

# 定义损失函数和优化器
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

训练与测试模型

# 训练和测试模型
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)

训练多个周期

epochs = 10
for t in range(epochs):
    print(f"epoch{t+1}\n")
    train(train_dataloader, model, loss_fn, optimizer)
print("done")
test(test_dataloader, model, loss_fn)

完整代码

import numpy as np
from torch.utils.data import Dataset, DataLoader
import torch
import torch.nn as nn
from PIL import Image
from torchvision import transforms

# 数据预处理转换
data_transforms = {
    'train': transforms.Compose([
        transforms.Resize([256, 256]),  # 调整图像大小
        transforms.ToTensor(),  # 将图像转换为Tensor
    ]),
    'valid': transforms.Compose([
        transforms.Resize([256, 256]),  # 调整图像大小
        transforms.ToTensor(),  # 将图像转换为Tensor
    ])
}

# 自定义数据集类
class data1(Dataset):
    def __init__(self, file_path, transform=None):
        self.file_path = file_path
        self.imgs = []
        self.labels = []
        self.transform = transform
        with open(self.file_path) as f:
            samples = [x.strip().split(' ') for x in f.readlines()]
            for img_path, label in samples:
                self.imgs.append(img_path)
                self.labels.append(label)

    def __len__(self):
        return len(self.imgs)

    def __getitem__(self, idx):
        image = Image.open(self.imgs[idx])
        if self.transform:
            image = self.transform(image)
        label = self.labels[idx]
        label = torch.from_numpy(np.array(label, dtype=np.int64))
        return image, label

# 实例化训练和测试数据集
training_data = data1(file_path='./train.txt', transform=data_transforms['train'])
test_data = data1(file_path='./test.txt', transform=data_transforms['valid'])

# 创建数据加载器
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)

# 选择设备
device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
print(f"{device}")

# 定义CNN模型
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=16, kernel_size=5, stride=1, padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(16, 32, 5, 1, 2),
            nn.ReLU(),
            nn.Conv2d(32, 32, 5, 1, 2),
            nn.ReLU(),
            nn.MaxPool2d(2),
        )
        self.conv3 = nn.Sequential(nn.Conv2d(32, 128, 5, 1, 2), nn.ReLU())
        self.out = nn.Linear(128 * 64 * 64, 20)  # 这里的尺寸需要根据实际情况调整

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = x.view(x.size(0), -1)
        output = self.out(x)
        return output

# 实例化模型并移动到选择的设备
model = CNN().to(device)

# 定义训练函数
def train(dataloader, model, loss_fn, optimizer):
    model.train()
    batch_size_num = 1
    for x, y in dataloader:
        x, y = x.to(device), y.to(device)
        pred = model(x)  # 使用model(x)而不是model.forward(x)
        loss = loss_fn(pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        loss_value = loss.item()
        print(f"{loss_value} {batch_size_num}")
        batch_size_num += 1

# 定义测试函数
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    model.eval()
    test_loss, correct = 0, 0
    with torch.no_grad():
        for x, y in dataloader:
            x, y = x.to(device), y.to(device)
            pred = model(x)  # 使用model(x)而不是model.forward(x)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct /= size
    print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}")

# 定义损失函数和优化器
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 训练和测试模型
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)

# 训练多个周期
epochs = 10
for t in range(epochs):
    print(f"epoch{t+1}\n")
    train(train_dataloader, model, loss_fn, optimizer)
print("done")
test(test_dataloader, model, loss_fn)

结果

模型在训练集上的表现优于测试集,这可能是由于过拟合。训练过程中的损失逐渐减小,准确率逐渐提高。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2162354.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Cloud Alibaba-(3)OpenFeign【服务调用】

Spring Cloud Alibaba-(1)搭建项目环境 Spring Cloud Alibaba-(2)Nacos【服务注册与发现、配置管理】 Spring Cloud Alibaba-(3)OpenFeign【服务调用】 Spring Cloud Alibaba-(4)Sen…

SeeClick: Harnessing GUI Grounding for Advanced Visual GUI Agents论文学习

首先是惯例强调一下自己的工作是基于视觉的,不是那种拿一个html文件或者UI结构树给模型让他操作的工作。然后提出了一个很有意思的观点,认为Grounding能力(定位能力)对模型表现的影响非常大。 主要novelty就这几个: …

Python 解析 html

一、场景分析 假设有如下 html 文档&#xff1a; 写一段 python 脚本&#xff0c;解析出里面的数据&#xff0c;包括经度维度。 <div classstorelist><ul><li lng"100.111111" lat"10.111111"><h4>联盟店1</h4><p>…

单片机带隙电压基准电路

单片机带隙电压基准电路 一、带隙电压基准电路概述 带隙电压基准电路在单片机中占据着至关重要的地位。它能够为各种模拟集成电路提供稳定的参考电压&#xff0c;确保电路的正常运行。例如&#xff0c;在高精度的比较器中&#xff0c;带隙电压基准电路可以提供一个精确的参考…

电源芯片测试系统如何完成欠压关断/欠压关断滞后?

电源芯片欠压关断测试原理&#xff1a; 在测试芯片的欠压关断过程中我们会测试到芯片的启动电压和欠压关断滞后电压&#xff0c;所以这三个指标可以一起进行测量;而测试这些指标我们需要一台电源和数字万用表。 电源芯片欠压关断的测试需要将电源的接入芯片进行供电&#xff…

稳定为恒定功率负载供电的 DC/DC 转换器

恒定功率负载 (CPL) 存在于电动汽车、电信设备、电力电子设备等各种应用中。这些 CPL 是无论施加的电压或电流如何变化都保持恒定功耗的电气负载。与呈现恒定电阻的电阻负载不同&#xff0c;CPL 具有随电压或电流变化而变化的动态阻抗&#xff0c;即&#xff0c;当负载两端的电…

Vue的工程化和element快速入门

vue项目的创建&#xff1a; vue项目的启动方式&#xff1a; vue项目开发流程&#xff1a; 代码示例&#xff1a; <!-- <script>//写数据export default{data(){return{msg: 上海}}} </script> --><script setup>import {ref} from vue;//调用ref函数&…

网页护眼宝——全方位解析 Chrome Dark Reader 插件

网页护眼宝——全方位解析 Chrome Dark Reader 插件 1. 基本介绍&#xff1a;Chrome 插件的力量与 Dark Reader 的独特之处 随着现代浏览器的功能越来越强大&#xff0c;Chrome 插件为用户提供了极大的定制化能力。从广告屏蔽、性能优化到页面翻译&#xff0c;Chrome 插件几乎…

python如何匹配换行符

如下所示&#xff1a; p1 r(?<<div class"ds_cr">)(.*?)(?<div id"pageurl">) #这样采集html时出错&#xff0c;采集不到数据&#xff0c;正则中.是不能匹配 换行符&#xff0c;改成如下&#xff1a; p1 r(?<<div class"d…

Nanite缺失项目设置问题

今天新建虚幻引擎项目时 , 编辑器右下角收到这个提示 , 缺失项目设置&#xff01; 使用Nanite资产需要Shader Model 6&#xff08;SM6&#xff09;。请在此启用&#xff1a; 项目设置-> 平台-> Windows->D3D12目标着色器格式如未启用&#xff0c;Nanite资产将无法正常…

【研赛F题成品论文】24华为杯数学建模研赛F题成品论文+可运行代码丨免费分享

2024华为杯研究生数学建模竞赛F题精品成品论文已出&#xff01; F 题 X射线脉冲星光子到达时间建模 摘要 X射线脉冲星具有高度稳定的自转周期&#xff0c;被广泛应用于深空导航和时间基准的维护。本文针对Crab脉冲星&#xff0c;建立了光子到达时间的数学模型&#xff0c;并模…

初始MYSQL数据库(7)—— 视图

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; MYSQL 引言 前面我们学习MySQL数据库时&#xff0c;创建表之后&#xff0c;会在表中插入数据&#xff0c;在需要的时候&#xff0c;也会进行…

Qt-QComboBox输入类控件(31)

目录 描述 核心方法 核心信号 使用 代码方式 界面操作方式 动态使用 如何看待输入输出 String与QString互相转化 描述 一个可以下拉的输入框 核心方法 addItem(constQString&)添加⼀个条⽬currentIndex()获取当前条⽬的下标 从0开始计算.如果当前没有条⽬被选中…

MySQL的msi版本9.0在安装过程总结和需要注意的地方

下载 参考文档 [官方包快速下载]&#xff08;https://dev.mysql.com/downloads/mysql/&#xff09; 使用zip文件安装可参考&#xff0c;这种直接把zip安装包解压到想要放的地方&#xff0c;并安装其中的方式一步步修改数据地址等配置即可。 个人使用了msi的安装文件 msi版本…

Vue3:快速生成模板代码

目录 一.模板代码 1.提供基础结构 2.定义组件名称 3.初始化数据和方法 4.应用样式 5.提高开发效率 二.操作 1.点击右下角设置按钮选择代码片段 2.输入vue.json&#xff0c;打开vue.json文件 3.构造模板 4.模板代码 5.使用 6.效果 一.模板代码 Vue3快速生成模板代…

通过document获取节点元素

1.层级节点 <ul><li id"li1">1</li><li>2</li><li id"li3">3</li><li>4</li><li>5</li></ul><script>//获取id名为li1的元素赋值给li1let li1document.getElementById(li…

为什么越来越多的视频监控AI分析做到了摄像头上?

在安防行业&#xff0c;视频监控已经非常广泛&#xff0c;是无可替代的基础信息化设施。早期的视频监控只是简单的通过摄像机对画面进行记录&#xff0c;然后通过记录的画面服务入侵探测和震慑burglars。随着近年来人工智能技术的兴起&#xff0c;人们越来越希望利用AI计算机的…

【Go】Go 环境下载与安装教程(Windows系统)

引言 Go&#xff0c;也被称为Golang&#xff0c;是一种静态类型&#xff0c;编译型的编程语言&#xff0c;由Google设计和开发。Go语言的设计目标是“解决软件开发中的一些问题”&#xff0c;特别是在大规模软件系统的构建和维护方面。 下载安装包 打开官网下载页面&#xff…

排序----基数排序、桶排序(附排序总结)

一、基数排序 从个位开始往高位不断排序&#xff0c;把各个数字按每一位的顺序排起来。 二、桶排序 建立一个指针数组&#xff0c;指针指向一个链表&#xff0c;然后再对链表排序。永远只建立一个筒&#xff0c;只适用于全是两位数或者全是三位数的排序。 三、总结 归并排序当…

如何把pdf转换成word文档?6种转换方法看完就学会

在日常工作和学习中&#xff0c;PDF文件和Word文档可以说是两种非常常见的文件格式了。然而&#xff0c;PDF文件的不可编辑性常常让我们感到困扰&#xff0c;在遇到需要编辑修改内容的PDF文件时&#xff0c;就需要将其转换成Word文档来便于编辑修改&#xff0c;那么该怎么转换呢…