当前位置:首页 > 公众号精选 > AI科技大本营
[导读]作者|闫永强来源 |Datawhale本文利用YOLOV5对手势进行训练识别,并识别显示出对应的emoji,如同下图:本文整体思路如下。提示:本文含完整实践代码,代码较长,建议先看文字部分的实践思路,代码先马后看一、YOLOV5训练数据集1.安装环境依赖本教程所用环境:YOLOV...

本文利用YOLOV5对手势进行训练识别,并识别显示出对应的emoji,如同下图:


用 YOLOv5模型识别出表情!


本文整体思路如下。提示:本文含完整实践代码,代码较长,建议先看文字部分的实践思路,代码先马后看
用 YOLOv5模型识别出表情!


一 、YOLOV5训练数据集

1. 安装环境依赖

本教程所用环境:YOLOV5版本是V3.1。


通过git clone 将源码下载到本地,通过pip install -r requirements.txt 安装依赖包  (其中官方要求python>=3.8 and torch>=1.6)。


我的环境是:系统环境Ubuntu16.04;cuda版本10.2;cudnn版本7.6.5;torch版本1.6.0;python版本3.8


2. 准备手势识别数据集

其中手势数据集已上传至开源数据平台Graviti,包含了完整代码。


手势数据集地址:https://gas.graviti.cn/dataset/datawhale/HandPose?utm_medium=0831datawhale


:代码在数据地址的讨论区2.1 数据集的采集以及标注


手势数据采集的代码:


import cv2

def main():
total_pics = 1000
cap = cv2.VideoCapture(0)

pic_no = 0
flag_start_capturing = False
frames = 0

while True:
ret,frame = cap.read()
frame = cv2.flip(frame,1)
cv2.imwrite("hand_images/" str(pic_no) ".jpg",frame)
cv2.imshow("Capturing gesture",frame)
cv2.waitKey(10)
pic_no  = 1
if pic_no == total_pics:
break

main()
在yolov5目录下创建VOC2012文件夹(名字自己定义的),目录结构就是VOC数据集的,对应如下:


VOC2012../Annotations   #这个是存放数据集图片对应的xml文件../images  #这个存放图片的../ImageSets/Main  #这个主要是存放train.txt,test.txt,val.txt和trainval.txt四个文件。里面的内容是训练集、测试集、验证集以及训练验证集的名字(不带扩展后缀名)。 示例:


VOC2012文件夹下内容:


用 YOLOv5模型识别出表情!


Annotations文件中是xml文件(labelimg标注的):


用 YOLOv5模型识别出表情!


images为VOC数据集格式中的JPRGImages:


用 YOLOv5模型识别出表情!


ImageSets文件中Main子文件夹主要存放训练,测试验证集的划分txt。这个划分通过以下脚本代码生成:


# coding:utf-8

import os
import random
import argparse

parser = argparse.ArgumentParser()
#xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下
parser.add_argument('--xml_path', default='C:\\Users\\Lenovo\\Desktop\\hand_datasets\\VOC2012\\Annotations\\', type=str, help='input xml label path')
#数据集的划分,地址选择自己数据下的ImageSets/Main
parser.add_argument('--txt_path', default='C:\\Users\\Lenovo\\Desktop\\hand_datasets\\VOC2012\\ImageSets\\Main\\', type=str, help='output txt label path')
opt = parser.parse_args()

trainval_percent = 1.0
train_percent = 0.99
xmlfilepath = opt.xml_path
txtsavepath = opt.txt_path
total_xml = os.listdir(xmlfilepath)
if not os.path.exists(txtsavepath):
os.makedirs(txtsavepath)

num = len(total_xml)
list_index = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list_index, tv)
train = random.sample(trainval, tr)

file_trainval = open(txtsavepath 'trainval.txt', 'w')
file_test = open(txtsavepath 'test.txt', 'w')
file_train = open(txtsavepath 'train.txt', 'w')
file_val = open(txtsavepath 'val.txt', 'w')

for i in list_index:
name = total_xml[i][:-4] '\n'
if i in trainval:
file_trainval.write(name)
if i in train:
file_train.write(name)
else:
file_val.write(name)
else:
file_test.write(name)

file_trainval.close()
file_train.close()
file_val.close()
file_test.close()
运行代码在Main文件下生成txt文档如下:


用 YOLOv5模型识别出表情!


2.2 生成yolo训练格式labels


把xml标注信息转换成yolo的txt格式。其中yolo的txt标签格式信息:每个图像对应一个txt文件,文件每一行为一个目标信息,包括classx_center, y_center, width, height 格式。如下图所示:


用 YOLOv5模型识别出表情!


创建voc_label.py文件,将训练集,验证集以及测试集生成txt标签,代码如下:


# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os
from os import getcwd

sets = ['train', 'val', 'test']
classes = ["four_fingers","hand_with_fingers_splayed","index_pointing_up","little_finger","ok_hand","raised_fist","raised_hand","sign_of_the_horns","three","thumbup","victory_hand"]
# 11 classes  # 改成自己的类别
abs_path = os.getcwd()
print(abs_path)

def convert(size, box):
dw = 1. / (size[0])
dh = 1. / (size[1])
x = (box[0]   box[1]) / 2.0 - 1
y = (box[2]   box[3]) / 2.0 - 1
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('/home/yanyq/Ryan/yolov5/VOC2012/Annotations/%s.xml' % (image_id), encoding='UTF-8')
out_file = open('/home/yanyq/Ryan/yolov5/VOC2012/labels/%s.txt' % (image_id), 'w')
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 = obj.find('difficult').text
difficult = obj.find('difficult').text
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))
b1, b2, b3, b4 = b
# 标注越界修正
if b2 > w:
b2 = w
if b4 > h:
b4 = h
b = (b1, b2, b3, b4)
bb = convert((w, h), b)
out_file.write(str(cls_id) " " " ".join([str(a) for a in bb]) '\n')

wd = getcwd()
for image_set in sets:
if not os.path.exists('/home/yanyq/Ryan/yolov5/VOC2012/labels/'):
os.makedirs('/home/yanyq/Ryan/yolov5/VOC2012/labels/')
image_ids = open('/home/yanyq/Ryan/yolov5/VOC2012/ImageSets/Main/%s.txt' % (image_set)).read().strip().split()
list_file = open('%s.txt' % (image_set), 'w')
for image_id in image_ids:
list_file.write(abs_path '/images/%s.jpg\n' % (image_id))
convert_annotation(image_id)
list_file.close()

运行上述脚本后会生成labels文件夹和三个包含数据集的txt文件,其中labels中为图像的yolo格式标注文件,train.txt,test.txt, val.txt文件为划分后图像所在位置的绝对路径。


三个txt文件内容:


用 YOLOv5模型识别出表情!


2.3 配置文件


1)数据集的配置


在yolov5目录的data文件夹新建一个Emoji.yaml文件(自己定义)。用来存放训练集验证集的划分文件train.txt和val.txt(其中这两个文件是voc_label.py生成的)。具体内容如下:


用 YOLOv5模型识别出表情!


2)模型的配置文件


一般训练yolo模型的时候,是可以聚类自己标注的框作为先验框(这样可以保证标注样本最大化的利用)。我们这里就直接采用默认值了。


选择一个需要的模型,YOLOV5有提供s、m、l、x版本,其是逐渐增大的架构,也就是训练时间和推理时间都对应增加,我们这里选择s版本。在yolov5文件夹下的models文件夹中打开yolov5s.yaml文件,修改内容如下图(我们选择默认anchor,所以不做修改,只需要更改nc中的类别数,由于我们是11类,所以改成11就可以了):


用 YOLOv5模型识别出表情!


到这里我们的自定义数据集以及配置文件创建完毕,下面就是训练模型了。


3.模型训练

3.1、下载预训练模型


在源码yolov5目录下的weights文件夹下提供了下载smlx模型的脚本--download_weights.sh,执行这个脚本就可以下载这四个模型的预训练模型了。


3.2、训练模型


用 YOLOv5模型识别出表情!



以上参数解释如下:epochs:指的就是训练过程中整个数据集将被迭代多少次,显卡不行你就调小点。batch-size:一次看完多少张图片才进行权重更新,梯度下降的mini-batch,显卡不行你就调小点。cfg:存储模型结构的配置文件。data:存储训练、测试数据的文件。img-size:输入图片宽高,显卡不行你就……。rect:进行矩形训练。resume:恢复最近保存的模型开始训练。nosave:仅保存最终checkpoint。notest:仅测试最后的epoch。evolve:进化超参数。bucket:gsutil bucket。 cache-images:缓存图像以加快训练速度。 weights:权重文件路径。name:重命名results.txt to results_name.txt。device:cuda device, i.e. 0 or 0,1,2,3 or cpu。adam:使用adam优化。multi-scale:多尺度训练,img-size /- 50%。single-cls:单类别的训练集


