Vision: ..functional.rotate() arguments broke with 0.5 update

Created on 16 Jan 2020  路  21Comments  路  Source: pytorch/vision

Hey, I just did a fresh install of Pytorch and torchvision on a clean ubuntu 18.04 os.

When I run my code, I get the following Error message
TypeError: function takes exactly 1 argument (3 given)
even though i did not change my code.
torchvision.__version__= 0.5.0
pytorch.__version__=1.4.0

Running the same code on an older machine (0.4.2 and 1.3.1 respectively) works without an issue, I guess it has something to do with the new addition of the fill-colour of the 0.5 update.

How to reproduce:

Img=torch.rand(1,32,32)
Img_PIL=torchvision.transforms.functional.to_pil_image(Img)
Img_PIL_Rot=torchvision.transforms.functional.rotate(Img_PIL, 5)
Img=torchvision.transforms.functional.to_tensor(Img_PIL_Rot)*255

Expeceted result:
rotated Image

Result:

File "/home/.../anaconda3/envs/Python3.7/lib/python3.7/site-packages/PIL/Image.py", line 2544, in new
    return im._new(core.fill(mode, size, color))
TypeError: function takes exactly 1 argument (3 given)
bug transforms

Most helpful comment

@chinglamchoi

This is a bug in torchvision==0.5.0. As long as you have pillow>=5.2.0, the actual version is irrelevant.

If you are bound to torchvision==0.5.0 you can add fill=[filler] * num_bands to your rotation parameters. Here filler = 0.0 if img.mode.startswith("F") else 0 and num_bands = len(img.getbands()) where img is an PIL.Image.Image.

If you can use an older version, I suggest you downgrade to torchvision==0.4.2, since this is the last version that does not have this bug.

