华为ModelArts-Lab拓展试验记录(二) 华为ModelArts-Lab拓展试验记录(二)

网友投稿 702 2022-05-30

华为ModelArts-Lab拓展试验记录(二)

在2019年7月至2019年12月期间,参加了华为云ModelArt训练营活动,在ModelArt平台上,做了一些AI实验,现在整理一下资料,把我主要做的几个拓展实验内容做了记录,方便以后查阅,且分享给那些对使用华为云ModelArt开发有兴趣的朋友。第二个拓展实验就是训练营第五期内容的拓展,关于物体检测的Faster R-CNN算法的使用mAP评价指标。

1、概述

本次拓展实验内容为对Faster R-CNN算法模型使用mAP评价指标进行衡量,在第五期的notebook案例中,并没有对物体检测模型的精度进行评估,物体检测模型的精度使用mAP评价指标进行衡量。要求在notebook案例中,开发代码,计算出模型的mAP。

和以前一样,从最基本概念入手,由浅入深,介绍本次实验的过程及其内容,并且对实验代码做解析。

1.1、Faster RCNN简介

机器视觉领域的核心问题之一就是目标检测(Object Detection),它的任务是找出图像当中所有感兴趣的目标(物体),确定其位置和大小。Faster RCNN是由Ross Girshick由何凯明等人在2016年将其用于目标检测任务中,能够完成高效的与传统的RCNN相比,利用RPN(Region Proposal Networks)完成候选框的选择。其发展历程是:R-CNN——Fast R-CNN——Faster  R-CNN——Mask R-CNN,都是将神经网络应用于目标检测的典型代表,Faster  R-CNN具有性能较好,速度较快的优点。

Faster  R-CNN是在R-CNN,Fast R-CNN基础之上发展而来,原理图如下:

算法步骤

1.Conv layers:首先使用一组基础conv+relu+pooling层提取image的feture map。接层。

2.Region Proposal Networks:RPN网络用于生成region proposcals.该层通过softmax判断anchors属于foreground或者background,再利用box regression修正anchors获得精确的propocals

3.Roi Pooling:该层收集输入的feature map 和 proposcal,综合这些信息提取proposal feature map,送入后续的全连接层判定目标类别。

4.Classification。利用proposal feature map计算proposcal类别,同时再次bounding box regression获得检验框的最终精确地位置。

具体细节这里就不阐述了,以上几个步骤,在这次实验中都有涉及。

1.2、mAP评价指标

Mean Average Precision(MAP):平均精度均值。P(Precision)精度,正确率。定义为: precision=返回结果中相关文档的数目/返回结果的数目。 Rec(Recall)召回率:定义为:Recall=返回结果中相关文档的数目/所有相关文档的数目。 数学公式理解:

1)True Positive(真正,TP):将正类预测为正类数;2)True Negative(真负,TN):将负类预测为负类数;3)False Positive(假正,FP):将负类预测为正类数误报 (Type I error);4)False Negative(假负,FN):将正类预测为负类数→漏报 (Type II error)。

