diff --git a/.github/workflows/prototype-tests-linux-gpu.yml b/.github/workflows/prototype-tests-linux-gpu.yml deleted file mode 100644 index f32d5a7fc3a..00000000000 --- a/.github/workflows/prototype-tests-linux-gpu.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Prototype tests on Linux - -# IMPORTANT: This workflow has been manually disabled from the GitHub interface -# in June 2024. The file is kept for reference in case we ever put this back. - -on: - pull_request: - -jobs: - unittests-prototype: - strategy: - matrix: - python-version: - - "3.8" - - "3.9" - - "3.10" - - "3.11" - - "3.12" - runner: ["linux.12xlarge"] - gpu-arch-type: ["cpu"] - include: - - python-version: "3.8" - runner: linux.g5.4xlarge.nvidia.gpu - gpu-arch-type: cuda - gpu-arch-version: "11.8" - fail-fast: false - uses: pytorch/test-infra/.github/workflows/linux_job.yml@release/2.4 - with: - repository: pytorch/vision - runner: ${{ matrix.runner }} - gpu-arch-type: ${{ matrix.gpu-arch-type }} - gpu-arch-version: ${{ matrix.gpu-arch-version }} - timeout: 120 - script: | - set -euo pipefail - - export PYTHON_VERSION=${{ matrix.python-version }} - export GPU_ARCH_TYPE=${{ matrix.gpu-arch-type }} - export GPU_ARCH_VERSION=${{ matrix.gpu-arch-version }} - ./.github/scripts/setup-env.sh - - # Prepare conda - CONDA_PATH=$(which conda) - eval "$(${CONDA_PATH} shell.bash hook)" - conda activate ci - - echo '::group::Install testing utilities' - pip install --progress-bar=off pytest pytest-mock pytest-cov - echo '::endgroup::' - - # We don't want to run the prototype datasets tests. Since the positional glob into `pytest`, i.e. - # `test/test_prototype*.py` takes the highest priority, neither `--ignore` nor `--ignore-glob` can help us here. - rm test/test_prototype_datasets*.py - pytest \ - -v --durations=25 \ - --cov=torchvision/prototype --cov-report=term-missing \ - --junit-xml="${RUNNER_TEST_RESULTS_DIR}/test-results.xml" \ - test/test_prototype_*.py diff --git a/mypy.ini b/mypy.ini index d6f3cb16963..e66bee0af36 100644 --- a/mypy.ini +++ b/mypy.ini @@ -7,28 +7,6 @@ allow_redefinition = True no_implicit_optional = True warn_redundant_casts = True -[mypy-torchvision.prototype.datapoints.*] - -; untyped definitions and calls -disallow_untyped_defs = True - -; None and Optional handling -no_implicit_optional = True - -; warnings -warn_unused_ignores = True - -; miscellaneous strictness flags -allow_redefinition = True - -[mypy-torchvision.prototype.transforms.*] - -ignore_errors = True - -[mypy-torchvision.prototype.datasets.*] - -ignore_errors = True - [mypy-torchvision.io.image.*] ignore_errors = True diff --git a/setup.py b/setup.py index fedbc370f72..c0c1050f784 100644 --- a/setup.py +++ b/setup.py @@ -550,7 +550,7 @@ def run(self): license="BSD", # Package info packages=find_packages(exclude=("test",)), - package_data={package_name: ["*.dll", "*.dylib", "*.so", "prototype/datasets/_builtin/*.categories"]}, + package_data={package_name: ["*.dll", "*.dylib", "*.so"]}, zip_safe=False, install_requires=requirements, extras_require={ diff --git a/test/builtin_dataset_mocks.py b/test/builtin_dataset_mocks.py deleted file mode 100644 index ef5d5e1ec96..00000000000 --- a/test/builtin_dataset_mocks.py +++ /dev/null @@ -1,1582 +0,0 @@ -import bz2 -import collections.abc -import csv -import functools -import gzip -import io -import itertools -import json -import lzma -import pathlib -import pickle -import random -import shutil -import unittest.mock -import xml.etree.ElementTree as ET -from collections import Counter, defaultdict - -import numpy as np -import pytest -import torch -from common_utils import combinations_grid -from datasets_utils import create_image_file, create_image_folder, make_tar, make_zip -from torch.nn.functional import one_hot -from torch.testing import make_tensor as _make_tensor -from torchvision.prototype import datasets - -make_tensor = functools.partial(_make_tensor, device="cpu") -make_scalar = functools.partial(make_tensor, ()) - - -__all__ = ["DATASET_MOCKS", "parametrize_dataset_mocks"] - - -class DatasetMock: - def __init__(self, name, *, mock_data_fn, configs): - # FIXME: error handling for unknown names - self.name = name - self.mock_data_fn = mock_data_fn - self.configs = configs - - def _parse_mock_info(self, mock_info): - if mock_info is None: - raise pytest.UsageError( - f"The mock data function for dataset '{self.name}' returned nothing. It needs to at least return an " - f"integer indicating the number of samples for the current `config`." - ) - elif isinstance(mock_info, int): - mock_info = dict(num_samples=mock_info) - elif not isinstance(mock_info, dict): - raise pytest.UsageError( - f"The mock data function for dataset '{self.name}' returned a {type(mock_info)}. The returned object " - f"should be a dictionary containing at least the number of samples for the key `'num_samples'`. If no " - f"additional information is required for specific tests, the number of samples can also be returned as " - f"an integer." - ) - elif "num_samples" not in mock_info: - raise pytest.UsageError( - f"The dictionary returned by the mock data function for dataset '{self.name}' has to contain a " - f"`'num_samples'` entry indicating the number of samples." - ) - - return mock_info - - def load(self, config): - # `datasets.home()` is patched to a temporary directory through the autouse fixture `test_home` in - # test/test_prototype_builtin_datasets.py - root = pathlib.Path(datasets.home()) / self.name - # We cannot place the mock data upfront in `root`. Loading a dataset calls `OnlineResource.load`. In turn, - # this will only download **and** preprocess if the file is not present. In other words, if we already place - # the file in `root` before the resource is loaded, we are effectively skipping the preprocessing. - # To avoid that we first place the mock data in a temporary directory and patch the download logic to move it to - # `root` only when it is requested. - tmp_mock_data_folder = root / "__mock__" - tmp_mock_data_folder.mkdir(parents=True) - - mock_info = self._parse_mock_info(self.mock_data_fn(tmp_mock_data_folder, config)) - - def patched_download(resource, root, **kwargs): - src = tmp_mock_data_folder / resource.file_name - if not src.exists(): - raise pytest.UsageError( - f"Dataset '{self.name}' requires the file {resource.file_name} for {config}" - f"but it was not created by the mock data function." - ) - - dst = root / resource.file_name - shutil.move(str(src), str(root)) - - return dst - - with unittest.mock.patch( - "torchvision.prototype.datasets.utils._resource.OnlineResource.download", new=patched_download - ): - dataset = datasets.load(self.name, **config) - - extra_files = list(tmp_mock_data_folder.glob("**/*")) - if extra_files: - raise pytest.UsageError( - ( - f"Dataset '{self.name}' created the following files for {config} in the mock data function, " - f"but they were not loaded:\n\n" - ) - + "\n".join(str(file.relative_to(tmp_mock_data_folder)) for file in extra_files) - ) - - tmp_mock_data_folder.rmdir() - - return dataset, mock_info - - -def config_id(name, config): - parts = [name] - for name, value in config.items(): - if isinstance(value, bool): - part = ("" if value else "no_") + name - else: - part = str(value) - parts.append(part) - return "-".join(parts) - - -def parametrize_dataset_mocks(*dataset_mocks, marks=None): - mocks = {} - for mock in dataset_mocks: - if isinstance(mock, DatasetMock): - mocks[mock.name] = mock - elif isinstance(mock, collections.abc.Mapping): - mocks.update(mock) - else: - raise pytest.UsageError( - f"The positional arguments passed to `parametrize_dataset_mocks` can either be a `DatasetMock`, " - f"a sequence of `DatasetMock`'s, or a mapping of names to `DatasetMock`'s, " - f"but got {mock} instead." - ) - dataset_mocks = mocks - - if marks is None: - marks = {} - elif not isinstance(marks, collections.abc.Mapping): - raise pytest.UsageError() - - return pytest.mark.parametrize( - ("dataset_mock", "config"), - [ - pytest.param(dataset_mock, config, id=config_id(name, config), marks=marks.get(name, ())) - for name, dataset_mock in dataset_mocks.items() - for config in dataset_mock.configs - ], - ) - - -DATASET_MOCKS = {} - - -def register_mock(name=None, *, configs): - def wrapper(mock_data_fn): - nonlocal name - if name is None: - name = mock_data_fn.__name__ - DATASET_MOCKS[name] = DatasetMock(name, mock_data_fn=mock_data_fn, configs=configs) - - return mock_data_fn - - return wrapper - - -class MNISTMockData: - _DTYPES_ID = { - torch.uint8: 8, - torch.int8: 9, - torch.int16: 11, - torch.int32: 12, - torch.float32: 13, - torch.float64: 14, - } - - @classmethod - def _magic(cls, dtype, ndim): - return cls._DTYPES_ID[dtype] * 256 + ndim + 1 - - @staticmethod - def _encode(t): - return torch.tensor(t, dtype=torch.int32).numpy().tobytes()[::-1] - - @staticmethod - def _big_endian_dtype(dtype): - np_dtype = getattr(np, str(dtype).replace("torch.", ""))().dtype - return np.dtype(f">{np_dtype.kind}{np_dtype.itemsize}") - - @classmethod - def _create_binary_file(cls, root, filename, *, num_samples, shape, dtype, compressor, low=0, high): - with compressor(root / filename, "wb") as fh: - for meta in (cls._magic(dtype, len(shape)), num_samples, *shape): - fh.write(cls._encode(meta)) - - data = make_tensor((num_samples, *shape), dtype=dtype, low=low, high=high) - - fh.write(data.numpy().astype(cls._big_endian_dtype(dtype)).tobytes()) - - @classmethod - def generate( - cls, - root, - *, - num_categories, - num_samples=None, - images_file, - labels_file, - image_size=(28, 28), - image_dtype=torch.uint8, - label_size=(), - label_dtype=torch.uint8, - compressor=None, - ): - if num_samples is None: - num_samples = num_categories - if compressor is None: - compressor = gzip.open - - cls._create_binary_file( - root, - images_file, - num_samples=num_samples, - shape=image_size, - dtype=image_dtype, - compressor=compressor, - high=float("inf"), - ) - cls._create_binary_file( - root, - labels_file, - num_samples=num_samples, - shape=label_size, - dtype=label_dtype, - compressor=compressor, - high=num_categories, - ) - - return num_samples - - -def mnist(root, config): - prefix = "train" if config["split"] == "train" else "t10k" - return MNISTMockData.generate( - root, - num_categories=10, - images_file=f"{prefix}-images-idx3-ubyte.gz", - labels_file=f"{prefix}-labels-idx1-ubyte.gz", - ) - - -DATASET_MOCKS.update( - { - name: DatasetMock(name, mock_data_fn=mnist, configs=combinations_grid(split=("train", "test"))) - for name in ["mnist", "fashionmnist", "kmnist"] - } -) - - -@register_mock( - configs=combinations_grid( - split=("train", "test"), - image_set=("Balanced", "By_Merge", "By_Class", "Letters", "Digits", "MNIST"), - ) -) -def emnist(root, config): - num_samples_map = {} - file_names = set() - for split, image_set in itertools.product( - ("train", "test"), - ("Balanced", "By_Merge", "By_Class", "Letters", "Digits", "MNIST"), - ): - prefix = f"emnist-{image_set.replace('_', '').lower()}-{split}" - images_file = f"{prefix}-images-idx3-ubyte.gz" - labels_file = f"{prefix}-labels-idx1-ubyte.gz" - file_names.update({images_file, labels_file}) - num_samples_map[(split, image_set)] = MNISTMockData.generate( - root, - # The image sets that merge some lower case letters in their respective upper case variant, still use dense - # labels in the data files. Thus, num_categories != len(categories) there. - num_categories=47 if config["image_set"] in ("Balanced", "By_Merge") else 62, - images_file=images_file, - labels_file=labels_file, - ) - - make_zip(root, "emnist-gzip.zip", *file_names) - - return num_samples_map[(config["split"], config["image_set"])] - - -@register_mock(configs=combinations_grid(split=("train", "test", "test10k", "test50k", "nist"))) -def qmnist(root, config): - num_categories = 10 - if config["split"] == "train": - num_samples = num_samples_gen = num_categories + 2 - prefix = "qmnist-train" - suffix = ".gz" - compressor = gzip.open - elif config["split"].startswith("test"): - # The split 'test50k' is defined as the last 50k images beginning at index 10000. Thus, we need to create - # more than 10000 images for the dataset to not be empty. - num_samples_gen = 10001 - num_samples = { - "test": num_samples_gen, - "test10k": min(num_samples_gen, 10_000), - "test50k": num_samples_gen - 10_000, - }[config["split"]] - prefix = "qmnist-test" - suffix = ".gz" - compressor = gzip.open - else: # config["split"] == "nist" - num_samples = num_samples_gen = num_categories + 3 - prefix = "xnist" - suffix = ".xz" - compressor = lzma.open - - MNISTMockData.generate( - root, - num_categories=num_categories, - num_samples=num_samples_gen, - images_file=f"{prefix}-images-idx3-ubyte{suffix}", - labels_file=f"{prefix}-labels-idx2-int{suffix}", - label_size=(8,), - label_dtype=torch.int32, - compressor=compressor, - ) - return num_samples - - -class CIFARMockData: - NUM_PIXELS = 32 * 32 * 3 - - @classmethod - def _create_batch_file(cls, root, name, *, num_categories, labels_key, num_samples=1): - content = { - "data": make_tensor((num_samples, cls.NUM_PIXELS), dtype=torch.uint8).numpy(), - labels_key: torch.randint(0, num_categories, size=(num_samples,)).tolist(), - } - with open(pathlib.Path(root) / name, "wb") as fh: - pickle.dump(content, fh) - - @classmethod - def generate( - cls, - root, - name, - *, - folder, - train_files, - test_files, - num_categories, - labels_key, - ): - folder = root / folder - folder.mkdir() - files = (*train_files, *test_files) - for file in files: - cls._create_batch_file( - folder, - file, - num_categories=num_categories, - labels_key=labels_key, - ) - - make_tar(root, name, folder, compression="gz") - - -@register_mock(configs=combinations_grid(split=("train", "test"))) -def cifar10(root, config): - train_files = [f"data_batch_{idx}" for idx in range(1, 6)] - test_files = ["test_batch"] - - CIFARMockData.generate( - root=root, - name="cifar-10-python.tar.gz", - folder=pathlib.Path("cifar-10-batches-py"), - train_files=train_files, - test_files=test_files, - num_categories=10, - labels_key="labels", - ) - - return len(train_files if config["split"] == "train" else test_files) - - -@register_mock(configs=combinations_grid(split=("train", "test"))) -def cifar100(root, config): - train_files = ["train"] - test_files = ["test"] - - CIFARMockData.generate( - root=root, - name="cifar-100-python.tar.gz", - folder=pathlib.Path("cifar-100-python"), - train_files=train_files, - test_files=test_files, - num_categories=100, - labels_key="fine_labels", - ) - - return len(train_files if config["split"] == "train" else test_files) - - -@register_mock(configs=[dict()]) -def caltech101(root, config): - def create_ann_file(root, name): - import scipy.io - - box_coord = make_tensor((1, 4), dtype=torch.int32, low=0).numpy().astype(np.uint16) - obj_contour = make_tensor((2, int(torch.randint(3, 6, size=()))), dtype=torch.float64, low=0).numpy() - - scipy.io.savemat(str(pathlib.Path(root) / name), dict(box_coord=box_coord, obj_contour=obj_contour)) - - def create_ann_folder(root, name, file_name_fn, num_examples): - root = pathlib.Path(root) / name - root.mkdir(parents=True) - - for idx in range(num_examples): - create_ann_file(root, file_name_fn(idx)) - - images_root = root / "101_ObjectCategories" - anns_root = root / "Annotations" - - image_category_map = { - "Faces": "Faces_2", - "Faces_easy": "Faces_3", - "Motorbikes": "Motorbikes_16", - "airplanes": "Airplanes_Side_2", - } - - categories = ["Faces", "Faces_easy", "Motorbikes", "airplanes", "yin_yang"] - - num_images_per_category = 2 - for category in categories: - create_image_folder( - root=images_root, - name=category, - file_name_fn=lambda idx: f"image_{idx + 1:04d}.jpg", - num_examples=num_images_per_category, - ) - create_ann_folder( - root=anns_root, - name=image_category_map.get(category, category), - file_name_fn=lambda idx: f"annotation_{idx + 1:04d}.mat", - num_examples=num_images_per_category, - ) - - (images_root / "BACKGROUND_Goodle").mkdir() - make_tar(root, f"{images_root.name}.tar.gz", images_root, compression="gz") - - make_tar(root, f"{anns_root.name}.tar", anns_root) - - return num_images_per_category * len(categories) - - -@register_mock(configs=[dict()]) -def caltech256(root, config): - dir = root / "256_ObjectCategories" - num_images_per_category = 2 - - categories = [ - (1, "ak47"), - (127, "laptop-101"), - (198, "spider"), - (257, "clutter"), - ] - - for category_idx, category in categories: - files = create_image_folder( - dir, - name=f"{category_idx:03d}.{category}", - file_name_fn=lambda image_idx: f"{category_idx:03d}_{image_idx + 1:04d}.jpg", - num_examples=num_images_per_category, - ) - if category == "spider": - open(files[0].parent / "RENAME2", "w").close() - - make_tar(root, f"{dir.name}.tar", dir) - - return num_images_per_category * len(categories) - - -@register_mock(configs=combinations_grid(split=("train", "val", "test"))) -def imagenet(root, config): - from scipy.io import savemat - - info = datasets.info("imagenet") - - if config["split"] == "train": - num_samples = len(info["wnids"]) - archive_name = "ILSVRC2012_img_train.tar" - - files = [] - for wnid in info["wnids"]: - create_image_folder( - root=root, - name=wnid, - file_name_fn=lambda image_idx: f"{wnid}_{image_idx:04d}.JPEG", - num_examples=1, - ) - files.append(make_tar(root, f"{wnid}.tar")) - elif config["split"] == "val": - num_samples = 3 - archive_name = "ILSVRC2012_img_val.tar" - files = [create_image_file(root, f"ILSVRC2012_val_{idx + 1:08d}.JPEG") for idx in range(num_samples)] - - devkit_root = root / "ILSVRC2012_devkit_t12" - data_root = devkit_root / "data" - data_root.mkdir(parents=True) - - with open(data_root / "ILSVRC2012_validation_ground_truth.txt", "w") as file: - for label in torch.randint(0, len(info["wnids"]), (num_samples,)).tolist(): - file.write(f"{label}\n") - - num_children = 0 - synsets = [ - (idx, wnid, category, "", num_children, [], 0, 0) - for idx, (category, wnid) in enumerate(zip(info["categories"], info["wnids"]), 1) - ] - num_children = 1 - synsets.extend((0, "", "", "", num_children, [], 0, 0) for _ in range(5)) - synsets = np.array( - synsets, - dtype=np.dtype( - [ - ("ILSVRC2012_ID", "O"), - ("WNID", "O"), - ("words", "O"), - ("gloss", "O"), - ("num_children", "O"), - ("children", "O"), - ("wordnet_height", "O"), - ("num_train_images", "O"), - ] - ), - ) - savemat(data_root / "meta.mat", dict(synsets=synsets)) - - make_tar(root, devkit_root.with_suffix(".tar.gz").name, compression="gz") - else: # config["split"] == "test" - num_samples = 5 - archive_name = "ILSVRC2012_img_test_v10102019.tar" - files = [create_image_file(root, f"ILSVRC2012_test_{idx + 1:08d}.JPEG") for idx in range(num_samples)] - - make_tar(root, archive_name, *files) - - return num_samples - - -class CocoMockData: - @classmethod - def _make_annotations_json( - cls, - root, - name, - *, - images_meta, - fn, - ): - num_anns_per_image = torch.randint(1, 5, (len(images_meta),)) - num_anns_total = int(num_anns_per_image.sum()) - ann_ids_iter = iter(torch.arange(num_anns_total)[torch.randperm(num_anns_total)]) - - anns_meta = [] - for image_meta, num_anns in zip(images_meta, num_anns_per_image): - for _ in range(num_anns): - ann_id = int(next(ann_ids_iter)) - anns_meta.append(dict(fn(ann_id, image_meta), id=ann_id, image_id=image_meta["id"])) - anns_meta.sort(key=lambda ann: ann["id"]) - - with open(root / name, "w") as file: - json.dump(dict(images=images_meta, annotations=anns_meta), file) - - return num_anns_per_image - - @staticmethod - def _make_instances_data(ann_id, image_meta): - def make_rle_segmentation(): - height, width = image_meta["height"], image_meta["width"] - numel = height * width - counts = [] - while sum(counts) <= numel: - counts.append(int(torch.randint(5, 8, ()))) - if sum(counts) > numel: - counts[-1] -= sum(counts) - numel - return dict(counts=counts, size=[height, width]) - - return dict( - segmentation=make_rle_segmentation(), - bbox=make_tensor((4,), dtype=torch.float32, low=0).tolist(), - iscrowd=True, - area=float(make_scalar(dtype=torch.float32)), - category_id=int(make_scalar(dtype=torch.int64)), - ) - - @staticmethod - def _make_captions_data(ann_id, image_meta): - return dict(caption=f"Caption {ann_id} describing image {image_meta['id']}.") - - @classmethod - def _make_annotations(cls, root, name, *, images_meta): - num_anns_per_image = torch.zeros((len(images_meta),), dtype=torch.int64) - for annotations, fn in ( - ("instances", cls._make_instances_data), - ("captions", cls._make_captions_data), - ): - num_anns_per_image += cls._make_annotations_json( - root, f"{annotations}_{name}.json", images_meta=images_meta, fn=fn - ) - - return int(num_anns_per_image.sum()) - - @classmethod - def generate( - cls, - root, - *, - split, - year, - num_samples, - ): - annotations_dir = root / "annotations" - annotations_dir.mkdir() - - for split_ in ("train", "val"): - config_name = f"{split_}{year}" - - images_meta = [ - dict( - file_name=f"{idx:012d}.jpg", - id=idx, - width=width, - height=height, - ) - for idx, (height, width) in enumerate( - torch.randint(3, 11, size=(num_samples, 2), dtype=torch.int).tolist() - ) - ] - - if split_ == split: - create_image_folder( - root, - config_name, - file_name_fn=lambda idx: images_meta[idx]["file_name"], - num_examples=num_samples, - size=lambda idx: (3, images_meta[idx]["height"], images_meta[idx]["width"]), - ) - make_zip(root, f"{config_name}.zip") - - cls._make_annotations( - annotations_dir, - config_name, - images_meta=images_meta, - ) - - make_zip(root, f"annotations_trainval{year}.zip", annotations_dir) - - return num_samples - - -@register_mock( - configs=combinations_grid( - split=("train", "val"), - year=("2017", "2014"), - annotations=("instances", "captions", None), - ) -) -def coco(root, config): - return CocoMockData.generate(root, split=config["split"], year=config["year"], num_samples=5) - - -class SBDMockData: - _NUM_CATEGORIES = 20 - - @classmethod - def _make_split_files(cls, root_map, *, split): - splits_and_idcs = [ - ("train", [0, 1, 2]), - ("val", [3]), - ] - if split == "train_noval": - splits_and_idcs.append(("train_noval", [0, 2])) - - ids_map = {split: [f"2008_{idx:06d}" for idx in idcs] for split, idcs in splits_and_idcs} - - for split, ids in ids_map.items(): - with open(root_map[split] / f"{split}.txt", "w") as fh: - fh.writelines(f"{id}\n" for id in ids) - - return sorted(set(itertools.chain(*ids_map.values()))), {split: len(ids) for split, ids in ids_map.items()} - - @classmethod - def _make_anns_folder(cls, root, name, ids): - from scipy.io import savemat - - anns_folder = root / name - anns_folder.mkdir() - - sizes = torch.randint(1, 9, size=(len(ids), 2)).tolist() - for id, size in zip(ids, sizes): - savemat( - anns_folder / f"{id}.mat", - { - "GTcls": { - "Boundaries": cls._make_boundaries(size), - "Segmentation": cls._make_segmentation(size), - } - }, - ) - return sizes - - @classmethod - def _make_boundaries(cls, size): - from scipy.sparse import csc_matrix - - return [ - [csc_matrix(torch.randint(0, 2, size=size, dtype=torch.uint8).numpy())] for _ in range(cls._NUM_CATEGORIES) - ] - - @classmethod - def _make_segmentation(cls, size): - return torch.randint(0, cls._NUM_CATEGORIES + 1, size=size, dtype=torch.uint8).numpy() - - @classmethod - def generate(cls, root, *, split): - archive_folder = root / "benchmark_RELEASE" - dataset_folder = archive_folder / "dataset" - dataset_folder.mkdir(parents=True, exist_ok=True) - - ids, num_samples_map = cls._make_split_files( - defaultdict(lambda: dataset_folder, {"train_noval": root}), split=split - ) - sizes = cls._make_anns_folder(dataset_folder, "cls", ids) - create_image_folder( - dataset_folder, "img", lambda idx: f"{ids[idx]}.jpg", num_examples=len(ids), size=lambda idx: sizes[idx] - ) - - make_tar(root, "benchmark.tgz", archive_folder, compression="gz") - - return num_samples_map[split] - - -@register_mock(configs=combinations_grid(split=("train", "val", "train_noval"))) -def sbd(root, config): - return SBDMockData.generate(root, split=config["split"]) - - -@register_mock(configs=[dict()]) -def semeion(root, config): - num_samples = 3 - num_categories = 10 - - images = torch.rand(num_samples, 256) - labels = one_hot(torch.randint(num_categories, size=(num_samples,)), num_classes=num_categories) - with open(root / "semeion.data", "w") as fh: - for image, one_hot_label in zip(images, labels): - image_columns = " ".join([f"{pixel.item():.4f}" for pixel in image]) - labels_columns = " ".join([str(label.item()) for label in one_hot_label]) - fh.write(f"{image_columns} {labels_columns} \n") - - return num_samples - - -class VOCMockData: - _TRAIN_VAL_FILE_NAMES = { - "2007": "VOCtrainval_06-Nov-2007.tar", - "2008": "VOCtrainval_14-Jul-2008.tar", - "2009": "VOCtrainval_11-May-2009.tar", - "2010": "VOCtrainval_03-May-2010.tar", - "2011": "VOCtrainval_25-May-2011.tar", - "2012": "VOCtrainval_11-May-2012.tar", - } - _TEST_FILE_NAMES = { - "2007": "VOCtest_06-Nov-2007.tar", - } - - @classmethod - def _make_split_files(cls, root, *, year, trainval): - split_folder = root / "ImageSets" - - if trainval: - idcs_map = { - "train": [0, 1, 2], - "val": [3, 4], - } - idcs_map["trainval"] = [*idcs_map["train"], *idcs_map["val"]] - else: - idcs_map = { - "test": [5], - } - ids_map = {split: [f"{year}_{idx:06d}" for idx in idcs] for split, idcs in idcs_map.items()} - - for task_sub_folder in ("Main", "Segmentation"): - task_folder = split_folder / task_sub_folder - task_folder.mkdir(parents=True, exist_ok=True) - for split, ids in ids_map.items(): - with open(task_folder / f"{split}.txt", "w") as fh: - fh.writelines(f"{id}\n" for id in ids) - - return sorted(set(itertools.chain(*ids_map.values()))), {split: len(ids) for split, ids in ids_map.items()} - - @classmethod - def _make_detection_anns_folder(cls, root, name, *, file_name_fn, num_examples): - folder = root / name - folder.mkdir(parents=True, exist_ok=True) - - for idx in range(num_examples): - cls._make_detection_ann_file(folder, file_name_fn(idx)) - - @classmethod - def _make_detection_ann_file(cls, root, name): - def add_child(parent, name, text=None): - child = ET.SubElement(parent, name) - child.text = str(text) - return child - - def add_name(obj, name="dog"): - add_child(obj, "name", name) - - def add_size(obj): - obj = add_child(obj, "size") - size = {"width": 0, "height": 0, "depth": 3} - for name, text in size.items(): - add_child(obj, name, text) - - def add_bndbox(obj): - obj = add_child(obj, "bndbox") - bndbox = {"xmin": 1, "xmax": 2, "ymin": 3, "ymax": 4} - for name, text in bndbox.items(): - add_child(obj, name, text) - - annotation = ET.Element("annotation") - add_size(annotation) - obj = add_child(annotation, "object") - add_name(obj) - add_bndbox(obj) - - with open(root / name, "wb") as fh: - fh.write(ET.tostring(annotation)) - - @classmethod - def generate(cls, root, *, year, trainval): - archive_folder = root - if year == "2011": - archive_folder = root / "TrainVal" - data_folder = archive_folder / "VOCdevkit" - else: - archive_folder = data_folder = root / "VOCdevkit" - data_folder = data_folder / f"VOC{year}" - data_folder.mkdir(parents=True, exist_ok=True) - - ids, num_samples_map = cls._make_split_files(data_folder, year=year, trainval=trainval) - for make_folder_fn, name, suffix in [ - (create_image_folder, "JPEGImages", ".jpg"), - (create_image_folder, "SegmentationClass", ".png"), - (cls._make_detection_anns_folder, "Annotations", ".xml"), - ]: - make_folder_fn(data_folder, name, file_name_fn=lambda idx: ids[idx] + suffix, num_examples=len(ids)) - make_tar(root, (cls._TRAIN_VAL_FILE_NAMES if trainval else cls._TEST_FILE_NAMES)[year], archive_folder) - - return num_samples_map - - -@register_mock( - configs=[ - *combinations_grid( - split=("train", "val", "trainval"), - year=("2007", "2008", "2009", "2010", "2011", "2012"), - task=("detection", "segmentation"), - ), - *combinations_grid( - split=("test",), - year=("2007",), - task=("detection", "segmentation"), - ), - ], -) -def voc(root, config): - trainval = config["split"] != "test" - return VOCMockData.generate(root, year=config["year"], trainval=trainval)[config["split"]] - - -class CelebAMockData: - @classmethod - def _make_ann_file(cls, root, name, data, *, field_names=None): - with open(root / name, "w") as file: - if field_names: - file.write(f"{len(data)}\r\n") - file.write(" ".join(field_names) + "\r\n") - file.writelines(" ".join(str(item) for item in row) + "\r\n" for row in data) - - _SPLIT_TO_IDX = { - "train": 0, - "val": 1, - "test": 2, - } - - @classmethod - def _make_split_file(cls, root): - num_samples_map = {"train": 4, "val": 3, "test": 2} - - data = [ - (f"{idx:06d}.jpg", cls._SPLIT_TO_IDX[split]) - for split, num_samples in num_samples_map.items() - for idx in range(num_samples) - ] - cls._make_ann_file(root, "list_eval_partition.txt", data) - - image_file_names, _ = zip(*data) - return image_file_names, num_samples_map - - @classmethod - def _make_identity_file(cls, root, image_file_names): - cls._make_ann_file( - root, "identity_CelebA.txt", [(name, int(make_scalar(low=1, dtype=torch.int))) for name in image_file_names] - ) - - @classmethod - def _make_attributes_file(cls, root, image_file_names): - field_names = ("5_o_Clock_Shadow", "Young") - data = [ - [name, *[" 1" if attr else "-1" for attr in make_tensor((len(field_names),), dtype=torch.bool)]] - for name in image_file_names - ] - cls._make_ann_file(root, "list_attr_celeba.txt", data, field_names=(*field_names, "")) - - @classmethod - def _make_bounding_boxes_file(cls, root, image_file_names): - field_names = ("image_id", "x_1", "y_1", "width", "height") - data = [ - [f"{name} ", *[f"{coord:3d}" for coord in make_tensor((4,), low=0, dtype=torch.int).tolist()]] - for name in image_file_names - ] - cls._make_ann_file(root, "list_bbox_celeba.txt", data, field_names=field_names) - - @classmethod - def _make_landmarks_file(cls, root, image_file_names): - field_names = ("lefteye_x", "lefteye_y", "rightmouth_x", "rightmouth_y") - data = [ - [ - name, - *[ - f"{coord:4d}" if idx else coord - for idx, coord in enumerate(make_tensor((len(field_names),), low=0, dtype=torch.int).tolist()) - ], - ] - for name in image_file_names - ] - cls._make_ann_file(root, "list_landmarks_align_celeba.txt", data, field_names=field_names) - - @classmethod - def generate(cls, root): - image_file_names, num_samples_map = cls._make_split_file(root) - - image_files = create_image_folder( - root, "img_align_celeba", file_name_fn=lambda idx: image_file_names[idx], num_examples=len(image_file_names) - ) - make_zip(root, image_files[0].parent.with_suffix(".zip").name) - - for make_ann_file_fn in ( - cls._make_identity_file, - cls._make_attributes_file, - cls._make_bounding_boxes_file, - cls._make_landmarks_file, - ): - make_ann_file_fn(root, image_file_names) - - return num_samples_map - - -@register_mock(configs=combinations_grid(split=("train", "val", "test"))) -def celeba(root, config): - return CelebAMockData.generate(root)[config["split"]] - - -@register_mock(configs=combinations_grid(split=("train", "val", "test"))) -def country211(root, config): - split_folder = pathlib.Path(root, "country211", "valid" if config["split"] == "val" else config["split"]) - split_folder.mkdir(parents=True, exist_ok=True) - - num_examples = { - "train": 3, - "val": 4, - "test": 5, - }[config["split"]] - - classes = ("AD", "BS", "GR") - for cls in classes: - create_image_folder( - split_folder, - name=cls, - file_name_fn=lambda idx: f"{idx}.jpg", - num_examples=num_examples, - ) - make_tar(root, f"{split_folder.parent.name}.tgz", split_folder.parent, compression="gz") - return num_examples * len(classes) - - -@register_mock(configs=combinations_grid(split=("train", "test"))) -def food101(root, config): - data_folder = root / "food-101" - - num_images_per_class = 3 - image_folder = data_folder / "images" - categories = ["apple_pie", "baby_back_ribs", "waffles"] - image_ids = [] - for category in categories: - image_files = create_image_folder( - image_folder, - category, - file_name_fn=lambda idx: f"{idx:04d}.jpg", - num_examples=num_images_per_class, - ) - image_ids.extend(path.relative_to(path.parents[1]).with_suffix("").as_posix() for path in image_files) - - meta_folder = data_folder / "meta" - meta_folder.mkdir() - - with open(meta_folder / "classes.txt", "w") as file: - for category in categories: - file.write(f"{category}\n") - - splits = ["train", "test"] - num_samples_map = {} - for offset, split in enumerate(splits): - image_ids_in_split = image_ids[offset :: len(splits)] - num_samples_map[split] = len(image_ids_in_split) - with open(meta_folder / f"{split}.txt", "w") as file: - for image_id in image_ids_in_split: - file.write(f"{image_id}\n") - - make_tar(root, f"{data_folder.name}.tar.gz", compression="gz") - - return num_samples_map[config["split"]] - - -@register_mock(configs=combinations_grid(split=("train", "val", "test"), fold=(1, 4, 10))) -def dtd(root, config): - data_folder = root / "dtd" - - num_images_per_class = 3 - image_folder = data_folder / "images" - categories = {"banded", "marbled", "zigzagged"} - image_ids_per_category = { - category: [ - str(path.relative_to(path.parents[1]).as_posix()) - for path in create_image_folder( - image_folder, - category, - file_name_fn=lambda idx: f"{category}_{idx:04d}.jpg", - num_examples=num_images_per_class, - ) - ] - for category in categories - } - - meta_folder = data_folder / "labels" - meta_folder.mkdir() - - with open(meta_folder / "labels_joint_anno.txt", "w") as file: - for cls, image_ids in image_ids_per_category.items(): - for image_id in image_ids: - joint_categories = random.choices( - list(categories - {cls}), k=int(torch.randint(len(categories) - 1, ())) - ) - file.write(" ".join([image_id, *sorted([cls, *joint_categories])]) + "\n") - - image_ids = list(itertools.chain(*image_ids_per_category.values())) - splits = ("train", "val", "test") - num_samples_map = {} - for fold in range(1, 11): - random.shuffle(image_ids) - for offset, split in enumerate(splits): - image_ids_in_config = image_ids[offset :: len(splits)] - with open(meta_folder / f"{split}{fold}.txt", "w") as file: - file.write("\n".join(image_ids_in_config) + "\n") - - num_samples_map[(split, fold)] = len(image_ids_in_config) - - make_tar(root, "dtd-r1.0.1.tar.gz", data_folder, compression="gz") - - return num_samples_map[config["split"], config["fold"]] - - -@register_mock(configs=combinations_grid(split=("train", "test"))) -def fer2013(root, config): - split = config["split"] - num_samples = 5 if split == "train" else 3 - - path = root / f"{split}.csv" - with open(path, "w", newline="") as file: - field_names = ["emotion"] if split == "train" else [] - field_names.append("pixels") - - file.write(",".join(field_names) + "\n") - - writer = csv.DictWriter(file, fieldnames=field_names, quotechar='"', quoting=csv.QUOTE_NONNUMERIC) - for _ in range(num_samples): - rowdict = { - "pixels": " ".join([str(int(pixel)) for pixel in torch.randint(256, (48 * 48,), dtype=torch.uint8)]) - } - if split == "train": - rowdict["emotion"] = int(torch.randint(7, ())) - writer.writerow(rowdict) - - make_zip(root, f"{path.name}.zip", path) - - return num_samples - - -@register_mock(configs=combinations_grid(split=("train", "test"))) -def gtsrb(root, config): - num_examples_per_class = 5 if config["split"] == "train" else 3 - classes = ("00000", "00042", "00012") - num_examples = num_examples_per_class * len(classes) - - csv_columns = ["Filename", "Width", "Height", "Roi.X1", "Roi.Y1", "Roi.X2", "Roi.Y2", "ClassId"] - - def _make_ann_file(path, num_examples, class_idx): - if class_idx == "random": - class_idx = torch.randint(1, len(classes) + 1, size=(1,)).item() - - with open(path, "w") as csv_file: - writer = csv.DictWriter(csv_file, fieldnames=csv_columns, delimiter=";") - writer.writeheader() - for image_idx in range(num_examples): - writer.writerow( - { - "Filename": f"{image_idx:05d}.ppm", - "Width": torch.randint(1, 100, size=()).item(), - "Height": torch.randint(1, 100, size=()).item(), - "Roi.X1": torch.randint(1, 100, size=()).item(), - "Roi.Y1": torch.randint(1, 100, size=()).item(), - "Roi.X2": torch.randint(1, 100, size=()).item(), - "Roi.Y2": torch.randint(1, 100, size=()).item(), - "ClassId": class_idx, - } - ) - - archive_folder = root / "GTSRB" - - if config["split"] == "train": - train_folder = archive_folder / "Training" - train_folder.mkdir(parents=True) - - for class_idx in classes: - create_image_folder( - train_folder, - name=class_idx, - file_name_fn=lambda image_idx: f"{class_idx}_{image_idx:05d}.ppm", - num_examples=num_examples_per_class, - ) - _make_ann_file( - path=train_folder / class_idx / f"GT-{class_idx}.csv", - num_examples=num_examples_per_class, - class_idx=int(class_idx), - ) - make_zip(root, "GTSRB-Training_fixed.zip", archive_folder) - else: - test_folder = archive_folder / "Final_Test" - test_folder.mkdir(parents=True) - - create_image_folder( - test_folder, - name="Images", - file_name_fn=lambda image_idx: f"{image_idx:05d}.ppm", - num_examples=num_examples, - ) - - make_zip(root, "GTSRB_Final_Test_Images.zip", archive_folder) - - _make_ann_file( - path=root / "GT-final_test.csv", - num_examples=num_examples, - class_idx="random", - ) - - make_zip(root, "GTSRB_Final_Test_GT.zip", "GT-final_test.csv") - - return num_examples - - -@register_mock(configs=combinations_grid(split=("train", "val", "test"))) -def clevr(root, config): - data_folder = root / "CLEVR_v1.0" - - num_samples_map = { - "train": 3, - "val": 2, - "test": 1, - } - - images_folder = data_folder / "images" - image_files = { - split: create_image_folder( - images_folder, - split, - file_name_fn=lambda idx: f"CLEVR_{split}_{idx:06d}.jpg", - num_examples=num_samples, - ) - for split, num_samples in num_samples_map.items() - } - - scenes_folder = data_folder / "scenes" - scenes_folder.mkdir() - for split in ["train", "val"]: - with open(scenes_folder / f"CLEVR_{split}_scenes.json", "w") as file: - json.dump( - { - "scenes": [ - { - "image_filename": image_file.name, - # We currently only return the number of objects in a scene. - # Thus, it is sufficient for now to only mock the number of elements. - "objects": [None] * int(torch.randint(1, 5, ())), - } - for image_file in image_files[split] - ] - }, - file, - ) - - make_zip(root, f"{data_folder.name}.zip", data_folder) - - return num_samples_map[config["split"]] - - -class OxfordIIITPetMockData: - @classmethod - def _meta_to_split_and_classification_ann(cls, meta, idx): - image_id = "_".join( - [ - *[(str.title if meta["species"] == "cat" else str.lower)(part) for part in meta["cls"].split()], - str(idx), - ] - ) - class_id = str(meta["label"] + 1) - species = "1" if meta["species"] == "cat" else "2" - breed_id = "-1" - return (image_id, class_id, species, breed_id) - - @classmethod - def generate(self, root): - classification_anns_meta = ( - dict(cls="Abyssinian", label=0, species="cat"), - dict(cls="Keeshond", label=18, species="dog"), - dict(cls="Yorkshire Terrier", label=36, species="dog"), - ) - split_and_classification_anns = [ - self._meta_to_split_and_classification_ann(meta, idx) - for meta, idx in itertools.product(classification_anns_meta, (1, 2, 10)) - ] - image_ids, *_ = zip(*split_and_classification_anns) - - image_files = create_image_folder( - root, "images", file_name_fn=lambda idx: f"{image_ids[idx]}.jpg", num_examples=len(image_ids) - ) - - anns_folder = root / "annotations" - anns_folder.mkdir() - random.shuffle(split_and_classification_anns) - splits = ("trainval", "test") - num_samples_map = {} - for offset, split in enumerate(splits): - split_and_classification_anns_in_split = split_and_classification_anns[offset :: len(splits)] - with open(anns_folder / f"{split}.txt", "w") as file: - writer = csv.writer(file, delimiter=" ") - for split_and_classification_ann in split_and_classification_anns_in_split: - writer.writerow(split_and_classification_ann) - - num_samples_map[split] = len(split_and_classification_anns_in_split) - - segmentation_files = create_image_folder( - anns_folder, "trimaps", file_name_fn=lambda idx: f"{image_ids[idx]}.png", num_examples=len(image_ids) - ) - - # The dataset has some rogue files - for path in image_files[:3]: - path.with_suffix(".mat").touch() - for path in segmentation_files: - path.with_name(f".{path.name}").touch() - - make_tar(root, "images.tar.gz", compression="gz") - make_tar(root, anns_folder.with_suffix(".tar.gz").name, compression="gz") - - return num_samples_map - - -@register_mock(name="oxford-iiit-pet", configs=combinations_grid(split=("trainval", "test"))) -def oxford_iiit_pet(root, config): - return OxfordIIITPetMockData.generate(root)[config["split"]] - - -class _CUB200MockData: - @classmethod - def _category_folder(cls, category, idx): - return f"{idx:03d}.{category}" - - @classmethod - def _file_stem(cls, category, idx): - return f"{category}_{idx:04d}" - - @classmethod - def _make_images(cls, images_folder): - image_files = [] - for category_idx, category in [ - (1, "Black_footed_Albatross"), - (100, "Brown_Pelican"), - (200, "Common_Yellowthroat"), - ]: - image_files.extend( - create_image_folder( - images_folder, - cls._category_folder(category, category_idx), - lambda image_idx: f"{cls._file_stem(category, image_idx)}.jpg", - num_examples=5, - ) - ) - - return image_files - - -class CUB2002011MockData(_CUB200MockData): - @classmethod - def _make_archive(cls, root): - archive_folder = root / "CUB_200_2011" - - images_folder = archive_folder / "images" - image_files = cls._make_images(images_folder) - image_ids = list(range(1, len(image_files) + 1)) - - with open(archive_folder / "images.txt", "w") as file: - file.write( - "\n".join( - f"{id} {path.relative_to(images_folder).as_posix()}" for id, path in zip(image_ids, image_files) - ) - ) - - split_ids = torch.randint(2, (len(image_ids),)).tolist() - counts = Counter(split_ids) - num_samples_map = {"train": counts[1], "test": counts[0]} - with open(archive_folder / "train_test_split.txt", "w") as file: - file.write("\n".join(f"{image_id} {split_id}" for image_id, split_id in zip(image_ids, split_ids))) - - with open(archive_folder / "bounding_boxes.txt", "w") as file: - file.write( - "\n".join( - " ".join( - str(item) - for item in [image_id, *make_tensor((4,), dtype=torch.int, low=0).to(torch.float).tolist()] - ) - for image_id in image_ids - ) - ) - - make_tar(root, archive_folder.with_suffix(".tgz").name, compression="gz") - - return image_files, num_samples_map - - @classmethod - def _make_segmentations(cls, root, image_files): - segmentations_folder = root / "segmentations" - for image_file in image_files: - folder = segmentations_folder.joinpath(image_file.relative_to(image_file.parents[1])) - folder.mkdir(exist_ok=True, parents=True) - create_image_file( - folder, - image_file.with_suffix(".png").name, - size=[1, *make_tensor((2,), low=3, dtype=torch.int).tolist()], - ) - - make_tar(root, segmentations_folder.with_suffix(".tgz").name, compression="gz") - - @classmethod - def generate(cls, root): - image_files, num_samples_map = cls._make_archive(root) - cls._make_segmentations(root, image_files) - return num_samples_map - - -class CUB2002010MockData(_CUB200MockData): - @classmethod - def _make_hidden_rouge_file(cls, *files): - for file in files: - (file.parent / f"._{file.name}").touch() - - @classmethod - def _make_splits(cls, root, image_files): - split_folder = root / "lists" - split_folder.mkdir() - random.shuffle(image_files) - splits = ("train", "test") - num_samples_map = {} - for offset, split in enumerate(splits): - image_files_in_split = image_files[offset :: len(splits)] - - split_file = split_folder / f"{split}.txt" - with open(split_file, "w") as file: - file.write( - "\n".join( - sorted( - str(image_file.relative_to(image_file.parents[1]).as_posix()) - for image_file in image_files_in_split - ) - ) - ) - - cls._make_hidden_rouge_file(split_file) - num_samples_map[split] = len(image_files_in_split) - - make_tar(root, split_folder.with_suffix(".tgz").name, compression="gz") - - return num_samples_map - - @classmethod - def _make_anns(cls, root, image_files): - from scipy.io import savemat - - anns_folder = root / "annotations-mat" - for image_file in image_files: - ann_file = anns_folder / image_file.with_suffix(".mat").relative_to(image_file.parents[1]) - ann_file.parent.mkdir(parents=True, exist_ok=True) - - savemat( - ann_file, - { - "seg": torch.randint( - 256, make_tensor((2,), low=3, dtype=torch.int).tolist(), dtype=torch.uint8 - ).numpy(), - "bbox": dict( - zip(("left", "top", "right", "bottom"), make_tensor((4,), dtype=torch.uint8).tolist()) - ), - }, - ) - - readme_file = anns_folder / "README.txt" - readme_file.touch() - cls._make_hidden_rouge_file(readme_file) - - make_tar(root, "annotations.tgz", anns_folder, compression="gz") - - @classmethod - def generate(cls, root): - images_folder = root / "images" - image_files = cls._make_images(images_folder) - cls._make_hidden_rouge_file(*image_files) - make_tar(root, images_folder.with_suffix(".tgz").name, compression="gz") - - num_samples_map = cls._make_splits(root, image_files) - cls._make_anns(root, image_files) - - return num_samples_map - - -@register_mock(configs=combinations_grid(split=("train", "test"), year=("2010", "2011"))) -def cub200(root, config): - num_samples_map = (CUB2002011MockData if config["year"] == "2011" else CUB2002010MockData).generate(root) - return num_samples_map[config["split"]] - - -@register_mock(configs=[dict()]) -def eurosat(root, config): - data_folder = root / "2750" - data_folder.mkdir(parents=True) - - num_examples_per_class = 3 - categories = ["AnnualCrop", "Forest"] - for category in categories: - create_image_folder( - root=data_folder, - name=category, - file_name_fn=lambda idx: f"{category}_{idx + 1}.jpg", - num_examples=num_examples_per_class, - ) - make_zip(root, "EuroSAT.zip", data_folder) - return len(categories) * num_examples_per_class - - -@register_mock(configs=combinations_grid(split=("train", "test", "extra"))) -def svhn(root, config): - import scipy.io as sio - - num_samples = { - "train": 2, - "test": 3, - "extra": 4, - }[config["split"]] - - sio.savemat( - root / f"{config['split']}_32x32.mat", - { - "X": np.random.randint(256, size=(32, 32, 3, num_samples), dtype=np.uint8), - "y": np.random.randint(10, size=(num_samples,), dtype=np.uint8), - }, - ) - return num_samples - - -@register_mock(configs=combinations_grid(split=("train", "val", "test"))) -def pcam(root, config): - import h5py - - num_images = {"train": 2, "test": 3, "val": 4}[config["split"]] - - split = "valid" if config["split"] == "val" else config["split"] - - images_io = io.BytesIO() - with h5py.File(images_io, "w") as f: - f["x"] = np.random.randint(0, 256, size=(num_images, 10, 10, 3), dtype=np.uint8) - - targets_io = io.BytesIO() - with h5py.File(targets_io, "w") as f: - f["y"] = np.random.randint(0, 2, size=(num_images, 1, 1, 1), dtype=np.uint8) - - # Create .gz compressed files - images_file = root / f"camelyonpatch_level_2_split_{split}_x.h5.gz" - targets_file = root / f"camelyonpatch_level_2_split_{split}_y.h5.gz" - for compressed_file_name, uncompressed_file_io in ((images_file, images_io), (targets_file, targets_io)): - compressed_data = gzip.compress(uncompressed_file_io.getbuffer()) - with open(compressed_file_name, "wb") as compressed_file: - compressed_file.write(compressed_data) - - return num_images - - -@register_mock(name="stanford-cars", configs=combinations_grid(split=("train", "test"))) -def stanford_cars(root, config): - import scipy.io as io - from numpy.core.records import fromarrays - - split = config["split"] - num_samples = {"train": 5, "test": 7}[split] - num_categories = 3 - - if split == "train": - images_folder_name = "cars_train" - devkit = root / "devkit" - devkit.mkdir() - annotations_mat_path = devkit / "cars_train_annos.mat" - else: - images_folder_name = "cars_test" - annotations_mat_path = root / "cars_test_annos_withlabels.mat" - - create_image_folder( - root=root, - name=images_folder_name, - file_name_fn=lambda image_index: f"{image_index:5d}.jpg", - num_examples=num_samples, - ) - - make_tar(root, f"cars_{split}.tgz", images_folder_name) - bbox = np.random.randint(1, 200, num_samples, dtype=np.uint8) - classes = np.random.randint(1, num_categories + 1, num_samples, dtype=np.uint8) - fnames = [f"{i:5d}.jpg" for i in range(num_samples)] - rec_array = fromarrays( - [bbox, bbox, bbox, bbox, classes, fnames], - names=["bbox_x1", "bbox_y1", "bbox_x2", "bbox_y2", "class", "fname"], - ) - - io.savemat(annotations_mat_path, {"annotations": rec_array}) - if split == "train": - make_tar(root, "car_devkit.tgz", devkit, compression="gz") - - return num_samples - - -@register_mock(configs=combinations_grid(split=("train", "test"))) -def usps(root, config): - num_samples = {"train": 15, "test": 7}[config["split"]] - - with bz2.open(root / f"usps{'.t' if not config['split'] == 'train' else ''}.bz2", "wb") as fh: - lines = [] - for _ in range(num_samples): - label = make_tensor(1, low=1, high=11, dtype=torch.int) - values = make_tensor(256, low=-1, high=1, dtype=torch.float) - lines.append( - " ".join([f"{int(label)}", *(f"{idx}:{float(value):.6f}" for idx, value in enumerate(values, 1))]) - ) - - fh.write("\n".join(lines).encode()) - - return num_samples diff --git a/test/test_prototype_datasets_builtin.py b/test/test_prototype_datasets_builtin.py deleted file mode 100644 index 5f8fc90debf..00000000000 --- a/test/test_prototype_datasets_builtin.py +++ /dev/null @@ -1,282 +0,0 @@ -import io -import pickle -from collections import deque -from pathlib import Path - -import pytest -import torch -import torchvision.transforms.v2 as transforms - -from builtin_dataset_mocks import DATASET_MOCKS, parametrize_dataset_mocks -from torch.testing._comparison import not_close_error_metas, ObjectPair, TensorLikePair - -# TODO: replace with torchdata.dataloader2.DataLoader2 as soon as it is stable-ish -from torch.utils.data import DataLoader - -# TODO: replace with torchdata equivalent as soon as it is available -from torch.utils.data.graph_settings import get_all_graph_pipes - -from torchdata.dataloader2.graph.utils import traverse_dps -from torchdata.datapipes.iter import ShardingFilter, Shuffler -from torchdata.datapipes.utils import StreamWrapper -from torchvision import tv_tensors -from torchvision._utils import sequence_to_str -from torchvision.prototype import datasets -from torchvision.prototype.datasets.utils import EncodedImage -from torchvision.prototype.datasets.utils._internal import INFINITE_BUFFER_SIZE -from torchvision.prototype.tv_tensors import Label -from torchvision.transforms.v2._utils import is_pure_tensor - - -def assert_samples_equal(*args, msg=None, **kwargs): - error_metas = not_close_error_metas( - *args, pair_types=(TensorLikePair, ObjectPair), rtol=0, atol=0, equal_nan=True, **kwargs - ) - if error_metas: - raise error_metas[0].to_error(msg) - - -def extract_datapipes(dp): - return get_all_graph_pipes(traverse_dps(dp)) - - -def consume(iterator): - # Copied from the official itertools recipes: https://docs.python.org/3/library/itertools.html#itertools-recipes - deque(iterator, maxlen=0) - - -def next_consume(iterator): - item = next(iterator) - consume(iterator) - return item - - -@pytest.fixture(autouse=True) -def test_home(mocker, tmp_path): - mocker.patch("torchvision.prototype.datasets._api.home", return_value=str(tmp_path)) - mocker.patch("torchvision.prototype.datasets.home", return_value=str(tmp_path)) - yield tmp_path - - -def test_coverage(): - untested_datasets = set(datasets.list_datasets()) - DATASET_MOCKS.keys() - if untested_datasets: - raise AssertionError( - f"The dataset(s) {sequence_to_str(sorted(untested_datasets), separate_last='and ')} " - f"are exposed through `torchvision.prototype.datasets.load()`, but are not tested. " - f"Please add mock data to `test/builtin_dataset_mocks.py`." - ) - - -@pytest.mark.filterwarnings("error") -class TestCommon: - @pytest.mark.parametrize("name", datasets.list_datasets()) - def test_info(self, name): - try: - info = datasets.info(name) - except ValueError: - raise AssertionError("No info available.") from None - - if not (isinstance(info, dict) and all(isinstance(key, str) for key in info.keys())): - raise AssertionError("Info should be a dictionary with string keys.") - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_smoke(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - if not isinstance(dataset, datasets.utils.Dataset): - raise AssertionError(f"Loading the dataset should return an Dataset, but got {type(dataset)} instead.") - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_sample(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - try: - sample = next_consume(iter(dataset)) - except StopIteration: - raise AssertionError("Unable to draw any sample.") from None - except Exception as error: - raise AssertionError("Drawing a sample raised the error above.") from error - - if not isinstance(sample, dict): - raise AssertionError(f"Samples should be dictionaries, but got {type(sample)} instead.") - - if not sample: - raise AssertionError("Sample dictionary is empty.") - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_num_samples(self, dataset_mock, config): - dataset, mock_info = dataset_mock.load(config) - - assert len(list(dataset)) == mock_info["num_samples"] - - @pytest.fixture - def log_session_streams(self): - debug_unclosed_streams = StreamWrapper.debug_unclosed_streams - try: - StreamWrapper.debug_unclosed_streams = True - yield - finally: - StreamWrapper.debug_unclosed_streams = debug_unclosed_streams - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_stream_closing(self, log_session_streams, dataset_mock, config): - def make_msg_and_close(head): - unclosed_streams = [] - for stream in list(StreamWrapper.session_streams.keys()): - unclosed_streams.append(repr(stream.file_obj)) - stream.close() - unclosed_streams = "\n".join(unclosed_streams) - return f"{head}\n\n{unclosed_streams}" - - if StreamWrapper.session_streams: - raise pytest.UsageError(make_msg_and_close("A previous test did not close the following streams:")) - - dataset, _ = dataset_mock.load(config) - - consume(iter(dataset)) - - if StreamWrapper.session_streams: - raise AssertionError(make_msg_and_close("The following streams were not closed after a full iteration:")) - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_no_unaccompanied_pure_tensors(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - sample = next_consume(iter(dataset)) - - pure_tensors = {key for key, value in sample.items() if is_pure_tensor(value)} - - if pure_tensors and not any( - isinstance(item, (tv_tensors.Image, tv_tensors.Video, EncodedImage)) for item in sample.values() - ): - raise AssertionError( - f"The values of key(s) " - f"{sequence_to_str(sorted(pure_tensors), separate_last='and ')} contained pure tensors, " - f"but didn't find any (encoded) image or video." - ) - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_transformable(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - dataset = dataset.map(transforms.Identity()) - - consume(iter(dataset)) - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_traversable(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - traverse_dps(dataset) - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_serializable(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - pickle.dumps(dataset) - - # This has to be a proper function, since lambda's or local functions - # cannot be pickled, but this is a requirement for the DataLoader with - # multiprocessing, i.e. num_workers > 0 - def _collate_fn(self, batch): - return batch - - @pytest.mark.parametrize("num_workers", [0, 1]) - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_data_loader(self, dataset_mock, config, num_workers): - dataset, _ = dataset_mock.load(config) - - dl = DataLoader( - dataset, - batch_size=2, - num_workers=num_workers, - collate_fn=self._collate_fn, - ) - - consume(dl) - - # TODO: we need to enforce not only that both a Shuffler and a ShardingFilter are part of the datapipe, but also - # that the Shuffler comes before the ShardingFilter. Early commits in https://github.com/pytorch/vision/pull/5680 - # contain a custom test for that, but we opted to wait for a potential solution / test from torchdata for now. - @parametrize_dataset_mocks(DATASET_MOCKS) - @pytest.mark.parametrize("annotation_dp_type", (Shuffler, ShardingFilter)) - def test_has_annotations(self, dataset_mock, config, annotation_dp_type): - dataset, _ = dataset_mock.load(config) - - if not any(isinstance(dp, annotation_dp_type) for dp in extract_datapipes(dataset)): - raise AssertionError(f"The dataset doesn't contain a {annotation_dp_type.__name__}() datapipe.") - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_save_load(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - sample = next_consume(iter(dataset)) - - with io.BytesIO() as buffer: - torch.save(sample, buffer) - buffer.seek(0) - assert_samples_equal(torch.load(buffer, weights_only=True), sample) - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_infinite_buffer_size(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - for dp in extract_datapipes(dataset): - if hasattr(dp, "buffer_size"): - # TODO: replace this with the proper sentinel as soon as https://github.com/pytorch/data/issues/335 is - # resolved - assert dp.buffer_size == INFINITE_BUFFER_SIZE - - @parametrize_dataset_mocks(DATASET_MOCKS) - def test_has_length(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - assert len(dataset) > 0 - - -@parametrize_dataset_mocks(DATASET_MOCKS["qmnist"]) -class TestQMNIST: - def test_extra_label(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - sample = next_consume(iter(dataset)) - for key, type in ( - ("nist_hsf_series", int), - ("nist_writer_id", int), - ("digit_index", int), - ("nist_label", int), - ("global_digit_index", int), - ("duplicate", bool), - ("unused", bool), - ): - assert key in sample and isinstance(sample[key], type) - - -@parametrize_dataset_mocks(DATASET_MOCKS["gtsrb"]) -class TestGTSRB: - def test_label_matches_path(self, dataset_mock, config): - # We read the labels from the csv files instead. But for the trainset, the labels are also part of the path. - # This test makes sure that they're both the same - if config["split"] != "train": - return - - dataset, _ = dataset_mock.load(config) - - for sample in dataset: - label_from_path = int(Path(sample["path"]).parent.name) - assert sample["label"] == label_from_path - - -@parametrize_dataset_mocks(DATASET_MOCKS["usps"]) -class TestUSPS: - def test_sample_content(self, dataset_mock, config): - dataset, _ = dataset_mock.load(config) - - for sample in dataset: - assert "image" in sample - assert "label" in sample - - assert isinstance(sample["image"], tv_tensors.Image) - assert isinstance(sample["label"], Label) - - assert sample["image"].shape == (1, 16, 16) diff --git a/test/test_prototype_datasets_utils.py b/test/test_prototype_datasets_utils.py deleted file mode 100644 index 2098ac736ac..00000000000 --- a/test/test_prototype_datasets_utils.py +++ /dev/null @@ -1,302 +0,0 @@ -import gzip -import pathlib -import sys - -import numpy as np -import pytest -import torch -from datasets_utils import make_fake_flo_file, make_tar -from torchdata.datapipes.iter import FileOpener, TarArchiveLoader -from torchvision.datasets._optical_flow import _read_flo as read_flo_ref -from torchvision.datasets.utils import _decompress -from torchvision.prototype.datasets.utils import Dataset, GDriveResource, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import fromfile, read_flo - - -@pytest.mark.filterwarnings("error:The given NumPy array is not writeable:UserWarning") -@pytest.mark.parametrize( - ("np_dtype", "torch_dtype", "byte_order"), - [ - (">f4", torch.float32, "big"), - ("i8", torch.int64, "big"), - ("|u1", torch.uint8, sys.byteorder), - ], -) -@pytest.mark.parametrize("count", (-1, 2)) -@pytest.mark.parametrize("mode", ("rb", "r+b")) -def test_fromfile(tmpdir, np_dtype, torch_dtype, byte_order, count, mode): - path = tmpdir / "data.bin" - rng = np.random.RandomState(0) - rng.randn(5 if count == -1 else count + 1).astype(np_dtype).tofile(path) - - for count_ in (-1, count // 2): - expected = torch.from_numpy(np.fromfile(path, dtype=np_dtype, count=count_).astype(np_dtype[1:])) - - with open(path, mode) as file: - actual = fromfile(file, dtype=torch_dtype, byte_order=byte_order, count=count_) - - torch.testing.assert_close(actual, expected) - - -def test_read_flo(tmpdir): - path = tmpdir / "test.flo" - make_fake_flo_file(3, 4, path) - - with open(path, "rb") as file: - actual = read_flo(file) - - expected = torch.from_numpy(read_flo_ref(path).astype("f4", copy=False)) - - torch.testing.assert_close(actual, expected) - - -class TestOnlineResource: - class DummyResource(OnlineResource): - def __init__(self, download_fn=None, **kwargs): - super().__init__(**kwargs) - self._download_fn = download_fn - - def _download(self, root): - if self._download_fn is None: - raise pytest.UsageError( - "`_download()` was called, but `DummyResource(...)` was constructed without `download_fn`." - ) - - return self._download_fn(self, root) - - def _make_file(self, root, *, content, name="file.txt"): - file = root / name - with open(file, "w") as fh: - fh.write(content) - - return file - - def _make_folder(self, root, *, name="folder"): - folder = root / name - subfolder = folder / "subfolder" - subfolder.mkdir(parents=True) - - files = {} - for idx, root in enumerate([folder, folder, subfolder]): - content = f"sentinel{idx}" - file = self._make_file(root, name=f"file{idx}.txt", content=content) - files[str(file)] = content - - return folder, files - - def _make_tar(self, root, *, name="archive.tar", remove=True): - folder, files = self._make_folder(root, name=name.split(".")[0]) - archive = make_tar(root, name, folder, remove=remove) - files = {str(archive / pathlib.Path(file).relative_to(root)): content for file, content in files.items()} - return archive, files - - def test_load_file(self, tmp_path): - content = "sentinel" - file = self._make_file(tmp_path, content=content) - - resource = self.DummyResource(file_name=file.name) - - dp = resource.load(tmp_path) - assert isinstance(dp, FileOpener) - - data = list(dp) - assert len(data) == 1 - - path, buffer = data[0] - assert path == str(file) - assert buffer.read().decode() == content - - def test_load_folder(self, tmp_path): - folder, files = self._make_folder(tmp_path) - - resource = self.DummyResource(file_name=folder.name) - - dp = resource.load(tmp_path) - assert isinstance(dp, FileOpener) - assert {path: buffer.read().decode() for path, buffer in dp} == files - - def test_load_archive(self, tmp_path): - archive, files = self._make_tar(tmp_path) - - resource = self.DummyResource(file_name=archive.name) - - dp = resource.load(tmp_path) - assert isinstance(dp, TarArchiveLoader) - assert {path: buffer.read().decode() for path, buffer in dp} == files - - def test_priority_decompressed_gt_raw(self, tmp_path): - # We don't need to actually compress here. Adding the suffix is sufficient - self._make_file(tmp_path, content="raw_sentinel", name="file.txt.gz") - file = self._make_file(tmp_path, content="decompressed_sentinel", name="file.txt") - - resource = self.DummyResource(file_name=file.name) - - dp = resource.load(tmp_path) - path, buffer = next(iter(dp)) - - assert path == str(file) - assert buffer.read().decode() == "decompressed_sentinel" - - def test_priority_extracted_gt_decompressed(self, tmp_path): - archive, _ = self._make_tar(tmp_path, remove=False) - - resource = self.DummyResource(file_name=archive.name) - - dp = resource.load(tmp_path) - # If the archive had been selected, this would be a `TarArchiveReader` - assert isinstance(dp, FileOpener) - - def test_download(self, tmp_path): - download_fn_was_called = False - - def download_fn(resource, root): - nonlocal download_fn_was_called - download_fn_was_called = True - - return self._make_file(root, content="_", name=resource.file_name) - - resource = self.DummyResource( - file_name="file.txt", - download_fn=download_fn, - ) - - resource.load(tmp_path) - - assert download_fn_was_called, "`download_fn()` was never called" - - # This tests the `"decompress"` literal as well as a custom callable - @pytest.mark.parametrize( - "preprocess", - [ - "decompress", - lambda path: _decompress(str(path), remove_finished=True), - ], - ) - def test_preprocess_decompress(self, tmp_path, preprocess): - file_name = "file.txt.gz" - content = "sentinel" - - def download_fn(resource, root): - file = root / resource.file_name - with gzip.open(file, "wb") as fh: - fh.write(content.encode()) - return file - - resource = self.DummyResource(file_name=file_name, preprocess=preprocess, download_fn=download_fn) - - dp = resource.load(tmp_path) - data = list(dp) - assert len(data) == 1 - - path, buffer = data[0] - assert path == str(tmp_path / file_name).replace(".gz", "") - assert buffer.read().decode() == content - - def test_preprocess_extract(self, tmp_path): - files = None - - def download_fn(resource, root): - nonlocal files - archive, files = self._make_tar(root, name=resource.file_name) - return archive - - resource = self.DummyResource(file_name="folder.tar", preprocess="extract", download_fn=download_fn) - - dp = resource.load(tmp_path) - assert files is not None, "`download_fn()` was never called" - assert isinstance(dp, FileOpener) - - actual = {path: buffer.read().decode() for path, buffer in dp} - expected = { - path.replace(resource.file_name, resource.file_name.split(".")[0]): content - for path, content in files.items() - } - assert actual == expected - - def test_preprocess_only_after_download(self, tmp_path): - file = self._make_file(tmp_path, content="_") - - def preprocess(path): - raise AssertionError("`preprocess` was called although the file was already present.") - - resource = self.DummyResource( - file_name=file.name, - preprocess=preprocess, - ) - - resource.load(tmp_path) - - -class TestHttpResource: - def test_resolve_to_http(self, mocker): - file_name = "data.tar" - original_url = f"http://downloads.pytorch.org/{file_name}" - - redirected_url = original_url.replace("http", "https") - - sha256_sentinel = "sha256_sentinel" - - def preprocess_sentinel(path): - return path - - original_resource = HttpResource( - original_url, - sha256=sha256_sentinel, - preprocess=preprocess_sentinel, - ) - - mocker.patch("torchvision.prototype.datasets.utils._resource._get_redirect_url", return_value=redirected_url) - redirected_resource = original_resource.resolve() - - assert isinstance(redirected_resource, HttpResource) - assert redirected_resource.url == redirected_url - assert redirected_resource.file_name == file_name - assert redirected_resource.sha256 == sha256_sentinel - assert redirected_resource._preprocess is preprocess_sentinel - - def test_resolve_to_gdrive(self, mocker): - file_name = "data.tar" - original_url = f"http://downloads.pytorch.org/{file_name}" - - id_sentinel = "id-sentinel" - redirected_url = f"https://drive.google.com/file/d/{id_sentinel}/view" - - sha256_sentinel = "sha256_sentinel" - - def preprocess_sentinel(path): - return path - - original_resource = HttpResource( - original_url, - sha256=sha256_sentinel, - preprocess=preprocess_sentinel, - ) - - mocker.patch("torchvision.prototype.datasets.utils._resource._get_redirect_url", return_value=redirected_url) - redirected_resource = original_resource.resolve() - - assert isinstance(redirected_resource, GDriveResource) - assert redirected_resource.id == id_sentinel - assert redirected_resource.file_name == file_name - assert redirected_resource.sha256 == sha256_sentinel - assert redirected_resource._preprocess is preprocess_sentinel - - -def test_missing_dependency_error(): - class DummyDataset(Dataset): - def __init__(self): - super().__init__(root="root", dependencies=("fake_dependency",)) - - def _resources(self): - pass - - def _datapipe(self, resource_dps): - pass - - def __len__(self): - pass - - with pytest.raises(ModuleNotFoundError, match="depends on the third-party package 'fake_dependency'"): - DummyDataset() diff --git a/test/test_prototype_models.py b/test/test_prototype_models.py deleted file mode 100644 index d32df68f1f4..00000000000 --- a/test/test_prototype_models.py +++ /dev/null @@ -1,84 +0,0 @@ -import pytest -import test_models as TM -import torch -from common_utils import cpu_and_cuda, set_rng_seed -from torchvision.prototype import models - - -@pytest.mark.parametrize("model_fn", (models.depth.stereo.raft_stereo_base,)) -@pytest.mark.parametrize("model_mode", ("standard", "scripted")) -@pytest.mark.parametrize("dev", cpu_and_cuda()) -def test_raft_stereo(model_fn, model_mode, dev): - # A simple test to make sure the model can do forward pass and jit scriptable - set_rng_seed(0) - - # Use corr_pyramid and corr_block with smaller num_levels and radius to prevent nan output - # get the idea from test_models.test_raft - corr_pyramid = models.depth.stereo.raft_stereo.CorrPyramid1d(num_levels=2) - corr_block = models.depth.stereo.raft_stereo.CorrBlock1d(num_levels=2, radius=2) - model = model_fn(corr_pyramid=corr_pyramid, corr_block=corr_block).eval().to(dev) - - if model_mode == "scripted": - model = torch.jit.script(model) - - img1 = torch.rand(1, 3, 64, 64).to(dev) - img2 = torch.rand(1, 3, 64, 64).to(dev) - num_iters = 3 - - preds = model(img1, img2, num_iters=num_iters) - depth_pred = preds[-1] - - assert len(preds) == num_iters, "Number of predictions should be the same as model.num_iters" - - assert depth_pred.shape == torch.Size( - [1, 1, 64, 64] - ), f"The output shape of depth_pred should be [1, 1, 64, 64] but instead it is {preds[0].shape}" - - # Test against expected file output - TM._assert_expected(depth_pred, name=model_fn.__name__, atol=1e-2, rtol=1e-2) - - -@pytest.mark.parametrize("model_fn", (models.depth.stereo.crestereo_base,)) -@pytest.mark.parametrize("model_mode", ("standard", "scripted")) -@pytest.mark.parametrize("dev", cpu_and_cuda()) -def test_crestereo(model_fn, model_mode, dev): - set_rng_seed(0) - - model = model_fn().eval().to(dev) - - if model_mode == "scripted": - model = torch.jit.script(model) - - img1 = torch.rand(1, 3, 64, 64).to(dev) - img2 = torch.rand(1, 3, 64, 64).to(dev) - iterations = 3 - - preds = model(img1, img2, flow_init=None, num_iters=iterations) - disparity_pred = preds[-1] - - # all the pyramid levels except the highest res make only half the number of iterations - expected_iterations = (iterations // 2) * (len(model.resolutions) - 1) - expected_iterations += iterations - assert ( - len(preds) == expected_iterations - ), "Number of predictions should be the number of iterations multiplied by the number of pyramid levels" - - assert disparity_pred.shape == torch.Size( - [1, 2, 64, 64] - ), f"Predicted disparity should have the same spatial shape as the input. Inputs shape {img1.shape[2:]}, Prediction shape {disparity_pred.shape[2:]}" - - assert all( - d.shape == torch.Size([1, 2, 64, 64]) for d in preds - ), "All predicted disparities are expected to have the same shape" - - # test a backward pass with a dummy loss as well - preds = torch.stack(preds, dim=0) - targets = torch.ones_like(preds, requires_grad=False) - loss = torch.nn.functional.mse_loss(preds, targets) - - try: - loss.backward() - except Exception as e: - assert False, f"Backward pass failed with an unexpected exception: {e.__class__.__name__} {e}" - - TM._assert_expected(disparity_pred, name=model_fn.__name__, atol=1e-2, rtol=1e-2) diff --git a/test/test_prototype_transforms.py b/test/test_prototype_transforms.py deleted file mode 100644 index 3f2e5015863..00000000000 --- a/test/test_prototype_transforms.py +++ /dev/null @@ -1,429 +0,0 @@ -import collections.abc -import re - -import PIL.Image -import pytest -import torch - -from common_utils import assert_equal, make_bounding_boxes, make_detection_masks, make_image, make_video - -from torchvision.prototype import transforms, tv_tensors -from torchvision.transforms.v2._utils import check_type, is_pure_tensor -from torchvision.transforms.v2.functional import clamp_bounding_boxes, InterpolationMode, pil_to_tensor, to_pil_image - -from torchvision.tv_tensors import BoundingBoxes, BoundingBoxFormat, Image, Mask, Video - - -def _parse_categories(categories): - if categories is None: - num_categories = int(torch.randint(1, 11, ())) - elif isinstance(categories, int): - num_categories = categories - categories = [f"category{idx}" for idx in range(num_categories)] - elif isinstance(categories, collections.abc.Sequence) and all(isinstance(category, str) for category in categories): - categories = list(categories) - num_categories = len(categories) - else: - raise pytest.UsageError( - f"`categories` can either be `None` (default), an integer, or a sequence of strings, " - f"but got '{categories}' instead." - ) - return categories, num_categories - - -def make_label(*, extra_dims=(), categories=10, dtype=torch.int64, device="cpu"): - categories, num_categories = _parse_categories(categories) - # The idiom `make_tensor(..., dtype=torch.int64).to(dtype)` is intentional to only get integer values, - # regardless of the requested dtype, e.g. 0 or 0.0 rather than 0 or 0.123 - data = torch.testing.make_tensor(extra_dims, low=0, high=num_categories, dtype=torch.int64, device=device).to(dtype) - return tv_tensors.Label(data, categories=categories) - - -class TestSimpleCopyPaste: - def create_fake_image(self, mocker, image_type): - if image_type == PIL.Image.Image: - return PIL.Image.new("RGB", (32, 32), 123) - return mocker.MagicMock(spec=image_type) - - def test__extract_image_targets_assertion(self, mocker): - transform = transforms.SimpleCopyPaste() - - flat_sample = [ - # images, batch size = 2 - self.create_fake_image(mocker, Image), - # labels, bboxes, masks - mocker.MagicMock(spec=tv_tensors.Label), - mocker.MagicMock(spec=BoundingBoxes), - mocker.MagicMock(spec=Mask), - # labels, bboxes, masks - mocker.MagicMock(spec=BoundingBoxes), - mocker.MagicMock(spec=Mask), - ] - - with pytest.raises(TypeError, match="requires input sample to contain equal sized list of Images"): - transform._extract_image_targets(flat_sample) - - @pytest.mark.parametrize("image_type", [Image, PIL.Image.Image, torch.Tensor]) - @pytest.mark.parametrize("label_type", [tv_tensors.Label, tv_tensors.OneHotLabel]) - def test__extract_image_targets(self, image_type, label_type, mocker): - transform = transforms.SimpleCopyPaste() - - flat_sample = [ - # images, batch size = 2 - self.create_fake_image(mocker, image_type), - self.create_fake_image(mocker, image_type), - # labels, bboxes, masks - mocker.MagicMock(spec=label_type), - mocker.MagicMock(spec=BoundingBoxes), - mocker.MagicMock(spec=Mask), - # labels, bboxes, masks - mocker.MagicMock(spec=label_type), - mocker.MagicMock(spec=BoundingBoxes), - mocker.MagicMock(spec=Mask), - ] - - images, targets = transform._extract_image_targets(flat_sample) - - assert len(images) == len(targets) == 2 - if image_type == PIL.Image.Image: - torch.testing.assert_close(images[0], pil_to_tensor(flat_sample[0])) - torch.testing.assert_close(images[1], pil_to_tensor(flat_sample[1])) - else: - assert images[0] == flat_sample[0] - assert images[1] == flat_sample[1] - - for target in targets: - for key, type_ in [ - ("boxes", BoundingBoxes), - ("masks", Mask), - ("labels", label_type), - ]: - assert key in target - assert isinstance(target[key], type_) - assert target[key] in flat_sample - - @pytest.mark.parametrize("label_type", [tv_tensors.Label, tv_tensors.OneHotLabel]) - def test__copy_paste(self, label_type): - image = 2 * torch.ones(3, 32, 32) - masks = torch.zeros(2, 32, 32) - masks[0, 3:9, 2:8] = 1 - masks[1, 20:30, 20:30] = 1 - labels = torch.tensor([1, 2]) - blending = True - resize_interpolation = InterpolationMode.BILINEAR - antialias = None - if label_type == tv_tensors.OneHotLabel: - labels = torch.nn.functional.one_hot(labels, num_classes=5) - target = { - "boxes": BoundingBoxes( - torch.tensor([[2.0, 3.0, 8.0, 9.0], [20.0, 20.0, 30.0, 30.0]]), format="XYXY", canvas_size=(32, 32) - ), - "masks": Mask(masks), - "labels": label_type(labels), - } - - paste_image = 10 * torch.ones(3, 32, 32) - paste_masks = torch.zeros(2, 32, 32) - paste_masks[0, 13:19, 12:18] = 1 - paste_masks[1, 15:19, 1:8] = 1 - paste_labels = torch.tensor([3, 4]) - if label_type == tv_tensors.OneHotLabel: - paste_labels = torch.nn.functional.one_hot(paste_labels, num_classes=5) - paste_target = { - "boxes": BoundingBoxes( - torch.tensor([[12.0, 13.0, 19.0, 18.0], [1.0, 15.0, 8.0, 19.0]]), format="XYXY", canvas_size=(32, 32) - ), - "masks": Mask(paste_masks), - "labels": label_type(paste_labels), - } - - transform = transforms.SimpleCopyPaste() - random_selection = torch.tensor([0, 1]) - output_image, output_target = transform._copy_paste( - image, target, paste_image, paste_target, random_selection, blending, resize_interpolation, antialias - ) - - assert output_image.unique().tolist() == [2, 10] - assert output_target["boxes"].shape == (4, 4) - torch.testing.assert_close(output_target["boxes"][:2, :], target["boxes"]) - torch.testing.assert_close(output_target["boxes"][2:, :], paste_target["boxes"]) - - expected_labels = torch.tensor([1, 2, 3, 4]) - if label_type == tv_tensors.OneHotLabel: - expected_labels = torch.nn.functional.one_hot(expected_labels, num_classes=5) - torch.testing.assert_close(output_target["labels"], label_type(expected_labels)) - - assert output_target["masks"].shape == (4, 32, 32) - torch.testing.assert_close(output_target["masks"][:2, :], target["masks"]) - torch.testing.assert_close(output_target["masks"][2:, :], paste_target["masks"]) - - -class TestFixedSizeCrop: - def test__get_params(self, mocker): - crop_size = (7, 7) - batch_shape = (10,) - canvas_size = (11, 5) - - transform = transforms.FixedSizeCrop(size=crop_size) - - flat_inputs = [ - make_image(size=canvas_size, color_space="RGB"), - make_bounding_boxes(format=BoundingBoxFormat.XYXY, canvas_size=canvas_size, num_boxes=batch_shape[0]), - ] - params = transform._get_params(flat_inputs) - - assert params["needs_crop"] - assert params["height"] <= crop_size[0] - assert params["width"] <= crop_size[1] - - assert ( - isinstance(params["is_valid"], torch.Tensor) - and params["is_valid"].dtype is torch.bool - and params["is_valid"].shape == batch_shape - ) - - assert params["needs_pad"] - assert any(pad > 0 for pad in params["padding"]) - - def test__transform_culling(self, mocker): - batch_size = 10 - canvas_size = (10, 10) - - is_valid = torch.randint(0, 2, (batch_size,), dtype=torch.bool) - mocker.patch( - "torchvision.prototype.transforms._geometry.FixedSizeCrop._get_params", - return_value=dict( - needs_crop=True, - top=0, - left=0, - height=canvas_size[0], - width=canvas_size[1], - is_valid=is_valid, - needs_pad=False, - ), - ) - - bounding_boxes = make_bounding_boxes( - format=BoundingBoxFormat.XYXY, canvas_size=canvas_size, num_boxes=batch_size - ) - masks = make_detection_masks(size=canvas_size, num_masks=batch_size) - labels = make_label(extra_dims=(batch_size,)) - - transform = transforms.FixedSizeCrop((-1, -1)) - mocker.patch("torchvision.prototype.transforms._geometry.has_any", return_value=True) - - output = transform( - dict( - bounding_boxes=bounding_boxes, - masks=masks, - labels=labels, - ) - ) - - assert_equal(output["bounding_boxes"], bounding_boxes[is_valid]) - assert_equal(output["masks"], masks[is_valid]) - assert_equal(output["labels"], labels[is_valid]) - - def test__transform_bounding_boxes_clamping(self, mocker): - batch_size = 3 - canvas_size = (10, 10) - - mocker.patch( - "torchvision.prototype.transforms._geometry.FixedSizeCrop._get_params", - return_value=dict( - needs_crop=True, - top=0, - left=0, - height=canvas_size[0], - width=canvas_size[1], - is_valid=torch.full((batch_size,), fill_value=True), - needs_pad=False, - ), - ) - - bounding_boxes = make_bounding_boxes( - format=BoundingBoxFormat.XYXY, canvas_size=canvas_size, num_boxes=batch_size - ) - mock = mocker.patch( - "torchvision.prototype.transforms._geometry.F.clamp_bounding_boxes", wraps=clamp_bounding_boxes - ) - - transform = transforms.FixedSizeCrop((-1, -1)) - mocker.patch("torchvision.prototype.transforms._geometry.has_any", return_value=True) - - transform(bounding_boxes) - - mock.assert_called_once() - - -class TestLabelToOneHot: - def test__transform(self): - categories = ["apple", "pear", "pineapple"] - labels = tv_tensors.Label(torch.tensor([0, 1, 2, 1]), categories=categories) - transform = transforms.LabelToOneHot() - ohe_labels = transform(labels) - assert isinstance(ohe_labels, tv_tensors.OneHotLabel) - assert ohe_labels.shape == (4, 3) - assert ohe_labels.categories == labels.categories == categories - - -class TestPermuteDimensions: - @pytest.mark.parametrize( - ("dims", "inverse_dims"), - [ - ( - {Image: (2, 1, 0), Video: None}, - {Image: (2, 1, 0), Video: None}, - ), - ( - {Image: (2, 1, 0), Video: (1, 2, 3, 0)}, - {Image: (2, 1, 0), Video: (3, 0, 1, 2)}, - ), - ], - ) - def test_call(self, dims, inverse_dims): - sample = dict( - image=make_image(), - bounding_boxes=make_bounding_boxes(format=BoundingBoxFormat.XYXY), - video=make_video(), - str="str", - int=0, - ) - - transform = transforms.PermuteDimensions(dims) - transformed_sample = transform(sample) - - for key, value in sample.items(): - value_type = type(value) - transformed_value = transformed_sample[key] - - if check_type(value, (Image, is_pure_tensor, Video)): - if transform.dims.get(value_type) is not None: - assert transformed_value.permute(inverse_dims[value_type]).equal(value) - assert type(transformed_value) == torch.Tensor - else: - assert transformed_value is value - - @pytest.mark.filterwarnings("error") - def test_plain_tensor_call(self): - tensor = torch.empty((2, 3, 4)) - transform = transforms.PermuteDimensions(dims=(1, 2, 0)) - - assert transform(tensor).shape == (3, 4, 2) - - @pytest.mark.parametrize("other_type", [Image, Video]) - def test_plain_tensor_warning(self, other_type): - with pytest.warns(UserWarning, match=re.escape("`torch.Tensor` will *not* be transformed")): - transforms.PermuteDimensions(dims={torch.Tensor: (0, 1), other_type: (1, 0)}) - - -class TestTransposeDimensions: - @pytest.mark.parametrize( - "dims", - [ - (-1, -2), - {Image: (1, 2), Video: None}, - ], - ) - def test_call(self, dims): - sample = dict( - image=make_image(), - bounding_boxes=make_bounding_boxes(format=BoundingBoxFormat.XYXY), - video=make_video(), - str="str", - int=0, - ) - - transform = transforms.TransposeDimensions(dims) - transformed_sample = transform(sample) - - for key, value in sample.items(): - value_type = type(value) - transformed_value = transformed_sample[key] - - transposed_dims = transform.dims.get(value_type) - if check_type(value, (Image, is_pure_tensor, Video)): - if transposed_dims is not None: - assert transformed_value.transpose(*transposed_dims).equal(value) - assert type(transformed_value) == torch.Tensor - else: - assert transformed_value is value - - @pytest.mark.filterwarnings("error") - def test_plain_tensor_call(self): - tensor = torch.empty((2, 3, 4)) - transform = transforms.TransposeDimensions(dims=(0, 2)) - - assert transform(tensor).shape == (4, 3, 2) - - @pytest.mark.parametrize("other_type", [Image, Video]) - def test_plain_tensor_warning(self, other_type): - with pytest.warns(UserWarning, match=re.escape("`torch.Tensor` will *not* be transformed")): - transforms.TransposeDimensions(dims={torch.Tensor: (0, 1), other_type: (1, 0)}) - - -import importlib.machinery -import importlib.util -from pathlib import Path - - -def import_transforms_from_references(reference): - HERE = Path(__file__).parent - PROJECT_ROOT = HERE.parent - - loader = importlib.machinery.SourceFileLoader( - "transforms", str(PROJECT_ROOT / "references" / reference / "transforms.py") - ) - spec = importlib.util.spec_from_loader("transforms", loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) - return module - - -det_transforms = import_transforms_from_references("detection") - - -def test_fixed_sized_crop_against_detection_reference(): - def make_tv_tensors(): - size = (600, 800) - num_objects = 22 - - pil_image = to_pil_image(make_image(size=size, color_space="RGB")) - target = { - "boxes": make_bounding_boxes(canvas_size=size, format="XYXY", num_boxes=num_objects, dtype=torch.float), - "labels": make_label(extra_dims=(num_objects,), categories=80), - "masks": make_detection_masks(size=size, num_masks=num_objects, dtype=torch.long), - } - - yield (pil_image, target) - - tensor_image = torch.Tensor(make_image(size=size, color_space="RGB")) - target = { - "boxes": make_bounding_boxes(canvas_size=size, format="XYXY", num_boxes=num_objects, dtype=torch.float), - "labels": make_label(extra_dims=(num_objects,), categories=80), - "masks": make_detection_masks(size=size, num_masks=num_objects, dtype=torch.long), - } - - yield (tensor_image, target) - - tv_tensor_image = make_image(size=size, color_space="RGB") - target = { - "boxes": make_bounding_boxes(canvas_size=size, format="XYXY", num_boxes=num_objects, dtype=torch.float), - "labels": make_label(extra_dims=(num_objects,), categories=80), - "masks": make_detection_masks(size=size, num_masks=num_objects, dtype=torch.long), - } - - yield (tv_tensor_image, target) - - t = transforms.FixedSizeCrop((1024, 1024), fill=0) - t_ref = det_transforms.FixedSizeCrop((1024, 1024), fill=0) - - for dp in make_tv_tensors(): - # We should use prototype transform first as reference transform performs inplace target update - torch.manual_seed(12) - output = t(dp) - - torch.manual_seed(12) - expected_output = t_ref(*dp) - - assert_equal(expected_output, output) diff --git a/torchvision/prototype/__init__.py b/torchvision/prototype/__init__.py deleted file mode 100644 index 0621c9bf756..00000000000 --- a/torchvision/prototype/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import models, transforms, tv_tensors, utils diff --git a/torchvision/prototype/datasets/README.md b/torchvision/prototype/datasets/README.md deleted file mode 100644 index 79b426caaf3..00000000000 --- a/torchvision/prototype/datasets/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Status of prototype datasets - -These prototype datasets are based on [torchdata](https://github.com/pytorch/data)'s datapipes. Torchdata -development [is -paused](https://github.com/pytorch/data/#torchdata-see-note-below-on-current-status) -as of July 2023, so we are not actively maintaining this module. There is no -estimated date for a stable release of these datasets. diff --git a/torchvision/prototype/datasets/__init__.py b/torchvision/prototype/datasets/__init__.py deleted file mode 100644 index 848d9135c2f..00000000000 --- a/torchvision/prototype/datasets/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -try: - import torchdata -except ModuleNotFoundError: - raise ModuleNotFoundError( - "`torchvision.prototype.datasets` depends on PyTorch's `torchdata` (https://github.com/pytorch/data). " - "You can install it with `pip install --pre torchdata --extra-index-url https://download.pytorch.org/whl/nightly/cpu" - ) from None - -from . import utils -from ._home import home - -# Load this last, since some parts depend on the above being loaded first -from ._api import list_datasets, info, load, register_info, register_dataset # usort: skip -from ._folder import from_data_folder, from_image_folder -from ._builtin import * diff --git a/torchvision/prototype/datasets/_api.py b/torchvision/prototype/datasets/_api.py deleted file mode 100644 index f6f06c60a21..00000000000 --- a/torchvision/prototype/datasets/_api.py +++ /dev/null @@ -1,65 +0,0 @@ -import pathlib -from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union - -from torchvision.prototype.datasets import home -from torchvision.prototype.datasets.utils import Dataset -from torchvision.prototype.utils._internal import add_suggestion - - -T = TypeVar("T") -D = TypeVar("D", bound=Type[Dataset]) - -BUILTIN_INFOS: Dict[str, Dict[str, Any]] = {} - - -def register_info(name: str) -> Callable[[Callable[[], Dict[str, Any]]], Callable[[], Dict[str, Any]]]: - def wrapper(fn: Callable[[], Dict[str, Any]]) -> Callable[[], Dict[str, Any]]: - BUILTIN_INFOS[name] = fn() - return fn - - return wrapper - - -BUILTIN_DATASETS = {} - - -def register_dataset(name: str) -> Callable[[D], D]: - def wrapper(dataset_cls: D) -> D: - BUILTIN_DATASETS[name] = dataset_cls - return dataset_cls - - return wrapper - - -def list_datasets() -> List[str]: - return sorted(BUILTIN_DATASETS.keys()) - - -def find(dct: Dict[str, T], name: str) -> T: - name = name.lower() - try: - return dct[name] - except KeyError as error: - raise ValueError( - add_suggestion( - f"Unknown dataset '{name}'.", - word=name, - possibilities=dct.keys(), - alternative_hint=lambda _: ( - "You can use torchvision.datasets.list_datasets() to get a list of all available datasets." - ), - ) - ) from error - - -def info(name: str) -> Dict[str, Any]: - return find(BUILTIN_INFOS, name) - - -def load(name: str, *, root: Optional[Union[str, pathlib.Path]] = None, **config: Any) -> Dataset: - dataset_cls = find(BUILTIN_DATASETS, name) - - if root is None: - root = pathlib.Path(home()) / name - - return dataset_cls(root, **config) diff --git a/torchvision/prototype/datasets/_builtin/README.md b/torchvision/prototype/datasets/_builtin/README.md deleted file mode 100644 index 3b33100eb81..00000000000 --- a/torchvision/prototype/datasets/_builtin/README.md +++ /dev/null @@ -1,340 +0,0 @@ -# How to add new built-in prototype datasets - -As the name implies, the datasets are still in a prototype state and thus subject to rapid change. This in turn means -that this document will also change a lot. - -If you hit a blocker while adding a dataset, please have a look at another similar dataset to see how it is implemented -there. If you can't resolve it yourself, feel free to send a draft PR in order for us to help you out. - -Finally, `from torchvision.prototype import datasets` is implied below. - -## Implementation - -Before we start with the actual implementation, you should create a module in `torchvision/prototype/datasets/_builtin` -that hints at the dataset you are going to add. For example `caltech.py` for `caltech101` and `caltech256`. In that -module create a class that inherits from `datasets.utils.Dataset` and overwrites four methods that will be discussed in -detail below: - -```python -import pathlib -from typing import Any, BinaryIO, Dict, List, Tuple, Union - -from torchdata.datapipes.iter import IterDataPipe -from torchvision.prototype.datasets.utils import Dataset, OnlineResource - -from .._api import register_dataset, register_info - -NAME = "my-dataset" - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict( - ... - ) - -@register_dataset(NAME) -class MyDataset(Dataset): - def __init__(self, root: Union[str, pathlib.Path], *, ..., skip_integrity_check: bool = False) -> None: - ... - super().__init__(root, skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - ... - - def _datapipe(self, resource_dps: List[IterDataPipe[Tuple[str, BinaryIO]]]) -> IterDataPipe[Dict[str, Any]]: - ... - - def __len__(self) -> int: - ... -``` - -In addition to the dataset, you also need to implement an `_info()` function that takes no arguments and returns a -dictionary of static information. The most common use case is to provide human-readable categories. -[See below](#how-do-i-handle-a-dataset-that-defines-many-categories) how to handle cases with many categories. - -Finally, both the dataset class and the info function need to be registered on the API with the respective decorators. -With that they are loadable through `datasets.load("my-dataset")` and `datasets.info("my-dataset")`, respectively. - -### `__init__(self, root, *, ..., skip_integrity_check = False)` - -Constructor of the dataset that will be called when the dataset is instantiated. In addition to the parameters of the -base class, it can take arbitrary keyword-only parameters with defaults. The checking of these parameters as well as -setting them as instance attributes has to happen before the call of `super().__init__(...)`, because that will invoke -the other methods, which possibly depend on the parameters. All instance attributes must be private, i.e. prefixed with -an underscore. - -If the implementation of the dataset depends on third-party packages, pass them as a collection of strings to the base -class constructor, e.g. `super().__init__(..., dependencies=("scipy",))`. Their availability will be automatically -checked if a user tries to load the dataset. Within the implementation of the dataset, import these packages lazily to -avoid missing dependencies at import time. - -### `_resources(self)` - -Returns `List[datasets.utils.OnlineResource]` of all the files that need to be present locally before the dataset can be -build. The download will happen automatically. - -Currently, the following `OnlineResource`'s are supported: - -- `HttpResource`: Used for files that are directly exposed through HTTP(s) and only requires the URL. -- `GDriveResource`: Used for files that are hosted on GDrive and requires the GDrive ID as well as the `file_name`. -- `ManualDownloadResource`: Used files are not publicly accessible and requires instructions how to download them - manually. If the file does not exist, an error will be raised with the supplied instructions. -- `KaggleDownloadResource`: Used for files that are available on Kaggle. This inherits from `ManualDownloadResource`. - -Although optional in general, all resources used in the built-in datasets should comprise -[SHA256](https://en.wikipedia.org/wiki/SHA-2) checksum for security. It will be automatically checked after the -download. You can compute the checksum with system utilities e.g `sha256-sum`, or this snippet: - -```python -import hashlib - -def sha256sum(path, chunk_size=1024 * 1024): - checksum = hashlib.sha256() - with open(path, "rb") as f: - while chunk := f.read(chunk_size): - checksum.update(chunk) - print(checksum.hexdigest()) -``` - -### `_datapipe(self, resource_dps)` - -This method is the heart of the dataset, where we transform the raw data into a usable form. A major difference compared -to the current stable datasets is that everything is performed through `IterDataPipe`'s. From the perspective of someone -that is working with them rather than on them, `IterDataPipe`'s behave just as generators, i.e. you can't do anything -with them besides iterating. - -Of course, there are some common building blocks that should suffice in 95% of the cases. The most used are: - -- `Mapper`: Apply a callable to every item in the datapipe. -- `Filter`: Keep only items that satisfy a condition. -- `Demultiplexer`: Split a datapipe into multiple ones. -- `IterKeyZipper`: Merge two datapipes into one. - -All of them can be imported `from torchdata.datapipes.iter`. In addition, use `functools.partial` in case a callable -needs extra arguments. If the provided `IterDataPipe`'s are not sufficient for the use case, it is also not complicated -to add one. See the MNIST or CelebA datasets for example. - -`_datapipe()` receives `resource_dps`, which is a list of datapipes that has a 1-to-1 correspondence with the return -value of `_resources()`. In case of archives with regular suffixes (`.tar`, `.zip`, ...), the datapipe will contain -tuples comprised of the path and the handle for every file in the archive. Otherwise, the datapipe will only contain one -of such tuples for the file specified by the resource. - -Since the datapipes are iterable in nature, some datapipes feature an in-memory buffer, e.g. `IterKeyZipper` and -`Grouper`. There are two issues with that: - -1. If not used carefully, this can easily overflow the host memory, since most datasets will not fit in completely. -2. This can lead to unnecessarily long warm-up times when data is buffered that is only needed at runtime. - -Thus, all buffered datapipes should be used as early as possible, e.g. zipping two datapipes of file handles rather than -trying to zip already loaded images. - -There are two special datapipes that are not used through their class, but through the functions `hint_shuffling` and -`hint_sharding`. As the name implies they only hint at a location in the datapipe graph where shuffling and sharding -should take place, but are no-ops by default. They can be imported from `torchvision.prototype.datasets.utils._internal` -and are required in each dataset. `hint_shuffling` has to be placed before `hint_sharding`. - -Finally, each item in the final datapipe should be a dictionary with `str` keys. There is no standardization of the -names (yet!). - -### `__len__` - -This returns an integer denoting the number of samples that can be drawn from the dataset. Please use -[underscores](https://peps.python.org/pep-0515/) after every three digits starting from the right to enhance the -readability. For example, `1_281_167` vs. `1281167`. - -If there are only two different numbers, a simple `if` / `else` is fine: - -```py -def __len__(self): - return 12_345 if self._split == "train" else 6_789 -``` - -If there are more options, using a dictionary usually is the most readable option: - -```py -def __len__(self): - return { - "train": 3, - "val": 2, - "test": 1, - }[self._split] -``` - -If the number of samples depends on more than one parameter, you can use tuples as dictionary keys: - -```py -def __len__(self): - return { - ("train", "bar"): 4, - ("train", "baz"): 3, - ("test", "bar"): 2, - ("test", "baz"): 1, - }[(self._split, self._foo)] -``` - -The length of the datapipe is only an annotation for subsequent processing of the datapipe and not needed during the -development process. Since it is an `@abstractmethod` you still have to implement it from the start. The canonical way -is to define a dummy method like - -```py -def __len__(self): - return 1 -``` - -and only fill it with the correct data if the implementation is otherwise finished. -[See below](#how-do-i-compute-the-number-of-samples) for a possible way to compute the number of samples. - -## Tests - -To test the dataset implementation, you usually don't need to add any tests, but need to provide a mock-up of the data. -This mock-up should resemble the original data as close as necessary, while containing only few examples. - -To do this, add a new function in [`test/builtin_dataset_mocks.py`](../../../../test/builtin_dataset_mocks.py) with the -same name as you have used in `@register_info` and `@register_dataset`. This function is called "mock data function". -Decorate it with `@register_mock(configs=[dict(...), ...])`. Each dictionary denotes one configuration that the dataset -will be loaded with, e.g. `datasets.load("my-dataset", **config)`. For the most common case of a product of all options, -you can use the `combinations_grid()` helper function, e.g. -`configs=combinations_grid(split=("train", "test"), foo=("bar", "baz"))`. - -In case the name of the dataset includes hyphens `-`, replace them with underscores `_` in the function name and pass -the `name` parameter to `@register_mock` - -```py -# this is defined in torchvision/prototype/datasets/_builtin -@register_dataset("my-dataset") -class MyDataset(Dataset): - ... - -@register_mock(name="my-dataset", configs=...) -def my_dataset(root, config): - ... -``` - -The mock data function receives two arguments: - -- `root`: A [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path) of a folder, in which the data - needs to be placed. -- `config`: The configuration to generate the data for. This is one of the dictionaries defined in - `@register_mock(configs=...)` - -The function should generate all files that are needed for the current `config`. Each file should be complete, e.g. if -the dataset only has a single archive that contains multiple splits, you need to generate the full archive regardless of -the current `config`. Although this seems odd at first, this is important. Consider the following original data setup: - -``` -root -├── test -│ ├── test_image0.jpg -│ ... -└── train - ├── train_image0.jpg - ... -``` - -For map-style datasets (like the one currently in `torchvision.datasets`), one explicitly selects the files they want to -load. For example, something like `(root / split).iterdir()` works fine even if only the specific split folder is -present. With iterable-style datasets though, we get something like `root.iterdir()` from `resource_dps` in -`_datapipe()` and need to manually `Filter` it to only keep the files we want. If we would only generate the data for -the current `config`, the test would also pass if the dataset is missing the filtering, but would fail on the real data. - -For datasets that are ported from the old API, we already have some mock data in -[`test/test_datasets.py`](../../../../test/test_datasets.py). You can find the test case corresponding test case there -and have a look at the `inject_fake_data` function. There are a few differences though: - -- `tmp_dir` corresponds to `root`, but is a `str` rather than a - [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path). Thus, you often see something like - `folder = pathlib.Path(tmp_dir)`. This is not needed. -- The data generated by `inject_fake_data` was supposed to be in an extracted state. This is no longer the case for the - new mock-ups. Thus, you need to use helper functions like `make_zip` or `make_tar` to actually generate the files - specified in the dataset. -- As explained in the paragraph above, the generated data is often "incomplete" and only valid for given the config. - Make sure you follow the instructions above. - -The function should return an integer indicating the number of samples in the dataset for the current `config`. -Preferably, this number should be different for different `config`'s to have more confidence in the dataset -implementation. - -Finally, you can run the tests with `pytest test/test_prototype_builtin_datasets.py -k {name}`. - -## FAQ - -### How do I start? - -Get the skeleton of your dataset class ready with all 4 methods. For `_datapipe()`, you can just do -`return resources_dp[0]` to get started. Then import the dataset class in -`torchvision/prototype/datasets/_builtin/__init__.py`: this will automatically register the dataset, and it will be -instantiable via `datasets.load("mydataset")`. On a separate script, try something like - -```py -from torchvision.prototype import datasets - -dataset = datasets.load("mydataset") -for sample in dataset: - print(sample) # this is the content of an item in datapipe returned by _datapipe() - break -# Or you can also inspect the sample in a debugger -``` - -This will give you an idea of what the first datapipe in `resources_dp` contains. You can also do that with -`resources_dp[1]` or `resources_dp[2]` (etc.) if they exist. Then follow the instructions above to manipulate these -datapipes and return the appropriate dictionary format. - -### How do I handle a dataset that defines many categories? - -As a rule of thumb, `categories` in the info dictionary should only be set manually for ten categories or fewer. If more -categories are needed, you can add a `$NAME.categories` file to the `_builtin` folder in which each line specifies a -category. To load such a file, use the `from torchvision.prototype.datasets.utils._internal import read_categories_file` -function and pass it `$NAME`. - -In case the categories can be generated from the dataset files, e.g. the dataset follows an image folder approach where -each folder denotes the name of the category, the dataset can overwrite the `_generate_categories` method. The method -should return a sequence of strings representing the category names. In the method body, you'll have to manually load -the resources, e.g. - -```py -resources = self._resources() -dp = resources[0].load(self._root) -``` - -Note that it is not necessary here to keep a datapipe until the final step. Stick with datapipes as long as it makes -sense and afterwards materialize the data with `next(iter(dp))` or `list(dp)` and proceed with that. - -To generate the `$NAME.categories` file, run `python -m torchvision.prototype.datasets.generate_category_files $NAME`. - -### What if a resource file forms an I/O bottleneck? - -In general, we are ok with small performance hits of iterating archives rather than their extracted content. However, if -the performance hit becomes significant, the archives can still be preprocessed. `OnlineResource` accepts the -`preprocess` parameter that can be a `Callable[[pathlib.Path], pathlib.Path]` where the input points to the file to be -preprocessed and the return value should be the result of the preprocessing to load. For convenience, `preprocess` also -accepts `"decompress"` and `"extract"` to handle these common scenarios. - -### How do I compute the number of samples? - -Unless the authors of the dataset published the exact numbers (even in this case we should check), there is no other way -than to iterate over the dataset and count the number of samples: - -```py -import itertools -from torchvision.prototype import datasets - - -def combinations_grid(**kwargs): - return [dict(zip(kwargs.keys(), values)) for values in itertools.product(*kwargs.values())] - - -# If you have implemented the mock data function for the dataset tests, you can simply copy-paste from there -configs = combinations_grid(split=("train", "test"), foo=("bar", "baz")) - -for config in configs: - dataset = datasets.load("my-dataset", **config) - - num_samples = 0 - for _ in dataset: - num_samples += 1 - - print(", ".join(f"{key}={value}" for key, value in config.items()), num_samples) -``` - -To speed this up, it is useful to temporarily comment out all unnecessary I/O, such as loading of images or annotation -files. diff --git a/torchvision/prototype/datasets/_builtin/__init__.py b/torchvision/prototype/datasets/_builtin/__init__.py deleted file mode 100644 index d84e9af9fc4..00000000000 --- a/torchvision/prototype/datasets/_builtin/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -from .caltech import Caltech101, Caltech256 -from .celeba import CelebA -from .cifar import Cifar10, Cifar100 -from .clevr import CLEVR -from .coco import Coco -from .country211 import Country211 -from .cub200 import CUB200 -from .dtd import DTD -from .eurosat import EuroSAT -from .fer2013 import FER2013 -from .food101 import Food101 -from .gtsrb import GTSRB -from .imagenet import ImageNet -from .mnist import EMNIST, FashionMNIST, KMNIST, MNIST, QMNIST -from .oxford_iiit_pet import OxfordIIITPet -from .pcam import PCAM -from .sbd import SBD -from .semeion import SEMEION -from .stanford_cars import StanfordCars -from .svhn import SVHN -from .usps import USPS -from .voc import VOC diff --git a/torchvision/prototype/datasets/_builtin/caltech.py b/torchvision/prototype/datasets/_builtin/caltech.py deleted file mode 100644 index 5072902b212..00000000000 --- a/torchvision/prototype/datasets/_builtin/caltech.py +++ /dev/null @@ -1,212 +0,0 @@ -import pathlib -import re -from typing import Any, BinaryIO, Dict, List, Tuple, Union - -import numpy as np - -import torch -from torchdata.datapipes.iter import Filter, IterDataPipe, IterKeyZipper, Mapper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, GDriveResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - read_categories_file, - read_mat, -) -from torchvision.prototype.tv_tensors import Label -from torchvision.tv_tensors import BoundingBoxes - -from .._api import register_dataset, register_info - - -@register_info("caltech101") -def _caltech101_info() -> Dict[str, Any]: - return dict(categories=read_categories_file("caltech101")) - - -@register_dataset("caltech101") -class Caltech101(Dataset): - """ - - **homepage**: https://data.caltech.edu/records/20086 - - **dependencies**: - - _ - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - skip_integrity_check: bool = False, - ) -> None: - self._categories = _caltech101_info()["categories"] - - super().__init__( - root, - dependencies=("scipy",), - skip_integrity_check=skip_integrity_check, - ) - - def _resources(self) -> List[OnlineResource]: - images = GDriveResource( - "137RyRjvTBkBiIfeYBNZBtViDHQ6_Ewsp", - file_name="101_ObjectCategories.tar.gz", - sha256="af6ece2f339791ca20f855943d8b55dd60892c0a25105fcd631ee3d6430f9926", - preprocess="decompress", - ) - anns = GDriveResource( - "175kQy3UsZ0wUEHZjqkUDdNVssr7bgh_m", - file_name="Annotations.tar", - sha256="1717f4e10aa837b05956e3f4c94456527b143eec0d95e935028b30aff40663d8", - ) - return [images, anns] - - _IMAGES_NAME_PATTERN = re.compile(r"image_(?P\d+)[.]jpg") - _ANNS_NAME_PATTERN = re.compile(r"annotation_(?P\d+)[.]mat") - _ANNS_CATEGORY_MAP = { - "Faces_2": "Faces", - "Faces_3": "Faces_easy", - "Motorbikes_16": "Motorbikes", - "Airplanes_Side_2": "airplanes", - } - - def _is_not_background_image(self, data: Tuple[str, Any]) -> bool: - path = pathlib.Path(data[0]) - return path.parent.name != "BACKGROUND_Google" - - def _is_ann(self, data: Tuple[str, Any]) -> bool: - path = pathlib.Path(data[0]) - return bool(self._ANNS_NAME_PATTERN.match(path.name)) - - def _images_key_fn(self, data: Tuple[str, Any]) -> Tuple[str, str]: - path = pathlib.Path(data[0]) - - category = path.parent.name - id = self._IMAGES_NAME_PATTERN.match(path.name).group("id") # type: ignore[union-attr] - - return category, id - - def _anns_key_fn(self, data: Tuple[str, Any]) -> Tuple[str, str]: - path = pathlib.Path(data[0]) - - category = path.parent.name - if category in self._ANNS_CATEGORY_MAP: - category = self._ANNS_CATEGORY_MAP[category] - - id = self._ANNS_NAME_PATTERN.match(path.name).group("id") # type: ignore[union-attr] - - return category, id - - def _prepare_sample( - self, data: Tuple[Tuple[str, str], Tuple[Tuple[str, BinaryIO], Tuple[str, BinaryIO]]] - ) -> Dict[str, Any]: - key, (image_data, ann_data) = data - category, _ = key - image_path, image_buffer = image_data - ann_path, ann_buffer = ann_data - - image = EncodedImage.from_file(image_buffer) - ann = read_mat(ann_buffer) - - return dict( - label=Label.from_category(category, categories=self._categories), - image_path=image_path, - image=image, - ann_path=ann_path, - bounding_boxes=BoundingBoxes( - ann["box_coord"].astype(np.int64).squeeze()[[2, 0, 3, 1]], - format="xyxy", - spatial_size=image.spatial_size, - ), - contour=torch.as_tensor(ann["obj_contour"].T), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - images_dp, anns_dp = resource_dps - - images_dp = Filter(images_dp, self._is_not_background_image) - images_dp = hint_shuffling(images_dp) - images_dp = hint_sharding(images_dp) - - anns_dp = Filter(anns_dp, self._is_ann) - - dp = IterKeyZipper( - images_dp, - anns_dp, - key_fn=self._images_key_fn, - ref_key_fn=self._anns_key_fn, - buffer_size=INFINITE_BUFFER_SIZE, - keep_key=True, - ) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return 8677 - - def _generate_categories(self) -> List[str]: - resources = self._resources() - - dp = resources[0].load(self._root) - dp = Filter(dp, self._is_not_background_image) - - return sorted({pathlib.Path(path).parent.name for path, _ in dp}) - - -@register_info("caltech256") -def _caltech256_info() -> Dict[str, Any]: - return dict(categories=read_categories_file("caltech256")) - - -@register_dataset("caltech256") -class Caltech256(Dataset): - """ - - **homepage**: https://data.caltech.edu/records/20087 - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - skip_integrity_check: bool = False, - ) -> None: - self._categories = _caltech256_info()["categories"] - - super().__init__(root, skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - return [ - GDriveResource( - "1r6o0pSROcV1_VwT4oSjA2FBUSCWGuxLK", - file_name="256_ObjectCategories.tar", - sha256="08ff01b03c65566014ae88eb0490dbe4419fc7ac4de726ee1163e39fd809543e", - ) - ] - - def _is_not_rogue_file(self, data: Tuple[str, Any]) -> bool: - path = pathlib.Path(data[0]) - return path.name != "RENAME2" - - def _prepare_sample(self, data: Tuple[str, BinaryIO]) -> Dict[str, Any]: - path, buffer = data - - return dict( - path=path, - image=EncodedImage.from_file(buffer), - label=Label(int(pathlib.Path(path).parent.name.split(".", 1)[0]) - 1, categories=self._categories), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - dp = resource_dps[0] - dp = Filter(dp, self._is_not_rogue_file) - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return 30607 - - def _generate_categories(self) -> List[str]: - resources = self._resources() - - dp = resources[0].load(self._root) - dir_names = {pathlib.Path(path).parent.name for path, _ in dp} - - return [name.split(".")[1] for name in sorted(dir_names)] diff --git a/torchvision/prototype/datasets/_builtin/caltech101.categories b/torchvision/prototype/datasets/_builtin/caltech101.categories deleted file mode 100644 index d5c18654b4e..00000000000 --- a/torchvision/prototype/datasets/_builtin/caltech101.categories +++ /dev/null @@ -1,101 +0,0 @@ -Faces -Faces_easy -Leopards -Motorbikes -accordion -airplanes -anchor -ant -barrel -bass -beaver -binocular -bonsai -brain -brontosaurus -buddha -butterfly -camera -cannon -car_side -ceiling_fan -cellphone -chair -chandelier -cougar_body -cougar_face -crab -crayfish -crocodile -crocodile_head -cup -dalmatian -dollar_bill -dolphin -dragonfly -electric_guitar -elephant -emu -euphonium -ewer -ferry -flamingo -flamingo_head -garfield -gerenuk -gramophone -grand_piano -hawksbill -headphone -hedgehog -helicopter -ibis -inline_skate -joshua_tree -kangaroo -ketch -lamp -laptop -llama -lobster -lotus -mandolin -mayfly -menorah -metronome -minaret -nautilus -octopus -okapi -pagoda -panda -pigeon -pizza -platypus -pyramid -revolver -rhino -rooster -saxophone -schooner -scissors -scorpion -sea_horse -snoopy -soccer_ball -stapler -starfish -stegosaurus -stop_sign -strawberry -sunflower -tick -trilobite -umbrella -watch -water_lilly -wheelchair -wild_cat -windsor_chair -wrench -yin_yang diff --git a/torchvision/prototype/datasets/_builtin/caltech256.categories b/torchvision/prototype/datasets/_builtin/caltech256.categories deleted file mode 100644 index 82128efba97..00000000000 --- a/torchvision/prototype/datasets/_builtin/caltech256.categories +++ /dev/null @@ -1,257 +0,0 @@ -ak47 -american-flag -backpack -baseball-bat -baseball-glove -basketball-hoop -bat -bathtub -bear -beer-mug -billiards -binoculars -birdbath -blimp -bonsai-101 -boom-box -bowling-ball -bowling-pin -boxing-glove -brain-101 -breadmaker -buddha-101 -bulldozer -butterfly -cactus -cake -calculator -camel -cannon -canoe -car-tire -cartman -cd -centipede -cereal-box -chandelier-101 -chess-board -chimp -chopsticks -cockroach -coffee-mug -coffin -coin -comet -computer-keyboard -computer-monitor -computer-mouse -conch -cormorant -covered-wagon -cowboy-hat -crab-101 -desk-globe -diamond-ring -dice -dog -dolphin-101 -doorknob -drinking-straw -duck -dumb-bell -eiffel-tower -electric-guitar-101 -elephant-101 -elk -ewer-101 -eyeglasses -fern -fighter-jet -fire-extinguisher -fire-hydrant -fire-truck -fireworks -flashlight -floppy-disk -football-helmet -french-horn -fried-egg -frisbee -frog -frying-pan -galaxy -gas-pump -giraffe -goat -golden-gate-bridge -goldfish -golf-ball -goose -gorilla -grand-piano-101 -grapes -grasshopper -guitar-pick -hamburger -hammock -harmonica -harp -harpsichord -hawksbill-101 -head-phones -helicopter-101 -hibiscus -homer-simpson -horse -horseshoe-crab -hot-air-balloon -hot-dog -hot-tub -hourglass -house-fly -human-skeleton -hummingbird -ibis-101 -ice-cream-cone -iguana -ipod -iris -jesus-christ -joy-stick -kangaroo-101 -kayak -ketch-101 -killer-whale -knife -ladder -laptop-101 -lathe -leopards-101 -license-plate -lightbulb -light-house -lightning -llama-101 -mailbox -mandolin -mars -mattress -megaphone -menorah-101 -microscope -microwave -minaret -minotaur -motorbikes-101 -mountain-bike -mushroom -mussels -necktie -octopus -ostrich -owl -palm-pilot -palm-tree -paperclip -paper-shredder -pci-card -penguin -people -pez-dispenser -photocopier -picnic-table -playing-card -porcupine -pram -praying-mantis -pyramid -raccoon -radio-telescope -rainbow -refrigerator -revolver-101 -rifle -rotary-phone -roulette-wheel -saddle -saturn -school-bus -scorpion-101 -screwdriver -segway -self-propelled-lawn-mower -sextant -sheet-music -skateboard -skunk -skyscraper -smokestack -snail -snake -sneaker -snowmobile -soccer-ball -socks -soda-can -spaghetti -speed-boat -spider -spoon -stained-glass -starfish-101 -steering-wheel -stirrups -sunflower-101 -superman -sushi -swan -swiss-army-knife -sword -syringe -tambourine -teapot -teddy-bear -teepee -telephone-box -tennis-ball -tennis-court -tennis-racket -theodolite -toaster -tomato -tombstone -top-hat -touring-bike -tower-pisa -traffic-light -treadmill -triceratops -tricycle -trilobite-101 -tripod -t-shirt -tuning-fork -tweezer -umbrella-101 -unicorn -vcr -video-projector -washing-machine -watch-101 -waterfall -watermelon -welding-mask -wheelbarrow -windmill -wine-bottle -xylophone -yarmulke -yo-yo -zebra -airplanes-101 -car-side-101 -faces-easy-101 -greyhound -tennis-shoes -toad -clutter diff --git a/torchvision/prototype/datasets/_builtin/celeba.py b/torchvision/prototype/datasets/_builtin/celeba.py deleted file mode 100644 index 5ec3ee3ebef..00000000000 --- a/torchvision/prototype/datasets/_builtin/celeba.py +++ /dev/null @@ -1,200 +0,0 @@ -import csv -import pathlib -from typing import Any, BinaryIO, Dict, Iterator, List, Optional, Sequence, Tuple, Union - -import torch -from torchdata.datapipes.iter import Filter, IterDataPipe, IterKeyZipper, Mapper, Zipper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, GDriveResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_accessor, -) -from torchvision.prototype.tv_tensors import Label -from torchvision.tv_tensors import BoundingBoxes - -from .._api import register_dataset, register_info - -csv.register_dialect("celeba", delimiter=" ", skipinitialspace=True) - - -class CelebACSVParser(IterDataPipe[Tuple[str, Dict[str, str]]]): - def __init__( - self, - datapipe: IterDataPipe[Tuple[Any, BinaryIO]], - *, - fieldnames: Optional[Sequence[str]] = None, - ) -> None: - self.datapipe = datapipe - self.fieldnames = fieldnames - - def __iter__(self) -> Iterator[Tuple[str, Dict[str, str]]]: - for _, file in self.datapipe: - try: - lines = (line.decode() for line in file) - - if self.fieldnames: - fieldnames = self.fieldnames - else: - # The first row is skipped, because it only contains the number of samples - next(lines) - - # Empty field names are filtered out, because some files have an extra white space after the header - # line, which is recognized as extra column - fieldnames = [name for name in next(csv.reader([next(lines)], dialect="celeba")) if name] - # Some files do not include a label for the image ID column - if fieldnames[0] != "image_id": - fieldnames.insert(0, "image_id") - - for line in csv.DictReader(lines, fieldnames=fieldnames, dialect="celeba"): - yield line.pop("image_id"), line - finally: - file.close() - - -NAME = "celeba" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict() - - -@register_dataset(NAME) -class CelebA(Dataset): - """ - - **homepage**: https://mmlab.ie.cuhk.edu.hk/projects/CelebA.html - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "val", "test")) - - super().__init__(root, skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - splits = GDriveResource( - "0B7EVK8r0v71pY0NSMzRuSXJEVkk", - sha256="fc955bcb3ef8fbdf7d5640d9a8693a8431b5f2ee291a5c1449a1549e7e073fe7", - file_name="list_eval_partition.txt", - ) - images = GDriveResource( - "0B7EVK8r0v71pZjFTYXZWM3FlRnM", - sha256="46fb89443c578308acf364d7d379fe1b9efb793042c0af734b6112e4fd3a8c74", - file_name="img_align_celeba.zip", - ) - identities = GDriveResource( - "1_ee_0u7vcNLOfNLegJRHmolfH5ICW-XS", - sha256="c6143857c3e2630ac2da9f782e9c1232e5e59be993a9d44e8a7916c78a6158c0", - file_name="identity_CelebA.txt", - ) - attributes = GDriveResource( - "0B7EVK8r0v71pblRyaVFSWGxPY0U", - sha256="f0e5da289d5ccf75ffe8811132694922b60f2af59256ed362afa03fefba324d0", - file_name="list_attr_celeba.txt", - ) - bounding_boxes = GDriveResource( - "0B7EVK8r0v71pbThiMVRxWXZ4dU0", - sha256="7487a82e57c4bb956c5445ae2df4a91ffa717e903c5fa22874ede0820c8ec41b", - file_name="list_bbox_celeba.txt", - ) - landmarks = GDriveResource( - "0B7EVK8r0v71pd0FJY3Blby1HUTQ", - sha256="6c02a87569907f6db2ba99019085697596730e8129f67a3d61659f198c48d43b", - file_name="list_landmarks_align_celeba.txt", - ) - return [splits, images, identities, attributes, bounding_boxes, landmarks] - - def _filter_split(self, data: Tuple[str, Dict[str, str]]) -> bool: - split_id = { - "train": "0", - "val": "1", - "test": "2", - }[self._split] - return data[1]["split_id"] == split_id - - def _prepare_sample( - self, - data: Tuple[ - Tuple[str, Tuple[Tuple[str, List[str]], Tuple[str, BinaryIO]]], - Tuple[ - Tuple[str, Dict[str, str]], - Tuple[str, Dict[str, str]], - Tuple[str, Dict[str, str]], - Tuple[str, Dict[str, str]], - ], - ], - ) -> Dict[str, Any]: - split_and_image_data, ann_data = data - _, (_, image_data) = split_and_image_data - path, buffer = image_data - - image = EncodedImage.from_file(buffer) - (_, identity), (_, attributes), (_, bounding_boxes), (_, landmarks) = ann_data - - return dict( - path=path, - image=image, - identity=Label(int(identity["identity"])), - attributes={attr: value == "1" for attr, value in attributes.items()}, - bounding_boxes=BoundingBoxes( - [int(bounding_boxes[key]) for key in ("x_1", "y_1", "width", "height")], - format="xywh", - spatial_size=image.spatial_size, - ), - landmarks={ - landmark: torch.tensor((int(landmarks[f"{landmark}_x"]), int(landmarks[f"{landmark}_y"]))) - for landmark in {key[:-2] for key in landmarks.keys()} - }, - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - splits_dp, images_dp, identities_dp, attributes_dp, bounding_boxes_dp, landmarks_dp = resource_dps - - splits_dp = CelebACSVParser(splits_dp, fieldnames=("image_id", "split_id")) - splits_dp = Filter(splits_dp, self._filter_split) - splits_dp = hint_shuffling(splits_dp) - splits_dp = hint_sharding(splits_dp) - - anns_dp = Zipper( - *[ - CelebACSVParser(dp, fieldnames=fieldnames) - for dp, fieldnames in ( - (identities_dp, ("image_id", "identity")), - (attributes_dp, None), - (bounding_boxes_dp, None), - (landmarks_dp, None), - ) - ] - ) - - dp = IterKeyZipper( - splits_dp, - images_dp, - key_fn=getitem(0), - ref_key_fn=path_accessor("name"), - buffer_size=INFINITE_BUFFER_SIZE, - keep_key=True, - ) - dp = IterKeyZipper( - dp, - anns_dp, - key_fn=getitem(0), - ref_key_fn=getitem(0, 0), - buffer_size=INFINITE_BUFFER_SIZE, - ) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return { - "train": 162_770, - "val": 19_867, - "test": 19_962, - }[self._split] diff --git a/torchvision/prototype/datasets/_builtin/cifar.py b/torchvision/prototype/datasets/_builtin/cifar.py deleted file mode 100644 index 0668ec9fc42..00000000000 --- a/torchvision/prototype/datasets/_builtin/cifar.py +++ /dev/null @@ -1,142 +0,0 @@ -import abc -import io -import pathlib -import pickle -from typing import Any, BinaryIO, cast, Dict, Iterator, List, Optional, Tuple, Union - -import numpy as np -from torchdata.datapipes.iter import Filter, IterDataPipe, Mapper -from torchvision.prototype.datasets.utils import Dataset, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - hint_sharding, - hint_shuffling, - path_comparator, - read_categories_file, -) -from torchvision.prototype.tv_tensors import Label -from torchvision.tv_tensors import Image - -from .._api import register_dataset, register_info - - -class CifarFileReader(IterDataPipe[Tuple[np.ndarray, int]]): - def __init__(self, datapipe: IterDataPipe[Dict[str, Any]], *, labels_key: str) -> None: - self.datapipe = datapipe - self.labels_key = labels_key - - def __iter__(self) -> Iterator[Tuple[np.ndarray, int]]: - for mapping in self.datapipe: - image_arrays = mapping["data"].reshape((-1, 3, 32, 32)) - category_idcs = mapping[self.labels_key] - yield from iter(zip(image_arrays, category_idcs)) - - -class _CifarBase(Dataset): - _FILE_NAME: str - _SHA256: str - _LABELS_KEY: str - _META_FILE_NAME: str - _CATEGORIES_KEY: str - _categories: List[str] - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "test")) - super().__init__(root, skip_integrity_check=skip_integrity_check) - - @abc.abstractmethod - def _is_data_file(self, data: Tuple[str, BinaryIO]) -> Optional[int]: - pass - - def _resources(self) -> List[OnlineResource]: - return [ - HttpResource( - f"https://www.cs.toronto.edu/~kriz/{self._FILE_NAME}", - sha256=self._SHA256, - ) - ] - - def _unpickle(self, data: Tuple[str, io.BytesIO]) -> Dict[str, Any]: - _, file = data - content = cast(Dict[str, Any], pickle.load(file, encoding="latin1")) - file.close() - return content - - def _prepare_sample(self, data: Tuple[np.ndarray, int]) -> Dict[str, Any]: - image_array, category_idx = data - return dict( - image=Image(image_array), - label=Label(category_idx, categories=self._categories), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - dp = resource_dps[0] - dp = Filter(dp, self._is_data_file) - dp = Mapper(dp, self._unpickle) - dp = CifarFileReader(dp, labels_key=self._LABELS_KEY) - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return 50_000 if self._split == "train" else 10_000 - - def _generate_categories(self) -> List[str]: - resources = self._resources() - - dp = resources[0].load(self._root) - dp = Filter(dp, path_comparator("name", self._META_FILE_NAME)) - dp = Mapper(dp, self._unpickle) - - return cast(List[str], next(iter(dp))[self._CATEGORIES_KEY]) - - -@register_info("cifar10") -def _cifar10_info() -> Dict[str, Any]: - return dict(categories=read_categories_file("cifar10")) - - -@register_dataset("cifar10") -class Cifar10(_CifarBase): - """ - - **homepage**: https://www.cs.toronto.edu/~kriz/cifar.html - """ - - _FILE_NAME = "cifar-10-python.tar.gz" - _SHA256 = "6d958be074577803d12ecdefd02955f39262c83c16fe9348329d7fe0b5c001ce" - _LABELS_KEY = "labels" - _META_FILE_NAME = "batches.meta" - _CATEGORIES_KEY = "label_names" - _categories = _cifar10_info()["categories"] - - def _is_data_file(self, data: Tuple[str, Any]) -> bool: - path = pathlib.Path(data[0]) - return path.name.startswith("data" if self._split == "train" else "test") - - -@register_info("cifar100") -def _cifar100_info() -> Dict[str, Any]: - return dict(categories=read_categories_file("cifar100")) - - -@register_dataset("cifar100") -class Cifar100(_CifarBase): - """ - - **homepage**: https://www.cs.toronto.edu/~kriz/cifar.html - """ - - _FILE_NAME = "cifar-100-python.tar.gz" - _SHA256 = "85cd44d02ba6437773c5bbd22e183051d648de2e7d6b014e1ef29b855ba677a7" - _LABELS_KEY = "fine_labels" - _META_FILE_NAME = "meta" - _CATEGORIES_KEY = "fine_label_names" - _categories = _cifar100_info()["categories"] - - def _is_data_file(self, data: Tuple[str, Any]) -> bool: - path = pathlib.Path(data[0]) - return path.name == self._split diff --git a/torchvision/prototype/datasets/_builtin/cifar10.categories b/torchvision/prototype/datasets/_builtin/cifar10.categories deleted file mode 100644 index fa30c22b95d..00000000000 --- a/torchvision/prototype/datasets/_builtin/cifar10.categories +++ /dev/null @@ -1,10 +0,0 @@ -airplane -automobile -bird -cat -deer -dog -frog -horse -ship -truck diff --git a/torchvision/prototype/datasets/_builtin/cifar100.categories b/torchvision/prototype/datasets/_builtin/cifar100.categories deleted file mode 100644 index 7f7bf51d1ab..00000000000 --- a/torchvision/prototype/datasets/_builtin/cifar100.categories +++ /dev/null @@ -1,100 +0,0 @@ -apple -aquarium_fish -baby -bear -beaver -bed -bee -beetle -bicycle -bottle -bowl -boy -bridge -bus -butterfly -camel -can -castle -caterpillar -cattle -chair -chimpanzee -clock -cloud -cockroach -couch -crab -crocodile -cup -dinosaur -dolphin -elephant -flatfish -forest -fox -girl -hamster -house -kangaroo -keyboard -lamp -lawn_mower -leopard -lion -lizard -lobster -man -maple_tree -motorcycle -mountain -mouse -mushroom -oak_tree -orange -orchid -otter -palm_tree -pear -pickup_truck -pine_tree -plain -plate -poppy -porcupine -possum -rabbit -raccoon -ray -road -rocket -rose -sea -seal -shark -shrew -skunk -skyscraper -snail -snake -spider -squirrel -streetcar -sunflower -sweet_pepper -table -tank -telephone -television -tiger -tractor -train -trout -tulip -turtle -wardrobe -whale -willow_tree -wolf -woman -worm diff --git a/torchvision/prototype/datasets/_builtin/clevr.py b/torchvision/prototype/datasets/_builtin/clevr.py deleted file mode 100644 index 46cef90efbb..00000000000 --- a/torchvision/prototype/datasets/_builtin/clevr.py +++ /dev/null @@ -1,107 +0,0 @@ -import pathlib -from typing import Any, BinaryIO, Dict, List, Optional, Tuple, Union - -from torchdata.datapipes.iter import Demultiplexer, Filter, IterDataPipe, IterKeyZipper, JsonParser, Mapper, UnBatcher -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_accessor, - path_comparator, -) -from torchvision.prototype.tv_tensors import Label - -from .._api import register_dataset, register_info - -NAME = "clevr" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict() - - -@register_dataset(NAME) -class CLEVR(Dataset): - """ - - **homepage**: https://cs.stanford.edu/people/jcjohns/clevr/ - """ - - def __init__( - self, root: Union[str, pathlib.Path], *, split: str = "train", skip_integrity_check: bool = False - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "val", "test")) - - super().__init__(root, skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - archive = HttpResource( - "https://dl.fbaipublicfiles.com/clevr/CLEVR_v1.0.zip", - sha256="5cd61cf1096ed20944df93c9adb31e74d189b8459a94f54ba00090e5c59936d1", - ) - return [archive] - - def _classify_archive(self, data: Tuple[str, Any]) -> Optional[int]: - path = pathlib.Path(data[0]) - if path.parents[1].name == "images": - return 0 - elif path.parent.name == "scenes": - return 1 - else: - return None - - def _filter_scene_anns(self, data: Tuple[str, Any]) -> bool: - key, _ = data - return key == "scenes" - - def _add_empty_anns(self, data: Tuple[str, BinaryIO]) -> Tuple[Tuple[str, BinaryIO], None]: - return data, None - - def _prepare_sample(self, data: Tuple[Tuple[str, BinaryIO], Optional[Dict[str, Any]]]) -> Dict[str, Any]: - image_data, scenes_data = data - path, buffer = image_data - - return dict( - path=path, - image=EncodedImage.from_file(buffer), - label=Label(len(scenes_data["objects"])) if scenes_data else None, - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - archive_dp = resource_dps[0] - images_dp, scenes_dp = Demultiplexer( - archive_dp, - 2, - self._classify_archive, - drop_none=True, - buffer_size=INFINITE_BUFFER_SIZE, - ) - - images_dp = Filter(images_dp, path_comparator("parent.name", self._split)) - images_dp = hint_shuffling(images_dp) - images_dp = hint_sharding(images_dp) - - if self._split != "test": - scenes_dp = Filter(scenes_dp, path_comparator("name", f"CLEVR_{self._split}_scenes.json")) - scenes_dp = JsonParser(scenes_dp) - scenes_dp = Mapper(scenes_dp, getitem(1, "scenes")) - scenes_dp = UnBatcher(scenes_dp) - - dp = IterKeyZipper( - images_dp, - scenes_dp, - key_fn=path_accessor("name"), - ref_key_fn=getitem("image_filename"), - buffer_size=INFINITE_BUFFER_SIZE, - ) - else: - for _, file in scenes_dp: - file.close() - dp = Mapper(images_dp, self._add_empty_anns) - - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return 70_000 if self._split == "train" else 15_000 diff --git a/torchvision/prototype/datasets/_builtin/coco.categories b/torchvision/prototype/datasets/_builtin/coco.categories deleted file mode 100644 index 27e612f6d7d..00000000000 --- a/torchvision/prototype/datasets/_builtin/coco.categories +++ /dev/null @@ -1,91 +0,0 @@ -__background__,N/A -person,person -bicycle,vehicle -car,vehicle -motorcycle,vehicle -airplane,vehicle -bus,vehicle -train,vehicle -truck,vehicle -boat,vehicle -traffic light,outdoor -fire hydrant,outdoor -N/A,N/A -stop sign,outdoor -parking meter,outdoor -bench,outdoor -bird,animal -cat,animal -dog,animal -horse,animal -sheep,animal -cow,animal -elephant,animal -bear,animal -zebra,animal -giraffe,animal -N/A,N/A -backpack,accessory -umbrella,accessory -N/A,N/A -N/A,N/A -handbag,accessory -tie,accessory -suitcase,accessory -frisbee,sports -skis,sports -snowboard,sports -sports ball,sports -kite,sports -baseball bat,sports -baseball glove,sports -skateboard,sports -surfboard,sports -tennis racket,sports -bottle,kitchen -N/A,N/A -wine glass,kitchen -cup,kitchen -fork,kitchen -knife,kitchen -spoon,kitchen -bowl,kitchen -banana,food -apple,food -sandwich,food -orange,food -broccoli,food -carrot,food -hot dog,food -pizza,food -donut,food -cake,food -chair,furniture -couch,furniture -potted plant,furniture -bed,furniture -N/A,N/A -dining table,furniture -N/A,N/A -N/A,N/A -toilet,furniture -N/A,N/A -tv,electronic -laptop,electronic -mouse,electronic -remote,electronic -keyboard,electronic -cell phone,electronic -microwave,appliance -oven,appliance -toaster,appliance -sink,appliance -refrigerator,appliance -N/A,N/A -book,indoor -clock,indoor -vase,indoor -scissors,indoor -teddy bear,indoor -hair drier,indoor -toothbrush,indoor diff --git a/torchvision/prototype/datasets/_builtin/coco.py b/torchvision/prototype/datasets/_builtin/coco.py deleted file mode 100644 index 628629e33c0..00000000000 --- a/torchvision/prototype/datasets/_builtin/coco.py +++ /dev/null @@ -1,274 +0,0 @@ -import pathlib -import re -from collections import defaultdict, OrderedDict -from typing import Any, BinaryIO, cast, Dict, List, Optional, Tuple, Union - -import torch -from torchdata.datapipes.iter import ( - Demultiplexer, - Filter, - Grouper, - IterDataPipe, - IterKeyZipper, - JsonParser, - Mapper, - UnBatcher, -) -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - MappingIterator, - path_accessor, - read_categories_file, -) -from torchvision.prototype.tv_tensors import Label -from torchvision.tv_tensors import BoundingBoxes, Mask - -from .._api import register_dataset, register_info - - -NAME = "coco" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - categories, super_categories = zip(*read_categories_file(NAME)) - return dict(categories=categories, super_categories=super_categories) - - -@register_dataset(NAME) -class Coco(Dataset): - """ - - **homepage**: https://cocodataset.org/ - - **dependencies**: - - _ - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - year: str = "2017", - annotations: Optional[str] = "instances", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", {"train", "val"}) - self._year = self._verify_str_arg(year, "year", {"2017", "2014"}) - self._annotations = ( - self._verify_str_arg(annotations, "annotations", self._ANN_DECODERS.keys()) - if annotations is not None - else None - ) - - info = _info() - categories, super_categories = info["categories"], info["super_categories"] - self._categories = categories - self._category_to_super_category = dict(zip(categories, super_categories)) - - super().__init__(root, dependencies=("pycocotools",), skip_integrity_check=skip_integrity_check) - - _IMAGE_URL_BASE = "http://images.cocodataset.org/zips" - - _IMAGES_CHECKSUMS = { - ("2014", "train"): "ede4087e640bddba550e090eae701092534b554b42b05ac33f0300b984b31775", - ("2014", "val"): "fe9be816052049c34717e077d9e34aa60814a55679f804cd043e3cbee3b9fde0", - ("2017", "train"): "69a8bb58ea5f8f99d24875f21416de2e9ded3178e903f1f7603e283b9e06d929", - ("2017", "val"): "4f7e2ccb2866ec5041993c9cf2a952bbed69647b115d0f74da7ce8f4bef82f05", - } - - _META_URL_BASE = "http://images.cocodataset.org/annotations" - - _META_CHECKSUMS = { - "2014": "031296bbc80c45a1d1f76bf9a90ead27e94e99ec629208449507a4917a3bf009", - "2017": "113a836d90195ee1f884e704da6304dfaaecff1f023f49b6ca93c4aaae470268", - } - - def _resources(self) -> List[OnlineResource]: - images = HttpResource( - f"{self._IMAGE_URL_BASE}/{self._split}{self._year}.zip", - sha256=self._IMAGES_CHECKSUMS[(self._year, self._split)], - ) - meta = HttpResource( - f"{self._META_URL_BASE}/annotations_trainval{self._year}.zip", - sha256=self._META_CHECKSUMS[self._year], - ) - return [images, meta] - - def _segmentation_to_mask( - self, segmentation: Any, *, is_crowd: bool, spatial_size: Tuple[int, int] - ) -> torch.Tensor: - from pycocotools import mask - - if is_crowd: - segmentation = mask.frPyObjects(segmentation, *spatial_size) - else: - segmentation = mask.merge(mask.frPyObjects(segmentation, *spatial_size)) - - return torch.from_numpy(mask.decode(segmentation)).to(torch.bool) - - def _decode_instances_anns(self, anns: List[Dict[str, Any]], image_meta: Dict[str, Any]) -> Dict[str, Any]: - spatial_size = (image_meta["height"], image_meta["width"]) - labels = [ann["category_id"] for ann in anns] - return dict( - segmentations=Mask( - torch.stack( - [ - self._segmentation_to_mask( - ann["segmentation"], is_crowd=ann["iscrowd"], spatial_size=spatial_size - ) - for ann in anns - ] - ) - ), - areas=torch.as_tensor([ann["area"] for ann in anns]), - crowds=torch.as_tensor([ann["iscrowd"] for ann in anns], dtype=torch.bool), - bounding_boxes=BoundingBoxes( - [ann["bbox"] for ann in anns], - format="xywh", - spatial_size=spatial_size, - ), - labels=Label(labels, categories=self._categories), - super_categories=[self._category_to_super_category[self._categories[label]] for label in labels], - ann_ids=[ann["id"] for ann in anns], - ) - - def _decode_captions_ann(self, anns: List[Dict[str, Any]], image_meta: Dict[str, Any]) -> Dict[str, Any]: - return dict( - captions=[ann["caption"] for ann in anns], - ann_ids=[ann["id"] for ann in anns], - ) - - _ANN_DECODERS = OrderedDict( - [ - ("instances", _decode_instances_anns), - ("captions", _decode_captions_ann), - ] - ) - - _META_FILE_PATTERN = re.compile( - rf"(?P({'|'.join(_ANN_DECODERS.keys())}))_(?P[a-zA-Z]+)(?P\d+)[.]json" - ) - - def _filter_meta_files(self, data: Tuple[str, Any]) -> bool: - match = self._META_FILE_PATTERN.match(pathlib.Path(data[0]).name) - return bool( - match - and match["split"] == self._split - and match["year"] == self._year - and match["annotations"] == self._annotations - ) - - def _classify_meta(self, data: Tuple[str, Any]) -> Optional[int]: - key, _ = data - if key == "images": - return 0 - elif key == "annotations": - return 1 - else: - return None - - def _prepare_image(self, data: Tuple[str, BinaryIO]) -> Dict[str, Any]: - path, buffer = data - return dict( - path=path, - image=EncodedImage.from_file(buffer), - ) - - def _prepare_sample( - self, - data: Tuple[Tuple[List[Dict[str, Any]], Dict[str, Any]], Tuple[str, BinaryIO]], - ) -> Dict[str, Any]: - ann_data, image_data = data - anns, image_meta = ann_data - - sample = self._prepare_image(image_data) - # this method is only called if we have annotations - annotations = cast(str, self._annotations) - sample.update(self._ANN_DECODERS[annotations](self, anns, image_meta)) - return sample - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - images_dp, meta_dp = resource_dps - - if self._annotations is None: - dp = hint_shuffling(images_dp) - dp = hint_sharding(dp) - dp = hint_shuffling(dp) - return Mapper(dp, self._prepare_image) - - meta_dp = Filter(meta_dp, self._filter_meta_files) - meta_dp = JsonParser(meta_dp) - meta_dp = Mapper(meta_dp, getitem(1)) - meta_dp: IterDataPipe[Dict[str, Dict[str, Any]]] = MappingIterator(meta_dp) - images_meta_dp, anns_meta_dp = Demultiplexer( - meta_dp, - 2, - self._classify_meta, - drop_none=True, - buffer_size=INFINITE_BUFFER_SIZE, - ) - - images_meta_dp = Mapper(images_meta_dp, getitem(1)) - images_meta_dp = UnBatcher(images_meta_dp) - - anns_meta_dp = Mapper(anns_meta_dp, getitem(1)) - anns_meta_dp = UnBatcher(anns_meta_dp) - anns_meta_dp = Grouper(anns_meta_dp, group_key_fn=getitem("image_id"), buffer_size=INFINITE_BUFFER_SIZE) - anns_meta_dp = hint_shuffling(anns_meta_dp) - anns_meta_dp = hint_sharding(anns_meta_dp) - - anns_dp = IterKeyZipper( - anns_meta_dp, - images_meta_dp, - key_fn=getitem(0, "image_id"), - ref_key_fn=getitem("id"), - buffer_size=INFINITE_BUFFER_SIZE, - ) - dp = IterKeyZipper( - anns_dp, - images_dp, - key_fn=getitem(1, "file_name"), - ref_key_fn=path_accessor("name"), - buffer_size=INFINITE_BUFFER_SIZE, - ) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return { - ("train", "2017"): defaultdict(lambda: 118_287, instances=117_266), - ("train", "2014"): defaultdict(lambda: 82_783, instances=82_081), - ("val", "2017"): defaultdict(lambda: 5_000, instances=4_952), - ("val", "2014"): defaultdict(lambda: 40_504, instances=40_137), - }[(self._split, self._year)][ - self._annotations # type: ignore[index] - ] - - def _generate_categories(self) -> Tuple[Tuple[str, str]]: - self._annotations = "instances" - resources = self._resources() - - dp = resources[1].load(self._root) - dp = Filter(dp, self._filter_meta_files) - dp = JsonParser(dp) - - _, meta = next(iter(dp)) - # List[Tuple[super_category, id, category]] - label_data = [cast(Tuple[str, int, str], tuple(info.values())) for info in meta["categories"]] - - # COCO actually defines 91 categories, but only 80 of them have instances. Still, the category_id refers to the - # full set. To keep the labels dense, we fill the gaps with N/A. Note that there are only 10 gaps, so the total - # number of categories is 90 rather than 91. - _, ids, _ = zip(*label_data) - missing_ids = set(range(1, max(ids) + 1)) - set(ids) - label_data.extend([("N/A", id, "N/A") for id in missing_ids]) - - # We also add a background category to be used during segmentation. - label_data.append(("N/A", 0, "__background__")) - - super_categories, _, categories = zip(*sorted(label_data, key=lambda info: info[1])) - - return cast(Tuple[Tuple[str, str]], tuple(zip(categories, super_categories))) diff --git a/torchvision/prototype/datasets/_builtin/country211.categories b/torchvision/prototype/datasets/_builtin/country211.categories deleted file mode 100644 index 6fc3e99a185..00000000000 --- a/torchvision/prototype/datasets/_builtin/country211.categories +++ /dev/null @@ -1,211 +0,0 @@ -AD -AE -AF -AG -AI -AL -AM -AO -AQ -AR -AT -AU -AW -AX -AZ -BA -BB -BD -BE -BF -BG -BH -BJ -BM -BN -BO -BQ -BR -BS -BT -BW -BY -BZ -CA -CD -CF -CH -CI -CK -CL -CM -CN -CO -CR -CU -CV -CW -CY -CZ -DE -DK -DM -DO -DZ -EC -EE -EG -ES -ET -FI -FJ -FK -FO -FR -GA -GB -GD -GE -GF -GG -GH -GI -GL -GM -GP -GR -GS -GT -GU -GY -HK -HN -HR -HT -HU -ID -IE -IL -IM -IN -IQ -IR -IS -IT -JE -JM -JO -JP -KE -KG -KH -KN -KP -KR -KW -KY -KZ -LA -LB -LC -LI -LK -LR -LT -LU -LV -LY -MA -MC -MD -ME -MF -MG -MK -ML -MM -MN -MO -MQ -MR -MT -MU -MV -MW -MX -MY -MZ -NA -NC -NG -NI -NL -NO -NP -NZ -OM -PA -PE -PF -PG -PH -PK -PL -PR -PS -PT -PW -PY -QA -RE -RO -RS -RU -RW -SA -SB -SC -SD -SE -SG -SH -SI -SJ -SK -SL -SM -SN -SO -SS -SV -SX -SY -SZ -TG -TH -TJ -TL -TM -TN -TO -TR -TT -TW -TZ -UA -UG -US -UY -UZ -VA -VE -VG -VI -VN -VU -WS -XK -YE -ZA -ZM -ZW diff --git a/torchvision/prototype/datasets/_builtin/country211.py b/torchvision/prototype/datasets/_builtin/country211.py deleted file mode 100644 index 3308ddb99c9..00000000000 --- a/torchvision/prototype/datasets/_builtin/country211.py +++ /dev/null @@ -1,81 +0,0 @@ -import pathlib -from typing import Any, Dict, List, Tuple, Union - -from torchdata.datapipes.iter import Filter, IterDataPipe, Mapper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - hint_sharding, - hint_shuffling, - path_comparator, - read_categories_file, -) -from torchvision.prototype.tv_tensors import Label - -from .._api import register_dataset, register_info - -NAME = "country211" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict(categories=read_categories_file(NAME)) - - -@register_dataset(NAME) -class Country211(Dataset): - """ - - **homepage**: https://github.com/openai/CLIP/blob/main/data/country211.md - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "val", "test")) - self._split_folder_name = "valid" if split == "val" else split - - self._categories = _info()["categories"] - - super().__init__(root, skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - return [ - HttpResource( - "https://openaipublic.azureedge.net/clip/data/country211.tgz", - sha256="c011343cdc1296a8c31ff1d7129cf0b5e5b8605462cffd24f89266d6e6f4da3c", - ) - ] - - def _prepare_sample(self, data: Tuple[str, Any]) -> Dict[str, Any]: - path, buffer = data - category = pathlib.Path(path).parent.name - return dict( - label=Label.from_category(category, categories=self._categories), - path=path, - image=EncodedImage.from_file(buffer), - ) - - def _filter_split(self, data: Tuple[str, Any], *, split: str) -> bool: - return pathlib.Path(data[0]).parent.parent.name == split - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - dp = resource_dps[0] - dp = Filter(dp, path_comparator("parent.parent.name", self._split_folder_name)) - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return { - "train": 31_650, - "val": 10_550, - "test": 21_100, - }[self._split] - - def _generate_categories(self) -> List[str]: - resources = self._resources() - dp = resources[0].load(self._root) - return sorted({pathlib.Path(path).parent.name for path, _ in dp}) diff --git a/torchvision/prototype/datasets/_builtin/cub200.categories b/torchvision/prototype/datasets/_builtin/cub200.categories deleted file mode 100644 index f91754c930c..00000000000 --- a/torchvision/prototype/datasets/_builtin/cub200.categories +++ /dev/null @@ -1,200 +0,0 @@ -Black_footed_Albatross -Laysan_Albatross -Sooty_Albatross -Groove_billed_Ani -Crested_Auklet -Least_Auklet -Parakeet_Auklet -Rhinoceros_Auklet -Brewer_Blackbird -Red_winged_Blackbird -Rusty_Blackbird -Yellow_headed_Blackbird -Bobolink -Indigo_Bunting -Lazuli_Bunting -Painted_Bunting -Cardinal -Spotted_Catbird -Gray_Catbird -Yellow_breasted_Chat -Eastern_Towhee -Chuck_will_Widow -Brandt_Cormorant -Red_faced_Cormorant -Pelagic_Cormorant -Bronzed_Cowbird -Shiny_Cowbird -Brown_Creeper -American_Crow -Fish_Crow -Black_billed_Cuckoo -Mangrove_Cuckoo -Yellow_billed_Cuckoo -Gray_crowned_Rosy_Finch -Purple_Finch -Northern_Flicker -Acadian_Flycatcher -Great_Crested_Flycatcher -Least_Flycatcher -Olive_sided_Flycatcher -Scissor_tailed_Flycatcher -Vermilion_Flycatcher -Yellow_bellied_Flycatcher -Frigatebird -Northern_Fulmar -Gadwall -American_Goldfinch -European_Goldfinch -Boat_tailed_Grackle -Eared_Grebe -Horned_Grebe -Pied_billed_Grebe -Western_Grebe -Blue_Grosbeak -Evening_Grosbeak -Pine_Grosbeak -Rose_breasted_Grosbeak -Pigeon_Guillemot -California_Gull -Glaucous_winged_Gull -Heermann_Gull -Herring_Gull -Ivory_Gull -Ring_billed_Gull -Slaty_backed_Gull -Western_Gull -Anna_Hummingbird -Ruby_throated_Hummingbird -Rufous_Hummingbird -Green_Violetear -Long_tailed_Jaeger -Pomarine_Jaeger -Blue_Jay -Florida_Jay -Green_Jay -Dark_eyed_Junco -Tropical_Kingbird -Gray_Kingbird -Belted_Kingfisher -Green_Kingfisher -Pied_Kingfisher -Ringed_Kingfisher -White_breasted_Kingfisher -Red_legged_Kittiwake -Horned_Lark -Pacific_Loon -Mallard -Western_Meadowlark -Hooded_Merganser -Red_breasted_Merganser -Mockingbird -Nighthawk -Clark_Nutcracker -White_breasted_Nuthatch -Baltimore_Oriole -Hooded_Oriole -Orchard_Oriole -Scott_Oriole -Ovenbird -Brown_Pelican -White_Pelican -Western_Wood_Pewee -Sayornis -American_Pipit -Whip_poor_Will -Horned_Puffin -Common_Raven -White_necked_Raven -American_Redstart -Geococcyx -Loggerhead_Shrike -Great_Grey_Shrike -Baird_Sparrow -Black_throated_Sparrow -Brewer_Sparrow -Chipping_Sparrow -Clay_colored_Sparrow -House_Sparrow -Field_Sparrow -Fox_Sparrow -Grasshopper_Sparrow -Harris_Sparrow -Henslow_Sparrow -Le_Conte_Sparrow -Lincoln_Sparrow -Nelson_Sharp_tailed_Sparrow -Savannah_Sparrow -Seaside_Sparrow -Song_Sparrow -Tree_Sparrow -Vesper_Sparrow -White_crowned_Sparrow -White_throated_Sparrow -Cape_Glossy_Starling -Bank_Swallow -Barn_Swallow -Cliff_Swallow -Tree_Swallow -Scarlet_Tanager -Summer_Tanager -Artic_Tern -Black_Tern -Caspian_Tern -Common_Tern -Elegant_Tern -Forsters_Tern -Least_Tern -Green_tailed_Towhee -Brown_Thrasher -Sage_Thrasher -Black_capped_Vireo -Blue_headed_Vireo -Philadelphia_Vireo -Red_eyed_Vireo -Warbling_Vireo -White_eyed_Vireo -Yellow_throated_Vireo -Bay_breasted_Warbler -Black_and_white_Warbler -Black_throated_Blue_Warbler -Blue_winged_Warbler -Canada_Warbler -Cape_May_Warbler -Cerulean_Warbler -Chestnut_sided_Warbler -Golden_winged_Warbler -Hooded_Warbler -Kentucky_Warbler -Magnolia_Warbler -Mourning_Warbler -Myrtle_Warbler -Nashville_Warbler -Orange_crowned_Warbler -Palm_Warbler -Pine_Warbler -Prairie_Warbler -Prothonotary_Warbler -Swainson_Warbler -Tennessee_Warbler -Wilson_Warbler -Worm_eating_Warbler -Yellow_Warbler -Northern_Waterthrush -Louisiana_Waterthrush -Bohemian_Waxwing -Cedar_Waxwing -American_Three_toed_Woodpecker -Pileated_Woodpecker -Red_bellied_Woodpecker -Red_cockaded_Woodpecker -Red_headed_Woodpecker -Downy_Woodpecker -Bewick_Wren -Cactus_Wren -Carolina_Wren -House_Wren -Marsh_Wren -Rock_Wren -Winter_Wren -Common_Yellowthroat diff --git a/torchvision/prototype/datasets/_builtin/cub200.py b/torchvision/prototype/datasets/_builtin/cub200.py deleted file mode 100644 index 1230c88fb8d..00000000000 --- a/torchvision/prototype/datasets/_builtin/cub200.py +++ /dev/null @@ -1,265 +0,0 @@ -import csv -import functools -import pathlib -from typing import Any, BinaryIO, Callable, Dict, List, Optional, Tuple, Union - -import torch -from torchdata.datapipes.iter import ( - CSVDictParser, - CSVParser, - Demultiplexer, - Filter, - IterDataPipe, - IterKeyZipper, - LineReader, - Mapper, -) -from torchdata.datapipes.map import IterToMapConverter -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, GDriveResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_accessor, - path_comparator, - read_categories_file, - read_mat, -) -from torchvision.prototype.tv_tensors import Label -from torchvision.tv_tensors import BoundingBoxes - -from .._api import register_dataset, register_info - -csv.register_dialect("cub200", delimiter=" ") - - -NAME = "cub200" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict(categories=read_categories_file(NAME)) - - -@register_dataset(NAME) -class CUB200(Dataset): - """ - - **homepage**: http://www.vision.caltech.edu/visipedia/CUB-200.html - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - year: str = "2011", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "test")) - self._year = self._verify_str_arg(year, "year", ("2010", "2011")) - - self._categories = _info()["categories"] - - super().__init__( - root, - # TODO: this will only be available after https://github.com/pytorch/vision/pull/5473 - # dependencies=("scipy",), - skip_integrity_check=skip_integrity_check, - ) - - def _resources(self) -> List[OnlineResource]: - if self._year == "2011": - archive = GDriveResource( - "1hbzc_P1FuxMkcabkgn9ZKinBwW683j45", - file_name="CUB_200_2011.tgz", - sha256="0c685df5597a8b24909f6a7c9db6d11e008733779a671760afef78feb49bf081", - preprocess="decompress", - ) - segmentations = GDriveResource( - "1EamOKGLoTuZdtcVYbHMWNpkn3iAVj8TP", - file_name="segmentations.tgz", - sha256="dc77f6cffea0cbe2e41d4201115c8f29a6320ecb04fffd2444f51b8066e4b84f", - preprocess="decompress", - ) - return [archive, segmentations] - else: # self._year == "2010" - split = GDriveResource( - "1vZuZPqha0JjmwkdaS_XtYryE3Jf5Q1AC", - file_name="lists.tgz", - sha256="aeacbd5e3539ae84ea726e8a266a9a119c18f055cd80f3836d5eb4500b005428", - preprocess="decompress", - ) - images = GDriveResource( - "1GDr1OkoXdhaXWGA8S3MAq3a522Tak-nx", - file_name="images.tgz", - sha256="2a6d2246bbb9778ca03aa94e2e683ccb4f8821a36b7f235c0822e659d60a803e", - preprocess="decompress", - ) - anns = GDriveResource( - "16NsbTpMs5L6hT4hUJAmpW2u7wH326WTR", - file_name="annotations.tgz", - sha256="c17b7841c21a66aa44ba8fe92369cc95dfc998946081828b1d7b8a4b716805c1", - preprocess="decompress", - ) - return [split, images, anns] - - def _2011_classify_archive(self, data: Tuple[str, Any]) -> Optional[int]: - path = pathlib.Path(data[0]) - if path.parents[1].name == "images": - return 0 - elif path.name == "train_test_split.txt": - return 1 - elif path.name == "images.txt": - return 2 - elif path.name == "bounding_boxes.txt": - return 3 - else: - return None - - def _2011_extract_file_name(self, rel_posix_path: str) -> str: - return rel_posix_path.rsplit("/", maxsplit=1)[1] - - def _2011_filter_split(self, row: List[str]) -> bool: - _, split_id = row - return { - "0": "test", - "1": "train", - }[split_id] == self._split - - def _2011_segmentation_key(self, data: Tuple[str, Any]) -> str: - path = pathlib.Path(data[0]) - return path.with_suffix(".jpg").name - - def _2011_prepare_ann( - self, data: Tuple[str, Tuple[List[str], Tuple[str, BinaryIO]]], spatial_size: Tuple[int, int] - ) -> Dict[str, Any]: - _, (bounding_boxes_data, segmentation_data) = data - segmentation_path, segmentation_buffer = segmentation_data - return dict( - bounding_boxes=BoundingBoxes( - [float(part) for part in bounding_boxes_data[1:]], format="xywh", spatial_size=spatial_size - ), - segmentation_path=segmentation_path, - segmentation=EncodedImage.from_file(segmentation_buffer), - ) - - def _2010_split_key(self, data: str) -> str: - return data.rsplit("/", maxsplit=1)[1] - - def _2010_anns_key(self, data: Tuple[str, BinaryIO]) -> Tuple[str, Tuple[str, BinaryIO]]: - path = pathlib.Path(data[0]) - return path.with_suffix(".jpg").name, data - - def _2010_prepare_ann( - self, data: Tuple[str, Tuple[str, BinaryIO]], spatial_size: Tuple[int, int] - ) -> Dict[str, Any]: - _, (path, buffer) = data - content = read_mat(buffer) - return dict( - ann_path=path, - bounding_boxes=BoundingBoxes( - [int(content["bbox"][coord]) for coord in ("left", "bottom", "right", "top")], - format="xyxy", - spatial_size=spatial_size, - ), - segmentation=torch.as_tensor(content["seg"]), - ) - - def _prepare_sample( - self, - data: Tuple[Tuple[str, Tuple[str, BinaryIO]], Any], - *, - prepare_ann_fn: Callable[[Any, Tuple[int, int]], Dict[str, Any]], - ) -> Dict[str, Any]: - data, anns_data = data - _, image_data = data - path, buffer = image_data - - image = EncodedImage.from_file(buffer) - - return dict( - prepare_ann_fn(anns_data, image.spatial_size), - image=image, - label=Label( - int(pathlib.Path(path).parent.name.rsplit(".", 1)[0]) - 1, - categories=self._categories, - ), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - prepare_ann_fn: Callable - if self._year == "2011": - archive_dp, segmentations_dp = resource_dps - images_dp, split_dp, image_files_dp, bounding_boxes_dp = Demultiplexer( - archive_dp, 4, self._2011_classify_archive, drop_none=True, buffer_size=INFINITE_BUFFER_SIZE - ) - - image_files_dp = CSVParser(image_files_dp, dialect="cub200") - image_files_dp = Mapper(image_files_dp, self._2011_extract_file_name, input_col=1) - image_files_map = IterToMapConverter(image_files_dp) - - split_dp = CSVParser(split_dp, dialect="cub200") - split_dp = Filter(split_dp, self._2011_filter_split) - split_dp = Mapper(split_dp, getitem(0)) - split_dp = Mapper(split_dp, image_files_map.__getitem__) - - bounding_boxes_dp = CSVParser(bounding_boxes_dp, dialect="cub200") - bounding_boxes_dp = Mapper(bounding_boxes_dp, image_files_map.__getitem__, input_col=0) - - anns_dp = IterKeyZipper( - bounding_boxes_dp, - segmentations_dp, - key_fn=getitem(0), - ref_key_fn=self._2011_segmentation_key, - keep_key=True, - buffer_size=INFINITE_BUFFER_SIZE, - ) - - prepare_ann_fn = self._2011_prepare_ann - else: # self._year == "2010" - split_dp, images_dp, anns_dp = resource_dps - - split_dp = Filter(split_dp, path_comparator("name", f"{self._split}.txt")) - split_dp = LineReader(split_dp, decode=True, return_path=False) - split_dp = Mapper(split_dp, self._2010_split_key) - - anns_dp = Mapper(anns_dp, self._2010_anns_key) - - prepare_ann_fn = self._2010_prepare_ann - - split_dp = hint_shuffling(split_dp) - split_dp = hint_sharding(split_dp) - - dp = IterKeyZipper( - split_dp, - images_dp, - getitem(), - path_accessor("name"), - buffer_size=INFINITE_BUFFER_SIZE, - ) - dp = IterKeyZipper( - dp, - anns_dp, - getitem(0), - buffer_size=INFINITE_BUFFER_SIZE, - ) - return Mapper(dp, functools.partial(self._prepare_sample, prepare_ann_fn=prepare_ann_fn)) - - def __len__(self) -> int: - return { - ("train", "2010"): 3_000, - ("test", "2010"): 3_033, - ("train", "2011"): 5_994, - ("test", "2011"): 5_794, - }[(self._split, self._year)] - - def _generate_categories(self) -> List[str]: - self._year = "2011" - resources = self._resources() - - dp = resources[0].load(self._root) - dp = Filter(dp, path_comparator("name", "classes.txt")) - dp = CSVDictParser(dp, fieldnames=("label", "category"), dialect="cub200") - - return [row["category"].split(".")[1] for row in dp] diff --git a/torchvision/prototype/datasets/_builtin/dtd.categories b/torchvision/prototype/datasets/_builtin/dtd.categories deleted file mode 100644 index 7f3df8a2b00..00000000000 --- a/torchvision/prototype/datasets/_builtin/dtd.categories +++ /dev/null @@ -1,47 +0,0 @@ -banded -blotchy -braided -bubbly -bumpy -chequered -cobwebbed -cracked -crosshatched -crystalline -dotted -fibrous -flecked -freckled -frilly -gauzy -grid -grooved -honeycombed -interlaced -knitted -lacelike -lined -marbled -matted -meshed -paisley -perforated -pitted -pleated -polka-dotted -porous -potholed -scaly -smeared -spiralled -sprinkled -stained -stratified -striped -studded -swirly -veined -waffled -woven -wrinkled -zigzagged diff --git a/torchvision/prototype/datasets/_builtin/dtd.py b/torchvision/prototype/datasets/_builtin/dtd.py deleted file mode 100644 index 5b9922a8269..00000000000 --- a/torchvision/prototype/datasets/_builtin/dtd.py +++ /dev/null @@ -1,139 +0,0 @@ -import enum -import pathlib -from typing import Any, BinaryIO, Dict, List, Optional, Tuple, Union - -from torchdata.datapipes.iter import CSVParser, Demultiplexer, Filter, IterDataPipe, IterKeyZipper, LineReader, Mapper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_comparator, - read_categories_file, -) -from torchvision.prototype.tv_tensors import Label - -from .._api import register_dataset, register_info - - -NAME = "dtd" - - -class DTDDemux(enum.IntEnum): - SPLIT = 0 - JOINT_CATEGORIES = 1 - IMAGES = 2 - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict(categories=read_categories_file(NAME)) - - -@register_dataset(NAME) -class DTD(Dataset): - """DTD Dataset. - homepage="https://www.robots.ox.ac.uk/~vgg/data/dtd/", - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - fold: int = 1, - skip_validation_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", {"train", "val", "test"}) - - if not (1 <= fold <= 10): - raise ValueError(f"The fold parameter should be an integer in [1, 10]. Got {fold}") - self._fold = fold - - self._categories = _info()["categories"] - - super().__init__(root, skip_integrity_check=skip_validation_check) - - def _resources(self) -> List[OnlineResource]: - archive = HttpResource( - "https://www.robots.ox.ac.uk/~vgg/data/dtd/download/dtd-r1.0.1.tar.gz", - sha256="e42855a52a4950a3b59612834602aa253914755c95b0cff9ead6d07395f8e205", - preprocess="decompress", - ) - return [archive] - - def _classify_archive(self, data: Tuple[str, Any]) -> Optional[int]: - path = pathlib.Path(data[0]) - if path.parent.name == "labels": - if path.name == "labels_joint_anno.txt": - return DTDDemux.JOINT_CATEGORIES - - return DTDDemux.SPLIT - elif path.parents[1].name == "images": - return DTDDemux.IMAGES - else: - return None - - def _image_key_fn(self, data: Tuple[str, Any]) -> str: - path = pathlib.Path(data[0]) - # The split files contain hardcoded posix paths for the images, e.g. banded/banded_0001.jpg - return str(path.relative_to(path.parents[1]).as_posix()) - - def _prepare_sample(self, data: Tuple[Tuple[str, List[str]], Tuple[str, BinaryIO]]) -> Dict[str, Any]: - (_, joint_categories_data), image_data = data - _, *joint_categories = joint_categories_data - path, buffer = image_data - - category = pathlib.Path(path).parent.name - - return dict( - joint_categories={category for category in joint_categories if category}, - label=Label.from_category(category, categories=self._categories), - path=path, - image=EncodedImage.from_file(buffer), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - archive_dp = resource_dps[0] - - splits_dp, joint_categories_dp, images_dp = Demultiplexer( - archive_dp, 3, self._classify_archive, drop_none=True, buffer_size=INFINITE_BUFFER_SIZE - ) - - splits_dp = Filter(splits_dp, path_comparator("name", f"{self._split}{self._fold}.txt")) - splits_dp = LineReader(splits_dp, decode=True, return_path=False) - splits_dp = hint_shuffling(splits_dp) - splits_dp = hint_sharding(splits_dp) - - joint_categories_dp = CSVParser(joint_categories_dp, delimiter=" ") - - dp = IterKeyZipper( - splits_dp, - joint_categories_dp, - key_fn=getitem(), - ref_key_fn=getitem(0), - buffer_size=INFINITE_BUFFER_SIZE, - ) - dp = IterKeyZipper( - dp, - images_dp, - key_fn=getitem(0), - ref_key_fn=self._image_key_fn, - buffer_size=INFINITE_BUFFER_SIZE, - ) - return Mapper(dp, self._prepare_sample) - - def _filter_images(self, data: Tuple[str, Any]) -> bool: - return self._classify_archive(data) == DTDDemux.IMAGES - - def _generate_categories(self) -> List[str]: - resources = self._resources() - - dp = resources[0].load(self._root) - dp = Filter(dp, self._filter_images) - - return sorted({pathlib.Path(path).parent.name for path, _ in dp}) - - def __len__(self) -> int: - return 1_880 # All splits have the same length diff --git a/torchvision/prototype/datasets/_builtin/eurosat.py b/torchvision/prototype/datasets/_builtin/eurosat.py deleted file mode 100644 index 747f0320e86..00000000000 --- a/torchvision/prototype/datasets/_builtin/eurosat.py +++ /dev/null @@ -1,66 +0,0 @@ -import pathlib -from typing import Any, Dict, List, Tuple, Union - -from torchdata.datapipes.iter import IterDataPipe, Mapper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import hint_sharding, hint_shuffling -from torchvision.prototype.tv_tensors import Label - -from .._api import register_dataset, register_info - -NAME = "eurosat" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict( - categories=( - "AnnualCrop", - "Forest", - "HerbaceousVegetation", - "Highway", - "Industrial", - "Pasture", - "PermanentCrop", - "Residential", - "River", - "SeaLake", - ) - ) - - -@register_dataset(NAME) -class EuroSAT(Dataset): - """EuroSAT Dataset. - homepage="https://github.com/phelber/eurosat", - """ - - def __init__(self, root: Union[str, pathlib.Path], *, skip_integrity_check: bool = False) -> None: - self._categories = _info()["categories"] - super().__init__(root, skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - return [ - HttpResource( - "https://madm.dfki.de/files/sentinel/EuroSAT.zip", - sha256="8ebea626349354c5328b142b96d0430e647051f26efc2dc974c843f25ecf70bd", - ) - ] - - def _prepare_sample(self, data: Tuple[str, Any]) -> Dict[str, Any]: - path, buffer = data - category = pathlib.Path(path).parent.name - return dict( - label=Label.from_category(category, categories=self._categories), - path=path, - image=EncodedImage.from_file(buffer), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - dp = resource_dps[0] - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return 27_000 diff --git a/torchvision/prototype/datasets/_builtin/fer2013.py b/torchvision/prototype/datasets/_builtin/fer2013.py deleted file mode 100644 index e6194ab01bd..00000000000 --- a/torchvision/prototype/datasets/_builtin/fer2013.py +++ /dev/null @@ -1,64 +0,0 @@ -import pathlib -from typing import Any, Dict, List, Union - -import torch -from torchdata.datapipes.iter import CSVDictParser, IterDataPipe, Mapper -from torchvision.prototype.datasets.utils import Dataset, KaggleDownloadResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import hint_sharding, hint_shuffling -from torchvision.prototype.tv_tensors import Label -from torchvision.tv_tensors import Image - -from .._api import register_dataset, register_info - -NAME = "fer2013" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict(categories=("angry", "disgust", "fear", "happy", "sad", "surprise", "neutral")) - - -@register_dataset(NAME) -class FER2013(Dataset): - """FER 2013 Dataset - homepage="https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge" - """ - - def __init__( - self, root: Union[str, pathlib.Path], *, split: str = "train", skip_integrity_check: bool = False - ) -> None: - self._split = self._verify_str_arg(split, "split", {"train", "test"}) - self._categories = _info()["categories"] - - super().__init__(root, skip_integrity_check=skip_integrity_check) - - _CHECKSUMS = { - "train": "a2b7c9360cc0b38d21187e5eece01c2799fce5426cdeecf746889cc96cda2d10", - "test": "dec8dfe8021e30cd6704b85ec813042b4a5d99d81cb55e023291a94104f575c3", - } - - def _resources(self) -> List[OnlineResource]: - archive = KaggleDownloadResource( - "https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge", - file_name=f"{self._split}.csv.zip", - sha256=self._CHECKSUMS[self._split], - ) - return [archive] - - def _prepare_sample(self, data: Dict[str, Any]) -> Dict[str, Any]: - label_id = data.get("emotion") - - return dict( - image=Image(torch.tensor([int(idx) for idx in data["pixels"].split()], dtype=torch.uint8).reshape(48, 48)), - label=Label(int(label_id), categories=self._categories) if label_id is not None else None, - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - dp = resource_dps[0] - dp = CSVDictParser(dp) - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return 28_709 if self._split == "train" else 3_589 diff --git a/torchvision/prototype/datasets/_builtin/food101.categories b/torchvision/prototype/datasets/_builtin/food101.categories deleted file mode 100644 index 59f252ddff4..00000000000 --- a/torchvision/prototype/datasets/_builtin/food101.categories +++ /dev/null @@ -1,101 +0,0 @@ -apple_pie -baby_back_ribs -baklava -beef_carpaccio -beef_tartare -beet_salad -beignets -bibimbap -bread_pudding -breakfast_burrito -bruschetta -caesar_salad -cannoli -caprese_salad -carrot_cake -ceviche -cheesecake -cheese_plate -chicken_curry -chicken_quesadilla -chicken_wings -chocolate_cake -chocolate_mousse -churros -clam_chowder -club_sandwich -crab_cakes -creme_brulee -croque_madame -cup_cakes -deviled_eggs -donuts -dumplings -edamame -eggs_benedict -escargots -falafel -filet_mignon -fish_and_chips -foie_gras -french_fries -french_onion_soup -french_toast -fried_calamari -fried_rice -frozen_yogurt -garlic_bread -gnocchi -greek_salad -grilled_cheese_sandwich -grilled_salmon -guacamole -gyoza -hamburger -hot_and_sour_soup -hot_dog -huevos_rancheros -hummus -ice_cream -lasagna -lobster_bisque -lobster_roll_sandwich -macaroni_and_cheese -macarons -miso_soup -mussels -nachos -omelette -onion_rings -oysters -pad_thai -paella -pancakes -panna_cotta -peking_duck -pho -pizza -pork_chop -poutine -prime_rib -pulled_pork_sandwich -ramen -ravioli -red_velvet_cake -risotto -samosa -sashimi -scallops -seaweed_salad -shrimp_and_grits -spaghetti_bolognese -spaghetti_carbonara -spring_rolls -steak -strawberry_shortcake -sushi -tacos -takoyaki -tiramisu -tuna_tartare -waffles diff --git a/torchvision/prototype/datasets/_builtin/food101.py b/torchvision/prototype/datasets/_builtin/food101.py deleted file mode 100644 index ed446f342e9..00000000000 --- a/torchvision/prototype/datasets/_builtin/food101.py +++ /dev/null @@ -1,97 +0,0 @@ -from pathlib import Path -from typing import Any, BinaryIO, Dict, List, Optional, Tuple, Union - -from torchdata.datapipes.iter import Demultiplexer, Filter, IterDataPipe, IterKeyZipper, LineReader, Mapper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_comparator, - read_categories_file, -) -from torchvision.prototype.tv_tensors import Label - -from .._api import register_dataset, register_info - - -NAME = "food101" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict(categories=read_categories_file(NAME)) - - -@register_dataset(NAME) -class Food101(Dataset): - """Food 101 dataset - homepage="https://data.vision.ee.ethz.ch/cvl/datasets_extra/food-101", - """ - - def __init__(self, root: Union[str, Path], *, split: str = "train", skip_integrity_check: bool = False) -> None: - self._split = self._verify_str_arg(split, "split", {"train", "test"}) - self._categories = _info()["categories"] - - super().__init__(root, skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - return [ - HttpResource( - url="http://data.vision.ee.ethz.ch/cvl/food-101.tar.gz", - sha256="d97d15e438b7f4498f96086a4f7e2fa42a32f2712e87d3295441b2b6314053a4", - preprocess="decompress", - ) - ] - - def _classify_archive(self, data: Tuple[str, Any]) -> Optional[int]: - path = Path(data[0]) - if path.parents[1].name == "images": - return 0 - elif path.parents[0].name == "meta": - return 1 - else: - return None - - def _prepare_sample(self, data: Tuple[str, Tuple[str, BinaryIO]]) -> Dict[str, Any]: - id, (path, buffer) = data - return dict( - label=Label.from_category(id.split("/", 1)[0], categories=self._categories), - path=path, - image=EncodedImage.from_file(buffer), - ) - - def _image_key(self, data: Tuple[str, Any]) -> str: - path = Path(data[0]) - return path.relative_to(path.parents[1]).with_suffix("").as_posix() - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - archive_dp = resource_dps[0] - images_dp, split_dp = Demultiplexer( - archive_dp, 2, self._classify_archive, drop_none=True, buffer_size=INFINITE_BUFFER_SIZE - ) - split_dp = Filter(split_dp, path_comparator("name", f"{self._split}.txt")) - split_dp = LineReader(split_dp, decode=True, return_path=False) - split_dp = hint_sharding(split_dp) - split_dp = hint_shuffling(split_dp) - - dp = IterKeyZipper( - split_dp, - images_dp, - key_fn=getitem(), - ref_key_fn=self._image_key, - buffer_size=INFINITE_BUFFER_SIZE, - ) - - return Mapper(dp, self._prepare_sample) - - def _generate_categories(self) -> List[str]: - resources = self._resources() - dp = resources[0].load(self._root) - dp = Filter(dp, path_comparator("name", "classes.txt")) - dp = LineReader(dp, decode=True, return_path=False) - return list(dp) - - def __len__(self) -> int: - return 75_750 if self._split == "train" else 25_250 diff --git a/torchvision/prototype/datasets/_builtin/gtsrb.py b/torchvision/prototype/datasets/_builtin/gtsrb.py deleted file mode 100644 index b31793c0fa9..00000000000 --- a/torchvision/prototype/datasets/_builtin/gtsrb.py +++ /dev/null @@ -1,112 +0,0 @@ -import pathlib -from typing import Any, Dict, List, Optional, Tuple, Union - -from torchdata.datapipes.iter import CSVDictParser, Demultiplexer, Filter, IterDataPipe, Mapper, Zipper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_comparator, -) -from torchvision.prototype.tv_tensors import Label -from torchvision.tv_tensors import BoundingBoxes - -from .._api import register_dataset, register_info - -NAME = "gtsrb" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict( - categories=[f"{label:05d}" for label in range(43)], - ) - - -@register_dataset(NAME) -class GTSRB(Dataset): - """GTSRB Dataset - - homepage="https://benchmark.ini.rub.de" - """ - - def __init__( - self, root: Union[str, pathlib.Path], *, split: str = "train", skip_integrity_check: bool = False - ) -> None: - self._split = self._verify_str_arg(split, "split", {"train", "test"}) - self._categories = _info()["categories"] - super().__init__(root, skip_integrity_check=skip_integrity_check) - - _URL_ROOT = "https://sid.erda.dk/public/archives/daaeac0d7ce1152aea9b61d9f1e19370/" - _URLS = { - "train": f"{_URL_ROOT}GTSRB-Training_fixed.zip", - "test": f"{_URL_ROOT}GTSRB_Final_Test_Images.zip", - "test_ground_truth": f"{_URL_ROOT}GTSRB_Final_Test_GT.zip", - } - _CHECKSUMS = { - "train": "df4144942083645bd60b594de348aa6930126c3e0e5de09e39611630abf8455a", - "test": "48ba6fab7e877eb64eaf8de99035b0aaecfbc279bee23e35deca4ac1d0a837fa", - "test_ground_truth": "f94e5a7614d75845c74c04ddb26b8796b9e483f43541dd95dd5b726504e16d6d", - } - - def _resources(self) -> List[OnlineResource]: - rsrcs: List[OnlineResource] = [HttpResource(self._URLS[self._split], sha256=self._CHECKSUMS[self._split])] - - if self._split == "test": - rsrcs.append( - HttpResource( - self._URLS["test_ground_truth"], - sha256=self._CHECKSUMS["test_ground_truth"], - ) - ) - - return rsrcs - - def _classify_train_archive(self, data: Tuple[str, Any]) -> Optional[int]: - path = pathlib.Path(data[0]) - if path.suffix == ".ppm": - return 0 - elif path.suffix == ".csv": - return 1 - else: - return None - - def _prepare_sample(self, data: Tuple[Tuple[str, Any], Dict[str, Any]]) -> Dict[str, Any]: - (path, buffer), csv_info = data - label = int(csv_info["ClassId"]) - - bounding_boxes = BoundingBoxes( - [int(csv_info[k]) for k in ("Roi.X1", "Roi.Y1", "Roi.X2", "Roi.Y2")], - format="xyxy", - spatial_size=(int(csv_info["Height"]), int(csv_info["Width"])), - ) - - return { - "path": path, - "image": EncodedImage.from_file(buffer), - "label": Label(label, categories=self._categories), - "bounding_boxes": bounding_boxes, - } - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - if self._split == "train": - images_dp, ann_dp = Demultiplexer( - resource_dps[0], 2, self._classify_train_archive, drop_none=True, buffer_size=INFINITE_BUFFER_SIZE - ) - else: - images_dp, ann_dp = resource_dps - images_dp = Filter(images_dp, path_comparator("suffix", ".ppm")) - - # The order of the image files in the .zip archives perfectly match the order of the entries in the - # (possibly concatenated) .csv files. So we're able to use Zipper here instead of a IterKeyZipper. - ann_dp = CSVDictParser(ann_dp, delimiter=";") - dp = Zipper(images_dp, ann_dp) - - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return 26_640 if self._split == "train" else 12_630 diff --git a/torchvision/prototype/datasets/_builtin/imagenet.categories b/torchvision/prototype/datasets/_builtin/imagenet.categories deleted file mode 100644 index 7b6006ff57f..00000000000 --- a/torchvision/prototype/datasets/_builtin/imagenet.categories +++ /dev/null @@ -1,1000 +0,0 @@ -tench,n01440764 -goldfish,n01443537 -great white shark,n01484850 -tiger shark,n01491361 -hammerhead,n01494475 -electric ray,n01496331 -stingray,n01498041 -cock,n01514668 -hen,n01514859 -ostrich,n01518878 -brambling,n01530575 -goldfinch,n01531178 -house finch,n01532829 -junco,n01534433 -indigo bunting,n01537544 -robin,n01558993 -bulbul,n01560419 -jay,n01580077 -magpie,n01582220 -chickadee,n01592084 -water ouzel,n01601694 -kite,n01608432 -bald eagle,n01614925 -vulture,n01616318 -great grey owl,n01622779 -European fire salamander,n01629819 -common newt,n01630670 -eft,n01631663 -spotted salamander,n01632458 -axolotl,n01632777 -bullfrog,n01641577 -tree frog,n01644373 -tailed frog,n01644900 -loggerhead,n01664065 -leatherback turtle,n01665541 -mud turtle,n01667114 -terrapin,n01667778 -box turtle,n01669191 -banded gecko,n01675722 -common iguana,n01677366 -American chameleon,n01682714 -whiptail,n01685808 -agama,n01687978 -frilled lizard,n01688243 -alligator lizard,n01689811 -Gila monster,n01692333 -green lizard,n01693334 -African chameleon,n01694178 -Komodo dragon,n01695060 -African crocodile,n01697457 -American alligator,n01698640 -triceratops,n01704323 -thunder snake,n01728572 -ringneck snake,n01728920 -hognose snake,n01729322 -green snake,n01729977 -king snake,n01734418 -garter snake,n01735189 -water snake,n01737021 -vine snake,n01739381 -night snake,n01740131 -boa constrictor,n01742172 -rock python,n01744401 -Indian cobra,n01748264 -green mamba,n01749939 -sea snake,n01751748 -horned viper,n01753488 -diamondback,n01755581 -sidewinder,n01756291 -trilobite,n01768244 -harvestman,n01770081 -scorpion,n01770393 -black and gold garden spider,n01773157 -barn spider,n01773549 -garden spider,n01773797 -black widow,n01774384 -tarantula,n01774750 -wolf spider,n01775062 -tick,n01776313 -centipede,n01784675 -black grouse,n01795545 -ptarmigan,n01796340 -ruffed grouse,n01797886 -prairie chicken,n01798484 -peacock,n01806143 -quail,n01806567 -partridge,n01807496 -African grey,n01817953 -macaw,n01818515 -sulphur-crested cockatoo,n01819313 -lorikeet,n01820546 -coucal,n01824575 -bee eater,n01828970 -hornbill,n01829413 -hummingbird,n01833805 -jacamar,n01843065 -toucan,n01843383 -drake,n01847000 -red-breasted merganser,n01855032 -goose,n01855672 -black swan,n01860187 -tusker,n01871265 -echidna,n01872401 -platypus,n01873310 -wallaby,n01877812 -koala,n01882714 -wombat,n01883070 -jellyfish,n01910747 -sea anemone,n01914609 -brain coral,n01917289 -flatworm,n01924916 -nematode,n01930112 -conch,n01943899 -snail,n01944390 -slug,n01945685 -sea slug,n01950731 -chiton,n01955084 -chambered nautilus,n01968897 -Dungeness crab,n01978287 -rock crab,n01978455 -fiddler crab,n01980166 -king crab,n01981276 -American lobster,n01983481 -spiny lobster,n01984695 -crayfish,n01985128 -hermit crab,n01986214 -isopod,n01990800 -white stork,n02002556 -black stork,n02002724 -spoonbill,n02006656 -flamingo,n02007558 -little blue heron,n02009229 -American egret,n02009912 -bittern,n02011460 -crane,n02012849 -limpkin,n02013706 -European gallinule,n02017213 -American coot,n02018207 -bustard,n02018795 -ruddy turnstone,n02025239 -red-backed sandpiper,n02027492 -redshank,n02028035 -dowitcher,n02033041 -oystercatcher,n02037110 -pelican,n02051845 -king penguin,n02056570 -albatross,n02058221 -grey whale,n02066245 -killer whale,n02071294 -dugong,n02074367 -sea lion,n02077923 -Chihuahua,n02085620 -Japanese spaniel,n02085782 -Maltese dog,n02085936 -Pekinese,n02086079 -Shih-Tzu,n02086240 -Blenheim spaniel,n02086646 -papillon,n02086910 -toy terrier,n02087046 -Rhodesian ridgeback,n02087394 -Afghan hound,n02088094 -basset,n02088238 -beagle,n02088364 -bloodhound,n02088466 -bluetick,n02088632 -black-and-tan coonhound,n02089078 -Walker hound,n02089867 -English foxhound,n02089973 -redbone,n02090379 -borzoi,n02090622 -Irish wolfhound,n02090721 -Italian greyhound,n02091032 -whippet,n02091134 -Ibizan hound,n02091244 -Norwegian elkhound,n02091467 -otterhound,n02091635 -Saluki,n02091831 -Scottish deerhound,n02092002 -Weimaraner,n02092339 -Staffordshire bullterrier,n02093256 -American Staffordshire terrier,n02093428 -Bedlington terrier,n02093647 -Border terrier,n02093754 -Kerry blue terrier,n02093859 -Irish terrier,n02093991 -Norfolk terrier,n02094114 -Norwich terrier,n02094258 -Yorkshire terrier,n02094433 -wire-haired fox terrier,n02095314 -Lakeland terrier,n02095570 -Sealyham terrier,n02095889 -Airedale,n02096051 -cairn,n02096177 -Australian terrier,n02096294 -Dandie Dinmont,n02096437 -Boston bull,n02096585 -miniature schnauzer,n02097047 -giant schnauzer,n02097130 -standard schnauzer,n02097209 -Scotch terrier,n02097298 -Tibetan terrier,n02097474 -silky terrier,n02097658 -soft-coated wheaten terrier,n02098105 -West Highland white terrier,n02098286 -Lhasa,n02098413 -flat-coated retriever,n02099267 -curly-coated retriever,n02099429 -golden retriever,n02099601 -Labrador retriever,n02099712 -Chesapeake Bay retriever,n02099849 -German short-haired pointer,n02100236 -vizsla,n02100583 -English setter,n02100735 -Irish setter,n02100877 -Gordon setter,n02101006 -Brittany spaniel,n02101388 -clumber,n02101556 -English springer,n02102040 -Welsh springer spaniel,n02102177 -cocker spaniel,n02102318 -Sussex spaniel,n02102480 -Irish water spaniel,n02102973 -kuvasz,n02104029 -schipperke,n02104365 -groenendael,n02105056 -malinois,n02105162 -briard,n02105251 -kelpie,n02105412 -komondor,n02105505 -Old English sheepdog,n02105641 -Shetland sheepdog,n02105855 -collie,n02106030 -Border collie,n02106166 -Bouvier des Flandres,n02106382 -Rottweiler,n02106550 -German shepherd,n02106662 -Doberman,n02107142 -miniature pinscher,n02107312 -Greater Swiss Mountain dog,n02107574 -Bernese mountain dog,n02107683 -Appenzeller,n02107908 -EntleBucher,n02108000 -boxer,n02108089 -bull mastiff,n02108422 -Tibetan mastiff,n02108551 -French bulldog,n02108915 -Great Dane,n02109047 -Saint Bernard,n02109525 -Eskimo dog,n02109961 -malamute,n02110063 -Siberian husky,n02110185 -dalmatian,n02110341 -affenpinscher,n02110627 -basenji,n02110806 -pug,n02110958 -Leonberg,n02111129 -Newfoundland,n02111277 -Great Pyrenees,n02111500 -Samoyed,n02111889 -Pomeranian,n02112018 -chow,n02112137 -keeshond,n02112350 -Brabancon griffon,n02112706 -Pembroke,n02113023 -Cardigan,n02113186 -toy poodle,n02113624 -miniature poodle,n02113712 -standard poodle,n02113799 -Mexican hairless,n02113978 -timber wolf,n02114367 -white wolf,n02114548 -red wolf,n02114712 -coyote,n02114855 -dingo,n02115641 -dhole,n02115913 -African hunting dog,n02116738 -hyena,n02117135 -red fox,n02119022 -kit fox,n02119789 -Arctic fox,n02120079 -grey fox,n02120505 -tabby,n02123045 -tiger cat,n02123159 -Persian cat,n02123394 -Siamese cat,n02123597 -Egyptian cat,n02124075 -cougar,n02125311 -lynx,n02127052 -leopard,n02128385 -snow leopard,n02128757 -jaguar,n02128925 -lion,n02129165 -tiger,n02129604 -cheetah,n02130308 -brown bear,n02132136 -American black bear,n02133161 -ice bear,n02134084 -sloth bear,n02134418 -mongoose,n02137549 -meerkat,n02138441 -tiger beetle,n02165105 -ladybug,n02165456 -ground beetle,n02167151 -long-horned beetle,n02168699 -leaf beetle,n02169497 -dung beetle,n02172182 -rhinoceros beetle,n02174001 -weevil,n02177972 -fly,n02190166 -bee,n02206856 -ant,n02219486 -grasshopper,n02226429 -cricket,n02229544 -walking stick,n02231487 -cockroach,n02233338 -mantis,n02236044 -cicada,n02256656 -leafhopper,n02259212 -lacewing,n02264363 -dragonfly,n02268443 -damselfly,n02268853 -admiral,n02276258 -ringlet,n02277742 -monarch,n02279972 -cabbage butterfly,n02280649 -sulphur butterfly,n02281406 -lycaenid,n02281787 -starfish,n02317335 -sea urchin,n02319095 -sea cucumber,n02321529 -wood rabbit,n02325366 -hare,n02326432 -Angora,n02328150 -hamster,n02342885 -porcupine,n02346627 -fox squirrel,n02356798 -marmot,n02361337 -beaver,n02363005 -guinea pig,n02364673 -sorrel,n02389026 -zebra,n02391049 -hog,n02395406 -wild boar,n02396427 -warthog,n02397096 -hippopotamus,n02398521 -ox,n02403003 -water buffalo,n02408429 -bison,n02410509 -ram,n02412080 -bighorn,n02415577 -ibex,n02417914 -hartebeest,n02422106 -impala,n02422699 -gazelle,n02423022 -Arabian camel,n02437312 -llama,n02437616 -weasel,n02441942 -mink,n02442845 -polecat,n02443114 -black-footed ferret,n02443484 -otter,n02444819 -skunk,n02445715 -badger,n02447366 -armadillo,n02454379 -three-toed sloth,n02457408 -orangutan,n02480495 -gorilla,n02480855 -chimpanzee,n02481823 -gibbon,n02483362 -siamang,n02483708 -guenon,n02484975 -patas,n02486261 -baboon,n02486410 -macaque,n02487347 -langur,n02488291 -colobus,n02488702 -proboscis monkey,n02489166 -marmoset,n02490219 -capuchin,n02492035 -howler monkey,n02492660 -titi,n02493509 -spider monkey,n02493793 -squirrel monkey,n02494079 -Madagascar cat,n02497673 -indri,n02500267 -Indian elephant,n02504013 -African elephant,n02504458 -lesser panda,n02509815 -giant panda,n02510455 -barracouta,n02514041 -eel,n02526121 -coho,n02536864 -rock beauty,n02606052 -anemone fish,n02607072 -sturgeon,n02640242 -gar,n02641379 -lionfish,n02643566 -puffer,n02655020 -abacus,n02666196 -abaya,n02667093 -academic gown,n02669723 -accordion,n02672831 -acoustic guitar,n02676566 -aircraft carrier,n02687172 -airliner,n02690373 -airship,n02692877 -altar,n02699494 -ambulance,n02701002 -amphibian,n02704792 -analog clock,n02708093 -apiary,n02727426 -apron,n02730930 -ashcan,n02747177 -assault rifle,n02749479 -backpack,n02769748 -bakery,n02776631 -balance beam,n02777292 -balloon,n02782093 -ballpoint,n02783161 -Band Aid,n02786058 -banjo,n02787622 -bannister,n02788148 -barbell,n02790996 -barber chair,n02791124 -barbershop,n02791270 -barn,n02793495 -barometer,n02794156 -barrel,n02795169 -barrow,n02797295 -baseball,n02799071 -basketball,n02802426 -bassinet,n02804414 -bassoon,n02804610 -bathing cap,n02807133 -bath towel,n02808304 -bathtub,n02808440 -beach wagon,n02814533 -beacon,n02814860 -beaker,n02815834 -bearskin,n02817516 -beer bottle,n02823428 -beer glass,n02823750 -bell cote,n02825657 -bib,n02834397 -bicycle-built-for-two,n02835271 -bikini,n02837789 -binder,n02840245 -binoculars,n02841315 -birdhouse,n02843684 -boathouse,n02859443 -bobsled,n02860847 -bolo tie,n02865351 -bonnet,n02869837 -bookcase,n02870880 -bookshop,n02871525 -bottlecap,n02877765 -bow,n02879718 -bow tie,n02883205 -brass,n02892201 -brassiere,n02892767 -breakwater,n02894605 -breastplate,n02895154 -broom,n02906734 -bucket,n02909870 -buckle,n02910353 -bulletproof vest,n02916936 -bullet train,n02917067 -butcher shop,n02927161 -cab,n02930766 -caldron,n02939185 -candle,n02948072 -cannon,n02950826 -canoe,n02951358 -can opener,n02951585 -cardigan,n02963159 -car mirror,n02965783 -carousel,n02966193 -carpenter's kit,n02966687 -carton,n02971356 -car wheel,n02974003 -cash machine,n02977058 -cassette,n02978881 -cassette player,n02979186 -castle,n02980441 -catamaran,n02981792 -CD player,n02988304 -cello,n02992211 -cellular telephone,n02992529 -chain,n02999410 -chainlink fence,n03000134 -chain mail,n03000247 -chain saw,n03000684 -chest,n03014705 -chiffonier,n03016953 -chime,n03017168 -china cabinet,n03018349 -Christmas stocking,n03026506 -church,n03028079 -cinema,n03032252 -cleaver,n03041632 -cliff dwelling,n03042490 -cloak,n03045698 -clog,n03047690 -cocktail shaker,n03062245 -coffee mug,n03063599 -coffeepot,n03063689 -coil,n03065424 -combination lock,n03075370 -computer keyboard,n03085013 -confectionery,n03089624 -container ship,n03095699 -convertible,n03100240 -corkscrew,n03109150 -cornet,n03110669 -cowboy boot,n03124043 -cowboy hat,n03124170 -cradle,n03125729 -construction crane,n03126707 -crash helmet,n03127747 -crate,n03127925 -crib,n03131574 -Crock Pot,n03133878 -croquet ball,n03134739 -crutch,n03141823 -cuirass,n03146219 -dam,n03160309 -desk,n03179701 -desktop computer,n03180011 -dial telephone,n03187595 -diaper,n03188531 -digital clock,n03196217 -digital watch,n03197337 -dining table,n03201208 -dishrag,n03207743 -dishwasher,n03207941 -disk brake,n03208938 -dock,n03216828 -dogsled,n03218198 -dome,n03220513 -doormat,n03223299 -drilling platform,n03240683 -drum,n03249569 -drumstick,n03250847 -dumbbell,n03255030 -Dutch oven,n03259280 -electric fan,n03271574 -electric guitar,n03272010 -electric locomotive,n03272562 -entertainment center,n03290653 -envelope,n03291819 -espresso maker,n03297495 -face powder,n03314780 -feather boa,n03325584 -file,n03337140 -fireboat,n03344393 -fire engine,n03345487 -fire screen,n03347037 -flagpole,n03355925 -flute,n03372029 -folding chair,n03376595 -football helmet,n03379051 -forklift,n03384352 -fountain,n03388043 -fountain pen,n03388183 -four-poster,n03388549 -freight car,n03393912 -French horn,n03394916 -frying pan,n03400231 -fur coat,n03404251 -garbage truck,n03417042 -gasmask,n03424325 -gas pump,n03425413 -goblet,n03443371 -go-kart,n03444034 -golf ball,n03445777 -golfcart,n03445924 -gondola,n03447447 -gong,n03447721 -gown,n03450230 -grand piano,n03452741 -greenhouse,n03457902 -grille,n03459775 -grocery store,n03461385 -guillotine,n03467068 -hair slide,n03476684 -hair spray,n03476991 -half track,n03478589 -hammer,n03481172 -hamper,n03482405 -hand blower,n03483316 -hand-held computer,n03485407 -handkerchief,n03485794 -hard disc,n03492542 -harmonica,n03494278 -harp,n03495258 -harvester,n03496892 -hatchet,n03498962 -holster,n03527444 -home theater,n03529860 -honeycomb,n03530642 -hook,n03532672 -hoopskirt,n03534580 -horizontal bar,n03535780 -horse cart,n03538406 -hourglass,n03544143 -iPod,n03584254 -iron,n03584829 -jack-o'-lantern,n03590841 -jean,n03594734 -jeep,n03594945 -jersey,n03595614 -jigsaw puzzle,n03598930 -jinrikisha,n03599486 -joystick,n03602883 -kimono,n03617480 -knee pad,n03623198 -knot,n03627232 -lab coat,n03630383 -ladle,n03633091 -lampshade,n03637318 -laptop,n03642806 -lawn mower,n03649909 -lens cap,n03657121 -letter opener,n03658185 -library,n03661043 -lifeboat,n03662601 -lighter,n03666591 -limousine,n03670208 -liner,n03673027 -lipstick,n03676483 -Loafer,n03680355 -lotion,n03690938 -loudspeaker,n03691459 -loupe,n03692522 -lumbermill,n03697007 -magnetic compass,n03706229 -mailbag,n03709823 -mailbox,n03710193 -maillot,n03710637 -tank suit,n03710721 -manhole cover,n03717622 -maraca,n03720891 -marimba,n03721384 -mask,n03724870 -matchstick,n03729826 -maypole,n03733131 -maze,n03733281 -measuring cup,n03733805 -medicine chest,n03742115 -megalith,n03743016 -microphone,n03759954 -microwave,n03761084 -military uniform,n03763968 -milk can,n03764736 -minibus,n03769881 -miniskirt,n03770439 -minivan,n03770679 -missile,n03773504 -mitten,n03775071 -mixing bowl,n03775546 -mobile home,n03776460 -Model T,n03777568 -modem,n03777754 -monastery,n03781244 -monitor,n03782006 -moped,n03785016 -mortar,n03786901 -mortarboard,n03787032 -mosque,n03788195 -mosquito net,n03788365 -motor scooter,n03791053 -mountain bike,n03792782 -mountain tent,n03792972 -mouse,n03793489 -mousetrap,n03794056 -moving van,n03796401 -muzzle,n03803284 -nail,n03804744 -neck brace,n03814639 -necklace,n03814906 -nipple,n03825788 -notebook,n03832673 -obelisk,n03837869 -oboe,n03838899 -ocarina,n03840681 -odometer,n03841143 -oil filter,n03843555 -organ,n03854065 -oscilloscope,n03857828 -overskirt,n03866082 -oxcart,n03868242 -oxygen mask,n03868863 -packet,n03871628 -paddle,n03873416 -paddlewheel,n03874293 -padlock,n03874599 -paintbrush,n03876231 -pajama,n03877472 -palace,n03877845 -panpipe,n03884397 -paper towel,n03887697 -parachute,n03888257 -parallel bars,n03888605 -park bench,n03891251 -parking meter,n03891332 -passenger car,n03895866 -patio,n03899768 -pay-phone,n03902125 -pedestal,n03903868 -pencil box,n03908618 -pencil sharpener,n03908714 -perfume,n03916031 -Petri dish,n03920288 -photocopier,n03924679 -pick,n03929660 -pickelhaube,n03929855 -picket fence,n03930313 -pickup,n03930630 -pier,n03933933 -piggy bank,n03935335 -pill bottle,n03937543 -pillow,n03938244 -ping-pong ball,n03942813 -pinwheel,n03944341 -pirate,n03947888 -pitcher,n03950228 -plane,n03954731 -planetarium,n03956157 -plastic bag,n03958227 -plate rack,n03961711 -plow,n03967562 -plunger,n03970156 -Polaroid camera,n03976467 -pole,n03976657 -police van,n03977966 -poncho,n03980874 -pool table,n03982430 -pop bottle,n03983396 -pot,n03991062 -potter's wheel,n03992509 -power drill,n03995372 -prayer rug,n03998194 -printer,n04004767 -prison,n04005630 -projectile,n04008634 -projector,n04009552 -puck,n04019541 -punching bag,n04023962 -purse,n04026417 -quill,n04033901 -quilt,n04033995 -racer,n04037443 -racket,n04039381 -radiator,n04040759 -radio,n04041544 -radio telescope,n04044716 -rain barrel,n04049303 -recreational vehicle,n04065272 -reel,n04067472 -reflex camera,n04069434 -refrigerator,n04070727 -remote control,n04074963 -restaurant,n04081281 -revolver,n04086273 -rifle,n04090263 -rocking chair,n04099969 -rotisserie,n04111531 -rubber eraser,n04116512 -rugby ball,n04118538 -rule,n04118776 -running shoe,n04120489 -safe,n04125021 -safety pin,n04127249 -saltshaker,n04131690 -sandal,n04133789 -sarong,n04136333 -sax,n04141076 -scabbard,n04141327 -scale,n04141975 -school bus,n04146614 -schooner,n04147183 -scoreboard,n04149813 -screen,n04152593 -screw,n04153751 -screwdriver,n04154565 -seat belt,n04162706 -sewing machine,n04179913 -shield,n04192698 -shoe shop,n04200800 -shoji,n04201297 -shopping basket,n04204238 -shopping cart,n04204347 -shovel,n04208210 -shower cap,n04209133 -shower curtain,n04209239 -ski,n04228054 -ski mask,n04229816 -sleeping bag,n04235860 -slide rule,n04238763 -sliding door,n04239074 -slot,n04243546 -snorkel,n04251144 -snowmobile,n04252077 -snowplow,n04252225 -soap dispenser,n04254120 -soccer ball,n04254680 -sock,n04254777 -solar dish,n04258138 -sombrero,n04259630 -soup bowl,n04263257 -space bar,n04264628 -space heater,n04265275 -space shuttle,n04266014 -spatula,n04270147 -speedboat,n04273569 -spider web,n04275548 -spindle,n04277352 -sports car,n04285008 -spotlight,n04286575 -stage,n04296562 -steam locomotive,n04310018 -steel arch bridge,n04311004 -steel drum,n04311174 -stethoscope,n04317175 -stole,n04325704 -stone wall,n04326547 -stopwatch,n04328186 -stove,n04330267 -strainer,n04332243 -streetcar,n04335435 -stretcher,n04336792 -studio couch,n04344873 -stupa,n04346328 -submarine,n04347754 -suit,n04350905 -sundial,n04355338 -sunglass,n04355933 -sunglasses,n04356056 -sunscreen,n04357314 -suspension bridge,n04366367 -swab,n04367480 -sweatshirt,n04370456 -swimming trunks,n04371430 -swing,n04371774 -switch,n04372370 -syringe,n04376876 -table lamp,n04380533 -tank,n04389033 -tape player,n04392985 -teapot,n04398044 -teddy,n04399382 -television,n04404412 -tennis ball,n04409515 -thatch,n04417672 -theater curtain,n04418357 -thimble,n04423845 -thresher,n04428191 -throne,n04429376 -tile roof,n04435653 -toaster,n04442312 -tobacco shop,n04443257 -toilet seat,n04447861 -torch,n04456115 -totem pole,n04458633 -tow truck,n04461696 -toyshop,n04462240 -tractor,n04465501 -trailer truck,n04467665 -tray,n04476259 -trench coat,n04479046 -tricycle,n04482393 -trimaran,n04483307 -tripod,n04485082 -triumphal arch,n04486054 -trolleybus,n04487081 -trombone,n04487394 -tub,n04493381 -turnstile,n04501370 -typewriter keyboard,n04505470 -umbrella,n04507155 -unicycle,n04509417 -upright,n04515003 -vacuum,n04517823 -vase,n04522168 -vault,n04523525 -velvet,n04525038 -vending machine,n04525305 -vestment,n04532106 -viaduct,n04532670 -violin,n04536866 -volleyball,n04540053 -waffle iron,n04542943 -wall clock,n04548280 -wallet,n04548362 -wardrobe,n04550184 -warplane,n04552348 -washbasin,n04553703 -washer,n04554684 -water bottle,n04557648 -water jug,n04560804 -water tower,n04562935 -whiskey jug,n04579145 -whistle,n04579432 -wig,n04584207 -window screen,n04589890 -window shade,n04590129 -Windsor tie,n04591157 -wine bottle,n04591713 -wing,n04592741 -wok,n04596742 -wooden spoon,n04597913 -wool,n04599235 -worm fence,n04604644 -wreck,n04606251 -yawl,n04612504 -yurt,n04613696 -web site,n06359193 -comic book,n06596364 -crossword puzzle,n06785654 -street sign,n06794110 -traffic light,n06874185 -book jacket,n07248320 -menu,n07565083 -plate,n07579787 -guacamole,n07583066 -consomme,n07584110 -hot pot,n07590611 -trifle,n07613480 -ice cream,n07614500 -ice lolly,n07615774 -French loaf,n07684084 -bagel,n07693725 -pretzel,n07695742 -cheeseburger,n07697313 -hotdog,n07697537 -mashed potato,n07711569 -head cabbage,n07714571 -broccoli,n07714990 -cauliflower,n07715103 -zucchini,n07716358 -spaghetti squash,n07716906 -acorn squash,n07717410 -butternut squash,n07717556 -cucumber,n07718472 -artichoke,n07718747 -bell pepper,n07720875 -cardoon,n07730033 -mushroom,n07734744 -Granny Smith,n07742313 -strawberry,n07745940 -orange,n07747607 -lemon,n07749582 -fig,n07753113 -pineapple,n07753275 -banana,n07753592 -jackfruit,n07754684 -custard apple,n07760859 -pomegranate,n07768694 -hay,n07802026 -carbonara,n07831146 -chocolate sauce,n07836838 -dough,n07860988 -meat loaf,n07871810 -pizza,n07873807 -potpie,n07875152 -burrito,n07880968 -red wine,n07892512 -espresso,n07920052 -cup,n07930864 -eggnog,n07932039 -alp,n09193705 -bubble,n09229709 -cliff,n09246464 -coral reef,n09256479 -geyser,n09288635 -lakeside,n09332890 -promontory,n09399592 -sandbar,n09421951 -seashore,n09428293 -valley,n09468604 -volcano,n09472597 -ballplayer,n09835506 -groom,n10148035 -scuba diver,n10565667 -rapeseed,n11879895 -daisy,n11939491 -yellow lady's slipper,n12057211 -corn,n12144580 -acorn,n12267677 -hip,n12620546 -buckeye,n12768682 -coral fungus,n12985857 -agaric,n12998815 -gyromitra,n13037406 -stinkhorn,n13040303 -earthstar,n13044778 -hen-of-the-woods,n13052670 -bolete,n13054560 -ear,n13133613 -toilet tissue,n15075141 diff --git a/torchvision/prototype/datasets/_builtin/imagenet.py b/torchvision/prototype/datasets/_builtin/imagenet.py deleted file mode 100644 index ad561c48c7d..00000000000 --- a/torchvision/prototype/datasets/_builtin/imagenet.py +++ /dev/null @@ -1,223 +0,0 @@ -import enum -import pathlib -import re - -from typing import Any, BinaryIO, cast, Dict, Iterator, List, Match, Optional, Tuple, Union - -from torchdata.datapipes.iter import ( - Demultiplexer, - Enumerator, - Filter, - IterDataPipe, - IterKeyZipper, - LineReader, - Mapper, - TarArchiveLoader, -) -from torchdata.datapipes.map import IterToMapConverter -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, ManualDownloadResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_accessor, - read_categories_file, - read_mat, -) -from torchvision.prototype.tv_tensors import Label - -from .._api import register_dataset, register_info - -NAME = "imagenet" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - categories, wnids = zip(*read_categories_file(NAME)) - return dict(categories=categories, wnids=wnids) - - -class ImageNetResource(ManualDownloadResource): - def __init__(self, **kwargs: Any) -> None: - super().__init__("Register on https://image-net.org/ and follow the instructions there.", **kwargs) - - -class ImageNetDemux(enum.IntEnum): - META = 0 - LABEL = 1 - - -class CategoryAndWordNetIDExtractor(IterDataPipe): - # Although the WordNet IDs (wnids) are unique, the corresponding categories are not. For example, both n02012849 - # and n03126707 are labeled 'crane' while the first means the bird and the latter means the construction equipment - _WNID_MAP = { - "n03126707": "construction crane", - "n03710721": "tank suit", - } - - def __init__(self, datapipe: IterDataPipe[Tuple[str, BinaryIO]]) -> None: - self.datapipe = datapipe - - def __iter__(self) -> Iterator[Tuple[str, str]]: - for _, stream in self.datapipe: - synsets = read_mat(stream, squeeze_me=True)["synsets"] - for _, wnid, category, _, num_children, *_ in synsets: - if num_children > 0: - # we are looking at a superclass that has no direct instance - continue - - yield self._WNID_MAP.get(wnid, category.split(",", 1)[0]), wnid - - -@register_dataset(NAME) -class ImageNet(Dataset): - """ - - **homepage**: https://www.image-net.org/ - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", {"train", "val", "test"}) - - info = _info() - categories, wnids = info["categories"], info["wnids"] - self._categories = categories - self._wnids = wnids - self._wnid_to_category = dict(zip(wnids, categories)) - - super().__init__(root, skip_integrity_check=skip_integrity_check) - - _IMAGES_CHECKSUMS = { - "train": "b08200a27a8e34218a0e58fde36b0fe8f73bc377f4acea2d91602057c3ca45bb", - "val": "c7e06a6c0baccf06d8dbeb6577d71efff84673a5dbdd50633ab44f8ea0456ae0", - "test_v10102019": "9cf7f8249639510f17d3d8a0deb47cd22a435886ba8e29e2b3223e65a4079eb4", - } - - def _resources(self) -> List[OnlineResource]: - name = "test_v10102019" if self._split == "test" else self._split - images = ImageNetResource( - file_name=f"ILSVRC2012_img_{name}.tar", - sha256=self._IMAGES_CHECKSUMS[name], - ) - resources: List[OnlineResource] = [images] - - if self._split == "val": - devkit = ImageNetResource( - file_name="ILSVRC2012_devkit_t12.tar.gz", - sha256="b59243268c0d266621fd587d2018f69e906fb22875aca0e295b48cafaa927953", - ) - resources.append(devkit) - - return resources - - _TRAIN_IMAGE_NAME_PATTERN = re.compile(r"(?Pn\d{8})_\d+[.]JPEG") - - def _prepare_train_data(self, data: Tuple[str, BinaryIO]) -> Tuple[Tuple[Label, str], Tuple[str, BinaryIO]]: - path = pathlib.Path(data[0]) - wnid = cast(Match[str], self._TRAIN_IMAGE_NAME_PATTERN.match(path.name))["wnid"] - label = Label.from_category(self._wnid_to_category[wnid], categories=self._categories) - return (label, wnid), data - - def _prepare_test_data(self, data: Tuple[str, BinaryIO]) -> Tuple[None, Tuple[str, BinaryIO]]: - return None, data - - def _classifiy_devkit(self, data: Tuple[str, BinaryIO]) -> Optional[int]: - return { - "meta.mat": ImageNetDemux.META, - "ILSVRC2012_validation_ground_truth.txt": ImageNetDemux.LABEL, - }.get(pathlib.Path(data[0]).name) - - _VAL_TEST_IMAGE_NAME_PATTERN = re.compile(r"ILSVRC2012_(val|test)_(?P\d{8})[.]JPEG") - - def _val_test_image_key(self, path: pathlib.Path) -> int: - return int(self._VAL_TEST_IMAGE_NAME_PATTERN.match(path.name)["id"]) # type: ignore[index] - - def _prepare_val_data( - self, data: Tuple[Tuple[int, str], Tuple[str, BinaryIO]] - ) -> Tuple[Tuple[Label, str], Tuple[str, BinaryIO]]: - label_data, image_data = data - _, wnid = label_data - label = Label.from_category(self._wnid_to_category[wnid], categories=self._categories) - return (label, wnid), image_data - - def _prepare_sample( - self, - data: Tuple[Optional[Tuple[Label, str]], Tuple[str, BinaryIO]], - ) -> Dict[str, Any]: - label_data, (path, buffer) = data - - return dict( - dict(zip(("label", "wnid"), label_data if label_data else (None, None))), - path=path, - image=EncodedImage.from_file(buffer), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - if self._split in {"train", "test"}: - dp = resource_dps[0] - - # the train archive is a tar of tars - if self._split == "train": - dp = TarArchiveLoader(dp) - - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - dp = Mapper(dp, self._prepare_train_data if self._split == "train" else self._prepare_test_data) - else: # config.split == "val": - images_dp, devkit_dp = resource_dps - - meta_dp, label_dp = Demultiplexer( - devkit_dp, 2, self._classifiy_devkit, drop_none=True, buffer_size=INFINITE_BUFFER_SIZE - ) - - # We cannot use self._wnids here, since we use a different order than the dataset - meta_dp = CategoryAndWordNetIDExtractor(meta_dp) - wnid_dp = Mapper(meta_dp, getitem(1)) - wnid_dp = Enumerator(wnid_dp, 1) - wnid_map = IterToMapConverter(wnid_dp) - - label_dp = LineReader(label_dp, decode=True, return_path=False) - label_dp = Mapper(label_dp, int) - label_dp = Mapper(label_dp, wnid_map.__getitem__) - label_dp: IterDataPipe[Tuple[int, str]] = Enumerator(label_dp, 1) - label_dp = hint_shuffling(label_dp) - label_dp = hint_sharding(label_dp) - - dp = IterKeyZipper( - label_dp, - images_dp, - key_fn=getitem(0), - ref_key_fn=path_accessor(self._val_test_image_key), - buffer_size=INFINITE_BUFFER_SIZE, - ) - dp = Mapper(dp, self._prepare_val_data) - - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return { - "train": 1_281_167, - "val": 50_000, - "test": 100_000, - }[self._split] - - def _filter_meta(self, data: Tuple[str, Any]) -> bool: - return self._classifiy_devkit(data) == ImageNetDemux.META - - def _generate_categories(self) -> List[Tuple[str, ...]]: - self._split = "val" - resources = self._resources() - - devkit_dp = resources[1].load(self._root) - meta_dp = Filter(devkit_dp, self._filter_meta) - meta_dp = CategoryAndWordNetIDExtractor(meta_dp) - - categories_and_wnids = cast(List[Tuple[str, ...]], list(meta_dp)) - categories_and_wnids.sort(key=lambda category_and_wnid: category_and_wnid[1]) - return categories_and_wnids diff --git a/torchvision/prototype/datasets/_builtin/mnist.py b/torchvision/prototype/datasets/_builtin/mnist.py deleted file mode 100644 index 218b8b330ba..00000000000 --- a/torchvision/prototype/datasets/_builtin/mnist.py +++ /dev/null @@ -1,419 +0,0 @@ -import abc -import functools -import operator -import pathlib -import string -from typing import Any, BinaryIO, cast, Dict, Iterator, List, Optional, Sequence, Tuple, Union - -import torch -from torchdata.datapipes.iter import Decompressor, Demultiplexer, IterDataPipe, Mapper, Zipper -from torchvision.prototype.datasets.utils import Dataset, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import hint_sharding, hint_shuffling, INFINITE_BUFFER_SIZE -from torchvision.prototype.tv_tensors import Label -from torchvision.prototype.utils._internal import fromfile -from torchvision.tv_tensors import Image - -from .._api import register_dataset, register_info - - -prod = functools.partial(functools.reduce, operator.mul) - - -class MNISTFileReader(IterDataPipe[torch.Tensor]): - _DTYPE_MAP = { - 8: torch.uint8, - 9: torch.int8, - 11: torch.int16, - 12: torch.int32, - 13: torch.float32, - 14: torch.float64, - } - - def __init__( - self, datapipe: IterDataPipe[Tuple[Any, BinaryIO]], *, start: Optional[int], stop: Optional[int] - ) -> None: - self.datapipe = datapipe - self.start = start - self.stop = stop - - def __iter__(self) -> Iterator[torch.Tensor]: - for _, file in self.datapipe: - try: - read = functools.partial(fromfile, file, byte_order="big") - - magic = int(read(dtype=torch.int32, count=1)) - dtype = self._DTYPE_MAP[magic // 256] - ndim = magic % 256 - 1 - - num_samples = int(read(dtype=torch.int32, count=1)) - shape = cast(List[int], read(dtype=torch.int32, count=ndim).tolist()) if ndim else [] - count = prod(shape) if shape else 1 - - start = self.start or 0 - stop = min(self.stop, num_samples) if self.stop else num_samples - - if start: - num_bytes_per_value = (torch.finfo if dtype.is_floating_point else torch.iinfo)(dtype).bits // 8 - file.seek(num_bytes_per_value * count * start, 1) - - for _ in range(stop - start): - yield read(dtype=dtype, count=count).reshape(shape) - finally: - file.close() - - -class _MNISTBase(Dataset): - _URL_BASE: Union[str, Sequence[str]] - - @abc.abstractmethod - def _files_and_checksums(self) -> Tuple[Tuple[str, str], Tuple[str, str]]: - pass - - def _resources(self) -> List[OnlineResource]: - (images_file, images_sha256), ( - labels_file, - labels_sha256, - ) = self._files_and_checksums() - - url_bases = self._URL_BASE - if isinstance(url_bases, str): - url_bases = (url_bases,) - - images_urls = [f"{url_base}/{images_file}" for url_base in url_bases] - images = HttpResource(images_urls[0], sha256=images_sha256, mirrors=images_urls[1:]) - - labels_urls = [f"{url_base}/{labels_file}" for url_base in url_bases] - labels = HttpResource(labels_urls[0], sha256=labels_sha256, mirrors=labels_urls[1:]) - - return [images, labels] - - def start_and_stop(self) -> Tuple[Optional[int], Optional[int]]: - return None, None - - _categories: List[str] - - def _prepare_sample(self, data: Tuple[torch.Tensor, torch.Tensor]) -> Dict[str, Any]: - image, label = data - return dict( - image=Image(image), - label=Label(label, dtype=torch.int64, categories=self._categories), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - images_dp, labels_dp = resource_dps - start, stop = self.start_and_stop() - - images_dp = Decompressor(images_dp) - images_dp = MNISTFileReader(images_dp, start=start, stop=stop) - - labels_dp = Decompressor(labels_dp) - labels_dp = MNISTFileReader(labels_dp, start=start, stop=stop) - - dp = Zipper(images_dp, labels_dp) - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - return Mapper(dp, self._prepare_sample) - - -@register_info("mnist") -def _mnist_info() -> Dict[str, Any]: - return dict( - categories=[str(label) for label in range(10)], - ) - - -@register_dataset("mnist") -class MNIST(_MNISTBase): - """ - - **homepage**: http://yann.lecun.com/exdb/mnist - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "test")) - super().__init__(root, skip_integrity_check=skip_integrity_check) - - _URL_BASE: Union[str, Sequence[str]] = ( - "http://yann.lecun.com/exdb/mnist", - "https://ossci-datasets.s3.amazonaws.com/mnist", - ) - _CHECKSUMS = { - "train-images-idx3-ubyte.gz": "440fcabf73cc546fa21475e81ea370265605f56be210a4024d2ca8f203523609", - "train-labels-idx1-ubyte.gz": "3552534a0a558bbed6aed32b30c495cca23d567ec52cac8be1a0730e8010255c", - "t10k-images-idx3-ubyte.gz": "8d422c7b0a1c1c79245a5bcf07fe86e33eeafee792b84584aec276f5a2dbc4e6", - "t10k-labels-idx1-ubyte.gz": "f7ae60f92e00ec6debd23a6088c31dbd2371eca3ffa0defaefb259924204aec6", - } - - def _files_and_checksums(self) -> Tuple[Tuple[str, str], Tuple[str, str]]: - prefix = "train" if self._split == "train" else "t10k" - images_file = f"{prefix}-images-idx3-ubyte.gz" - labels_file = f"{prefix}-labels-idx1-ubyte.gz" - return (images_file, self._CHECKSUMS[images_file]), ( - labels_file, - self._CHECKSUMS[labels_file], - ) - - _categories = _mnist_info()["categories"] - - def __len__(self) -> int: - return 60_000 if self._split == "train" else 10_000 - - -@register_info("fashionmnist") -def _fashionmnist_info() -> Dict[str, Any]: - return dict( - categories=[ - "T-shirt/top", - "Trouser", - "Pullover", - "Dress", - "Coat", - "Sandal", - "Shirt", - "Sneaker", - "Bag", - "Ankle boot", - ], - ) - - -@register_dataset("fashionmnist") -class FashionMNIST(MNIST): - """ - - **homepage**: https://github.com/zalandoresearch/fashion-mnist - """ - - _URL_BASE = "http://fashion-mnist.s3-website.eu-central-1.amazonaws.com" - _CHECKSUMS = { - "train-images-idx3-ubyte.gz": "3aede38d61863908ad78613f6a32ed271626dd12800ba2636569512369268a84", - "train-labels-idx1-ubyte.gz": "a04f17134ac03560a47e3764e11b92fc97de4d1bfaf8ba1a3aa29af54cc90845", - "t10k-images-idx3-ubyte.gz": "346e55b948d973a97e58d2351dde16a484bd415d4595297633bb08f03db6a073", - "t10k-labels-idx1-ubyte.gz": "67da17c76eaffca5446c3361aaab5c3cd6d1c2608764d35dfb1850b086bf8dd5", - } - - _categories = _fashionmnist_info()["categories"] - - -@register_info("kmnist") -def _kmnist_info() -> Dict[str, Any]: - return dict( - categories=["o", "ki", "su", "tsu", "na", "ha", "ma", "ya", "re", "wo"], - ) - - -@register_dataset("kmnist") -class KMNIST(MNIST): - """ - - **homepage**: http://codh.rois.ac.jp/kmnist/index.html.en - """ - - _URL_BASE = "http://codh.rois.ac.jp/kmnist/dataset/kmnist" - _CHECKSUMS = { - "train-images-idx3-ubyte.gz": "51467d22d8cc72929e2a028a0428f2086b092bb31cfb79c69cc0a90ce135fde4", - "train-labels-idx1-ubyte.gz": "e38f9ebcd0f3ebcdec7fc8eabdcdaef93bb0df8ea12bee65224341c8183d8e17", - "t10k-images-idx3-ubyte.gz": "edd7a857845ad6bb1d0ba43fe7e794d164fe2dce499a1694695a792adfac43c5", - "t10k-labels-idx1-ubyte.gz": "20bb9a0ef54c7db3efc55a92eef5582c109615df22683c380526788f98e42a1c", - } - - _categories = _kmnist_info()["categories"] - - -@register_info("emnist") -def _emnist_info() -> Dict[str, Any]: - return dict( - categories=list(string.digits + string.ascii_uppercase + string.ascii_lowercase), - ) - - -@register_dataset("emnist") -class EMNIST(_MNISTBase): - """ - - **homepage**: https://www.westernsydney.edu.au/icns/reproducible_research/publication_support_materials/emnist - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - image_set: str = "Balanced", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "test")) - self._image_set = self._verify_str_arg( - image_set, "image_set", ("Balanced", "By_Merge", "By_Class", "Letters", "Digits", "MNIST") - ) - super().__init__(root, skip_integrity_check=skip_integrity_check) - - _URL_BASE = "https://rds.westernsydney.edu.au/Institutes/MARCS/BENS/EMNIST" - - def _files_and_checksums(self) -> Tuple[Tuple[str, str], Tuple[str, str]]: - prefix = f"emnist-{self._image_set.replace('_', '').lower()}-{self._split}" - images_file = f"{prefix}-images-idx3-ubyte.gz" - labels_file = f"{prefix}-labels-idx1-ubyte.gz" - # Since EMNIST provides the data files inside an archive, we don't need to provide checksums for them - return (images_file, ""), (labels_file, "") - - def _resources(self) -> List[OnlineResource]: - return [ - HttpResource( - f"{self._URL_BASE}/emnist-gzip.zip", - sha256="909a2a39c5e86bdd7662425e9b9c4a49bb582bf8d0edad427f3c3a9d0c6f7259", - ) - ] - - def _classify_archive(self, data: Tuple[str, Any]) -> Optional[int]: - path = pathlib.Path(data[0]) - (images_file, _), (labels_file, _) = self._files_and_checksums() - if path.name == images_file: - return 0 - elif path.name == labels_file: - return 1 - else: - return None - - _categories = _emnist_info()["categories"] - - _LABEL_OFFSETS = { - 38: 1, - 39: 1, - 40: 1, - 41: 1, - 42: 1, - 43: 6, - 44: 8, - 45: 8, - 46: 9, - } - - def _prepare_sample(self, data: Tuple[torch.Tensor, torch.Tensor]) -> Dict[str, Any]: - # In these two splits, some lowercase letters are merged into their uppercase ones (see Fig 2. in the paper). - # That means for example that there is 'D', 'd', and 'C', but not 'c'. Since the labels are nevertheless dense, - # i.e. no gaps between 0 and 46 for 47 total classes, we need to add an offset to create these gaps. For - # example, since there is no 'c', 'd' corresponds to - # label 38 (10 digits + 26 uppercase letters + 3rd unmerged lower case letter - 1 for zero indexing), - # and at the same time corresponds to - # index 39 (10 digits + 26 uppercase letters + 4th lower case letter - 1 for zero indexing) - # in self._categories. Thus, we need to add 1 to the label to correct this. - if self._image_set in ("Balanced", "By_Merge"): - image, label = data - label += self._LABEL_OFFSETS.get(int(label), 0) - data = (image, label) - return super()._prepare_sample(data) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - archive_dp = resource_dps[0] - images_dp, labels_dp = Demultiplexer( - archive_dp, - 2, - self._classify_archive, - drop_none=True, - buffer_size=INFINITE_BUFFER_SIZE, - ) - return super()._datapipe([images_dp, labels_dp]) - - def __len__(self) -> int: - return { - ("train", "Balanced"): 112_800, - ("train", "By_Merge"): 697_932, - ("train", "By_Class"): 697_932, - ("train", "Letters"): 124_800, - ("train", "Digits"): 240_000, - ("train", "MNIST"): 60_000, - ("test", "Balanced"): 18_800, - ("test", "By_Merge"): 116_323, - ("test", "By_Class"): 116_323, - ("test", "Letters"): 20_800, - ("test", "Digits"): 40_000, - ("test", "MNIST"): 10_000, - }[(self._split, self._image_set)] - - -@register_info("qmnist") -def _qmnist_info() -> Dict[str, Any]: - return dict( - categories=[str(label) for label in range(10)], - ) - - -@register_dataset("qmnist") -class QMNIST(_MNISTBase): - """ - - **homepage**: https://github.com/facebookresearch/qmnist - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "test", "test10k", "test50k", "nist")) - super().__init__(root, skip_integrity_check=skip_integrity_check) - - _URL_BASE = "https://raw.githubusercontent.com/facebookresearch/qmnist/master" - _CHECKSUMS = { - "qmnist-train-images-idx3-ubyte.gz": "9e26a7bf1683614e065d7b76460ccd52807165b3f22561fb782bd9f38c52b51d", - "qmnist-train-labels-idx2-int.gz": "2c05dc77f6b916b38e455e97ab129a42a444f3dbef09b278a366f82904e0dd9f", - "qmnist-test-images-idx3-ubyte.gz": "43fc22bf7498b8fc98de98369d72f752d0deabc280a43a7bcc364ab19e57b375", - "qmnist-test-labels-idx2-int.gz": "9fbcbe594c3766fdf4f0b15c5165dc0d1e57ac604e01422608bb72c906030d06", - "xnist-images-idx3-ubyte.xz": "f075553993026d4359ded42208eff77a1941d3963c1eff49d6015814f15f0984", - "xnist-labels-idx2-int.xz": "db042968723ec2b7aed5f1beac25d2b6e983b9286d4f4bf725f1086e5ae55c4f", - } - - def _files_and_checksums(self) -> Tuple[Tuple[str, str], Tuple[str, str]]: - prefix = "xnist" if self._split == "nist" else f"qmnist-{'train' if self._split == 'train' else 'test'}" - suffix = "xz" if self._split == "nist" else "gz" - images_file = f"{prefix}-images-idx3-ubyte.{suffix}" - labels_file = f"{prefix}-labels-idx2-int.{suffix}" - return (images_file, self._CHECKSUMS[images_file]), ( - labels_file, - self._CHECKSUMS[labels_file], - ) - - def start_and_stop(self) -> Tuple[Optional[int], Optional[int]]: - start: Optional[int] - stop: Optional[int] - if self._split == "test10k": - start = 0 - stop = 10000 - elif self._split == "test50k": - start = 10000 - stop = None - else: - start = stop = None - - return start, stop - - _categories = _emnist_info()["categories"] - - def _prepare_sample(self, data: Tuple[torch.Tensor, torch.Tensor]) -> Dict[str, Any]: - image, ann = data - label, *extra_anns = ann - sample = super()._prepare_sample((image, label)) - - sample.update( - dict( - zip( - ("nist_hsf_series", "nist_writer_id", "digit_index", "nist_label", "global_digit_index"), - [int(value) for value in extra_anns[:5]], - ) - ) - ) - sample.update(dict(zip(("duplicate", "unused"), [bool(value) for value in extra_anns[-2:]]))) - return sample - - def __len__(self) -> int: - return { - "train": 60_000, - "test": 60_000, - "test10k": 10_000, - "test50k": 50_000, - "nist": 402_953, - }[self._split] diff --git a/torchvision/prototype/datasets/_builtin/oxford-iiit-pet.categories b/torchvision/prototype/datasets/_builtin/oxford-iiit-pet.categories deleted file mode 100644 index 36d29465b04..00000000000 --- a/torchvision/prototype/datasets/_builtin/oxford-iiit-pet.categories +++ /dev/null @@ -1,37 +0,0 @@ -Abyssinian -American Bulldog -American Pit Bull Terrier -Basset Hound -Beagle -Bengal -Birman -Bombay -Boxer -British Shorthair -Chihuahua -Egyptian Mau -English Cocker Spaniel -English Setter -German Shorthaired -Great Pyrenees -Havanese -Japanese Chin -Keeshond -Leonberger -Maine Coon -Miniature Pinscher -Newfoundland -Persian -Pomeranian -Pug -Ragdoll -Russian Blue -Saint Bernard -Samoyed -Scottish Terrier -Shiba Inu -Siamese -Sphynx -Staffordshire Bull Terrier -Wheaten Terrier -Yorkshire Terrier diff --git a/torchvision/prototype/datasets/_builtin/oxford_iiit_pet.py b/torchvision/prototype/datasets/_builtin/oxford_iiit_pet.py deleted file mode 100644 index 9d14a7b9b6f..00000000000 --- a/torchvision/prototype/datasets/_builtin/oxford_iiit_pet.py +++ /dev/null @@ -1,146 +0,0 @@ -import enum -import pathlib -from typing import Any, BinaryIO, Dict, List, Optional, Tuple, Union - -from torchdata.datapipes.iter import CSVDictParser, Demultiplexer, Filter, IterDataPipe, IterKeyZipper, Mapper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_accessor, - path_comparator, - read_categories_file, -) -from torchvision.prototype.tv_tensors import Label - -from .._api import register_dataset, register_info - - -NAME = "oxford-iiit-pet" - - -class OxfordIIITPetDemux(enum.IntEnum): - SPLIT_AND_CLASSIFICATION = 0 - SEGMENTATIONS = 1 - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict(categories=read_categories_file(NAME)) - - -@register_dataset(NAME) -class OxfordIIITPet(Dataset): - """Oxford IIIT Pet Dataset - homepage="https://www.robots.ox.ac.uk/~vgg/data/pets/", - """ - - def __init__( - self, root: Union[str, pathlib.Path], *, split: str = "trainval", skip_integrity_check: bool = False - ) -> None: - self._split = self._verify_str_arg(split, "split", {"trainval", "test"}) - self._categories = _info()["categories"] - super().__init__(root, skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - images = HttpResource( - "https://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz", - sha256="67195c5e1c01f1ab5f9b6a5d22b8c27a580d896ece458917e61d459337fa318d", - preprocess="decompress", - ) - anns = HttpResource( - "https://www.robots.ox.ac.uk/~vgg/data/pets/data/annotations.tar.gz", - sha256="52425fb6de5c424942b7626b428656fcbd798db970a937df61750c0f1d358e91", - preprocess="decompress", - ) - return [images, anns] - - def _classify_anns(self, data: Tuple[str, Any]) -> Optional[int]: - return { - "annotations": OxfordIIITPetDemux.SPLIT_AND_CLASSIFICATION, - "trimaps": OxfordIIITPetDemux.SEGMENTATIONS, - }.get(pathlib.Path(data[0]).parent.name) - - def _filter_images(self, data: Tuple[str, Any]) -> bool: - return pathlib.Path(data[0]).suffix == ".jpg" - - def _filter_segmentations(self, data: Tuple[str, Any]) -> bool: - return not pathlib.Path(data[0]).name.startswith(".") - - def _prepare_sample( - self, data: Tuple[Tuple[Dict[str, str], Tuple[str, BinaryIO]], Tuple[str, BinaryIO]] - ) -> Dict[str, Any]: - ann_data, image_data = data - classification_data, segmentation_data = ann_data - segmentation_path, segmentation_buffer = segmentation_data - image_path, image_buffer = image_data - - return dict( - label=Label(int(classification_data["label"]) - 1, categories=self._categories), - species="cat" if classification_data["species"] == "1" else "dog", - segmentation_path=segmentation_path, - segmentation=EncodedImage.from_file(segmentation_buffer), - image_path=image_path, - image=EncodedImage.from_file(image_buffer), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - images_dp, anns_dp = resource_dps - - images_dp = Filter(images_dp, self._filter_images) - - split_and_classification_dp, segmentations_dp = Demultiplexer( - anns_dp, - 2, - self._classify_anns, - drop_none=True, - buffer_size=INFINITE_BUFFER_SIZE, - ) - - split_and_classification_dp = Filter(split_and_classification_dp, path_comparator("name", f"{self._split}.txt")) - split_and_classification_dp = CSVDictParser( - split_and_classification_dp, fieldnames=("image_id", "label", "species"), delimiter=" " - ) - split_and_classification_dp = hint_shuffling(split_and_classification_dp) - split_and_classification_dp = hint_sharding(split_and_classification_dp) - - segmentations_dp = Filter(segmentations_dp, self._filter_segmentations) - - anns_dp = IterKeyZipper( - split_and_classification_dp, - segmentations_dp, - key_fn=getitem("image_id"), - ref_key_fn=path_accessor("stem"), - buffer_size=INFINITE_BUFFER_SIZE, - ) - - dp = IterKeyZipper( - anns_dp, - images_dp, - key_fn=getitem(0, "image_id"), - ref_key_fn=path_accessor("stem"), - buffer_size=INFINITE_BUFFER_SIZE, - ) - return Mapper(dp, self._prepare_sample) - - def _filter_split_and_classification_anns(self, data: Tuple[str, Any]) -> bool: - return self._classify_anns(data) == OxfordIIITPetDemux.SPLIT_AND_CLASSIFICATION - - def _generate_categories(self) -> List[str]: - resources = self._resources() - - dp = resources[1].load(self._root) - dp = Filter(dp, self._filter_split_and_classification_anns) - dp = Filter(dp, path_comparator("name", "trainval.txt")) - dp = CSVDictParser(dp, fieldnames=("image_id", "label"), delimiter=" ") - - raw_categories_and_labels = {(data["image_id"].rsplit("_", 1)[0], data["label"]) for data in dp} - raw_categories, _ = zip( - *sorted(raw_categories_and_labels, key=lambda raw_category_and_label: int(raw_category_and_label[1])) - ) - return [" ".join(part.title() for part in raw_category.split("_")) for raw_category in raw_categories] - - def __len__(self) -> int: - return 3_680 if self._split == "trainval" else 3_669 diff --git a/torchvision/prototype/datasets/_builtin/pcam.py b/torchvision/prototype/datasets/_builtin/pcam.py deleted file mode 100644 index 6eb4118ca28..00000000000 --- a/torchvision/prototype/datasets/_builtin/pcam.py +++ /dev/null @@ -1,129 +0,0 @@ -import io -import pathlib -from collections import namedtuple -from typing import Any, Dict, Iterator, List, Optional, Tuple, Union - -from torchdata.datapipes.iter import IterDataPipe, Mapper, Zipper -from torchvision.prototype.datasets.utils import Dataset, GDriveResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import hint_sharding, hint_shuffling -from torchvision.prototype.tv_tensors import Label -from torchvision.tv_tensors import Image - -from .._api import register_dataset, register_info - - -NAME = "pcam" - - -class PCAMH5Reader(IterDataPipe[Tuple[str, io.IOBase]]): - def __init__( - self, - datapipe: IterDataPipe[Tuple[str, io.IOBase]], - key: Optional[str] = None, # Note: this key thing might be very specific to the PCAM dataset - ) -> None: - self.datapipe = datapipe - self.key = key - - def __iter__(self) -> Iterator[Tuple[str, io.IOBase]]: - import h5py - - for _, handle in self.datapipe: - try: - with h5py.File(handle) as data: - if self.key is not None: - data = data[self.key] - yield from data - finally: - handle.close() - - -_Resource = namedtuple("_Resource", ("file_name", "gdrive_id", "sha256")) - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict(categories=["0", "1"]) - - -@register_dataset(NAME) -class PCAM(Dataset): - # TODO write proper docstring - """PCAM Dataset - - homepage="https://github.com/basveeling/pcam" - """ - - def __init__( - self, root: Union[str, pathlib.Path], split: str = "train", *, skip_integrity_check: bool = False - ) -> None: - self._split = self._verify_str_arg(split, "split", {"train", "val", "test"}) - self._categories = _info()["categories"] - super().__init__(root, skip_integrity_check=skip_integrity_check, dependencies=("h5py",)) - - _RESOURCES = { - "train": ( - _Resource( # Images - file_name="camelyonpatch_level_2_split_train_x.h5.gz", - gdrive_id="1Ka0XfEMiwgCYPdTI-vv6eUElOBnKFKQ2", - sha256="d619e741468a7ab35c7e4a75e6821b7e7e6c9411705d45708f2a0efc8960656c", - ), - _Resource( # Targets - file_name="camelyonpatch_level_2_split_train_y.h5.gz", - gdrive_id="1269yhu3pZDP8UYFQs-NYs3FPwuK-nGSG", - sha256="b74126d2c01b20d3661f9b46765d29cf4e4fba6faba29c8e0d09d406331ab75a", - ), - ), - "test": ( - _Resource( # Images - file_name="camelyonpatch_level_2_split_test_x.h5.gz", - gdrive_id="1qV65ZqZvWzuIVthK8eVDhIwrbnsJdbg_", - sha256="79174c2201ad521602a5888be8f36ee10875f37403dd3f2086caf2182ef87245", - ), - _Resource( # Targets - file_name="camelyonpatch_level_2_split_test_y.h5.gz", - gdrive_id="17BHrSrwWKjYsOgTMmoqrIjDy6Fa2o_gP", - sha256="0a522005fccc8bbd04c5a117bfaf81d8da2676f03a29d7499f71d0a0bd6068ef", - ), - ), - "val": ( - _Resource( # Images - file_name="camelyonpatch_level_2_split_valid_x.h5.gz", - gdrive_id="1hgshYGWK8V-eGRy8LToWJJgDU_rXWVJ3", - sha256="f82ee1670d027b4ec388048d9eabc2186b77c009655dae76d624c0ecb053ccb2", - ), - _Resource( # Targets - file_name="camelyonpatch_level_2_split_valid_y.h5.gz", - gdrive_id="1bH8ZRbhSVAhScTS0p9-ZzGnX91cHT3uO", - sha256="ce1ae30f08feb468447971cfd0472e7becd0ad96d877c64120c72571439ae48c", - ), - ), - } - - def _resources(self) -> List[OnlineResource]: - return [ # = [images resource, targets resource] - GDriveResource(file_name=file_name, id=gdrive_id, sha256=sha256, preprocess="decompress") - for file_name, gdrive_id, sha256 in self._RESOURCES[self._split] - ] - - def _prepare_sample(self, data: Tuple[Any, Any]) -> Dict[str, Any]: - image, target = data # They're both numpy arrays at this point - - return { - "image": Image(image.transpose(2, 0, 1)), - "label": Label(target.item(), categories=self._categories), - } - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - - images_dp, targets_dp = resource_dps - - images_dp = PCAMH5Reader(images_dp, key="x") - targets_dp = PCAMH5Reader(targets_dp, key="y") - - dp = Zipper(images_dp, targets_dp) - dp = hint_shuffling(dp) - dp = hint_sharding(dp) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return 262_144 if self._split == "train" else 32_768 diff --git a/torchvision/prototype/datasets/_builtin/sbd.categories b/torchvision/prototype/datasets/_builtin/sbd.categories deleted file mode 100644 index 8420ab35ede..00000000000 --- a/torchvision/prototype/datasets/_builtin/sbd.categories +++ /dev/null @@ -1,20 +0,0 @@ -aeroplane -bicycle -bird -boat -bottle -bus -car -cat -chair -cow -diningtable -dog -horse -motorbike -person -pottedplant -sheep -sofa -train -tvmonitor diff --git a/torchvision/prototype/datasets/_builtin/sbd.py b/torchvision/prototype/datasets/_builtin/sbd.py deleted file mode 100644 index 97986b58b5d..00000000000 --- a/torchvision/prototype/datasets/_builtin/sbd.py +++ /dev/null @@ -1,165 +0,0 @@ -import pathlib -import re -from typing import Any, BinaryIO, cast, Dict, List, Optional, Tuple, Union - -import numpy as np -import torch -from torchdata.datapipes.iter import Demultiplexer, Filter, IterDataPipe, IterKeyZipper, LineReader, Mapper -from torchvision.prototype.datasets.utils import Dataset, EncodedImage, HttpResource, OnlineResource -from torchvision.prototype.datasets.utils._internal import ( - getitem, - hint_sharding, - hint_shuffling, - INFINITE_BUFFER_SIZE, - path_accessor, - path_comparator, - read_categories_file, - read_mat, -) - -from .._api import register_dataset, register_info - -NAME = "sbd" - - -@register_info(NAME) -def _info() -> Dict[str, Any]: - return dict(categories=read_categories_file(NAME)) - - -@register_dataset(NAME) -class SBD(Dataset): - """ - - **homepage**: http://home.bharathh.info/pubs/codes/SBD/download.html - - **dependencies**: - - _ - """ - - def __init__( - self, - root: Union[str, pathlib.Path], - *, - split: str = "train", - skip_integrity_check: bool = False, - ) -> None: - self._split = self._verify_str_arg(split, "split", ("train", "val", "train_noval")) - - self._categories = _info()["categories"] - - super().__init__(root, dependencies=("scipy",), skip_integrity_check=skip_integrity_check) - - def _resources(self) -> List[OnlineResource]: - resources = [ - HttpResource( - "https://www2.eecs.berkeley.edu/Research/Projects/CS/vision/grouping/semantic_contours/benchmark.tgz", - sha256="6a5a2918d5c73ce032fdeba876574d150d9d04113ab87540a1304cbcc715be53", - ) - ] - if self._split == "train_noval": - resources.append( - HttpResource( - "http://home.bharathh.info/pubs/codes/SBD/train_noval.txt", - sha256="0b2068f7a359d2907431803e1cd63bf6162da37d7d503b589d3b08c6fd0c2432", - ) - ) - return resources # type: ignore[return-value] - - def _classify_archive(self, data: Tuple[str, Any]) -> Optional[int]: - path = pathlib.Path(data[0]) - parent, grandparent, *_ = path.parents - - if grandparent.name == "dataset": - if parent.name == "img": - return 0 - elif parent.name == "cls": - return 1 - - if parent.name == "dataset" and self._split != "train_noval": - return 2 - - return None - - def _prepare_sample(self, data: Tuple[Tuple[Any, Tuple[str, BinaryIO]], Tuple[str, BinaryIO]]) -> Dict[str, Any]: - split_and_image_data, ann_data = data - _, image_data = split_and_image_data - image_path, image_buffer = image_data - ann_path, ann_buffer = ann_data - - anns = read_mat(ann_buffer, squeeze_me=True)["GTcls"] - - return dict( - image_path=image_path, - image=EncodedImage.from_file(image_buffer), - ann_path=ann_path, - # the boundaries are stored in sparse CSC format, which is not supported by PyTorch - boundaries=torch.as_tensor( - np.stack([raw_boundary.toarray() for raw_boundary in anns["Boundaries"].item()]) - ), - segmentation=torch.as_tensor(anns["Segmentation"].item()), - ) - - def _datapipe(self, resource_dps: List[IterDataPipe]) -> IterDataPipe[Dict[str, Any]]: - if self._split == "train_noval": - archive_dp, split_dp = resource_dps - images_dp, anns_dp = Demultiplexer( - archive_dp, - 2, - self._classify_archive, - buffer_size=INFINITE_BUFFER_SIZE, - drop_none=True, - ) - else: - archive_dp = resource_dps[0] - images_dp, anns_dp, split_dp = Demultiplexer( - archive_dp, - 3, - self._classify_archive, - buffer_size=INFINITE_BUFFER_SIZE, - drop_none=True, - ) - - split_dp = Filter(split_dp, path_comparator("name", f"{self._split}.txt")) - split_dp = LineReader(split_dp, decode=True) - split_dp = hint_shuffling(split_dp) - split_dp = hint_sharding(split_dp) - - dp = split_dp - for level, data_dp in enumerate((images_dp, anns_dp)): - dp = IterKeyZipper( - dp, - data_dp, - key_fn=getitem(*[0] * level, 1), - ref_key_fn=path_accessor("stem"), - buffer_size=INFINITE_BUFFER_SIZE, - ) - return Mapper(dp, self._prepare_sample) - - def __len__(self) -> int: - return { - "train": 8_498, - "val": 2_857, - "train_noval": 5_623, - }[self._split] - - def _generate_categories(self) -> Tuple[str, ...]: - resources = self._resources() - - dp = resources[0].load(self._root) - dp = Filter(dp, path_comparator("name", "category_names.m")) - dp = LineReader(dp) - dp = Mapper(dp, bytes.decode, input_col=1) - lines = tuple(zip(*iter(dp)))[1] - - pattern = re.compile(r"\s*'(?P\w+)';\s*%(?P