一、前言
小王在毕设之余疯狂追剧,最近痴迷于《权利的游戏》中龙母的美貌,太🉑了
当然,二丫 和 雪诺 的故事线也非常好看,我喜欢剧透,欢迎大家向我剧透。👀
当然了,小王也不能忘记毕设进度啦——好像是什么手语识别来着?
哈哈哈哈,用最近了解的yolo跑个模型测试一下下吧,嘻嘻,效果还不错!
咳咳,进入正题啦!
前面一篇文章算是打通了【yolo3识别】的任督二脉:
【Yolo3】一文掌握图像标注、训练、识别(Keras+TensorFlow-gpu)
梳理一下yolo3的知识点:
1.结构图
参考CNN流程:
yolov3流程:
输入图片->darknet53(三个不同尺度特征层)->yolo3解码(卷积+采样+结合)->(三个特征结果)
图片引用见logo
2.步骤
第一步:输入图片(调整为416x416尺寸的图片)
经过darknet53(5轮,23个残差块——对残差网络进行特征提取)
分别得到✅3个不同尺度特征层:13x13x1024
,26x26x512
,52x52x256
,
其中13x13表示网格数、3表示3个先验框、后面表示类别数。
第二步:13x13的特征层经过5层卷积
同
第三步:
-
再次进行3x3的卷积✅输出特征feat3 + 1x1卷积调整通道数
其中(75分为4+1+20):- 4表示:偏移量x_offset、y_offset、height、width
- 1表示:置信度
- 25表示:对象类别数
-
13x13尺度: 卷积+上采样(步长为2,即把长宽变为1/2),再与16x16的特征层结合。
同
同理:16x16 五次卷积 -》3x3卷积✅输出此层特征feat2 + 1x1卷积调整通道数
16x16 卷积+上采样 -》
同理:52x52 五次卷积 -》3x3卷积✅输出此层特征feat1 + 1x1卷积调整通道数
3.loss值
作用:判断模型标准
特别说明:
-
先验框的由来。先验框数值越大,适合检测大窗格13x13;对像素小,容易失真的图片来说,先验框数值越小检测越精准,适合检测小窗格52x52。
-
loss函数的定义:
存在的框:- 编码后长宽与xy偏移量的差距
- 置信度与1的差值(loss =| 1- iou |)
- 种类预测结果与真实值的对比
不存在框: 最大iou与0的差值 (loss =| iou - 0|)
iou的概念补充:一般指代模型预测的 bbox 和 Groud Truth 之间的交并比。
左图为预测目标位置,右图为原始目标位置;交并比就是预测正确部分Area of overrap比上两个位置所占的全部面积Area of Union;iou越大,预测效果越好。 -
三个检测结果进行堆叠:
- 左上和右下角进行标记
- 非极大抑制(去掉重叠的框,最多20个框)
相同目标最近的几个框都满足要求,只显示最大的那个框。
- 左上和右下角进行标记
大概就是这些内容啦,接下来从源码入手!
二、手识别
本文是对手语数据集训练的一个记录,算是 tf2 - keras-yolo3 复现。
下面操作中包含了源码可训练,以及loss查看tensorboard的使用。
0.图片
(选做,用你自己的标注数据)
本次使用的数据集来自:牛津大学Arpit Mittal, Andrew Zisserman和 Phil Torr
综合的手图像数据集共有13050个手实例被注释。大于边界框固定区域(1500平方像素)的手部实例被认为“足够大”以进行检测,并用于评估。这给出了大约4170个高品质手实例。在收集数据时,对人的姿势或可见度没有任何限制,对环境也没有任何限制。在每幅图像中,都标注了人类可以清晰感知的所有手。注释由一个边界矩形组成,该矩形不必相对于手腕进行轴对齐。
资料下载:
我们用到的数据集为VOC格式:我们仅下载evaluation_code.tar.gz(13.8M)即可。
1.下载项目框架
参考:重磅!YOLOv3最全复现代码合集(含TensorFlow/PyTorch和Keras等)
我仅根据做出源码注释和修改:keras-tensorflow(https://github.com/qqwweee/keras-yolo3)
-
单独下载yolov3.weights 权重,放在项目根目录下
-
将 DarkNet 的.weights文件转换成 Keras 的.h5文件
python convert.py -w yolov3.cfg yolov3.weights model_data/yolo_weights.h5
2.标签分类
- 将下载的数据集复制到项目路径下:
事实是数据集有400+图片,我训练起来太累了,容易过拟合,这里只用了009985-010028共40+张图片进行训练
开源数据集nb😁,不用手动找资源,再标注啦,嘻嘻嘻!支持开源~😁
- voc标签格式:
voc_annotation.py
(后面我重构了一下项目结构,可能有出入)
会在ImageSets/Main目录下生成对应文件
- yolo标签格式:
yolo_annotation.py
- 修改classes为你训练的对象(我这里是hand)
查看标签:在VOCdevkit\VOC2007\Annotations\009985_hand.xml
- 这里需要修改一下float格式
b = (int(float(xmlbox.find('xmin').text)), int(float(xmlbox.find('ymin').text)), int(float(xmlbox.find('xmax').text)), int(float(xmlbox.find('ymax').text)))
- 执行
yolo_annotation.py
,在model_data目录下生成yolo标签格式
现在我们就得到了model_data(标签)
- 修改classes为你训练的对象(我这里是hand)
3.训练
Keras2.3.1 + TensorFlow-gpu2.1.0 + cuda 10.0
涉及到的文件和函数目录:
原始目录:tree_old目录
我重新整合了一下目录结构:tree目录
根目录
│
│ train.py --- 模型训练
│
├─data --- 参数配置
│ │ yolo_weights.h5 --- 权重文件
│ │
│ ├─anchors
│ │ coco_anchors.txt --- 先验参数
│ │
│ ├─classes
│ │ coco.name
│ │ voc_classes.txt --- 标签样本名称
│ │
│ └─dataset
│ test.txt
│ train.txt
│ val.txt
│
└─core
│ darknet53.py --- 特征提取网络
│ loss.py --- 损失函数
│ yolo3.py --- yolo网络
└─ utils.py --- 图片加载工具类
运行train.py
50轮和100轮
(之前我更新了一次keras,导致之前的修改被抹除了,这里修改一下:)
报错:
参考:'Model’object has no attribute '_get_distribution_strategy’的一种解决方案
问题2:(运行到64轮时,VSCode崩掉了,这里接着之前的模型运行)
注释掉前50轮,直接model.load_weights('logs/ep064-loss16.422-val_loss20.496.h5')
你觉得合适的版本,
再把 initial_epoch 改为当前的序号可以接着运行。
这是绝招了!
最终我运行到100轮时,loss值为19.2
神经网络可视化分析:
-
读取运行时记录:(这里train和validation分别记录)
-
在路径下打开控制台运行:
tensorboard --logdir=logs\
tensorboard 是 tensorflow安装时就附带安装的可视化工具🍳,别说你还没用过。
-
打开浏览器查看:http://localhost:6006/
其中GRAPHS可以打印出我们的神经网络结构:(可以导出为png图片)
4.测试
修改yolo.py的模型路径,socre和iou——是显示检测结果画框框的重要因素:
"score": 0.45, # 框置信度阈值,小于阈值的框被删除,需要的框较多,则调低阈值,需要的框较少,则调高阈值
"iou": 0.3, # 同类别框的IoU阈值,大于阈值的重叠框被删除,重叠物体较多,则调高阈值,重叠物体较少,则调低阈值
直接检测:predict.py
from keras.layers import Input
from yolo import YOLO,detect_video
from PIL import Image
def for_img(yolo):
path = 'D:/myworkspace/dataset/test.jpg'
try:
image = Image.open(path)
except:
print('Open Error! Try again!')
else:
r_image = yolo.detect_image(image)
r_image.show()
yolo.close_session()
def for_video(yolo):
detect_video(yolo, "D:/myworkspace/dataset/xuanya.mp4", "D:/myworkspace/dataset/xuanya_detect.mp4")
if __name__ == '__main__':
_yolo = YOLO()
for_img(_yolo)
# for_video(_yolo)
yolo.py测试部分报错:
最终参考:tf2-keras-yolo3,可以直接对图片和视频进行检测。
因为模型是训练一次就好了,测试部分我单独提出封装到代码里:(后面在这基础上还要做手语识别,前途明朗~)
识别部分——代码下载链接
yolo_video.py:
import sys
import argparse
from yolo import YOLO, detect_video
from PIL import Image
def detect_img(yolo):
while True:
print("Press 'q' quit !")
img = input('Input image filename:')
if img.lower() == 'q':
exit(0)
try:
image = Image.open(img)
except:
print('Open Error! Try again!')
continue
else:
r_image = yolo.detect_image(image)
r_image.show()
yolo.close_session()
FLAGS = None
if __name__ == '__main__':
# class YOLO defines the default value, so suppress any default here
parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
'''
Command line options
'''
parser.add_argument(
'--model_path', type=str,
help='path to model weight file, default ' + YOLO.get_defaults("model_path")
)
parser.add_argument(
'--anchors_path', type=str,
help='path to anchor definitions, default ' + YOLO.get_defaults("anchors_path")
)
parser.add_argument(
'--classes_path', type=str,
help='path to class definitions, default ' + YOLO.get_defaults("classes_path")
)
parser.add_argument(
'--gpu_num', type=int,
help='Number of GPU to use, default ' + str(YOLO.get_defaults("gpu_num"))
)
parser.add_argument(
'--image', default=False, action="store_true",
help='Image detection mode, will ignore all positional arguments'
)
'''
Command line positional arguments -- for video detection mode
'''
parser.add_argument(
"--input", nargs='?', type=str,required=False,default='./path2your_video',
help = "Video input path"
)
parser.add_argument(
"--output", nargs='?', type=str, default="",
help = "[Optional] Video output path"
)
FLAGS = parser.parse_args()
if FLAGS.image:
"""
Image detection mode, disregard any remaining command line arguments
"""
print("Image detection mode")
if "input" in FLAGS:
print(" Ignoring remaining command line arguments: " + FLAGS.input + "," + FLAGS.output)
detect_img(YOLO(**vars(FLAGS)))
elif "input" in FLAGS:
detect_video(YOLO(**vars(FLAGS)), FLAGS.input, FLAGS.output)
else:
print("Must specify at least video_input_path. See usage with --help.")
或者直接检测
# 图片检测
python yolo_video.py --image
再输入图片路径
# 视频检测
python yolo_video.py --input img\test.mp4
图片识别率都不错:
视频检测最高识别率为57%
0.5秒检测一帧,正确率在70%左右
后面会用来检测我的手语:Python+Opencv2(三)保存视频关键帧
手语手势识别效果最高88%,非常nice!
yolo目标检测,比过拟合的模型和openpose粗略估计好很多yo~~
三、总结
40+张图片,跑的yolov3模型240M,检测效果比较满意啦。这里检测的是人手,如果把标注改为权游的龙,也是能检测出来的哦,just try it!
环境:【GPU】win10 (1050Ti)+anaconda3+python3.6+CUDA10.0+tensorflow-gpu2.1.0
仅对于yolov3模型来说,模型较大,如果转换成yolo-tiny甚至是yolo-nano会不会更方便移植。
生命不息,学习不止!😎
源码:
补充,识别部分函数调用图: