|
| 1 | +# coding=utf-8 |
| 2 | +# Copyright 2019 The TensorFlow Datasets Authors. |
| 3 | +# |
| 4 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +# you may not use this file except in compliance with the License. |
| 6 | +# You may obtain a copy of the License at |
| 7 | +# |
| 8 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +# |
| 10 | +# Unless required by applicable law or agreed to in writing, software |
| 11 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +# See the License for the specific language governing permissions and |
| 14 | +# limitations under the License. |
| 15 | + |
| 16 | +# Lint as: python3 |
| 17 | +"""INaturalist datasets.""" |
| 18 | + |
| 19 | +from __future__ import absolute_import |
| 20 | +from __future__ import division |
| 21 | +from __future__ import print_function |
| 22 | + |
| 23 | +import json |
| 24 | +import os |
| 25 | + |
| 26 | +import six.moves.urllib as urllib |
| 27 | +import tensorflow as tf |
| 28 | +import tensorflow_datasets.public_api as tfds |
| 29 | + |
| 30 | +_DESCRIPTION = """\ |
| 31 | +This dataset contains a total of 5,089 categories, across 579,184 training |
| 32 | +images and 95,986 validation images. For the training set, the distribution of |
| 33 | +images per category follows the observation frequency of that category by the |
| 34 | +iNaturalist community. |
| 35 | +
|
| 36 | +Although the original dataset contains some images with bounding boxes, |
| 37 | +currently, only image-level annotations are provided (single label/image). |
| 38 | +In addition, the organizers have not published the test labels, so we only |
| 39 | +provide the test images (label = -1). |
| 40 | +""" |
| 41 | +_CITATION = """\ |
| 42 | +@InProceedings{Horn_2018_CVPR, |
| 43 | +author = { |
| 44 | +Van Horn, Grant and Mac Aodha, Oisin and Song, Yang and Cui, Yin and Sun, Chen |
| 45 | +and Shepard, Alex and Adam, Hartwig and Perona, Pietro and Belongie, Serge}, |
| 46 | +title = {The INaturalist Species Classification and Detection Dataset}, |
| 47 | +booktitle = { |
| 48 | +The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, |
| 49 | +month = {June}, |
| 50 | +year = {2018} |
| 51 | +} |
| 52 | +""" |
| 53 | +_URL = "http://www.vision.caltech.edu/~gvanhorn/datasets/inaturalist/fgvc4_competition/" |
| 54 | + |
| 55 | + |
| 56 | +class INaturalist2017(tfds.core.GeneratorBasedBuilder): |
| 57 | + """Dataset from the INaturalist Competition 2017.""" |
| 58 | + |
| 59 | + VERSION = tfds.core.Version("0.1.0") |
| 60 | + |
| 61 | + def _info(self): |
| 62 | + """Define the dataset info.""" |
| 63 | + return tfds.core.DatasetInfo( |
| 64 | + builder=self, |
| 65 | + description=_DESCRIPTION, |
| 66 | + features=tfds.features.FeaturesDict({ |
| 67 | + "id": tfds.features.Text(), |
| 68 | + "image": tfds.features.Image(), |
| 69 | + "label": tfds.features.ClassLabel( |
| 70 | + names_file=tfds.core.get_tfds_path( |
| 71 | + os.path.join("image", "inaturalist_labels.txt"))), |
| 72 | + "supercategory": tfds.features.ClassLabel( |
| 73 | + names_file=tfds.core.get_tfds_path( |
| 74 | + os.path.join("image", "inaturalist_supercategories.txt"))), |
| 75 | + }), |
| 76 | + supervised_keys=("image", "label"), |
| 77 | + homepage="https://github.com/visipedia/inat_comp/tree/master/2017", |
| 78 | + citation=_CITATION) |
| 79 | + |
| 80 | + def _split_generators(self, dl_manager): |
| 81 | + output_files = dl_manager.download_and_extract({ |
| 82 | + "trainval_images": |
| 83 | + tfds.download.Resource( |
| 84 | + url=urllib.parse.urljoin(_URL, "train_val_images.tar.gz"), |
| 85 | + extract_method=tfds.download.ExtractMethod.NO_EXTRACT), |
| 86 | + "trainval_annos": |
| 87 | + urllib.parse.urljoin(_URL, "train_val2017.zip"), |
| 88 | + "test_images": |
| 89 | + tfds.download.Resource( |
| 90 | + url=urllib.parse.urljoin(_URL, "test2017.tar.gz"), |
| 91 | + extract_method=tfds.download.ExtractMethod.NO_EXTRACT), |
| 92 | + |
| 93 | + }) |
| 94 | + return [ |
| 95 | + tfds.core.SplitGenerator( |
| 96 | + name=tfds.Split.TRAIN, |
| 97 | + gen_kwargs=dict( |
| 98 | + images_archive=dl_manager.iter_archive( |
| 99 | + output_files["trainval_images"]), |
| 100 | + annon_file=os.path.join(output_files["trainval_annos"], |
| 101 | + "train2017.json"), |
| 102 | + ), |
| 103 | + ), |
| 104 | + tfds.core.SplitGenerator( |
| 105 | + name=tfds.Split.VALIDATION, |
| 106 | + gen_kwargs=dict( |
| 107 | + images_archive=dl_manager.iter_archive( |
| 108 | + output_files["trainval_images"]), |
| 109 | + annon_file=os.path.join(output_files["trainval_annos"], |
| 110 | + "val2017.json"), |
| 111 | + ), |
| 112 | + ), |
| 113 | + tfds.core.SplitGenerator( |
| 114 | + name=tfds.Split.TEST, |
| 115 | + gen_kwargs=dict( |
| 116 | + images_archive=dl_manager.iter_archive( |
| 117 | + output_files["test_images"]), |
| 118 | + annon_file=None, |
| 119 | + ), |
| 120 | + ), |
| 121 | + ] |
| 122 | + |
| 123 | + def _generate_examples(self, images_archive, annon_file): |
| 124 | + """Generate examples.""" |
| 125 | + if annon_file is not None: |
| 126 | + # Training and validation images. |
| 127 | + with tf.io.gfile.GFile(annon_file, "r") as f: |
| 128 | + data = json.load(f) |
| 129 | + # First read the annotations file, used to filter the contents of the |
| 130 | + # tar.gz file when yielding examples. |
| 131 | + key2data = {} |
| 132 | + for image, annotation in zip(data["images"], data["annotations"]): |
| 133 | + category_id = annotation["category_id"] |
| 134 | + category = data["categories"][category_id]["name"] |
| 135 | + supercategory = data["categories"][category_id]["supercategory"] |
| 136 | + key = os.path.basename(image["file_name"]).split(".")[0] |
| 137 | + key2data[key] = { |
| 138 | + "id": key, |
| 139 | + "label": category, |
| 140 | + "supercategory": supercategory, |
| 141 | + } |
| 142 | + # Read tar.gz file containing train & validation images and yield relevant |
| 143 | + # examples. |
| 144 | + for fpath, fobj in images_archive: |
| 145 | + key = os.path.basename(fpath).split(".")[0] |
| 146 | + if key in key2data: |
| 147 | + data = key2data[key].copy() |
| 148 | + data["image"] = fobj |
| 149 | + yield key, data |
| 150 | + else: |
| 151 | + # Read tar.gz file containing all test images and yield all examples. |
| 152 | + for fpath, fobj in images_archive: |
| 153 | + key = os.path.basename(fpath).split(".")[0] |
| 154 | + # Note: test labels are not annotated, so just return -1 as labels. |
| 155 | + yield key, { |
| 156 | + "id": key, |
| 157 | + "image": fobj, |
| 158 | + "label": -1, |
| 159 | + "supercategory": -1, |
| 160 | + } |
0 commit comments