machine-learningdeep-learningpytorchkaggle

AttributeError : 'tuple' has no attribute 'to'


I am writing this Image Classifier and I have defined the loaders but getting this mistake and I have no clue about it.

I have defined the train loader, for a better explanation I tried this

for ina,lab in train_loader:
    print(type(ina))
    print(type(lab)) 

and I got

<class 'torch.Tensor'>
<class 'tuple'>

Now, For training of the model, I did

def train_model(model,optimizer,n_epochs,criterion):
    start_time = time.time()
    for epoch in range(1,n_epochs-1):
        epoch_time = time.time()
        epoch_loss = 0
        correct = 0
        total = 0
        print( "Epoch {}/{}".format(epoch,n_epochs))
        
        model.train()
        
        for inputs,labels in train_loader:
            inputs = inputs.to(device)
            labels  = labels.to(device)
            optimizer.zero_grad()
            output = model(inputs)
            loss = criterion(output,labels)
            loss.backward()
            optimizer.step()
            epoch_loss +=loss.item()
            _,pred =torch.max(output,1)
            correct += (pred.cpu()==label.cpu()).sum().item()
            total +=labels.shape[0]
            
        acc = correct/total
      

and I got the error:

Epoch 1/15
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-36-fea243b3636a> in <module>
----> 1 train_model(model=arch, optimizer=optim, n_epochs=15, criterion=criterion)

<ipython-input-34-b53149a4bac0> in train_model(model, optimizer, n_epochs, criterion)
     12         for inputs,labels in train_loader:
     13             inputs = inputs.to(device)
---> 14             labels  = labels.to(device)
     15             optimizer.zero_grad()
     16             output = model(inputs)

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

If you want anything more, please tell me! Thanks

Edit: The label looks like this. This was an Image Classification between Bee and Wasp. It also contains insects and non insects

('wasp', 'wasp', 'insect', 'insect', 'wasp', 'insect', 'insect', 'wasp', 'wasp', 'bee', 'insect', 'insect', 'other', 'bee', 'other', 'wasp', 'other', 'wasp', 'bee', 'bee', 'wasp', 'wasp', 'wasp', 'wasp', 'bee', 'wasp', 'wasp', 'other', 'bee', 'wasp', 'bee', 'bee') ('wasp', 'wasp', 'insect', 'bee', 'other', 'wasp', 'insect', 'wasp', 'insect', 'insect', 'insect', 'wasp', 'wasp', 'insect', 'wasp', 'wasp', 'wasp', 'bee', 'wasp', 'wasp', 'insect', 'insect', 'wasp', 'wasp', 'bee', 'wasp', 'insect', 'bee', 'bee', 'insect', 'insect', 'other')


Solution

  • It literally means that the the tuple class in Python doesn't have a method called to. Since you're trying to put your labels onto your device, just do labels = torch.tensor(labels).to(device).

    If you don't want to do this, you can change the way the DataLoader works by making it return your labels as a PyTorch tensor rather than a tuple.

    Edit

    Since the labels seem to be strings, I would convert them to one-hot encoded vectors first:

    >>> import torch
    >>> labels_unique = set(labels)
    >>> keys = {key: value for key, value in zip(labels_unique, range(len(labels_unique)))}
    >>> labels_onehot = torch.zeros(size=(len(labels), len(keys)))
    >>> for idx, label in enumerate(labels_onehot):
    ...     labels_onehot[idx][keys[label]] = 1
    ...
    >>> labels_onehot = labels.to(device)
    

    I'm shooting a bit in the dark here because I don't know the details exactly, but yeah strings won't work with tensors.