Commit bf491463 authored by limm's avatar limm
Browse files

add v0.19.1 release

parent e17f5ea2
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
import os
import contextlib
import hashlib
import pickle
import re
import tarfile
import unittest.mock
from distutils import dir_util
import numpy as np
import PIL
import torch
from common_utils import get_tmp_dir
def mock_class_attribute(stack, target, new):
mock = unittest.mock.patch(target, new_callable=unittest.mock.PropertyMock, return_value=new)
stack.enter_context(mock)
return mock
def compute_md5(file):
with open(file, "rb") as fh:
return hashlib.md5(fh.read()).hexdigest()
def make_tar(root, name, *files, compression=None):
ext = ".tar"
mode = "w"
if compression is not None:
ext = f"{ext}.{compression}"
mode = f"{mode}:{compression}"
name = os.path.splitext(name)[0] + ext
archive = os.path.join(root, name)
with tarfile.open(archive, mode) as fh:
for file in files:
fh.add(os.path.join(root, file), arcname=file)
return name, compute_md5(archive)
def clean_dir(root, *keep):
pattern = re.compile(f"({f')|('.join(keep)})")
for file_or_dir in os.listdir(root):
if pattern.search(file_or_dir):
continue
file_or_dir = os.path.join(root, file_or_dir)
if os.path.isfile(file_or_dir):
os.remove(file_or_dir)
else:
dir_util.remove_tree(file_or_dir)
@contextlib.contextmanager
def mnist_root(num_images, cls_name):
def _encode(v):
return torch.tensor(v, dtype=torch.int32).numpy().tobytes()[::-1]
def _make_image_file(filename, num_images):
img = torch.randint(0, 256, size=(28 * 28 * num_images,), dtype=torch.uint8)
with open(filename, "wb") as f:
f.write(_encode(2051)) # magic header
f.write(_encode(num_images))
f.write(_encode(28))
f.write(_encode(28))
f.write(img.numpy().tobytes())
def _make_label_file(filename, num_images):
labels = torch.zeros((num_images,), dtype=torch.uint8)
with open(filename, "wb") as f:
f.write(_encode(2049)) # magic header
f.write(_encode(num_images))
f.write(labels.numpy().tobytes())
with get_tmp_dir() as tmp_dir:
raw_dir = os.path.join(tmp_dir, cls_name, "raw")
os.makedirs(raw_dir)
_make_image_file(os.path.join(raw_dir, "train-images-idx3-ubyte"), num_images)
_make_label_file(os.path.join(raw_dir, "train-labels-idx1-ubyte"), num_images)
_make_image_file(os.path.join(raw_dir, "t10k-images-idx3-ubyte"), num_images)
_make_label_file(os.path.join(raw_dir, "t10k-labels-idx1-ubyte"), num_images)
yield tmp_dir
@contextlib.contextmanager
def cifar_root(version):
def _get_version_params(version):
if version == 'CIFAR10':
return {
'base_folder': 'cifar-10-batches-py',
'train_files': ['data_batch_{}'.format(batch) for batch in range(1, 6)],
'test_file': 'test_batch',
'target_key': 'labels',
'meta_file': 'batches.meta',
'classes_key': 'label_names',
}
elif version == 'CIFAR100':
return {
'base_folder': 'cifar-100-python',
'train_files': ['train'],
'test_file': 'test',
'target_key': 'fine_labels',
'meta_file': 'meta',
'classes_key': 'fine_label_names',
}
else:
raise ValueError
def _make_pickled_file(obj, file):
with open(file, 'wb') as fh:
pickle.dump(obj, fh, 2)
def _make_data_file(file, target_key):
obj = {
'data': np.zeros((1, 32 * 32 * 3), dtype=np.uint8),
target_key: [0]
}
_make_pickled_file(obj, file)
def _make_meta_file(file, classes_key):
obj = {
classes_key: ['fakedata'],
}
_make_pickled_file(obj, file)
params = _get_version_params(version)
with get_tmp_dir() as root:
base_folder = os.path.join(root, params['base_folder'])
os.mkdir(base_folder)
for file in list(params['train_files']) + [params['test_file']]:
_make_data_file(os.path.join(base_folder, file), params['target_key'])
_make_meta_file(os.path.join(base_folder, params['meta_file']),
params['classes_key'])
yield root
@contextlib.contextmanager
def widerface_root():
"""
Generates a dataset with the following folder structure and returns the path root:
<root>
└── widerface
├── wider_face_split
├── WIDER_train
├── WIDER_val
└── WIDER_test
The dataset consist of
1 image for each dataset split (train, val, test) and annotation files
for each split
"""
def _make_image(file):
PIL.Image.fromarray(np.zeros((32, 32, 3), dtype=np.uint8)).save(file)
def _make_train_archive(root):
extracted_dir = os.path.join(root, 'WIDER_train', 'images', '0--Parade')
os.makedirs(extracted_dir)
_make_image(os.path.join(extracted_dir, '0_Parade_marchingband_1_1.jpg'))
def _make_val_archive(root):
extracted_dir = os.path.join(root, 'WIDER_val', 'images', '0--Parade')
os.makedirs(extracted_dir)
_make_image(os.path.join(extracted_dir, '0_Parade_marchingband_1_2.jpg'))
def _make_test_archive(root):
extracted_dir = os.path.join(root, 'WIDER_test', 'images', '0--Parade')
os.makedirs(extracted_dir)
_make_image(os.path.join(extracted_dir, '0_Parade_marchingband_1_3.jpg'))
def _make_annotations_archive(root):
train_bbox_contents = '0--Parade/0_Parade_marchingband_1_1.jpg\n1\n449 330 122 149 0 0 0 0 0 0\n'
val_bbox_contents = '0--Parade/0_Parade_marchingband_1_2.jpg\n1\n501 160 285 443 0 0 0 0 0 0\n'
test_filelist_contents = '0--Parade/0_Parade_marchingband_1_3.jpg\n'
extracted_dir = os.path.join(root, 'wider_face_split')
os.mkdir(extracted_dir)
# bbox training file
bbox_file = os.path.join(extracted_dir, "wider_face_train_bbx_gt.txt")
with open(bbox_file, "w") as txt_file:
txt_file.write(train_bbox_contents)
# bbox validation file
bbox_file = os.path.join(extracted_dir, "wider_face_val_bbx_gt.txt")
with open(bbox_file, "w") as txt_file:
txt_file.write(val_bbox_contents)
# test filelist file
filelist_file = os.path.join(extracted_dir, "wider_face_test_filelist.txt")
with open(filelist_file, "w") as txt_file:
txt_file.write(test_filelist_contents)
with get_tmp_dir() as root:
root_base = os.path.join(root, "widerface")
os.mkdir(root_base)
_make_train_archive(root_base)
_make_val_archive(root_base)
_make_test_archive(root_base)
_make_annotations_archive(root_base)
yield root
{
"_description": "This is a dict containing failures for tests autogenerated by generate_opcheck_tests. For more details, please see https://docs.google.com/document/d/1Pj5HRZvdOq3xpFpbEjUZp2hBovhy7Wnxw14m6lF2154/edit",
"_version": 1,
"data": {}
}
import argparse
import os
from timeit import default_timer as timer
from torch.utils.model_zoo import tqdm
import torch
import torch.utils.data
import torchvision
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torchvision.transforms as transforms
from torch.utils.model_zoo import tqdm
parser = argparse.ArgumentParser(description='PyTorch ImageNet Training')
parser.add_argument('--data', metavar='PATH', required=True,
help='path to dataset')
parser.add_argument('--nThreads', '-j', default=2, type=int, metavar='N',
help='number of data loading threads (default: 2)')
parser.add_argument('--batchSize', '-b', default=256, type=int, metavar='N',
help='mini-batch size (1 = pure stochastic) Default: 256')
parser.add_argument('--accimage', action='store_true',
help='use accimage')
parser = argparse.ArgumentParser(description="PyTorch ImageNet Training")
parser.add_argument("--data", metavar="PATH", required=True, help="path to dataset")
parser.add_argument(
"--nThreads", "-j", default=2, type=int, metavar="N", help="number of data loading threads (default: 2)"
)
parser.add_argument(
"--batchSize", "-b", default=256, type=int, metavar="N", help="mini-batch size (1 = pure stochastic) Default: 256"
)
parser.add_argument("--accimage", action="store_true", help="use accimage")
if __name__ == "__main__":
args = parser.parse_args()
if args.accimage:
torchvision.set_image_backend('accimage')
print('Using {}'.format(torchvision.get_image_backend()))
torchvision.set_image_backend("accimage")
print(f"Using {torchvision.get_image_backend()}")
# Data loading code
transform = transforms.Compose([
transform = transforms.Compose(
[
transforms.RandomSizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
])
transforms.PILToTensor(),
transforms.ConvertImageDtype(torch.float),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
]
)
traindir = os.path.join(args.data, 'train')
valdir = os.path.join(args.data, 'val')
traindir = os.path.join(args.data, "train")
valdir = os.path.join(args.data, "val")
train = datasets.ImageFolder(traindir, transform)
val = datasets.ImageFolder(valdir, transform)
train_loader = torch.utils.data.DataLoader(
train, batch_size=args.batchSize, shuffle=True, num_workers=args.nThreads)
train, batch_size=args.batchSize, shuffle=True, num_workers=args.nThreads
)
train_iter = iter(train_loader)
start_time = timer()
......@@ -51,9 +55,12 @@ if __name__ == "__main__":
pbar.update(1)
batch = next(train_iter)
end_time = timer()
print("Performance: {dataset:.0f} minutes/dataset, {batch:.1f} ms/batch,"
" {image:.2f} ms/image {rate:.0f} images/sec"
.format(dataset=(end_time - start_time) * (float(len(train_loader)) / batch_count / 60.0),
batch=(end_time - start_time) / float(batch_count) * 1.0e+3,
image=(end_time - start_time) / (batch_count * args.batchSize) * 1.0e+3,
rate=(batch_count * args.batchSize) / (end_time - start_time)))
print(
"Performance: {dataset:.0f} minutes/dataset, {batch:.1f} ms/batch,"
" {image:.2f} ms/image {rate:.0f} images/sec".format(
dataset=(end_time - start_time) * (float(len(train_loader)) / batch_count / 60.0),
batch=(end_time - start_time) / float(batch_count) * 1.0e3,
image=(end_time - start_time) / (batch_count * args.batchSize) * 1.0e3,
rate=(batch_count * args.batchSize) / (end_time - start_time),
)
)
This source diff could not be displayed because it is too large. You can view the blob instead.
"""Run smoke tests"""
import sys
from pathlib import Path
import torch
import torchvision
import torchvision.datasets as dset
import torchvision.transforms
from torchvision.io import decode_jpeg, read_file, read_image
from torchvision.models import resnet50, ResNet50_Weights
SCRIPT_DIR = Path(__file__).parent
def smoke_test_torchvision() -> None:
print(
"Is torchvision usable?",
all(x is not None for x in [torch.ops.image.decode_png, torch.ops.torchvision.roi_align]),
)
def smoke_test_torchvision_read_decode() -> None:
img_jpg = read_image(str(SCRIPT_DIR / "assets" / "encode_jpeg" / "grace_hopper_517x606.jpg"))
if img_jpg.shape != (3, 606, 517):
raise RuntimeError(f"Unexpected shape of img_jpg: {img_jpg.shape}")
img_png = read_image(str(SCRIPT_DIR / "assets" / "interlaced_png" / "wizard_low.png"))
if img_png.shape != (4, 471, 354):
raise RuntimeError(f"Unexpected shape of img_png: {img_png.shape}")
def smoke_test_torchvision_decode_jpeg(device: str = "cpu"):
img_jpg_data = read_file(str(SCRIPT_DIR / "assets" / "encode_jpeg" / "grace_hopper_517x606.jpg"))
img_jpg = decode_jpeg(img_jpg_data, device=device)
if img_jpg.shape != (3, 606, 517):
raise RuntimeError(f"Unexpected shape of img_jpg: {img_jpg.shape}")
def smoke_test_compile() -> None:
try:
model = resnet50().cuda()
model = torch.compile(model)
x = torch.randn(1, 3, 224, 224, device="cuda")
out = model(x)
print(f"torch.compile model output: {out.shape}")
except RuntimeError:
if sys.platform == "win32":
print("Successfully caught torch.compile RuntimeError on win")
else:
raise
def smoke_test_torchvision_resnet50_classify(device: str = "cpu") -> None:
img = read_image(str(SCRIPT_DIR / ".." / "gallery" / "assets" / "dog2.jpg")).to(device)
# Step 1: Initialize model with the best available weights
weights = ResNet50_Weights.DEFAULT
model = resnet50(weights=weights, progress=False).to(device)
model.eval()
# Step 2: Initialize the inference transforms
preprocess = weights.transforms(antialias=(device != "mps")) # antialias not supported on MPS
# Step 3: Apply inference preprocessing transforms
batch = preprocess(img).unsqueeze(0)
# Step 4: Use the model and print the predicted category
prediction = model(batch).squeeze(0).softmax(0)
class_id = prediction.argmax().item()
score = prediction[class_id].item()
category_name = weights.meta["categories"][class_id]
expected_category = "German shepherd"
print(f"{category_name} ({device}): {100 * score:.1f}%")
if category_name != expected_category:
raise RuntimeError(f"Failed ResNet50 classify {category_name} Expected: {expected_category}")
def main() -> None:
print(f"torchvision: {torchvision.__version__}")
print(f"torch.cuda.is_available: {torch.cuda.is_available()}")
# Turn 1.11.0aHASH into 1.11 (major.minor only)
version = ".".join(torchvision.__version__.split(".")[:2])
if version >= "0.16":
print(f"{torch.ops.image._jpeg_version() = }")
assert torch.ops.image._is_compiled_against_turbo()
smoke_test_torchvision()
smoke_test_torchvision_read_decode()
smoke_test_torchvision_resnet50_classify()
smoke_test_torchvision_decode_jpeg()
if torch.cuda.is_available():
smoke_test_torchvision_decode_jpeg("cuda")
smoke_test_torchvision_resnet50_classify("cuda")
# TODO: remove once pytorch/pytorch#110436 is resolved
if sys.version_info < (3, 12, 0):
smoke_test_compile()
if torch.backends.mps.is_available():
smoke_test_torchvision_resnet50_classify("mps")
if __name__ == "__main__":
main()
import unittest
import pytest
import torch
from torchvision.models.maxvit import SwapAxes, WindowDepartition, WindowPartition
class MaxvitTester(unittest.TestCase):
def test_maxvit_window_partition(self):
input_shape = (1, 3, 224, 224)
partition_size = 7
n_partitions = input_shape[3] // partition_size
x = torch.randn(input_shape)
partition = WindowPartition()
departition = WindowDepartition()
x_hat = partition(x, partition_size)
x_hat = departition(x_hat, partition_size, n_partitions, n_partitions)
torch.testing.assert_close(x, x_hat)
def test_maxvit_grid_partition(self):
input_shape = (1, 3, 224, 224)
partition_size = 7
n_partitions = input_shape[3] // partition_size
x = torch.randn(input_shape)
pre_swap = SwapAxes(-2, -3)
post_swap = SwapAxes(-2, -3)
partition = WindowPartition()
departition = WindowDepartition()
x_hat = partition(x, n_partitions)
x_hat = pre_swap(x_hat)
x_hat = post_swap(x_hat)
x_hat = departition(x_hat, n_partitions, partition_size, partition_size)
torch.testing.assert_close(x, x_hat)
if __name__ == "__main__":
pytest.main([__file__])
import unittest
import random
from itertools import chain
from typing import Mapping, Sequence
import pytest
import torch
from torchvision.models.detection.backbone_utils import resnet_fpn_backbone
class ResnetFPNBackboneTester(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.dtype = torch.float32
def test_resnet18_fpn_backbone(self):
device = torch.device('cpu')
x = torch.rand(1, 3, 300, 300, dtype=self.dtype, device=device)
resnet18_fpn = resnet_fpn_backbone(backbone_name='resnet18', pretrained=False)
y = resnet18_fpn(x)
self.assertEqual(list(y.keys()), ['0', '1', '2', '3', 'pool'])
def test_resnet50_fpn_backbone(self):
device = torch.device('cpu')
x = torch.rand(1, 3, 300, 300, dtype=self.dtype, device=device)
resnet50_fpn = resnet_fpn_backbone(backbone_name='resnet50', pretrained=False)
y = resnet50_fpn(x)
self.assertEqual(list(y.keys()), ['0', '1', '2', '3', 'pool'])
from common_utils import set_rng_seed
from torchvision import models
from torchvision.models._utils import IntermediateLayerGetter
from torchvision.models.detection.backbone_utils import BackboneWithFPN, mobilenet_backbone, resnet_fpn_backbone
from torchvision.models.feature_extraction import create_feature_extractor, get_graph_node_names
@pytest.mark.parametrize("backbone_name", ("resnet18", "resnet50"))
def test_resnet_fpn_backbone(backbone_name):
x = torch.rand(1, 3, 300, 300, dtype=torch.float32, device="cpu")
model = resnet_fpn_backbone(backbone_name=backbone_name, weights=None)
assert isinstance(model, BackboneWithFPN)
y = model(x)
assert list(y.keys()) == ["0", "1", "2", "3", "pool"]
with pytest.raises(ValueError, match=r"Trainable layers should be in the range"):
resnet_fpn_backbone(backbone_name=backbone_name, weights=None, trainable_layers=6)
with pytest.raises(ValueError, match=r"Each returned layer should be in the range"):
resnet_fpn_backbone(backbone_name=backbone_name, weights=None, returned_layers=[0, 1, 2, 3])
with pytest.raises(ValueError, match=r"Each returned layer should be in the range"):
resnet_fpn_backbone(backbone_name=backbone_name, weights=None, returned_layers=[2, 3, 4, 5])
@pytest.mark.parametrize("backbone_name", ("mobilenet_v2", "mobilenet_v3_large", "mobilenet_v3_small"))
def test_mobilenet_backbone(backbone_name):
with pytest.raises(ValueError, match=r"Trainable layers should be in the range"):
mobilenet_backbone(backbone_name=backbone_name, weights=None, fpn=False, trainable_layers=-1)
with pytest.raises(ValueError, match=r"Each returned layer should be in the range"):
mobilenet_backbone(backbone_name=backbone_name, weights=None, fpn=True, returned_layers=[-1, 0, 1, 2])
with pytest.raises(ValueError, match=r"Each returned layer should be in the range"):
mobilenet_backbone(backbone_name=backbone_name, weights=None, fpn=True, returned_layers=[3, 4, 5, 6])
model_fpn = mobilenet_backbone(backbone_name=backbone_name, weights=None, fpn=True)
assert isinstance(model_fpn, BackboneWithFPN)
model = mobilenet_backbone(backbone_name=backbone_name, weights=None, fpn=False)
assert isinstance(model, torch.nn.Sequential)
# Needed by TestFxFeatureExtraction.test_leaf_module_and_function
def leaf_function(x):
return int(x)
# Needed by TestFXFeatureExtraction. Checking that node naming conventions
# are respected. Particularly the index postfix of repeated node names
class TestSubModule(torch.nn.Module):
def __init__(self):
super().__init__()
self.relu = torch.nn.ReLU()
def forward(self, x):
x = x + 1
x = x + 1
x = self.relu(x)
x = self.relu(x)
return x
class TestModule(torch.nn.Module):
def __init__(self):
super().__init__()
self.submodule = TestSubModule()
self.relu = torch.nn.ReLU()
def forward(self, x):
x = self.submodule(x)
x = x + 1
x = x + 1
x = self.relu(x)
x = self.relu(x)
return x
test_module_nodes = [
"x",
"submodule.add",
"submodule.add_1",
"submodule.relu",
"submodule.relu_1",
"add",
"add_1",
"relu",
"relu_1",
]
class TestFxFeatureExtraction:
inp = torch.rand(1, 3, 224, 224, dtype=torch.float32, device="cpu")
model_defaults = {"num_classes": 1}
leaf_modules = []
def _create_feature_extractor(self, *args, **kwargs):
"""
Apply leaf modules
"""
tracer_kwargs = {}
if "tracer_kwargs" not in kwargs:
tracer_kwargs = {"leaf_modules": self.leaf_modules}
else:
tracer_kwargs = kwargs.pop("tracer_kwargs")
return create_feature_extractor(*args, **kwargs, tracer_kwargs=tracer_kwargs, suppress_diff_warning=True)
def _get_return_nodes(self, model):
set_rng_seed(0)
exclude_nodes_filter = [
"getitem",
"floordiv",
"size",
"chunk",
"_assert",
"eq",
"dim",
"getattr",
]
train_nodes, eval_nodes = get_graph_node_names(
model, tracer_kwargs={"leaf_modules": self.leaf_modules}, suppress_diff_warning=True
)
# Get rid of any nodes that don't return tensors as they cause issues
# when testing backward pass.
train_nodes = [n for n in train_nodes if not any(x in n for x in exclude_nodes_filter)]
eval_nodes = [n for n in eval_nodes if not any(x in n for x in exclude_nodes_filter)]
return random.sample(train_nodes, 10), random.sample(eval_nodes, 10)
@pytest.mark.parametrize("model_name", models.list_models(models))
def test_build_fx_feature_extractor(self, model_name):
set_rng_seed(0)
model = models.get_model(model_name, **self.model_defaults).eval()
train_return_nodes, eval_return_nodes = self._get_return_nodes(model)
# Check that it works with both a list and dict for return nodes
self._create_feature_extractor(
model, train_return_nodes={v: v for v in train_return_nodes}, eval_return_nodes=eval_return_nodes
)
self._create_feature_extractor(
model, train_return_nodes=train_return_nodes, eval_return_nodes=eval_return_nodes
)
# Check must specify return nodes
with pytest.raises(ValueError):
self._create_feature_extractor(model)
# Check return_nodes and train_return_nodes / eval_return nodes
# mutual exclusivity
with pytest.raises(ValueError):
self._create_feature_extractor(
model, return_nodes=train_return_nodes, train_return_nodes=train_return_nodes
)
# Check train_return_nodes / eval_return nodes must both be specified
with pytest.raises(ValueError):
self._create_feature_extractor(model, train_return_nodes=train_return_nodes)
# Check invalid node name raises ValueError
with pytest.raises(ValueError):
# First just double check that this node really doesn't exist
if not any(n.startswith("l") or n.startswith("l.") for n in chain(train_return_nodes, eval_return_nodes)):
self._create_feature_extractor(model, train_return_nodes=["l"], eval_return_nodes=["l"])
else: # otherwise skip this check
raise ValueError
def test_node_name_conventions(self):
model = TestModule()
train_nodes, _ = get_graph_node_names(model)
assert all(a == b for a, b in zip(train_nodes, test_module_nodes))
@pytest.mark.parametrize("model_name", models.list_models(models))
def test_forward_backward(self, model_name):
model = models.get_model(model_name, **self.model_defaults).train()
train_return_nodes, eval_return_nodes = self._get_return_nodes(model)
model = self._create_feature_extractor(
model, train_return_nodes=train_return_nodes, eval_return_nodes=eval_return_nodes
)
out = model(self.inp)
out_agg = 0
for node_out in out.values():
if isinstance(node_out, Sequence):
out_agg += sum(o.float().mean() for o in node_out if o is not None)
elif isinstance(node_out, Mapping):
out_agg += sum(o.float().mean() for o in node_out.values() if o is not None)
else:
# Assume that the only other alternative at this point is a Tensor
out_agg += node_out.float().mean()
out_agg.backward()
def test_feature_extraction_methods_equivalence(self):
model = models.resnet18(**self.model_defaults).eval()
return_layers = {"layer1": "layer1", "layer2": "layer2", "layer3": "layer3", "layer4": "layer4"}
ilg_model = IntermediateLayerGetter(model, return_layers).eval()
fx_model = self._create_feature_extractor(model, return_layers)
# Check that we have same parameters
for (n1, p1), (n2, p2) in zip(ilg_model.named_parameters(), fx_model.named_parameters()):
assert n1 == n2
assert p1.equal(p2)
# And that outputs match
with torch.no_grad():
ilg_out = ilg_model(self.inp)
fgn_out = fx_model(self.inp)
assert all(k1 == k2 for k1, k2 in zip(ilg_out.keys(), fgn_out.keys()))
for k in ilg_out.keys():
assert ilg_out[k].equal(fgn_out[k])
@pytest.mark.parametrize("model_name", models.list_models(models))
def test_jit_forward_backward(self, model_name):
set_rng_seed(0)
model = models.get_model(model_name, **self.model_defaults).train()
train_return_nodes, eval_return_nodes = self._get_return_nodes(model)
model = self._create_feature_extractor(
model, train_return_nodes=train_return_nodes, eval_return_nodes=eval_return_nodes
)
model = torch.jit.script(model)
fgn_out = model(self.inp)
out_agg = 0
for node_out in fgn_out.values():
if isinstance(node_out, Sequence):
out_agg += sum(o.float().mean() for o in node_out if o is not None)
elif isinstance(node_out, Mapping):
out_agg += sum(o.float().mean() for o in node_out.values() if o is not None)
else:
# Assume that the only other alternative at this point is a Tensor
out_agg += node_out.float().mean()
out_agg.backward()
def test_train_eval(self):
class TestModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.dropout = torch.nn.Dropout(p=1.0)
def forward(self, x):
x = x.float().mean()
x = self.dropout(x) # dropout
if self.training:
x += 100 # add
else:
x *= 0 # mul
x -= 0 # sub
return x
model = TestModel()
train_return_nodes = ["dropout", "add", "sub"]
eval_return_nodes = ["dropout", "mul", "sub"]
def checks(model, mode):
with torch.no_grad():
out = model(torch.ones(10, 10))
if mode == "train":
# Check that dropout is respected
assert out["dropout"].item() == 0
# Check that control flow dependent on training_mode is respected
assert out["sub"].item() == 100
assert "add" in out
assert "mul" not in out
elif mode == "eval":
# Check that dropout is respected
assert out["dropout"].item() == 1
# Check that control flow dependent on training_mode is respected
assert out["sub"].item() == 0
assert "mul" in out
assert "add" not in out
# Starting from train mode
model.train()
fx_model = self._create_feature_extractor(
model, train_return_nodes=train_return_nodes, eval_return_nodes=eval_return_nodes
)
# Check that the models stay in their original training state
assert model.training
assert fx_model.training
# Check outputs
checks(fx_model, "train")
# Check outputs after switching to eval mode
fx_model.eval()
checks(fx_model, "eval")
# Starting from eval mode
model.eval()
fx_model = self._create_feature_extractor(
model, train_return_nodes=train_return_nodes, eval_return_nodes=eval_return_nodes
)
# Check that the models stay in their original training state
assert not model.training
assert not fx_model.training
# Check outputs
checks(fx_model, "eval")
# Check outputs after switching to train mode
fx_model.train()
checks(fx_model, "train")
def test_leaf_module_and_function(self):
class LeafModule(torch.nn.Module):
def forward(self, x):
# This would raise a TypeError if it were not in a leaf module
int(x.shape[0])
return torch.nn.functional.relu(x + 4)
class TestModule(torch.nn.Module):
def __init__(self):
super().__init__()
self.conv = torch.nn.Conv2d(3, 1, 3)
self.leaf_module = LeafModule()
def forward(self, x):
leaf_function(x.shape[0])
x = self.conv(x)
return self.leaf_module(x)
model = self._create_feature_extractor(
TestModule(),
return_nodes=["leaf_module"],
tracer_kwargs={"leaf_modules": [LeafModule], "autowrap_functions": [leaf_function]},
).train()
# Check that LeafModule is not in the list of nodes
assert "relu" not in [str(n) for n in model.graph.nodes]
assert "leaf_module" in [str(n) for n in model.graph.nodes]
# Check forward
out = model(self.inp)
# And backward
out["leaf_module"].float().mean().backward()
import torch
import os
import unittest
from torchvision import models, transforms
import sys
from PIL import Image
import torchvision.transforms.functional as F
try:
from torchvision import _C_tests
except ImportError:
_C_tests = None
def process_model(model, tensor, func, name):
model.eval()
traced_script_module = torch.jit.trace(model, tensor)
traced_script_module.save("model.pt")
py_output = model.forward(tensor)
cpp_output = func("model.pt", tensor)
assert torch.allclose(py_output, cpp_output), 'Output mismatch of ' + name + ' models'
def read_image1():
image_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'assets', 'encode_jpeg',
'grace_hopper_517x606.jpg')
image = Image.open(image_path)
image = image.resize((224, 224))
x = F.to_tensor(image)
return x.view(1, 3, 224, 224)
def read_image2():
image_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'assets', 'encode_jpeg',
'grace_hopper_517x606.jpg')
image = Image.open(image_path)
image = image.resize((299, 299))
x = F.to_tensor(image)
x = x.view(1, 3, 299, 299)
return torch.cat([x, x], 0)
@unittest.skipIf(
sys.platform == "darwin" or True,
"C++ models are broken on OS X at the moment, and there's a BC breakage on master; "
"see https://github.com/pytorch/vision/issues/1191")
class Tester(unittest.TestCase):
pretrained = False
image = read_image1()
def test_alexnet(self):
process_model(models.alexnet(self.pretrained), self.image, _C_tests.forward_alexnet, 'Alexnet')
def test_vgg11(self):
process_model(models.vgg11(self.pretrained), self.image, _C_tests.forward_vgg11, 'VGG11')
def test_vgg13(self):
process_model(models.vgg13(self.pretrained), self.image, _C_tests.forward_vgg13, 'VGG13')
def test_vgg16(self):
process_model(models.vgg16(self.pretrained), self.image, _C_tests.forward_vgg16, 'VGG16')
def test_vgg19(self):
process_model(models.vgg19(self.pretrained), self.image, _C_tests.forward_vgg19, 'VGG19')
def test_vgg11_bn(self):
process_model(models.vgg11_bn(self.pretrained), self.image, _C_tests.forward_vgg11bn, 'VGG11BN')
def test_vgg13_bn(self):
process_model(models.vgg13_bn(self.pretrained), self.image, _C_tests.forward_vgg13bn, 'VGG13BN')
def test_vgg16_bn(self):
process_model(models.vgg16_bn(self.pretrained), self.image, _C_tests.forward_vgg16bn, 'VGG16BN')
def test_vgg19_bn(self):
process_model(models.vgg19_bn(self.pretrained), self.image, _C_tests.forward_vgg19bn, 'VGG19BN')
def test_resnet18(self):
process_model(models.resnet18(self.pretrained), self.image, _C_tests.forward_resnet18, 'Resnet18')
def test_resnet34(self):
process_model(models.resnet34(self.pretrained), self.image, _C_tests.forward_resnet34, 'Resnet34')
def test_resnet50(self):
process_model(models.resnet50(self.pretrained), self.image, _C_tests.forward_resnet50, 'Resnet50')
def test_resnet101(self):
process_model(models.resnet101(self.pretrained), self.image, _C_tests.forward_resnet101, 'Resnet101')
def test_resnet152(self):
process_model(models.resnet152(self.pretrained), self.image, _C_tests.forward_resnet152, 'Resnet152')
def test_resnext50_32x4d(self):
process_model(models.resnext50_32x4d(), self.image, _C_tests.forward_resnext50_32x4d, 'ResNext50_32x4d')
def test_resnext101_32x8d(self):
process_model(models.resnext101_32x8d(), self.image, _C_tests.forward_resnext101_32x8d, 'ResNext101_32x8d')
def test_wide_resnet50_2(self):
process_model(models.wide_resnet50_2(), self.image, _C_tests.forward_wide_resnet50_2, 'WideResNet50_2')
def test_wide_resnet101_2(self):
process_model(models.wide_resnet101_2(), self.image, _C_tests.forward_wide_resnet101_2, 'WideResNet101_2')
def test_squeezenet1_0(self):
process_model(models.squeezenet1_0(self.pretrained), self.image,
_C_tests.forward_squeezenet1_0, 'Squeezenet1.0')
def test_squeezenet1_1(self):
process_model(models.squeezenet1_1(self.pretrained), self.image,
_C_tests.forward_squeezenet1_1, 'Squeezenet1.1')
def test_densenet121(self):
process_model(models.densenet121(self.pretrained), self.image, _C_tests.forward_densenet121, 'Densenet121')
def test_densenet169(self):
process_model(models.densenet169(self.pretrained), self.image, _C_tests.forward_densenet169, 'Densenet169')
def test_densenet201(self):
process_model(models.densenet201(self.pretrained), self.image, _C_tests.forward_densenet201, 'Densenet201')
def test_densenet161(self):
process_model(models.densenet161(self.pretrained), self.image, _C_tests.forward_densenet161, 'Densenet161')
def test_mobilenet_v2(self):
process_model(models.mobilenet_v2(self.pretrained), self.image, _C_tests.forward_mobilenetv2, 'MobileNet')
def test_googlenet(self):
process_model(models.googlenet(self.pretrained), self.image, _C_tests.forward_googlenet, 'GoogLeNet')
def test_mnasnet0_5(self):
process_model(models.mnasnet0_5(self.pretrained), self.image, _C_tests.forward_mnasnet0_5, 'MNASNet0_5')
def test_mnasnet0_75(self):
process_model(models.mnasnet0_75(self.pretrained), self.image, _C_tests.forward_mnasnet0_75, 'MNASNet0_75')
def test_mnasnet1_0(self):
process_model(models.mnasnet1_0(self.pretrained), self.image, _C_tests.forward_mnasnet1_0, 'MNASNet1_0')
def test_mnasnet1_3(self):
process_model(models.mnasnet1_3(self.pretrained), self.image, _C_tests.forward_mnasnet1_3, 'MNASNet1_3')
def test_inception_v3(self):
self.image = read_image2()
process_model(models.inception_v3(self.pretrained), self.image, _C_tests.forward_inceptionv3, 'Inceptionv3')
if __name__ == '__main__':
unittest.main()
import bz2
import contextlib
import csv
import io
import itertools
import json
import os
import pathlib
import pickle
import json
import random
import re
import shutil
import string
import unittest
import xml.etree.ElementTree as ET
import zipfile
from typing import Callable, Tuple, Union
import PIL
import datasets_utils
import numpy as np
import PIL
import pytest
import torch
import torch.nn.functional as F
from common_utils import combinations_grid
from torchvision import datasets
from torchvision.transforms import v2
class STL10TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.STL10
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(
split=("train", "test", "unlabeled", "train+unlabeled"))
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test", "unlabeled", "train+unlabeled"))
@staticmethod
def _make_binary_file(num_elements, root, name):
......@@ -88,20 +93,20 @@ class STL10TestCase(datasets_utils.ImageDatasetTestCase):
def test_folds(self):
for fold in range(10):
with self.create_dataset(split="train", folds=fold) as (dataset, _):
self.assertEqual(len(dataset), fold + 1)
assert len(dataset) == fold + 1
def test_unlabeled(self):
with self.create_dataset(split="unlabeled") as (dataset, _):
labels = [dataset[idx][1] for idx in range(len(dataset))]
self.assertTrue(all(label == -1 for label in labels))
assert all(label == -1 for label in labels)
def test_invalid_folds1(self):
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
with self.create_dataset(folds=10):
pass
def test_invalid_folds2(self):
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
with self.create_dataset(folds="0"):
pass
......@@ -110,9 +115,7 @@ class Caltech101TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Caltech101
FEATURE_TYPES = (PIL.Image.Image, (int, np.ndarray, tuple))
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(
target_type=("category", "annotation", ["category", "annotation"])
)
ADDITIONAL_CONFIGS = combinations_grid(target_type=("category", "annotation", ["category", "annotation"]))
REQUIRED_PACKAGES = ("scipy",)
def inject_fake_data(self, tmpdir, config):
......@@ -167,23 +170,24 @@ class Caltech101TestCase(datasets_utils.ImageDatasetTestCase):
actual = len(individual_targets)
expected = len(combined_targets)
self.assertEqual(
actual,
expected,
f"The number of the returned combined targets does not match the the number targets if requested "
assert (
actual == expected
), "The number of the returned combined targets does not match the the number targets if requested "
f"individually: {actual} != {expected}",
)
for target_type, combined_target, individual_target in zip(target_types, combined_targets, individual_targets):
with self.subTest(target_type=target_type):
actual = type(combined_target)
expected = type(individual_target)
self.assertIs(
actual,
expected,
f"Type of the combined target does not match the type of the corresponding individual target: "
assert (
actual is expected
), "Type of the combined target does not match the type of the corresponding individual target: "
f"{actual} is not {expected}",
)
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(target_type="category", transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class Caltech256TestCase(datasets_utils.ImageDatasetTestCase):
......@@ -192,7 +196,7 @@ class Caltech256TestCase(datasets_utils.ImageDatasetTestCase):
def inject_fake_data(self, tmpdir, config):
tmpdir = pathlib.Path(tmpdir) / "caltech256" / "256_ObjectCategories"
categories = ((1, "ak47"), (127, "laptop-101"), (257, "clutter"))
categories = ((1, "ak47"), (2, "american-flag"), (3, "backpack"))
num_images_per_category = 2
for idx, category in categories:
......@@ -209,11 +213,11 @@ class Caltech256TestCase(datasets_utils.ImageDatasetTestCase):
class WIDERFaceTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.WIDERFace
FEATURE_TYPES = (PIL.Image.Image, (dict, type(None))) # test split returns None as target
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(split=('train', 'val', 'test'))
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "val", "test"))
def inject_fake_data(self, tmpdir, config):
widerface_dir = pathlib.Path(tmpdir) / 'widerface'
annotations_dir = widerface_dir / 'wider_face_split'
widerface_dir = pathlib.Path(tmpdir) / "widerface"
annotations_dir = widerface_dir / "wider_face_split"
os.makedirs(annotations_dir)
split_to_idx = split_to_num_examples = {
......@@ -223,21 +227,21 @@ class WIDERFaceTestCase(datasets_utils.ImageDatasetTestCase):
}
# We need to create all folders regardless of the split in config
for split in ('train', 'val', 'test'):
for split in ("train", "val", "test"):
split_idx = split_to_idx[split]
num_examples = split_to_num_examples[split]
datasets_utils.create_image_folder(
root=tmpdir,
name=widerface_dir / f'WIDER_{split}' / 'images' / '0--Parade',
name=widerface_dir / f"WIDER_{split}" / "images" / "0--Parade",
file_name_fn=lambda image_idx: f"0_Parade_marchingband_1_{split_idx + image_idx}.jpg",
num_examples=num_examples,
)
annotation_file_name = {
'train': annotations_dir / 'wider_face_train_bbx_gt.txt',
'val': annotations_dir / 'wider_face_val_bbx_gt.txt',
'test': annotations_dir / 'wider_face_test_filelist.txt',
"train": annotations_dir / "wider_face_train_bbx_gt.txt",
"val": annotations_dir / "wider_face_val_bbx_gt.txt",
"test": annotations_dir / "wider_face_test_filelist.txt",
}[split]
annotation_content = {
......@@ -260,6 +264,11 @@ class WIDERFaceTestCase(datasets_utils.ImageDatasetTestCase):
return split_to_num_examples[config["split"]]
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class CityScapesTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Cityscapes
......@@ -270,10 +279,8 @@ class CityScapesTestCase(datasets_utils.ImageDatasetTestCase):
"color",
)
ADDITIONAL_CONFIGS = (
*datasets_utils.combinations_grid(
mode=("fine",), split=("train", "test", "val"), target_type=TARGET_TYPES
),
*datasets_utils.combinations_grid(
*combinations_grid(mode=("fine",), split=("train", "test", "val"), target_type=TARGET_TYPES),
*combinations_grid(
mode=("coarse",),
split=("train", "train_extra", "val"),
target_type=TARGET_TYPES,
......@@ -327,6 +334,7 @@ class CityScapesTestCase(datasets_utils.ImageDatasetTestCase):
gt_dir = tmpdir / f"gt{mode}"
for split in mode_to_splits[mode]:
for city in cities:
def make_image(name, size=10):
datasets_utils.create_image_folder(
root=gt_dir / split,
......@@ -335,6 +343,7 @@ class CityScapesTestCase(datasets_utils.ImageDatasetTestCase):
size=size,
num_examples=1,
)
make_image(f"{city}_000000_000000_gt{mode}_instanceIds.png")
make_image(f"{city}_000000_000000_gt{mode}_labelIds.png")
make_image(f"{city}_000000_000000_gt{mode}_color.png", size=(4, 10, 10))
......@@ -344,7 +353,7 @@ class CityScapesTestCase(datasets_utils.ImageDatasetTestCase):
json.dump(polygon_target, outfile)
# Create leftImg8bit folder
for split in ['test', 'train_extra', 'train', 'val']:
for split in ["test", "train_extra", "train", "val"]:
for city in cities:
datasets_utils.create_image_folder(
root=tmpdir / "leftImg8bit" / split,
......@@ -353,52 +362,58 @@ class CityScapesTestCase(datasets_utils.ImageDatasetTestCase):
num_examples=1,
)
info = {'num_examples': len(cities)}
if config['target_type'] == 'polygon':
info['expected_polygon_target'] = polygon_target
info = {"num_examples": len(cities)}
if config["target_type"] == "polygon":
info["expected_polygon_target"] = polygon_target
return info
def test_combined_targets(self):
target_types = ['semantic', 'polygon', 'color']
target_types = ["semantic", "polygon", "color"]
with self.create_dataset(target_type=target_types) as (dataset, _):
output = dataset[0]
self.assertTrue(isinstance(output, tuple))
self.assertTrue(len(output) == 2)
self.assertTrue(isinstance(output[0], PIL.Image.Image))
self.assertTrue(isinstance(output[1], tuple))
self.assertTrue(len(output[1]) == 3)
self.assertTrue(isinstance(output[1][0], PIL.Image.Image)) # semantic
self.assertTrue(isinstance(output[1][1], dict)) # polygon
self.assertTrue(isinstance(output[1][2], PIL.Image.Image)) # color
assert isinstance(output, tuple)
assert len(output) == 2
assert isinstance(output[0], PIL.Image.Image)
assert isinstance(output[1], tuple)
assert len(output[1]) == 3
assert isinstance(output[1][0], PIL.Image.Image) # semantic
assert isinstance(output[1][1], dict) # polygon
assert isinstance(output[1][2], PIL.Image.Image) # color
def test_feature_types_target_color(self):
with self.create_dataset(target_type='color') as (dataset, _):
with self.create_dataset(target_type="color") as (dataset, _):
color_img, color_target = dataset[0]
self.assertTrue(isinstance(color_img, PIL.Image.Image))
self.assertTrue(np.array(color_target).shape[2] == 4)
assert isinstance(color_img, PIL.Image.Image)
assert np.array(color_target).shape[2] == 4
def test_feature_types_target_polygon(self):
with self.create_dataset(target_type='polygon') as (dataset, info):
with self.create_dataset(target_type="polygon") as (dataset, info):
polygon_img, polygon_target = dataset[0]
self.assertTrue(isinstance(polygon_img, PIL.Image.Image))
self.assertEqual(polygon_target, info['expected_polygon_target'])
assert isinstance(polygon_img, PIL.Image.Image)
(polygon_target, info["expected_polygon_target"])
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
for target_type in ["instance", "semantic", ["instance", "semantic"]]:
with self.create_dataset(target_type=target_type, transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class ImageNetTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.ImageNet
REQUIRED_PACKAGES = ('scipy',)
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(split=('train', 'val'))
REQUIRED_PACKAGES = ("scipy",)
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "val"))
def inject_fake_data(self, tmpdir, config):
tmpdir = pathlib.Path(tmpdir)
wnid = 'n01234567'
if config['split'] == 'train':
wnid = "n01234567"
if config["split"] == "train":
num_examples = 3
datasets_utils.create_image_folder(
root=tmpdir,
name=tmpdir / 'train' / wnid / wnid,
name=tmpdir / "train" / wnid / wnid,
file_name_fn=lambda image_idx: f"{wnid}_{image_idx}.JPEG",
num_examples=num_examples,
)
......@@ -406,19 +421,24 @@ class ImageNetTestCase(datasets_utils.ImageDatasetTestCase):
num_examples = 1
datasets_utils.create_image_folder(
root=tmpdir,
name=tmpdir / 'val' / wnid,
name=tmpdir / "val" / wnid,
file_name_fn=lambda image_ifx: "ILSVRC2012_val_0000000{image_idx}.JPEG",
num_examples=num_examples,
)
wnid_to_classes = {wnid: [1]}
torch.save((wnid_to_classes, None), tmpdir / 'meta.bin')
torch.save((wnid_to_classes, None), tmpdir / "meta.bin")
return num_examples
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class CIFAR10TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.CIFAR10
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(train=(True, False))
ADDITIONAL_CONFIGS = combinations_grid(train=(True, False))
_VERSION_CONFIG = dict(
base_folder="cifar-10-batches-py",
......@@ -447,8 +467,9 @@ class CIFAR10TestCase(datasets_utils.ImageDatasetTestCase):
)
def _create_batch_file(self, root, name, num_images):
np_rng = np.random.RandomState(0)
data = datasets_utils.create_image_or_video_tensor((num_images, 32 * 32 * 3))
labels = np.random.randint(0, self._VERSION_CONFIG["num_categories"], size=num_images).tolist()
labels = np_rng.randint(0, self._VERSION_CONFIG["num_categories"], size=num_images).tolist()
self._create_binary_file(root, name, {"data": data, self._VERSION_CONFIG["labels_key"]: labels})
def _create_meta_file(self, root):
......@@ -469,7 +490,7 @@ class CIFAR10TestCase(datasets_utils.ImageDatasetTestCase):
with self.create_dataset() as (dataset, info):
expected = {category: label for label, category in enumerate(info["categories"])}
actual = dataset.class_to_idx
self.assertEqual(actual, expected)
assert actual == expected
class CIFAR100(CIFAR10TestCase):
......@@ -490,7 +511,7 @@ class CelebATestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.CelebA
FEATURE_TYPES = (PIL.Image.Image, (torch.Tensor, int, tuple, type(None)))
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(
ADDITIONAL_CONFIGS = combinations_grid(
split=("train", "valid", "test", "all"),
target_type=("attr", "identity", "bbox", "landmarks", ["attr", "identity"]),
)
......@@ -514,7 +535,7 @@ class CelebATestCase(datasets_utils.ImageDatasetTestCase):
return dict(num_examples=num_images_per_split[config["split"]], attr_names=attr_names)
def _create_split_txt(self, root):
num_images_per_split = dict(train=3, valid=2, test=1)
num_images_per_split = dict(train=4, valid=3, test=2)
data = [
[self._SPLIT_TO_IDX[split]] for split, num_images in num_images_per_split.items() for _ in range(num_images)
......@@ -573,33 +594,46 @@ class CelebATestCase(datasets_utils.ImageDatasetTestCase):
actual = len(individual_targets)
expected = len(combined_targets)
self.assertEqual(
actual,
expected,
f"The number of the returned combined targets does not match the the number targets if requested "
assert (
actual == expected
), "The number of the returned combined targets does not match the the number targets if requested "
f"individually: {actual} != {expected}",
)
for target_type, combined_target, individual_target in zip(target_types, combined_targets, individual_targets):
with self.subTest(target_type=target_type):
actual = type(combined_target)
expected = type(individual_target)
self.assertIs(
actual,
expected,
f"Type of the combined target does not match the type of the corresponding individual target: "
assert (
actual is expected
), "Type of the combined target does not match the type of the corresponding individual target: "
f"{actual} is not {expected}",
)
def test_no_target(self):
with self.create_dataset(target_type=[]) as (dataset, _):
_, target = dataset[0]
self.assertIsNone(target)
assert target is None
def test_attr_names(self):
with self.create_dataset() as (dataset, info):
self.assertEqual(tuple(dataset.attr_names), info["attr_names"])
assert tuple(dataset.attr_names) == info["attr_names"]
def test_images_names_split(self):
with self.create_dataset(split="all") as (dataset, _):
all_imgs_names = set(dataset.filename)
merged_imgs_names = set()
for split in ["train", "valid", "test"]:
with self.create_dataset(split=split) as (dataset, _):
merged_imgs_names.update(dataset.filename)
assert merged_imgs_names == all_imgs_names
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
for target_type in ["identity", "bbox", ["identity", "bbox"]]:
with self.create_dataset(target_type=target_type, transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class VOCSegmentationTestCase(datasets_utils.ImageDatasetTestCase):
......@@ -607,19 +641,12 @@ class VOCSegmentationTestCase(datasets_utils.ImageDatasetTestCase):
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image)
ADDITIONAL_CONFIGS = (
*datasets_utils.combinations_grid(
year=[f"20{year:02d}" for year in range(7, 13)], image_set=("train", "val", "trainval")
),
*combinations_grid(year=[f"20{year:02d}" for year in range(7, 13)], image_set=("train", "val", "trainval")),
dict(year="2007", image_set="test"),
dict(year="2007-test", image_set="test"),
)
def inject_fake_data(self, tmpdir, config):
year, is_test_set = (
("2007", True)
if config["year"] == "2007-test" or config["image_set"] == "test"
else (config["year"], False)
)
year, is_test_set = config["year"], config["image_set"] == "test"
image_set = config["image_set"]
base_dir = pathlib.Path(tmpdir)
......@@ -650,7 +677,7 @@ class VOCSegmentationTestCase(datasets_utils.ImageDatasetTestCase):
shutil.copytree(src, root / "Segmentation")
num_images = max(itertools.chain(*idcs.values())) + 1
num_images_per_image_set = dict([(image_set, len(idcs_)) for image_set, idcs_ in idcs.items()])
num_images_per_image_set = {image_set: len(idcs_) for image_set, idcs_ in idcs.items()}
return num_images, num_images_per_image_set
def _create_image_set_file(self, root, image_set, idcs):
......@@ -695,6 +722,11 @@ class VOCSegmentationTestCase(datasets_utils.ImageDatasetTestCase):
return data
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class VOCDetectionTestCase(VOCSegmentationTestCase):
DATASET_CLASS = datasets.VOCDetection
......@@ -704,16 +736,21 @@ class VOCDetectionTestCase(VOCSegmentationTestCase):
with self.create_dataset() as (dataset, info):
_, target = dataset[0]
self.assertIn("annotation", target)
assert "annotation" in target
annotation = target["annotation"]
self.assertIn("object", annotation)
assert "object" in annotation
objects = annotation["object"]
self.assertEqual(len(objects), 1)
assert len(objects) == 1
object = objects[0]
self.assertEqual(object, info["annotation"])
assert object == info["annotation"]
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class CocoDetectionTestCase(datasets_utils.ImageDatasetTestCase):
......@@ -745,28 +782,52 @@ class CocoDetectionTestCase(datasets_utils.ImageDatasetTestCase):
annotation_folder = tmpdir / self._ANNOTATIONS_FOLDER
os.makedirs(annotation_folder)
segmentation_kind = config.pop("segmentation_kind", "list")
info = self._create_annotation_file(
annotation_folder, self._ANNOTATIONS_FILE, file_names, num_annotations_per_image
annotation_folder,
self._ANNOTATIONS_FILE,
file_names,
num_annotations_per_image,
segmentation_kind=segmentation_kind,
)
info["num_examples"] = num_images
return info
def _create_annotation_file(self, root, name, file_names, num_annotations_per_image):
def _create_annotation_file(self, root, name, file_names, num_annotations_per_image, segmentation_kind="list"):
image_ids = [int(file_name.stem) for file_name in file_names]
images = [dict(file_name=str(file_name), id=id) for file_name, id in zip(file_names, image_ids)]
annotations, info = self._create_annotations(image_ids, num_annotations_per_image)
annotations, info = self._create_annotations(image_ids, num_annotations_per_image, segmentation_kind)
self._create_json(root, name, dict(images=images, annotations=annotations))
return info
def _create_annotations(self, image_ids, num_annotations_per_image):
annotations = datasets_utils.combinations_grid(
image_id=image_ids, bbox=([1.0, 2.0, 3.0, 4.0],) * num_annotations_per_image
def _create_annotations(self, image_ids, num_annotations_per_image, segmentation_kind="list"):
annotations = []
annotion_id = 0
for image_id in itertools.islice(itertools.cycle(image_ids), len(image_ids) * num_annotations_per_image):
segmentation = {
"list": [torch.rand(8).tolist()],
"rle": {"size": [10, 10], "counts": [1]},
"rle_encoded": {"size": [2400, 2400], "counts": "PQRQ2[1\\Y2f0gNVNRhMg2"},
"bad": 123,
}[segmentation_kind]
annotations.append(
dict(
image_id=image_id,
id=annotion_id,
bbox=torch.rand(4).tolist(),
segmentation=segmentation,
category_id=int(torch.randint(91, ())),
area=float(torch.rand(1)),
iscrowd=int(torch.randint(2, size=(1,))),
)
for id, annotation in enumerate(annotations):
annotation["id"] = id
)
annotion_id += 1
return annotations, dict()
def _create_json(self, root, name, content):
......@@ -775,13 +836,39 @@ class CocoDetectionTestCase(datasets_utils.ImageDatasetTestCase):
json.dump(content, fh)
return file
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
def test_slice_error(self):
with self.create_dataset() as (dataset, _):
with pytest.raises(ValueError, match="Index must be of type integer"):
dataset[:2]
def test_segmentation_kind(self):
if isinstance(self, CocoCaptionsTestCase):
return
for segmentation_kind in ("list", "rle", "rle_encoded"):
config = {"segmentation_kind": segmentation_kind}
with self.create_dataset(config) as (dataset, _):
dataset = datasets.wrap_dataset_for_transforms_v2(dataset, target_keys="all")
list(dataset)
config = {"segmentation_kind": "bad"}
with self.create_dataset(config) as (dataset, _):
dataset = datasets.wrap_dataset_for_transforms_v2(dataset, target_keys="all")
with pytest.raises(ValueError, match="COCO segmentation expected to be a dict or a list"):
list(dataset)
class CocoCaptionsTestCase(CocoDetectionTestCase):
DATASET_CLASS = datasets.CocoCaptions
def _create_annotations(self, image_ids, num_annotations_per_image):
def _create_annotations(self, image_ids, num_annotations_per_image, segmentation_kind="list"):
captions = [str(idx) for idx in range(num_annotations_per_image)]
annotations = datasets_utils.combinations_grid(image_id=image_ids, caption=captions)
annotations = combinations_grid(image_id=image_ids, caption=captions)
for id, annotation in enumerate(annotations):
annotation["id"] = id
return annotations, dict(captions=captions)
......@@ -789,13 +876,18 @@ class CocoCaptionsTestCase(CocoDetectionTestCase):
def test_captions(self):
with self.create_dataset() as (dataset, info):
_, captions = dataset[0]
self.assertEqual(tuple(captions), tuple(info["captions"]))
assert tuple(captions) == tuple(info["captions"])
def test_transforms_v2_wrapper_spawn(self):
# We need to define this method, because otherwise the test from the super class will
# be run
pytest.skip("CocoCaptions is currently not supported by the v2 wrapper.")
class UCF101TestCase(datasets_utils.VideoDatasetTestCase):
DATASET_CLASS = datasets.UCF101
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(fold=(1, 2, 3), train=(True, False))
ADDITIONAL_CONFIGS = combinations_grid(fold=(1, 2, 3), train=(True, False))
_VIDEO_FOLDER = "videos"
_ANNOTATIONS_FOLDER = "annotations"
......@@ -849,16 +941,14 @@ class UCF101TestCase(datasets_utils.VideoDatasetTestCase):
def _create_annotation_file(self, root, name, video_files):
with open(pathlib.Path(root) / name, "w") as fh:
fh.writelines(f"{file}\n" for file in sorted(video_files))
fh.writelines(f"{str(file).replace(os.sep, '/')}\n" for file in sorted(video_files))
class LSUNTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.LSUN
REQUIRED_PACKAGES = ("lmdb",)
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(
classes=("train", "test", "val", ["bedroom_train", "church_outdoor_train"])
)
ADDITIONAL_CONFIGS = combinations_grid(classes=("train", "test", "val", ["bedroom_train", "church_outdoor_train"]))
_CATEGORIES = (
"bedroom",
......@@ -883,10 +973,7 @@ class LSUNTestCase(datasets_utils.ImageDatasetTestCase):
return num_images
@contextlib.contextmanager
def create_dataset(
self,
*args, **kwargs
):
def create_dataset(self, *args, **kwargs):
with super().create_dataset(*args, **kwargs) as output:
yield output
# Currently datasets.LSUN caches the keys in the current directory rather than in the root directory. Thus,
......@@ -940,33 +1027,39 @@ class LSUNTestCase(datasets_utils.ImageDatasetTestCase):
def test_not_found_or_corrupted(self):
# LSUN does not raise built-in exception, but a custom one. It is expressive enough to not 'cast' it to
# RuntimeError or FileNotFoundError that are normally checked by this test.
with self.assertRaises(datasets_utils.lazy_importer.lmdb.Error):
with pytest.raises(datasets_utils.lazy_importer.lmdb.Error):
super().test_not_found_or_corrupted()
class Kinetics400TestCase(datasets_utils.VideoDatasetTestCase):
DATASET_CLASS = datasets.Kinetics400
class KineticsTestCase(datasets_utils.VideoDatasetTestCase):
DATASET_CLASS = datasets.Kinetics
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "val"), num_classes=("400", "600", "700"))
def inject_fake_data(self, tmpdir, config):
classes = ("Abseiling", "Zumba")
num_videos_per_class = 2
tmpdir = pathlib.Path(tmpdir) / config["split"]
digits = string.ascii_letters + string.digits + "-_"
for cls in classes:
datasets_utils.create_video_folder(
tmpdir,
cls,
lambda _: f"{datasets_utils.create_random_string(11, digits)}.avi",
lambda _: f"{datasets_utils.create_random_string(11, digits)}.mp4",
num_videos_per_class,
)
return num_videos_per_class * len(classes)
@pytest.mark.xfail(reason="FIXME")
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(output_format="TCHW", transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class HMDB51TestCase(datasets_utils.VideoDatasetTestCase):
DATASET_CLASS = datasets.HMDB51
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(fold=(1, 2, 3), train=(True, False))
ADDITIONAL_CONFIGS = combinations_grid(fold=(1, 2, 3), train=(True, False))
_VIDEO_FOLDER = "videos"
_SPLITS_FOLDER = "splits"
......@@ -1026,7 +1119,7 @@ class HMDB51TestCase(datasets_utils.VideoDatasetTestCase):
class OmniglotTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Omniglot
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(background=(True, False))
ADDITIONAL_CONFIGS = combinations_grid(background=(True, False))
def inject_fake_data(self, tmpdir, config):
target_folder = (
......@@ -1106,7 +1199,7 @@ class SEMEIONTestCase(datasets_utils.ImageDatasetTestCase):
class USPSTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.USPS
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(train=(True, False))
ADDITIONAL_CONFIGS = combinations_grid(train=(True, False))
def inject_fake_data(self, tmpdir, config):
num_images = 2 if config["train"] else 1
......@@ -1128,7 +1221,7 @@ class SBDatasetTestCase(datasets_utils.ImageDatasetTestCase):
REQUIRED_PACKAGES = ("scipy.io", "scipy.sparse")
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(
ADDITIONAL_CONFIGS = combinations_grid(
image_set=("train", "val", "train_noval"), mode=("boundaries", "segmentation")
)
......@@ -1154,7 +1247,7 @@ class SBDatasetTestCase(datasets_utils.ImageDatasetTestCase):
self._create_split_file(root, split, idcs)
num_images = max(itertools.chain(*splits.values())) + 1
num_images_per_split = dict([(split, len(idcs)) for split, idcs in splits.items()])
num_images_per_split = {split: len(idcs) for split, idcs in splits.items()}
return num_images, num_images_per_split
def _create_split_file(self, root, name, idcs):
......@@ -1189,6 +1282,11 @@ class SBDatasetTestCase(datasets_utils.ImageDatasetTestCase):
def _file_stem(self, idx):
return f"2008_{idx:06d}"
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(mode="segmentation", transforms=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class FakeDataTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.FakeData
......@@ -1214,7 +1312,7 @@ class PhotoTourTestCase(datasets_utils.ImageDatasetTestCase):
_TRAIN_FEATURE_TYPES = (torch.Tensor,)
_TEST_FEATURE_TYPES = (torch.Tensor, torch.Tensor, torch.Tensor)
datasets_utils.combinations_grid(train=(True, False))
combinations_grid(train=(True, False))
_NAME = "liberty"
......@@ -1348,7 +1446,8 @@ class Flickr8kTestCase(datasets_utils.ImageDatasetTestCase):
def test_captions(self):
with self.create_dataset() as (dataset, info):
_, captions = dataset[0]
self.assertSequenceEqual(captions, info["captions"])
assert len(captions) == len(info["captions"])
assert all([a == b for a, b in zip(captions, info["captions"])])
class Flickr30kTestCase(Flickr8kTestCase):
......@@ -1372,7 +1471,7 @@ class Flickr30kTestCase(Flickr8kTestCase):
class MNISTTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.MNIST
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(train=(True, False))
ADDITIONAL_CONFIGS = combinations_grid(train=(True, False))
_MAGIC_DTYPES = {
torch.uint8: 8,
......@@ -1442,7 +1541,7 @@ class EMNISTTestCase(MNISTTestCase):
DATASET_CLASS = datasets.EMNIST
DEFAULT_CONFIG = dict(split="byclass")
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(
ADDITIONAL_CONFIGS = combinations_grid(
split=("byclass", "bymerge", "balanced", "letters", "digits", "mnist"), train=(True, False)
)
......@@ -1453,7 +1552,7 @@ class EMNISTTestCase(MNISTTestCase):
class QMNISTTestCase(MNISTTestCase):
DATASET_CLASS = datasets.QMNIST
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(what=("train", "test", "test10k", "nist"))
ADDITIONAL_CONFIGS = combinations_grid(what=("train", "test", "test10k", "nist"))
_LABELS_SIZE = (8,)
_LABELS_DTYPE = torch.int32
......@@ -1492,33 +1591,54 @@ class QMNISTTestCase(MNISTTestCase):
with self.create_dataset(what="test50k") as (dataset, info):
# Since the split 'test50k' selects all images beginning from the index 10000, we subtract the number of
# created examples by this.
self.assertEqual(len(dataset), info["num_examples"] - 10000)
assert len(dataset) == info["num_examples"] - 10000
class MovingMNISTTestCase(datasets_utils.DatasetTestCase):
DATASET_CLASS = datasets.MovingMNIST
FEATURE_TYPES = (torch.Tensor,)
ADDITIONAL_CONFIGS = combinations_grid(split=(None, "train", "test"), split_ratio=(10, 1, 19))
_NUM_FRAMES = 20
def inject_fake_data(self, tmpdir, config):
base_folder = os.path.join(tmpdir, self.DATASET_CLASS.__name__)
os.makedirs(base_folder, exist_ok=True)
num_samples = 5
data = np.concatenate(
[
np.zeros((config["split_ratio"], num_samples, 64, 64)),
np.ones((self._NUM_FRAMES - config["split_ratio"], num_samples, 64, 64)),
]
)
np.save(os.path.join(base_folder, "mnist_test_seq.npy"), data)
return num_samples
@datasets_utils.test_all_configs
def test_split(self, config):
with self.create_dataset(config) as (dataset, _):
if config["split"] == "train":
assert (dataset.data == 0).all()
elif config["split"] == "test":
assert (dataset.data == 1).all()
else:
assert dataset.data.size()[1] == self._NUM_FRAMES
class DatasetFolderTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.DatasetFolder
# The dataset has no fixed return type since it is defined by the loader parameter. For testing, we use a loader
# that simply returns the path as type 'str' instead of loading anything. See the 'dataset_args()' method.
FEATURE_TYPES = (str, int)
_IMAGE_EXTENSIONS = ("jpg", "png")
_VIDEO_EXTENSIONS = ("avi", "mp4")
_EXTENSIONS = (*_IMAGE_EXTENSIONS, *_VIDEO_EXTENSIONS)
_EXTENSIONS = ("jpg", "png")
# DatasetFolder has two mutually exclusive parameters: 'extensions' and 'is_valid_file'. One of both is required.
# We only iterate over different 'extensions' here and handle the tests for 'is_valid_file' in the
# 'test_is_valid_file()' method.
DEFAULT_CONFIG = dict(extensions=_EXTENSIONS)
ADDITIONAL_CONFIGS = (
*datasets_utils.combinations_grid(extensions=[(ext,) for ext in _IMAGE_EXTENSIONS]),
dict(extensions=_IMAGE_EXTENSIONS),
*datasets_utils.combinations_grid(extensions=[(ext,) for ext in _VIDEO_EXTENSIONS]),
dict(extensions=_VIDEO_EXTENSIONS),
)
ADDITIONAL_CONFIGS = combinations_grid(extensions=[(ext,) for ext in _EXTENSIONS])
def dataset_args(self, tmpdir, config):
return tmpdir, lambda x: x
return tmpdir, datasets.folder.pil_loader
def inject_fake_data(self, tmpdir, config):
extensions = config["extensions"] or self._is_valid_file_to_extensions(config["is_valid_file"])
......@@ -1529,18 +1649,16 @@ class DatasetFolderTestCase(datasets_utils.ImageDatasetTestCase):
if ext not in extensions:
continue
create_example_folder = (
datasets_utils.create_image_folder
if ext in self._IMAGE_EXTENSIONS
else datasets_utils.create_video_folder
)
num_examples = torch.randint(1, 3, size=()).item()
create_example_folder(tmpdir, cls, lambda idx: self._file_name_fn(cls, ext, idx), num_examples)
datasets_utils.create_image_folder(tmpdir, cls, lambda idx: self._file_name_fn(cls, ext, idx), num_examples)
num_examples_total += num_examples
classes.append(cls)
if config.pop("make_empty_class", False):
os.makedirs(pathlib.Path(tmpdir) / "empty_class")
classes.append("empty_class")
return dict(num_examples=num_examples_total, classes=classes)
def _file_name_fn(self, cls, ext, idx):
......@@ -1557,12 +1675,30 @@ class DatasetFolderTestCase(datasets_utils.ImageDatasetTestCase):
with self.create_dataset(
config, extensions=None, is_valid_file=lambda file: pathlib.Path(file).suffix[1:] in extensions
) as (dataset, info):
self.assertEqual(len(dataset), info["num_examples"])
assert len(dataset) == info["num_examples"]
@datasets_utils.test_all_configs
def test_classes(self, config):
with self.create_dataset(config) as (dataset, info):
self.assertSequenceEqual(dataset.classes, info["classes"])
assert len(dataset.classes) == len(info["classes"])
assert all([a == b for a, b in zip(dataset.classes, info["classes"])])
def test_allow_empty(self):
config = {
"extensions": self._EXTENSIONS,
"make_empty_class": True,
}
config["allow_empty"] = True
with self.create_dataset(config) as (dataset, info):
assert "empty_class" in dataset.classes
assert len(dataset.classes) == len(info["classes"])
assert all([a == b for a, b in zip(dataset.classes, info["classes"])])
config["allow_empty"] = False
with pytest.raises(FileNotFoundError, match="Found no valid file"):
with self.create_dataset(config) as (dataset, info):
pass
class ImageFolderTestCase(datasets_utils.ImageDatasetTestCase):
......@@ -1582,13 +1718,14 @@ class ImageFolderTestCase(datasets_utils.ImageDatasetTestCase):
@datasets_utils.test_all_configs
def test_classes(self, config):
with self.create_dataset(config) as (dataset, info):
self.assertSequenceEqual(dataset.classes, info["classes"])
assert len(dataset.classes) == len(info["classes"])
assert all([a == b for a, b in zip(dataset.classes, info["classes"])])
class KittiTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Kitti
FEATURE_TYPES = (PIL.Image.Image, (list, type(None))) # test split returns None as target
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(train=(True, False))
ADDITIONAL_CONFIGS = combinations_grid(train=(True, False))
def inject_fake_data(self, tmpdir, config):
kitti_dir = os.path.join(tmpdir, "Kitti", "raw")
......@@ -1620,11 +1757,16 @@ class KittiTestCase(datasets_utils.ImageDatasetTestCase):
return split_to_num_examples[config["train"]]
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class SvhnTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.SVHN
REQUIRED_PACKAGES = ("scipy",)
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(split=("train", "test", "extra"))
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test", "extra"))
def inject_fake_data(self, tmpdir, config):
import scipy.io as sio
......@@ -1639,13 +1781,13 @@ class SvhnTestCase(datasets_utils.ImageDatasetTestCase):
file = f"{split}_32x32.mat"
images = np.zeros((32, 32, 3, num_examples), dtype=np.uint8)
targets = np.zeros((num_examples,), dtype=np.uint8)
sio.savemat(os.path.join(tmpdir, file), {'X': images, 'y': targets})
sio.savemat(os.path.join(tmpdir, file), {"X": images, "y": targets})
return num_examples
class Places365TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Places365
ADDITIONAL_CONFIGS = datasets_utils.combinations_grid(
ADDITIONAL_CONFIGS = combinations_grid(
split=("train-standard", "train-challenge", "val"),
small=(False, True),
)
......@@ -1674,8 +1816,7 @@ class Places365TestCase(datasets_utils.ImageDatasetTestCase):
# (file, idx)
_FILE_LIST_CONTENT = (
("Places365_val_00000001.png", 0),
*((f"{category}/Places365_train_00000001.png", idx)
for category, idx in _CATEGORIES_CONTENT),
*((f"{category}/Places365_train_00000001.png", idx) for category, idx in _CATEGORIES_CONTENT),
)
@staticmethod
......@@ -1715,24 +1856,1699 @@ class Places365TestCase(datasets_utils.ImageDatasetTestCase):
return [(os.path.join(root, folder_name, image), idx) for image, idx in zip(images, idcs)]
def inject_fake_data(self, tmpdir, config):
self._make_devkit_archive(tmpdir, config['split'])
return len(self._make_images_archive(tmpdir, config['split'], config['small']))
self._make_devkit_archive(tmpdir, config["split"])
return len(self._make_images_archive(tmpdir, config["split"], config["small"]))
def test_classes(self):
classes = list(map(lambda x: x[0], self._CATEGORIES_CONTENT))
with self.create_dataset() as (dataset, _):
self.assertEqual(dataset.classes, classes)
assert dataset.classes == classes
def test_class_to_idx(self):
class_to_idx = dict(self._CATEGORIES_CONTENT)
with self.create_dataset() as (dataset, _):
self.assertEqual(dataset.class_to_idx, class_to_idx)
assert dataset.class_to_idx == class_to_idx
def test_images_download_preexisting(self):
with self.assertRaises(RuntimeError):
with self.create_dataset({'download': True}):
with pytest.raises(RuntimeError):
with self.create_dataset({"download": True}):
pass
class INaturalistTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.INaturalist
FEATURE_TYPES = (PIL.Image.Image, (int, tuple))
ADDITIONAL_CONFIGS = combinations_grid(
target_type=("kingdom", "full", "genus", ["kingdom", "phylum", "class", "order", "family", "genus", "full"]),
version=("2021_train",),
)
def inject_fake_data(self, tmpdir, config):
categories = [
"00000_Akingdom_0phylum_Aclass_Aorder_Afamily_Agenus_Aspecies",
"00001_Akingdom_1phylum_Aclass_Border_Afamily_Bgenus_Aspecies",
"00002_Akingdom_2phylum_Cclass_Corder_Cfamily_Cgenus_Cspecies",
]
num_images_per_category = 3
for category in categories:
datasets_utils.create_image_folder(
root=os.path.join(tmpdir, config["version"]),
name=category,
file_name_fn=lambda idx: f"image_{idx + 1:04d}.jpg",
num_examples=num_images_per_category,
)
return num_images_per_category * len(categories)
def test_targets(self):
target_types = ["kingdom", "phylum", "class", "order", "family", "genus", "full"]
with self.create_dataset(target_type=target_types, version="2021_valid") as (dataset, _):
items = [d[1] for d in dataset]
for i, item in enumerate(items):
assert dataset.category_name("kingdom", item[0]) == "Akingdom"
assert dataset.category_name("phylum", item[1]) == f"{i // 3}phylum"
assert item[6] == i // 3
class LFWPeopleTestCase(datasets_utils.DatasetTestCase):
DATASET_CLASS = datasets.LFWPeople
FEATURE_TYPES = (PIL.Image.Image, int)
ADDITIONAL_CONFIGS = combinations_grid(
split=("10fold", "train", "test"), image_set=("original", "funneled", "deepfunneled")
)
_IMAGES_DIR = {"original": "lfw", "funneled": "lfw_funneled", "deepfunneled": "lfw-deepfunneled"}
_file_id = {"10fold": "", "train": "DevTrain", "test": "DevTest"}
def inject_fake_data(self, tmpdir, config):
tmpdir = pathlib.Path(tmpdir) / "lfw-py"
os.makedirs(tmpdir, exist_ok=True)
return dict(
num_examples=self._create_images_dir(tmpdir, self._IMAGES_DIR[config["image_set"]], config["split"]),
split=config["split"],
)
def _create_images_dir(self, root, idir, split):
idir = os.path.join(root, idir)
os.makedirs(idir, exist_ok=True)
n, flines = (10, ["10\n"]) if split == "10fold" else (1, [])
num_examples = 0
names = []
for _ in range(n):
num_people = random.randint(2, 5)
flines.append(f"{num_people}\n")
for i in range(num_people):
name = self._create_random_id()
no = random.randint(1, 10)
flines.append(f"{name}\t{no}\n")
names.append(f"{name}\t{no}\n")
datasets_utils.create_image_folder(idir, name, lambda n: f"{name}_{n+1:04d}.jpg", no, 250)
num_examples += no
with open(pathlib.Path(root) / f"people{self._file_id[split]}.txt", "w") as f:
f.writelines(flines)
with open(pathlib.Path(root) / "lfw-names.txt", "w") as f:
f.writelines(sorted(names))
return num_examples
def _create_random_id(self):
part1 = datasets_utils.create_random_string(random.randint(5, 7))
part2 = datasets_utils.create_random_string(random.randint(4, 7))
return f"{part1}_{part2}"
class LFWPairsTestCase(LFWPeopleTestCase):
DATASET_CLASS = datasets.LFWPairs
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, int)
def _create_images_dir(self, root, idir, split):
idir = os.path.join(root, idir)
os.makedirs(idir, exist_ok=True)
num_pairs = 7 # effectively 7*2*n = 14*n
n, self.flines = (10, [f"10\t{num_pairs}"]) if split == "10fold" else (1, [str(num_pairs)])
for _ in range(n):
self._inject_pairs(idir, num_pairs, True)
self._inject_pairs(idir, num_pairs, False)
with open(pathlib.Path(root) / f"pairs{self._file_id[split]}.txt", "w") as f:
f.writelines(self.flines)
return num_pairs * 2 * n
def _inject_pairs(self, root, num_pairs, same):
for i in range(num_pairs):
name1 = self._create_random_id()
name2 = name1 if same else self._create_random_id()
no1, no2 = random.randint(1, 100), random.randint(1, 100)
if same:
self.flines.append(f"\n{name1}\t{no1}\t{no2}")
else:
self.flines.append(f"\n{name1}\t{no1}\t{name2}\t{no2}")
datasets_utils.create_image_folder(root, name1, lambda _: f"{name1}_{no1:04d}.jpg", 1, 250)
datasets_utils.create_image_folder(root, name2, lambda _: f"{name2}_{no2:04d}.jpg", 1, 250)
class SintelTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Sintel
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"), pass_name=("clean", "final", "both"))
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)))
FLOW_H, FLOW_W = 3, 4
def inject_fake_data(self, tmpdir, config):
root = pathlib.Path(tmpdir) / "Sintel"
num_images_per_scene = 3 if config["split"] == "train" else 4
num_scenes = 2
for split_dir in ("training", "test"):
for pass_name in ("clean", "final"):
image_root = root / split_dir / pass_name
for scene_id in range(num_scenes):
scene_dir = image_root / f"scene_{scene_id}"
datasets_utils.create_image_folder(
image_root,
name=str(scene_dir),
file_name_fn=lambda image_idx: f"frame_000{image_idx}.png",
num_examples=num_images_per_scene,
)
flow_root = root / "training" / "flow"
for scene_id in range(num_scenes):
scene_dir = flow_root / f"scene_{scene_id}"
os.makedirs(scene_dir)
for i in range(num_images_per_scene - 1):
file_name = str(scene_dir / f"frame_000{i}.flo")
datasets_utils.make_fake_flo_file(h=self.FLOW_H, w=self.FLOW_W, file_name=file_name)
# with e.g. num_images_per_scene = 3, for a single scene with have 3 images
# which are frame_0000, frame_0001 and frame_0002
# They will be consecutively paired as (frame_0000, frame_0001), (frame_0001, frame_0002),
# that is 3 - 1 = 2 examples. Hence the formula below
num_passes = 2 if config["pass_name"] == "both" else 1
num_examples = (num_images_per_scene - 1) * num_scenes * num_passes
return num_examples
def test_flow(self):
# Make sure flow exists for train split, and make sure there are as many flow values as (pairs of) images
h, w = self.FLOW_H, self.FLOW_W
expected_flow = np.arange(2 * h * w).reshape(h, w, 2).transpose(2, 0, 1)
with self.create_dataset(split="train") as (dataset, _):
assert dataset._flow_list and len(dataset._flow_list) == len(dataset._image_list)
for _, _, flow in dataset:
assert flow.shape == (2, h, w)
np.testing.assert_allclose(flow, expected_flow)
# Make sure flow is always None for test split
with self.create_dataset(split="test") as (dataset, _):
assert dataset._image_list and not dataset._flow_list
for _, _, flow in dataset:
assert flow is None
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument split"):
with self.create_dataset(split="bad"):
pass
with pytest.raises(ValueError, match="Unknown value 'bad' for argument pass_name"):
with self.create_dataset(pass_name="bad"):
pass
class KittiFlowTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.KittiFlow
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)), (np.ndarray, type(None)))
def inject_fake_data(self, tmpdir, config):
root = pathlib.Path(tmpdir) / "KittiFlow"
num_examples = 2 if config["split"] == "train" else 3
for split_dir in ("training", "testing"):
datasets_utils.create_image_folder(
root / split_dir,
name="image_2",
file_name_fn=lambda image_idx: f"{image_idx}_10.png",
num_examples=num_examples,
)
datasets_utils.create_image_folder(
root / split_dir,
name="image_2",
file_name_fn=lambda image_idx: f"{image_idx}_11.png",
num_examples=num_examples,
)
# For kitti the ground truth flows are encoded as 16-bits pngs.
# create_image_folder() will actually create 8-bits pngs, but it doesn't
# matter much: the flow reader will still be able to read the files, it
# will just be garbage flow value - but we don't care about that here.
datasets_utils.create_image_folder(
root / "training",
name="flow_occ",
file_name_fn=lambda image_idx: f"{image_idx}_10.png",
num_examples=num_examples,
)
return num_examples
def test_flow_and_valid(self):
# Make sure flow exists for train split, and make sure there are as many flow values as (pairs of) images
# Also assert flow and valid are of the expected shape
with self.create_dataset(split="train") as (dataset, _):
assert dataset._flow_list and len(dataset._flow_list) == len(dataset._image_list)
for _, _, flow, valid in dataset:
two, h, w = flow.shape
assert two == 2
assert valid.shape == (h, w)
# Make sure flow and valid are always None for test split
with self.create_dataset(split="test") as (dataset, _):
assert dataset._image_list and not dataset._flow_list
for _, _, flow, valid in dataset:
assert flow is None
assert valid is None
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument split"):
with self.create_dataset(split="bad"):
pass
class FlyingChairsTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.FlyingChairs
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "val"))
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)))
FLOW_H, FLOW_W = 3, 4
def _make_split_file(self, root, num_examples):
# We create a fake split file here, but users are asked to download the real one from the authors website
split_ids = [1] * num_examples["train"] + [2] * num_examples["val"]
random.shuffle(split_ids)
with open(str(root / "FlyingChairs_train_val.txt"), "w+") as split_file:
for split_id in split_ids:
split_file.write(f"{split_id}\n")
def inject_fake_data(self, tmpdir, config):
root = pathlib.Path(tmpdir) / "FlyingChairs"
num_examples = {"train": 5, "val": 3}
num_examples_total = sum(num_examples.values())
datasets_utils.create_image_folder( # img1
root,
name="data",
file_name_fn=lambda image_idx: f"00{image_idx}_img1.ppm",
num_examples=num_examples_total,
)
datasets_utils.create_image_folder( # img2
root,
name="data",
file_name_fn=lambda image_idx: f"00{image_idx}_img2.ppm",
num_examples=num_examples_total,
)
for i in range(num_examples_total):
file_name = str(root / "data" / f"00{i}_flow.flo")
datasets_utils.make_fake_flo_file(h=self.FLOW_H, w=self.FLOW_W, file_name=file_name)
self._make_split_file(root, num_examples)
return num_examples[config["split"]]
@datasets_utils.test_all_configs
def test_flow(self, config):
# Make sure flow always exists, and make sure there are as many flow values as (pairs of) images
# Also make sure the flow is properly decoded
h, w = self.FLOW_H, self.FLOW_W
expected_flow = np.arange(2 * h * w).reshape(h, w, 2).transpose(2, 0, 1)
with self.create_dataset(config=config) as (dataset, _):
assert dataset._flow_list and len(dataset._flow_list) == len(dataset._image_list)
for _, _, flow in dataset:
assert flow.shape == (2, h, w)
np.testing.assert_allclose(flow, expected_flow)
class FlyingThings3DTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.FlyingThings3D
ADDITIONAL_CONFIGS = combinations_grid(
split=("train", "test"), pass_name=("clean", "final", "both"), camera=("left", "right", "both")
)
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)))
FLOW_H, FLOW_W = 3, 4
def inject_fake_data(self, tmpdir, config):
root = pathlib.Path(tmpdir) / "FlyingThings3D"
num_images_per_camera = 3 if config["split"] == "train" else 4
passes = ("frames_cleanpass", "frames_finalpass")
splits = ("TRAIN", "TEST")
letters = ("A", "B", "C")
subfolders = ("0000", "0001")
cameras = ("left", "right")
for pass_name, split, letter, subfolder, camera in itertools.product(
passes, splits, letters, subfolders, cameras
):
current_folder = root / pass_name / split / letter / subfolder
datasets_utils.create_image_folder(
current_folder,
name=camera,
file_name_fn=lambda image_idx: f"00{image_idx}.png",
num_examples=num_images_per_camera,
)
directions = ("into_future", "into_past")
for split, letter, subfolder, direction, camera in itertools.product(
splits, letters, subfolders, directions, cameras
):
current_folder = root / "optical_flow" / split / letter / subfolder / direction / camera
os.makedirs(str(current_folder), exist_ok=True)
for i in range(num_images_per_camera):
datasets_utils.make_fake_pfm_file(self.FLOW_H, self.FLOW_W, file_name=str(current_folder / f"{i}.pfm"))
num_cameras = 2 if config["camera"] == "both" else 1
num_passes = 2 if config["pass_name"] == "both" else 1
num_examples = (
(num_images_per_camera - 1) * num_cameras * len(subfolders) * len(letters) * len(splits) * num_passes
)
return num_examples
@datasets_utils.test_all_configs
def test_flow(self, config):
h, w = self.FLOW_H, self.FLOW_W
expected_flow = np.arange(3 * h * w).reshape(h, w, 3).transpose(2, 0, 1)
expected_flow = np.flip(expected_flow, axis=1)
expected_flow = expected_flow[:2, :, :]
with self.create_dataset(config=config) as (dataset, _):
assert dataset._flow_list and len(dataset._flow_list) == len(dataset._image_list)
for _, _, flow in dataset:
assert flow.shape == (2, self.FLOW_H, self.FLOW_W)
np.testing.assert_allclose(flow, expected_flow)
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument split"):
with self.create_dataset(split="bad"):
pass
with pytest.raises(ValueError, match="Unknown value 'bad' for argument pass_name"):
with self.create_dataset(pass_name="bad"):
pass
with pytest.raises(ValueError, match="Unknown value 'bad' for argument camera"):
with self.create_dataset(camera="bad"):
pass
class HD1KTestCase(KittiFlowTestCase):
DATASET_CLASS = datasets.HD1K
def inject_fake_data(self, tmpdir, config):
root = pathlib.Path(tmpdir) / "hd1k"
num_sequences = 4 if config["split"] == "train" else 3
num_examples_per_train_sequence = 3
for seq_idx in range(num_sequences):
# Training data
datasets_utils.create_image_folder(
root / "hd1k_input",
name="image_2",
file_name_fn=lambda image_idx: f"{seq_idx:06d}_{image_idx}.png",
num_examples=num_examples_per_train_sequence,
)
datasets_utils.create_image_folder(
root / "hd1k_flow_gt",
name="flow_occ",
file_name_fn=lambda image_idx: f"{seq_idx:06d}_{image_idx}.png",
num_examples=num_examples_per_train_sequence,
)
# Test data
datasets_utils.create_image_folder(
root / "hd1k_challenge",
name="image_2",
file_name_fn=lambda _: f"{seq_idx:06d}_10.png",
num_examples=1,
)
datasets_utils.create_image_folder(
root / "hd1k_challenge",
name="image_2",
file_name_fn=lambda _: f"{seq_idx:06d}_11.png",
num_examples=1,
)
num_examples_per_sequence = num_examples_per_train_sequence if config["split"] == "train" else 2
return num_sequences * (num_examples_per_sequence - 1)
class EuroSATTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.EuroSAT
FEATURE_TYPES = (PIL.Image.Image, int)
def inject_fake_data(self, tmpdir, config):
data_folder = os.path.join(tmpdir, "eurosat", "2750")
os.makedirs(data_folder)
num_examples_per_class = 3
classes = ("AnnualCrop", "Forest")
for cls in classes:
datasets_utils.create_image_folder(
root=data_folder,
name=cls,
file_name_fn=lambda idx: f"{cls}_{idx}.jpg",
num_examples=num_examples_per_class,
)
return len(classes) * num_examples_per_class
class Food101TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Food101
FEATURE_TYPES = (PIL.Image.Image, int)
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
def inject_fake_data(self, tmpdir: str, config):
root_folder = pathlib.Path(tmpdir) / "food-101"
image_folder = root_folder / "images"
meta_folder = root_folder / "meta"
image_folder.mkdir(parents=True)
meta_folder.mkdir()
num_images_per_class = 5
metadata = {}
n_samples_per_class = 3 if config["split"] == "train" else 2
sampled_classes = ("apple_pie", "crab_cakes", "gyoza")
for cls in sampled_classes:
im_fnames = datasets_utils.create_image_folder(
image_folder,
cls,
file_name_fn=lambda idx: f"{idx}.jpg",
num_examples=num_images_per_class,
)
metadata[cls] = [
"/".join(fname.relative_to(image_folder).with_suffix("").parts)
for fname in random.choices(im_fnames, k=n_samples_per_class)
]
with open(meta_folder / f"{config['split']}.json", "w") as file:
file.write(json.dumps(metadata))
return len(sampled_classes * n_samples_per_class)
class FGVCAircraftTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.FGVCAircraft
ADDITIONAL_CONFIGS = combinations_grid(
split=("train", "val", "trainval", "test"), annotation_level=("variant", "family", "manufacturer")
)
def inject_fake_data(self, tmpdir: str, config):
split = config["split"]
annotation_level = config["annotation_level"]
annotation_level_to_file = {
"variant": "variants.txt",
"family": "families.txt",
"manufacturer": "manufacturers.txt",
}
root_folder = pathlib.Path(tmpdir) / "fgvc-aircraft-2013b"
data_folder = root_folder / "data"
classes = ["707-320", "Hawk T1", "Tornado"]
num_images_per_class = 5
datasets_utils.create_image_folder(
data_folder,
"images",
file_name_fn=lambda idx: f"{idx}.jpg",
num_examples=num_images_per_class * len(classes),
)
annotation_file = data_folder / annotation_level_to_file[annotation_level]
with open(annotation_file, "w") as file:
file.write("\n".join(classes))
num_samples_per_class = 4 if split == "trainval" else 2
images_classes = []
for i in range(len(classes)):
images_classes.extend(
[
f"{idx} {classes[i]}"
for idx in random.sample(
range(i * num_images_per_class, (i + 1) * num_images_per_class), num_samples_per_class
)
]
)
images_annotation_file = data_folder / f"images_{annotation_level}_{split}.txt"
with open(images_annotation_file, "w") as file:
file.write("\n".join(images_classes))
return len(classes * num_samples_per_class)
class SUN397TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.SUN397
def inject_fake_data(self, tmpdir: str, config):
data_dir = pathlib.Path(tmpdir) / "SUN397"
data_dir.mkdir()
num_images_per_class = 5
sampled_classes = ("abbey", "airplane_cabin", "airport_terminal")
im_paths = []
for cls in sampled_classes:
image_folder = data_dir / cls[0]
im_paths.extend(
datasets_utils.create_image_folder(
image_folder,
image_folder / cls,
file_name_fn=lambda idx: f"sun_{idx}.jpg",
num_examples=num_images_per_class,
)
)
with open(data_dir / "ClassName.txt", "w") as file:
file.writelines("\n".join(f"/{cls[0]}/{cls}" for cls in sampled_classes))
num_samples = len(im_paths)
return num_samples
class DTDTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.DTD
FEATURE_TYPES = (PIL.Image.Image, int)
ADDITIONAL_CONFIGS = combinations_grid(
split=("train", "test", "val"),
# There is no need to test the whole matrix here, since each fold is treated exactly the same
partition=(1, 5, 10),
)
def inject_fake_data(self, tmpdir: str, config):
data_folder = pathlib.Path(tmpdir) / "dtd" / "dtd"
num_images_per_class = 3
image_folder = data_folder / "images"
image_files = []
for cls in ("banded", "marbled", "zigzagged"):
image_files.extend(
datasets_utils.create_image_folder(
image_folder,
cls,
file_name_fn=lambda idx: f"{cls}_{idx:04d}.jpg",
num_examples=num_images_per_class,
)
)
meta_folder = data_folder / "labels"
meta_folder.mkdir()
image_ids = [str(path.relative_to(path.parents[1])).replace(os.sep, "/") for path in image_files]
image_ids_in_config = random.choices(image_ids, k=len(image_files) // 2)
with open(meta_folder / f"{config['split']}{config['partition']}.txt", "w") as file:
file.write("\n".join(image_ids_in_config) + "\n")
return len(image_ids_in_config)
class FER2013TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.FER2013
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
FEATURE_TYPES = (PIL.Image.Image, (int, type(None)))
def inject_fake_data(self, tmpdir, config):
base_folder = os.path.join(tmpdir, "fer2013")
os.makedirs(base_folder)
use_icml = config.pop("use_icml", False)
use_fer = config.pop("use_fer", False)
num_samples = 5
if use_icml or use_fer:
pixels_key, usage_key = (" pixels", " Usage") if use_icml else ("pixels", "Usage")
fieldnames = ("emotion", usage_key, pixels_key) if use_icml else ("emotion", pixels_key, usage_key)
filename = "icml_face_data.csv" if use_icml else "fer2013.csv"
with open(os.path.join(base_folder, filename), "w", newline="") as file:
writer = csv.DictWriter(
file,
fieldnames=fieldnames,
quoting=csv.QUOTE_NONNUMERIC,
quotechar='"',
)
writer.writeheader()
for i in range(num_samples):
row = {
"emotion": str(int(torch.randint(0, 7, ()))),
usage_key: "Training" if i % 2 else "PublicTest",
pixels_key: " ".join(
str(pixel)
for pixel in datasets_utils.create_image_or_video_tensor((48, 48)).view(-1).tolist()
),
}
writer.writerow(row)
else:
with open(os.path.join(base_folder, f"{config['split']}.csv"), "w", newline="") as file:
writer = csv.DictWriter(
file,
fieldnames=("emotion", "pixels") if config["split"] == "train" else ("pixels",),
quoting=csv.QUOTE_NONNUMERIC,
quotechar='"',
)
writer.writeheader()
for _ in range(num_samples):
row = dict(
pixels=" ".join(
str(pixel)
for pixel in datasets_utils.create_image_or_video_tensor((48, 48)).view(-1).tolist()
)
)
if config["split"] == "train":
row["emotion"] = str(int(torch.randint(0, 7, ())))
writer.writerow(row)
return num_samples
def test_icml_file(self):
config = {"split": "test"}
with self.create_dataset(config=config) as (dataset, _):
assert all(s[1] is None for s in dataset)
for split in ("train", "test"):
for d in ({"use_icml": True}, {"use_fer": True}):
config = {"split": split, **d}
with self.create_dataset(config=config) as (dataset, _):
assert all(s[1] is not None for s in dataset)
class GTSRBTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.GTSRB
FEATURE_TYPES = (PIL.Image.Image, int)
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
def inject_fake_data(self, tmpdir: str, config):
root_folder = os.path.join(tmpdir, "gtsrb")
os.makedirs(root_folder, exist_ok=True)
# Train data
train_folder = os.path.join(root_folder, "GTSRB", "Training")
os.makedirs(train_folder, exist_ok=True)
num_examples = 3 if config["split"] == "train" else 4
classes = ("00000", "00042", "00012")
for class_idx in classes:
datasets_utils.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,
)
total_number_of_examples = num_examples * len(classes)
# Test data
test_folder = os.path.join(root_folder, "GTSRB", "Final_Test", "Images")
os.makedirs(test_folder, exist_ok=True)
with open(os.path.join(root_folder, "GT-final_test.csv"), "w") as csv_file:
csv_file.write("Filename;Width;Height;Roi.X1;Roi.Y1;Roi.X2;Roi.Y2;ClassId\n")
for _ in range(total_number_of_examples):
image_file = datasets_utils.create_random_string(5, string.digits) + ".ppm"
datasets_utils.create_image_file(test_folder, image_file)
row = [
image_file,
torch.randint(1, 100, size=()).item(),
torch.randint(1, 100, size=()).item(),
torch.randint(1, 100, size=()).item(),
torch.randint(1, 100, size=()).item(),
torch.randint(1, 100, size=()).item(),
torch.randint(1, 100, size=()).item(),
torch.randint(0, 43, size=()).item(),
]
csv_file.write(";".join(map(str, row)) + "\n")
return total_number_of_examples
class CLEVRClassificationTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.CLEVRClassification
FEATURE_TYPES = (PIL.Image.Image, (int, type(None)))
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "val", "test"))
def inject_fake_data(self, tmpdir, config):
data_folder = pathlib.Path(tmpdir) / "clevr" / "CLEVR_v1.0"
images_folder = data_folder / "images"
image_files = datasets_utils.create_image_folder(
images_folder, config["split"], lambda idx: f"CLEVR_{config['split']}_{idx:06d}.png", num_examples=5
)
scenes_folder = data_folder / "scenes"
scenes_folder.mkdir()
if config["split"] != "test":
with open(scenes_folder / f"CLEVR_{config['split']}_scenes.json", "w") as file:
json.dump(
dict(
info=dict(),
scenes=[
dict(image_filename=image_file.name, objects=[dict()] * int(torch.randint(10, ())))
for image_file in image_files
],
),
file,
)
return len(image_files)
class OxfordIIITPetTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.OxfordIIITPet
FEATURE_TYPES = (PIL.Image.Image, (int, PIL.Image.Image, tuple, type(None)))
ADDITIONAL_CONFIGS = combinations_grid(
split=("trainval", "test"),
target_types=("category", "binary-category", "segmentation", ["category", "segmentation"], []),
)
def inject_fake_data(self, tmpdir, config):
base_folder = os.path.join(tmpdir, "oxford-iiit-pet")
classification_anns_meta = (
dict(cls="Abyssinian", label=0, species="cat"),
dict(cls="Keeshond", label=18, species="dog"),
dict(cls="Yorkshire Terrier", label=37, 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 = datasets_utils.create_image_folder(
base_folder, "images", file_name_fn=lambda idx: f"{image_ids[idx]}.jpg", num_examples=len(image_ids)
)
anns_folder = os.path.join(base_folder, "annotations")
os.makedirs(anns_folder)
split_and_classification_anns_in_split = random.choices(split_and_classification_anns, k=len(image_ids) // 2)
with open(os.path.join(anns_folder, f"{config['split']}.txt"), "w", newline="") 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)
segmentation_files = datasets_utils.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[:2]:
path.with_suffix(".mat").touch()
for path in segmentation_files:
path.with_name(f".{path.name}").touch()
return len(split_and_classification_anns_in_split)
def _meta_to_split_and_classification_ann(self, 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)
def test_transforms_v2_wrapper_spawn(self):
expected_size = (123, 321)
with self.create_dataset(transform=v2.Resize(size=expected_size)) as (dataset, _):
datasets_utils.check_transforms_v2_wrapper_spawn(dataset, expected_size=expected_size)
class StanfordCarsTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.StanfordCars
REQUIRED_PACKAGES = ("scipy",)
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
def inject_fake_data(self, tmpdir, config):
import scipy.io as io
from numpy.core.records import fromarrays
num_examples = {"train": 5, "test": 7}[config["split"]]
num_classes = 3
base_folder = pathlib.Path(tmpdir) / "stanford_cars"
devkit = base_folder / "devkit"
devkit.mkdir(parents=True)
if config["split"] == "train":
images_folder_name = "cars_train"
annotations_mat_path = devkit / "cars_train_annos.mat"
else:
images_folder_name = "cars_test"
annotations_mat_path = base_folder / "cars_test_annos_withlabels.mat"
datasets_utils.create_image_folder(
root=base_folder,
name=images_folder_name,
file_name_fn=lambda image_index: f"{image_index:5d}.jpg",
num_examples=num_examples,
)
classes = np.random.randint(1, num_classes + 1, num_examples, dtype=np.uint8)
fnames = [f"{i:5d}.jpg" for i in range(num_examples)]
rec_array = fromarrays(
[classes, fnames],
names=["class", "fname"],
)
io.savemat(annotations_mat_path, {"annotations": rec_array})
random_class_names = ["random_name"] * num_classes
io.savemat(devkit / "cars_meta.mat", {"class_names": random_class_names})
return num_examples
class Country211TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Country211
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "valid", "test"))
def inject_fake_data(self, tmpdir: str, config):
split_folder = pathlib.Path(tmpdir) / "country211" / config["split"]
split_folder.mkdir(parents=True, exist_ok=True)
num_examples = {
"train": 3,
"valid": 4,
"test": 5,
}[config["split"]]
classes = ("AD", "BS", "GR")
for cls in classes:
datasets_utils.create_image_folder(
split_folder,
name=cls,
file_name_fn=lambda idx: f"{idx}.jpg",
num_examples=num_examples,
)
return num_examples * len(classes)
class Flowers102TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Flowers102
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "val", "test"))
REQUIRED_PACKAGES = ("scipy",)
def inject_fake_data(self, tmpdir: str, config):
base_folder = pathlib.Path(tmpdir) / "flowers-102"
num_classes = 3
num_images_per_split = dict(train=5, val=4, test=3)
num_images_total = sum(num_images_per_split.values())
datasets_utils.create_image_folder(
base_folder,
"jpg",
file_name_fn=lambda idx: f"image_{idx + 1:05d}.jpg",
num_examples=num_images_total,
)
label_dict = dict(
labels=np.random.randint(1, num_classes + 1, size=(1, num_images_total), dtype=np.uint8),
)
datasets_utils.lazy_importer.scipy.io.savemat(str(base_folder / "imagelabels.mat"), label_dict)
setid_mat = np.arange(1, num_images_total + 1, dtype=np.uint16)
np.random.shuffle(setid_mat)
setid_dict = dict(
trnid=setid_mat[: num_images_per_split["train"]].reshape(1, -1),
valid=setid_mat[num_images_per_split["train"] : -num_images_per_split["test"]].reshape(1, -1),
tstid=setid_mat[-num_images_per_split["test"] :].reshape(1, -1),
)
datasets_utils.lazy_importer.scipy.io.savemat(str(base_folder / "setid.mat"), setid_dict)
return num_images_per_split[config["split"]]
class PCAMTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.PCAM
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "val", "test"))
REQUIRED_PACKAGES = ("h5py",)
def inject_fake_data(self, tmpdir: str, config):
base_folder = pathlib.Path(tmpdir) / "pcam"
base_folder.mkdir()
num_images = {"train": 2, "test": 3, "val": 4}[config["split"]]
images_file = datasets.PCAM._FILES[config["split"]]["images"][0]
with datasets_utils.lazy_importer.h5py.File(str(base_folder / images_file), "w") as f:
f["x"] = np.random.randint(0, 256, size=(num_images, 10, 10, 3), dtype=np.uint8)
targets_file = datasets.PCAM._FILES[config["split"]]["targets"][0]
with datasets_utils.lazy_importer.h5py.File(str(base_folder / targets_file), "w") as f:
f["y"] = np.random.randint(0, 2, size=(num_images, 1, 1, 1), dtype=np.uint8)
return num_images
class RenderedSST2TestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.RenderedSST2
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "val", "test"))
SPLIT_TO_FOLDER = {"train": "train", "val": "valid", "test": "test"}
def inject_fake_data(self, tmpdir: str, config):
root_folder = pathlib.Path(tmpdir) / "rendered-sst2"
image_folder = root_folder / self.SPLIT_TO_FOLDER[config["split"]]
num_images_per_class = {"train": 5, "test": 6, "val": 7}
sampled_classes = ["positive", "negative"]
for cls in sampled_classes:
datasets_utils.create_image_folder(
image_folder,
cls,
file_name_fn=lambda idx: f"{idx}.png",
num_examples=num_images_per_class[config["split"]],
)
return len(sampled_classes) * num_images_per_class[config["split"]]
class Kitti2012StereoTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Kitti2012Stereo
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)), (np.ndarray, type(None)))
def inject_fake_data(self, tmpdir, config):
kitti_dir = pathlib.Path(tmpdir) / "Kitti2012"
os.makedirs(kitti_dir, exist_ok=True)
split_dir = kitti_dir / (config["split"] + "ing")
os.makedirs(split_dir, exist_ok=True)
num_examples = {"train": 4, "test": 3}.get(config["split"], 0)
datasets_utils.create_image_folder(
root=split_dir,
name="colored_0",
file_name_fn=lambda i: f"{i:06d}_10.png",
num_examples=num_examples,
size=(3, 100, 200),
)
datasets_utils.create_image_folder(
root=split_dir,
name="colored_1",
file_name_fn=lambda i: f"{i:06d}_10.png",
num_examples=num_examples,
size=(3, 100, 200),
)
if config["split"] == "train":
datasets_utils.create_image_folder(
root=split_dir,
name="disp_noc",
file_name_fn=lambda i: f"{i:06d}.png",
num_examples=num_examples,
# Kitti2012 uses a single channel image for disparities
size=(1, 100, 200),
)
return num_examples
def test_train_splits(self):
for split in ["train"]:
with self.create_dataset(split=split) as (dataset, _):
for left, right, disparity, mask in dataset:
assert mask is None
datasets_utils.shape_test_for_stereo(left, right, disparity)
def test_test_split(self):
for split in ["test"]:
with self.create_dataset(split=split) as (dataset, _):
for left, right, disparity, mask in dataset:
assert mask is None
assert disparity is None
datasets_utils.shape_test_for_stereo(left, right)
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument split"):
with self.create_dataset(split="bad"):
pass
class Kitti2015StereoTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Kitti2015Stereo
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)), (np.ndarray, type(None)))
def inject_fake_data(self, tmpdir, config):
kitti_dir = pathlib.Path(tmpdir) / "Kitti2015"
os.makedirs(kitti_dir, exist_ok=True)
split_dir = kitti_dir / (config["split"] + "ing")
os.makedirs(split_dir, exist_ok=True)
num_examples = {"train": 4, "test": 6}.get(config["split"], 0)
datasets_utils.create_image_folder(
root=split_dir,
name="image_2",
file_name_fn=lambda i: f"{i:06d}_10.png",
num_examples=num_examples,
size=(3, 100, 200),
)
datasets_utils.create_image_folder(
root=split_dir,
name="image_3",
file_name_fn=lambda i: f"{i:06d}_10.png",
num_examples=num_examples,
size=(3, 100, 200),
)
if config["split"] == "train":
datasets_utils.create_image_folder(
root=split_dir,
name="disp_occ_0",
file_name_fn=lambda i: f"{i:06d}.png",
num_examples=num_examples,
# Kitti2015 uses a single channel image for disparities
size=(1, 100, 200),
)
datasets_utils.create_image_folder(
root=split_dir,
name="disp_occ_1",
file_name_fn=lambda i: f"{i:06d}.png",
num_examples=num_examples,
# Kitti2015 uses a single channel image for disparities
size=(1, 100, 200),
)
return num_examples
def test_train_splits(self):
for split in ["train"]:
with self.create_dataset(split=split) as (dataset, _):
for left, right, disparity, mask in dataset:
assert mask is None
datasets_utils.shape_test_for_stereo(left, right, disparity)
def test_test_split(self):
for split in ["test"]:
with self.create_dataset(split=split) as (dataset, _):
for left, right, disparity, mask in dataset:
assert mask is None
assert disparity is None
datasets_utils.shape_test_for_stereo(left, right)
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument split"):
with self.create_dataset(split="bad"):
pass
class CarlaStereoTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.CarlaStereo
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, None))
@staticmethod
def _create_scene_folders(num_examples: int, root_dir: Union[str, pathlib.Path]):
# make the root_dir if it does not exits
os.makedirs(root_dir, exist_ok=True)
for i in range(num_examples):
scene_dir = pathlib.Path(root_dir) / f"scene_{i}"
os.makedirs(scene_dir, exist_ok=True)
# populate with left right images
datasets_utils.create_image_file(root=scene_dir, name="im0.png", size=(100, 100))
datasets_utils.create_image_file(root=scene_dir, name="im1.png", size=(100, 100))
datasets_utils.make_fake_pfm_file(100, 100, file_name=str(scene_dir / "disp0GT.pfm"))
datasets_utils.make_fake_pfm_file(100, 100, file_name=str(scene_dir / "disp1GT.pfm"))
def inject_fake_data(self, tmpdir, config):
carla_dir = pathlib.Path(tmpdir) / "carla-highres"
os.makedirs(carla_dir, exist_ok=True)
split_dir = pathlib.Path(carla_dir) / "trainingF"
os.makedirs(split_dir, exist_ok=True)
num_examples = 6
self._create_scene_folders(num_examples=num_examples, root_dir=split_dir)
return num_examples
def test_train_splits(self):
with self.create_dataset() as (dataset, _):
for left, right, disparity in dataset:
datasets_utils.shape_test_for_stereo(left, right, disparity)
class CREStereoTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.CREStereo
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, np.ndarray, type(None))
def inject_fake_data(self, tmpdir, config):
crestereo_dir = pathlib.Path(tmpdir) / "CREStereo"
os.makedirs(crestereo_dir, exist_ok=True)
examples = {"tree": 2, "shapenet": 3, "reflective": 6, "hole": 5}
for category_name in ["shapenet", "reflective", "tree", "hole"]:
split_dir = crestereo_dir / category_name
os.makedirs(split_dir, exist_ok=True)
num_examples = examples[category_name]
for idx in range(num_examples):
datasets_utils.create_image_file(root=split_dir, name=f"{idx}_left.jpg", size=(100, 100))
datasets_utils.create_image_file(root=split_dir, name=f"{idx}_right.jpg", size=(100, 100))
# these are going to end up being gray scale images
datasets_utils.create_image_file(root=split_dir, name=f"{idx}_left.disp.png", size=(1, 100, 100))
datasets_utils.create_image_file(root=split_dir, name=f"{idx}_right.disp.png", size=(1, 100, 100))
return sum(examples.values())
def test_splits(self):
with self.create_dataset() as (dataset, _):
for left, right, disparity, mask in dataset:
assert mask is None
datasets_utils.shape_test_for_stereo(left, right, disparity)
class FallingThingsStereoTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.FallingThingsStereo
ADDITIONAL_CONFIGS = combinations_grid(variant=("single", "mixed", "both"))
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)))
@staticmethod
def _make_dummy_depth_map(root: str, name: str, size: Tuple[int, int]):
file = pathlib.Path(root) / name
image = np.ones((size[0], size[1]), dtype=np.uint8)
PIL.Image.fromarray(image).save(file)
@staticmethod
def _make_scene_folder(root: str, scene_name: str, size: Tuple[int, int]) -> None:
root = pathlib.Path(root) / scene_name
os.makedirs(root, exist_ok=True)
# jpg images
datasets_utils.create_image_file(root, "image1.left.jpg", size=(3, size[1], size[0]))
datasets_utils.create_image_file(root, "image1.right.jpg", size=(3, size[1], size[0]))
# single channel depth maps
FallingThingsStereoTestCase._make_dummy_depth_map(root, "image1.left.depth.png", size=(size[0], size[1]))
FallingThingsStereoTestCase._make_dummy_depth_map(root, "image1.right.depth.png", size=(size[0], size[1]))
# camera settings json. Minimal example for _read_disparity function testing
settings_json = {"camera_settings": [{"intrinsic_settings": {"fx": 1}}]}
with open(root / "_camera_settings.json", "w") as f:
json.dump(settings_json, f)
def inject_fake_data(self, tmpdir, config):
fallingthings_dir = pathlib.Path(tmpdir) / "FallingThings"
os.makedirs(fallingthings_dir, exist_ok=True)
num_examples = {"single": 2, "mixed": 3, "both": 4}.get(config["variant"], 0)
variants = {
"single": ["single"],
"mixed": ["mixed"],
"both": ["single", "mixed"],
}.get(config["variant"], [])
variant_dir_prefixes = {
"single": 1,
"mixed": 0,
}
for variant_name in variants:
variant_dir = pathlib.Path(fallingthings_dir) / variant_name
os.makedirs(variant_dir, exist_ok=True)
for i in range(variant_dir_prefixes[variant_name]):
variant_dir = variant_dir / f"{i:02d}"
os.makedirs(variant_dir, exist_ok=True)
for i in range(num_examples):
self._make_scene_folder(
root=variant_dir,
scene_name=f"scene_{i:06d}",
size=(100, 200),
)
if config["variant"] == "both":
num_examples *= 2
return num_examples
def test_splits(self):
for variant_name in ["single", "mixed"]:
with self.create_dataset(variant=variant_name) as (dataset, _):
for left, right, disparity in dataset:
datasets_utils.shape_test_for_stereo(left, right, disparity)
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument variant"):
with self.create_dataset(variant="bad"):
pass
class SceneFlowStereoTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.SceneFlowStereo
ADDITIONAL_CONFIGS = combinations_grid(
variant=("FlyingThings3D", "Driving", "Monkaa"), pass_name=("clean", "final", "both")
)
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)))
@staticmethod
def _create_pfm_folder(
root: str, name: str, file_name_fn: Callable[..., str], num_examples: int, size: Tuple[int, int]
) -> None:
root = pathlib.Path(root) / name
os.makedirs(root, exist_ok=True)
for i in range(num_examples):
datasets_utils.make_fake_pfm_file(size[0], size[1], root / file_name_fn(i))
def inject_fake_data(self, tmpdir, config):
scene_flow_dir = pathlib.Path(tmpdir) / "SceneFlow"
os.makedirs(scene_flow_dir, exist_ok=True)
variant_dir = scene_flow_dir / config["variant"]
variant_dir_prefixes = {
"Monkaa": 0,
"Driving": 2,
"FlyingThings3D": 2,
}
os.makedirs(variant_dir, exist_ok=True)
num_examples = {"FlyingThings3D": 4, "Driving": 6, "Monkaa": 5}.get(config["variant"], 0)
passes = {
"clean": ["frames_cleanpass"],
"final": ["frames_finalpass"],
"both": ["frames_cleanpass", "frames_finalpass"],
}.get(config["pass_name"], [])
for pass_dir_name in passes:
# create pass directories
pass_dir = variant_dir / pass_dir_name
disp_dir = variant_dir / "disparity"
os.makedirs(pass_dir, exist_ok=True)
os.makedirs(disp_dir, exist_ok=True)
for i in range(variant_dir_prefixes.get(config["variant"], 0)):
pass_dir = pass_dir / str(i)
disp_dir = disp_dir / str(i)
os.makedirs(pass_dir, exist_ok=True)
os.makedirs(disp_dir, exist_ok=True)
for direction in ["left", "right"]:
for scene_idx in range(num_examples):
os.makedirs(pass_dir / f"scene_{scene_idx:06d}", exist_ok=True)
datasets_utils.create_image_folder(
root=pass_dir / f"scene_{scene_idx:06d}",
name=direction,
file_name_fn=lambda i: f"{i:06d}.png",
num_examples=1,
size=(3, 200, 100),
)
os.makedirs(disp_dir / f"scene_{scene_idx:06d}", exist_ok=True)
self._create_pfm_folder(
root=disp_dir / f"scene_{scene_idx:06d}",
name=direction,
file_name_fn=lambda i: f"{i:06d}.pfm",
num_examples=1,
size=(100, 200),
)
if config["pass_name"] == "both":
num_examples *= 2
return num_examples
def test_splits(self):
for variant_name, pass_name in itertools.product(["FlyingThings3D", "Driving", "Monkaa"], ["clean", "final"]):
with self.create_dataset(variant=variant_name, pass_name=pass_name) as (dataset, _):
for left, right, disparity in dataset:
datasets_utils.shape_test_for_stereo(left, right, disparity)
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument variant"):
with self.create_dataset(variant="bad"):
pass
class InStereo2k(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.InStereo2k
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)))
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
@staticmethod
def _make_scene_folder(root: str, name: str, size: Tuple[int, int]):
root = pathlib.Path(root) / name
os.makedirs(root, exist_ok=True)
datasets_utils.create_image_file(root=root, name="left.png", size=(3, size[0], size[1]))
datasets_utils.create_image_file(root=root, name="right.png", size=(3, size[0], size[1]))
datasets_utils.create_image_file(root=root, name="left_disp.png", size=(1, size[0], size[1]))
datasets_utils.create_image_file(root=root, name="right_disp.png", size=(1, size[0], size[1]))
def inject_fake_data(self, tmpdir, config):
in_stereo_dir = pathlib.Path(tmpdir) / "InStereo2k"
os.makedirs(in_stereo_dir, exist_ok=True)
split_dir = pathlib.Path(in_stereo_dir) / config["split"]
os.makedirs(split_dir, exist_ok=True)
num_examples = {"train": 4, "test": 5}.get(config["split"], 0)
for i in range(num_examples):
self._make_scene_folder(split_dir, f"scene_{i:06d}", (100, 200))
return num_examples
def test_splits(self):
for split_name in ["train", "test"]:
with self.create_dataset(split=split_name) as (dataset, _):
for left, right, disparity in dataset:
datasets_utils.shape_test_for_stereo(left, right, disparity)
def test_bad_input(self):
with pytest.raises(
ValueError, match="Unknown value 'bad' for argument split. Valid values are {'train', 'test'}."
):
with self.create_dataset(split="bad"):
pass
class SintelStereoTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.SintelStereo
ADDITIONAL_CONFIGS = combinations_grid(pass_name=("final", "clean", "both"))
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)), (np.ndarray, type(None)))
def inject_fake_data(self, tmpdir, config):
sintel_dir = pathlib.Path(tmpdir) / "Sintel"
os.makedirs(sintel_dir, exist_ok=True)
split_dir = pathlib.Path(sintel_dir) / "training"
os.makedirs(split_dir, exist_ok=True)
# a single setting, since there are no splits
num_examples = {"final": 2, "clean": 3}
pass_names = {
"final": ["final"],
"clean": ["clean"],
"both": ["final", "clean"],
}.get(config["pass_name"], [])
for p in pass_names:
for view in [f"{p}_left", f"{p}_right"]:
root = split_dir / view
os.makedirs(root, exist_ok=True)
datasets_utils.create_image_folder(
root=root,
name="scene1",
file_name_fn=lambda i: f"{i:06d}.png",
num_examples=num_examples[p],
size=(3, 100, 200),
)
datasets_utils.create_image_folder(
root=split_dir / "occlusions",
name="scene1",
file_name_fn=lambda i: f"{i:06d}.png",
num_examples=max(num_examples.values()),
size=(1, 100, 200),
)
datasets_utils.create_image_folder(
root=split_dir / "outofframe",
name="scene1",
file_name_fn=lambda i: f"{i:06d}.png",
num_examples=max(num_examples.values()),
size=(1, 100, 200),
)
datasets_utils.create_image_folder(
root=split_dir / "disparities",
name="scene1",
file_name_fn=lambda i: f"{i:06d}.png",
num_examples=max(num_examples.values()),
size=(3, 100, 200),
)
if config["pass_name"] == "both":
num_examples = sum(num_examples.values())
else:
num_examples = num_examples.get(config["pass_name"], 0)
return num_examples
def test_splits(self):
for pass_name in ["final", "clean", "both"]:
with self.create_dataset(pass_name=pass_name) as (dataset, _):
for left, right, disparity, valid_mask in dataset:
datasets_utils.shape_test_for_stereo(left, right, disparity, valid_mask)
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument pass_name"):
with self.create_dataset(pass_name="bad"):
pass
class ETH3DStereoestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.ETH3DStereo
ADDITIONAL_CONFIGS = combinations_grid(split=("train", "test"))
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)), (np.ndarray, type(None)))
@staticmethod
def _create_scene_folder(num_examples: int, root_dir: str):
# make the root_dir if it does not exits
root_dir = pathlib.Path(root_dir)
os.makedirs(root_dir, exist_ok=True)
for i in range(num_examples):
scene_dir = root_dir / f"scene_{i}"
os.makedirs(scene_dir, exist_ok=True)
# populate with left right images
datasets_utils.create_image_file(root=scene_dir, name="im0.png", size=(100, 100))
datasets_utils.create_image_file(root=scene_dir, name="im1.png", size=(100, 100))
@staticmethod
def _create_annotation_folder(num_examples: int, root_dir: str):
# make the root_dir if it does not exits
root_dir = pathlib.Path(root_dir)
os.makedirs(root_dir, exist_ok=True)
# create scene directories
for i in range(num_examples):
scene_dir = root_dir / f"scene_{i}"
os.makedirs(scene_dir, exist_ok=True)
# populate with a random png file for occlusion mask, and a pfm file for disparity
datasets_utils.create_image_file(root=scene_dir, name="mask0nocc.png", size=(1, 100, 100))
pfm_path = scene_dir / "disp0GT.pfm"
datasets_utils.make_fake_pfm_file(h=100, w=100, file_name=pfm_path)
def inject_fake_data(self, tmpdir, config):
eth3d_dir = pathlib.Path(tmpdir) / "ETH3D"
num_examples = 2 if config["split"] == "train" else 3
split_name = "two_view_training" if config["split"] == "train" else "two_view_test"
split_dir = eth3d_dir / split_name
self._create_scene_folder(num_examples, split_dir)
if config["split"] == "train":
annot_dir = eth3d_dir / "two_view_training_gt"
self._create_annotation_folder(num_examples, annot_dir)
return num_examples
def test_training_splits(self):
with self.create_dataset(split="train") as (dataset, _):
for left, right, disparity, valid_mask in dataset:
datasets_utils.shape_test_for_stereo(left, right, disparity, valid_mask)
def test_testing_splits(self):
with self.create_dataset(split="test") as (dataset, _):
assert all(d == (None, None) for d in dataset._disparities)
for left, right, disparity, valid_mask in dataset:
assert valid_mask is None
datasets_utils.shape_test_for_stereo(left, right, disparity)
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument split"):
with self.create_dataset(split="bad"):
pass
class Middlebury2014StereoTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Middlebury2014Stereo
ADDITIONAL_CONFIGS = combinations_grid(
split=("train", "additional"),
calibration=("perfect", "imperfect", "both"),
use_ambient_views=(True, False),
)
FEATURE_TYPES = (PIL.Image.Image, PIL.Image.Image, (np.ndarray, type(None)), (np.ndarray, type(None)))
@staticmethod
def _make_scene_folder(root_dir: str, scene_name: str, split: str) -> None:
calibrations = [None] if split == "test" else ["-perfect", "-imperfect"]
root_dir = pathlib.Path(root_dir)
for c in calibrations:
scene_dir = root_dir / f"{scene_name}{c}"
os.makedirs(scene_dir, exist_ok=True)
# make normal images first
datasets_utils.create_image_file(root=scene_dir, name="im0.png", size=(3, 100, 100))
datasets_utils.create_image_file(root=scene_dir, name="im1.png", size=(3, 100, 100))
datasets_utils.create_image_file(root=scene_dir, name="im1E.png", size=(3, 100, 100))
datasets_utils.create_image_file(root=scene_dir, name="im1L.png", size=(3, 100, 100))
# these are going to end up being gray scale images
datasets_utils.make_fake_pfm_file(h=100, w=100, file_name=scene_dir / "disp0.pfm")
datasets_utils.make_fake_pfm_file(h=100, w=100, file_name=scene_dir / "disp1.pfm")
def inject_fake_data(self, tmpdir, config):
split_scene_map = {
"train": ["Adirondack", "Jadeplant", "Motorcycle", "Piano"],
"additional": ["Backpack", "Bicycle1", "Cable", "Classroom1"],
"test": ["Plants", "Classroom2E", "Classroom2", "Australia"],
}
middlebury_dir = pathlib.Path(tmpdir, "Middlebury2014")
os.makedirs(middlebury_dir, exist_ok=True)
split_dir = middlebury_dir / config["split"]
os.makedirs(split_dir, exist_ok=True)
num_examples = {"train": 2, "additional": 3, "test": 4}.get(config["split"], 0)
for idx in range(num_examples):
scene_name = split_scene_map[config["split"]][idx]
self._make_scene_folder(root_dir=split_dir, scene_name=scene_name, split=config["split"])
if config["calibration"] == "both":
num_examples *= 2
return num_examples
def test_train_splits(self):
for split, calibration in itertools.product(["train", "additional"], ["perfect", "imperfect", "both"]):
with self.create_dataset(split=split, calibration=calibration) as (dataset, _):
for left, right, disparity, mask in dataset:
datasets_utils.shape_test_for_stereo(left, right, disparity, mask)
def test_test_split(self):
for split in ["test"]:
with self.create_dataset(split=split, calibration=None) as (dataset, _):
for left, right, disparity, mask in dataset:
datasets_utils.shape_test_for_stereo(left, right)
def test_augmented_view_usage(self):
with self.create_dataset(split="train", use_ambient_views=True) as (dataset, _):
for left, right, disparity, mask in dataset:
datasets_utils.shape_test_for_stereo(left, right, disparity, mask)
def test_value_err_train(self):
# train set invalid
split = "train"
calibration = None
with pytest.raises(
ValueError,
match=f"Split '{split}' has calibration settings, however None was provided as an argument."
f"\nSetting calibration to 'perfect' for split '{split}'. Available calibration settings are: 'perfect', 'imperfect', 'both'.",
):
with self.create_dataset(split=split, calibration=calibration):
pass
def test_value_err_test(self):
# test set invalid
split = "test"
calibration = "perfect"
with pytest.raises(
ValueError, match="Split 'test' has only no calibration settings, please set `calibration=None`."
):
with self.create_dataset(split=split, calibration=calibration):
pass
def test_bad_input(self):
with pytest.raises(ValueError, match="Unknown value 'bad' for argument split"):
with self.create_dataset(split="bad"):
pass
class ImagenetteTestCase(datasets_utils.ImageDatasetTestCase):
DATASET_CLASS = datasets.Imagenette
ADDITIONAL_CONFIGS = combinations_grid(split=["train", "val"], size=["full", "320px", "160px"])
_WNIDS = [
"n01440764",
"n02102040",
"n02979186",
"n03000684",
"n03028079",
"n03394916",
"n03417042",
"n03425413",
"n03445777",
"n03888257",
]
def inject_fake_data(self, tmpdir, config):
archive_root = "imagenette2"
if config["size"] != "full":
archive_root += f"-{config['size'].replace('px', '')}"
image_root = pathlib.Path(tmpdir) / archive_root / config["split"]
num_images_per_class = 3
for wnid in self._WNIDS:
datasets_utils.create_image_folder(
root=image_root,
name=wnid,
file_name_fn=lambda idx: f"{wnid}_{idx}.JPEG",
num_examples=num_images_per_class,
)
return num_images_per_class * len(self._WNIDS)
class TestDatasetWrapper:
def test_unknown_type(self):
unknown_object = object()
with pytest.raises(
TypeError, match=re.escape("is meant for subclasses of `torchvision.datasets.VisionDataset`")
):
datasets.wrap_dataset_for_transforms_v2(unknown_object)
def test_unknown_dataset(self):
class MyVisionDataset(datasets.VisionDataset):
pass
dataset = MyVisionDataset("root")
with pytest.raises(TypeError, match="No wrapper exist"):
datasets.wrap_dataset_for_transforms_v2(dataset)
def test_missing_wrapper(self):
dataset = datasets.FakeData()
with pytest.raises(TypeError, match="please open an issue"):
datasets.wrap_dataset_for_transforms_v2(dataset)
def test_subclass(self, mocker):
from torchvision import tv_tensors
sentinel = object()
mocker.patch.dict(
tv_tensors._dataset_wrapper.WRAPPER_FACTORIES,
clear=False,
values={datasets.FakeData: lambda dataset, target_keys: lambda idx, sample: sentinel},
)
class MyFakeData(datasets.FakeData):
pass
dataset = MyFakeData()
wrapped_dataset = datasets.wrap_dataset_for_transforms_v2(dataset)
assert wrapped_dataset[0] is sentinel
if __name__ == "__main__":
unittest.main()
import contextlib
import itertools
import shutil
import tempfile
import time
import traceback
import unittest.mock
import warnings
from datetime import datetime
from distutils import dir_util
from os import path
from urllib.error import HTTPError, URLError
from urllib.parse import urlparse
from urllib.request import urlopen, Request
import tempfile
import warnings
from urllib.request import Request, urlopen
import pytest
from torchvision import datasets
from torchvision.datasets.utils import (
download_url,
check_integrity,
download_file_from_google_drive,
_get_redirect_url,
USER_AGENT,
)
from common_utils import get_tmp_dir
from torchvision.datasets.utils import _get_redirect_url, USER_AGENT
def limit_requests_per_time(min_secs_between_requests=2.0):
......@@ -86,63 +78,65 @@ urlopen = resolve_redirects()(urlopen)
@contextlib.contextmanager
def log_download_attempts(
urls_and_md5s=None,
file="utils",
patch=True,
mock_auxiliaries=None,
urls,
*,
dataset_module,
):
def add_mock(stack, name, file, **kwargs):
def maybe_add_mock(*, module, name, stack, lst=None):
patcher = unittest.mock.patch(f"torchvision.datasets.{module}.{name}")
try:
return stack.enter_context(unittest.mock.patch(f"torchvision.datasets.{file}.{name}", **kwargs))
except AttributeError as error:
if file != "utils":
return add_mock(stack, name, "utils", **kwargs)
else:
raise pytest.UsageError from error
mock = stack.enter_context(patcher)
except AttributeError:
return
if urls_and_md5s is None:
urls_and_md5s = set()
if mock_auxiliaries is None:
mock_auxiliaries = patch
if lst is not None:
lst.append(mock)
with contextlib.ExitStack() as stack:
url_mock = add_mock(stack, "download_url", file, wraps=None if patch else download_url)
google_drive_mock = add_mock(
stack, "download_file_from_google_drive", file, wraps=None if patch else download_file_from_google_drive
download_url_mocks = []
download_file_from_google_drive_mocks = []
for module in [dataset_module, "utils"]:
maybe_add_mock(module=module, name="download_url", stack=stack, lst=download_url_mocks)
maybe_add_mock(
module=module,
name="download_file_from_google_drive",
stack=stack,
lst=download_file_from_google_drive_mocks,
)
if mock_auxiliaries:
add_mock(stack, "extract_archive", file)
maybe_add_mock(module=module, name="extract_archive", stack=stack)
try:
yield urls_and_md5s
yield
finally:
for args, kwargs in url_mock.call_args_list:
url = args[0]
md5 = args[-1] if len(args) == 4 else kwargs.get("md5")
urls_and_md5s.add((url, md5))
for download_url_mock in download_url_mocks:
for args, kwargs in download_url_mock.call_args_list:
urls.append(args[0] if args else kwargs["url"])
for args, kwargs in google_drive_mock.call_args_list:
id = args[0]
url = f"https://drive.google.com/file/d/{id}"
md5 = args[3] if len(args) == 4 else kwargs.get("md5")
urls_and_md5s.add((url, md5))
for download_file_from_google_drive_mock in download_file_from_google_drive_mocks:
for args, kwargs in download_file_from_google_drive_mock.call_args_list:
file_id = args[0] if args else kwargs["file_id"]
urls.append(f"https://drive.google.com/file/d/{file_id}")
def retry(fn, times=1, wait=5.0):
msgs = []
tbs = []
for _ in range(times + 1):
try:
return fn()
except AssertionError as error:
msgs.append(str(error))
tbs.append("".join(traceback.format_exception(type(error), error, error.__traceback__)))
time.sleep(wait)
else:
raise AssertionError(
"\n".join(
(
f"Assertion failed {times + 1} times with {wait:.1f} seconds intermediate wait time.\n",
*(f"{idx}: {error}" for idx, error in enumerate(msgs, 1)),
"\n",
*[f"{'_' * 40} {idx:2d} {'_' * 40}\n\n{tb}" for idx, tb in enumerate(tbs, 1)],
(
f"Assertion failed {times + 1} times with {wait:.1f} seconds intermediate wait time. "
f"You can find the the full tracebacks above."
),
)
)
)
......@@ -152,10 +146,12 @@ def retry(fn, times=1, wait=5.0):
def assert_server_response_ok():
try:
yield
except URLError as error:
raise AssertionError("The request timed out.") from error
except HTTPError as error:
raise AssertionError(f"The server returned {error.code}: {error.reason}.") from error
except URLError as error:
raise AssertionError(
"Connection not possible due to SSL." if "SSL" in str(error) else "The request timed out."
) from error
except RecursionError as error:
raise AssertionError(str(error)) from error
......@@ -166,46 +162,14 @@ def assert_url_is_accessible(url, timeout=5.0):
urlopen(request, timeout=timeout)
def assert_file_downloads_correctly(url, md5, timeout=5.0):
with get_tmp_dir() as root:
file = path.join(root, path.basename(url))
with assert_server_response_ok():
with open(file, "wb") as fh:
request = Request(url, headers={"User-Agent": USER_AGENT})
response = urlopen(request, timeout=timeout)
fh.write(response.read())
assert check_integrity(file, md5=md5), "The MD5 checksums mismatch"
class DownloadConfig:
def __init__(self, url, md5=None, id=None):
self.url = url
self.md5 = md5
self.id = id or url
def __repr__(self):
return self.id
def make_download_configs(urls_and_md5s, name=None):
return [
DownloadConfig(url, md5=md5, id=f"{name}, {url}" if name is not None else None) for url, md5 in urls_and_md5s
]
def collect_download_configs(dataset_loader, name=None, **kwargs):
urls_and_md5s = set()
try:
with log_download_attempts(urls_and_md5s=urls_and_md5s, **kwargs):
dataset = dataset_loader()
except Exception:
dataset = None
if name is None and dataset is not None:
name = type(dataset).__name__
def collect_urls(dataset_cls, *args, **kwargs):
urls = []
with contextlib.suppress(Exception), log_download_attempts(
urls, dataset_module=dataset_cls.__module__.split(".")[-1]
):
dataset_cls(*args, **kwargs)
return make_download_configs(urls_and_md5s, name)
return [(url, f"{dataset_cls.__name__}, {url}") for url in urls]
# This is a workaround since fixtures, such as the built-in tmp_dir, can only be used within a test but not within a
......@@ -216,16 +180,18 @@ ROOT = tempfile.mkdtemp()
@pytest.fixture(scope="module", autouse=True)
def root():
yield ROOT
dir_util.remove_tree(ROOT)
shutil.rmtree(ROOT)
def places365():
return itertools.chain(
*[
collect_download_configs(
lambda: datasets.Places365(ROOT, split=split, small=small, download=True),
name=f"Places365, {split}, {'small' if small else 'large'}",
file="places365",
return itertools.chain.from_iterable(
[
collect_urls(
datasets.Places365,
ROOT,
split=split,
small=small,
download=True,
)
for split, small in itertools.product(("train-standard", "train-challenge", "val"), (False, True))
]
......@@ -233,85 +199,69 @@ def places365():
def caltech101():
return collect_download_configs(lambda: datasets.Caltech101(ROOT, download=True), name="Caltech101")
return collect_urls(datasets.Caltech101, ROOT, download=True)
def caltech256():
return collect_download_configs(lambda: datasets.Caltech256(ROOT, download=True), name="Caltech256")
return collect_urls(datasets.Caltech256, ROOT, download=True)
def cifar10():
return collect_download_configs(lambda: datasets.CIFAR10(ROOT, download=True), name="CIFAR10")
return collect_urls(datasets.CIFAR10, ROOT, download=True)
def cifar100():
return collect_download_configs(lambda: datasets.CIFAR100(ROOT, download=True), name="CIFAR100")
return collect_urls(datasets.CIFAR100, ROOT, download=True)
def voc():
return itertools.chain(
*[
collect_download_configs(
lambda: datasets.VOCSegmentation(ROOT, year=year, download=True),
name=f"VOC, {year}",
file="voc",
)
for year in ("2007", "2007-test", "2008", "2009", "2010", "2011", "2012")
# TODO: Also test the "2007-test" key
return itertools.chain.from_iterable(
[
collect_urls(datasets.VOCSegmentation, ROOT, year=year, download=True)
for year in ("2007", "2008", "2009", "2010", "2011", "2012")
]
)
def mnist():
with unittest.mock.patch.object(datasets.MNIST, "mirrors", datasets.MNIST.mirrors[-1:]):
return collect_download_configs(lambda: datasets.MNIST(ROOT, download=True), name="MNIST")
return collect_urls(datasets.MNIST, ROOT, download=True)
def fashion_mnist():
return collect_download_configs(lambda: datasets.FashionMNIST(ROOT, download=True), name="FashionMNIST")
return collect_urls(datasets.FashionMNIST, ROOT, download=True)
def kmnist():
return collect_download_configs(lambda: datasets.KMNIST(ROOT, download=True), name="KMNIST")
return collect_urls(datasets.KMNIST, ROOT, download=True)
def emnist():
# the 'split' argument can be any valid one, since everything is downloaded anyway
return collect_download_configs(lambda: datasets.EMNIST(ROOT, split="byclass", download=True), name="EMNIST")
return collect_urls(datasets.EMNIST, ROOT, split="byclass", download=True)
def qmnist():
return itertools.chain(
*[
collect_download_configs(
lambda: datasets.QMNIST(ROOT, what=what, download=True),
name=f"QMNIST, {what}",
file="mnist",
)
for what in ("train", "test", "nist")
]
return itertools.chain.from_iterable(
[collect_urls(datasets.QMNIST, ROOT, what=what, download=True) for what in ("train", "test", "nist")]
)
def moving_mnist():
return collect_urls(datasets.MovingMNIST, ROOT, download=True)
def omniglot():
return itertools.chain(
*[
collect_download_configs(
lambda: datasets.Omniglot(ROOT, background=background, download=True),
name=f"Omniglot, {'background' if background else 'evaluation'}",
)
for background in (True, False)
]
return itertools.chain.from_iterable(
[collect_urls(datasets.Omniglot, ROOT, background=background, download=True) for background in (True, False)]
)
def phototour():
return itertools.chain(
*[
collect_download_configs(
lambda: datasets.PhotoTour(ROOT, name=name, download=True),
name=f"PhotoTour, {name}",
file="phototour",
)
return itertools.chain.from_iterable(
[
collect_urls(datasets.PhotoTour, ROOT, name=name, download=True)
# The names postfixed with '_harris' point to the domain 'matthewalunbrown.com'. For some reason all
# requests timeout from within CI. They are disabled until this is resolved.
for name in ("notredame", "yosemite", "liberty") # "notredame_harris", "yosemite_harris", "liberty_harris"
......@@ -320,134 +270,119 @@ def phototour():
def sbdataset():
return collect_download_configs(
lambda: datasets.SBDataset(ROOT, download=True),
name="SBDataset",
file="voc",
)
return collect_urls(datasets.SBDataset, ROOT, download=True)
def sbu():
return collect_download_configs(
lambda: datasets.SBU(ROOT, download=True),
name="SBU",
file="sbu",
)
return collect_urls(datasets.SBU, ROOT, download=True)
def semeion():
return collect_download_configs(
lambda: datasets.SEMEION(ROOT, download=True),
name="SEMEION",
file="semeion",
)
return collect_urls(datasets.SEMEION, ROOT, download=True)
def stl10():
return collect_download_configs(
lambda: datasets.STL10(ROOT, download=True),
name="STL10",
)
return collect_urls(datasets.STL10, ROOT, download=True)
def svhn():
return itertools.chain(
*[
collect_download_configs(
lambda: datasets.SVHN(ROOT, split=split, download=True),
name=f"SVHN, {split}",
file="svhn",
)
for split in ("train", "test", "extra")
]
return itertools.chain.from_iterable(
[collect_urls(datasets.SVHN, ROOT, split=split, download=True) for split in ("train", "test", "extra")]
)
def usps():
return itertools.chain(
*[
collect_download_configs(
lambda: datasets.USPS(ROOT, train=train, download=True),
name=f"USPS, {'train' if train else 'test'}",
file="usps",
)
for train in (True, False)
]
return itertools.chain.from_iterable(
[collect_urls(datasets.USPS, ROOT, train=train, download=True) for train in (True, False)]
)
def celeba():
return collect_download_configs(
lambda: datasets.CelebA(ROOT, download=True),
name="CelebA",
file="celeba",
)
return collect_urls(datasets.CelebA, ROOT, download=True)
def widerface():
return collect_download_configs(
lambda: datasets.WIDERFace(ROOT, download=True),
name="WIDERFace",
file="widerface",
return collect_urls(datasets.WIDERFace, ROOT, download=True)
def kinetics():
return itertools.chain.from_iterable(
[
collect_urls(
datasets.Kinetics,
path.join(ROOT, f"Kinetics{num_classes}"),
frames_per_clip=1,
num_classes=num_classes,
split=split,
download=True,
)
for num_classes, split in itertools.product(("400", "600", "700"), ("train", "val"))
]
)
def kitti():
return itertools.chain(
*[
collect_download_configs(
lambda train=train: datasets.Kitti(ROOT, train=train, download=True),
name=f"Kitti, {'train' if train else 'test'}",
file="kitti",
return itertools.chain.from_iterable(
[collect_urls(datasets.Kitti, ROOT, train=train, download=True) for train in (True, False)]
)
for train in (True, False)
]
)
def make_parametrize_kwargs(download_configs):
argvalues = []
ids = []
for config in download_configs:
argvalues.append((config.url, config.md5))
ids.append(config.id)
return dict(argnames=("url", "md5"), argvalues=argvalues, ids=ids)
def url_parametrization(*dataset_urls_and_ids_fns):
return pytest.mark.parametrize(
"url",
[
pytest.param(url, id=id)
for dataset_urls_and_ids_fn in dataset_urls_and_ids_fns
for url, id in sorted(set(dataset_urls_and_ids_fn()))
],
)
@pytest.mark.parametrize(
**make_parametrize_kwargs(
itertools.chain(
places365(),
caltech101(),
caltech256(),
cifar10(),
cifar100(),
@url_parametrization(
caltech101,
caltech256,
cifar10,
cifar100,
# The VOC download server is unstable. See https://github.com/pytorch/vision/issues/2953 for details.
# voc(),
mnist(),
fashion_mnist(),
kmnist(),
emnist(),
qmnist(),
omniglot(),
phototour(),
sbdataset(),
sbu(),
semeion(),
stl10(),
svhn(),
usps(),
celeba(),
widerface(),
kitti(),
)
)
# voc,
mnist,
fashion_mnist,
kmnist,
emnist,
qmnist,
omniglot,
phototour,
sbdataset,
semeion,
stl10,
svhn,
usps,
celeba,
widerface,
kinetics,
kitti,
places365,
sbu,
)
def test_url_is_accessible(url, md5):
def test_url_is_accessible(url):
"""
If you see this test failing, find the offending dataset in the parametrization and move it to
``test_url_is_not_accessible`` and link an issue detailing the problem.
"""
retry(lambda: assert_url_is_accessible(url))
@pytest.mark.parametrize(**make_parametrize_kwargs(itertools.chain()))
def test_file_downloads_correctly(url, md5):
retry(lambda: assert_file_downloads_correctly(url, md5))
# TODO: if e.g. caltech101 starts failing, remove the pytest.mark.parametrize below and use
# @url_parametrization(caltech101)
@pytest.mark.parametrize("url", ("http://url_that_doesnt_exist.com",)) # here until we actually have a failing dataset
@pytest.mark.xfail
def test_url_is_not_accessible(url):
"""
As the name implies, this test is the 'inverse' of ``test_url_is_accessible``. Since the download servers are
beyond our control, some files might not be accessible for longer stretches of time. Still, we want to know if they
come back up, or if we need to remove the download functionality of the dataset for good.
If you see this test failing, find the offending dataset in the parametrization and move it to
``test_url_is_accessible``.
"""
assert_url_is_accessible(url)
import contextlib
import sys
import os
import pytest
import torch
import unittest
from common_utils import assert_equal, get_list_of_videos
from torchvision import io
from torchvision.datasets.samplers import (
DistributedSampler,
RandomClipSampler,
UniformClipSampler,
)
from torchvision.datasets.video_utils import VideoClips, unfold
from torchvision import get_video_backend
from common_utils import get_tmp_dir
from _assert_utils import assert_equal
@contextlib.contextmanager
def get_list_of_videos(num_videos=5, sizes=None, fps=None):
with get_tmp_dir() as tmp_dir:
names = []
for i in range(num_videos):
if sizes is None:
size = 5 * (i + 1)
else:
size = sizes[i]
if fps is None:
f = 5
else:
f = fps[i]
data = torch.randint(0, 256, (size, 300, 400, 3), dtype=torch.uint8)
name = os.path.join(tmp_dir, "{}.mp4".format(i))
names.append(name)
io.write_video(name, data, fps=f)
yield names
from torchvision.datasets.samplers import DistributedSampler, RandomClipSampler, UniformClipSampler
from torchvision.datasets.video_utils import VideoClips
@unittest.skipIf(not io.video._av_available(), "this test requires av")
class Tester(unittest.TestCase):
def test_random_clip_sampler(self):
with get_list_of_videos(num_videos=3, sizes=[25, 25, 25]) as video_list:
@pytest.mark.skipif(not io.video._av_available(), reason="this test requires av")
class TestDatasetsSamplers:
def test_random_clip_sampler(self, tmpdir):
video_list = get_list_of_videos(tmpdir, num_videos=3, sizes=[25, 25, 25])
video_clips = VideoClips(video_list, 5, 5)
sampler = RandomClipSampler(video_clips, 3)
self.assertEqual(len(sampler), 3 * 3)
assert len(sampler) == 3 * 3
indices = torch.tensor(list(iter(sampler)))
videos = torch.div(indices, 5, rounding_mode='floor')
videos = torch.div(indices, 5, rounding_mode="floor")
v_idxs, count = torch.unique(videos, return_counts=True)
assert_equal(v_idxs, torch.tensor([0, 1, 2]))
assert_equal(count, torch.tensor([3, 3, 3]))
def test_random_clip_sampler_unequal(self):
with get_list_of_videos(num_videos=3, sizes=[10, 25, 25]) as video_list:
def test_random_clip_sampler_unequal(self, tmpdir):
video_list = get_list_of_videos(tmpdir, num_videos=3, sizes=[10, 25, 25])
video_clips = VideoClips(video_list, 5, 5)
sampler = RandomClipSampler(video_clips, 3)
self.assertEqual(len(sampler), 2 + 3 + 3)
assert len(sampler) == 2 + 3 + 3
indices = list(iter(sampler))
self.assertIn(0, indices)
self.assertIn(1, indices)
assert 0 in indices
assert 1 in indices
# remove elements of the first video, to simplify testing
indices.remove(0)
indices.remove(1)
indices = torch.tensor(indices) - 2
videos = torch.div(indices, 5, rounding_mode='floor')
videos = torch.div(indices, 5, rounding_mode="floor")
v_idxs, count = torch.unique(videos, return_counts=True)
assert_equal(v_idxs, torch.tensor([0, 1]))
assert_equal(count, torch.tensor([3, 3]))
def test_uniform_clip_sampler(self):
with get_list_of_videos(num_videos=3, sizes=[25, 25, 25]) as video_list:
def test_uniform_clip_sampler(self, tmpdir):
video_list = get_list_of_videos(tmpdir, num_videos=3, sizes=[25, 25, 25])
video_clips = VideoClips(video_list, 5, 5)
sampler = UniformClipSampler(video_clips, 3)
self.assertEqual(len(sampler), 3 * 3)
assert len(sampler) == 3 * 3
indices = torch.tensor(list(iter(sampler)))
videos = torch.div(indices, 5, rounding_mode='floor')
videos = torch.div(indices, 5, rounding_mode="floor")
v_idxs, count = torch.unique(videos, return_counts=True)
assert_equal(v_idxs, torch.tensor([0, 1, 2]))
assert_equal(count, torch.tensor([3, 3, 3]))
assert_equal(indices, torch.tensor([0, 2, 4, 5, 7, 9, 10, 12, 14]))
def test_uniform_clip_sampler_insufficient_clips(self):
with get_list_of_videos(num_videos=3, sizes=[10, 25, 25]) as video_list:
def test_uniform_clip_sampler_insufficient_clips(self, tmpdir):
video_list = get_list_of_videos(tmpdir, num_videos=3, sizes=[10, 25, 25])
video_clips = VideoClips(video_list, 5, 5)
sampler = UniformClipSampler(video_clips, 3)
self.assertEqual(len(sampler), 3 * 3)
assert len(sampler) == 3 * 3
indices = torch.tensor(list(iter(sampler)))
assert_equal(indices, torch.tensor([0, 0, 1, 2, 4, 6, 7, 9, 11]))
def test_distributed_sampler_and_uniform_clip_sampler(self):
with get_list_of_videos(num_videos=3, sizes=[25, 25, 25]) as video_list:
def test_distributed_sampler_and_uniform_clip_sampler(self, tmpdir):
video_list = get_list_of_videos(tmpdir, num_videos=3, sizes=[25, 25, 25])
video_clips = VideoClips(video_list, 5, 5)
clip_sampler = UniformClipSampler(video_clips, 3)
......@@ -100,7 +68,7 @@ class Tester(unittest.TestCase):
group_size=3,
)
indices = torch.tensor(list(iter(distributed_sampler_rank0)))
self.assertEqual(len(distributed_sampler_rank0), 6)
assert len(distributed_sampler_rank0) == 6
assert_equal(indices, torch.tensor([0, 2, 4, 10, 12, 14]))
distributed_sampler_rank1 = DistributedSampler(
......@@ -110,9 +78,9 @@ class Tester(unittest.TestCase):
group_size=3,
)
indices = torch.tensor(list(iter(distributed_sampler_rank1)))
self.assertEqual(len(distributed_sampler_rank1), 6)
assert len(distributed_sampler_rank1) == 6
assert_equal(indices, torch.tensor([5, 7, 9, 0, 2, 4]))
if __name__ == '__main__':
unittest.main()
if __name__ == "__main__":
pytest.main([__file__])
import contextlib
import gzip
import os
import torchvision.datasets.utils as utils
import unittest
import unittest.mock
import zipfile
import pathlib
import re
import tarfile
import gzip
import warnings
import zipfile
import pytest
import torch
import torchvision.datasets.utils as utils
from common_utils import assert_equal
from torch._utils_internal import get_file_path_2
from urllib.error import URLError
import itertools
import lzma
from torchvision.datasets.folder import make_dataset
from torchvision.datasets.utils import _COMPRESSED_FILE_OPENERS
from common_utils import get_tmp_dir, call_args_to_kwargs_only
TEST_FILE = get_file_path_2(
os.path.dirname(os.path.abspath(__file__)), "assets", "encode_jpeg", "grace_hopper_517x606.jpg"
)
TEST_FILE = get_file_path_2(
os.path.dirname(os.path.abspath(__file__)), 'assets', 'encode_jpeg', 'grace_hopper_517x606.jpg')
def patch_url_redirection(mocker, redirect_url):
class Response:
def __init__(self, url):
self.url = url
@contextlib.contextmanager
def patched_opener(*args, **kwargs):
yield Response(redirect_url)
return mocker.patch("torchvision.datasets.utils.urllib.request.urlopen", side_effect=patched_opener)
class TestDatasetsUtils:
def test_get_redirect_url(self, mocker):
url = "https://url.org"
expected_redirect_url = "https://redirect.url.org"
mock = patch_url_redirection(mocker, expected_redirect_url)
actual = utils._get_redirect_url(url)
assert actual == expected_redirect_url
class Tester(unittest.TestCase):
assert mock.call_count == 2
call_args_1, call_args_2 = mock.call_args_list
assert call_args_1[0][0].full_url == url
assert call_args_2[0][0].full_url == expected_redirect_url
def test_check_md5(self):
def test_get_redirect_url_max_hops_exceeded(self, mocker):
url = "https://url.org"
redirect_url = "https://redirect.url.org"
mock = patch_url_redirection(mocker, redirect_url)
with pytest.raises(RecursionError):
utils._get_redirect_url(url, max_hops=0)
assert mock.call_count == 1
assert mock.call_args[0][0].full_url == url
@pytest.mark.parametrize("use_pathlib", (True, False))
def test_check_md5(self, use_pathlib):
fpath = TEST_FILE
correct_md5 = '9c0bb82894bb3af7f7675ef2b3b6dcdc'
false_md5 = ''
self.assertTrue(utils.check_md5(fpath, correct_md5))
self.assertFalse(utils.check_md5(fpath, false_md5))
if use_pathlib:
fpath = pathlib.Path(fpath)
correct_md5 = "9c0bb82894bb3af7f7675ef2b3b6dcdc"
false_md5 = ""
assert utils.check_md5(fpath, correct_md5)
assert not utils.check_md5(fpath, false_md5)
def test_check_integrity(self):
existing_fpath = TEST_FILE
nonexisting_fpath = ''
correct_md5 = '9c0bb82894bb3af7f7675ef2b3b6dcdc'
false_md5 = ''
self.assertTrue(utils.check_integrity(existing_fpath, correct_md5))
self.assertFalse(utils.check_integrity(existing_fpath, false_md5))
self.assertTrue(utils.check_integrity(existing_fpath))
self.assertFalse(utils.check_integrity(nonexisting_fpath))
nonexisting_fpath = ""
correct_md5 = "9c0bb82894bb3af7f7675ef2b3b6dcdc"
false_md5 = ""
assert utils.check_integrity(existing_fpath, correct_md5)
assert not utils.check_integrity(existing_fpath, false_md5)
assert utils.check_integrity(existing_fpath)
assert not utils.check_integrity(nonexisting_fpath)
def test_get_google_drive_file_id(self):
url = "https://drive.google.com/file/d/1hbzc_P1FuxMkcabkgn9ZKinBwW683j45/view"
expected = "1hbzc_P1FuxMkcabkgn9ZKinBwW683j45"
url = "https://drive.google.com/file/d/1GO-BHUYRuvzr1Gtp2_fqXRsr9TIeYbhV/view"
expected = "1GO-BHUYRuvzr1Gtp2_fqXRsr9TIeYbhV"
actual = utils._get_google_drive_file_id(url)
assert actual == expected
......@@ -49,84 +90,64 @@ class Tester(unittest.TestCase):
assert utils._get_google_drive_file_id(url) is None
def test_detect_file_type(self):
for file, expected in [
@pytest.mark.parametrize(
"file, expected",
[
("foo.tar.bz2", (".tar.bz2", ".tar", ".bz2")),
("foo.tar.xz", (".tar.xz", ".tar", ".xz")),
("foo.tar", (".tar", ".tar", None)),
("foo.tar.gz", (".tar.gz", ".tar", ".gz")),
("foo.tbz", (".tbz", ".tar", ".bz2")),
("foo.tbz2", (".tbz2", ".tar", ".bz2")),
("foo.tgz", (".tgz", ".tar", ".gz")),
("foo.bz2", (".bz2", None, ".bz2")),
("foo.gz", (".gz", None, ".gz")),
("foo.zip", (".zip", ".zip", None)),
("foo.xz", (".xz", None, ".xz")),
]:
with self.subTest(file=file):
self.assertSequenceEqual(utils._detect_file_type(file), expected)
def test_detect_file_type_no_ext(self):
with self.assertRaises(RuntimeError):
utils._detect_file_type("foo")
def test_detect_file_type_to_many_exts(self):
with self.assertRaises(RuntimeError):
utils._detect_file_type("foo.bar.tar.gz")
def test_detect_file_type_unknown_archive_type(self):
with self.assertRaises(RuntimeError):
utils._detect_file_type("foo.bar.gz")
def test_detect_file_type_unknown_compression(self):
with self.assertRaises(RuntimeError):
utils._detect_file_type("foo.tar.baz")
def test_detect_file_type_unknown_partial_ext(self):
with self.assertRaises(RuntimeError):
utils._detect_file_type("foo.bar")
def test_decompress_gzip(self):
("foo.bar.tar.gz", (".tar.gz", ".tar", ".gz")),
("foo.bar.gz", (".gz", None, ".gz")),
("foo.bar.zip", (".zip", ".zip", None)),
],
)
def test_detect_file_type(self, file, expected):
assert utils._detect_file_type(file) == expected
@pytest.mark.parametrize("file", ["foo", "foo.tar.baz", "foo.bar"])
def test_detect_file_type_incompatible(self, file):
# tests detect file type for no extension, unknown compression and unknown partial extension
with pytest.raises(RuntimeError):
utils._detect_file_type(file)
@pytest.mark.parametrize("extension", [".bz2", ".gz", ".xz"])
@pytest.mark.parametrize("use_pathlib", (True, False))
def test_decompress(self, extension, tmpdir, use_pathlib):
def create_compressed(root, content="this is the content"):
file = os.path.join(root, "file")
compressed = f"{file}.gz"
compressed = f"{file}{extension}"
compressed_file_opener = _COMPRESSED_FILE_OPENERS[extension]
with gzip.open(compressed, "wb") as fh:
with compressed_file_opener(compressed, "wb") as fh:
fh.write(content.encode())
return compressed, file, content
with get_tmp_dir() as temp_dir:
compressed, file, content = create_compressed(temp_dir)
compressed, file, content = create_compressed(tmpdir)
if use_pathlib:
compressed = pathlib.Path(compressed)
utils._decompress(compressed)
self.assertTrue(os.path.exists(file))
with open(file, "r") as fh:
self.assertEqual(fh.read(), content)
assert os.path.exists(file)
def test_decompress_lzma(self):
def create_compressed(root, content="this is the content"):
file = os.path.join(root, "file")
compressed = f"{file}.xz"
with lzma.open(compressed, "wb") as fh:
fh.write(content.encode())
return compressed, file, content
with get_tmp_dir() as temp_dir:
compressed, file, content = create_compressed(temp_dir)
utils.extract_archive(compressed, temp_dir)
self.assertTrue(os.path.exists(file))
with open(file, "r") as fh:
self.assertEqual(fh.read(), content)
with open(file) as fh:
assert fh.read() == content
def test_decompress_no_compression(self):
with self.assertRaises(RuntimeError):
with pytest.raises(RuntimeError):
utils._decompress("foo.tar")
def test_decompress_remove_finished(self):
@pytest.mark.parametrize("use_pathlib", (True, False))
def test_decompress_remove_finished(self, tmpdir, use_pathlib):
def create_compressed(root, content="this is the content"):
file = os.path.join(root, "file")
compressed = f"{file}.gz"
......@@ -136,28 +157,35 @@ class Tester(unittest.TestCase):
return compressed, file, content
with get_tmp_dir() as temp_dir:
compressed, file, content = create_compressed(temp_dir)
utils.extract_archive(compressed, temp_dir, remove_finished=True)
self.assertFalse(os.path.exists(compressed))
def test_extract_archive_defer_to_decompress(self):
compressed, file, content = create_compressed(tmpdir)
print(f"{type(compressed)=}")
if use_pathlib:
compressed = pathlib.Path(compressed)
tmpdir = pathlib.Path(tmpdir)
extracted_dir = utils.extract_archive(compressed, tmpdir, remove_finished=True)
assert not os.path.exists(compressed)
if use_pathlib:
assert isinstance(extracted_dir, pathlib.Path)
assert isinstance(compressed, pathlib.Path)
else:
assert isinstance(extracted_dir, str)
assert isinstance(compressed, str)
@pytest.mark.parametrize("extension", [".gz", ".xz"])
@pytest.mark.parametrize("remove_finished", [True, False])
def test_extract_archive_defer_to_decompress(self, extension, remove_finished, mocker):
filename = "foo"
for ext, remove_finished in itertools.product((".gz", ".xz"), (True, False)):
with self.subTest(ext=ext, remove_finished=remove_finished):
with unittest.mock.patch("torchvision.datasets.utils._decompress") as mock:
file = f"{filename}{ext}"
file = f"{filename}{extension}"
mocked = mocker.patch("torchvision.datasets.utils._decompress")
utils.extract_archive(file, remove_finished=remove_finished)
mock.assert_called_once()
self.assertEqual(
call_args_to_kwargs_only(mock.call_args, utils._decompress),
dict(from_path=file, to_path=filename, remove_finished=remove_finished),
)
mocked.assert_called_once_with(file, filename, remove_finished=remove_finished)
def test_extract_zip(self):
@pytest.mark.parametrize("use_pathlib", (True, False))
def test_extract_zip(self, tmpdir, use_pathlib):
def create_archive(root, content="this is the content"):
file = os.path.join(root, "dst.txt")
archive = os.path.join(root, "archive.zip")
......@@ -167,21 +195,26 @@ class Tester(unittest.TestCase):
return archive, file, content
with get_tmp_dir() as temp_dir:
archive, file, content = create_archive(temp_dir)
if use_pathlib:
tmpdir = pathlib.Path(tmpdir)
archive, file, content = create_archive(tmpdir)
utils.extract_archive(archive, temp_dir)
utils.extract_archive(archive, tmpdir)
self.assertTrue(os.path.exists(file))
assert os.path.exists(file)
with open(file, "r") as fh:
self.assertEqual(fh.read(), content)
with open(file) as fh:
assert fh.read() == content
def test_extract_tar(self):
def create_archive(root, ext, mode, content="this is the content"):
@pytest.mark.parametrize(
"extension, mode", [(".tar", "w"), (".tar.gz", "w:gz"), (".tgz", "w:gz"), (".tar.xz", "w:xz")]
)
@pytest.mark.parametrize("use_pathlib", (True, False))
def test_extract_tar(self, extension, mode, tmpdir, use_pathlib):
def create_archive(root, extension, mode, content="this is the content"):
src = os.path.join(root, "src.txt")
dst = os.path.join(root, "dst.txt")
archive = os.path.join(root, f"archive{ext}")
archive = os.path.join(root, f"archive{extension}")
with open(src, "w") as fh:
fh.write(content)
......@@ -191,47 +224,64 @@ class Tester(unittest.TestCase):
return archive, dst, content
for ext, mode in zip(['.tar', '.tar.gz', '.tgz'], ['w', 'w:gz', 'w:gz']):
with get_tmp_dir() as temp_dir:
archive, file, content = create_archive(temp_dir, ext, mode)
if use_pathlib:
tmpdir = pathlib.Path(tmpdir)
archive, file, content = create_archive(tmpdir, extension, mode)
utils.extract_archive(archive, temp_dir)
utils.extract_archive(archive, tmpdir)
self.assertTrue(os.path.exists(file))
assert os.path.exists(file)
with open(file, "r") as fh:
self.assertEqual(fh.read(), content)
with open(file) as fh:
assert fh.read() == content
def test_extract_tar_xz(self):
def create_archive(root, ext, mode, content="this is the content"):
src = os.path.join(root, "src.txt")
dst = os.path.join(root, "dst.txt")
archive = os.path.join(root, f"archive{ext}")
with open(src, "w") as fh:
fh.write(content)
def test_verify_str_arg(self):
assert "a" == utils.verify_str_arg("a", "arg", ("a",))
pytest.raises(ValueError, utils.verify_str_arg, 0, ("a",), "arg")
pytest.raises(ValueError, utils.verify_str_arg, "b", ("a",), "arg")
@pytest.mark.parametrize(
("dtype", "actual_hex", "expected_hex"),
[
(torch.uint8, "01 23 45 67 89 AB CD EF", "01 23 45 67 89 AB CD EF"),
(torch.float16, "01 23 45 67 89 AB CD EF", "23 01 67 45 AB 89 EF CD"),
(torch.int32, "01 23 45 67 89 AB CD EF", "67 45 23 01 EF CD AB 89"),
(torch.float64, "01 23 45 67 89 AB CD EF", "EF CD AB 89 67 45 23 01"),
],
)
def test_flip_byte_order(self, dtype, actual_hex, expected_hex):
def to_tensor(hex):
return torch.frombuffer(bytes.fromhex(hex), dtype=dtype)
with tarfile.open(archive, mode=mode) as fh:
fh.add(src, arcname=os.path.basename(dst))
assert_equal(
utils._flip_byte_order(to_tensor(actual_hex)),
to_tensor(expected_hex),
)
return archive, dst, content
for ext, mode in zip(['.tar.xz'], ['w:xz']):
with get_tmp_dir() as temp_dir:
archive, file, content = create_archive(temp_dir, ext, mode)
@pytest.mark.parametrize(
("kwargs", "expected_error_msg"),
[
(dict(is_valid_file=lambda path: pathlib.Path(path).suffix in {".png", ".jpeg"}), "classes c"),
(dict(extensions=".png"), re.escape("classes b, c. Supported extensions are: .png")),
(dict(extensions=(".png", ".jpeg")), re.escape("classes c. Supported extensions are: .png, .jpeg")),
],
)
def test_make_dataset_no_valid_files(tmpdir, kwargs, expected_error_msg):
tmpdir = pathlib.Path(tmpdir)
utils.extract_archive(archive, temp_dir)
(tmpdir / "a").mkdir()
(tmpdir / "a" / "a.png").touch()
self.assertTrue(os.path.exists(file))
(tmpdir / "b").mkdir()
(tmpdir / "b" / "b.jpeg").touch()
with open(file, "r") as fh:
self.assertEqual(fh.read(), content)
(tmpdir / "c").mkdir()
(tmpdir / "c" / "c.unknown").touch()
def test_verify_str_arg(self):
self.assertEqual("a", utils.verify_str_arg("a", "arg", ("a",)))
self.assertRaises(ValueError, utils.verify_str_arg, 0, ("a",), "arg")
self.assertRaises(ValueError, utils.verify_str_arg, "b", ("a",), "arg")
with pytest.raises(FileNotFoundError, match=expected_error_msg):
make_dataset(str(tmpdir), **kwargs)
if __name__ == '__main__':
unittest.main()
if __name__ == "__main__":
pytest.main([__file__])
import contextlib
import os
import pytest
import torch
import unittest
from common_utils import assert_equal, get_list_of_videos
from torchvision import io
from torchvision.datasets.video_utils import VideoClips, unfold
from common_utils import get_tmp_dir
from _assert_utils import assert_equal
@contextlib.contextmanager
def get_list_of_videos(num_videos=5, sizes=None, fps=None):
with get_tmp_dir() as tmp_dir:
names = []
for i in range(num_videos):
if sizes is None:
size = 5 * (i + 1)
else:
size = sizes[i]
if fps is None:
f = 5
else:
f = fps[i]
data = torch.randint(0, 256, (size, 300, 400, 3), dtype=torch.uint8)
name = os.path.join(tmp_dir, "{}.mp4".format(i))
names.append(name)
io.write_video(name, data, fps=f)
from torchvision.datasets.video_utils import unfold, VideoClips
yield names
class Tester(unittest.TestCase):
class TestVideo:
def test_unfold(self):
a = torch.arange(7)
r = unfold(a, 3, 3, 1)
expected = torch.tensor([
expected = torch.tensor(
[
[0, 1, 2],
[3, 4, 5],
])
assert_equal(r, expected, check_stride=False)
]
)
assert_equal(r, expected)
r = unfold(a, 3, 2, 1)
expected = torch.tensor([
[0, 1, 2],
[2, 3, 4],
[4, 5, 6]
])
assert_equal(r, expected, check_stride=False)
expected = torch.tensor([[0, 1, 2], [2, 3, 4], [4, 5, 6]])
assert_equal(r, expected)
r = unfold(a, 3, 2, 2)
expected = torch.tensor([
expected = torch.tensor(
[
[0, 2, 4],
[2, 4, 6],
])
assert_equal(r, expected, check_stride=False)
]
)
assert_equal(r, expected)
@unittest.skipIf(not io.video._av_available(), "this test requires av")
def test_video_clips(self):
with get_list_of_videos(num_videos=3) as video_list:
@pytest.mark.skipif(not io.video._av_available(), reason="this test requires av")
def test_video_clips(self, tmpdir):
video_list = get_list_of_videos(tmpdir, num_videos=3)
video_clips = VideoClips(video_list, 5, 5, num_workers=2)
assert video_clips.num_clips() == 1 + 2 + 3
for i, (v_idx, c_idx) in enumerate([(0, 0), (1, 0), (1, 1), (2, 0), (2, 1), (2, 2)]):
......@@ -82,12 +55,12 @@ class Tester(unittest.TestCase):
assert video_idx == v_idx
assert clip_idx == c_idx
@unittest.skipIf(not io.video._av_available(), "this test requires av")
def test_video_clips_custom_fps(self):
with get_list_of_videos(num_videos=3, sizes=[12, 12, 12], fps=[3, 4, 6]) as video_list:
@pytest.mark.skipif(not io.video._av_available(), reason="this test requires av")
def test_video_clips_custom_fps(self, tmpdir):
video_list = get_list_of_videos(tmpdir, num_videos=3, sizes=[12, 12, 12], fps=[3, 4, 6])
num_frames = 4
for fps in [1, 3, 4, 10]:
video_clips = VideoClips(video_list, num_frames, num_frames, fps, num_workers=2)
video_clips = VideoClips(video_list, num_frames, num_frames, fps)
for i in range(video_clips.num_clips()):
video, audio, info, video_idx = video_clips.get_clip(i)
assert video.shape[0] == num_frames
......@@ -101,8 +74,7 @@ class Tester(unittest.TestCase):
orig_fps = 30
duration = float(len(video_pts)) / orig_fps
new_fps = 13
clips, idxs = VideoClips.compute_clips_for_video(video_pts, num_frames, num_frames,
orig_fps, new_fps)
clips, idxs = VideoClips.compute_clips_for_video(video_pts, num_frames, num_frames, orig_fps, new_fps)
resampled_idxs = VideoClips._resample_video_idx(int(duration * new_fps), orig_fps, new_fps)
assert len(clips) == 1
assert_equal(clips, idxs)
......@@ -113,8 +85,7 @@ class Tester(unittest.TestCase):
orig_fps = 30
duration = float(len(video_pts)) / orig_fps
new_fps = 12
clips, idxs = VideoClips.compute_clips_for_video(video_pts, num_frames, num_frames,
orig_fps, new_fps)
clips, idxs = VideoClips.compute_clips_for_video(video_pts, num_frames, num_frames, orig_fps, new_fps)
resampled_idxs = VideoClips._resample_video_idx(int(duration * new_fps), orig_fps, new_fps)
assert len(clips) == 3
assert_equal(clips, idxs)
......@@ -124,12 +95,11 @@ class Tester(unittest.TestCase):
num_frames = 32
orig_fps = 30
new_fps = 13
with self.assertWarns(UserWarning):
clips, idxs = VideoClips.compute_clips_for_video(video_pts, num_frames, num_frames,
orig_fps, new_fps)
with pytest.warns(UserWarning):
clips, idxs = VideoClips.compute_clips_for_video(video_pts, num_frames, num_frames, orig_fps, new_fps)
assert len(clips) == 0
assert len(idxs) == 0
if __name__ == '__main__':
unittest.main()
if __name__ == "__main__":
pytest.main([__file__])
import unittest
from torchvision import set_video_backend
import test_datasets_video_utils
from torchvision import set_video_backend # noqa: 401
# Disabling the video backend switching temporarily
# set_video_backend('video_reader')
if __name__ == '__main__':
if __name__ == "__main__":
suite = unittest.TestLoader().loadTestsFromModule(test_datasets_video_utils)
unittest.TextTestRunner(verbosity=1).run(suite)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment