前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Detectron学习三:自定义数据层

Detectron学习三:自定义数据层

原创
作者头像
CV_Learner
修改2019-12-09 15:14:27
1.7K0
修改2019-12-09 15:14:27
举报
文章被收录于专栏:CV_LearnCV_Learn

博客:https://www.cnblogs.com/marsggbo/p/11727556.html

官方文档:https://detectron2.readthedocs.io/tutorials/datasets.html

自定义数据层需要实现的步骤:

1:注册DatasetCatalog----将自定义的数据类型转换为detectron2标准的数据格式

2:注册metadataCatalog---(可选)

3:更新配置文件Config

一、注册DatasetCatalog

参考文件/detectron2/data/datasets/pascal_voc.py

# -*- coding: utf-8 -*-
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved

from fvcore.common.file_io import PathManager
import os
import numpy as np
import xml.etree.ElementTree as ET

from detectron2.structures import BoxMode
from detectron2.data import DatasetCatalog, MetadataCatalog


__all__ = ["register_pascal_voc"]


# fmt: off
CLASS_NAMES = [
    "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat",
    "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person",
    "pottedplant", "sheep", "sofa", "train", "tvmonitor",
]   ##为xml中目标的name名称
# fmt: on


def load_voc_instances(dirname: str, split: str):
    """
    Load Pascal VOC detection annotations to Detectron2 format.

    Args:
        dirname: Contain "Annotations", "ImageSets", "JPEGImages"
        split (str): one of "train", "test", "val", "trainval"
    """
    with PathManager.open(os.path.join(dirname, "ImageSets", "Main", split + ".txt")) as f:
        fileids = np.loadtxt(f, dtype=np.str)

    dicts = []
    ######################
    xml解析(省略)
    ######################
    return dicts

def register_pascal_voc(name, dirname, split, year):
    DatasetCatalog.register(name, lambda: load_voc_instances(dirname, split))
    MetadataCatalog.get(name).set(
        thing_classes=CLASS_NAMES, dirname=dirname, year=year, split=split
    )

/detectron2/data/datasets/builtin.py中注册实现:

# ==== Predefined splits for PASCAL VOC ===========
def register_all_pascal_voc(root="datasets"):
    SPLITS = [
        ("voc_2007_trainval", "VOC2007", "trainval"),
        ("voc_2007_train", "VOC2007", "train"),
        ("voc_2007_val", "VOC2007", "val"),
        ("voc_2007_test", "VOC2007", "test"),
        ("voc_2012_trainval", "VOC2012", "trainval"),
        ("voc_2012_train", "VOC2012", "train"),
        ("voc_2012_val", "VOC2012", "val"),
    ]   ##该列表中的名称与configs中yaml中DATASETS.{TRAIN,TEST}中的名字完全一致
    
    for name, dirname, split in SPLITS:
        year = 2007 if "2007" in name else 2012
        register_pascal_voc(name, os.path.join(root, dirname), split, year)
        MetadataCatalog.get(name).evaluator_type = "pascal_voc"

步骤:

1:实现函数load_voc_instances,返回detectron2标准数据格式。

标准数据格式:datasetFormat=[dict1,dict2,dict3,....]  ##len(datasetFormat)为数据集大小,一张图像对应一个dict
dict1={
    "file_name":str, ##图像绝对路径
    "image_id":str or int,
    "annotations":[ ##list[dict]
        {
            "category_id":int,  ##类别索引,CLASS_NAMES.index(cls)的返回值,cls为类别名name
            "bbox":[float,float,float,float], ##排列顺序与下面bbox_mode有关
            "bbox_mode":int    ##XYXY_ABS:[xmin,ymin,xmax,ymax]  XYWH_ABS:[xmin,ymin,width,height]
                                ##XYXY_REL XYWH 相对与图像尺寸的坐标值,范围[0,1]
        },
        {
        },
    ]    
}

2:注册DatasetCatalog

def register_pascal_voc(name, dirname, split, year):
    DatasetCatalog.register(name, lambda: load_voc_instances(dirname, split))
 
 #################################
 类DatasetCatalog中register函数的定义
 @staticmethod
 def register(name,func):
        """
        Args:
            name (str): the name that identifies a dataset, e.g. "coco_2014_train".
            func (callable): a callable which takes no arguments and returns a list of dicts.
        """
  #############################
  此处使用了lambda表达式
  作用:借助lambda给回调函数传参,做了一个“函数打包”的操作,它把函数和它的参数列表打包在一起,得到一个新的函数,
  实际传入到register的并不是原来的load_voc_instances,而是打包得到的新函数。至于这个新函数叫做什么名字,对于
  我们来说是无所谓的(匿名函数),反正也只用这一次,下次还要用的话,lambda会再一次重新打包,得到新的匿名函数。

二、注册metadataCatalog -----没太明白具体是做什么用的,后续若有新的理解在进行补充

参考博客https://www.cnblogs.com/marsggbo/p/11727556.html

MetadataCatalog的作用是记录数据集的一些特征,这样我们就可以很方便的在整个代码中获取数据集的特征信息。在注册DatasetCatalog后,我们可以按如下栗子对MetadataCatalog进行注册并定义我们后面可能会用到的属性特征:

from detectron2.data import MetadataCatalog
MetadataCatalog.get("my_dataset").thing_classes = ["person", "dog"]

# 也可以这样
MetadataCatalog.get("my_dataset").set("thing_classes",["person", "dog"])

注意:如果你的数据集名字未注册过,MetadataCatalog.get会自动进行注册,然后会自动设置你所设定的属性值。

其实MetadataCatalog还有其他的特征属性可以设置,如stuff_classes,stuff_colors等等。你可能会好奇thing_classesstuff_classes有什么区别,区别如下:

  • 抽象解释:thing_classes用于指定instance-level任务,stuff_classes用于semantic segmentation任务。
  • 具体解释:像椅子,书这种可数的东西,就可以理解成thing,所以用于instance-level;而雪、天空这种不可数的就理解成stuff,所以用于semantic segmentation。参考On Seeing Stuff: The Perception of Materials by Humans and Machines

最后,get_detection_dataset_dicts会返回一个包含若干个dict的list,之所以是list是因为参数dataset_names也是一个list,这样我们就可以制定多个names来同时对数据进行读取。

三、修改配置文件 在对应加载的配置文件如/configs/PascalVOC-Detection/faster_rcnn_R_50_FPN.yaml中修改MODEL.NUM_CLASSES参数

DATASETS.{TRAIN,TEST}参数

。。。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档