• 如何打一个 CV 比赛 V2.0



    一、报名并理解赛题任务

    1.平台注册

    点击:华为赛事官网注册网址官方网址,进入官网,点击右上角:注册。
    在这里插入图片描述
    在这里插入图片描述

    2.比赛报名

    1、点击:华为赛事官网报名地址报名地址,进入赛事报名页。创建团队、选择报名来源、完善基础信息,最后提交即可。

    在这里插入图片描述

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

    3.数据下载

    在这里插入图片描述

    在这里插入图片描述
    原始数据35.6G,没有足够算力的小伙伴可以下载如下数据,我们在原始数据数据集上进行了采样,数据大小总共2.5GB左右。
    数据下载链接:数据下载

    4.赛题解析

    本次比赛是一个计算机视觉缺陷检测领域的图像分类赛,需要选手通过训练集数据构建模型,然后对验证集数据进行预测,预测结果进行提交。

    本赛题给出的车道渲染数据为图片格式,包含两个大类,即问题图片和无问题图片。本题的任务是构建一种模型,根据地图渲染图片数据来预测图片是否存在问题。

    二、配置环境

    • 安装 Anaconda:https://blog.csdn.net/fan18317517352/article/details/123035625
    • 安装 CUDA 与 cuDNN:https://www.bilibili.com/video/BV12V4y1s7MU/
    • 参照上面的教程,在 Pytorch 官网下载安装 Pytorch,并且使用 conda 安装pandas,numpy,opencv

    三、实践思路

    1.代码实现

    导入库
    Pytorch环境请参考:Pytorch深度学习环境配置

    #安装相关依赖库 如果是windows系统,cmd命令框中输入pip安装,或在Jupyter notebook中!pip安装,参考上述环境配置
    #!pip install pandas numpy cv2 torch torchvision codecs PIL glob
    #---------------------------------------------------
    #导入库
    import os
    import glob
    from PIL import Image
    import csv, time
    import numpy as np
    
    # pytorch相关
    import torch
    import torchvision
    import torch.optim as optim
    import torch.nn as nn
    import torchvision.transforms as transforms
    from torch.utils.data import DataLoader
    import torch.utils.data as data
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    测试GPU是否可以使用

    device = 'cuda' if torch.cuda.is_available() else 'cpu'
    #输出cuda说明使用gpu,输出cpu说明使用cpu,最好使用gpu训练
    print(device)
    
    • 1
    • 2
    • 3

    数据读取与数据处理
    首先我们需要定义如何读取数据,这里我们定义了一个读取文件的dataset,可以很方便完成数据读取和数据扩增操作。自定义dataset只需要重写init、getitem和len方法。

    # 自定义读取数据集
    class ImageSet(data.Dataset):
        def __init__(
                self,
                images,
                labels,
                transform):
            self.transform = transform
            self.images = images
            self.labels = labels
    
        def __getitem__(self, item):
            imagename = self.images[item]
            
            # 防止文件出错,这里生成一个随机的照片
            try:
                image = Image.open(imagename)
                image = image.convert('RGB')
            except:
                image = Image.fromarray(np.zeros((256, 256), dtype=np.int8))
                image = image.convert('RGB')
    
            image = self.transform(image)
            return image, torch.tensor(self.labels[item])
    
        def __len__(self):
            return len(self.images)
    
    • 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

    读取训练集图片和标注数据,注意这里的文件路径:

    import pandas as pd
    import codecs
    
    # 训练集标注数据
    lines = codecs.open('train_label.csv').readlines()
    train_label = pd.DataFrame({
        'image': ['train_image/' + x.strip().split(',')[0] for x in lines],
        'label': [x.strip().split(',')[1:] for x in lines],
    })
    
    # 将标签进行二值化处理
    train_label['new_label'] = train_label['label'].apply(lambda x: int('0' in x))
    
    import cv2, os
    def check_image(path):
        try:
            if os.path.exists(path):
                return True
            else:
                return False
        except:
            return False
    # 筛选路径存在的训练集
    train_is_valid = train_label['image'].apply(lambda x: check_image(x) )
    train_label = train_label[train_is_valid]
    
    # 数据扩增方法
    trfs = transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
    
    # 训练集dataset和dataloder
    # 这里我们使用前1000张图片进行训练,后续可以自行修改
    train_dataset = ImageSet(train_label['image'].values[:1000],
                             train_label['new_label'].values[:1000],
                             trfs)
    train_loader = DataLoader(
        train_dataset,
        batch_size=32,
        shuffle=True,
        num_workers=1,
        pin_memory=True,
    )
    
    # 测试集dataset和dataloder
    test_images = glob.glob('./test_images/*')
    test_dataset = ImageSet(test_images, [0] * len(test_images), trfs)
    
    test_loader = DataLoader(
        test_dataset,
        batch_size=32,
        shuffle=False,
        num_workers=5,
        pin_memory=True,
    )
    
    • 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

    接下来验证数据集是否可以正确读取,读取一个批次的图片:

    for data in train_loader:
        break
        
    for data in test_loader:
        break
          
     #如果出现BrokenPipeError: [Errno 32] Broken pipe,调整DataLoader中num_workers = 0
     #num_workers参数是指在进行数据集加载时,启用的线程数目,windows下多线程可能出问题
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    模型搭建与训练
    我们使用resnet18预训练模型,然后修改最终模型的输出层维度:

    # 加载resnet18预训练模型
    model = torchvision.models.resnet18(pretrained=True)
    model.fc = torch.nn.Linear(512, 2)
    model = model.to('cuda') #使用GPU
    
    # 模型优化器
    optimizer = optim.SGD(model.parameters(), lr=0.001)
    
    # 模型损失函数
    loss = nn.CrossEntropyLoss()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    接下来我们使用pytorch完成模型的训练:

    # 设置迭代轮数epochs,可调整,轮数越多,所花时间越久
    epochs = 3
    for epoch in range(epochs):
        start_t = time.time()
        epoch_l = 0
        epoch_t = 0
        
        # 批量训练
        for batch_idx, batch in enumerate(train_loader):
            optimizer.zero_grad()
            image, label = batch
            image, label = image.to('cuda'), label.to('cuda')
            output = model(image) # 正向传播
    
            l = loss(output, label) # 计算损失
            l.backward()
            optimizer.step()
    
            batch_l = l.item()
            epoch_l += batch_l
            batch_t = time.time() - start_t
            epoch_t += batch_t
            start_t = time.time()
            
            # 打印loss
            if batch_idx % 10 == 0:
                print(l.item(), batch_idx, len(train_loader))
    
        epoch_t = epoch_t / len(train_loader)
        epoch_l = epoch_l / len(train_loader)
        print('...epoch: {:3d}/{:3d}, loss: {:.4f}, average time: {:.2f}.'.format(
            epoch + 1, epochs, epoch_l, epoch_t))
    
    • 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

    模型验证
    接下来我们对测试集进行预测,并生成提交文件。

    model.eval()
    to_prob = nn.Softmax(dim=1)
    with torch.no_grad():
        imagenames, probs = list(), list()
        for batch_idx, batch in enumerate(test_loader):
            image, _ = batch
            image = image.to('cuda')
            pred = model(image)
            prob = to_prob(pred)
            prob = list(prob.data.cpu().numpy())
            probs += prob
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果输出
    写入提交结果格式

    import csv
    with open('submission.csv', 'w',newline = '', encoding='utf8') as fp:
        writer = csv.writer(fp)
        writer.writerow(['imagename', 'defect_prob'])
        for imagename, prob in zip(test_images, probs):
            imagename = os.path.basename(imagename)
            writer.writerow([imagename, str(prob[0])])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    本次教程完成了基础的模型搭建和训练过程,在学习版数据后可以在30分钟左右完成实践。如果想要获取更好的精度,可以从如下几个角度进行改进:

    • 使用更多的训练数据进行训练,但需要更多的算力和时间
    • 加入额外的数据扩增操作,需要选择合适的变换
    • 使用更加强大的深度学习模型

    2.结果提交

    • 在提交结果处提交,提交 submission.csv(程序生成的CSV文件),查看自己的成绩排名
      在这里插入图片描述

    特别注意首次提交需要三个文件Source Code.zip为你的代码压缩文件、DIGIX Implementation Instruction.docx为官方提供文件、submission.csv为你的结果文件,注意文件名必须一致。
    在这里插入图片描述

    四、进阶提升

    1. 提分思路

    如何提高模型的分类精度? -》 验证集的精度进行参考。

    • 数据扩增:randcrop、randnoise、flip
    • 更加强大的模型:输入的图片的尺寸、模型的最终的精度
    • 利用无标签的数据集:伪标签的进行打标
      • 筛选出置信度比较高的样本 3000
      • 3000 + 训练集 再次训练

    timm和torchvison 权重是不同,使用的超参数需要调整。

    如果使用全量数据集进行训练,AUC 0.7 +

    更加强化模型-》更长的训练时间,AUC 0.8 +
    合理的数据增加, 无标签的数据集

    如果使用预训练模型 vs 从头训练,精度还是有差异,前者更好。

    知识蒸馏 大概率 用不到。

  • 相关阅读:
    ​UWA报告使用技巧小视频,你get了么?(第六弹)
    8.查询数据
    深度剖析Linux磁盘分区 | LVM逻辑卷 | VDO卷 | AutoFS存储自动挂载
    微信交友unicloud云开发小程序
    阻塞式队列
    记一次 splice 导致 io.Copy 阻塞的排查过程
    Minecraft 服务器安装Forge 并添加Mod
    掌握这十个Linux命令,秒变Linux老手
    人工智能核心基础 - 规划和概要
    AT32F415 修改时钟和晶振方法(原创)
  • 原文地址:https://blog.csdn.net/weixin_44336912/article/details/126828582