当前位置:   article > 正文

CIFAR-10数据集分类实验报告_cifar10实验报告

cifar10实验报告

本篇文章只是一篇CIFAR-10数据集分类简介,是我的一门课程的大作业,从BP网络进行分类到CNN进行分类。
程序贴在最后!!!

1 开发环境

目前主流的神经网络框架有Tensorflow,Pytorch,MXNET,Keras等。本次实验使用Pytroch深度学习框架。PyTorch看作加入了GPU支持的numpy,并且它是一个拥有自动求导功能的强大的深度神经网络。

2 BP神经网络相关知识

2.1 激活函数

  • 激活函数的作用是加入非线性因素,从而提高神经网络对模型的表达能力,解决线性模型所不能解决的问题。
    在这里插入图片描述
    在这里插入图片描述

  • 上图是sigmoid激活函数。

  • 计算量大,反向传播求误差梯度时,求导涉及除法。

  • 反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。
    在这里插入图片描述
    在这里插入图片描述

  • 上图是ReLU激活函数。

  • ReLU 的收敛速度会比 sigmoid 快很多。

2.2 损失函数

在这里插入图片描述

  • MSE损失更适合用于回归问题,比如房价预测,对于分类问题,MSE Loss不能很好的逼近目标。
    在这里插入图片描述
  • 交叉熵损失,以二分类为例。该损失更适合用于分类问题。

3 CIFAR-10数据集

在这里插入图片描述

  • 该数据集分为训练集和测试集,一共有10种动物。其中,训练集有50000张图片,测试集有10000张图片,训练集和测试集不重叠,图片大小为32 * 32 * 3。

4 BP网络实验

  • SGD(随机梯度下降)优化策略。SGD就是每一次随机抽取一个mini-batch,迭代计算mini-batch的梯度,然后对参数进行更新。weight decay(权重衰减):设置为5e-4,防止过拟合,是放在正则项(regularization)前面的一个系数,正则项一般指示模型的复杂度。momentum(动量):设置为0.9,提高收敛速度。学习率设置为0.01,ReLU实验的学习率为0.005。
  • 引入Batchsize,设置为128,通过并行化提高内存的利用率。就是尽量让你的GPU满载运行,提高训练速度;适当Batch Size使得梯度下降方向更加准确。
  • 输入是将32 * 32 * 3的图像展平为3072维的图像特征,输出是10维。
  • 总共学习100个epochs。
  • 从隐藏层神经元个数、激活函数和隐藏层层数三个角度实验,证明对BP网络的影响。
  • 实验并没有对学习率有一个很好的调整,只是大范围的确定了学习率,所以训练的精度不代表模型最好精度。

4.1 三层BP网络隐藏层神经元个数

在这里插入图片描述

  • 如图,是三层BP网络,使用sigmoid激活函数,将损失函数改为交叉熵损失,而不是使用均方差MSE损失。
    在这里插入图片描述

  • 上图是确定三层BP网络确定隐藏层神经元个数的经验。
    在这里插入图片描述
    在这里插入图片描述

  • 如图,对三层BP网络的隐藏层分别设置为8,2048和10240个神经元。

  • 对于隐藏层设置为8个神经元,神经元个数太少会导致网络表达能力太弱,无法对特征进行正确的表达。

  • 对于隐藏层设置为10240个神经元,神经元个数太多不一定就能够对特征有正确的表达,而且神经元个数过大容易导致模型泛化能力较差。

  • 由上述经验确定的隐藏层设置为2048个神经元,效果最好。
    在这里插入图片描述
    在这里插入图片描述

  • 分别选择512,2048,4096个神经元,可以看到512个神经元相对于2048和4096个神经元稍微差一点,而2048和4096个神经元效果相似。

4.2 激活函数Sigmoid和ReLU

在这里插入图片描述
在这里插入图片描述

  • 使用三层BP网络实验,隐藏层神经元个数为2048,该实验只改变了两个模型的激活函数。
  • 可以看到ReLU激活函数明显优于Sigmoid激活函数。
  • ReLU收敛速度更快,且能使损失收敛到一个更小的值。
    在这里插入图片描述
    在这里插入图片描述
  • 注意这里有一个尖峰,损失突然增大,我个人的理解是我只固定了一个学习率,当损失很小的适合应该使用小学习率。

4.3 隐藏层层数

在这里插入图片描述

  • 四层BP网络,隐藏层增加一层。隐藏层的神经元个数为2048。
    在这里插入图片描述
    在这里插入图片描述

  • 如图所示,粉色和紫色分别表示4层BP网络和3层BP网络,他们使用Sigmoid激活函数。

  • 层数的增加反而训练收敛速度变慢,看测试准确率几乎相似,,说明层数增加并没有对特征有个更好的非线性表示,这有可能是我参数没调好,也有可能是Sigmoid激活函数两端梯度为0,梯度不均匀,训练不稳定。
    在这里插入图片描述
    在这里插入图片描述

  • 在上述实验基础上,将Sigmoid函数改为ReLU函数,可以看到,层数增加,模型的收敛速度更快,精度更高,能更好的表示非线性。

5 卷积神经网络

  • BP网络实验我将图片的像素展平为32 * 32 * 3的数组,将该数组作为这张图片的特征。实际上可以将分类问题实际上是特征提取之后加全连接层进行分类,这里提取特征就可以使用效率更高的CNN卷积神经网络。
    在这里插入图片描述

在这里插入图片描述

5.1 LeNet-5

