




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
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
img[i//img_w][i%img_w][2]=0else:
img[i//img_w][i%img_w][0]=255
img[i//img_w][i%img_w][1]=255
img[i//img_w][i%img_w][2]=255cv2.imwrite("ret.png",img)7.4模型的量化7.4.1RKNN量化结合代码中注释来解释。推理后的输出有4个维度,第一个维度是rk中输出节点,当前项目只有一个输出,所以这一维度是1;第二个维度是图片的张数,其实也就是batchsize,这里也是1,这两个维度在本项目中没有作用;第三个维度是在训练时将图片的宽高两个维度给转化成了一维,还是可以按照h*w的排布来解析;第四个维度是通道,这里是对应像素点上0通道的值和1通道的值,其实也就是对应类别的分数。在解析的过程中,只需要取分数大的通道作为当前像素格上的推理结果即可。下图为推理过程及推理后的结果。推理过程推理结果原图(左)推理后(右)7.4模型的量化7.4.2小结通过上述项目的量化过程可以看到,量化是整个过程中必不可少的一环,因为量化在加速推理的同时,也是对硬件环境的一种适配。其实即便是落地在PC上的项目,原模型可以直接运行的情况下,考虑到性能也会使用例如TensorRT等方式对模型进行量化。在这个阶段需要关心的只是送入网络的图片和网络输出的数据解析。为了让模型在项目部署落地上有最佳的表现,训练、量化、落地这三个阶段所有的素材、网络输入输出都必须有统一标准。7.5项目部署与落地经过上述几个环节得到RKNN文件后,我们就能将模型移植进RV1808芯片的嵌入式板子中了,这部分就是嵌入式开发的工作。通过AIBOX的摄像头得到输入图像,经过前面得到的模型实现车道线检测,将其绘制输出到显示屏上。其逻辑和上一节的推理过程类似。此部分代码例程在“部署代码”文件夹下,其结构如图所示。其中build用于camke与make生成文件的存放,build_emv.cmake用于编译环境配置,供CMakeLists调用,CMakeLists.txt用于生成makefile,各源码模块中也有对应文件,逐级调用。sdk_rk1808文件夹保存相关的sdk,src是源码,其结构如图所示。在./src/stest/assets/rk1808下存放RKNN模型文件,在./src/test下是测试程序。部署代码文件夹结构src文件夹结构7.5项目部署与落地7.5.1源码解析本小节仅对关键函数进行解析,其他可见源码的注释。主模块,对rga进行初始化。详见代码清单7-6。车道线检测需要推理的仅仅是图片的下半部分,在程序中rga初始化的部分,就要和训练时数据集处理步骤对应起来,先裁剪下半部分,再缩放到网络输入的大小。子线程循环推理,详见代码清单。这部分代码中,因为本项目仅介绍到模型推理的部分,单纯从语义分割的结果上来看,到这一步回调给外部的就是一张和标签图类似的图片。实际车道线项目中会在推理结果的基础上做进一步的后处理,然后依据上层应用的需求返回车道线。推理模块,网络输出转换为像素格类别。详见代码清单。这部分代码就是PC上测试代码的翻译,函数中做了nhwc和nchw的兼容,这一部分信息RKNN在量化时已经写入了模型中。TensorFlow默认是nhwc排布,所以本项目中值用到了判断的第一个分支,感兴趣的读者可以尝试用PyTorch搭建复现模型,然后同样可以用这份代码落地。7.5项目部署与落地7.5.2部署工程使用本书提供的例程,进入“部署代码”文件夹,进入build中,执行cmake命令。cmake-DTARGET_SDK=../sdk_rk1808..当看到如下打印时则表明执行成功。--Configuringdone--Generatingdone执行编译makeinstall如果没有报错并且打印了一连串的--Installing:信息,则表示执行成功。至此在build下会生成一个install的目录,结构如图所示。其中assets是模型文件,从src/otest/assets中拷贝过来的;include是主模块库的头文件,从src/otest中拷贝过来的;lib是主模块的库文件和相关联的一些库;test_test是生成的可执行文件。可执行文件所在文件夹结构7.5项目部署与落地7.5.2部署工程进入到install文件夹下,将程序推入AIBOX。adbpushotest/home如果是通过网线连接,AIBOX也可以直接拖拽进去。进入到AIBOX中,进入刚才推送程序的路径,这里是/home/otest,对可执行程序赋权限后执行。chmod755test_test./test_test程序开始运行,并打印出如图所示的单张图片的推理速度、当前的推理帧率、视频流帧率。处理信息打印7.5项目部署与落地7.5.2部署工程程序运行结果如图所示。终端识别结果(1)终端识别结果(2)课后习题1)什么是车道线检测?2)车道线检测有哪些方法?3)什么是数据增强?4)车道线检测有哪些挑战?5)如何克服这些挑战?8人脸检测实践FACIALDETECTIONPRACTICEChapter02学习目标数据集采集与标注01模型训练 02模型量化03项目落地与部署048人脸检测实践本章介绍的是人脸检测项目,顾名思义,就是通过目标检测方法获取图像中的人脸,本项目还包括同时获取人脸的五个关键点,包括两只眼睛、鼻子和两嘴角。单纯的人脸检测是人脸关键点检测的前提,但由于本项目同时检测人脸和关键点,因此不需要再单独实现人脸关键点检测功能,这能大大提升程序的整体运行速度。人脸检测的主要应用场景有智慧人脸考勤、刷脸闸机通行、门禁、人脸特效美颜、名人换脸等。
接下来介绍本项目人脸检测的主要流程,如右图所示,后续将详细介绍流程每一节点。8.1数据集采集与标注8.1.1素材采集本项目的素材来源主要有两个:1)公开数据集本项目使用WIDERFACE数据集,下载网址是http://shuoyang1213.me/WIDERFACE/。根据官网的介绍,WiderFace数据集最早是在2015年公开的(v1.0版本)。该数据集的图片来源是WIDER数据集,从中挑选出了32,203图片并进行了人脸标注,总共标注了393,703个人脸数据。并且对于每张人脸都附带有更加详细的信息,包括expression(表情),illumination(光照),occlusion(遮挡),pose(姿态)等,如图所示,后面会进一步介绍。8.1数据集采集与标注8.1.1素材采集数据集文件结构如右所示,包含人脸检测和人脸关键点数据集,分别存放于WIDER_FACE_rect和WIDER_FACE_landmark文件夹。#人脸检测数据集├──WIDER_FACE_landmark│├──annotations│ ├──0--Parade│ ├──0_Parade_marchingband_1_849.xml│├──images│ ├──0--Parade│ ├──0_Parade_marchingband_1_849.jpg#人脸关键点数据集├──WIDER_FACE_rect│├──annotations│ ├──0--Parade│ ├──0_Parade_marchingband_1_849.xml│├──images│ ├──0--Parade│ ├──0_Parade_marchingband_1_849.jpg8.1数据集采集与标注8.1.1素材采集WIDER_FACE_rect文件夹包含61类人脸,共12880张jpg格式的图片和xml格式的标签,分别存放于当前目录下的images和annotations文件夹中,xml标签文件包含了图片所有人脸的坐标。xml标签文件内容如下所示:<?xmlversion="1.0"?><annotation> #标签对应的图像名称<filename>1501925967889.jpg</filename>#图像大小,包括宽、高和通道数<size><width>640</width><height>480</height><depth>3</depth></size>#人脸目标<object><name>face</name><truncated>1</truncated><difficult>0</difficult> #人脸框左上角和右下角坐标<bndbox><xmin>317</xmin><ymin>0</ymin><xmax>534</xmax><ymax>200</ymax></bndbox> #无人脸关键点<has_lm>0</has_lm></object></annotation>8.1数据集采集与标注8.1.1素材采集WIDER_FACE_landmark文件夹包含了同样类别的人脸,共12596张图片和标签,同样分别存放于当前目录下的images和annotations文件夹中,xml标签文件包含了图片所有人脸关键点的坐标。与WIDER_FACE_rect中相同人脸图像对应的人脸关键点标签文件内容如下所示:<?xmlversion="1.0"?><annotation> #标签文件对应的图像,与上一标签图像名称相同,不同是标签包含的信息有区别<filename>1501925967889.jpg</filename>#图像大小,包括宽、高和通道数<size><width>640</width><height>480</height><depth>3</depth></size>#人脸目标
<object><name>face</name><truncated>1</truncated><difficult>0</difficult>#人脸框左上角和右下角坐标<bndbox><xmin>317</xmin><ymin>0</ymin><xmax>534</xmax><ymax>200</ymax></bndbox> #人脸框对应的人脸关键点坐标,包括两只眼睛、鼻子和两嘴角坐标<lm><x1>389.362</x1><y1>38.352</y1><x2>478.723</x2><y2>36.879</y2><x3>451.773</x3><y3>85.816</y3><x4>405.674</x4><y4>137.589</y4><x5>482.27</x5><y5>133.333</y5></lm> #有人脸关键点<has_lm>1</has_lm></object></annotation>8.1数据集采集与标注8.1.1素材采集2)自主采集由于不同摄像头采集的图像其特征存在差异,因此利用公开数据集训练得到的模型有时候不一定能在自己摄像头获取的图像上推理成功,这时就需要使用自己摄像头采集的数据集进行训练,来减少训练图像和推理图像特征之间存在的差异,从而提升图像推理成功率。自主采集首先需确定摄像头类型,然后利用第3.2.4节介绍的方式进行素材采集,此处不再赘述。通过自主采集获得数据集之后,需要将数据集按WIDERFACE数据集结构形式存放,有利于后续的数据集制作和数据集加载。8.1数据集采集与标注8.1.2素材标注公开数据集已包含训练所需的人脸框和关键点标签信息,因此无需再对其进行标注,现主要针对自主采集的素材进行标注。首先,根据项目的具体任务选择合适的标注软件。本项目的任务是对图像中的人脸及其5个关键点进行检测,也就是说标注素材时既需要标注人脸框,也需要标注人脸关键点,本项目选择LabelImge和Sloth标注软件分别对人脸和关键点进行标注。其次,标注之前,需要明确本项目的图像标注要求。可结合项目的具体需求对自主采集的素材进行标注,标注要求如下:1)标注人脸框时,人脸框需包含整个人脸轮廓,不包含耳朵和额头往上的头发部分;标注人脸关键点时,关键点应在眼睛开合处的中心、鼻尖和嘴角如图(a)所示。2)当人脸是侧脸,且看不见该人脸的眼睛、鼻子和嘴巴时,不标注人脸框及其关键点,如图(b)所示。3)当人脸被遮挡,且看不见该人脸的眼睛、鼻子和嘴巴或者遮挡超过一半时,不标注人脸框及其关键点,如图(c)所示。4)因图像较为模糊、曝光较强、光线较暗导致人脸特征不清晰时,不标注人脸及其关键点,如图(d)所示。8.2环境部署 本项目采用的深度学习框架是PyTorch,版本为2.0.1。假设已安装PyTorch2.0.1虚拟环境,还需安装的Python依赖包及其版本如下所示。PackageVersion-----------------------------------------albumentations1.0.3matplotlib3.3.4numpy1.19.2onnx1.9.0onnx-simplifier0.3.6onnxoptimizer0.2.6onnxruntime1.8.0opencv-pythonopencv-python-headless6Pillow8.2.0protobuf3.17.2scikit-image0.17.2scipy1.5.4tqdm4.62.28.2环境部署 建议将上述依赖包写入requirements.txt中,然后使用pipinstall-rrequirements.txt自动安装。如果建议方法安装较慢,也可使用pip单独进行安装,命令最后加上国内源,如下所示,即可加快安装速度。pipinstallalbumentations=1.0.3-i/ubuntu/8.3模型训练8.3.1训练代码准备从/ShiqiYu/libfacedetection.train.git下载训练代码。代码包含两部分,如下所示,一部分是数据集制作、iou损失计算、nms、预选框生成等模块,一部分是网络定义、训练、测试和ONNX模型转换等相关脚本。├──src│├──data.py│├──eiou.py│├──multibox_loss.py│├──nms.py│├──prior_box.py│├──timer.py│└──utils.py└──tasks └──task1 ├──config.py ├──datasets.py ├──detect.py ├──exportcpp.py ├──exportonnx.py ├──test.py ├──train.py └──yufacedetectnet.py。8.3模型训练8.3.2模型设计思想本项目采用的模型YuFaceDetectNet是一个轻量级的SSD架构,该网络实现了多个尺度特征预测,这大大提升了小目标的检测精度,同时该网络还借鉴了RetinaFace回归关键点的方法,可以在回归人脸框的同时回归该人脸的5个关键点。下面通过代码实现的方式详细介绍该网络模型。首先,定位到项目中train.py中模型的入口,如下代码所示:#从模型定义文件中导入模型类from
yufacedetectnet
import
YuFaceDetectNet#模型输入img_dim
=
160#加载模型net
=
YuFaceDetectNet('train',
img_dim)然后,定位至yufacedetectnet.py中的YuFaceDetectNet类,见书本246页代码所示,从__init__、multibox和forward三个模块可知,本项目采用的模型由特征提取网络和SSD检测头组成,特征提取网络采用类似VGG的直筒式结构,由多组卷积层以及最大池化层完成下采样,每组卷积层由两到三个卷积模块组成[3*3+1*1]或[3*3+1*1+3*3]的组合,每个卷积模块由卷积Conv2d、归一化BatchNorm2d和激活函数ReLu构成,即网络代码里的self.model1~self.model6。图像经过上述特征提取网络得到四个特征层的特征,分别是self.model3、self.model4、self.model5、self.model6层的输出,这四个层的特征通过SSD检测头最终输出人脸框位置loc、置信度conf和iou。8.3模型训练8.3.2模型设计思想最后,定位到SSD模块的预选框生成部分,即train.py中的PriorBox类实例和src/prior_box.py中的PriorBox类实现部分。由config.py中的cfg字典中的“min_sizes”可知,libfacedetection设置了四组锚框,分别是[[10,
16,
24],
[32,
48],
[64,
96],
[128,
192,
256]],共有3+2+2+3=9种不同尺寸的预选框。由src.py中的PriorBox类可知,每组锚框对应不同的特征层,因此共需要四个特征层来生成预选框,分别是输入图像的1/8、1/16、1/32、1/64下的特征层。由上述条件,我们可获取预选框生成公式如下:上述公式中,
为生成的预选框总数量,
和
分别表示每个特征层的宽高,即输入图像尺寸的1/8、1/16、1/32、1/64特征尺寸,
表示每个特征层上的每一个像素所对应的预选框个数,即该特征层对应的一组锚框的尺寸。假如图像输入宽高为160和160,有上述公式可得,生成的预选框总计(160/8)*(160/8)*3+(160/16)*(160/16)*2+(160/32)*(160/32)*2+(160/64)*(160/64)*3=1200+200+50+45=1495个。8.3模型训练8.3.3数据集制作(1)数据集制作通过第8.1节素材采集和标注,我们得到了一批原始数据集,现在需要将原始数据集制作成训练时数据集加载所需的文件img_list.txt,该文件每一行保存一张图片路径和对应的xml标签文件路径信息并以空格分开,注意文件名不能有空格,路径信息由两部分组成并以符号“_”连接,“_”之前为该图片或标签所属文件夹名,之后为该图片或标签真实名称,如下所示为根据WIDER_FACE_rect数据集制作成的
img_list.txt。0--Parade_0_Parade_marchingband_1_849.jpg0--Parade_0_Parade_marchingband_1_849.xml0--Parade_0_Parade_Parade_0_904.jpg0--Parade_0_Parade_Parade_0_904.xml0--Parade_0_Parade_marchingband_1_799.jpg0--Parade_0_Parade_marchingband_1_799.xml8.3模型训练8.3.3数据集制作以第一行为例,图片路径信息为0--Parade_0_Parade_marchingband_1_849.jpg,标签路径信息为0--Parade_0_Parade_marchingband_1_849.xml,中间用空格分开,其中两者路径信息0--Parade_0_Parade_marchingband_1_849由两部分组成并以符号“_”连接,其中0--Parade是该图片和标签所属的文件夹,0_Parade_marchingband_1_849.jpg为该文件夹下一张图片的名称,具体的图片路径为WIDER_FACE_rect/images/0--Parade/0_Parade_marchingband_1_849.jpg,标签路径为WIDER_FACE_rect/annotations/0--Parade/0_Parade_marchingband_1_849.xml,该路径将由后续数据集加载部分获取。现在,我们使用make_data_list.py中的如下代码将数据集制作成img_list.txt,如果公开数据集中已生成该文件,可忽略此操作。8.3模型训练8.3.3数据集制作(2)数据集加载根据(1)获取数据集文件img_list.txt后,在训练时需要对img_list.txt包含的所有图片和标签进行加载,即根据设置的数据集目录和img_list.txt文件,对数据集进行解析。解析模块包括xml转换、图像增强、裁剪等。dataset_rect=FaceRectLMDataset(training_face_rect_dir,img_dim,rgb_mean)使用PyTorch数据加载模块加载数据,输出是一个以批次(batchsize)为单位的字典。train_loader=torch.utilis.data.DataLoader(dataset=dataset,batch_size=batch_size,collate_fn=detection_collate,shuffle=True,num_workers=num_workers,pin_memory=False,drop_last=True,)读入PyTorch数据加载结果,以batch为单位,将数据送入网络,得到网络推理结果。foriter_idx,one_batch_datainenumerate(train_loader) images,targets=one_batch_data out=net(images)8.3模型训练8.3.4训练参数设置'--training_face_rect_dir''--training_face_landmark_dir''-b','--batch_size''--num_workers''--gpu_ids''--lr','--learning-rate''--momentum''--resume_net''--resume_epoch''-max','--max_epoch''--weight_decay''--gamma''--weight_filename_prefix''--lambda_bbox''--lambda_iouhead'1)优化器和损失函数optimizer=optim.SGD(net.parameters(),lr=args.lr,momentum=momentum,weight_decay=weight_decay)criterion=MultiBoxLoss(num_classes,0.35,True,0,True,3,0.35,False,False)#lossofdifferentpartloss_l,loss_lm,loss_c,loss_iou=criterion(out,priors,targets)#backpropoptimizer.zero_grad()loss.backward()optimizer.step()8.3模型训练8.3.4训练2)训练在设置参数后,就可以训练了。训练脚本train.sh如下:pythontrain.py--gamma0.1--gpu_ids0,1,2可以在脚本中适当增加定制参数。nohuptrain.sh&3)保存模型见train.py中的相关代码。4)测试pythondetect.py-mweights/yunet_final.pth--
image_file=test.jpg测试所需源图像如左图所示,其推理结果如右图所示。5)结果评估pythontest.py-mweights/yunet_final.pth8.4模型量化8.4.1ONNX转换及测试
代码清单8-3#第一步,从pth文件加载模型#第二步,使用torch的onnx模块导出onnx模型weights=“weights/yunet_final.pth”file=weights.replace('.pt','.onnx')torch.onnx.export(model,img,file,verbose=False,opset_version=11,input_names=['images'],dynamic_axes={'images':{0:'batch',2:'height',3:'width'},'output':{0:'batch',2:'y',3:'x'}}ifopt.dynamicelseNone)#第三步,checkimportonnxmodel_onnx=onnx.load(f)onnx.checker.check_model(model_onnx)#第四步,简化importonnxsimmodel_onnx,check=onnxsim.simplify(model_onnx,dynamic_input_shape=opt.dynamic,input_shapes={'images':list(img.shape)}ifopt.dynamicelseNone)onnx.save(model_onnx,file)8.4模型量化8.4.1ONNX转换及测试
onnx转rknn#第一步,创建rknn对象rknn=RKNN()#第二步,预处理配置rknn.config(channel_mean_value='0.00.00.01.0',reorder_channel='201',target_platform=target_platform_str)#第三步,加载onnx模型ret=rknn.load_onnx(model='weights/yunet_final.onnx')#第四步,构建模型ret=rknn.build(do_quantization=True,dataset='./dataset300_192.txt',pre_compile=True)#第五步,输出rknn模型ret=rknn.export_rknn('./face_det.rknn')#第六步,释放资源rknn.release()最终生成的模型如下图所示8.4模型量化8.4.2rknn转换及测试importrknn#Setinputsimg=cv2.imread('./cat_224x224.jpg')img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)print('-->Initruntimeenvironment')ret=rknn.init_runtime()ifret!=0:print('Initruntimeenvironmentfailed')exit(ret)print('done')#Inferenceprint('-->Runningmodel')outputs=rknn.inference(inputs=[img])show_outputs(outputs)print('done')#perf-性能测试print('-->Beginevaluatemodelperformance')perf_results=rknn.eval_perf(inputs=[img])print('done')8.6项目落地8.6.1编译环境
操作系统
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025合同法试用规定
- 2025餐馆转让合同范本
- 2025年二建继续教育:深入解析建设工程合同管理
- 2025年车辆买卖合同范本
- 机动勤务面试真题及答案
- 2025国内货物买卖合同范本参考
- 2025购物中心商铺租赁合同协议书
- 2025租房转租赁的合同样本
- 保函转让合同范例
- 免租门面合同范例
- 数据分析与评价控制程序
- 钻341 18号 陕西旅游版五年级英语上册 unit 6 How much is it 单元综合作业设计 3000字 版面设计
- AI赋能光伏电站视频监控系统解决方案
- 【我的祖国诗朗诵稿董卿】我的祖国诗朗诵稿
- (沪教牛津版)三年级英语下册单元检测试卷合集(14套)
- 外墙 吊绳滑板油漆安全施工方案
- 小学心理健康教育鄂科版三年级第一单元 《长大的梦想》 《学习的乐趣》 《做一个受欢迎的人》《当我独自一人》 单元作业设计
- 泌尿系统先天畸形
- 试卷印制服务投标方案
- 科技放飞梦想课件
- 中国旅游地理(第四版)中职PPT完整全套教学课件
评论
0/150
提交评论