人工智能技术及应用 课件 张文安ch6-行人检测实践;ch7-车道线检测实践_第1页
人工智能技术及应用 课件 张文安ch6-行人检测实践;ch7-车道线检测实践_第2页
人工智能技术及应用 课件 张文安ch6-行人检测实践;ch7-车道线检测实践_第3页
人工智能技术及应用 课件 张文安ch6-行人检测实践;ch7-车道线检测实践_第4页
人工智能技术及应用 课件 张文安ch6-行人检测实践;ch7-车道线检测实践_第5页
已阅读5页,还剩65页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

6行人检测实践HISTORYOFDEVELOPMENTChapter06本章目录数据采集与标注01模型训练02模型转换与量化03项目落地与部署046行人检测实践本章主要介绍的是基于目标检测的行人识别,行人检测主要用于保障车辆盲区的安全,尤其是商用车,由于车身庞大,存在较多盲区,且车长带来的内轮差也会让行人不经意间就进入了车辆的危险区域。行人检测利用摄像头照射车辆盲区,一旦有行人进入盲区则对司机和行人进行提醒。整个项目主要流程如图所示,本章节也会按照该顺序依次讲解整个流程。6.1数据集采集与标注6.1.1素材采集数据来源主要有两个:1)公开数据集行人检测是一个应用范围比较广的项目,行人标签也是各大数据集中常见的标签,前期没有足够的“财力”和“精力”去收集、标注素材的情况下,使用公开数据集训练是一个不错的办法。除了深度学习界人尽皆知的coco、voc数据集,还有不少可以用来训练的带有行人标签的公开数据集,其实相比coco、voc数据集,这些数据集会更加符合本实践项目的场景。数据集:CaltechPedestrianDetectionBenchmark存放地址:/Image_Datasets/CaltechPedestrians/数据集:TheCityscapesDataset存放地址:/数据集:TheEuroCityPersonsDataset存放地址:https://eurocity-dataset.tudelft.nl/2)自主采集如果有私家车,并且装了行车记录仪,可以从行车记录仪中导出视频作为素材,如果没有,那么在视频网站搜索行车记录仪,也能获取到他人上传的行车记录仪视频,挑选清晰度较高的视频下载即可。6.1数据集采集与标注针对以上几点标注要求,给出几个标注的示例。1)如下左图人多杂乱,尽可能标记人能识别的人,远处杂乱无法区分轮廓的人不做标记。2)如上右图左边远处骑车可以辨别人形,需要标记;右边两人虽有重叠但依旧可以单独区分开,需要分开标记;中间的人手臂部分超出身体轮廓太多,仅标记身体部分;中间偏右的黑色人群无法区分不做标记。6.1数据集采集与标注针对以上几点标注要求,给出几个标注的示例。3)如下左图对于这类已经动态模糊比较严重的情况,不需要标记(图中框只是展示下),否则会对训练造成干扰。4)如上右图被护栏挡住的行人,如果某些角度隔着护栏依旧可以看到腿需要标注全身,若护栏将腿完全挡住,则仅标记身体露出的部分。6.1数据集采集与标注针对以上几点标注要求,给出几个标注的示例。5)如下左图人行道上的行人和骑车的人虽然被柱子和树遮挡,但依旧可以辨别为人,需要标记,但标记露出的部分,不要将柱子标记进去;对于骑车的人不要刻意去标记车的部分,把人的轮廓标记全,框里面尽量是人的信息。6)如上右图中间骑车带人虽然有两个人,但已经完全重叠,只需要标记一个即可。6.1数据集采集与标注6.1.3小结素材是一切深度学习项目的基础,行人识别的项目在素材采集和标注方面难度并不算太大。前期使用广大公开数据集的行人素材,也可以让算法得到一个不错的效果,但倘若要把效果做到更好,在素材方面则需要用更多真实的场景进行扩充。如今市面上还有很多素材标注公司,他们不光提供素材标注的服务,同时出售素材或者按需求采集素材,如果项目时间紧迫但有足够的预算,找他们帮忙也是一个不错的选择。6.2模型训练6.2.1模型设计思想本实验使用SSD的目标检测网络,在正式进入项目之前,简单介绍下其设计思想。若想了解详细细节,可以参考论文《SSD:SingleShotMultiBoxDetector》。SSD是一种引人注目的目标检测结构,它结合了直接回归框和分类概率的方法,又利用大量的预选框来提升识别准确度。ssd在预测阶段不仅仅使用最后一层的特征映射,而是取出中间层的特征,在不同尺寸的特征映射上对结果进行预测,虽然增加运算量,但使检测结果具有更多个可能性,从而提升精度。如图所示是ssd的模型,从图中可以看出SSD的主干网络为VGG网络,作者在VGG-16的基础上,将FC6和FC7层转化为卷积层,去掉了所有的Dropout层和FC8层,添加了Conv6,Conv7,Conv8和Conv9层。6.2模型训练为了从特征获取预测结果,分别取出conv4的第三层卷积特征、fc7卷积特征,conv6的第二次卷积特征,conv7的第二次卷积特征,conv8的第二次卷积特征和conv9的第二次卷积特征,共六个特征层作为有效特征层如图所示。对获取到的每个有效特征层做一次num_anchorsx4的卷积和一次num_anchorsxnum_classes的卷积,num_anchors指的是该特征层每一个特征点所拥有的先验框数量。上述提到的六个特征层,每个特征层的每个特征点对应的先验框数量分别为4、6、6、6、4、4。其中num_anchorsx4的卷积用于预测该特征层上每一个网格点上每一个先验框的变化情况;num_anchorsxnum_classes的卷积用于预测该特征层上每一个网格点上每一个预测对应的种类。利用num_anchorsx4的卷积对每一个有效特征层对应的先验框进行调整可以获得预测框。6.2模型训练SSD解码过程可以分为两部分:(1)将每个网格的中心点加上它对应的x_offset和y_offset,加完之后的记过就是预测框的中心;(2)利用h和w调整先验框获得预测框的宽和高。获得预测框的中心和宽高时,便可以在图片上绘制预测框了。但是想要获得最终的预测结果,还要对每一个预测框在进行得分排序与非极大抑制筛选,这一部分基本上时目标检测领域通用的部分。实现代码见代码清单6-3,这里仅展示部分代码importnumpyasnpimporttorchfromtorchimportnnfromtorchvision.opsimportnmsclassBBoxUtility(object):

def__init__(self,num_classes):

self.num_classes=num_classes

...6.2模型训练6.2.2数据集制作数据集制作采取VOC格式,在project下新建目录VOCdevkit,整个数据集的目录结构如下,将标签文件放在VOCdevkit文件夹下VOC_xxx下的Annotation中,将.jpg格式的图片放在JPEGImages中。VOCdevkit|--VOC_xxx|--JPEGImages存放图片|--Annotations存放xml标注文件|--ImageSets|--Main存放不带后缀的文件名列表|--subdir2...|--dir2...在完成数据集的摆放后,需对数据集进行下一步处理,目的是为了获得训练用的_xxx_train.txt和_xxx_val.txt,在工程下新建voc_annotation.py,脚本见代码清单6-46.2模型训练6.2.3训练如果训练过程中存在中断训练的操作,可以将model_path设置成logs文件夹下的权值文件,将已经训练了一部分的权值再次载入。同时修改下方的冻结阶段或者解冻阶段的参数,来保证模型epoch的连续性。当model_path=''的时候不加载整个模型的权值。此处使用的是整个模型的权重,因此是在train.py进行加载的,下面的pretrain不影响此处的权值加载。如果想要让模型从主干的预训练权值开始训练,则设置model_path='',下面的pretrain=True,此时仅加载主干。如果想要让模型从0开始训练,则设置model_path='',下面的pretrain=Fasle,Freeze_Train=Fasle,此时从0开始训练,且没有冻结主干的过程。一般来讲,从0开始训练效果会很差,因为权值太过随机,特征提取效果不明显。网络一般不从0开始训练,至少会使用主干部分的权值,有些论文提到可以不用预训练,主要原因是他们数据集较大且调参能力优秀。如果一定要训练网络的主干部分,可以了解imagenet数据集,首先训练分类模型,分类模型的主干部分和该模型通用,基于此进行训练。6.2模型训练6.2.3训练训练分为两个阶段,分别时冻结阶段和解冻阶段,显存不足与数据集的大小无关,提示显存不足请调小batch_size收到BatchNorm层影响,batch_size最小为2,不能为1。冻结阶段训练参数,此时模型的主干被冻结了,特征提取网络不发生改变,占用的显存较小进队网络进行微调。解冻阶段训练参数,此时模型的主干不被冻结了,特征提取网络会发生改变,占用的显存较大,网络所有的参数都会发生改变。Freeze_Train设为True,也就是默认先冻结主干训练后解冻训练。num_workers用于设置是否使用多线程读取数据,开启后会加快数据读取速度,但是会占用更多内存,内存较小的电脑可以设置为2或0。train_annotation_path和val_annotation_path是获取图片和标签的路径。6.2模型训练6.2.3训练运行train.py文件,如下左图可以观察到已经开始训练模型。训练完成之后可以观察到在log文件下,存取了训练过程中的权值文件,如上右图所示。6.2模型训练6.2.4预测和评估训练结果预测需要用到两个文件,分别是ssd.py和predict.py,代码详见本书附带资料,和之前一样,需要去ssd.py里面修改model_path以及classes_path为自己对应的训练权重文件和目标识别种类。在此我们选择上一步训练模型表现最好的权重,对应设置如下:"model_path":'logs/best_epoch_weights.pth',"classes_path":'model_data/cls_classes.txt',predict.py代码如下,该代码将单张图片预测、摄像头检测、FPS检测和目录遍历检测多功能融为一体,具体测试模式由参数mode决定,当mode为predict时表示单张图片预测;为video表示视频检测,可调用摄像头或者视频进行检测;为fps表示测试fps,使用的图片是img里的street.jpg;为dir_predict表示遍历文件夹进行检测并保存,默认遍历img文件夹,保存img_out文件夹,为export_onnx表示将模型导出为onnx。6.2模型训练6.2.4预测和评估在终端输入pythonpredict.py运行predict.py。运行时要求输入待检测图片的路径,在这里我们把测试图片test.jpg放入了img文件夹下,所以这里输入的路径为img/test.jpg,预测完成之后会将结果以img.img(如图所示)形式保存在工程根目录下。6.2模型训练6.2.4预测和评估评估需要用到get_map.py文件,同样需要设置model_path和classes_path,设置方式和预测时的设置相同。随后便可以在终端输入pythonget_map.py运行get_map.py文件,运行时在终端的显示如图所示,从图中可以看出此模型预测出行人这一类别时的AP值为91.23%,在门限值为0.5的情况下,F1值为0.85,召回率为73.81%,精确度值为99.20%。6.2模型训练6.2.4预测和评估不同门限值对应的F1值、召回率和精确度也对应绘制成了图片如图所示,保存至map_out文件夹中。6.3模型转换与量化6.3.1模型转换ONNX(OpenNeuralNetworkExchange)是一种开放的深度学习模型表示格式,它旨在提供一个通用的格式,用于在不同的深度学习框架之间无缝地交换模型。所以为了更好完成后续的部署工作,可将模型转换为onnx格式。具体是在predict.py中调用了ssd.py的方法convert_to_onnx,其实现代码见代码清单6-7,这里仅展示部分代码。defconvert_to_onnx(self,simplify,model_path):importonnxself.generate(onnx=True)