在这里插入图片描述

  • 首先进行卷积操作,提取图片特征后,将特征展平用全连接层进行分类。
    在这里插入图片描述
  • 网络结构,假设原来图像大小32 * 32 * 3,conv1将其变为16 * 16 * 6,conv2经过第一个Conv卷积核变为12 * 12 * 16,然后经过MaxPool变为6 * 6 * 16,然后输入到全连接层。

5.2 自制CNN

    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(3, 8, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(8, 16, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.conv3 = nn.Sequential(
            nn.Conv2d(16, 32, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.conv4 = nn.Sequential(
            nn.Conv2d(32, 64, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.fc1 = nn.Sequential(
            nn.Linear(64 * 2 * 2, 120),
            nn.ReLU()
        )
        self.fc2 = nn.Sequential(
            nn.Linear(120, 84),
            nn.ReLU()
        )
        self.fc3 = nn.Linear(84, 10)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 使用大小为3的卷积核

5.3 实验

在这里插入图片描述
在这里插入图片描述

  • 如图,使用卷积神经网络效果要远远好于BP网络。

6 代码

import torch
from torch.utils import data
import torch.nn as nn
from tqdm import tqdm
import wandb
import torchvision.transforms as transforms
import torchvision

class BP_model(nn.Module):
    def __init__(self):
        super(BP_model, self).__init__()
        self.fc1 = nn.Linear(32 * 32 * 3, 2048) # 线性层
        self.fc2 = nn.Linear(2048, 2048)
        self.fc3 = nn.Linear(2048, 10)

    def forward(self, x):
        out = x.view(-1, 32 * 32 * 3) # 展平处理
        out = nn.ReLU()(self.fc1(out))
        out = nn.ReLU()(self.fc2(out))
        out = self.fc3(out)
        return out

class LeNet5(nn.Module):
    def __init__(self):
        super(LeNet5, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(3, 6, 5, 1, 2), # 卷积核 原来通道数 转换后通道数 卷积核大小 步长 填充
            nn.ReLU(), # 激活函数
            nn.MaxPool2d(2) # 最大池化层
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(6, 16, 5, 1, 0),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.fc1 = nn.Sequential(
            nn.Linear(16 * 6 * 6, 120),
            nn.ReLU()
        )
        self.fc2 = nn.Sequential(
            nn.Linear(120, 84),
            nn.ReLU()
        )
        self.fc3 = nn.Linear(84, 10)
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(-1, 16 * 6 * 6)
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(3, 8, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(8, 16, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.conv3 = nn.Sequential(
            nn.Conv2d(16, 32, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.conv4 = nn.Sequential(
            nn.Conv2d(32, 64, 3, 1, 1),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )
        self.fc1 = nn.Sequential(
            nn.Linear(64 * 2 * 2, 120),
            nn.ReLU()
        )
        self.fc2 = nn.Sequential(
            nn.Linear(120, 84),
            nn.ReLU()
        )
        self.fc3 = nn.Linear(84, 10)
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.conv4(x)
        x = x.view(-1, 64 * 2 * 2)
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x

if __name__ == '__main__':

    wandb.init(project="BP")
    wandb.config.dropout = 0.2
    wandb.config.hidden_layer_size = 128
    # 读取数据,数据预处理
    transform = transforms.Compose([
                transforms.ToTensor(),
                transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))]) # totensor是将0-255转到0-1,normalize是将0-1转换到-1-1
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                            download=False, transform=transform) # 读取数据集,数据预处理
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=128,
                                              shuffle=True, num_workers=1, pin_memory=True) # 打乱,包装成batchsize
    testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                           download=False, transform=transform)
    testloader = torch.utils.data.DataLoader(testset, batch_size=128,
                                             shuffle=False, num_workers=1, pin_memory=True)

    device = torch.device("cuda:0") # 选择cpu或者GPU
    # model = BP_model()
    # model = LeNet5() # 用哪个模型,打开哪个,屏蔽另外两个
    model = CNN()
    model.to(device) # 选择cpu或者gpu
    criterion = nn.CrossEntropyLoss() # 交叉熵损失
    optimizer = torch.optim.SGD([{'params': model.parameters()}],
                                lr=0.005, weight_decay=5e-4, momentum=0.9) # 随机梯度优化策略
    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=200) # CNN训练使用该学习率优化策略,bp网络也可以使用试试

    for epoch in range(80):
        # 训练
        model.train()
        for i, (img, label) in tqdm(enumerate(trainloader)):
            img, label = img.to(device, non_blocking=True), label.to(device, non_blocking=True).long() # 加载数据
            output = model(img) # 计算结果
            loss = criterion(output, label) # 计算损失
            optimizer.zero_grad()
            loss.backward() # 反向传播
            optimizer.step() # 优化器更新

            iters = epoch * len(trainloader) + i
            if iters % 10 == 0:
                wandb.log({'loss': loss}) # 可视化
        # 测试
        accuracy = 0
        model.eval()
        for i, (img, label) in enumerate(testloader):
            img, label = img.to(device), label.to(device).long()
            output = model(img)
            output = output.max(dim=1)[1] # 预测是哪一类
            accuracy += (output==label).sum().item() # 准确率计算
        accuracy = accuracy / 10000 # 准确率计算
        print(accuracy)
        wandb.log({'accuracy': accuracy}) # 可视化

        scheduler.step() # 学习率更新






  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/544812
推荐阅读
相关标签
  

闽ICP备14008679号