自学内容网 自学内容网

Pytorch实现图像分类-水果数据集分类--深度学习大作业

目录

1.概述 

2.设计

3.实现

4.实验 

5.总结


1.概述 

本次深度学习大作业,我使用AlexNet模型对"Fruits-360"数据集中的两部分水果和蔬菜图片进行分类

2.设计

模型设计:Alexnet网络

  • 卷积层部分:构建了一系列卷积层、激活函数、最大池化层以及Dropout层,这一系列操作旨在从原始图像中提取丰富的特征。
  • 全连接层部分:通过计算得到的特征图尺寸动态设置全连接层的输入大小,设计了多层全连接网络,包含ReLU激活、Dropout正则化,最后输出层针对数据集的类别数量(本例中为2)进行调整。

因为输入图像数据为RGB图像,在模型的设计时调整,并在设计全连接层时引入了动态尺寸计算方法,保证了模型的通用性和适应性。

3.实现

 代码如下:


import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import torch.nn.functional as F
from torch import nn, optim

# 数据预处理
image_size = (224, 224)
data_transforms = transforms.Compose([
    transforms.RandomHorizontalFlip(),
    transforms.Resize(image_size),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
])

#导入数据集
import torchvision.datasets as datasets
train_data=datasets.ImageFolder (root='fruits-360-original-size/fruits-360-original-size/Training',transform=data_transforms)
test_data=datasets.ImageFolder (root='fruits-360-original-size/fruits-360-original-size/Test',transform=data_transforms)
# print(train_data.classes)
# print('..............')
# print(test_data.classes)

#DataLoader

batchsize=10#每个批次(batch)中包含的样本数量
train_loader = DataLoader(train_data, batch_size=batchsize, shuffle=True, num_workers=1)
test_loader = DataLoader(test_data, batch_size=batchsize, shuffle=False, num_workers=1)  # 测试时不需打乱数据


#创建模型

class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(3, 96, 5, 1, 2),#输入通道数,输出通道数,卷积核大小,步长,填充(!!!rgb图像所以是三个通道,开始没注意以为灰度图像)
            nn.ReLU(),
            nn.MaxPool2d(3, 2), 
            nn.Conv2d(96, 256, 5, 1, 2),
            nn.ReLU(),
            nn.MaxPool2d(3, 2),
            nn.Conv2d(256, 384, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(384, 384, 3, 1, 1),
            nn.ReLU(),
            nn.Conv2d(384, 256, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(3, 2)
        )
        # 计算全连接层输入大小
        self.fc_input_size = self._get_fc_input_size()
        self.fc = nn.Sequential(
            nn.Linear(self.fc_input_size, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),#随机丢弃
            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(4096, 2)#修改为2因为输出只有两个类
        )

    def forward(self, img):
        # 通过卷积层前向传播,img是输入图像张量
        feature = self.conv(img)
        feature = feature.view(img.size(0), -1)#展平
        # 通过全连接层(fc)进行前向传播,得到最终的输出
        output = self.fc(feature)
        return output
    
    #动态计算全连接层(FC层)所需要的输入尺寸
    def _get_fc_input_size(self):
        # 创建一个与训练/测试时相同尺寸和通道数的随机张量,用于通过卷积层
        x = torch.randn(1, 3, image_size[0], image_size[1])# 其中3对应RGB图像的通道数,image_size是从外部传入的图像预处理后的尺寸,默认为(224, 224)
        x = self.conv(x)
        return x.view(-1).size(0)#展平后的向量长度

# 实例化模型、损失函数和优化器
model = AlexNet().to(device="cuda" if torch.cuda.is_available() else "cpu")
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

# 训练函数
def train(model, device, train_loader, optimizer, criterion):
    model.train()
    # 遍历训练数据加载器中的每个批次
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)#这样更快
        # 梯度清零,防止梯度累积
        optimizer.zero_grad()
        output = model(data)#预测输出
    
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        # 每10个batch打印一次训练信息
        if (batch_idx + 1) % 10 == 0 or (batch_idx + 1) == len(train_loader):
            print(f'训练轮次: {epoch + 1}/{num_epochs} 损失: {loss.item():.6f}')

# 测试函数
def test(model, device, test_loader):
    model.eval()
    test_loss = 0
    correct = 0
    #避免在测试过程中计算和存储梯度,节省内存并加速计算
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += criterion(output, target).item()  # 累加批次损失
            pred = output.argmax(dim=1, keepdim=True)  # 获取预测概率最大的类别索引
            correct += pred.eq(target.view_as(pred)).sum().item()#累加预测正确的数量

    test_loss /= len(test_loader.dataset)  # 平均损失
    # 打印测试结果,包括平均损失、正确预测的总数、总样本数以及准确率
    print(f'\n测试集: 平均损失: {test_loss:.6f}, 正确: {correct}/{len(test_loader.dataset)} ({100. * correct / len(test_loader.dataset):.2f}%)\n')

# 主训练循环
num_epochs = 10  # 设置训练轮数
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

for epoch in range(num_epochs):
    print(f'第{epoch + 1}轮训练开始')
    train(model, device, train_loader, optimizer, criterion)
    test(model, device, test_loader)

4.实验 

实验过程:首先对数据进行预处理,然后导入数据集合和数据加载,然后对模型进行构造,然后对模型进行训练和测试

实验结果如下:

 

5.总结

      在实验中由于使用AlexNet网络对RGB图像进行图像分类,所以不是灰度图像的输入通道为1,而是改成3,一开始没想到这点,然后对于模型的输出来说,由于我是在电脑上跑的,内存不太够,我对于Fruits-360数据集进行删减,最后剩下两个类别,所以模型的输出应该改成2,然后还有一些训练过程中的错误,实现了深度学习的图像分类,锻炼了实践能力以及综合能力

 

 


原文地址:https://blog.csdn.net/m0_74102824/article/details/140606531

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!