Alternatively, if you are not bound to a stable version, you can use the nightly version of torchvision, since this bug is already fixed on the master branch (#1760, #1828).

All 21 comments

Thanks for the report. Indeed

https://github.com/pytorch/vision/blob/add2ecc75121d324a037435700b5236821831b75/torchvision/transforms/functional.py#L726-L729

causes the error. I will investigate this tomorrow and send a fix.


For your next bug report, please post the full stack trace. That makes it easier for us to investigate where the error might originate from.

Hi,

This error happens because you have an old version of Pillow. If you update pillow, this should work.

@pmeier we should add a compatibility fix for older versions of PIL, and add a test (which was missing before)

FYI, fillcolor is present in Pillow 6, but not in Pillow 5

@fmassa

I don't think this is the issue here. The problem is that we always convert a scalar into a tuple of 3. This works fine for RGB images but fails for greyscale images like in the example given. Actually this will fail for every image with a number of bands / channels different from 3.

From the official documentation:

A new named parameter, fillcolor, has been added to Image.transform. This color specifies the background color to use in the area outside the transformed area in the output image. This parameter takes the same color specifications as used in Image.new.

The documentation of Image.new states:

color - [...] If given, this should be a single integer or floating point value for single-band modes, and a tuple for multi-band modes (one value per band).

Apart from that I agree that we should add a compatibility fix for pillow<5.0.0 and a test for this.


@Jarei002

For a quick fix add fill=(0,) to your call of rotate:

Img=torch.rand(1,32,32)
Img_PIL=torchvision.transforms.functional.to_pil_image(Img)
Img_PIL_Rot=torchvision.transforms.functional.rotate(Img_PIL, 5, fill=(0,))
Img=torchvision.transforms.functional.to_tensor(Img_PIL_Rot)*255

Thanks for the report. Indeed

https://github.com/pytorch/vision/blob/add2ecc75121d324a037435700b5236821831b75/torchvision/transforms/functional.py#L726-L729

causes the error. I will investigate this tomorrow and send a fix.

For your next bug report, please post the full stack trace. That makes it easier for us to investigate where the error might originate from.

Okay, here is the complete stack trace:

Traceback (most recent call last):

  File "<ipython-input-12-db9c93cfce73>", line 4, in <module>
    PermutedImage=torchvision.transforms.functional.rotate(img=PermutedImage,angle=3,fill=(0),)

  File "/home/at-lab/anaconda3/envs/Python3.7/lib/python3.7/site-packages/torchvision/transforms/functional.py", line 729, in rotate
    return img.rotate(angle, resample, expand, center, fillcolor=fill)

  File "/home/at-lab/anaconda3/envs/Python3.7/lib/python3.7/site-packages/PIL/Image.py", line 2023, in rotate
    return self.transform((w, h), AFFINE, matrix, resample, fillcolor=fillcolor)

  File "/home/at-lab/anaconda3/envs/Python3.7/lib/python3.7/site-packages/PIL/Image.py", line 2337, in transform
    im = new(self.mode, size, fillcolor)

  File "/home/at-lab/anaconda3/envs/Python3.7/lib/python3.7/site-packages/PIL/Image.py", line 2544, in new
    return im._new(core.fill(mode, size, color))

TypeError: function takes exactly 1 argument (3 given)

Hi,

This error happens because you have an old version of Pillow. If you update pillow, this should work.

@pmeier we should add a compatibility fix for older versions of PIL, and add a test (which was missing before)

The current PIL version is 7.0.0.

For a quick fix add fill=(0,) to your call of rotate:

As seen from the stack trace, fill=(0), did not fix the issue.

Thanks for the quick responses so far.

You missed a comma there. It should be fill=(0,) and not fill=(0). With that comma you create tuple with a single element. This circumvents the buggy code. Without it the parentheses are just used for priority and simply removed (0 == (0))

You missed a comma there. It should be fill=(0,) and not fill=(0). With that comma you create tuple with a single element. This circumvents the buggy code. Without it the parentheses are just used for priority and simply removed (0 == (0))

Astonishing that things work when they are done right. Somehow the comma moved outside the parantheses, works now. Thanks again.

As a general question, should I close this issue now, or is this done by someone else at later stages once the actual fix is implemented?

You don't need to close it manually. If the PR I send gets merged, this issue will be closed automatically. Until then its good to be open so others know that this is still worked on.

I still get the error with transforms.RandomRotation(10, fill=(0,)),:

Traceback (most recent call last):
  File "train-tagan.py", line 423, in <module>
    train(args)
  File "train-tagan.py", line 152, in train
    ranker.update_emb()
  File "/home/itautkute/fashion-iq/scripts/utils.py", line 253, in update_emb
    images, asins = self.get_items(batch_ids)
  File "/home/itautkute/fashion-iq/scripts/utils.py", line 111, in get_items
    i) for i in indexes)
  File "/opt/conda/lib/python3.7/site-packages/joblib/parallel.py", line 1004, in __call__
    if self.dispatch_one_batch(iterator):
  File "/opt/conda/lib/python3.7/site-packages/joblib/parallel.py", line 835, in dispatch_one_batch
    self._dispatch(tasks)
  File "/opt/conda/lib/python3.7/site-packages/joblib/parallel.py", line 754, in _dispatch
    job = self._backend.apply_async(batch, callback=cb)
  File "/opt/conda/lib/python3.7/site-packages/joblib/_parallel_backends.py", line 209, in apply_async
    result = ImmediateResult(func)
  File "/opt/conda/lib/python3.7/site-packages/joblib/_parallel_backends.py", line 590, in __init__
    self.results = batch()
  File "/opt/conda/lib/python3.7/site-packages/joblib/parallel.py", line 256, in __call__
    for func, args, kwargs in self.items]
  File "/opt/conda/lib/python3.7/site-packages/joblib/parallel.py", line 256, in <listcomp>
    for func, args, kwargs in self.items]
  File "/home/itautkute/fashion-iq/scripts/utils.py", line 105, in get_item
    image = self.transform(image)
  File "/opt/conda/lib/python3.7/site-packages/torchvision/transforms/transforms.py", line 70, in __call__
    img = t(img)
  File "/opt/conda/lib/python3.7/site-packages/torchvision/transforms/transforms.py", line 1003, in __call__
    return F.rotate(img, angle, self.resample, self.expand, self.center, self.fill)
  File "/opt/conda/lib/python3.7/site-packages/torchvision/transforms/functional.py", line 729, in rotate
    return img.rotate(angle, resample, expand, center, fillcolor=fill)
  File "/opt/conda/lib/python3.7/site-packages/PIL/Image.py", line 2023, in rotate
    return self.transform((w, h), AFFINE, matrix, resample, fillcolor=fillcolor)
  File "/opt/conda/lib/python3.7/site-packages/PIL/Image.py", line 2337, in transform
    im = new(self.mode, size, fillcolor)
  File "/opt/conda/lib/python3.7/site-packages/PIL/Image.py", line 2544, in new
    return im._new(core.fill(mode, size, color))
TypeError: function takes at least 3 arguments (1 given)

torchvision.__version__ == 0.5.0
PIL.__version__ == 7.0.0

@IvonaTau Could you please post your complete code? A quick test by me run without any error

import numpy as np
from PIL import Image
from torchvision import transforms

img = np.zeros((100, 100), dtype=np.uint8)
img = Image.fromarray(img, mode="L")

transform = transforms.RandomRotation(10, fill=(0,))
transform(img)

I had the same problem with torchvision v0.5.0 & PIL v7.0.0. Downgrading to torchvision 0.4.0 & PIL v6.2.0 solved the problem for me.

@chinglamchoi

This is a bug in torchvision==0.5.0. As long as you have pillow>=5.2.0, the actual version is irrelevant.

If you are bound to torchvision==0.5.0 you can add fill=[filler] * num_bands to your rotation parameters. Here filler = 0.0 if img.mode.startswith("F") else 0 and num_bands = len(img.getbands()) where img is an PIL.Image.Image.

If you can use an older version, I suggest you downgrade to torchvision==0.4.2, since this is the last version that does not have this bug.

Alternatively, if you are not bound to a stable version, you can use the nightly version of torchvision, since this bug is already fixed on the master branch (#1760, #1828).

I get this issue as well with torchvision 0.5.0 and Pillow 7.1.1 as well as 7.0.0. Complete trace below:

```
File "/home/gio/Documents/KNet/src/utils/data_loading.py", line 579, in mnist_class_loader
traindata[i] = train[i][0].view((28*28))
File "/home/gio/Documents/KNet/venv2/lib/python3.7/site-packages/torchvision/datasets/mnist.py", line 97, in __getitem__
img = self.transform(img)
File "/home/gio/Documents/KNet/venv2/lib/python3.7/site-packages/torchvision/transforms/transforms.py", line 70, in __call__
img = t(img)
File "/home/gio/Documents/KNet/venv2/lib/python3.7/site-packages/torchvision/transforms/transforms.py", line 1003, in __call__
return F.rotate(img, angle, self.resample, self.expand, self.center, self.fill)
File "/home/gio/Documents/KNet/venv2/lib/python3.7/site-packages/torchvision/transforms/functional.py", line 729, in rotate
return img.rotate(angle, resample, expand, center, fillcolor=fill)
File "/home/gio/Documents/KNet/venv2/lib/python3.7/site-packages/PIL/Image.py", line 2023, in rotate
return self.transform((w, h), AFFINE, matrix, resample, fillcolor=fillcolor)
File "/home/gio/Documents/KNet/venv2/lib/python3.7/site-packages/PIL/Image.py", line 2337, in transform
im = new(self.mode, size, fillcolor)
File "/home/gio/Documents/KNet/venv2/lib/python3.7/site-packages/PIL/Image.py", line 2544, in new
return im._new(core.fill(mode, size, color))
TypeError: function takes exactly 1 argument (3 given)

```

@Ge0rges As stated above:

This is a bug in torchvision==0.5.0. As long as you have pillow>=5.2.0, the actual version is irrelevant.

I've outlined possible workarounds in that comment. If they do not work for you, please open a new bug report issue.

I was surprised a fix has been pushed for so long but no updates to torch vision stable have been put out yet.

I think a new release is just around the corner, but I have no precise information about that.

Next release is ready and will be made available early next week

class randomRotate(nn.Module):
    def __init__(self, degrees=[0, 90, 180, 270]):
        super(randomRotate, self).__init__()
        self.degrees = degrees

    def __call__(self, x):
        degree = random.choice(self.degrees)
        return transforms.functional.rotate(x, degree)

__init__:
self.data_cube = segyio.cube(self.data_path)
self.data_cube = torch.from_numpy(self.data_cube)
self.augment = transforms.Compose([
            transforms.ToPILImage(),
            transforms.RandomHorizontalFlip(),
            transforms.RandomVerticalFlip(),
            randomRotate(),
            transforms.ToTensor()
        ])

__getitem__:
image = self.data_cube[i]
image = self.augment(image)

is totally ok.

but I change the data_cube axis:

__init__:
self.data_cube = np.transpose(segyio.cube(self.data_path), (0,2,1))

it runs error,

  File "/home/cym/.conda/envs/action/lib/python3.6/site-packages/PIL/Image.py", line 2072, in rotate
    return self.transform((w, h), AFFINE, matrix, resample, fillcolor=fillcolor)
  File "/home/cym/.conda/envs/action/lib/python3.6/site-packages/PIL/Image.py", line 2406, in transform
    im = new(self.mode, size, fillcolor)
  File "/home/cym/.conda/envs/action/lib/python3.6/site-packages/PIL/Image.py", line 2621, in new
    return im._new(core.fill(mode, size, color))
TypeError: function takes exactly 1 argument (3 given)

add contiguous also doesn't work.

it really strange.

@Interesting6 I believe your image doesn't have the right number of channels, but without further information it's hard to say more

@Interesting6 I believe your image doesn't have the right number of channels, but without further information it's hard to say more

data_cube is a numpy ndarray with dimensions [c=4, h=906, w=463] read from segyio.

@Interesting6 could you please open a new issue with the torchvision version that you are using, and a self-contained example reproducing the issue?

Was this page helpful?
0 / 5 - 0 ratings