卷积神经网络实现CIFAR10数据集分类

CIFAR10数据集

        CIFAR10数据集中有5万张训练集,1万张测试集。针对是十分类的问题,其中包括的类别如下图所示:

        CIFAR10数据集中的图像都是3通道,尺寸为32*32。 

        在PyTorch中,通过torchvision下的datasets来加以实现的,实例代码如下:

from torchvision import datasets,transforms
from torch.utils.data import DataLoader

#root:数据集的根目录
#train:是否为训练集
#transform:可以将PIL和numpy格式的数据从[0,255]范围转换到[0,1]。原始数据的shape是(H x W x C),转换后shape会变为(C x H x W)
#download:是否下载
train_dataset = datasets.CIFAR10(root="data/CIFAR10",train=True,transform=transforms.ToTensor(),download=True)
test_dataset = datasets.CIFAR10(root="data/CIFAR10",train=False,transform=transforms.ToTensor(),download=True)
#训练集长度
print(len(train_dataset))
#测试集长度
print(len(test_dataset))
#数据集类别
print(train_dataset.classes)
#训练集最后一张图片的类别
print(train_dataset.targets[49999])
#训练集最后一张图片的形状
print(train_dataset.data[49999].shape)
#训练集最后一张图片的数据
print(train_dataset.data[49999])
#测试集最后一张图片的类别
print(test_dataset.targets[9999])
#测试集最后一张图片的形状
print(test_dataset.data[9999].shape)
#测试集最后一张图片的数据
print(test_dataset.data[9999])

#上述的ToTensor在dataloader中调用
train_dataloader = DataLoader(dataset=train_dataset,batch_size=5,shuffle=True)
for i,(img,tag) in enumerate(train_dataloader):
    print(tag)
    print(img.shape)
    print(img)
    break

神经网络设计

        因为使用的数据集为CIFAR10数据集,最终做的还是一个分类问题。所以在神经网络中包含了卷积神经网络和全连接神经网络。使用全连接神经网络对最终的分类概率进行求解

残差模块

        在进行网络设计之前先设计出一个残差的模块。注意残差模块的输入通道和输出通道必须要是相等的。

class Res_Net(nn.Module):
    def __init__(self,c_in,c_out,c):
        super(Res_Net, self).__init__()
        self.layer = nn.Sequential(
            #输入通道,输出通道,卷积核尺寸,步长,padding,参数b
            nn.Conv2d(c_in,c,3,1,padding=1,bias=True),
            nn.ReLU(),
            nn.Conv2d(c,c_out,3,1,padding=1,bias=True),
            nn.ReLU()
        )
    
    def forward(self,x):
        return self.layer(x) + x

网络设计

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #卷积
        self.conv_layer = nn.Sequential(
            #将3通道的图片转化为64通道
            nn.Conv2d(3,64,3,1,padding=1),
            nn.ReLU(),
            #最大池化
            nn.MaxPool2d(2,2),
            nn.ReLU(),
            #残差模块
            Res_Net(64,64,64),

            nn.Conv2d(64,128,3,1),
            nn.ReLU(),
            Res_Net(128,128,128),
            Res_Net(128,128,128),

            nn.Conv2d(128,256,3,1),
            nn.ReLU(),
            Res_Net(256,256,256),
            Res_Net(256,256,256),
            Res_Net(256,256,256),

            nn.Conv2d(256,512,3,1),
            nn.ReLU(),
            Res_Net(512,512,512)
        )
        #全连接
        self.linear_layer = nn.Sequential(
            #输入为卷积的输出
            nn.Linear(512*10*10,1024),
            nn.ReLU(),
            #抑制全连接神经网络,减小运算量
            nn.Dropout(0.5),
            nn.Linear(1024,512),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(512,10),
            #softmax激活,10个类别的真实概率
            nn.Softmax(dim=1)
        )
    def forward(self,x):
        conv_out = self.conv_layer(x)
        linear_in = conv_out.reshape(-1,512*10*10)
        linear_out = self.linear_layer(linear_in)
        return linear_out

测试网络

if __name__ == '__main__':
    net = Net()
    print(net)
    x = torch.randn(3,3,32,32)
    result = net.forward(x)
    print(result.shape)
    print(result)

