一、报名并理解赛题任务
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
测试GPU是否可以使用
device = 'cuda' if torch.cuda.is_available() else 'cpu'
#输出cuda说明使用gpu,输出cpu说明使用cpu,最好使用gpu训练
print(device)
数据读取与数据处理
首先我们需要定义如何读取数据,这里我们定义了一个读取文件的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)
读取训练集图片和标注数据,注意这里的文件路径:
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,
)
接下来验证数据集是否可以正确读取,读取一个批次的图片:
for data in train_loader:
break
for data in test_loader:
break
#如果出现BrokenPipeError: [Errno 32] Broken pipe,调整DataLoader中num_workers = 0
#num_workers参数是指在进行数据集加载时,启用的线程数目,windows下多线程可能出问题
模型搭建与训练
我们使用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()
接下来我们使用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))
模型验证
接下来我们对测试集进行预测,并生成提交文件。
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
结果输出
写入提交结果格式
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])])
本次教程完成了基础的模型搭建和训练过程,在学习版数据后可以在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 从头训练,精度还是有差异,前者更好。
知识蒸馏 大概率 用不到。