精确率(precision):P=TP/(TP+FP)(分类后的结果中正类的占比),召回率(recall):recall=TP/(TP+FN)(所有正例被分对的比例。

在图像中,主要计算两个指标:precision和recall。precision,recall都是选多少个样本k的函数,如果我总共有1000个样本,那么我就可以像这样计算1000对P-R,并且把他们画出来,这就是PR曲线:这里有一个趋势,recall越高,precision越低。 平均精度AP(average precision):就是PR曲线下的面积,这里average,等于是对recall取平均。而mean average precision的mean,是对所有类别取平均(每一个类当做一次二分类任务)。现在的图像分类论文基本都是用mAP作为标准。AP是把准确率在recall值为Recall = {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1}时(总共11个rank水平上),求平均值。mAP是均精度均值:只是把每个类别的AP都算了一遍,再取平均值。

AP是针对单个类别的,mAP是针对所有类别的。

2、mAP检测实验

根据本期实验内容,结合mAP方式,在modelArt平台上,先制定检测流程,在实验代码中添加mAP检测代码,然后对实验数据进行mAP检测。

2.1、定义检测数据集

首先,需要获取测试数据,依然从VOC2007数据里面获取,定义一个imdb(检测数据),作为检测mAP用。也是利用原来的实验部分代码的写法构成。定义了加载函数 def combined_roidb(imdb_names),里面处理比较常规,选用数据集,对图像进行了反转处理。最后返回两个数据:imdb 和 roidb。

这里要用到一个python类:pascal_voc,它实际上是集成了imdb类的一个类,实现了各种功能,有兴趣的话,可以看它的源代码。首先要导入一个它的功能函数:

from datasets.factory import get_imdb

为了计算mAP,需要修改数据集参数:

imdb_name = "voc_2007_test"

在训练之前,我们先要定义好imdb数据,代码如下:

#定义加载数据集函数 def combined_roidb(imdb_names):          def get_roidb(imdb_name):         # 加载数据集         imdb = get_imdb(imdb_name) #记录了数据集的路径之类的信息,函数通过给数据集的名字返回了该数据集对应的类的对象。         print('Loaded dataset `{:s}` for training'.format(imdb.name))         # 使用ground truth作为数据集策略         #对每张影像名调用_load_pascal_annotation,即可以知道该函数读取的是影像对应存储目标的xml文件。最后返回了“boxes”,“gt_classes”等构成的字典。         imdb.set_proposal_method(cfg.TRAIN.PROPOSAL_METHOD)         print('Set proposal method: {:s}'.format(cfg.TRAIN.PROPOSAL_METHOD))         #增加翻转,对每张影像在上面进行了求最大处理,并记录影像路径还有影像高宽等信息在roidb中并返回,返回的roidb是一个长度与影像数一致的列表         roidb = get_training_roidb(imdb)          return roidb          #对于每个数据集返回了带有该数据集信息的imdb和包含每张影像感兴趣区域信息的roidb(包括每张影像点目标和影像宽高等信息)     roidbs = [get_roidb(s) for s in imdb_names.split('+')]     roidb = roidbs[0] #roidb包括数据集所有影像的影像路径,所有影像对应的目标,以及宽高等信息。     if len(roidbs) > 1:         for r in roidbs[1:]:             roidb.extend(r)         tmp = get_imdb(imdb_names.split('+')[1])         imdb = datasets.imdb.imdb(imdb_names, tmp.classes)     else:         imdb = get_imdb(imdb_names)     return imdb, roidb

在这里,这个部分主要还是提取VOC2007 的测试数据,作为检测mAP用。也是利用原来的实验部分代码的写法构成。

定义了加载函数 def combined_roidb(imdb_names),里面处理比较常规,选用数据集,对图像进行了反转处理。最后返回两个数据:imdb 和 roidb。

imdb的定义方式:imdb = get_imdb(imdb_name),它是一个基于pascal_voc.py 的类的实例对象,imdb这里的数据集获取的同时,还做了数据的初始化,get_imdb(imdb_name)将会返回的就是pascal_voc(split, year)这样一个对象。它们关系:get_imdb->factory->pascal_voc->(继承)imdb。

最后,不要忘记imdb, roidb = combined_roidb(imdb_name),这行代码是加载测试集数据。

2.2、定义神经网络

在测试计算时,还是需要建立神经网络,用来检测数据。这里还是根据案例情况,这里还是选择Vgg16网络,并且加载我们生成的训练模型,并且配置正确的参数。

from nets.vgg16 import vgg16   net = vgg16()

这里需要定义一下anchor的参数,主要是定义了anchor的尺寸,这里设置anchor_scales = [8, 16, 32]。对base anchor的宽高分别乘以尺寸,从而得到各个不同尺寸的anchor。

'ANCHOR_SCALES': [8, 16, 32],

接着做以下的工作:

1)net.create_architecture,构建faster rcnn进行计算图的操作。这里要注意,modelart环境中的参数和其它场景略有差异,是不需要传sess这个参数的(这个坑了我好久)。这里的参数中,参数ANCHOR_SCALES必须,参数ANCHOR_RATIOS可以省略,其它都按常规传。

net.create_architecture(imdb.num_classes,tag='default',anchor_scales=cfg.ANCHOR_SCALES)

2)加载权重文件,net.load_state_dict方法,主要是加载的文件位于"./models/vgg16-voc0712/vgg16_faster_rcnn_iter_110000.pth",这个就是训练模型文件。

net.load_state_dict(torch.load(saved_model, map_location=lambda storage, loc: storage))         net.eval()

3)选择计算设施:net.to(net._device)。