模型训练

import torch
from torchvision import datasets,transforms
from torch.utils.data import DataLoader
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from Net import Net

#如果有cuda,则用cuda训练,没有则使用cpu训练
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")

class Train():
    def __init__(self):
        #训练集
        self.train_dataset = datasets.CIFAR10(root="data/CIFAR10",train=True,transform=transforms.ToTensor(),download=True)
        #测试集
        self.test_dataset = datasets.CIFAR10(root="data/CIFAR10",train=False,transform=transforms.ToTensor(),download=True)
        #训练集加载器
        self.train_dataloader = DataLoader(dataset=self.train_dataset,batch_size=500,shuffle=True)
        #测试集加载器
        self.test_dataloader = DataLoader(dataset=self.test_dataset,batch_size=100,shuffle=True)
        #创建网络
        self.net = Net()
        #网络位置
        self.net.to(DEVICE)
        #优化器
        self.opt = torch.optim.Adam(self.net.parameters())
        #损失函数:均方差
        self.loss_func = nn.MSELoss()
        #SummaryWriter类可以在指定文件夹生成一个事件文件,这个事件文件可以对TensorBoard解析。
        self.summaryWriter = SummaryWriter("logs")

    def __call__(self, *args, **kwargs):
        #训练轮次
        for epoch in range(1000):
            #每一轮次训练总损失
            sum_loss = 0
            #加载数据
            for i,(img,tag) in enumerate(self.train_dataloader):
                self.net.train()#训练模式
                img,tag = img.to(DEVICE),tag.to(DEVICE)#将数据放在cuda上
                out = self.net.forward(img)#计算结果
                one_hot_tag = nn.functional.one_hot(tag,10).float()#制作one_hot标签
                loss = self.loss_func(out,one_hot_tag)#计算损失
                sum_loss = sum_loss + loss
                self.opt.zero_grad()#清空梯度
                loss.backward()#反向求导
                self.opt.step()#更新参数
            avg_loss = sum_loss/len(self.train_dataloader)
            print("训练轮次:{}".format(epoch))
            print("训练损失:{}".format(avg_loss))
            #每一轮次测试总损失
            sum_test_loss = 0
            #每一轮次测试总分数
            sum_score = 0
            with torch.no_grad():#不进行梯度下降操作,节约空间
                #加载数据
                for i,(img,tag) in enumerate(self.test_dataloader):
                    self.net.eval()#测试模式
                    img,tag = img.to(DEVICE),tag.to(DEVICE)#将数据放在cuda上
                    test_out = self.net.forward(img)#计算结果
                    one_hot_tag = nn.functional.one_hot(tag,10).float()#制作one_hot标签
                    test_loss = self.loss_func(test_out,one_hot_tag)#计算损失
                    sum_test_loss = sum_test_loss + test_loss
                    out_label = torch.argmax(test_out,dim=1)
                    tag_label = torch.argmax(one_hot_tag,dim=1)
                    score = torch.mean(torch.eq(out_label,tag_label).float())#计算得分
                    sum_score = sum_score + score
                avg_test_loss = sum_test_loss/len(self.test_dataloader)
                avg_score = sum_score/len(self.test_dataloader)
                print("  ")
                print("测试损失:{}".format(avg_test_loss))
                print("测试得分:{}".format(avg_score))
                print("========================")
                #保存训练参数
                torch.save(self.net.state_dict(),f"weights/{epoch}.pt")
                #训练损失可视化:图名 y值 x值
                self.summaryWriter.add_scalars("loss",{"train_loss":avg_loss,"test_loss":avg_test_loss},epoch)

if __name__ == '__main__':
    train = Train()
    train()

        这里面提到了SummaryWriter,这里介绍两个作图方法:add_scalar和add_scalars。首先在__init__中创建了SummaryWriter类的对象,通过这个对象来调用上述方法。两个方法的区别就是一个只有一个y值,而另外一个可以有多个y值(以字典的形式存在)

        在运行项目后,找到项目所在的文件夹输入cmd

 进入命令行模式之后输入tensorboard --logdir=logs,回车后复制下面出现的网址即可。这里的logs就是在创建类对象时传入的参数,也就是文件存储的位置。

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值