Resnet18训练CIFAR10 准确率95%

这篇具有很好参考价值的文章主要介绍了Resnet18训练CIFAR10 准确率95%。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

准确率 95.31%

几个关键点:

1、改模型:原始的resnet18首层使用的7x7的卷积核,CIFAR10图片太小不适合,要改成3x3的,步长和padding都要一并改成1。因为图太小,最大池化层也同样没用,删掉。最后一个全连接层输出改成10。

2、图片增强不要太多,只要训练集和验证集结果没有出现10%以上的差距都算不上过拟合。

3、学习率从0.1开始,10个epoch跑完loss值没有下降的话衰减50%

4、损失函数用CrossEntropyLoss

5、优化器用SGD

改模型代码:

# 定义模型
model_ft = torchvision.models.resnet18(pretrained=False)

# 修改模型
model_ft.conv1 = nn.Conv2d(3, 64, 3, stride=1, padding=1, bias=False)  # 首层改成3x3卷积核
model_ft.maxpool = nn.MaxPool2d(1, 1, 0)  # 图像太小 本来就没什么特征 所以这里通过1x1的池化核让池化层失效
num_ftrs = model_ft.fc.in_features  # 获取(fc)层的输入的特征数
model_ft.fc = nn.Linear(num_ftrs, 10)

这里的最大池化层实在是想不出什么好办法直接删掉,只能用这个办法让其失效

如果不想用原始的模型也能自己写个

下面是我是随便写的一个

# 实现Resnet18
"""
 ResNet18 是由17个卷积层和1个全连接层组成
 下采样层的1x1卷积不算
 池化不算 激活不算

 主要思想是一个基础层 然后反复的重复这个基础层

"""
import torch
from torch import nn

# 基础块
from torch.nn import Conv2d, BatchNorm2d, ReLU, MaxPool2d, AdaptiveAvgPool2d, Linear


class BasicBlock(nn.Module):

    def __init__(self, in_features, out_features) -> None:
        super().__init__()

        self.in_features = in_features
        self.out_features = out_features

        stride = 1
        _features = out_features
        if self.in_features != self.out_features:
            # 在输入通道和输出通道不相等的情况下计算通道是否为2倍差值
            if self.out_features / self.in_features == 2.0:
                stride = 2  # 在输出特征是输入特征的2倍的情况下 要想参数不翻倍 步长就必须翻倍
            else:
                raise ValueError("输出特征数最多为输入特征数的2倍!")

        self.conv1 = Conv2d(in_features, _features, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = BatchNorm2d(_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        self.relu = ReLU(inplace=True)
        self.conv2 = Conv2d(_features, _features, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = BatchNorm2d(_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

        # 下采样
        self.downsample = None if self.in_features == self.out_features else nn.Sequential(
            Conv2d(in_features, out_features, kernel_size=1, stride=2, bias=False),
            BatchNorm2d(out_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        )

    def forward(self, x):
        identity = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)

        # 输入输出的特征数不同时使用下采样层
        if self.in_features != self.out_features:
            identity = self.downsample(x)

        # 残差求和
        out += identity
        out = self.relu(out)
        return out


class ResNet18(nn.Module):
    def __init__(self) -> None:
        super().__init__()

        self.conv1 = Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn1 = BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        self.relu = ReLU(inplace=True)
        # self.maxpool = MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
        self.layer1 = nn.Sequential(
            BasicBlock(64, 64),
            BasicBlock(64, 64)
        )
        self.layer2 = nn.Sequential(
            BasicBlock(64, 128),
            BasicBlock(128, 128)
        )
        self.layer3 = nn.Sequential(
            BasicBlock(128, 256),
            BasicBlock(256, 256)
        )
        self.layer4 = nn.Sequential(
            BasicBlock(256, 512),
            BasicBlock(512, 512)
        )
        self.avgpool = AdaptiveAvgPool2d(output_size=(1, 1))
        self.fc = Linear(in_features=512, out_features=10, bias=True)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        # x = self.maxpool(x)
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = self.avgpool(x)  # <---- 输出为{Tensor:(64,512,1,1)}
        x = torch.flatten(x, 1)  # <----------------这里是个坑 很容易漏 从池化层到全连接需要一个压平 输出为{Tensor:(64,512)}
        x = self.fc(x)  # <------------ 输出为{Tensor:(64,10)}
        return x


# 模型数据验证

if __name__ == "__main__":
    mode = ResNet18()
    print(mode)
    data = torch.ones((64, 3, 32, 32))
    output = mode(data)
    print(output.shape)

图片增强

transforms.Compose([
            transforms.ToTensor()
            , transforms.RandomCrop(32, padding=4)  # 先四周填充0,在吧图像随机裁剪成32*32
            , transforms.RandomHorizontalFlip(p=0.5)  # 随机水平翻转 选择一个概率概率
            , transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  # 均值,标准差
        ])

最开始我想的是为了避免过拟合,数据增强这里可以多做一些,所以图片旋转,水平翻转,垂直翻转,去色,随机调整色相饱和度对比度亮度都做了,但是验证集准确率死活上不了90%,一轮测试要搞几个小时,实在是吐血啊!

有兴趣的可以试试:

    train_transforms = transforms.Compose([

         transforms.RandomRotation(45)  # 随机旋转,-45到45度之间随机选
        , transforms.RandomCrop(32, padding=4)  # 先四周填充0,在吧图像随机裁剪成32*32
        , transforms.RandomHorizontalFlip(p=0.5)  # 随机水平翻转 选择一个概率概率
        , transforms.RandomVerticalFlip(p=0.5)  # 随机垂直翻转
        , transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1)
        # 参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相 全部是随机变化
        , transforms.RandomGrayscale(p=0.025)  # 概率转换成灰度率,3通道就是R=G=B
        , transforms.ToTensor()
        , transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  # 均值,标准差
    ])

还有一个坑,不要把CIFIA10的数据放大到224,然后直接用Resnet18训练,这样会很慢的,图片的预处理都是在CPU上完成的。暂时没找到什么好办法把预处理放到GPU上做。

如果还想再快点可以把CIFIA10的训练集划分成8:2的比例80%做训练集,20%做验证集,数据也够,一样能出结果,最后在CIFIA10的验证集上跑一把测试结果。

完整代码:

# 使用Resnet18原始model
# 用完整的测试集和验证集

import time
import copy
import numpy as np
import torch
import torchvision.models
from tqdm import tqdm
from torchvision.transforms import transforms
from torch import nn, optim
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10
from torch.utils.tensorboard import SummaryWriter


if __name__ == "__main__":

    # 这里面的变量都相当于全局变量 !!

    # GPU计算
    device = torch.device("cuda")

    #  训练总轮数
    total_epochs = 250
    # 每次取出样本数
    batch_size = 128
    # 初始学习率
    Lr = 0.1

    DATASET_PATH = '/kaggle/input/cifar10-python'
    SAVE_PATH = '/kaggle/working/'
    filename = '{}best_cnn_model'.format(SAVE_PATH)  # 文件扩展名在保存时添加

    torch.backends.cudnn.benchmark = True

    # 准备数据
    data_transforms = {
        'train': transforms.Compose([
            transforms.ToTensor()
            , transforms.RandomCrop(32, padding=4)  # 先四周填充0,在吧图像随机裁剪成32*32
            , transforms.RandomHorizontalFlip(p=0.5)  # 随机水平翻转 选择一个概率概率
            , transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  # 均值,标准差
        ]),
        'valid': transforms.Compose([
            transforms.ToTensor()
            , transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
    }
    # 准备数据 这里将训练集和验证集写到了一个list里 否则后面的训练与验证阶段重复代码太多
    image_datasets = {
        x: CIFAR10(DATASET_PATH, train=True if x == 'train' else False,
                   transform=data_transforms[x], download=True) for x in ['train', 'valid']}

    dataloaders: dict = {
        x: torch.utils.data.DataLoader(
            image_datasets[x], batch_size=batch_size, shuffle=True if x == 'train' else False
        ) for x in ['train', 'valid']
    }

    # 定义模型
    model_ft = torchvision.models.resnet18(pretrained=False)

    # 修改模型
    model_ft.conv1 = nn.Conv2d(3, 64, 3, stride=1, padding=1, bias=False)  # 首层改成3x3卷积核
    model_ft.maxpool = nn.MaxPool2d(1, 1, 0)  # 图像太小 本来就没什么特征 所以这里通过1x1的池化核让池化层失效
    num_ftrs = model_ft.fc.in_features  # 获取(fc)层的输入的特征数
    model_ft.fc = nn.Linear(num_ftrs, 10)

    model_ft.to(device)
    # 创建损失函数
    loss_fn = nn.CrossEntropyLoss()
    loss_fn.to(device)

    # 训练模型
    # 显示要训练的模型
    print("==============当前模型要训练的层==============")
    for name, params in model_ft.named_parameters():
        if params.requires_grad:
            print(name)

    # 训练模型所需参数
    # 用于记录损失值未发生变化batch数
    counter = 0
    # 记录训练次数
    total_step = {
        'train': 0, 'valid': 0
    }
    # 记录开始时间
    since = time.time()
    # 记录当前最小损失值
    valid_loss_min = np.Inf
    # 保存模型文件的尾标
    save_num = 0
    # 保存最优正确率
    best_acc = 0

    for epoch in range(total_epochs):
        # 动态调整学习率
        if counter / 10 == 1:
            counter = 0
            Lr = Lr * 0.5

        # 在每个epoch里重新创建优化器???
        optimizer = optim.SGD(model_ft.parameters(), lr=Lr, momentum=0.9, weight_decay=5e-4)

        print('Epoch {}/{}'.format(epoch + 1, total_epochs))
        print('-' * 10)
        print()
        # 训练和验证 每一轮都是先训练train 再验证valid
        for phase in ['train', 'valid']:
            # 调整模型状态
            if phase == 'train':
                model_ft.train()  # 训练
            else:
                model_ft.eval()  # 验证

            # 记录损失值
            running_loss = 0.0
            # 记录正确个数
            running_corrects = 0

            # 一次读取一个batch里面的全部数据
            for inputs, labels in tqdm(dataloaders[phase]):
                inputs = inputs.to(device)
                labels = labels.to(device)

                # 梯度清零
                optimizer.zero_grad()
                # 只有训练的时候计算和更新梯度
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model_ft(inputs)
                    loss = loss_fn(outputs, labels)

                    # torch.max() 返回的是一个元组 第一个参数是返回的最大值的数值 第二个参数是最大值的序号
                    _, preds = torch.max(outputs, 1)  # 前向传播 这里可以测试 在valid时梯度是否变化

                    # 训练阶段更新权重
                    if phase == 'train':
                        loss.backward()  # 反向传播
                        optimizer.step()  # 优化权重
                        # TODO:在SummaryWriter中记录学习率
                        # ....

                # 计算损失值
                running_loss += loss.item() * inputs.size(0)  # loss计算的是平均值,所以要乘上batch-size,计算损失的总和
                running_corrects += (preds == labels).sum()  # 计算预测正确总个数
                # 每个batch加1次
                total_step[phase] += 1

            # 一轮训练完后计算损失率和正确率
            epoch_loss = running_loss / len(dataloaders[phase].sampler)  # 当前轮的总体平均损失值
            epoch_acc = float(running_corrects) / len(dataloaders[phase].sampler)  # 当前轮的总正确率

            time_elapsed = time.time() - since
            print()
            print('当前总耗时 {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
            print('{} Loss: {:.4f}[{}] Acc: {:.4f}'.format(phase, epoch_loss, counter, epoch_acc))

            if phase == 'valid':
                # 得到最好那次的模型
                if epoch_loss < valid_loss_min:  # epoch_acc > best_acc:

                    best_acc = epoch_acc

                    # 保存当前模型
                    best_model_wts = copy.deepcopy(model_ft.state_dict())
                    state = {
                        'state_dict': model_ft.state_dict(),
                        'best_acc': best_acc,
                        'optimizer': optimizer.state_dict(),
                    }
                    # 只保存最近2次的训练结果
                    save_num = 0 if save_num > 1 else save_num
                    save_name_t = '{}_{}.pth'.format(filename, save_num)
                    torch.save(state, save_name_t)  # \033[1;31m 字体颜色:红色\033[0m
                    print("已保存最优模型,准确率:\033[1;31m {:.2f}%\033[0m,文件名:{}".format(best_acc * 100, save_name_t))
                    save_num += 1
                    valid_loss_min = epoch_loss
                    counter = 0
                else:
                    counter += 1

        print()
        print('当前学习率 : {:.7f}'.format(optimizer.param_groups[0]['lr']))
        print()

    # 训练结束
    time_elapsed = time.time() - since
    print()
    print('任务完成!')
    print('任务完成总耗时 {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
    print('最高验证集准确率: {:4f}'.format(best_acc))
    save_num = save_num - 1
    save_num = save_num if save_num < 0 else 1
    save_name_t = '{}_{}.pth'.format(filename, save_num)
    print('最优模型保存在:{}'.format(save_name_t))

运行结果片段:

Epoch 1/250
----------
100%|██████████| 391/391 [00:50<00:00,  7.80it/s]
当前总耗时 0m 50s
train Loss: 1.8680[0] Acc: 0.3292
100%|██████████| 79/79 [00:03<00:00, 20.67it/s]
当前总耗时 0m 54s
valid Loss: 1.4895[0] Acc: 0.4499
已保存最优模型,准确率: 44.99%,文件名:/kaggle/working/best_cnn_model_0.pth
当前学习率 : 0.1000000


Epoch 11/250
----------
100%|██████████| 391/391 [00:41<00:00,  9.33it/s]
当前总耗时 8m 31s
train Loss: 0.4722[2] Acc: 0.8391
100%|██████████| 79/79 [00:03<00:00, 21.90it/s]
当前总耗时 8m 35s
valid Loss: 0.5824[2] Acc: 0.8068
已保存最优模型,准确率: 80.68%,文件名:/kaggle/working/best_cnn_model_0.pth
当前学习率 : 0.1000000


Epoch 46/250
----------
100%|██████████| 391/391 [00:41<00:00,  9.46it/s]
当前总耗时 35m 11s
train Loss: 0.2126[0] Acc: 0.9276
100%|██████████| 79/79 [00:03<00:00, 21.00it/s]
当前总耗时 35m 15s
valid Loss: 0.2970[0] Acc: 0.9004
已保存最优模型,准确率: 90.04%,文件名:/kaggle/working/best_cnn_model_1.pth
当前学习率 : 0.0500000


Epoch 101/250
----------
100%|██████████| 391/391 [00:42<00:00,  9.23it/s]
当前总耗时 77m 28s
train Loss: 0.0037[0] Acc: 0.9995
100%|██████████| 79/79 [00:03<00:00, 21.22it/s]
当前总耗时 77m 32s
valid Loss: 0.1916[0] Acc: 0.9500
已保存最优模型,准确率: 95.00%,文件名:/kaggle/working/best_cnn_model_1.pth
当前学习率 : 0.0031250

Epoch 128/250
----------
100%|██████████| 391/391 [00:42<00:00,  9.27it/s]
当前总耗时 98m 10s
train Loss: 0.0021[4] Acc: 0.9999
100%|██████████| 79/79 [00:03<00:00, 21.68it/s]
当前总耗时 98m 14s
valid Loss: 0.1775[4] Acc: 0.9522
已保存最优模型,准确率: 95.22%,文件名:/kaggle/working/best_cnn_model_0.pth
当前学习率 : 0.0031250

Epoch 129/250
----------
100%|██████████| 391/391 [00:41<00:00,  9.32it/s]
当前总耗时 98m 56s
train Loss: 0.0020[0] Acc: 1.0000
100%|██████████| 79/79 [00:03<00:00, 21.31it/s]
当前总耗时 98m 59s
valid Loss: 0.1786[0] Acc: 0.9529
当前学习率 : 0.0031250

最后吐槽下google的Colab的那个 Colab Pro 这玩意并没有什么卵用,100个运行时很快就烧完,然后你就和白嫖用户一样了,不要花这冤枉钱,直接白嫖,存最近的两个最优模型,这样就是被踢了至少还能明天继续。或者把模型下载下来在传到Kaggle上继续白嫖。

不过最好还是能有自己的GPU,代码跑起来不用守着,可以去睡觉了,睡醒了再看结果。但是现在的显卡价格实在是一言难尽啊……文章来源地址https://www.toymoban.com/news/detail-787534.html

到了这里,关于Resnet18训练CIFAR10 准确率95%的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • pytorch进阶学习(六):如何对训练好的模型进行优化、验证并且对训练过程进行准确率、损失值等的可视化,新手友好超详细记录

    课程资源:  7、模型验证与训练过程可视化【小学生都会的Pytorch】【提供源码】_哔哩哔哩_bilibili 推荐与上一节笔记搭配食用~: pytorch进阶学习(五):神经网络迁移学习应用的保姆级详细介绍,如何将训练好的模型替换成自己所需模型_好喜欢吃红柚子的博客-CSDN博客 训练

    2023年04月17日
    浏览(35)
  • 基于ResNet-18实现Cifar-10图像分类

    安耀辉,男,西安工程大学电子信息学院,22级研究生 研究方向:小样本图像分类算法 电子邮箱:1349975181@qq.com 张思怡,女,西安工程大学电子信息学院,2022级研究生,张宏伟人工智能课题组 研究方向:机器视觉与人工智能 电子邮件:981664791@qq.com CIFAR-10 数据集由 60000张图

    2024年02月06日
    浏览(32)
  • 语义分割准确率计算

    目录 pytorch版 pytorch准确率,miou: sklearn版

    2024年02月06日
    浏览(42)
  • 深度学习提高模型准确率方法

    我们已经收集好了一个数据集,建立了一个神经网络,并训练了模型,在测试和验证阶段最后得到的准确率不高不到90%。或者没有达到业务的期望(需要100%)。 下面列举一些提高模型性能指标的策略或技巧,来提高模型的准确率。 使用更多数据 最简单的方法就是增加数据集

    2024年02月03日
    浏览(35)
  • 语音识别的挑战:如何提高准确率

    语音识别,也被称为语音转文本(Speech-to-Text),是一种将语音信号转换为文本信息的技术。随着人工智能和大数据技术的发展,语音识别技术在各个领域得到了广泛应用,如智能家居、智能汽车、语音助手、语音搜索等。然而,语音识别技术仍然面临着许多挑战,其中最大

    2024年02月02日
    浏览(39)
  • 自然语言处理学习笔记(八)———— 准确率

    目录 1.准确率定义 2.混淆矩阵与TP/FN/FP/TN 3. 精确率 4.召回率 5.F1值 6.中文分词的P、R、F1计算 7.实现 1.准确率定义         准确率是用来衡量一个系统的准确程度的值,可以理解为一系列评测指标。当预测与答案的数量相等时,准确率指的是系统做出正确判断的次数除以总

    2024年02月09日
    浏览(33)
  • 深度学习准确率提升之天花板分析

    OCR文字识别流水线主要分为三个模块:文字检测-字符分割-字符识别 训练完成后整个系统的准确率是72%,需要进一步提升准确率就需要单独分析每个模块的提升空间。 1)对于文件检测模块,把训练集的图像人工确保标注准确的文本位置来作为输入,系统准确率提升到89% 2)对

    2024年02月12日
    浏览(38)
  • 目前各类型准确率最高的图像识别算法

    1、目标检测 :截至2021年,最准确的目标检测算法是YOLOv4,它在COCO数据集上的mAP(平均平均精度)得分为43.5%。 2、图像分类 :截至2021年,最准确的图像分类算法是EfficientNet-L2,它在ImageNet数据集上的top-1精度最高,达到90.4%。 3、语义分割 :截至2021年,最准确的语义分割算法是u

    2024年02月13日
    浏览(27)
  • 识别准确率竟如此高,实时语音识别服务

    本文将介绍一个准确率非常高的语音识别框架,那就是FunASR,这个框架的模型训练数据超过几万个小时,经过测试,准确率非常高。本文将介绍如何启动WebSocket服务和Android调用这个服务来实时识别,一边说话一边出结果。 安装Pytorch。 使用conda安装ffmpeg等一些库。 安装其他依

    2024年02月07日
    浏览(29)
  • 分类模型评估:混淆矩阵、准确率、召回率、ROC

    在二分类问题中,混淆矩阵被用来度量模型的准确率。因为在二分类问题中单一样本的预测结果只有Yes or No,即:真或者假两种结果,所以全体样本经二分类模型处理后,处理结果不外乎四种情况,每种情况都有一个专门称谓,如果用一个2行2列表格描述,得到的就是“混淆

    2024年02月06日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包