2.3、图像检测和提取

这个是mAP计算的核心功能,主要是形成可以被计算mAP的图像文件。以下分三个步骤:

步骤一、定义目标图像框容器

根据每一类文件,每一张图片,都定义个容器,就是定义一个数据集存储单元。代码为:

all_boxes = [[[] for _ in range(num_images)]  for _ in range(imdb.num_classes)]

这里的只有存储单元,里面都空值。

步骤二、分类图像数据组织和填充,这里首先根据图像分类,按照类别对检测数据进行处理。前期处理:

from model.test import im_detect   im = cv2.imread(imdb.image_path_at(i))   scores, boxes = im_detect( net, im)

作用是返回这张图片中的多个目标和分数,存放在boxes和scores中。

主要处理:先获取上述过程中的为每一个图像分配的存储单元的尺寸数据,和图像数据集的数据,检测后,将数据进行填充。这里代码主要是:

inds = np.where(scores[:, j] > thresh)[0]  cls_scores = scores[inds, j]  cls_boxes = boxes[inds, j*4:(j+1)*4]  cls_dets = np.hstack((cls_boxes, cls_scores[:, np.newaxis])) \      .astype(np.float32, copy=False)  keep = nms(torch.from_numpy(cls_boxes), torch.from_numpy(cls_scores), NMS_THRESH)  cls_dets = cls_dets[keep, :]  all_boxes [j][i] = cls_dets

以上步骤完成后,all_boxes 里面已经有了数据。需要注意,这里的计算时间略长,大概要几分钟时间,需要等待。

步骤三、我们要把all_boxes的数据写入文件,这里调用imdb的函数:

imdb._write_voc_results_file(all_boxes)

write_voc_results_file 函数可以在pascal_voc.py的源代码中找到,完成之后,我们打开目录,/data/VOCdevkit2007/result/VOC2007/Main/下面目录,可以看到,每一类文件都做了单独存储,这里要注意,因为是modelart环境,每次产生文件名,里面有个计算机ID代码,每次启动,不一定是一样的。

2.4、计算AP和mAP

这里有两种方式,便捷的方式就是直接调用imdb.evaluate_detections(all_boxes, output_dir),可以忽略一些细节,使用默认设置,直接给出mAP。

第二种方式,我这里的做法是自己写了个文件voc_eval.py,提供voc_eval的函数供调用,这样更加灵活,也能更加符合我进行实验的目的,可以获得更加丰富的数据。voc_eval函数:

def voc_eval(detpath,         annopath,         imagesetfile,         classname,         cachedir,         ovthresh=0.5,         use_07_metric=False,         use_diff=False):

关键理如下:

1)读取文件数据,存入数据字典,这里的文件就是上述保存的文件位置,代码如下:

recs = {}#生成一个字典   for i, imagename in enumerate(imagenames): #对于每一张图像进行循环     recs[imagename] = parse_rec(annopath.format(imagename))#在字典里面放入每个图像缓存的标签路径     if i % 100 == 0:#在这里输出标签读取进度。         print('Reading annotation for {:d}/{:d}'.format(i + 1, len(imagenames)))#从这里可以看出来imagenames是什么,是一个测试集合的名字列表,这个Print输出进度。# save   print('Saving cached annotations to {:s}'.format(cachefile))#读取的标签保存到一个文件里面   with open(cachefile, 'wb+') as f:#打开缓存文件   pickle.dump(recs, f)#dump是序列化保存,load是反序列化解析

华为ModelArts-Lab拓展试验记录(二) 华为ModelArts-Lab拓展试验记录(二)

2)从以下代码开始就是具体计算了:

nd = len(image_ids) #统计检测出来的目标数量    tp = np.zeros(nd)#tp = true positive 就是检测结果中检测对的-检测是A类,结果是A类     fp = np.zeros(nd)#fp = false positive 检测结果中检测错的-检测是A类,结果gt是B类。   if BB.shape[0] > 0:#。shape是numpy里面的函数,用于计算矩阵的行数shape[0]和列数shape[1]

最后,每一类数据都会返回三个值:

rec: 召回率

prec:精确度

ap:平均精度

最后得出mAP:0.7020。

人工智能 AI

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:前端 vue 在可视化大屏领域的工作实践
下一篇:Oracle Linux 7.1使用源码安装Postgresql
相关文章