ValueError: Target size (torch.Size([1000])) must be the same as input size (torch.Size([1000, 1]))

Viewed 5117

I am trying to train my first neural net in pyTorch (I'm not a programmer, just a confused chemist).

The net itself is supposed to take 1064 element vectors and rate them with a float number.

So far I have encountered a variety of errors, ranging from 'float instead of long' to 'Target 1 is out of bounds'. Thus I have redefined the dtypes, corrected the dimensions of the input vector, changed the loss function and now I am stuck in the situation when correcting the current error sets me back to the previous ones.

Which is:

ValueError: Target size (torch.Size([1000])) must be the same as input size (torch.Size([1000, 1]))

at the 'loss=loss_calc(outputs, target)' line.

I tried unsqueezing the label during the DataSet class definition, but this solution sets me back. When I tried to label = label.view(1,1), the resulting error changed to

Target size (torch.Size([1000, 1, 1])) must be the same as input size (torch.Size([1000, 1]))

Could anyone please help me figure this out?

import pandas as pd
import numpy as np
import rdkit
from rdkit import Chem
from rdkit.Chem import AllChem
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader

class dataset(Dataset):
    def __init__(self, path, transform=None):
        self.data = pd.read_excel(path)
        self.transform = transform
        
    def __len__(self):
        return len(self.data)
    
    def __getitem__(self, index):
        smiles=self.data.at[index, 'smiles']
        mol=Chem.MolFromSmiles(smiles)
        morgan = torch.tensor(list(AllChem.GetMorganFingerprintAsBitVect(mol, 1, nBits=1064)), dtype=torch.float)
        
        label=torch.tensor(self.data.at[index, 'score'], dtype=torch.long)
        
        if self.transform is not None:
            morgan=self.transform(morgan)
        
        return morgan, label

class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(1064, 1064)
        self.fc2 = nn.Linear(1064, 1)
        self.act = nn.Tanh()
    
    def forward(self, x):
        x = self.act(self.fc1(x))
        x = self.act(self.fc2(x))
        x = self.fc2(x)
        return x

trainSet=dataset(r'C:\Users\BajMic\Peptides\trainingSet.xlsx')
testSet=dataset(r'C:\Users\BajMic\Peptides\testSet.xlsx')

net = Net()
loss_calc = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

for epoch in range(2):
    running_loss=0.0
    for data in DataLoader(trainSet, batch_size=1000, shuffle=True):
        inputs, target = data
        optimizer.zero_grad()
        outputs = net(inputs)
        print(outputs)
        loss = loss_calc(outputs, target)
        loss.backward()
        optimizer.step()        # print statistics
        running_loss += loss.item()
        print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss))
        running_loss = 0.0
print('Finished Training')
2 Answers

When working with a loss function and having problems with shapes you will usually have an error message of this type:

Target size (torch.Size([...])) must be the same as input size (torch.Size([...]))

'Target' refers to the label, the ground-truth, while 'input' refers to your model's output. In this case, the output is 1000 predictions (you set batch_size=1000) of 1 scalar value. Therefore the shape is (1000, 1). This last axis is the one bothering you, since the prediction vector is just a 1D tensor containing 1000 scalars, i.e. (1000).

To solve this you can expand your target tensor with an extra dimension. With torch.unsqueeze():

target = target.unsqueeze(-1) # -1 stands for last here equivalent to 1

Another solution to the problem is mentioned.

There could be a condition where there is a requirement for one-hot labels to be implemented in a machine learning model (required especially in binary classification models). For that purpose, you have to change your single column labels into one-hot encodings. The following code would help you do the same:

labels = torch.nn.functional.one_hot(labels)
Related