From bde8e36406babd375f2b80aa48e5242118b2dc0f Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 4 Jul 2018 20:18:53 +0900 Subject: [PATCH 01/10] add ImageNet detection dataset --- chainercv/datasets/__init__.py | 3 + chainercv/datasets/imagenet/__init__.py | 0 .../imagenet/imagenet_det_bbox_dataset.py | 139 ++++++ chainercv/datasets/imagenet/imagenet_utils.py | 405 ++++++++++++++++++ chainercv/datasets/voc/voc_bbox_dataset.py | 31 +- chainercv/datasets/voc/voc_utils.py | 37 ++ docs/source/reference/datasets.rst | 8 + .../test_imagenet_det_bbox_dataset.py | 56 +++ 8 files changed, 655 insertions(+), 24 deletions(-) create mode 100644 chainercv/datasets/imagenet/__init__.py create mode 100644 chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py create mode 100644 chainercv/datasets/imagenet/imagenet_utils.py create mode 100644 tests/datasets_tests/imagenet_tests/test_imagenet_det_bbox_dataset.py diff --git a/chainercv/datasets/__init__.py b/chainercv/datasets/__init__.py index 5cb1aa0734..5786365aee 100644 --- a/chainercv/datasets/__init__.py +++ b/chainercv/datasets/__init__.py @@ -17,6 +17,9 @@ from chainercv.datasets.cub.cub_utils import cub_label_names # NOQA from chainercv.datasets.directory_parsing_label_dataset import directory_parsing_label_names # NOQA from chainercv.datasets.directory_parsing_label_dataset import DirectoryParsingLabelDataset # NOQA +from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_bbox_label_names # NOQA +from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_synset_ids # NOQA +from chainercv.datasets.imagenet.imagenet_det_bbox_dataset import ImagenetDetBboxDataset # NOQA from chainercv.datasets.mixup_soft_label_dataset import MixUpSoftLabelDataset # NOQA from chainercv.datasets.online_products.online_products_dataset import online_products_super_label_names # NOQA from chainercv.datasets.online_products.online_products_dataset import OnlineProductsDataset # NOQA diff --git a/chainercv/datasets/imagenet/__init__.py b/chainercv/datasets/imagenet/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py new file mode 100644 index 0000000000..5ea0ab78a9 --- /dev/null +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -0,0 +1,139 @@ +import numpy as np +import os + +from chainer.dataset import download + +from chainercv.chainer_experimental.datasets.sliceable import GetterDataset +from chainercv.datasets.voc.voc_utils import parse_voc_bbox_annotation +from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_synset_ids +from chainercv.utils import read_image + + +class ImagenetDetBboxDataset(GetterDataset): + + """ILSVRC2014 ImageNet detection dataset + + The data is distributed on the `official Kaggle page`_. + + .. _`official Kaggle page`: https://www.kaggle.com/c/ + imagenet-object-detection-challenge + + Please refer to the readme of ILSVRC2014 dev kit for a comprehensive + documentation. Note that detection part of ILSVRC has not changed from + 2014. Overview of annotation process is described in the `paper`_. + + .. _`paper`: http://ai.stanford.edu/~olga/papers/chi2014-MultiLabel.pdf + + Every image in the training set has one or more image-level labels. + The image-level labels determine the partial presence, full presence or + absence of one or more object categories. + Bounding boxes are provided around instances of the present + categories. + + Args: + data_dir (string): Path to the root of the training data. If this is + :obj:`auto`, this class will automatically download data for you + under :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/imagenet`. + split ({'train', 'val', 'trainval', 'test'}): Select a split of the + dataset. :obj:`test` split is only available for + 2007 dataset. + return_img_label (bool): If :obj:`True`, this dataset returns + image-wise labels. This consits of two arrays: + :obj:`img_label` and :obj:`img_label_type`. + + This dataset returns the following data. + + .. csv-table:: + :header: name, shape, dtype, format + + :obj:`img`, ":math:`(3, H, W)`", :obj:`float32`, \ + "RGB, :math:`[0, 255]`" + :obj:`bbox`, ":math:`(R, 4)`", :obj:`float32`, \ + ":math:`(y_{min}, x_{min}, y_{max}, x_{max})`" + :obj:`label`, ":math:`(R,)`", :obj:`int32`, \ + ":math:`[0, \#fg\_class - 1]`" + :obj:`img_label` [#imagenet_det_1]_, ":math:`(M,)`", :obj:`int32`, \ + ":math:`[0, \#fg\_class - 1]`" + :obj:`img_label_type` [#imagenet_det_1]_ [#imagenet_det_2]_, \ + ":math:`(M,)`", :obj:`int32`, ":math:`[-1, 1]`" + + .. [#imagenet_det_1] available \ + if :obj:`return_img_label = True`. + .. [#imagenet_det_2] :obj:`-1` means absent. :obj:`1` means present. \ + :obj:`0` means partially present. When a category is partially \ + present, the image contains at least one + instance of X, but not all instances of X may be annotated with + bounding boxes. + + """ + + def __init__(self, data_dir='auto', split='train', return_img_label=False): + super(ImagenetDetBboxDataset, self).__init__() + if data_dir == 'auto': + data_dir = download.get_dataset_directory( + 'pfnet/chainercv/imagenet') + self.base_dir = os.path.join(data_dir, 'ILSVRC') + imageset_dir = os.path.join(self.base_dir, 'ImageSets/DET') + + if split == 'train': + img_labels = {} + for lb in range(0, 200): + with open(os.path.join( + imageset_dir, 'train_{}.txt'.format(lb + 1))) as f: + for l in f: + id_ = l.split()[0] + anno_type = l.split()[1] + if id_ not in img_labels: + img_labels[id_] = [] + img_labels[id_].append((lb, int(anno_type))) + self.img_labels = img_labels + self.ids = list(img_labels.keys()) + else: + if return_img_label: + raise ValueError('split has to be \'train\' when ' + 'return_img_label is True') + ids = [] + with open(os.path.join( + imageset_dir, 'val.txt')) as f: + for l in f: + id_ = l.split()[0] + ids.append(id_) + self.ids = ids + + self.split = split + + self.add_getter('img', self._get_image) + self.add_getter(('bbox', 'label'), self._get_inst_anno) + if return_img_label: + self.add_getter(('img_label', 'img_label_type'), self._get_img_label) + + def __len__(self): + return len(self.ids) + + def _get_image(self, i): + img_path = os.path.join( + self.base_dir, 'Data/DET', self.split, + self.ids[i] + '.JPEG') + img = read_image(img_path, color=True) + return img + + def _get_inst_anno(self, i): + if 'extra' not in self.ids[i]: + anno_path = os.path.join( + self.base_dir, 'Annotations/DET', self.split, + self.ids[i] + '.xml') + bbox, label, _ = parse_voc_bbox_annotation( + anno_path, imagenet_det_synset_ids, + skip_names_not_in_label_names=True) + else: + bbox = np.zeros((0, 4), dtype=np.float32) + label = np.zeros((0,), dtype=np.int32) + return bbox, label + + def _get_img_label(self, i): + img_label = np.array([val[0] for val in self.img_labels[self.ids[i]]], + dtype=np.int32) + img_label_type = np.array( + [val[1] for val in self.img_labels[self.ids[i]]], + dtype=np.int32) + return img_label, img_label_type diff --git a/chainercv/datasets/imagenet/imagenet_utils.py b/chainercv/datasets/imagenet/imagenet_utils.py new file mode 100644 index 0000000000..f39970a373 --- /dev/null +++ b/chainercv/datasets/imagenet/imagenet_utils.py @@ -0,0 +1,405 @@ +# Look up meta_det.mat from dev kit +imagenet_det_bbox_label_names = ( + 'accordion', + 'airplane', + 'ant', + 'antelope', + 'apple', + 'armadillo', + 'artichoke', + 'axe', + 'baby bed', + 'backpack', + 'bagel', + 'balance beam', + 'banana', + 'band aid', + 'banjo', + 'baseball', + 'basketball', + 'bathing cap', + 'beaker', + 'bear', + 'bee', + 'bell pepper', + 'bench', + 'bicycle', + 'binder', + 'bird', + 'bookshelf', + 'bow tie', + 'bow', + 'bowl', + 'brassiere', + 'burrito', + 'bus', + 'butterfly', + 'camel', + 'can opener', + 'car', + 'cart', + 'cattle', + 'cello', + 'centipede', + 'chain saw', + 'chair', + 'chime', + 'cocktail shaker', + 'coffee maker', + 'computer keyboard', + 'computer mouse', + 'corkscrew', + 'cream', + 'croquet ball', + 'crutch', + 'cucumber', + 'cup or mug', + 'diaper', + 'digital clock', + 'dishwasher', + 'dog', + 'domestic cat', + 'dragonfly', + 'drum', + 'dumbbell', + 'electric fan', + 'elephant', + 'face powder', + 'fig', + 'filing cabinet', + 'flower pot', + 'flute', + 'fox', + 'french horn', + 'frog', + 'frying pan', + 'giant panda', + 'goldfish', + 'golf ball', + 'golfcart', + 'guacamole', + 'guitar', + 'hair dryer', + 'hair spray', + 'hamburger', + 'hammer', + 'hamster', + 'harmonica', + 'harp', + 'hat with a wide brim', + 'head cabbage', + 'helmet', + 'hippopotamus', + 'horizontal bar', + 'horse', + 'hotdog', + 'iPod', + 'isopod', + 'jellyfish', + 'koala bear', + 'ladle', + 'ladybug', + 'lamp', + 'laptop', + 'lemon', + 'lion', + 'lipstick', + 'lizard', + 'lobster', + 'maillot', + 'maraca', + 'microphone', + 'microwave', + 'milk can', + 'miniskirt', + 'monkey', + 'motorcycle', + 'mushroom', + 'nail', + 'neck brace', + 'oboe', + 'orange', + 'otter', + 'pencil box', + 'pencil sharpener', + 'perfume', + 'person', + 'piano', + 'pineapple', + 'ping-pong ball', + 'pitcher', + 'pizza', + 'plastic bag', + 'plate rack', + 'pomegranate', + 'popsicle', + 'porcupine', + 'power drill', + 'pretzel', + 'printer', + 'puck', + 'punching bag', + 'purse', + 'rabbit', + 'racket', + 'ray', + 'red panda', + 'refrigerator', + 'remote control', + 'rubber eraser', + 'rugby ball', + 'ruler', + 'salt or pepper shaker', + 'saxophone', + 'scorpion', + 'screwdriver', + 'seal', + 'sheep', + 'ski', + 'skunk', + 'snail', + 'snake', + 'snowmobile', + 'snowplow', + 'soap dispenser', + 'soccer ball', + 'sofa', + 'spatula', + 'squirrel', + 'starfish', + 'stethoscope', + 'stove', + 'strainer', + 'strawberry', + 'stretcher', + 'sunglasses', + 'swimming trunks', + 'swine', + 'syringe', + 'table', + 'tape player', + 'tennis ball', + 'tick', + 'tie', + 'tiger', + 'toaster', + 'traffic light', + 'train', + 'trombone', + 'trumpet', + 'turtle', + 'tv or monitor', + 'unicycle', + 'vacuum', + 'violin', + 'volleyball', + 'waffle iron', + 'washer', + 'water bottle', + 'watercraft', + 'whale', + 'wine bottle', + 'zebra') + + +imagenet_det_synset_ids = ( + 'n02672831', + 'n02691156', + 'n02219486', + 'n02419796', + 'n07739125', + 'n02454379', + 'n07718747', + 'n02764044', + 'n02766320', + 'n02769748', + 'n07693725', + 'n02777292', + 'n07753592', + 'n02786058', + 'n02787622', + 'n02799071', + 'n02802426', + 'n02807133', + 'n02815834', + 'n02131653', + 'n02206856', + 'n07720875', + 'n02828884', + 'n02834778', + 'n02840245', + 'n01503061', + 'n02870880', + 'n02883205', + 'n02879718', + 'n02880940', + 'n02892767', + 'n07880968', + 'n02924116', + 'n02274259', + 'n02437136', + 'n02951585', + 'n02958343', + 'n02970849', + 'n02402425', + 'n02992211', + 'n01784675', + 'n03000684', + 'n03001627', + 'n03017168', + 'n03062245', + 'n03063338', + 'n03085013', + 'n03793489', + 'n03109150', + 'n03128519', + 'n03134739', + 'n03141823', + 'n07718472', + 'n03797390', + 'n03188531', + 'n03196217', + 'n03207941', + 'n02084071', + 'n02121808', + 'n02268443', + 'n03249569', + 'n03255030', + 'n03271574', + 'n02503517', + 'n03314780', + 'n07753113', + 'n03337140', + 'n03991062', + 'n03372029', + 'n02118333', + 'n03394916', + 'n01639765', + 'n03400231', + 'n02510455', + 'n01443537', + 'n03445777', + 'n03445924', + 'n07583066', + 'n03467517', + 'n03483316', + 'n03476991', + 'n07697100', + 'n03481172', + 'n02342885', + 'n03494278', + 'n03495258', + 'n03124170', + 'n07714571', + 'n03513137', + 'n02398521', + 'n03535780', + 'n02374451', + 'n07697537', + 'n03584254', + 'n01990800', + 'n01910747', + 'n01882714', + 'n03633091', + 'n02165456', + 'n03636649', + 'n03642806', + 'n07749582', + 'n02129165', + 'n03676483', + 'n01674464', + 'n01982650', + 'n03710721', + 'n03720891', + 'n03759954', + 'n03761084', + 'n03764736', + 'n03770439', + 'n02484322', + 'n03790512', + 'n07734744', + 'n03804744', + 'n03814639', + 'n03838899', + 'n07747607', + 'n02444819', + 'n03908618', + 'n03908714', + 'n03916031', + 'n00007846', + 'n03928116', + 'n07753275', + 'n03942813', + 'n03950228', + 'n07873807', + 'n03958227', + 'n03961711', + 'n07768694', + 'n07615774', + 'n02346627', + 'n03995372', + 'n07695742', + 'n04004767', + 'n04019541', + 'n04023962', + 'n04026417', + 'n02324045', + 'n04039381', + 'n01495701', + 'n02509815', + 'n04070727', + 'n04074963', + 'n04116512', + 'n04118538', + 'n04118776', + 'n04131690', + 'n04141076', + 'n01770393', + 'n04154565', + 'n02076196', + 'n02411705', + 'n04228054', + 'n02445715', + 'n01944390', + 'n01726692', + 'n04252077', + 'n04252225', + 'n04254120', + 'n04254680', + 'n04256520', + 'n04270147', + 'n02355227', + 'n02317335', + 'n04317175', + 'n04330267', + 'n04332243', + 'n07745940', + 'n04336792', + 'n04356056', + 'n04371430', + 'n02395003', + 'n04376876', + 'n04379243', + 'n04392985', + 'n04409515', + 'n01776313', + 'n04591157', + 'n02129604', + 'n04442312', + 'n06874185', + 'n04468005', + 'n04487394', + 'n03110669', + 'n01662784', + 'n03211117', + 'n04509417', + 'n04517823', + 'n04536866', + 'n04540053', + 'n04542943', + 'n04554684', + 'n04557648', + 'n04530566', + 'n02062744', + 'n04591713', + 'n02391049') diff --git a/chainercv/datasets/voc/voc_bbox_dataset.py b/chainercv/datasets/voc/voc_bbox_dataset.py index 87ab8ad815..5b4c8b1758 100644 --- a/chainercv/datasets/voc/voc_bbox_dataset.py +++ b/chainercv/datasets/voc/voc_bbox_dataset.py @@ -1,7 +1,6 @@ import numpy as np import os import warnings -import xml.etree.ElementTree as ET from chainercv.chainer_experimental.datasets.sliceable import GetterDataset from chainercv.datasets.voc import voc_utils @@ -89,27 +88,11 @@ def _get_image(self, i): def _get_annotations(self, i): id_ = self.ids[i] - anno = ET.parse( - os.path.join(self.data_dir, 'Annotations', id_ + '.xml')) - bbox = [] - label = [] - difficult = [] - for obj in anno.findall('object'): - # when in not using difficult split, and the object is - # difficult, skipt it. - if not self.use_difficult and int(obj.find('difficult').text) == 1: - continue - - difficult.append(int(obj.find('difficult').text)) - bndbox_anno = obj.find('bndbox') - # subtract 1 to make pixel indexes 0-based - bbox.append([ - int(bndbox_anno.find(tag).text) - 1 - for tag in ('ymin', 'xmin', 'ymax', 'xmax')]) - name = obj.find('name').text.lower().strip() - label.append(voc_utils.voc_bbox_label_names.index(name)) - bbox = np.stack(bbox).astype(np.float32) - label = np.stack(label).astype(np.int32) - # When `use_difficult==False`, all elements in `difficult` are False. - difficult = np.array(difficult, dtype=np.bool) + anno_path = os.path.join(self.data_dir, 'Annotations', id_ + '.xml') + bbox, label, difficult = voc_utils.parse_voc_bbox_annotation( + anno_path, voc_utils.voc_bbox_label_names) + if not self.use_difficult: + bbox = bbox[np.logical_not(difficult)] + label = label[np.logical_not(difficult)] + difficult = difficult[np.logical_not(difficult)] return bbox, label, difficult diff --git a/chainercv/datasets/voc/voc_utils.py b/chainercv/datasets/voc/voc_utils.py index ef09200f3a..08728398e8 100644 --- a/chainercv/datasets/voc/voc_utils.py +++ b/chainercv/datasets/voc/voc_utils.py @@ -1,5 +1,6 @@ import numpy as np import os +import xml.etree.ElementTree as ET from chainer.dataset import download @@ -38,6 +39,42 @@ def get_voc(year, split): return base_path +def parse_voc_bbox_annotation(anno_path, label_names, + skip_names_not_in_label_names=False): + anno = ET.parse(anno_path) + bbox = [] + label = [] + difficult = [] + obj = anno.find('size') + H = int(obj.find('height').text) + W = int(obj.find('width').text) + for obj in anno.findall('object'): + name = obj.find('name').text.lower().strip() + if skip_names_not_in_label_names and name not in label_names: + continue + label.append(label_names.index(name)) + bndbox_anno = obj.find('bndbox') + # subtract 1 to make pixel indexes 0-based + bbox.append([ + int(bndbox_anno.find(tag).text) - 1 + for tag in ('ymin', 'xmin', 'ymax', 'xmax')]) + if obj.find('difficult') is not None: + difficult.append(int(obj.find('difficult').text)) + + if len(bbox) > 0: + bbox = np.stack(bbox).astype(np.float32) + bbox[:, 0:2] = bbox[:, 0:2].clip(0) + bbox[:, 2] = bbox[:, 2].clip(0, H) + bbox[:, 3] = bbox[:, 3].clip(0, W) + label = np.stack(label).astype(np.int32) + difficult = np.array(difficult, dtype=np.bool) + else: + bbox = np.zeros((0, 4), dtype=np.float32) + label = np.zeros((0,), dtype=np.int32) + difficult = np.zeros((0,), dtype=np.bool) + return bbox, label, difficult + + def image_wise_to_instance_wise(label_img, inst_img): mask = [] label = [] diff --git a/docs/source/reference/datasets.rst b/docs/source/reference/datasets.rst index d075c6b1b7..fcbefc9bec 100644 --- a/docs/source/reference/datasets.rst +++ b/docs/source/reference/datasets.rst @@ -64,6 +64,14 @@ CUBPointDataset .. autoclass:: CUBPointDataset +Imagenet +-------- + +ImagenetDetBboxDataset +~~~~~~~~~~~~~~~~~~~~~~ +.. autoclass:: ImagenetDetBboxDataset + + MS COCO ------- diff --git a/tests/datasets_tests/imagenet_tests/test_imagenet_det_bbox_dataset.py b/tests/datasets_tests/imagenet_tests/test_imagenet_det_bbox_dataset.py new file mode 100644 index 0000000000..2504748f54 --- /dev/null +++ b/tests/datasets_tests/imagenet_tests/test_imagenet_det_bbox_dataset.py @@ -0,0 +1,56 @@ +import unittest + +import numpy as np + +from chainer import testing +from chainer.testing import attr +from chainer.testing import condition + +from chainercv.datasets import imagenet_det_bbox_label_names +from chainercv.datasets import ImagenetDetBboxDataset +from chainercv.utils import assert_is_bbox_dataset + + +@testing.parameterize( + {'split': 'train', 'return_img_label': False}, + {'split': 'train', 'return_img_label': True}, + {'split': 'val', 'return_img_label': False}, +) +class TestImagenetDetBboxDataset(unittest.TestCase): + + def setUp(self): + self.dataset = ImagenetDetBboxDataset( + split=self.split, + return_img_label=self.return_img_label) + self.n_out = 5 if self.return_img_label else 3 + + @attr.slow + def test_as_bbox_dataset(self): + assert_is_bbox_dataset( + self.dataset, len(imagenet_det_bbox_label_names), n_example=10) + + @attr.slow + @condition.repeat(10) + def test_img_label(self): + if not self.return_img_label: + return + + i = np.random.randint(0, len(self.dataset)) + _, _, label, img_label, img_label_type = self.dataset[i] + self.assertIsInstance(img_label, np.ndarray) + self.assertEqual(img_label.dtype, np.int32) + self.assertIsInstance(img_label_type, np.ndarray) + self.assertEqual(img_label_type.dtype, np.int32) + + self.assertEqual(img_label.shape, img_label_type.shape) + self.assertTrue(img_label.max() < len(imagenet_det_bbox_label_names) + and img_label.min() >= 0) + self.assertTrue(img_label_type.max() <= 1 + and img_label_type.min() >= -1) + if len(label) > 0: + pos_img_label = img_label[img_label_type >= 0] + for lb in label: + self.assertTrue(np.isin(lb, pos_img_label)) + + +testing.run_module(__name__, __file__) From 06c9b9e11d48c0c75d17e408e40975090fa37d38 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 4 Jul 2018 21:10:04 +0900 Subject: [PATCH 02/10] delete test --- .../test_imagenet_det_bbox_dataset.py | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 tests/datasets_tests/imagenet_tests/test_imagenet_det_bbox_dataset.py diff --git a/tests/datasets_tests/imagenet_tests/test_imagenet_det_bbox_dataset.py b/tests/datasets_tests/imagenet_tests/test_imagenet_det_bbox_dataset.py deleted file mode 100644 index 2504748f54..0000000000 --- a/tests/datasets_tests/imagenet_tests/test_imagenet_det_bbox_dataset.py +++ /dev/null @@ -1,56 +0,0 @@ -import unittest - -import numpy as np - -from chainer import testing -from chainer.testing import attr -from chainer.testing import condition - -from chainercv.datasets import imagenet_det_bbox_label_names -from chainercv.datasets import ImagenetDetBboxDataset -from chainercv.utils import assert_is_bbox_dataset - - -@testing.parameterize( - {'split': 'train', 'return_img_label': False}, - {'split': 'train', 'return_img_label': True}, - {'split': 'val', 'return_img_label': False}, -) -class TestImagenetDetBboxDataset(unittest.TestCase): - - def setUp(self): - self.dataset = ImagenetDetBboxDataset( - split=self.split, - return_img_label=self.return_img_label) - self.n_out = 5 if self.return_img_label else 3 - - @attr.slow - def test_as_bbox_dataset(self): - assert_is_bbox_dataset( - self.dataset, len(imagenet_det_bbox_label_names), n_example=10) - - @attr.slow - @condition.repeat(10) - def test_img_label(self): - if not self.return_img_label: - return - - i = np.random.randint(0, len(self.dataset)) - _, _, label, img_label, img_label_type = self.dataset[i] - self.assertIsInstance(img_label, np.ndarray) - self.assertEqual(img_label.dtype, np.int32) - self.assertIsInstance(img_label_type, np.ndarray) - self.assertEqual(img_label_type.dtype, np.int32) - - self.assertEqual(img_label.shape, img_label_type.shape) - self.assertTrue(img_label.max() < len(imagenet_det_bbox_label_names) - and img_label.min() >= 0) - self.assertTrue(img_label_type.max() <= 1 - and img_label_type.min() >= -1) - if len(label) > 0: - pos_img_label = img_label[img_label_type >= 0] - for lb in label: - self.assertTrue(np.isin(lb, pos_img_label)) - - -testing.run_module(__name__, __file__) From 33d8d9e3995a7c688fafffad1185fefec1e39b4b Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 4 Jul 2018 21:14:49 +0900 Subject: [PATCH 03/10] fix doc --- chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py index 5ea0ab78a9..b54df704e4 100644 --- a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -34,9 +34,8 @@ class ImagenetDetBboxDataset(GetterDataset): data_dir (string): Path to the root of the training data. If this is :obj:`auto`, this class will automatically download data for you under :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/imagenet`. - split ({'train', 'val', 'trainval', 'test'}): Select a split of the - dataset. :obj:`test` split is only available for - 2007 dataset. + split ({'train', 'val'}): Select a split of the + dataset. return_img_label (bool): If :obj:`True`, this dataset returns image-wise labels. This consits of two arrays: :obj:`img_label` and :obj:`img_label_type`. From 6e31126654061c48d9d6bc807a69bb1c1faab208 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 4 Jul 2018 21:48:37 +0900 Subject: [PATCH 04/10] flake8 --- chainercv/datasets/__init__.py | 2 +- chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/chainercv/datasets/__init__.py b/chainercv/datasets/__init__.py index 5786365aee..b3290551f1 100644 --- a/chainercv/datasets/__init__.py +++ b/chainercv/datasets/__init__.py @@ -17,9 +17,9 @@ from chainercv.datasets.cub.cub_utils import cub_label_names # NOQA from chainercv.datasets.directory_parsing_label_dataset import directory_parsing_label_names # NOQA from chainercv.datasets.directory_parsing_label_dataset import DirectoryParsingLabelDataset # NOQA +from chainercv.datasets.imagenet.imagenet_det_bbox_dataset import ImagenetDetBboxDataset # NOQA from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_bbox_label_names # NOQA from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_synset_ids # NOQA -from chainercv.datasets.imagenet.imagenet_det_bbox_dataset import ImagenetDetBboxDataset # NOQA from chainercv.datasets.mixup_soft_label_dataset import MixUpSoftLabelDataset # NOQA from chainercv.datasets.online_products.online_products_dataset import online_products_super_label_names # NOQA from chainercv.datasets.online_products.online_products_dataset import OnlineProductsDataset # NOQA diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py index b54df704e4..9476ad77fa 100644 --- a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -4,8 +4,8 @@ from chainer.dataset import download from chainercv.chainer_experimental.datasets.sliceable import GetterDataset -from chainercv.datasets.voc.voc_utils import parse_voc_bbox_annotation from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_synset_ids +from chainercv.datasets.voc.voc_utils import parse_voc_bbox_annotation from chainercv.utils import read_image @@ -104,7 +104,8 @@ def __init__(self, data_dir='auto', split='train', return_img_label=False): self.add_getter('img', self._get_image) self.add_getter(('bbox', 'label'), self._get_inst_anno) if return_img_label: - self.add_getter(('img_label', 'img_label_type'), self._get_img_label) + self.add_getter( + ('img_label', 'img_label_type'), self._get_img_label) def __len__(self): return len(self.ids) From 5b5c88c335137b1e2996ccfbe11345b08eb80876 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Wed, 4 Jul 2018 22:03:24 +0900 Subject: [PATCH 05/10] fix doc --- chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py index 9476ad77fa..d0eee41397 100644 --- a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -11,7 +11,7 @@ class ImagenetDetBboxDataset(GetterDataset): - """ILSVRC2014 ImageNet detection dataset + """ILSVRC2014 ImageNet detection dataset. The data is distributed on the `official Kaggle page`_. @@ -32,8 +32,8 @@ class ImagenetDetBboxDataset(GetterDataset): Args: data_dir (string): Path to the root of the training data. If this is - :obj:`auto`, this class will automatically download data for you - under :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/imagenet`. + :obj:`auto`, this uses + :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/imagenet` by default. split ({'train', 'val'}): Select a split of the dataset. return_img_label (bool): If :obj:`True`, this dataset returns From 6390d7655b7a6e299e1341b2a6734f7c0af5968c Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Thu, 5 Jul 2018 00:31:32 +0900 Subject: [PATCH 06/10] fix doc --- .../imagenet/imagenet_det_bbox_dataset.py | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py index d0eee41397..697740c294 100644 --- a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -19,25 +19,23 @@ class ImagenetDetBboxDataset(GetterDataset): imagenet-object-detection-challenge Please refer to the readme of ILSVRC2014 dev kit for a comprehensive - documentation. Note that detection part of ILSVRC has not changed from - 2014. Overview of annotation process is described in the `paper`_. + documentation. Note that the detection part of ILSVRC has not changed since + 2014. An overview of annotation process is described in the `paper`_. .. _`paper`: http://ai.stanford.edu/~olga/papers/chi2014-MultiLabel.pdf Every image in the training set has one or more image-level labels. - The image-level labels determine the partial presence, full presence or + The image-level labels determine the full presence, partial presence or absence of one or more object categories. - Bounding boxes are provided around instances of the present - categories. + Bounding boxes are provided around instances of the present categories. Args: data_dir (string): Path to the root of the training data. If this is - :obj:`auto`, this uses - :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/imagenet` by default. - split ({'train', 'val'}): Select a split of the - dataset. + :obj:`auto`, + :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/imagenet` is used. + split ({'train', 'val'}): Selects a split of the dataset. return_img_label (bool): If :obj:`True`, this dataset returns - image-wise labels. This consits of two arrays: + image-wise labels. This consists of two arrays: :obj:`img_label` and :obj:`img_label_type`. This dataset returns the following data. @@ -56,10 +54,10 @@ class ImagenetDetBboxDataset(GetterDataset): :obj:`img_label_type` [#imagenet_det_1]_ [#imagenet_det_2]_, \ ":math:`(M,)`", :obj:`int32`, ":math:`[-1, 1]`" - .. [#imagenet_det_1] available \ + .. [#imagenet_det_1] available if :obj:`return_img_label = True`. - .. [#imagenet_det_2] :obj:`-1` means absent. :obj:`1` means present. \ - :obj:`0` means partially present. When a category is partially \ + .. [#imagenet_det_2] :obj:`-1` means absent. :obj:`1` means present. + :obj:`0` means partially present. When a category is partially present, the image contains at least one instance of X, but not all instances of X may be annotated with bounding boxes. From 300a5f60ae57ccdb824813e621854d2d8b11c678 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Sat, 7 Jul 2018 21:37:07 +0900 Subject: [PATCH 07/10] support year 2013 --- .../imagenet/imagenet_det_bbox_dataset.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py index 697740c294..7797afa38a 100644 --- a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -11,7 +11,7 @@ class ImagenetDetBboxDataset(GetterDataset): - """ILSVRC2014 ImageNet detection dataset. + """ILSVRC ImageNet detection dataset. The data is distributed on the `official Kaggle page`_. @@ -33,7 +33,10 @@ class ImagenetDetBboxDataset(GetterDataset): data_dir (string): Path to the root of the training data. If this is :obj:`auto`, :obj:`$CHAINER_DATASET_ROOT/pfnet/chainercv/imagenet` is used. - split ({'train', 'val'}): Selects a split of the dataset. + split ({'train', 'val', 'val1', 'val2'}): Selects a split of the + dataset. + year ({'2013', '2014'}): Use a dataset prepared for a challenge + held in :obj:`year`. The default value is :obj:`2014`. return_img_label (bool): If :obj:`True`, this dataset returns image-wise labels. This consists of two arrays: :obj:`img_label` and :obj:`img_label_type`. @@ -64,11 +67,16 @@ class ImagenetDetBboxDataset(GetterDataset): """ - def __init__(self, data_dir='auto', split='train', return_img_label=False): + def __init__(self, data_dir='auto', split='train', year='2014', + return_img_label=False): super(ImagenetDetBboxDataset, self).__init__() if data_dir == 'auto': data_dir = download.get_dataset_directory( 'pfnet/chainercv/imagenet') + + if year not in ('2013', '2014'): + raise ValueError('\'year\' has to be either ' + '\'2013\' or \'2014\'.') self.base_dir = os.path.join(data_dir, 'ILSVRC') imageset_dir = os.path.join(self.base_dir, 'ImageSets/DET') @@ -79,6 +87,9 @@ def __init__(self, data_dir='auto', split='train', return_img_label=False): imageset_dir, 'train_{}.txt'.format(lb + 1))) as f: for l in f: id_ = l.split()[0] + if 'ILSVRC2014' in id_ and year != '2014': + continue + anno_type = l.split()[1] if id_ not in img_labels: img_labels[id_] = [] @@ -91,7 +102,7 @@ def __init__(self, data_dir='auto', split='train', return_img_label=False): 'return_img_label is True') ids = [] with open(os.path.join( - imageset_dir, 'val.txt')) as f: + imageset_dir, '{}.txt'.format(split))) as f: for l in f: id_ = l.split()[0] ids.append(id_) From 746eb58a883c640b70e624517eb65974f6f9b5b8 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Sat, 7 Jul 2018 21:43:45 +0900 Subject: [PATCH 08/10] fix bug with val1 and val2 --- chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py index 7797afa38a..a9d1122ad7 100644 --- a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -96,6 +96,7 @@ def __init__(self, data_dir='auto', split='train', year='2014', img_labels[id_].append((lb, int(anno_type))) self.img_labels = img_labels self.ids = list(img_labels.keys()) + self.split_type = 'train' else: if return_img_label: raise ValueError('split has to be \'train\' when ' @@ -107,8 +108,7 @@ def __init__(self, data_dir='auto', split='train', year='2014', id_ = l.split()[0] ids.append(id_) self.ids = ids - - self.split = split + self.split_type = 'val' self.add_getter('img', self._get_image) self.add_getter(('bbox', 'label'), self._get_inst_anno) @@ -121,7 +121,7 @@ def __len__(self): def _get_image(self, i): img_path = os.path.join( - self.base_dir, 'Data/DET', self.split, + self.base_dir, 'Data/DET', self.split_type, self.ids[i] + '.JPEG') img = read_image(img_path, color=True) return img @@ -129,7 +129,7 @@ def _get_image(self, i): def _get_inst_anno(self, i): if 'extra' not in self.ids[i]: anno_path = os.path.join( - self.base_dir, 'Annotations/DET', self.split, + self.base_dir, 'Annotations/DET', self.split_type, self.ids[i] + '.xml') bbox, label, _ = parse_voc_bbox_annotation( anno_path, imagenet_det_synset_ids, From 07097045a269d993a8419035b5f2591553e204b1 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Mon, 9 Jul 2018 10:54:05 +0900 Subject: [PATCH 09/10] add an option to ignore blacklist --- .../imagenet/imagenet_det_bbox_dataset.py | 28 +++++++++++++++++-- chainercv/datasets/imagenet/imagenet_utils.py | 20 +++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py index a9d1122ad7..21ef3ee7e3 100644 --- a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -4,6 +4,7 @@ from chainer.dataset import download from chainercv.chainer_experimental.datasets.sliceable import GetterDataset +from chainercv.datasets.imagenet.imagenet_utils import get_ilsvrc_devkit from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_synset_ids from chainercv.datasets.voc.voc_utils import parse_voc_bbox_annotation from chainercv.utils import read_image @@ -40,6 +41,9 @@ class ImagenetDetBboxDataset(GetterDataset): return_img_label (bool): If :obj:`True`, this dataset returns image-wise labels. This consists of two arrays: :obj:`img_label` and :obj:`img_label_type`. + use_val_blacklist (bool): If :obj:`False`, images that are + included in the blacklist are avoided when + the split is :obj:`val`. The default value is :obj:`False`. This dataset returns the following data. @@ -68,11 +72,15 @@ class ImagenetDetBboxDataset(GetterDataset): """ def __init__(self, data_dir='auto', split='train', year='2014', - return_img_label=False): + return_img_label=False, use_val_blacklist=False): super(ImagenetDetBboxDataset, self).__init__() if data_dir == 'auto': data_dir = download.get_dataset_directory( 'pfnet/chainercv/imagenet') + get_ilsvrc_devkit() + val_blacklist_path = os.path.join( + data_dir, 'ILSVRC2014_devkit/data/', + 'ILSVRC2014_det_validation_blacklist.txt') if year not in ('2013', '2014'): raise ValueError('\'year\' has to be either ' @@ -101,12 +109,28 @@ def __init__(self, data_dir='auto', split='train', year='2014', if return_img_label: raise ValueError('split has to be \'train\' when ' 'return_img_label is True') + if use_val_blacklist: + blacklist_ids = [] + else: + ids = [] + with open(os.path.join( + imageset_dir, 'val.txt'.format(split))) as f: + for l in f: + id_ = l.split()[0] + ids.append(id_) + blacklist_ids = [] + with open(val_blacklist_path) as f: + for l in f: + index = int(l.split()[0]) + blacklist_ids.append(ids[index]) + ids = [] with open(os.path.join( imageset_dir, '{}.txt'.format(split))) as f: for l in f: id_ = l.split()[0] - ids.append(id_) + if id_ not in blacklist_ids: + ids.append(id_) self.ids = ids self.split_type = 'val' diff --git a/chainercv/datasets/imagenet/imagenet_utils.py b/chainercv/datasets/imagenet/imagenet_utils.py index f39970a373..cfa28b2c78 100644 --- a/chainercv/datasets/imagenet/imagenet_utils.py +++ b/chainercv/datasets/imagenet/imagenet_utils.py @@ -1,3 +1,23 @@ +import os + +from chainer.dataset import download +from chainercv import utils + +root = 'pfnet/chainercv/imagenet' +devkit_url = 'http://image-net.org/image/ilsvrc2014/ILSVRC2014_devkit.tgz' + + +def get_ilsvrc_devkit(): + data_root = download.get_dataset_directory(root) + base_dir = os.path.join(data_root, 'ILSVRC2014_devkit') + if os.path.exists(base_dir): + return data_root + download_file_path = utils.cached_download(devkit_url) + ext = os.path.splitext(devkit_url)[1] + utils.extractall(download_file_path, data_root, ext) + return data_root + + # Look up meta_det.mat from dev kit imagenet_det_bbox_label_names = ( 'accordion', From 8bf3566cfde6ae8ab1aa492b7e56b8e5aa768ce1 Mon Sep 17 00:00:00 2001 From: Yusuke Niitani Date: Thu, 14 Feb 2019 16:18:25 +0900 Subject: [PATCH 10/10] add filelock && change name --- chainercv/datasets/__init__.py | 2 +- .../imagenet/imagenet_det_bbox_dataset.py | 14 +++++++------- chainercv/datasets/imagenet/imagenet_utils.py | 15 +++++++++------ docs/source/reference/datasets.rst | 6 +++--- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/chainercv/datasets/__init__.py b/chainercv/datasets/__init__.py index bb8b5fc46d..d3feb7be01 100644 --- a/chainercv/datasets/__init__.py +++ b/chainercv/datasets/__init__.py @@ -22,7 +22,7 @@ from chainercv.datasets.cub.cub_utils import cub_label_names # NOQA from chainercv.datasets.directory_parsing_label_dataset import directory_parsing_label_names # NOQA from chainercv.datasets.directory_parsing_label_dataset import DirectoryParsingLabelDataset # NOQA -from chainercv.datasets.imagenet.imagenet_det_bbox_dataset import ImagenetDetBboxDataset # NOQA +from chainercv.datasets.imagenet.imagenet_det_bbox_dataset import ImageNetDetBboxDataset # NOQA from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_bbox_label_names # NOQA from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_synset_ids # NOQA from chainercv.datasets.mixup_soft_label_dataset import MixUpSoftLabelDataset # NOQA diff --git a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py index 21ef3ee7e3..0a60545513 100644 --- a/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py +++ b/chainercv/datasets/imagenet/imagenet_det_bbox_dataset.py @@ -1,8 +1,6 @@ import numpy as np import os -from chainer.dataset import download - from chainercv.chainer_experimental.datasets.sliceable import GetterDataset from chainercv.datasets.imagenet.imagenet_utils import get_ilsvrc_devkit from chainercv.datasets.imagenet.imagenet_utils import imagenet_det_synset_ids @@ -10,7 +8,7 @@ from chainercv.utils import read_image -class ImagenetDetBboxDataset(GetterDataset): +class ImageNetDetBboxDataset(GetterDataset): """ILSVRC ImageNet detection dataset. @@ -73,11 +71,9 @@ class ImagenetDetBboxDataset(GetterDataset): def __init__(self, data_dir='auto', split='train', year='2014', return_img_label=False, use_val_blacklist=False): - super(ImagenetDetBboxDataset, self).__init__() + super(ImageNetDetBboxDataset, self).__init__() if data_dir == 'auto': - data_dir = download.get_dataset_directory( - 'pfnet/chainercv/imagenet') - get_ilsvrc_devkit() + data_dir = get_ilsvrc_devkit() val_blacklist_path = os.path.join( data_dir, 'ILSVRC2014_devkit/data/', 'ILSVRC2014_det_validation_blacklist.txt') @@ -87,6 +83,10 @@ def __init__(self, data_dir='auto', split='train', year='2014', '\'2013\' or \'2014\'.') self.base_dir = os.path.join(data_dir, 'ILSVRC') imageset_dir = os.path.join(self.base_dir, 'ImageSets/DET') + if not os.path.exists(imageset_dir): + raise ValueError( + 'Images of ImageNet Detection data is not found.' + 'Please download them from the offical kaggle page.') if split == 'train': img_labels = {} diff --git a/chainercv/datasets/imagenet/imagenet_utils.py b/chainercv/datasets/imagenet/imagenet_utils.py index cfa28b2c78..c00b3b96f3 100644 --- a/chainercv/datasets/imagenet/imagenet_utils.py +++ b/chainercv/datasets/imagenet/imagenet_utils.py @@ -1,3 +1,4 @@ +import filelock import os from chainer.dataset import download @@ -9,12 +10,14 @@ def get_ilsvrc_devkit(): data_root = download.get_dataset_directory(root) - base_dir = os.path.join(data_root, 'ILSVRC2014_devkit') - if os.path.exists(base_dir): - return data_root - download_file_path = utils.cached_download(devkit_url) - ext = os.path.splitext(devkit_url)[1] - utils.extractall(download_file_path, data_root, ext) + + with filelock.FileLock(os.path.join(data_root, 'lock')): + base_dir = os.path.join(data_root, 'ILSVRC2014_devkit') + if os.path.exists(base_dir): + return data_root + download_file_path = utils.cached_download(devkit_url) + ext = os.path.splitext(devkit_url)[1] + utils.extractall(download_file_path, data_root, ext) return data_root diff --git a/docs/source/reference/datasets.rst b/docs/source/reference/datasets.rst index 8c91b8a819..6cce9e27be 100644 --- a/docs/source/reference/datasets.rst +++ b/docs/source/reference/datasets.rst @@ -62,12 +62,12 @@ CUBPointDataset ~~~~~~~~~~~~~~~ .. autoclass:: CUBPointDataset -Imagenet +ImageNet -------- -ImagenetDetBboxDataset +ImageNetDetBboxDataset ~~~~~~~~~~~~~~~~~~~~~~ -.. autoclass:: ImagenetDetBboxDataset +.. autoclass:: ImageNetDetBboxDataset MS COCO -------