本文利用YOLOV5对手势进行训练识别,并识别显示出对应的emoji,如同下图:
本教程所用环境:YOLOV5版本是V3.1。
通过gitclone将源码下载到本地,通过pipinstall-rrequirements.txt安装依赖包(其中官方要求python>=3.8andtorch>=1.6)。
我的环境是:系统环境Ubuntu16.04;cuda版本10.2;cudnn版本7.6.5;torch版本1.6.0;python版本3.8
其中手势数据集已上传至开源数据平台Graviti,包含了完整代码。
2.1数据集的采集以及标注
手势数据采集的代码:
importcv2defmain():total_pics=1000cap=cv2.VideoCapture(0)pic_no=0flag_start_capturing=Falseframes=0whileTrue:ret,frame=cap.read()frame=cv2.flip(frame,1)cv2.imwrite("hand_images/"+str(pic_no)+".jpg",frame)cv2.imshow("Capturinggesture",frame)cv2.waitKey(10)pic_no+=1ifpic_no==total_pics:breakmain()在yolov5目录下创建VOC2012文件夹(名字自己定义的),目录结构就是VOC数据集的,对应如下:
示例:
VOC2012文件夹下内容:
Annotations文件中是xml文件(labelimg标注的):
images为VOC数据集格式中的JPRGImages:
ImageSets文件中Main子文件夹主要存放训练,测试验证集的划分txt。这个划分通过以下脚本代码生成:
2.2生成yolo训练格式labels
把xml标注信息转换成yolo的txt格式。其中yolo的txt标签格式信息:每个图像对应一个txt文件,文件每一行为一个目标信息,包括classx_center,y_center,width,height格式。如下图所示:
创建voc_label.py文件,将训练集,验证集以及测试集生成txt标签,代码如下:
三个txt文件内容:
2.3配置文件
1)数据集的配置
在yolov5目录的data文件夹新建一个Emoji.yaml文件(自己定义)。用来存放训练集验证集的划分文件train.txt和val.txt(其中这两个文件是voc_label.py生成的)。具体内容如下:
2)模型的配置文件
一般训练yolo模型的时候,是可以聚类自己标注的框作为先验框(这样可以保证标注样本最大化的利用)。我们这里就直接采用默认值了。
到这里我们的自定义数据集以及配置文件创建完毕,下面就是训练模型了。
3.1、下载预训练模型
在源码yolov5目录下的weights文件夹下提供了下载smlx模型的脚本--download_weights.sh,执行这个脚本就可以下载这四个模型的预训练模型了。
3.2、训练模型
以上参数解释如下:epochs:指的就是训练过程中整个数据集将被迭代多少次,显卡不行你就调小点。batch-size:一次看完多少张图片才进行权重更新,梯度下降的mini-batch,显卡不行你就调小点。cfg:存储模型结构的配置文件。data:存储训练、测试数据的文件。img-size:输入图片宽高,显卡不行你就……。rect:进行矩形训练。resume:恢复最近保存的模型开始训练。nosave:仅保存最终checkpoint。notest:仅测试最后的epoch。evolve:进化超参数。bucket:gsutilbucket。cache-images:缓存图像以加快训练速度。weights:权重文件路径。name:重命名results.txttoresults_name.txt。device:cudadevice,i.e.0or0,1,2,3orcpu。adam:使用adam优化。multi-scale:多尺度训练,img-size+/-50%。single-cls:单类别的训练集
训练只需要运行训练命令就可以了,如下:
$pythontrain.py--dataEmoji.yaml--cfgyolov5s.yaml--weightsweights/yolov5s.pt--batch-size64--device"0,1,2,3"--epochs200--img-size640其中devicebatch-size等需要根据自己机器进行设置。
4.模型测试
评估模型好坏就是在有标注的测试集或验证集上进行模型效果的评估,在目标检测中最常使用的评估指标为mAP。yolov5文件下的test.py文件中指定了数据集的配置文件和训练结果模型如下:
通过以下命令进行模型测试:
pythontest.py--datadata/Emoji.yaml--weightsruns/train/exp2/weights/best.pt--augment模型测试效果:
测试结果图:
1.安装依赖库
pipinstallonnxcoremltoolsonnx-simplifier2.导出ONNX模型
此时在best.pt同级目录下生成了best.mlmodelbest.onnxbest.torchscript.pt三个文件,我们只需best.onnx,这个文件可以直接用netron打开查看模型结构。
3.用onnx-simplifer简化模型
为什么要简化?
在训练完深度学习的pytorch或者tensorflow模型后,有时候需要把模型转成onnx,但是很多时候,很多节点比如cast节点,Identity这些节点可能都不需要,我们需要进行简化,这样会方便我们把模型转成ncnn或者mnn等这些端侧部署的模型格式或者通过tensorRT进行部署。
完成后就生成了简化版本的模型yolov5-best-sim.onnx。
由上述生成了yolov5-best-sim.onnx这个模型,我们利用ncnn自带的工具onnx2ncnn.exe(这个工具是自己编译生成的,我这里是在windows下编译生成的,可以用linux下的可执行文件)生成yolov5s.paramyolov5s.bin两个文件。
在windows平台下ctrl+rcmd命令行窗口输入:
去掉不支持的网络层,打开转换得到的yolov5s.param文件,前面几行需要删除的是标红部分。(注意我们训练yoloV5的版本是V3.1,这里不同的版本可能会不同。)
修改结果如下绿色框和红色框中的。因为去掉了10层所以变成191228。并用YoloV5Focus网络层代替去掉的10层,而YoloV5Focus网络层中的images代表该层的输入,207代表的输出名,这个是根据下边一层的卷积层输入层数写的。
修改网路的输出shape:
当基于修改后的网路使用ncnn/examples/yolov5测试时会发现出现图片中一堆乱框,这种情况需要修改网路的输出部分。在保证输出名一致的情况下,修改Reshape中的0=-1,使的最终的输出shape不固定。具体的修改地方以及修改之前和之后见下图。
以下是用C++实现的完整代码。建议一划到底,先看最后的整体思路