CIFAR-100数据集 卷积神经网络训练

目录

1. CIFAR-10数据集介绍

2. 问题说明

3. 模型训练过程

 4. 结果可视化


1. CIFAR-100数据集介绍

这个数据集就像CIFAR-10,除了它有100个类,每个类包含600个图像。,每类各有500个训练图像和100个测试图像。CIFAR-100中的100个类被分成20个超类。每个图像都带有一个“精细”标签(它所属的类)和一个“粗糙”标签(它所属的超类)以下是CIFAR-100中的类别列表:

cifar10
Cifar10
SuperclassClasses
aquaticmammals beaver, dolphin, otter, seal, whale
fishaquarium fish, flatfish, ray, shark, trout
flowersorchids, poppies, roses, sunflowers, tulips
foodcontainers bottles, bowls, cans, cups, plates
fruit and vegetablesapples, mushrooms, oranges, pears, sweet peppers
household electrical devicesclock, computer keyboard, lamp, telephone, television
householdfurniture bed, chair, couch, table, wardrobe
insectsbee, beetle, butterfly, caterpillar, cockroach
large carnivoresbear, leopard, lion, tiger, wolf
large man-made outdoor thingsbridge, castle, house, road, skyscraper
large natural outdoor scenescloud, forest, mountain, plain, sea
large omnivores and herbivorescamel, cattle, chimpanzee, elephant, kangaroo
medium-sized mammalsfox, porcupine, possum, raccoon, skunk
non-insect invertebratescrab, lobster, snail, spider, worm
peoplebaby, boy, girl, man, woman
reptilescrocodile, dinosaur, lizard, snake, turtle
small mammalshamster, mouse, rabbit, shrew, squirrel
treesmaple, oak, palm, pine, willow
vehicles 1bicycle, bus, motorcycle, pickup truck, train
vehicles 2lawn-mower, rocket, streetcar, tank, tractor

CIFAR-100标签

参考

2. 问题说明

  • 自由选择算法完成 cifar-100 数据集解析分类
  • 要求准确率至少大于60%

3. 模型训练过程

1.初步准备

采用ResNet模型

 两种残差网络块定义

'''
不带瓶颈段的残差块
'''
class BasicBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1):
        super(BasicBlock, self).__init__()
        self.network = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1, stride=stride),
            nn.BatchNorm2d(out_channels),
            nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1, stride=1),
            nn.MaxPool2d(3, stride=1, padding=1)
        )
        self.downSample = nn.Sequential()
        if in_channels != out_channels:
            self.downSample = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride),
                nn.BatchNorm2d(out_channels)
            )

    def forward(self, x):
        out = self.network(x) + self.downSample(x)
        return out
'''
带瓶颈段的残差块
in channel = [inChannel1,inChannel2,inChannel3]
in channel = [outChannel1,outChannel2,outChannel3]
stride = 1 长宽不变
stride = 2 长宽减半
'''
class BasicBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride):
        super(BasicBlock, self).__init__()
        self.network = nn.Sequential(
            nn.Conv2d(in_channels, out_channels[0], kernel_size=1, padding=0, stride=1),
            nn.BatchNorm2d(out_channels[0]),
            nn.ReLU(),
            nn.Conv2d(out_channels[0], out_channels[1], kernel_size=3, padding=1, stride=stride),
            nn.BatchNorm2d(out_channels[1]),
            nn.ReLU(),
            nn.Conv2d(out_channels[1], out_channels[2], kernel_size=1, padding=0, stride=1),
            nn.BatchNorm2d(out_channels[2]),
        )
        self.downSample = nn.Sequential(
             nn.Conv2d(in_channels, out_channels[2], kernel_size=1,  padding=0, stride=stride),
             nn.BatchNorm2d(out_channels[2])
        )

训练,测试函数定义如下

def train():
    net.train()
    acc = 0.0
    sum = 0.0
    loss_sum = 0
    for batch, (data, target) in enumerate(trainLoader):
        data, target = data.to(device), target.to(device)
        net.optimizer.zero_grad()
        output = net(data)
        loss = net.lossFunc(output, target)
        loss.backward()
        net.optimizer.step()
        acc += torch.sum(torch.argmax(output, dim=1) == target).item()
        sum += len(target)
        loss_sum += loss.item()
    writer.add_scalar('Cifar100_model_log/trainAccuracy', 100 * acc / sum, epoch + 1)
    writer.add_scalar('Cifar100_model_log/trainLoss', loss_sum / (batch + 1), epoch + 1)
    print('train accuracy: %.2f%%, loss: %.4f' % (100 * acc / sum, loss_sum / (batch + 1)))


def test():
    net.eval()
    acc = 0.0
    sum = 0.0
    loss_sum = 0
    step = 0
    for batch, (data, target) in enumerate(testLoader):
        initData = data
        data = testTransform2(data)
        data, target = data.to(device), target.to(device)
        output = net(data)
'''
用于通过tensorboard可视化训练结果,使用时要注意将epoch设置为1

        for i in range(len(output)):
           writer.add_image(fineLabelList[torch.argmax(output, dim=1)[i]], initData[i], step)
        step = step + 1
'''
        loss = net.lossFunc(output, target)
        acc += torch.sum(torch.argmax(output, dim=1) == target).item()
        sum += len(target)
        loss_sum += loss.item()
    writer.add_scalar('Cifar100_model_log/testAccuracy', 100 * acc / sum, epoch + 1)
    writer.add_scalar('Cifar100_model_log/trainLoss', loss_sum / (batch + 1), epoch + 1)
    print('test accuracy: %.2f%%, loss: %.4f' % (100 * acc / sum, loss_sum / (batch + 1)))

准备数据

'''
采用GPU加速训练,没有则用cpu
'''
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
trainTransform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
])

'''   
数据集扩充采用
trainTransform = transforms.Compose([
    transforms.ToTensor(),
    transforms.RandomCrop(32, padding=4),
    transforms.RandomHorizontalFlip(),
    transforms.ColorJitter(brightness=(0,1), contrast=(0,1), saturation=(0,1), hue=0),
    transforms.RandomVerticalFlip(p=0.5),
    transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
]) 
'''

testTransform1 = transforms.Compose([
    transforms.ToTensor(),
])
testTransform2 = transforms.Compose([
    transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
])

trainDataset = datasets.cifar.CIFAR100(root='cifar100', train=True, transform=trainTransform, download=False)
testDataset = datasets.cifar.CIFAR100(root='cifar100', train=False, transform=testTransform1, download=False)

trainLoader = DataLoader(trainDataset, batch_size=200, shuffle=True)
testLoader = DataLoader(testDataset, batch_size=200, shuffle=False)

2.模型训练及改进思路

训练过程中发现网络的过拟合问题情况严重,训练集正确率可达90%,测试集正确率卡在45%上下。

解决方案

(1)使用L1、L2正则化

(2)增加Dropout

(3)扩充数据集

(4)删除部分残差块,缩减网络

(5)迁移学习

经过测试,发现采用了缩减网络,扩充数据集,增加Dropout的网络可以使正确率从45%提升到了61.79%(迁移学习作用也比较明显,实验中的一种迁移学习方式在原训练基础上将正确率提升至63.13%)而相较于Dropout,L2正则化可以更好地防止过拟合,但是正确率上升缓慢且出现停滞。

最后网络定义如下,剩余残差块和卷积层可进行迁移训练

进行的部分迁移学习思路过程如下:

第一次迁移学习:
冻结block1~4
增加
block5:BasicBlock(128, 128) 
block6:BasicBlock(128, 512, 2)
重设全连接层
正确率浮动变化不大

第二次迁移学习:
第一次的基础上冻结所有层
补充cov1单层卷积2*2*512
(如果增加至三层则会下降严重)
正确率提升至58%

第三次迁移学习
冻结block1~4
原版基础上重设全连接层单层
目的为了训练卷积层

第四次迁移学习(较为成功)
冻结block1~4
在原版基础上增加
block5:BasicBlock(128, 1024) 
block6:BasicBlock(1024, 128)
进行一次放大将正确率提升至63.13%
经测试若采用缩小,正确率提高幅度不大  

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.block1 = BasicBlock(3, 16)
        self.block2 = BasicBlock(16, 64, 2)
        self.block3 = BasicBlock(64, 64)
        self.block4 = BasicBlock(64, 128, 2)

        self.block5 = nn.Sequential()
        self.block6 = nn.Sequential()
        self.block7 = nn.Sequential()
        self.block8 = nn.Sequential()
        self.block9 = nn.Sequential()
        self.cov1 = nn.Sequential()
        self.linear = nn.Sequential(
            nn.Flatten(),
            nn.Linear(8 * 8 * 128, 2048),
            nn.Dropout(0.1),
            nn.BatchNorm1d(2048),
            nn.Linear(2048, 1024),
            nn.Dropout(0.1),
            nn.ReLU(),
            nn.Linear(1024, 100)
        )
        self.optimizer = torch.optim.SGD(self.parameters(), lr=0.08)
        self.lossFunc = torch.nn.CrossEntropyLoss()

训练结果(可以发现还是过拟合严重)

 4. 结果可视化

受版面限制,部分展示如下

通过拖动发现,在bed标签下出现一只错误识别的兔子

  • 2
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅帅喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值