"torchvision/transforms/v2/functional/_meta.py" did not exist on "50b77fa7871504cdcb7a76c6f91e4ba39ac05bc9"
svhn.py 4.68 KB
Newer Older
1
2
import os
import os.path
3
from typing import Any, Callable, Optional, Tuple
4
5
6
7

import numpy as np
from PIL import Image

8
from .utils import download_url, check_integrity, verify_str_arg
9
from .vision import VisionDataset
10

soumith's avatar
soumith committed
11

12
class SVHN(VisionDataset):
13
    """`SVHN <http://ufldl.stanford.edu/housenumbers/>`_ Dataset.
14
15
16
    Note: The SVHN dataset assigns the label `10` to the digit `0`. However, in this Dataset,
    we assign the label `0` to the digit `0` to be compatible with PyTorch loss functions which
    expect the class labels to be in the range `[0, C-1]`
17

18
19
20
21
    .. warning::

        This class needs `scipy <https://docs.scipy.org/doc/>`_ to load data from `.mat` format.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
    Args:
        root (string): Root directory of dataset where directory
            ``SVHN`` exists.
        split (string): One of {'train', 'test', 'extra'}.
            Accordingly dataset is selected. 'extra' is Extra training set.
        transform (callable, optional): A function/transform that  takes in an PIL image
            and returns a transformed version. E.g, ``transforms.RandomCrop``
        target_transform (callable, optional): A function/transform that takes in the
            target and transforms it.
        download (bool, optional): If true, downloads the dataset from the internet and
            puts it in root directory. If dataset is already downloaded, it is not
            downloaded again.

    """
36
37

    split_list = {
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
        "train": [
            "http://ufldl.stanford.edu/housenumbers/train_32x32.mat",
            "train_32x32.mat",
            "e26dedcc434d2e4c54c9b2d4a06d8373",
        ],
        "test": [
            "http://ufldl.stanford.edu/housenumbers/test_32x32.mat",
            "test_32x32.mat",
            "eb5a983be6a315427106f1b164d9cef3",
        ],
        "extra": [
            "http://ufldl.stanford.edu/housenumbers/extra_32x32.mat",
            "extra_32x32.mat",
            "a93ce644f1a588dc4d68dda5feec44a7",
        ],
    }
54

55
    def __init__(
56
57
58
59
60
61
        self,
        root: str,
        split: str = "train",
        transform: Optional[Callable] = None,
        target_transform: Optional[Callable] = None,
        download: bool = False,
62
    ) -> None:
63
        super().__init__(root, transform=transform, target_transform=target_transform)
64
        self.split = verify_str_arg(split, "split", tuple(self.split_list.keys()))
65
66
67
68
69
70
71
72
        self.url = self.split_list[split][0]
        self.filename = self.split_list[split][1]
        self.file_md5 = self.split_list[split][2]

        if download:
            self.download()

        if not self._check_integrity():
73
            raise RuntimeError("Dataset not found or corrupted. You can use download=True to download it")
74
75
76
77
78
79

        # import here rather than at top of file because this is
        # an optional dependency for torchvision
        import scipy.io as sio

        # reading(loading) mat file as array
moskomule's avatar
moskomule committed
80
        loaded_mat = sio.loadmat(os.path.join(self.root, self.filename))
81

82
        self.data = loaded_mat["X"]
83
        # loading from the .mat file gives an np array of type np.uint8
vabh's avatar
vabh committed
84
        # converting to np.int64, so that we have a LongTensor after
85
86
        # the conversion from the numpy array
        # the squeeze is needed to obtain a 1D tensor
87
        self.labels = loaded_mat["y"].astype(np.int64).squeeze()
vabh's avatar
vabh committed
88

89
        # the svhn dataset assigns the class label "10" to the digit 0
vabh's avatar
vabh committed
90
        # this makes it inconsistent with several loss functions
91
        # which expect the class labels to be in the range [0, C-1]
vabh's avatar
vabh committed
92
        np.place(self.labels, self.labels == 10, 0)
93
94
        self.data = np.transpose(self.data, (3, 2, 0, 1))

95
    def __getitem__(self, index: int) -> Tuple[Any, Any]:
96
97
98
99
100
101
102
        """
        Args:
            index (int): Index

        Returns:
            tuple: (image, target) where target is index of the target class.
        """
103
        img, target = self.data[index], int(self.labels[index])
104
105
106
107
108
109
110
111
112
113
114
115
116

        # doing this so that it is consistent with all other datasets
        # to return a PIL Image
        img = Image.fromarray(np.transpose(img, (1, 2, 0)))

        if self.transform is not None:
            img = self.transform(img)

        if self.target_transform is not None:
            target = self.target_transform(target)

        return img, target

117
    def __len__(self) -> int:
118
119
        return len(self.data)

120
    def _check_integrity(self) -> bool:
121
122
123
        root = self.root
        md5 = self.split_list[self.split][2]
        fpath = os.path.join(root, self.filename)
soumith's avatar
soumith committed
124
        return check_integrity(fpath, md5)
125

126
    def download(self) -> None:
soumith's avatar
soumith committed
127
128
        md5 = self.split_list[self.split][2]
        download_url(self.url, self.root, self.filename, md5)
129

130
    def extra_repr(self) -> str:
131
        return "Split: {split}".format(**self.__dict__)