反光衣识别算法冠军方案总结(附源码)|极市打榜

反光衣识别算法冠军方案总结(附源码)|极市打榜

原创 CV开发者都爱看的 [极市平台](javascript:void(0)😉

极市平台

微信号 extrememart

功能介绍 专注计算机视觉前沿资讯和技术干货,官网:www.cvmart.net

图片

作者丨nobug_w

编辑丨极市平台

极市导读

本文为反光衣识别算法的冠军方案总结,作者总结了自己打榜时的经验并给出了相关训练和推理的代码,希望能给大家带来一些帮助~ >>加入极市CV技术交流群,走在计算机视觉的最前沿

平日比较关注极市平台,最近在极市平台看到类似竞赛的算法打榜,有些榜有冠军导师指导打榜,并且还有丰厚的奖品(又能躺还有奖品)。抱着试一试的心态,报名参加了一下,在获得奖励的同时让自己也得到了项目上的锻炼。下文总结了打榜时的经验以及相关训练和推理代码,希望能给大家带来一些帮助~

1.任务介绍

反光衣识别(学习训练营专属)对图像进行实时检测,可实时检测指定区域内的现场工作人员是否按照要求穿反光衣(绿色反光衣或红色反光衣任一即可),当发现视频画面内出现人员未穿反光衣时,系统主动触发告警提示。真正做到施工工地安全信息化管理,做到事前预防,事中常态监测,事后规范管理。

图片

算法打榜正在进行中

反光衣识别算法打榜(报名参与):

https://www.cvmart.net/topList/10044?tab=RealTime&dbType=1

2.评价指标

本榜最终得分采取准确率、算法性能绝对值综合得分的形式,具体如下:

图片

说明:

  1. 总分为本项目排行榜上的Score,排名:总分值越高,排名越靠前;

  2. 算法性能指的赛道标准值是 100 FPS, 如果所得性能值FPS≥赛道标准值FPS,则算法性能值得分=1;

  3. 评审标准:参赛者需要获得算法精度和算法性能值的成绩,且算法精度≥0.1,算法性能值FPS≥10,才能进入获奖评选;

反光衣识别(学习训练营专属)是对新手十分友好的,只要总分达到0.8分即可获得丰厚的奖励。

图片

奖励正在进行中…

3.数据分析

本次比赛一共包括四类类别:reflective_vest(反光衣),no_reflective_vest(未穿或不规范穿反光衣)、person_reflective_vest(穿反光衣的行人)、person_no_reflective_vest(未穿或不规范穿反光衣的行人)。打榜者对图像中反光衣穿着情况的进行目标检测,给出目标框和对应的类别信息,且预警情况只有no_reflective_vest(未穿或不规范穿反光衣)这一情况。

数据集是由监控摄像头采集的现场场景数据,训练数据集的数量为36346张,测试数据集的数量为14024张。可见数据集的图像数量非常很多,因此如果采用十分庞大的网络模型训练,比如两阶段检测模型,势必会十分缓慢。

通过查看样例集的数据,可以发现人员所处的环境比较复杂。另外,数据集是从监控摄像头中采集,人员在近距离和远距离都有,目标的尺度比较丰富。因此需要选用具有多尺度检测能力的检测器。虽然图像中有时会存在比较小的目标,但是由于场景为施工现场,所以目标相对比较稀疏,遮挡情况不太严重,且与周围环境相比目标特征也比较明显。

图片

4.技术展示

这次训练技术展示分为两个部分:训练方法和推理方法。

通过以上分析以及往届极市平台介绍的方案,我们选择YOLO算法。最近yolov5更新到v6.0版本,其性能优秀并且训练、部署、调优等方面使用非常灵活方便。因此选择YOLOv5作为baseline,在此基础上根据实际情况进行具体模型的选择和模型的修改。

图片

其中,yolov5算法的框架如下图所示。Yolov5s,m,x等结构仅仅为网络深度和宽度差别,由yolov5*.yaml结构定义文件夹的超参数depth_multiple和width_multiple控制。

图片

这是很早之前的一幅图,现在YOLOv5的v6.0版本,已经有了修改,backbone主要修改如下:

1.第一层取消了Focus,采用卷积核大小为6,步长为2的卷积层代替。yolov5官方解答,Focus() 是用来降低FLOPS的,跟mAP无关。Focus模块在v5中是图片进入backbone前,对图片进行切片操作,具体操作是在一张图片中每隔一个像素拿到一个值,类似于邻近下采样,这样就拿到了四张图片,四张图片互补,输入通道扩充了4倍,即拼接起来的图片相对于原先的RGB三通道模式变成了12个通道,最后将得到的新图片再经过卷积操作,最终得到了没有信息丢失情况下的二倍下采样特征图。

2.更改backbone的基本单元BottleneckCSP为c3模块。在新版yolov5中,作者将BottleneckCSP(瓶颈层)模块转变为了C3模块,其结构作用基本相同均为CSP架构,只是在修正单元的选择上有所不同,其包含了3个标准卷积层以及多个Bottleneck模块(数量由配置文件.yaml的ndepth_multiple参数乘积决定)从C3模块的结构图可以看出,C3相对于BottleneckCSP模块不同的是,经历过残差输出后的Conv模块被去掉了,concat后的标准卷积模块中的激活函数也由LeakyRelu变味了SiLU。

图片

①C3模块

图片

②BottleNeckCSP模块

3.更改Leaky_Relu激活函数为SiLU激活函数。作者在CONV模块(CBL模块)中封装了三个功能:包括卷积(Conv2d)、BN以及Activate函数(在新版yolov5中,作者采用了SiLU函数作为激活函数),同时autopad(k, p)实现了padding的效果。

图片

4.SPP更改为SPPF(Spatial Pyramid Pooling - Fast), 结果是一样的,但是可以降低FLOPS,运行的更快。

官方介绍:

图片

训练方法

首先,在训练之前,我们将训练集进行划分训练集:测试集为8:2。其中训练集图像数量为29077,测试集图像数量为7269.数据集目录在’/home/data/309/’,如果是在实例中,100张样例在’/home/data/309/sample_m’。

1.由于数据集的jpg和xml在一个文件夹,首先我们将图片和标签进行分离,源码如下:

import osimport shutilfrom os import listdir, getcwdfrom os.path import joindatasets_path = '/home/data/309/'def jpg_xml():    if not os.path.exists(datasets_path + 'Annotations/'):        os.makedirs(datasets_path + 'Annotations/')    if not os.path.exists(datasets_path + 'images/'):        os.makedirs(datasets_path + 'images/')    filelist = os.listdir(datasets_path)    for files in filelist:        filename1 = os.path.splitext(files)[1]  # 读取文件后缀名        if filename1 == '.jpg':            full_path = os.path.join(datasets_path, files)            shutil.move(full_path, datasets_path+'images')        elif filename1 == '.xml':            full_path = os.path.join(datasets_path, files)            shutil.move(full_path, datasets_path+'Annotations')        else :            continue

2.然后根据自定义的训练集和验证集比例,生成txt。如果要更改比例,仅仅更改 trainval_percent和train_percent即可,源码如下。

classes= ['reflective_vest','no_reflective_vest','person_reflective_vest','person_no_reflective_vest']  #自己训练的类别import randomdef train_val_split():    trainval_percent = 0.2    train_percent = 0.8    images_filepath = datasets_path + 'images/'    txtsavepath = datasets_path    total_imgfiles = os.listdir(images_filepath)    num = len(total_imgfiles)    lists = range(num)    tr = int(num * train_percent)    train = random.sample(lists, tr)    ftrain = open(txtsavepath + 'train.txt', 'w+')    ftest = open(txtsavepath +  'test.txt', 'w+')    fval = open(txtsavepath + 'val.txt', 'w+')    for i in lists:        name = images_filepath + total_imgfiles[i] + '\n'        if i in train:            ftrain.write(name)        else:            fval.write(name)            ftest.write(name)    ftrain.close()    fval.close()ftest.close()

3.最后将voc格式转换为yolo格式,源码如下。

def convert(size, box):    dw = 1. / size[0]    dh = 1. / size[1]    x = (box[0] + box[1]) / 2.0    y = (box[2] + box[3]) / 2.0    w = box[1] - box[0]    h = box[3] - box[2]    x = x * dw    w = w * dw    y = y * dh    h = h * dh    return (x, y, w, h)def convert_annotation(image_id):    in_file = open(datasets_path + 'Annotations/%s.xml' % (image_id),encoding='utf-8')    out_file = open(datasets_path + 'labels/%s.txt' % (image_id), 'w',encoding='utf-8')    tree = ET.parse(in_file)    root = tree.getroot()    size = root.find('size')    w = int(size.find('width').text)    h = int(size.find('height').text)    for obj in root.iter('object'):        difficult = 0        cls = obj.find('name').text        if cls not in classes or int(difficult) == 1:            continue        cls_id = classes.index(cls)        xmlbox = obj.find('bndbox')        b=(float(xmlbox.find('xmin').text),float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),        float(xmlbox.find('ymax').text))        bb = convert((w, h), b)        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')def generate_labels():    if not os.path.exists(datasets_path + 'labels/'):        os.makedirs(datasets_path + 'labels/')    sets = ['train', 'val']    for image_set in sets:        image_ids = open(datasets_path + '%s.txt' % (image_set)).read().strip().split()        for image_id in image_ids:            convert_annotation(image_id.split('/')[-1][:-4])

在第一次训练时,我们选择了yolov5m模型。在训练了12小时后,仅仅训练了几个epoch,并且进行第一次测试,结果f1-score仅仅为0.2732,并且性能分很低。在时间紧张且计算资源有限的情况下,这显然不能满足我们的需求。

图片

然后,我们选择了yolov5s模型,进行第二次训练。选择hyp.scratch.yaml配置文件作为参数,并且修改了其中数据增强方式,主要将参数mosaic: 1.0 # image mosaic (probability) 数值修改为0.5。如下图所示:

图片

因为在数据集中小目标较少,不需要每次都进行mosaic。并且不采用裁剪、复制粘贴、旋转、mixup。因为我觉得数据量其实已经足够训练yolov5s网络了。并且为了加快训练速度,输入图像改为512大小,能多训练几个epoch。优化器选择SGD优化器即可。并且这里需要采用官方的yolov5s.pt作为预训练模型,能加速模型的收殓。

在12小时训练完成后,f1-score就可以到0.7543。

图片

在第三次训练时,采用同样的方法进行训练。一方面使测试集中的图像参加到训练过程中;另一方面,12个小时才训练了几个epoch,肯定没有训练充分。再等12小时后训练完,f1-score就可以到0.7746。此时与0.8分就十分接近了。

最后,我们采用冻结训练策略,并且训练图像大小修改为640。Yolov5冻结参数也十分方便,只需要传递参数即可。我们将backbone以及neck+head轮流冻结。并且直接采用hyp.scratch-med.yaml进行最后的训练。这一部分具体看石工讲的冻结训练策略。通过最后一步,f1-sorce达到了0.8031。

图片

这里需要对源码进行修改,主要是因为在neck+head冻结时,yolov5只能顺序冻结。这里需要修改,修改方式如下。修改后便可以冻结任意层。

①train.py修改前:

图片

train.py修改后:

图片

②train.py修改前:

图片

train.py修改后:

图片

此时我们计算一下,0.8-0.8031*0.9=0.07721。然后再0.07721/0.1=0.7721。即,性能分达到77.21就满足了,是不是很容易了。

推理方法

在推理部分,我们这里直接pt文件直接进行推理,并没有采用模型加速方案。但是不采用FP32精度进行推理,而是采用FP16进行推理。具体可以参考,detect.py文件中的方法。运行时直接采用添加—half即可采用FP16进行推理。在本次打榜中,我仅仅采用FP16半精度推理即可达到比赛要求。

根据https://www.cvmart.net/topList/10044?dbType=1&tab=RankDescription 的赛道说明,我们写测试文件,源码如下。

import jsonimport torchimport sysimport numpy as npfrom pathlib import Pathfrom ensemble_boxes import weighted_boxes_fusionfrom models.experimental import attempt_loadfrom utils.torch_utils import select_devicefrom utils.general import check_img_size, non_max_suppression, scale_coordsfrom utils.augmentations import letterbox@torch.no_grad()model_path = '/best.pt'def init():    weights = model_path    device = 'cuda:0'  # cuda device, i.e. 0 or 0,1,2,3 or    half = True  # use FP16 half-precision inference    device = select_device(device)    w = str(weights[0] if isinstance(weights, list) else weights)    model = torch.jit.load(w) if 'torchscript' in w else attempt_load(weights, map_location=device)    if half:        model.half()  # to FP16    model.eval()    return modeldef process_image(handle=None, input_image=None, args=None, **kwargs):        half = True  # use FP16 half-precision inference        conf_thres = 0.5  # confidence threshold        iou_thres = 0.5  # NMS IOU threshold        max_det = 1000  # maximum detections per image        imgsz = [640, 640]        names = {            0: 'reflective_vest',            1: 'no_reflective_vest',            2: 'person_reflective_vest',            3: 'person_no_reflective_vest'        }        stride = 32    fake_result = {    }    fake_result["algorithm_data"] = {        "is_alert": False,        "target_count": 0,        "target_info": []    }    fake_result["model_data"] = {        "objects": []    }        img = letterbox(input_image, imgsz, stride, True)[0]        img = img.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB        img /= 255.0  # 0 - 255 to 0.0 - 1.0        pred = handle(img, augment=False, visualize=False)[0]        pred = non_max_suppression(pred, conf_thres, iou_thres, None, False, max_det=max_det)        for i, det in enumerate(pred):  # per image            det[:, :4] = scale_coords(img.shape[2:], det[:, :4], input_image.shape).round()            for *xyxy, conf, cls in reversed(det):                xyxy_list = torch.tensor(xyxy).view(1, 4).view(-1).tolist()                conf_list = conf.tolist()                label = names[int(cls)]                fake_result['model_data']['objects'].append({                    "xmin": int(xyxy_list[0]),                    "ymin": int(xyxy_list[1]),                    "xmax": int(xyxy_list[2]),                    "ymax": int(xyxy_list[3]),                    "confidence": conf_list,                    "name": label                })                if label == 'no_reflective_vest':                    fake_result['algorithm_data']['target_info'].append({                        "xmin": int(xyxy_list[0]),                        "ymin": int(xyxy_list[1]),                        "xmax": int(xyxy_list[2]),                        "ymax": int(xyxy_list[3]),                        "confidence": conf_list,                        "name": "no_reflective_vest"                    })        fake_result['algorithm_data']['is_alert'] = True if len(            fake_result['algorithm_data']['target_info']) > 0 else False        fake_result['algorithm_data']["target_count"] = len(fake_result['algorithm_data']['target_info'])            return json.dumps(fake_result, indent=4)

