Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeError: module 'torchvision.transforms.functional' has no attribute 'get_image_size' #4328

Closed
praveern opened this issue Aug 27, 2021 · 8 comments

Comments

@praveern
Copy link

praveern commented Aug 27, 2021

🐛 Bug


AttributeError Traceback (most recent call last)
in ()
40
41 for epoch in range(num_epochs):
---> 42 train_one_epoch(model, optimizer, data_loader, device, epoch, print_freq=10)
43 lr_scheduler.step()
44 # evaluate on the test dataset

5 frames
/usr/local/lib/python3.7/dist-packages/torch/_utils.py in reraise(self)
423 # have message field
424 raise self.exc_type(message=msg)
--> 425 raise self.exc_type(msg)
426
427

AttributeError: Caught AttributeError in DataLoader worker process 0.
Original Traceback (most recent call last):
File "/usr/local/lib/python3.7/dist-packages/torch/utils/data/_utils/worker.py", line 287, in _worker_loop
data = fetcher.fetch(index)
File "/usr/local/lib/python3.7/dist-packages/torch/utils/data/_utils/fetch.py", line 44, in fetch
data = [self.dataset[idx] for idx in possibly_batched_index]
File "/usr/local/lib/python3.7/dist-packages/torch/utils/data/_utils/fetch.py", line 44, in
data = [self.dataset[idx] for idx in possibly_batched_index]
File "/usr/local/lib/python3.7/dist-packages/torch/utils/data/dataset.py", line 311, in getitem
return self.dataset[self.indices[idx]]
File "/usr/local/lib/python3.7/dist-packages/torch/utils/data/dataset.py", line 311, in getitem
return self.dataset[self.indices[idx]]
File "", line 83, in getitem
image, target = self._transforms(image, target)
File "/content/transforms.py", line 26, in call
image, target = t(image, target)
File "/usr/local/lib/python3.7/dist-packages/torch/nn/modules/module.py", line 1051, in _call_impl
return forward_call(*input, **kwargs)
File "/content/transforms.py", line 36, in forward
width, _ = F.get_image_size(image)
AttributeError: module 'torchvision.transforms.functional' has no attribute 'get_image_size'

To Reproduce

Steps to reproduce the behavior:

  1. Follow tutorial as per https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html
  2. Error happening from the file - references/detection/transforms.py, line 36 (using an alias/local variable for
    torchvision.transforms.functional is not allowing access to the public method in the same file)

Expected behavior

The public method "get_image_size" should be accessed normally (I had to remove the alias "F" and explicitly call the method).

Environment

Google Colab (libraries are up to date)

cc @vfdev-5 @datumbox

@praveern
Copy link
Author

praveern commented Aug 27, 2021

Actually even the workaround is not working. Something seems broken.

@datumbox
Copy link
Contributor

@praveern The method was added just yesterday so it might not be available on nightly yet. I would recommend installing it from source and trying again.

If you continue facing problems, please provide the minimum code that would allow us to reproduce the problem along with information about the version you are using etc.

From what I see the following works find on latest main branch:

>>> import torch
>>> import torchvision.transforms.functional as F
>>> F.get_image_size(torch.zeros((3, 300, 400)))
[400, 300]

@praveern
Copy link
Author

Hello @datumbox I'm using the latest stable build v0.10 (pytorch version 1.9.0+cu10.2) (as per the installation section in getting started).

Regarding code, I am literally using the Pytorch tutorial as it is, with only tweaks being Google Drive paths to data and model checkpoint storage locations.

@datumbox
Copy link
Contributor

The latest stable version version of TorchVsion does not have the get_image_size() public. The change was made yesterday. If you want to access it along with other latest features, I advise you to either try the nightly or install from source.

If you continue having issues using the latest development version, send me a standalone minimal snippet that reproduces the issue so that we can investigate.

@praveern
Copy link
Author

praveern commented Aug 27, 2021

Okay, so I switched my environment to use the LTS version (pip install torch==1.8.2+cu102 torchvision==0.9.2+cu102 torchaudio===0.8.2 -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html) and the error still persists.

As for standalone snippet, I think these specific cells of code should help:

Source - "https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html#writing-a-custom-dataset-for-pennfudan"

import os
import numpy as np
import torch
from PIL import Image


class PennFudanDataset(torch.utils.data.Dataset):
    def __init__(self, root, transforms):
        self.root = root
        self.transforms = transforms
        # load all image files, sorting them to
        # ensure that they are aligned
        self.imgs = list(sorted(os.listdir(os.path.join(root, "PNGImages"))))
        self.masks = list(sorted(os.listdir(os.path.join(root, "PedMasks"))))

    def __getitem__(self, idx):
        # load images and masks
        img_path = os.path.join(self.root, "PNGImages", self.imgs[idx])
        mask_path = os.path.join(self.root, "PedMasks", self.masks[idx])
        img = Image.open(img_path).convert("RGB")
        # note that we haven't converted the mask to RGB,
        # because each color corresponds to a different instance
        # with 0 being background
        mask = Image.open(mask_path)
        # convert the PIL Image into a numpy array
        mask = np.array(mask)
        # instances are encoded as different colors
        obj_ids = np.unique(mask)
        # first id is the background, so remove it
        obj_ids = obj_ids[1:]

        # split the color-encoded mask into a set
        # of binary masks
        masks = mask == obj_ids[:, None, None]

        # get bounding box coordinates for each mask
        num_objs = len(obj_ids)
        boxes = []
        for i in range(num_objs):
            pos = np.where(masks[i])
            xmin = np.min(pos[1])
            xmax = np.max(pos[1])
            ymin = np.min(pos[0])
            ymax = np.max(pos[0])
            boxes.append([xmin, ymin, xmax, ymax])

        # convert everything into a torch.Tensor
        boxes = torch.as_tensor(boxes, dtype=torch.float32)
        # there is only one class
        labels = torch.ones((num_objs,), dtype=torch.int64)
        masks = torch.as_tensor(masks, dtype=torch.uint8)

        image_id = torch.tensor([idx])
        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])
        # suppose all instances are not crowd
        iscrowd = torch.zeros((num_objs,), dtype=torch.int64)

        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["masks"] = masks
        target["image_id"] = image_id
        target["area"] = area
        target["iscrowd"] = iscrowd

        if self.transforms is not None:
            img, target = self.transforms(img, target)

        return img, target

    def __len__(self):
        return len(self.imgs)

Source - "vision/references/detection/transforms.py"

from torch import nn, Tensor
from torchvision.transforms import functional as F
from torchvision.transforms import transforms as T
from typing import List, Tuple, Dict, Optional


class RandomHorizontalFlip(T.RandomHorizontalFlip):
    def forward(self, image: Tensor,
                target: Optional[Dict[str, Tensor]] = None) -> Tuple[Tensor, Optional[Dict[str, Tensor]]]:
        if torch.rand(1) < self.p:
            image = F.hflip(image)
            if target is not None:
                width, _ = F.get_image_size(image)  ## This line is throwing an error
                target["boxes"][:, [0, 2]] = width - target["boxes"][:, [2, 0]]
                if "masks" in target:
                    target["masks"] = target["masks"].flip(-1)
                if "keypoints" in target:
                    keypoints = target["keypoints"]
                    keypoints = _flip_coco_person_keypoints(keypoints, width)
                    target["keypoints"] = keypoints
        return image, target


# Importing vision/references/detection/transforms.py (the file is located at same level as Jupyter notebook)
import transforms as Tf  

def get_transform(train):
    transforms = []
    transforms.append(Tf.ToTensor())
    if train:
        transforms.append(RandomHorizontalFlip(0.5))
    return Tf.Compose(transforms)


# Import the custom dataset defined previously,
dataset = PennFudanDataset(os.path.join('PennFudanPed'), get_transform(train=True))
print(dataset.__getitem__(45))

--------------------------------------------------------------------------
Error:

AttributeError                            Traceback (most recent call last)
<ipython-input-20-87a7b71fa365> in <module>()
      4 dataset_test = torch.utils.data.Subset(dataset_test, indices[-50:])
      5 
----> 6 print(dataset.__getitem__(45))

4 frames
/usr/local/lib/python3.7/dist-packages/torch/utils/data/dataset.py in __getitem__(self, idx)
    328 
    329     def __getitem__(self, idx):
--> 330         return self.dataset[self.indices[idx]]
    331 
    332     def __len__(self):

<ipython-input-3-73612deaccc4> in __getitem__(self, idx)
     62 
     63         if self.transforms is not None:
---> 64             img, target = self.transforms(img, target)
     65 
     66         return img, target

/content/transforms.py in __call__(self, image, target)
     24     def __call__(self, image, target):
     25         for t in self.transforms:
---> 26             image, target = t(image, target)
     27         return image, target
     28 

/usr/local/lib/python3.7/dist-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
    887             result = self._slow_forward(*input, **kwargs)
    888         else:
--> 889             result = self.forward(*input, **kwargs)
    890         for hook in itertools.chain(
    891                 _global_forward_hooks.values(),

<ipython-input-16-75a1255e5fcd> in forward(self, image, target)
     11             image = F.hflip(image)
     12             if target is not None:
---> 13                 width, _ = F.get_image_size(image)
     14                 target["boxes"][:, [0, 2]] = width - target["boxes"][:, [2, 0]]
     15                 if "masks" in target:

AttributeError: module 'torchvision.transforms.functional' has no attribute 'get_image_size'

@datumbox
Copy link
Contributor

The reason why you get issues is because you are trying to use code from the latest development branch with an old stable version of TorchVision. When you mix code from different versions you can get issues. As I explained earlier, the PR #4321 which renamed the private method F._get_image_size() to F.get_image_size() was merged yesterday and thus this change is only available to the latest nightly version or if you install TorchVision from source.

You are currently trying to call a method that does not exist on the TorchVision version you are using. A quick workaround is to replace get_image_size with _get_image_size in your code but you are still at risk because you mix code from different versions. If you want to stick to the latest stable version (0.10.0) you should be using the reference scripts from that version.

I believe this answers your question and thus I'll close the ticket. If you have further concerns feel free to reopen it.

@praveern
Copy link
Author

Ouch. I just realized I really was doing a very silly mistake. 😅

@datumbox
Copy link
Contributor

@praveern hey don't worry about it! It's end of week, mistakes happen. 😀

ds2268 added a commit to ds2268/VICRegL that referenced this issue Nov 26, 2022
Private function _get_image_size was changed to public in torchvision v0.11.
The use of torchvision v0.11 and above will result in the following error:
pytorch/vision#4328
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants