AttributeError: 'tuple' object has no attribute 'size'

Hi, I am working on omniglot images and I am struggling with this error. I believe the problem is with my dataset generation. Please help me figure it out. Here is the dataset code:

import os
from PIL import Image
import numpy as np
from torch.utils.data import Dataset
import torch
from torchvision import datasets, transforms
class Dataset(Dataset):
    def __init__(self,data_txt,transformm):
        location_file = open(data_txt, 'r')
        locations = location_file.read().split()
        self.filenames = locations
        self.labels = []
        self.images = []
        self.transform = transformm
        self.path = os.getcwd()
        for address in locations:
            #label creation
            label = address.split('/')[0]
            self.labels.append(label)


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

    def __getitem__(self, idx):
        image = Image.open(os.path.join(self.path,'images_background', self.filenames[idx]))
        image = self.transform(image)
        return image, self.labels[idx]

Here is the full traceback
Traceback (most recent call last):
File “-/Documents/Code/AI/AI_Learning/Omniglot2/omniglot.py”, line 79, in
loss = crtieria(outputs, labels)
File “-AppData\Local\Programs\Python\Python36\lib\site-packages\torch\nn\modules\module.py”, line 541, in call
result = self.forward(*input, **kwargs)
File “-\AppData\Local\Programs\Python\Python36\lib\site-packages\torch\nn\modules\loss.py”, line 916, in forward
ignore_index=self.ignore_index, reduction=self.reduction)
File “-\AppData\Local\Programs\Python\Python36\lib\site-packages\torch\nn\functional.py”, line 2009, in cross_entropy
return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)
File “-\AppData\Local\Programs\Python\Python36\lib\site-packages\torch\nn\functional.py”, line 1834, in nll_loss
if input.size(0) != target.size(0):
AttributeError: ‘tuple’ object has no attribute ‘size’

Could you please post the stack trace so that we can have a better look at your issue?
I cannot find anything obviously wrong in the current code snippet.

I edited the original post you should be able to see it. Do you need the Network code aswell?

Could you check the type of outputs and labels?
I guess labels is passed as a tuple instead of a tensor.
If so, you could return labels in your __getitem__ as:

torch.tensor(self.labels[idx])
1 Like

I still have a question, when I make my labels to a tensor like that it gives me error about labels being a string(I know that they are) and I am suppose to make them integers right? Labels must be integers?
Do you have any suggestions for it?

Yes, nn.CrossEntropyLoss expects the target to be a LongTensor containing the class indices in the range [0, nb_classes-1].
If your current labels are stored as string, you might want to use a dict and map these strings to the corresponding indices.

2 Likes

I have a similar issue to this @ptrblck @idontknow
I have a custom image dataset modeled closely after this official pytorch tutorial.

The dataset passes a PIL image to a transform function:

class Resize(object):
    """Resize the image in a sample to a given size.
    Args:
        output_size (int): Desired size in pixels. Yields output_size by output_size image
    """

    def __init__(self, output_size):
        assert isinstance(output_size, int)
        self.output_size = output_size

    def __call__(self, sample):
        image = sample

        resized_image = image.resize((self.output_size, self.output_size))

        return resized_image

At the point where PIL Image.resize() is called, I get this error:

File “test.py”, line 52, in
for samples in train_dataloader:
File “/Users/nick/opt/anaconda3/lib/python3.7/site-packages/torch/utils/data/dataloader.py”, line 345, in next
data = self._next_data()
File “/Users/nick/opt/anaconda3/lib/python3.7/site-packages/torch/utils/data/dataloader.py”, line 385, in _next_data
data = self._dataset_fetcher.fetch(index) # may raise StopIteration
File “/Users/nick/opt/anaconda3/lib/python3.7/site-packages/torch/utils/data/_utils/fetch.py”, line 44, in fetch
data = [self.dataset[idx] for idx in possibly_batched_index]
File “/Users/nick/opt/anaconda3/lib/python3.7/site-packages/torch/utils/data/_utils/fetch.py”, line 44, in
data = [self.dataset[idx] for idx in possibly_batched_index]
File “/Users/nick/opt/anaconda3/lib/python3.7/site-packages/torch/utils/data/dataset.py”, line 207, in getitem
return self.datasets[dataset_idx][sample_idx]
File “/Users/nick/Projects/Personal_Projects/CNN/datasets/LDataset.py”, line 52, in getitem
sample = self.transform(sample)
File “/Users/nick/opt/anaconda3/lib/python3.7/site-packages/torchvision/transforms/transforms.py”, line 70, in call
img = t(img)
File “/Users/nick/Projects/Personal_Projects/CNN/datasets/LTransforms.py”, line 24, in call
resized_image = image.resize((self.output_size, self.output_size))
AttributeError: ‘tuple’ object has no attribute ‘resize’

OK, this was the problem. Following the pytorch tutorial for making a custom dataset, my dataset would pass a sample as a dictionary: {'image': image, 'label': label}.
Then the custom transforms would unpack this and access the image as sample[‘image’].

Interestingly, before being put in the dictionary, type(image) would be <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=341x341 at 0x12D907210> as expected. However, when retrieving it from sample[‘image’] it becomes: (<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=341x341 at 0x12D907210>,).

So it got converted into a tuple for some reason. Accessing the 0th element of the tuple and passing it along to transform fixes the issue.

#KÜTÜPHANELER

import os
from pathlib import Path
from tqdm import tqdm
from easydict import EasyDict as edict

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.utils as vutils
from torchvision import transforms as trans

from data.ms1m import get_train_loader
from data.lfw import LFW

from backbone.arcfacenet import SEResNet_IR
from margin.ArcMarginProduct import ArcMarginProduct

from util.utils import save_checkpoint, test
#KONFİGÜRASYON

conf = edict()
conf.train_root = “dataset/MS1M/MS1M”
conf.lwf_test_root = “dataset/lfw_aligned_112/lfw_aligned_112”
conf.lwf_file_list =“dataset/lfw_pair.txt”

conf.mode =“se_ir” #model
conf.depth = 50 #derinlik
conf.margin_type = “ArcFace”
conf.feature_dim = 512
conf.scale_siz = 32.0
conf.batch_size =96 # bir seferde 96 resim yüklenecek
conf.lr = 0.01 #modele daha az resim verilirse lr’ düşürülmeli
conf.milestones = [8,10,12]
conf.total_epoch = 14 # model 14 defa resimlerin üstünde geçecek 14 iterasyon sayısı

conf.save_folder="./saved"
conf.save_dir = os.path.join(conf.save_folder ,conf.mode +’_’ + str(conf.depth))

conf.device = torch.device (“cuda:0” if torch.cuda.is_available() else “cpu”) # modelin nerede çalışacağını söylüyoruz

conf.num_workers = 4
conf.pin_memory = True

os.makedirs(conf.save_dir,exist_ok=True)

#VERİ YÜKLEME

transform = trans.Compose([
trans.ToTensor(),
trans.Normalize(mean=(0.5,0.5,0.5),std=(0.5,0.5,0.5))
])
trainloader = class_num = get_train_loader(conf)

print("number of id ",class_num)

print(trainloader.dataset)

################################################################
Traceback (most recent call last):
File “C:/Users/hsyna/Desktop/ArcFace/train.py”, line 59, in
print(trainloader.dataset[0])
AttributeError: ‘tuple’ object has no attribute ‘dataset’

I have an error too, how do I fix it?

