Here we provide instructions for how to create and use your own custom dataset for training and evaluation.
The first step is to create your dataset loader in the fsdet/data
directory. The dataset loader should return a list of all the images in the dataset and their corresponding annotations. The format is shown below:
def dataset_loader(name, thing_classes):
data = []
for file in dataset:
annotation = [
"file_name" : "x.png", # full path to image
"image_id" : 0, # image unique ID
"height" : 123, # height of image
"width" : 123, # width of image
"annotations": [
"category_id" : thing_classes.index("class_name"), # class unique ID
"bbox" : [0, 0, 123, 123], # bbox coordinates
"bbox_mode" : BoxMode.XYXY_ABS, # bbox mode, depending on your format
]
]
data.append(annotation)
return data
For the bbox format, you see refer to the Detectron2 code for the available options.
For examples, you can refer to the PASCAL VOC dataset loader or the COCO dataset loader.
Next, you have to create the meta information for your dataset. The only needed information is the classes for each split. Below is an example of the classes information for the first split of PASCAL VOC:
thing_classes: [ # all classes
"aeroplane", "bicycle", "boat", "bottle", "car", "cat", "chair",
"diningtable", "dog", "horse", "person", "pottedplant", "sheep",
"train", "tvmonitor", "bird", "bus", "cow", "motorbike", "sofa",
]
base_classes: [ # base clases
"aeroplane", "bicycle", "boat", "bottle", "car", "cat", "chair",
"diningtable", "dog", "horse", "person", "pottedplant", "sheep",
"train", "tvmonitor",
]
novel_classes: ["bird", "bus", "cow", "motorbike", "sofa"] # novel classes
metadata = {
"thing_clases": thing_clases,
"base_classes": base_classes,
"novel_classes": novel_classes,
}
We put all the meta information in builtin_meta.py.
Now you need to write a evaluator to evaluate on your dataset. Your class should inherit from DatasetEvaluator
and implement all its functions. Example below:
from fsdet.evaluation.evaluator import DatasetEvaluator
class NewDatasetEvaluator(DatasetEvaluator):
def __init__(self, dataset_name): # initial needed variables
self._dataset_name = dataset_name
def reset(self): # reset predictions
self._predictions = []
def process(self, inputs, outputs): # prepare predictions for evaluation
for input, output in zip(inputs, outputs):
prediction = {"image_id": input["image_id"]}
if "instances" in output:
prediction["instances"] = output["instances"]
self._predictions.append(prediction)
def evaluate(self): # evaluate predictions
results = evaluate_predictions(self._predictions)
return {
"AP": results["AP"],
"AP50": results["AP50"],
"AP75": results["AP75"],
}
For examples, you can refer to the PASCAL VOC evaluator or the COCO evaluator.
For the rest of the code to see your new dataset, you need to register it with Detectron2's DatasetCatalog and MetadataCatalog. Example below:
def register_dataset(name, thing_classes, metadata):
# register dataset (step 1)
DatasetCatalog.register(
name, # name of dataset, this will be used in the config file
lambda: dataset_loader( # this calls your dataset loader to get the data
name, thing_classes, # inputs to your dataset loader
),
)
# register meta information (step 2)
MetadataCatalog.get(name).set(
thing_classes=metadata["thing_classes"], # all classes
base_classes=metadata["base_classes"], # base classes
novel_classes=metadata["novel_classes"], # novel classes
)
MetadataCatalog.get(name).evaluator_type = "new_dataset" # set evaluator
We put the above code in a register function in its corresponding dataset file. For examples, you can refer to the PASCAL VOC register code or the COCO register code.
Then, you also need to call the register function to register the dataset. We do this in builtin.py. You should register all your datasets, including all base and novel splits. Example below:
datasets = {
'dataset_all': metadata["thing_classes"],
'dataset_base': metadata["base_classes"],
'dataset_novel': metadata["novel_classes"],
}
for dataset_name, classes in datasets.items():
register_dataset(dataset_name, classes, metadata)
Also, add your evaluator to both tools/train_net.py
and tools/test_net.py
in the build_evaluator
function:
def build_evaluator(cls, cfg, dataset_name, output_folder=None):
...
if evaluator_type == "new_dataset":
return NewDatasetEvaluator(dataset_name)
...
Modify the config files to use your new dataset. You only need to replace the datasets part to include the name of your new dataset. Example below:
_BASE_: "../../Base-RCNN-FPN.yaml"
MODEL:
WEIGHTS: "detectron2://ImageNetPretrained/MSRA/R-101.pkl"
MASK_ON: False
RESNETS:
DEPTH: 101
ROI_HEADS:
NUM_CLASSES: 15
INPUT:
MIN_SIZE_TRAIN: (480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800)
MIN_SIZE_TEST: 800
DATASETS:
TRAIN: ('dataset_all',) # <-- modify this
TEST: ('dataset_novel',) # <-- modify this
SOLVER:
STEPS: (12000, 16000)
MAX_ITER: 18000
WARMUP_ITERS: 100
OUTPUT_DIR: "checkpoints/new_dataset"
Congratulations, now you can start training and testing on your new dataset!