PyTorch: Checking Model Accuracy Results in "TypeError: 'bool' object is not iterable."

Viewed 412

I am training a neural network and would like to check its accuracy. I've used Librosa and SciKitLearn to represent audio in the form of 1D Numpy arrays. Thus x_train, x_test, y_train, and y_test are all 1D Numpy arrays with the x_* arrays containing floats and the y_* arrays containing strings corresponding to classes of data. For example:

x_train = [0.235, 1.101, 3.497]
y_train = ['happy', 'angry', 'neutral'] 

I've written a dictionary to represent these classes (strings) as integers:

emotions = {
'01' : 'neutral',
'02' : 'calm',
'03' : 'happy',
'04' : 'sad',
'05' : 'angry',
'06' : 'fearful',
'07' : 'disgust',
'08' : 'surprised'}

emotion_list = list(emotions.values())

Next I've defined a class to transform this data such that it can be passed to torch.utils.data.DataLoader():

class MakeDataset(Dataset):
    def __init__(self, x_train, y_train):
        self.x_train = torch.FloatTensor(x_train)
        self.y_train = torch.FloatTensor([emotion_list.index(each) for each in y_train])
    def __len__(self):
        return self.x_train.shape[0]
    def __getitem__(self, ind):
        x = self.x_train[ind]
        y = emotion_list.index(y_train[ind])
        return x, y

I define a training set, testing set, batch size, and load the data:

train_set = MakeDataset(x_train, y_train)
test_set = MakeDataset(x_test, y_test)

batch_size = 512

train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=False)

I define the model, train, and test as follows:

class TwoLayerMLP(torch.nn.Module):
    def __init__(self, D_in, H, D_out):
        super(TwoLayerMLP, self).__init__()
        self.linear1 = torch.nn.Linear(D_in, H)
        self.linear2 = torch.nn.Linear(H, D_out)

    def forward(self, x):
        h_relu = self.linear1(x).clamp(min=0)
        y_pred = self.linear2(h_relu)
        return y_pred


model = TwoLayerMLP(180, 90, 8)
optimizer = torch.optim.Adam(model.parameters())
criterion = nn.CrossEntropyLoss()

epochs = 5000

total_train = 0
correct_train = 0
for epoch in range(epochs):
    model.train()
    running_loss = 0.0
    for batch_num, data in enumerate(train_loader):
        audio , label = data
        optimizer.zero_grad()
        outputs = model(audio.float())
        loss = criterion(outputs, label)
        loss.backward()
        optimizer.step()
        
        predicted = torch.max(outputs.data,1)
        total_train += float(label.size(0))
        
        # Code runs with line below commented 
        # Else returns "TypeError: 'bool' object not iterable."
        correct_train += sum(predicted == label)

Note that this code has been updated, formerly the problematic line was:

correct_train += float((predicted == label)).sum()

Can anyone explain why this boolean object cannot be iterated as expected?

SOLVED

Please see the comments in abhiskk's answer below, but for clarity and brevity the following changes solved the problem:

pred_values, pred_indices = torch.max(outputs.data,1)
total_train += float(label.size(0))
correct_train += (sum(pred_indices == label)).item()
2 Answers

The predicted variable contains both values and indices, you need to do pred_vals, pred_inds = torch.max(outputs.data, 1) and then you can do correct_train += (sum(pred_inds == label)).item()

Also you don't need to convert to float before summing, you can use:

(predicted == label).sum().item()

(predicted == label) returns a BoolTensor which can be summed to obtain a float value.

Replace

correct_train += float((predicted == label)).sum()

with

correct_train += sum(predicted == label)

You don't need to convert boolean tensor to float, the sum function is smart enough to convert False to 0 and True to 1

Related