Your get_train_loader method seems to return a tuple instead of a DataLoader instance, so you would either have to change the return statement or index the returned tuple.
PS: you can post code snippets by wrapping them into three backticks ```, which makes debugging easier. :wink:

from advertorch.attacks import LinfPGDAttack
import torch.nn as nn
import numpy as np

use_cuda = torch.cuda.is_available()
device = torch.device(“cuda” if use_cuda else “cpu”)

print(use_cuda)

model.to(device)
torch.cuda.empty_cache();

model = model.eval()

x = torch.from_numpy(train_image[0].asnumpy())

y = torch.from_numpy(class_ids[0])

x = torch.Tensor(batch[0][0].asnumpy())
y = torch.Tensor(batch[6][0].asnumpy())
print(type(x))

print("x = ",batch[0][0])

print(type(y))

print("y = ",batch[6][0])

adversary = LinfPGDAttack(
model, loss_fn=nn.BCEWithLogitsLoss(reduction=“none”), eps=0.3,
nb_iter=40, eps_iter=0.01, rand_init=False, clip_min=0.0, clip_max=1.0,
targeted=False)
#nn.CrossEntropyLoss(reduction=“sum”)

x = torch.unsqueeze(x,0)

adv_untargeted = adversary.perturb(x, y)

Output:

<class ‘torch.Tensor’>


AttributeError Traceback (most recent call last)
in
30 x = torch.unsqueeze(x,0)
31
—> 32 adv_untargeted = adversary.perturb(x, y)

~.conda\envs\final\lib\site-packages\advertorch\attacks\iterative_projected_gradient.py in perturb(self, x, y)
181 x + delta.data, min=self.clip_min, max=self.clip_max) - x
182
→ 183 rval = perturb_iterative(
184 x, y, self.predict, nb_iter=self.nb_iter,
185 eps=self.eps, eps_iter=self.eps_iter,

~.conda\envs\final\lib\site-packages\advertorch\attacks\iterative_projected_gradient.py in perturb_iterative(xvar, yvar, predict, nb_iter, eps, eps_iter, loss_fn, delta_init, minimize, ord, clip_min, clip_max, l1_sparsity)
64 for ii in range(nb_iter):
65 outputs = predict(xvar + delta)
—> 66 loss = loss_fn(outputs, yvar)
67 if minimize:
68 loss = -loss

~.conda\envs\final\lib\site-packages\torch\nn\modules\module.py in _call_impl(self, *input, **kwargs)
720 result = self._slow_forward(*input, **kwargs)
721 else:
→ 722 result = self.forward(*input, **kwargs)
723 for hook in itertools.chain(
724 _global_forward_hooks.values(),

~.conda\envs\final\lib\site-packages\torch\nn\modules\loss.py in forward(self, input, target)
626
627 def forward(self, input: Tensor, target: Tensor) → Tensor:
→ 628 return F.binary_cross_entropy_with_logits(input, target,
629 self.weight,
630 pos_weight=self.pos_weight,

~.conda\envs\final\lib\site-packages\torch\nn\functional.py in binary_cross_entropy_with_logits(input, target, weight, size_average, reduce, reduction, pos_weight)
2535 reduction_enum = _Reduction.get_enum(reduction)
2536
→ 2537 if not (target.size() == input.size()):
2538 raise ValueError(“Target size ({}) must be the same as input size ({})”.format(target.size(), input.size()))
2539

AttributeError: ‘tuple’ object has no attribute ‘size’

Please Help ! :frowning:

Based on the error message it seems you are also passing the model output or target as a tuple while a tensor is expected. Check the type() of both objects and make sure they are valid tensors before passing it to the criterion.

1 Like

This is the value of x and y and their types that i’m passing. x being the input image and y as labels. It seems they are both tensors as needed.

Thank You so much for a quick response sir :slight_smile:

In that case the model output is most likely creating the issue. :wink:

Thank You Sir ! I’ll check that :slight_smile:

The function is an inbuilt function in advertorch library of pytorch and the attack that I’m trying to do using that is PGD. Would you be able to explain a little what type of output should I expect from my model. Sorry, I am new to pytorch and tensorflows.

I’m not familiar with advertorch and don’t know which outputs are expected, so you could either check the implementation of the model in their repository as well as the documentation or check the output type manually.
I’m still unsure, if the error is raised by LinfPGDAttack or if your model just returns a tuple while tensors are expected, so you might also want to check the return type of it.

Ok Sir ! Thank You ! :slight_smile:

Hi, I’m using custom dataset inherited from torch.utils.data.Dataset and DataLoader.
Here is the code snippet and the output.

Note there is a change of type before and after variable assignment.

def __getitem__(self, idx):
        chunk = self.chunks[idx]

        print("type:", type(chunk["gesture"][:self.t_prev_20fps+self.window_len_20fps].T))
        gesture = chunk["gesture"][:self.t_prev_20fps+self.window_len_20fps].T,
        print("assigned type:", type(gesture))
        assert 0

Output:
type: <class 'numpy.ndarray'>
assigned type: <class 'tuple'>

The variable ‘gesture’ was unintendedly modified to be a tuple. Though using index 0 fixes the issue, could anyone tell me why this is happening?

Is this relevant to the return type of dict?

You are appending a comma after the gesture definition:

gesture = chunk["gesture"][:self.t_prev_20fps+self.window_len_20fps].T,

Remove it and the tuple shouldn’t be created.