Cannot combine [compose?] transforms

Hi,

Im trying to combine a couple transforms together using torchvision.transforms.Compose but I get the error:

TypeError: batch must contain tensors, numbers, dicts or lists; found <class ‘torchvision.transforms.Compose’>

At first I wrote the transform as simple functions but after reading here: https://pytorch.org/tutorials/beginner/data_loading_tutorial.html#transforms that they have to be callable objects for the Compose to work I rewrote them as callable classes but am still getting the error.

This is my line for Compose:

normalize = Normalize(mean, std)
random_flip = RandomFlip(random_state)
rotate_90 = RandomRotate90(num_rotate)
to_tensor = ToTensor(expand_dims=True, dtype=self.label_dtype)

img_transform = Compose([normalize(img),
                                 random_flip(img),
                                 rotate_90(img),
                                 to_tensor(img)
                                 ])

And here is Normalize

class Normalize:

    def __init__(self, mean, std, eps=1e-4):
        self.mean = mean
        self.std = std
        self.eps = eps

    def __call__(self, m):
        return (m - self.mean) / (self.std + self.eps)

Why is it not returning the images after transformations applied, rather than the Compose class?

Thanks

Could you try to pass just the classes without calling them, e.g. normalize instead of normalize(img).
Also, normalization should come after the ToTensor transformation.

To be honest I dont think I am using this the right way. Are you suggesting that I do the following:

img_transform = Compose([Normalize(mean, std),
                                 RandomFlip(random_state),
                                 RandomRotate90(num_rotate),
                                 ToTensor(expand_dims=True, dtype=self.label_dtype)
                                 ])

Then at what stage would I pass the actual image or sample on which the transformations are to be applied?

Also, normalization should come after the ToTensor transformation.

Noted. Can you please explain why it makes a difference to normalize after ToTensor.

Thanks

Usually you would apply the transformations on each sample in the __getitem__ method of your Dataset. Have a look at the data loading tutorial for an example.

If you wrap your Dataset in a DataLoader with multiple workers, the loading and processing will be applied using multiprocessing in the background while your GPU is busy with the training.

While a lot of torchvision.transforms are applied on PIL.Images, Normalize is applied on a tensor which is why I suggested to call it after ToTensor.
Note that ToTensor will return a tensor image with values in the range [0, 1]. Your mean and std in Normalize should therefore also be relative to this range.

1 Like

Hi @ptrblck ,

Is it possible to insert a new transform to an already composed transform.
For example: if I have train_transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize(mean=mean, std=std)])
And later I want to add RandomFlip to this train_transform.

Is it possible to insert this in train_transform?

Thanks,

transforms.Compose holds an internal list, which is passed as the initial argument to it and iterates all transformations in this list.
You could thus manipulate this list object directly via e.g. insert:

train_transform.transforms.insert(1,transforms.ToPILImage())
train_transform.transforms.insert(2,transforms.ToTensor())
2 Likes

Thanks for the quick response.