im=torch.zeros(1,3,*self.input_shape).to('cpu')#imagesize(1,3,512,512)BCHWinput_layer_names=["images"]output_layer_names=["output"]

#Exportthemodelprint(f'Startingexportwithonnx{onnx.__version__}.')torch.onnx.export(,调用时,我们只需在predict.py文件里将mode设置为export_onnx即可,随后保存predict.py文件,运行可以发现在model_data文件夹下生成了对应的model.onnx文件。6.3模型转换与量化6.3.2模型量化上面的所有步骤完成后,其实如果项目是用在PC端的,那么这个权重已经可以落地了,但是本章节的最终目标是将它在AIBOX中运行,所以针对AIBOX的环境,需要对模型文件进行量化。模型量化所需要用到的rknn-toolkit的container环境详见3.6章节。首先进入rknn-toolkit新建img文件夹存放一批素材用于量化,素材需要尽可能覆盖所有可能出现的场景,将它们的尺寸调整为网络输入的大小,并生成文件列表,程序见代码清单6-8,这里仅展示部分代码。defmain():img_path="./%s"%(img_flod)out_path="./%s%d_%d"%(img_flod,img_w,img_h)ifnotos.path.exists(out_path):os.mkdir(out_path)txt_file=open("./%s%d_%d.txt"%(img_flod,img_w,img_h),"w")......6.3模型转换与量化6.3.3小结模型训练阶段会遇到的各个步骤,也是深度学习项目中的重要环节之一,模型的训练结果很大程度上会直接影响到项目落地后的用户体验。在经历过不同硬件设备开发以后就会发现,量化也是整个过程中必不可少的一环,因为量化在加速推理的同时,也是对硬件环境的一种适配。其实即便是落地在PC上的项目,原模型可以直接运行的情况下,考虑到性能也会使用例如tensorRT等方式对模型进行量化。6.4项目落地与部署6.4.1项目工程工程目录结构如下otest|--sdk_rk1808相关sdk|--src源码 |--otest主模块程序 |--assets模型文件 |--test测试程序|--build_emv.cmake编译环境配置,供CMakeLists调用|--CMakeLists.txt用于生成makefile,各源码模块中也有对应文件,逐级调用6.4项目落地与部署源码读者可以直接从随书的资源中获取,本章节主要是梳理源码结构如图所示,对几个重要的模块进行讲解,帮助读者更快地理解代码。视频源:获取摄像头数据,用测试模块所配置的回调函数,向测试模块回调传输图像数据。测试模块:向视频源配置一个用于传输图像的回调函数,向主模块配置一个用于传输推理结果的回调函数。将视频源回调来的图像数据传给主模块推理,并将主模块回调来的推理结果提供给绘图模块。主模块:接收图像数据,用测试模块所配置的回调函数,向测试模块回调推理结果。主模块是另起线程进行异步推理,因为一旦推理的帧率低于视频源的帧率(25FPS)会导致阻塞。绘图:绘图模块将测试模块传输过来的推理结果,绘制在画面上用于展示。6.4项目落地与部署6.4.2源码解析1)主模块对模块进行初始化,代码见代码清单6-9,这里仅展示部分代码。if(item.image_header.width>0anditem.image_header.height>0){///默认值constchar*default_model="assets/model.rknn";constchar*default_prior_box="assets/otest_model_box_priors.txt";constchar*default_label_list="assets/otest_model_labels_list.txt";在初始化模块中,首先从传入的ini配置文件中读取模型文件,若没有配置这里直接给予了一个默认值。初始化推理模块后,程序可以直接从模型文件里读取模型的输入尺寸,然后利用初始化传入的视频源尺寸和模型的尺寸初始化rga。6.4项目落地与部署6.4.2源码解析1)主模块对rga进行初始化,代码见代码清单6-9,这里仅展示部分代码。boolret=false;ac::rga::SrcConfigsrc;ac::rga::DstConfigdst;autork_format=Convert2RkFormat(origin_header_.format);if(rk_format>=0){

///原始图片信息src.width=origin_header_.width;src.height=origin_header_.height;src.format=ac::rga::RkFormat(rk_format);在对rga初始化的过程中,需要指定原始图像的信息、原始图像中需要转换的部分、目标图像的信息,也就是告诉rga,需要从一种图转换成另一种图。6.4项目落地与部署6.4.2源码解析1)主模块更新最新图像,代码见代码清单6-9,这里仅展示部分代码。boolret=false;if(valid_flag_and(callback_.method!=nullptr)and(buffer_!=nullptr)and(notbuffer_->IsFull())and(data!=nullptr)and(size>0)){constauto&prev_pairs=rga_prev_->RgaBlit(reinterpret_cast<constuint8_t*>(data),size,true);......外部调用update函数,为主模块更新最新一帧的图像经过rga的转换送入缓冲区。取名更新也是因为,外部送入图片和主模块的推理是异步操作,中间用一个单项缓冲区连接,外部所传入的图片会不断更新缓冲区,内部在推理完成后会从缓冲区取数据。当处理的帧率低于视频帧率时,外部送入的图片会不断更新缓冲区的图片,从而保证每次推理的图片都是最近的视频画面。6.4项目落地与部署6.4.2源码解析1)主模块子线程循环推理,代码见代码清单6-9,这里仅展示部分代码。std::vector<TRectEx>boxes;while(true){///这一行代码可能阻塞constauto&pairs=buffer_->Read();constauto&img=std::get<0>(pairs);constauto&callback=std::get<1>(pairs);.........run函数循环运行在子线程中,直到反初始化或者析构时收到停止信号才会退出循环。该函数主要功能就是从缓冲区中取出图片进行推理,并将推理的结果,通过外部传入的回调函数传递出去。6.4项目落地与部署6.4.2源码解析2)推理模块推理模块的代码在ssd_detector.cpp中,主要工作就是调用rk的接口进行图片的推理,并对推理结果做后处理后输出。这部分其实就是将PC上的推理代码,将Python翻译成C++即可,读者可以对照着量化章节的代码阅读源码,这里不再赘述。6.4项目落地与部署6.4.3部署工程开发环境的搭建可以参考3.6.WSL安装,以下的全部指令都是在WSL下运行。新建build文件夹,并进入到build中,执行cmake命令。cmake..当看到如下打印时则表明执行成功。--Configuringdone--Generatingdone执行编译makeinstall如果没有报错并且打印了一连串的--Installing:信息,则表示执行成功。6.4项目落地与部署6.4.3部署工程至此在build下会生成一个install的目录,结构如下:install |--otest |--assets模型文件,从src/otest/assets中拷贝过来的 |--otest_model_box_priors.txt |--otest_model_labels_list.txt |--otest_model.rknn |--include主模块库的头文件,从src/otest中拷贝过来的 |--otest_proc.h |--lib主模块的库文件和相关联的一些库 |--libotest_proc.so |--libpredictor.so |--... |--test_test可执行文件,测试模块编译出来的6.4项目落地与部署6.4.3部署工程进入到install文件及下,将程序推入AIBOX。adbpushotest/home如果是通过网线链接AIBOX也可以直接拖拽进去。进入到AIBOX中,进入刚才推送程序的路径,这里是/home/otest,对可执行程序赋权限后执行chmod755test_test./test_test程序开始运行,并打印出如下图所示的单张图片的推理速度、当前的推理帧率、视频流帧率。6.4项目落地与部署6.4.3部署工程程序运行结果如下图所示。6.4项目落地与部署6.4.4小结至此整个行人识别实验全部完成,如果读者照着这个流程走完一遍,不妨运行起程序,拿起摄像头对准身边的那个人,看看他是否被框中显示在屏幕上。其实所有的深度学习落地项目都会经历这几个步骤,更进一步的,可以在落地的程序上对模型的输出结果按照个人的需求做其他的逻辑,比如限定行人的远近、范围,这些就有待读者发散思维进行探索了。6.5课后习题

