Python 3 & Keras YOLO v3解析与实

作者: Daisy丶 | 来源:发表于2018-04-09 22:29 被阅读6154次

    YOLOv3在YOLOv2的基础进行了一些改进,这些更改使其效果变得更好。 在320×320的图像上,YOLOv3运行速度达到了22.2毫秒,mAP为28.2。其与SSD一样准确,但速度快了三倍,具体效果如下图。本文对YOLO v3的改进点进行了总结,并实现了一个基于Keras的YOLOv3检测模型。

    inference

    PaperYOLOv3: An Incremental Improvement
    Official websitehttps://pjreddie.com/darknet/yolo
    Githubhttps://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-53

    2.边界框预测

    基本的坐标偏移公式与YOLO v2相同。

    box

    YOLO v3使用逻辑回归预测每个边界框的分数。 如果先验边界框与真实框的重叠度比之前的任何其他边界框都要好,则该值应该为1。 如果先验边界框不是最好的,但确实与真实对象的重叠超过某个阈值(这里是0.5),那么就忽略这次预测。YOLO v3只为每个真实对象分配一个边界框,如果先验边界框与真实对象不吻合,则不会产生坐标或类别预测损失,只会产生物体预测损失。

    3.类别预测

    为了实现多标签分类,模型不再使用softmax函数作为最终的分类器,而是使用logistic作为分类器,使用 binary cross-entropy作为损失函数。

    4.多尺度预测

    不同于之前的YOLO,YOLO v3从三种不同尺度的特征图谱上进行预测任务。

    1. 在Darknet-53得到的特征图的基础上,经过7个卷积得到第一个特征图谱,在这个特征图谱上做第一次预测。
    2. 然后从后向前获得倒数第3个卷积层的输出,进行一次卷积一次x2上采样,将上采样特征与第43个卷积特征连接,经过7个卷积得到第二个特征图谱,在这个特征图谱上做第二次预测。
    3. 然后从后向前获得倒数第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

    dog.png eagle.png giraffe.png horses.png person.png

    相关文章

      网友评论

      • LiYunfei:求助博主,我想要yolov3-tiny 的模型转成keras 请问要怎么改呢?目前好像找不到这转换器,不懂怎么改,模型训练好了,现在就卡在这了,希望能得到你的帮助,感激万分 350896791@qq.com
        Daisy丶:文中用的那个文件即可,把cfg配置文件换成yolov3-tiny的配置文件。
      • 95fc0cb29051:求助大佬
        yolo_model.py 脚本中 _process_feat()函数 box_xy-=(box_wh/2.) 这个是什么意思呢?
        Daisy丶:把xy从边界坐标转换为中心坐标。
      • 1e8714153977:从github上发现作者的,然后跟随到这儿来了,哈哈
      • 8c9f3e0dc569:请教两个问题:1.这个程序是不是每一帧只能检测3个物体?不是检测所有物体
        2.我原视频是每秒30帧,输出出来的视频不是每秒30帧,变慢了,请问可以在哪里修改帧数?
      • HsuCheng_a3c1:想請問 from model.yolo_model import YOLO 系統說沒有model 這個 package,該怎麼處理呢?? 謝謝~~
      • 刘十九:2018-07-18 15:34:48.944569: I T:\src\github\tensorflow\tensorflow\core\platform\cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2

        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: '

        这两个啥问题啊,大佬,怎么解决
        Daisy丶:@tdxt8 第二个是keras的配置编译警告,model需要通过compile()函数来添加训练配置,但是因为做的都是inference的部分,所以没有进行train的配置,但是不影响使用。
        tdxt8:上面一句是CPU可以提升性能,下面一句同问
      • d30115720666:安装python2.7的童鞋运行 python yad2k.py cfg\yolo.cfg yolov3.weights data\yolo.h5
        会出现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()
      • 谁把我昵称都起啦:小姐姐最近怎么不更新了啊,一直在跟着你的文章学习:blush:
      • Jayce_9cf4:大佬是在WIN还是linux下跑的?
      • LWZlwz:作者你好,想问一下我使用你的代码进行预测的时候,将threshold调到0.4也不能很好的预测到物体。例如图片里有许多行人,或者马路上的车,但是预测出来就只有1、2个anchor。
      • 796820ba1120:麻烦问下作者,这个例子的运行时间是多少,在我的机器上大约4秒一副图像
        387e517e29b9:是啊 实际不一定能用啊
        刘十九:我10多秒。。
        chantcalf:我跑也是4秒,而且好像有内存泄漏,检测图片时越来越慢,100幅之后每张就要几十秒了
      • b7e43959a579:谢谢楼主分享。只是我在运行权值转换的时候出现了这样的一个问题。
        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'
        实在不知道怎么解决。能否解答一下。十分的感谢。
        Daisy丶:@爱吃老虎的兔子 你这只是单纯的文件名写错了吧,反斜杠注意啊。。。
      • bb9cba719dc6:你好,我用代码给的模型能够很好的进行检测,但是用自己的模型时就没有任何输出,请问这是为什么?我转换模型使用了我自己的cfg文件,然后检测时也改了导入的模型和类别的txt
        Daisy丶:@深夜虫鸣_df7b 你调一下threshold看看有没有结果。
        bb9cba719dc6:@洛荷 我的cfg也没有对cfg和mask作任何改动。。。我观察了下,我的cfg和你的cfg,anchor和mask的参数是一样的,尴尬啊。。。
        Daisy丶:@深夜虫鸣_df7b 可能因为是masks和anchors的原因,这部分我是写在代码中的,没有从cfg文件中读取。
      • mmp1994::+1: 希望作者继续研究,比如怎末个训练自己的数据
      • bb9cba719dc6:你好,请问大概一张图要多少时间,用GPU的话
        796820ba1120:1050Ti 4秒一幅图片,你的是多少
      • upenggod:作者你好,还是以前问的问题,一直困扰我。请帮忙看一下

        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)就出错,感觉这是库数据格式转换的问题,就不是哪里出问题。

        请帮我看看指导一下,万分感谢!
      • upenggod:作者你好,还是以前问的问题,一直困扰我。请帮忙看一下

        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)就出错,感觉这是库数据格式转换的问题,就不是哪里出问题。

        请帮我看看指导一下,万分感谢!
        AlphaGoMaster:@upenggod keras版本2.1.2才行
      • passion_key:您好,我的ubuntu环境是14.0的,而tensorflow 1.5支持的cuda需要是9.0, 必须得是ubuntu 16.0,那我还有什么办法运行这个程序吗
        passion_key:@洛荷 好的,我试试,非常感谢。
        Daisy丶:@passion_key 可以使用低版本的tf, 只要保证与keras 2兼容即可。
      • f7edf13be536:您好,非常感谢您的程序,我有两个问题想问:
        1,是否有检测视频的程序?
        2,输入模型的分辨率能改得低一点吗?感觉python这个运行速度比darknet 的原来那个exe程序慢,有什么方法能加快吗?分辨率(416,416)能否改成小点,感觉能提升速度。我不知道改哪里能调分辨率,谢谢!
        Daisy丶:@陈耀华_85f1 这可能是我后来添加了结果文件夹,导致文件遍历出现了问题,已经修改了一下demo。
        f7edf13be536:@洛荷 非常感谢!还有一个问题反映一下,就是test文件夹里的图片一旦修改了以后,运行就会出现错误,图片不能显示。把原来的图片复制回去原来的状态也不行,不知道是什么原因?
        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
        Daisy丶:@陈耀华_85f1 1.视频检测可以使用opencv读入帧循环检测,参考yolov2文章的实现。
        2.当前模型的权值与416的大小是匹配的,如果要修改输入shape,那么你需要自己重新训练模型。比Darknet慢是因为原程序所有流程都是使用C实现,在python上虽然尽量使用了keras和numpy,但是还是不可避免的有大量纯python计算流程,因此慢是不可避免的。
      • 逍遥游_9b1c:你好,本人小白一枚,在运行你的程序时出现一下问题
        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.
        >>>
        还请你空闲时能否解答一下
        逍遥游_9b1c:@猛龙哎哎 是啊缺少hd5,多谢解答了
        Daisy丶:@逍遥游_9b1c 你这是没按步骤转换权值文件……
        6fb374017cc0:@逍遥游_9b1c 你应该是缺库,装hd5没有?

      本文标题:Python 3 & Keras YOLO v3解析与实

      本文链接:https://www.haomeiwen.com/subject/znzthftx.html