5.讨论与总结

本次极市平台举行的基于反光衣识别的新手训练营项目,确实对新手十分的友好,容易上手,不需要添加额外的tricks,也不需要更换backbone,neck即可达到要求,能够很好的熟悉平台。本人作为新人,本次打榜相关的结论可归纳为以下几点:

  1. **选择好baseline是基础。**最开始本人由于经验少,以为选择大的模型肯定能取得好的分数。因此,我们要针对数据情况、计算资源、算法精度和性能选择合适的baseline.

  2. **做好数据分析是关键。**目标尺度分布,目标遮挡情况,目标密集程度,数据集数量等等方面,影响着我们选择对应策略。比如,小目标过多的情况下,需要采用mosic数据增强策略;数据充足且丰富的情况下适当减少数据增强策略;图像尺寸根据实际情况进行调整。

  3. **多看别人经验十分重要。**本次能上榜的原因也是石工之前的冻结训练策略能运用上,才达到打榜要求。除此之外,还有许多提分经验,希望大家多多尝试。深度学习可能就是这样,在别人上面可能有效,在自己工程上就无效了,要多尝试。

  4. 针对赛题对性能的要求,采用FP16精度做推理,若需要更高的推理速度,可采用Openvino和TensorRT等方式部署模型

作者介绍

图片

王铖,来自西北师范大学VIGP团队成员,

研究方向:深度学习,目标检测等

参考

  1. https://github.com/ultralytics/yolov5

  2. https://mp.weixin.qq.com/s/e07eRbNAkoDVRs7Q-rV0TA

  3. https://mp.weixin.qq.com/s/VgDcS-edk9Mqkv-qSfcRJA

  4. www.cvmart.net

  5. https://blog.csdn.net/weixin_38842821/article/details/108544609


**打榜说明:**极市打榜是面向计算机视觉开发者的算法竞技,参与者人人都可以通过提高算法分数(精度+性能分)获得早鸟奖励+分分超越奖励,排行榜前三名的胜利者将有机会获得该算法的极市复购订单,获得持续的订单收益。

提供免费算力+真实场景数据集;早鸟奖励+分分超越奖励+持续订单分成,实时提现!

反光衣识别算法打榜(报名参与):

https://www.cvmart.net/topList/10044?tab=RealTime&dbType=1

墨镜识别、安全帽识别、占道经营识别等26个打榜算法地址(正在进行中):https://www.cvmart.net/topList

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ChLxP51-1637837795137)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

扫码查看(报名)打榜

如果觉得有用,就请分享到朋友圈吧!

极市平台

专注计算机视觉前沿资讯和技术干货,官网:www.cvmart.net

582篇原创内容

公众号

△点击卡片关注极市平台,获取最新CV干货

公众号后台回复“transformer”获取最新Transformer综述论文下载~

极市干货

课程/比赛:珠港澳人工智能算法大赛保姆级零基础人工智能教程

算法trick:目标检测比赛中的tricks集锦从39个kaggle竞赛中总结出来的图像分割的Tips和Tricks

技术综述:一文弄懂各种loss function工业图像异常检测最新研究总结(2019-2020)

图片

_CV技术社群邀请函 _#

图片

△长按添加极市小助手

添加极市小助手微信(ID : cvmart4)

备注:姓名-学校/公司-研究方向-城市(如:小极-北大-目标检测-深圳)

即可申请加入极市目标检测/图像分割/工业检测/人脸/医学影像/3D/SLAM/自动驾驶/超分辨率/姿态估计/ReID/GAN/图像增强/OCR/视频理解等技术交流群

每月大咖直播分享、真实项目需求对接、求职内推、算法竞赛、干货资讯汇总、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企视觉开发者互动交流~

觉得有用麻烦给个在看啦~[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Epwy0irU-1637837795141)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

var first_sceen__time = (+new Date()); if ("" == 1 && document.getElementById(‘js_content’)) { document.getElementById(‘js_content’).addEventListener(“selectstart”,function(e){ e.preventDefault(); }); }

预览时标签不可点

收录于话题 #

阅读原文

阅读

分享 收藏

赞 在看

示意图

反光衣识别算法冠军方案总结(附源码)|极市打榜

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值