1)什么是行人检测?2)行人检测有哪些方法?3)什么是SSD算法?7车道线检测实践LANELINEINSPECTIONPRACTICEChapter07本章目录数据采集与标注01环境部署02模型训练03模型的量化04项目部署与落地05本章总体介绍车道线检测是辅助驾驶中必不可少的一项,它的主要目标是通过计算机视觉和图像处理技术,从道路图像中精确提取出车道线的位置和形状信息。这些提取到的车道线信息可以用于车道保持、车道偏离预警、自动驾驶路径规划等应用。通过实现准确的车道线检测系统,可以提高驾驶安全性,减少交通事故的发生,并为驾驶员提供更好的驾驶体验。基于视觉的车道线检测方法可以分为:传统图像方法和深度学习方法两类。其中传统的图像检测方法可以通过边缘检测、滤波或是颜色空间的车道线检测等方式得到车道线区域,再结合相关图像检测算法实现车道线检测。但面对环境明显变化的场景并不能很好的检测,工作量大且鲁棒性差。而深度学习的方法有较好的鲁棒性,且准确率更高。它大致有基于分类和目标检测的方法和基于端到端图像分割的方法等相关车道线检测方法。而本书的车道线检测采用的是UNet的语义分割网络。本章总体介绍车道线检测算法的流程如下图所示。主要思路是:通过素材采集获取训练要用的原始数据,再经过标注与生成标签图两个步骤将原始数据转化为可以被学习训练的素材,然后通过模型训练得到相应模型,最后经过模型量化、转换和部署等步骤将模型优化并转化成可被嵌入式平台运行的程序。车道线项目流程图7.1数据集采集与标注素材的获取一般有两种途径,一种是自己利用相关设备如行车记录仪获取,另一种是通过下载公开的数据集获取。车道线检测相关的数据集有TuSimple、CULane、CurveLanes、BDD100k等。素材标注使用Labelme工具,本项目提供的例程的“数据集”文件夹内已经提供原图与对应标注文件,车道线识别项目对于车道线的标注有以下几点要求:需要标注的内容为图片中人眼可以识别的车道线,包括实线、虚线、白线和黄线。对于双线的车道线,两条分开标注。对于虚线中间没有车道线的部分进行补足。对于没有车道线的图片,直接跳过,不做处理。7.1数据集采集与标注下图是按以上要求所给出的标注示例。车道线项目流程图相较于分类和目标检测,语义分割的素材多了一步从标签文件到分割图的转换。因为语义分割是像素级别的推理,每个像素点都有其对应的标签,因此在训练中,它的标签就是和它等大的一张分割图。7.2环境部署深度学习的框架除了PyTorch外还有TensorFlow框架,本项目在TensorFlow框架下训练,所以在进行本章之前需要进行TensorFlow环境的搭建,其环境总体搭建步骤如下:(1)在Ubuntu系统(WSL2、虚拟机或多系统)下搭建TensorFlow环境的docker(2)在docker环境内安装本项目的相关库当然,若有需求也可以在创建一个docker容器后,在其内部建立conda的虚拟环境,然后安装本项目需要的TensorFlow环境与相关库。7.2环境部署7.2.1docker环境部署针对不同的显卡,需要搭建不同的环境。本项目以30系显卡为例进行环境搭建介绍,30系显卡需要CUDA11.1,可以使用NVIDIA提供的docker镜像—NVIDIA-TensorFlow。如果没有安装过NVIDIA-docker,首先要进行NVIDIA-docker的安装,它是使用上述镜像的前提,如下是安装步骤:$distribution=$(./etc/os-release;echo$ID$VERSION_ID)$curl-s-Lhttps://nvidia.github.io/nvidia-docker/gpgkey|sudoapt-keyadd-$curl-s-Lhttps://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list|sudotee/etc/apt/sources.list.d/nvidia-docker.list$sudoapt-getupdate$sudoapt-getinstall-ynvidia-docker27.2环境部署7.2.1docker环境部署接着进行NVIDIA-TensorFlow的docker环境部署#拉取镜像nvidia-dockerpullnvcr.io/nvidia/tensorflow:20.10-tf1-py3#创建容器nvidia-dockerrun-d-it-p10022:22-p10500:5000-v/home:/home--namenvidia_tensorflownvcr.io/nvidia/tensorflow:20.10-tf1-py3#-p代表了端口的映射-p宿主机端口:容器端口这里预留了22可以用于ssh登录5000后面会用到#进入容器nvidia-dockerexec-itnvidia_tensorflow/bin/bash安装TensorFlowwheel的索引pipinstallnvidia-index用官方提供的命令安装依赖的包pipinstallnvidia-tensorflow[horovod]7.2环境部署7.2.1docker环境部署下载完成后进入对应的目录,因为这些依赖包安装存在一定顺序,所以按以下顺序执行指令。若觉得一条一条执行繁琐,可以建一个后缀名为.sh的shell脚本文件,将下列指令复制进文件后执行sh文件名.sh指令提高效率。pipinstallgoogle_pasta-0.2.0-py3-none-any.whlpipinstallnvidia_cublas-4-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cuda_cupti-11.1.69-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cuda_nvcc-11.1.74-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cuda_cupti-11.1.69-cp36-cp36m-linux_x86_64.whlnvidia_cuda_nvcc-11.1.74-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cuda_nvrtc-11.1.74-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cuda_runtime-11.1.74-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cudnn-8.0.70-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cufft-4-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_curand-4-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cusolver-4-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_cusparse-75-cp36-cp36m-linux_x86_64.whl7.2环境部署7.2.1docker环境部署pipinstallnvidia_dali_cuda110-0.26.0-1608709-py3-none-manylinux2014_x86_64.whlpipinstallnvidia_dali_nvtf_plugin-0.26.0+nv20.10-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_nccl-2.7.8-cp36-cp36m-linux_x86_64.whlpipinstallnvidia_tensorboard-1.15.0+nv20.10-py3-none-any.whlpipinstallnvidia_tensorrt--cp36-none-linux_x86_64.whlpipinstallnvidia_tensorflow-1.15.4+nv20.10-cp36-cp36m-linux_x86_64.whlpipinstalltensorflow_estimator-1.15.1-py2.py3-none-any.whlpipinstallnvidia_horovod-0.20.0+nv20.10-cp36-cp36m-linux_x86_64.whl此外本项目还需要用到以下几个Python包,读者可以使用以下命令安装或者直接使用项目中的requirements.txt导入。pipinstallscipy==1.1.0-i/simplepipinstallscikit-learn-i/simplepipinstalltqdm-i/simple7.2环境部署7.2.2安装TensorFlowObjectDetectionAPITensorFlowObjectDetectionAPI是一个基于TensorFlow构建的开源框架,用于目标检测任务。它提供了丰富的目标检测模型,其中包括了一些经典的模型架构,如FasterR-CNN、SSD、Mask-RCNN等,具体可见TensorFlow的GitHub的model仓库。7.3模型训练项目文件夹为project,项目目录如图。“部署代码”文件夹包含的是模型部署的代码,“权重转换与量化”包含的是模型量化转换的相关代码,本节介绍“训练代码”和“数据集”文件夹部分,实现数据集制作与模型训练与保存。标签转换程序、数据集制作程序和模型及训练程序这三部分对应在“训练代码”文件夹下,分别对应的是ldw_draw.py、make_dataset.py和剩下其他程序,目录结构如图所示。models内存有模型程序,builders内存有模型接口程序,utils是相关的辅助函数集合,train.py是模型训练程序,ckpt2pb.py是将训练完成后的ckpt文件转换为pb文件的程序,eval.py是评估程序用训练过程中保存的pb文件进行推理。项目目录结构traincode目录结构7.3模型训练7.3.1模型设计思想本项目使用UNet的语义分割网络,从图中可以看到,其形状类似字母“U”所以被称为UNet。参考论文《U-Net:ConvolutionalNetworksforBiomedicalImageSegmentation》,起初UNet被用于医学领域,而后UNet凭借着突出的效果被广泛应用。UNet本质上是一个编码器和解码器的结构,左边是特征提取,右边是采样恢复原始分辨率,中间采用跳层链接的方式将位置信息和语义信息融合。UNet网络结构7.3模型训练7.3.2标签转换7.1节中标注完的素材仅仅是多了一个标签文件,保存了所标注的那些多边形的类别和位置。而实际在训练中用到的是像素级别的标签,也就是对于原图上每个像素点,都会有一个对应了类别的标签,这个时候就需要利用标注文件来生成分割用的标签图。本项目提供的标签转换程序为ldw_draw.py。详见代码清单7-1。将对应脚本—ldw_draw.sh中的Path参数配置成读者自己电脑上的标注图片的所在目录,执行脚本,结果如下。image中存放原始图片;json中存放标注文件;roadmap中存放分割标签图片,转换后的目录结构和图片经过转换后的结果如图所示。转换后的目录结构转换前后对比,原图(左),转换后图(右)7.3模型训练7.3.3数据集制作在project下的“数据集”目录中放置数据集,在“数据集”下再建一层子目录,用于数据集分类。这里就以type1、type2为例,将转化完成后的素材文件夹放入子文件夹中。对于本项目提供的例程,需要将“数据集”文件夹内data文件夹放入“训练代码”文件夹内make_dataset.py所在目录下,或者读者可以修改make_dataset.py的相关路径。详见代码清单7-2。将脚本—make_datase.sh中的dataset参数配置成data下的子目录,样例数据集中有两个子目录type1、type2,存有上一小节所转换的相关素材。input_height和input_width根据实际情况配置,所演示的项目中是256*128。修改make_datase.sh中的type1、type2后分别执行。完成后其目录结构如图所示,新增两个文件夹。数据集制作后的目录结构7.3模型训练7.3.3数据集制作新增文件夹的目录结构如图所示,test:测试集图片;test_label:测试机标签;train:训练集图片;train_label:训练集标签;val:验证集图片;val_label:验证集标签。同时,处理完的素材文件夹会被移动到data/done下面,以便于未来多次制作数据集时不会重复操作。新增文件夹的目录结构7.3模型训练7.3.4网络搭建在“训练代码”文件夹下models目录中放置需要搭建的模型文件,这里就以上面提到的UNet为例。本项目提供的例程在models下有一个UNet.py程序。详见代码清单7-3。在traincode下builders目录,本项目提供一个model_builder.py程序作为创建模型总的接口,用于不同类型模型的选择和搭建。importsys,osimporttensorflowastfimportsubprocess#存放模型的目录sys.path.append("models")#载入模型的搭建函数frommodels.UNetimportbuild_unet#自定义模型名称SUPPORTED_MODELS=["UNet"]#统一的模型搭建接口defbuild_model(model_name,net_input,num_classes,is_training=False):print("Preparingthemodel...") ifmodel_namenotinSUPPORTED_MODELS: raiseValueError("Themodelyouselectedisnotsupported.Thefollowingmodelsarecurrentlysupported:{0}".format(SUPPORTED_MODELS)) network=None #根据模型名称调用对应的模型搭建函数

ifmodel_name=="UNet": network=build_unet(net_input,num_classes,is_training=is_training) else: raiseValueError("Error:themodel%disnotavailable.Trycheckingwhichmodelsareavailableusingthecommandpythonmain.py--help") returnnetwork7.3模型训练7.3.5模型训练训练的代码由相关数据的读取、训练参数设置、数据增强、训练信息显示及保存、继续训练等相关部分构成。在训练开始前,需要对训练进行一些相关参数的设置,其中一些参数的设置将会影响训练模型的效果。相关参数有:num_epochs:总训练轮数;epoch_start_i:开始轮数,配合继续训练使用,程序会自动加载epoch_start_i-1的权重;validation_step:间隔多少轮验证一次模型;continue_training:是否继续训练;dataset:数据集,可配置列表;imgprocess:载入图片操作,裁剪或者缩放;input_height:网络输入的高;input_width:网络输入的宽;batch_size:每个批次图片数量;num_val_images:每次验证取多少张验证集中的图片;h_flip:数据增强是否进行水平翻转;v_flip:数据增强是否进行垂直翻转;brightness:数据增强是否随机亮度;color:数据增强是否随机添加颜色;rotation:数据增强随机旋转角度;model:训练的模型;savedir:保存的路径;7.3模型训练7.3.5模型训练数据增强是一种在深度学习中广泛使用的技术,用于扩充训练数据集,以提高模型的泛化能力和鲁棒性。数据增强通过对原始训练数据应用一系列随机变换或变形操作,生成额外的训练样本,从而增加数据的多样性。数据增强部分,程序根据读者传入的训练参数,再载入每个批次的图片时会对图片进行随机数据增强的操作。详见代码清单7-4。损失函数,也称为目标函数或代价函数,是深度学习模型中的一个关键组成部分。损失函数用于度量模型的预测输出与真实标签之间的差异或错误程度,通过最小化该差异来优化模型的参数。本项目损失函数部分采用的是focal_loss,其主要侧重于根据样本的难易程度给样本对应的损失增加权重。deffocal_loss(prediction_tensor,target_tensor,weights=None,alpha=0.25,gamma=2):

sigmoid_p=tf.nn.sigmoid(prediction_tensor)#创建一个将所有元素设置为0的张量

zeros=array_ops.zeros_like(sigmoid_p,dtype=sigmoid_p.dtype)#正样本损失(车道线)

pos_p_sub=array_ops.where(target_tensor>zeros,target_tensor-sigmoid_p,zeros)#负样本损失(背景)

neg_p_sub=array_ops.where(target_tensor>zeros,zeros,sigmoid_p)#-ylog(p^)-(1-y)log(1-p^)

per_entry_cross_ent=-alpha*(pos_p_sub**gamma)*tf.log(tf.clip_by_value(sigmoid_p,1e-8,1.0))-(1-alpha)*(neg_p_sub**gamma)*tf.log(tf.clip_by_value(1.0-sigmoid_p,1e-8,1.0))returntf.reduce_mean(per_entry_cross_ent)7.3模型训练7.3.5模型训练载入每个批次的图片,语义分割的标签是一张图,所以在送入网络之前要对rgb对应的标签做一次转化,再进行独热编码(one-hot)。defone_hot_it(label,label_values):semantic_map=[]#label_values从csv文件中载入forcolourinlabel_values:equality=np.equal(label,colour)class_map=np.all(equality,axis=-1)semantic_map.append(class_map)semantic_map=np.stack(semantic_map,axis=-1)returnsemantic_map评估指标部分,打印了整体分数、各类别分数、F1、IOU。defevaluate_segmentation(pred,label,num_classes,score_averaging="weighted"):flat_pred=pred.flatten()flat_label=label.flatten()#计算全局的分数

global_accuracy=compute_global_accuracy(flat_pred,flat_label)#计算每个类别的分数

class_accuracies=compute_class_accuracies(flat_pred,flat_label,num_classes)#计算精确率

prec=precision_score(flat_pred,flat_label,average=score_averaging)#计算召回率

rec=recall_score(flat_pred,flat_label,average=score_averaging)#计算F1f1=f1_score(flat_pred,flat_label,average=score_averaging)#计算IOUiou=compute_mean_iou(flat_pred,flat_label)returnglobal_accuracy,class_accuracies,prec,rec,f1,iou7.3模型训练7.3.5模型训练执行文件夹内的train.sh脚本后进行训练,其训练部分过程如图所示。训练过程7.3模型训练7.3.5模型训练训练结束后将多出一个checkpoints文件夹,如图所示。训练后文件夹结构checkpoints文件夹中包含了训练过程中的一些保存信息,如图所示。训练信息保存文件夹结构其中每个文件夹内保存了对应epoch的训练信息,训练是以ckpt的形式保存模型的,包含三个文件:(1).mate文件保存了当前图结构(2).data文件保存了当前参数名和值(3).index文件保存了辅助索引信息7.3模型训练7.3.5模型训练这里需要把ckpt固化成pb模型文件,真正部署的时候,一般不会提供ckpt的模型,而是固化成pb模型。程序见ckpt2pb.py,如图所示,其中frozen_graph.pb文件就是后续小节“模型转换”所需要的模型保存文件。在评估阶段会用到数据集中的test部分,由于目录结构类似,所以这一部分的代码其实就是train中验证部分给单独提取出来,用训练过程中保存的pb文件进行推理,代码详见eval.py,运行脚本后会从train目录的checkpoint文件中找到model_checkpoint_path权重进行评估。run_once参数的作用在于是否定时对权重进行评估,eval操作是可以和train同时进行的,因为train会定期保存权重,对应的checkpoint中model_checkpoint_path权重随之变化,所以可以实时对权重进行评估,如图所示。保存节点文件夹结构评估结果7.4模型的量化7.4.1RKNN量化上面的所有步骤完成后,其实如果项目是用在PC端的,那么这个权重已经可以落地了,但是本章节的最终目标是将它在AIBOX中运行,所以,针对AIBOX的环境,需要对模型文件进行量化。模型量化所需要用到的RKNN-toolkit的container环境详见前面章节。本书提供的此部分代码在“权重转换与量化”文件夹下,结构如图所示。这部分的作用是将模型转化成RV1808芯片可用的类型,从而实现后续的部署。其中ldw.py是将pb文件转换为RKNN文件的程序,resize_ldw.py是调整素材的程序,test.py用于生成后的RKNN模型的推理。ret.png是执行推理后的结果,它表示所转化的RKNN模型文件可以实现车道线的检测,并能看出其检测效果。RKNN模型转换文件夹结构7.4模型的量化7.4.1RKNN量化其中有一个注意点,就是图片输入的顺序。车道线检测的模型,用于输入网络训练的图片其通道次序为BGR,按照训练和部署需要统一的标准,部署在AIBOX上送入网络推理的图片通道次序也应该是BGR。RKNN的量化过程中,程序会读取一个列表中的图像送入网络量化,内部读取图片的方式是按照RGB来的,和OpenCV是相反的。所以如果要用BGR的图片进行量化,在准备数据集的时候,如果用OpenCV打开,就要做一步操作,就是BGR2RGB。虽然参数上是BGR到RGB的转化,但本质上是通道变更,当OpenCV将图片按照RGB的格式保存以后,其他默认以RGB载入图片的包将图片加载后,实际得到的就是BGR。首先准备好一批素材用于量化,素材需要尽可能覆盖所有可能出现的场景,将它们的尺寸调整为网络输入的大小,并生成文件列表,程序见代码清单7-5。然后运行ldw.py程序将pb模型转换为RKNN模型,程序见代码清单。7.4模型的量化7.4.1RKNN量化量化部分重点要讲的是推理的部分,在PC上推理出正确的结果,那么在部署的时候只需要把对应的Python代码翻译成C++即可。PC推理的代码在test.py中,核心代码片段如下。print('-->Runningmodel')outputs=rknn.inference(inputs=[img])print('done')

nout=len(outputs)foriinrange(np.array(outputs).shape[2]):l1=outputs[0][0][i][0]l2=outputs[0][0][i][1]ifl1>l2:#这里可以参考训练工程中的输出节点来理解

#logit=tf.reshape(network,(-1,args.input_height*args.input_width,num_classes),name='logits')

#当通道0的数值大时则该像素格推理为背景,填充0,黑色

#当通道1的数值大时则该像素格推力为车道线,填充255,白色

img[i//img_w][i%img_w][0]=0

img[i//img_w][i%img_w][1]=0

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论