训练只需要运行训练命令就可以了,如下:


$ python train.py  --data Emoji.yaml --cfg yolov5s.yaml --weights weights/yolov5s.pt --batch-size 64 --device "0,1,2,3" --epochs 200 --img-size 640
其中device batch-size 等需要根据自己机器进行设置。


用 YOLOv5模型识别出表情!




4.模型测试


评估模型好坏就是在有标注的测试集或验证集上进行模型效果的评估,在目标检测中最常使用的评估指标为mAP。yolov5文件下的test.py文件中指定了数据集的配置文件和训练结果模型如下:


用 YOLOv5模型识别出表情!


通过以下命令进行模型测试:


python test.py --data data/Emoji.yaml --weights runs/train/exp2/weights/best.pt --augment

模型测试效果:


用 YOLOv5模型识别出表情!


测试结果图:


用 YOLOv5模型识别出表情!


二、YOLOV5模型转换

1.安装依赖库


pip install onnx coremltools onnx-simplifier
2.导出ONNX模型


python models/export.py --weights runs/train/exp2/weights/best.pt --img 640 --batch 1
用 YOLOv5模型识别出表情!


此时在best.pt同级目录下生成了best.mlmodel best.onnx best.torchscript.pt三个文件,我们只需best.onnx,这个文件可以直接用netron打开查看模型结构。


3.用onnx-simplifer简化模型


为什么要简化?


在训练完深度学习的pytorch或者tensorflow模型后,有时候需要把模型转成 onnx,但是很多时候,很多节点比如cast节点,Identity 这些节点可能都不需要,我们需要进行简化,这样会方便我们把模型转成ncnn或者mnn等这些端侧部署的模型格式或者通过tensorRT进行部署。


python -m onnxsim best.onnx yolov5-best-sim.onnx
用 YOLOv5模型识别出表情!


完成后就生成了简化版本的模型yolov5-best-sim.onnx。


三、YOLOV5转换成ncnn模型

1、onnx转.param .bin

由上述生成了yolov5-best-sim.onnx这个模型,我们利用ncnn自带的工具onnx2ncnn.exe(这个工具是自己编译生成的,我这里是在windows下编译生成的,可以用linux下的可执行文件)生成yolov5s.param  yolov5s.bin两个文件。


在windows平台下ctrl r   cmd命令行窗口输入:


onnx2ncnn.exe yolov5-best-sim.onnx yolov5s.param yolov5s.bin
用 YOLOv5模型识别出表情!



转换的过程中会出现上图所示的ncnn不支持层,下边就是要修改param文件,把不支持层改成支持层。

2、修改.param 参数去除不支持的网络层

去掉不支持的网络层,打开转换得到的yolov5s.param文件,前面几行需要删除的是标红部分。(注意我们训练yoloV5的版本是V3.1,这里不同的版本可能会不同。)


用 YOLOv5模型识别出表情!


修改结果如下绿色框和红色框中的。因为去掉了10层所以变成191  228。并用YoloV5Focus网络层代替去掉的10层,而YoloV5Focus网络层中的images代表该层的输入,207代表的输出名,这个是根据下边一层的卷积层输入层数写的。


用 YOLOv5模型识别出表情!


修改网路的输出shape:


当基于修改后的网路使用ncnn/examples/yolov5测试时会发现出现图片中一堆乱框,这种情况需要修改网路的输出部分。在保证输出名一致的情况下,修改Reshape中的0=-1,使的最终的输出shape不固定。具体的修改地方以及修改之前和之后见下图。


用 YOLOv5模型识别出表情!


用 YOLOv5模型识别出表情!


3、ncnn的c 测试代码实现

以下是用C 实现的完整代码。建议一划到底,先看最后的整体思路


#include
#include
#include "iostream"
//#include
//#include < ctime >
//#include 
//#include 

// ncnn
#include "ncnn/layer.h"
#include "ncnn/net.h"
#include "ncnn/benchmark.h"
//#include "gpu.h"

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

static ncnn::UnlockedPoolAllocator g_blob_pool_allocator;
static ncnn::PoolAllocator g_workspace_pool_allocator;

static ncnn::Net yolov5;

class YoloV5Focus : public ncnn::Layer
{
public:
YoloV5Focus()
{
one_blob_only = true;
}

virtual int forward(const ncnn::Mat
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