YOLOv3在YOLOv2的基础进行了一些改进,这些更改使其效果变得更好。 在320×320的图像上,YOLOv3运行速度达到了22.2毫秒,mAP为28.2。其与SSD一样准确,但速度快了三倍,具体效果如下图。本文对YOLO v3的改进点进行了总结,并实现了一个基于Keras的YOLOv3检测模型。
inferencePaper:YOLOv3: An Incremental Improvement
Official website:https://pjreddie.com/darknet/yolo
Github:https://github.com/xiaochus/YOLOv3
环境
- Python 3.6
- Tensorflow-gpu 1.5.0
- Keras 2.1.3
- OpenCV 3.4
改进点
1.Darknet-53特征提取网络
不同于Darknet-19,YOLO v3中使用了一个53层的卷积网络,这个网络由残差单元叠加而成。根据作者的实验,在分类准确度上跟效率的平衡上,这个模型比ResNet-101、 ResNet-152和Darknet-19表现得更好。
Darknet-532.边界框预测
基本的坐标偏移公式与YOLO v2相同。
boxYOLO v3使用逻辑回归预测每个边界框的分数。 如果先验边界框与真实框的重叠度比之前的任何其他边界框都要好,则该值应该为1。 如果先验边界框不是最好的,但确实与真实对象的重叠超过某个阈值(这里是0.5),那么就忽略这次预测。YOLO v3只为每个真实对象分配一个边界框,如果先验边界框与真实对象不吻合,则不会产生坐标或类别预测损失,只会产生物体预测损失。
3.类别预测
为了实现多标签分类,模型不再使用softmax函数作为最终的分类器,而是使用logistic作为分类器,使用 binary cross-entropy作为损失函数。
4.多尺度预测
不同于之前的YOLO,YOLO v3从三种不同尺度的特征图谱上进行预测任务。
- 在Darknet-53得到的特征图的基础上,经过7个卷积得到第一个特征图谱,在这个特征图谱上做第一次预测。
- 然后从后向前获得倒数第3个卷积层的输出,进行一次卷积一次x2上采样,将上采样特征与第43个卷积特征连接,经过7个卷积得到第二个特征图谱,在这个特征图谱上做第二次预测。
- 然后从后向前获得倒数第3个卷积层的输出,进行一次卷积一次x2上采样,将上采样特征与第26个卷积特征连接,经过7个卷积得到第三个特征图谱,在这个特征图谱上做第三次预测。
每个预测任务得到的特征大小都为N ×N ×[3∗(4+1+80)] ,N为格子大小,3为每个格子得到的边界框数量, 4是边界框坐标数量,1是目标预测值,80是类别数量。
out实验
实现了一个输入大小为(416, 416)的yolo v3检测模型,模型使用了coco训练的权值文件。
权值文件转换
参考了yad2k项目的转换方法,我们为其添加了几个新的层,用来将Darknet的网络结构和权值文件转换为keras 2的网络结构和权值文件。
首先下载权值文件yolov3.weights
执行下列命令转换
python yad2k.py cfg\yolo.cfg yolov3.weights data\yolo.h5
检测
demo.py
文件提供了使用yolo v3进行检测的例子。图片检测结果输出到images\res
文件夹。
"""Demo for use yolo v3
"""
import os
import time
import cv2
import numpy as np
from model.yolo_model import YOLO
def process_image(img):
"""Resize, reduce and expand image.
# Argument:
img: original image.
# Returns
image: ndarray(64, 64, 3), processed image.
"""
image = cv2.resize(img, (416, 416),
interpolation=cv2.INTER_CUBIC)
image = np.array(image, dtype='float32')
image /= 255.
image = np.expand_dims(image, axis=0)
return image
def get_classes(file):
"""Get classes name.
# Argument:
file: classes name for database.
# Returns
class_names: List, classes name.
"""
with open(file) as f:
class_names = f.readlines()
class_names = [c.strip() for c in class_names]
return class_names
def draw(image, boxes, scores, classes, all_classes):
"""Draw the boxes on the image.
# Argument:
image: original image.
boxes: ndarray, boxes of objects.
classes: ndarray, classes of objects.
scores: ndarray, scores of objects.
all_classes: all classes name.
"""
for box, score, cl in zip(boxes, scores, classes):
x, y, w, h = box
top = max(0, np.floor(x + 0.5).astype(int))
left = max(0, np.floor(y + 0.5).astype(int))
right = min(image.shape[1], np.floor(x + w + 0.5).astype(int))
bottom = min(image.shape[0], np.floor(y + h + 0.5).astype(int))
cv2.rectangle(image, (top, left), (right, bottom), (255, 0, 0), 2)
cv2.putText(image, '{0} {1:.2f}'.format(all_classes[cl], score),
(top, left - 6),
cv2.FONT_HERSHEY_SIMPLEX,
0.6, (0, 0, 255), 1,
cv2.LINE_AA)
print('class: {0}, score: {1:.2f}'.format(all_classes[cl], score))
print('box coordinate x,y,w,h: {0}'.format(box))
print()
def detect_image(image, yolo, all_classes):
"""Use yolo v3 to detect images.
# Argument:
image: original image.
yolo: YOLO, yolo model.
all_classes: all classes name.
# Returns:
image: processed image.
"""
pimage = process_image(image)
start = time.time()
boxes, classes, scores = yolo.predict(pimage, image.shape)
end = time.time()
print('time: {0:.2f}s'.format(end - start))
if boxes is not None:
draw(image, boxes, scores, classes, all_classes)
return image
def detect_vedio(video, yolo, all_classes):
"""Use yolo v3 to detect video.
# Argument:
video: video file.
yolo: YOLO, yolo model.
all_classes: all classes name.
"""
camera = cv2.VideoCapture(video)
cv2.namedWindow("detection", cv2.WINDOW_NORMAL)
while True:
res, frame = camera.read()
if not res:
break
image = detect_image(frame, yolo, all_classes)
cv2.imshow("detection", image)
if cv2.waitKey(110) & 0xff == 27:
break
camera.release()
if __name__ == '__main__':
yolo = YOLO(0.6, 0.5)
file = 'data/coco_classes.txt'
all_classes = get_classes(file)
# detect images in test floder.
for (root, dirs, files) in os.walk('images/test'):
if files:
for f in files:
print(f)
path = os.path.join(root, f)
image = cv2.imread(path)
image = detect_image(image, yolo, all_classes)
cv2.imwrite('images/res/' + f, image)
# detect vedio.
video = 'E:/video/car.flv'
detect_vedio(video, yolo, all_classes)
结果
运行python demo.py
网友评论
yolo_model.py 脚本中 _process_feat()函数 box_xy-=(box_wh/2.) 这个是什么意思呢?
2.我原视频是每秒30帧,输出出来的视频不是每秒30帧,变慢了,请问可以在哪里修改帧数?
D:\Program Files\Python36\lib\site-packages\keras\engine\saving.py:270: UserWarning: No training configuration found in save file: the model was *not* compiled. Compile it manually.
warnings.warn('No training configuration found in save file: '
这两个啥问题啊,大佬,怎么解决
会出现Parsing Darknet config.
Traceback (most recent call last):
File "convert.py", line 262, in <module>
_main(parser.parse_args())
File "convert.py", line 83, in _main
unique_config_file = unique_config_sections(config_path)
File "convert.py", line 53, in unique_config_sections
output_stream.write(line)
TypeError: unicode argument expected, got 'str'的错误。。。
在第50行将output_stream = io.StringIO()的改为output_stream = io.BytesIO()
xuzhenzhe@xuzhenzhe-All-Series:~/Desktop/YOLOv3-master$ python yad2k.py cfg\yolo.cfg yolov3.weights data\yolo.h5
Using TensorFlow backend.
Loading weights.
Weights Header: [ 0 2 0 32013312 0]
Parsing Darknet config.
Traceback (most recent call last):
File "yad2k.py", line 277, in <module>
_main(parser.parse_args())
File "yad2k.py", line 86, in _main
unique_config_file = unique_config_sections(config_path)
File "yad2k.py", line 51, in unique_config_sections
with open(config_file) as fin:
FileNotFoundError: [Errno 2] No such file or directory: 'cfgyolo.cfg'
实在不知道怎么解决。能否解答一下。十分的感谢。
File "/home/god/anaconda3/envs/tensorflow/lib/python3.5/site-packages/keras/layers/advanced_activations.py", line 38, in __init__
self.alpha = K.cast_to_floatx(alpha)
File "/home/god/anaconda3/envs/tensorflow/lib/python3.5/site-packages/keras/backend/common.py", line 108, in cast_to_floatx
return np.asarray(x, dtype=_FLOATX)
File "/home/god/anaconda3/envs/tensorflow/lib/python3.5/site-packages/numpy/core/numeric.py", line 492, in asarray
return array(a, dtype, copy=False, order=order)
TypeError: float() argument must be a string or a number, not 'dict'
就是这个地方总是出问题,用的tf是1.6,Keras是2.0.5,到了上面cast_to_floatx地方调用array(a, dtype, copy=False, order=order)就出错,感觉这是库数据格式转换的问题,就不是哪里出问题。
请帮我看看指导一下,万分感谢!
File "/home/god/anaconda3/envs/tensorflow/lib/python3.5/site-packages/keras/backend/common.py", line 108, in cast_to_floatx
return np.asarray(x, dtype=_FLOATX)
File "/home/god/anaconda3/envs/tensorflow/lib/python3.5/site-packages/numpy/core/numeric.py", line 492, in asarray
return array(a, dtype, copy=False, order=order)
TypeError: float() argument must be a string or a number, not 'dict'
就是这个地方总是出问题,用的tf是1.6,Keras是2.0.5,到了上面cast_to_floatx地方调用array(a, dtype, copy=False, order=order)就出错,感觉这是库数据格式转换的问题,就不是哪里出问题。
请帮我看看指导一下,万分感谢!
1,是否有检测视频的程序?
2,输入模型的分辨率能改得低一点吗?感觉python这个运行速度比darknet 的原来那个exe程序慢,有什么方法能加快吗?分辨率(416,416)能否改成小点,感觉能提升速度。我不知道改哪里能调分辨率,谢谢!
Traceback (most recent call last):
File "C:\Users\chen9\Source\Repos\YOLOv3-master\demo.py", line 109, in <module>
detect()
File "C:\Users\chen9\Source\Repos\YOLOv3-master\demo.py", line 85, in detect
pimage = process_image(image)
File "C:\Users\chen9\Source\Repos\YOLOv3-master\demo.py", line 20, in process_image
interpolation=cv2.INTER_CUBIC)
cv2.error: C:\projects\opencv-python\opencv\modules\imgproc\src\resize.cpp:4044: error: (-215) ssize.width > 0 && ssize.height > 0 in function cv::resize
2.当前模型的权值与416的大小是匹配的,如果要修改输入shape,那么你需要自己重新训练模型。比Darknet慢是因为原程序所有流程都是使用C实现,在python上虽然尽量使用了keras和numpy,但是还是不可避免的有大量纯python计算流程,因此慢是不可避免的。
Using TensorFlow backend.
Traceback (most recent call last):
File "C:/python/YOLOv3-master/YOLOv3-master/yolo.py", line 109, in <module>
detect()
File "C:/python/YOLOv3-master/YOLOv3-master/yolo.py", line 74, in detect
yolo = YOLO(0.6, 0.5)
File "C:/python/YOLOv3-master/YOLOv3-master\model\yolo_model.py", line 18, in __init__
self._yolo = load_model('data/yolo.h5')
File "C:\python\lib\site-packages\keras\models.py", line 208, in load_model
raise ImportError('`load_model` requires h5py.')
ImportError: `load_model` requires h5py.
>>>
还请你空闲时能否解答一下