【Tensorflow tf 掏粪记录】笔记五——YOLOv3 tensorflow 实现

YOLOv3是YOLO作者优化的YOLO算法,与之前的相比,网络结构多了残差块来连接网络,采用了金字塔结构,网络的深度大大加深,达到了53层。所以作者把网络命名为DarkNet-53。

由于作者的编码能力实在是太强了,连所用的框架好像都是自己写的,所以目前并没有其他的框架的版本的发布。我根据作者写的关于YOLOv3的论文和之前的关于YOLO的所有论文,按我对论文的理解来实现YOLOv3。(若我对论文的理解有误, 欢迎指出。不胜感激)
还是老样子,各种设置可以到config文件夹下修改对应的设置项

项目代码

https://github.com/IronMastiff/YOLOv3_tensorflow

简要介绍YOLO


YOLO( you only look once)的缩写。顾名思义,就是只看一次,整个预测过程只看图片一次。这有别与之前的目标定位识别的项目,YOLO之前的项目一般是定位目标看一次图像,物体分类再看一次图像。所以简单直观地看,YOLO似乎效率比他们都高,毕竟少看了一次,省下了时间。事实上YOLO也是快的惊人,作者在Titan GPU上实现了实时目标定位与识别,识别视频在官网首页就有,若没有可能是冲浪方法不够科学。

项目结构


本次的项目主要有3个文件,2个文件夹。utils文件夹中有6个文件。config文件夹中config.yml配置文件。

  • reader.py:
    • 存放了用来读取数据集,数据集标签存放地址与文件的方法。并在读取名字的过程中实现的mini_batch的操作
  • train.py:
    • 就是组合各种工具,用来训练网络的代码
  • eval.ph:
    • 用来跑训练好的YOLOv3
  • utils文件夹:
    • extract_labels.py:
      • 里面的labels_normaliszer()根据传入的标签的存放地址来读取标签,并且把标签转化成我们网络需要的格式
    • get_loss.py:
      • 整合了计算YOLOv3作者之前提到的3个loss的计算方法,并计算batchloss
    • IOU.py:
      • 里面的IOU_calculator()方法根据传入的预测值和目标的标签的值来计算IOU
    • net.ph:
      • 里面实现了YOLOv3的核心算法。DarkNet-53
    • read_config.py:
      • 读取config配置文件中的配置参数
    • ·select_things.py`:
      • 顾名思义,里面的方法实现了选择功能。例如选择YOLOv3中scale的大小,选择scale对应的check_point文件

Utils 工具

extract_labels


对于标注的数据的处理我的思路是生成一个shape与神经网络输出的数组shape相同的数组,并把目标的标签赋给对应下标的数组单元

labels_normalizer()方法中,我建立了一个map,用来把所有的种类(class)转化为数组中对应的位置的下标。这里我用的是VOC2007数据集,可以从官网下载,官网上说明了数据集中的种类(class)的个数。更换数据集记得过来修改map的内容。

由于VOC数据集的标签格式是xml类型的,所以我调用了xml.dom.minidom这个库来解析xml文件,
并且组合成元组,然后连接元组组成链表。然后返回链表
从中提取了object_name, bdbox, xmin,ymin,xmax,ymax

import xml.dom.minidom

def xml_extractor( dir ):
    DOMTree = parse( dir )
    collection = DOMTree.documentElement    # 得到xml文件的根节点
    file_name_xml = collection.getElementsByTagName( 'filename' )[0]
    objects_xml = collection.getElementsByTagName( 'object' )
    size_xml = collection.getElementsByTagName( 'size' )

    file_name = file_name_xml.childNodes[0].data

    for size in size_xml:
        width = size.getElementsByTagName( 'width' )[0]
        height = size.getElementsByTagName( 'height' )[0]

        width = width.childNodes[0].data
        height = height.childNodes[0].data

    objects = []
    for object_xml in objects_xml:
        object_name = object_xml.getElementsByTagName( 'name' )[0]
        bdbox = object_xml.getElementsByTagName( 'bndbox' )[0]
        xmin = bdbox.getElementsByTagName( 'xmin' )[0]
        ymin = bdbox.getElementsByTagName( 'ymin' )[0]
        xmax = bdbox.getElementsByTagName( 'xmax' )[0]
        ymax = bdbox.getElementsByTagName( 'ymax' )[0]

        object = ( object_name.childNodes[0].data,
                   xmin.childNodes[0].data,
                   ymin.childNodes[0].data,
                   xmax.childNodes[0].data,
                   ymax.childNodes[0].data )

        objects.append( object )

    return file_name, width, height, objects

labels_normalizer()方法中我才正式的把得到的labels转化为数组。有一点值得注意,在生成新的数组的时候务必要加1e-8(一个近似0的数),为的是防止之后在计算IOU时出现分母为0从而输出为nan的情况。因为VOC数据集标记的是目标的对角线的坐标,而我们需要的是目标中点的坐标与之对应的boundding box的长宽。所以需要一点小计算。

而且由于YOLOv3的检测机制是中点所在的对应的box对目标物体进行预测,所以还需要得出物体所在的box,并对对应下标的数组赋值。为了防止下标越界我把最右与最下边界上的点归为前一个box管理,他们本来归下一个box管理,但是会发生越界错误

def labels_normalizer( batches_filenames, target_width, target_height, layerout_width, layerout_height ):

    class_map = {
        'person' : 5,
        'bird' : 6,
        'cat' : 7,
        'cow' : 8,
        'dog' : 9,
        'horse' : 10,
        'sheep' : 11,
        'aeroplane' : 12,
        'bicycle' : 13,
        'boat' : 14,
        'bus' : 15,
        'car' : 16,
        'motorbike' : 17,
        'train' : 18,
        'bottle' : 19,
        'chair' : 20,
        'diningtable' : 21,
        'pottedplant': 22,
        'sofa' : 23,
        'tvmonitor' : 24
    }

    height_width = []
    batches_labels = []
    for batch_filenames in batches_filenames:
        batch_labels = []
        for filename in batch_filenames:
            _, width, height, objects = xml_extractor( filename )
            width_preprotion = target_width / int( width )
            height_preprotion = target_height / int( height )
            label = np.add( np.zeros( [int( layerout_height ), int( layerout_width ), 255] ), 1e-8 )    # 这里加1e-8的原因是防止之后在用该数据在计算IOU时出现分母为0从而导致输出为nan的情况
            for object in objects:
                class_label = class_map[object[0]]
                xmin = float( object[1] )
                ymin = float( o
  • 13
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 46
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 46
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值