Beginner:Query Regarding Confusion matrix first argument with pytorch data class

Hi,
I am new to pytorch and machine learning.
I have created a model and I want to print the classification report.
I am somewhat certain that the first argument of the classification report is incorrect.
I was wondering it i could get some guidance on what should be added instead.

I have used this link: PyTorch [Tabular] —Multiclass Classification | by Akshaj Verma | Towards Data Science

The dataset files are saved on my google drive and accessed from there.

from __future__ import print_function
from __future__ import division
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import torchvision
from torchvision import datasets, models, transforms
import matplotlib.pyplot as plt
import time
import os
import copy
print("PyTorch Version: ",torch.__version__)
print("Torchvision Version: ",torchvision.__version__)
#from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
import os

import pprint
import itertools
from collections import defaultdict
#from collections import OrderedDict

# generate random integer values
from random import seed
from random import randint
import numpy as np
#from pylab import array
from random import sample
from random import shuffle
import math

import torch
from torch.utils.data import Dataset, DataLoader, IterableDataset
from torchvision import transforms, utils, models
from torch import nn, optim
from torchvision import datasets, transforms
#from torchvision.utils import make_grid
from PIL import Image
from google.colab import drive
drive.mount('/content/drive/')
#import csv
from time import time
import sys
sys.path.append('/content/drive/MyDrive')
#!cp -r "/content/gdrive/MyDrive/ColabNotebooks/Square_Data_Set_Generation.ipynb" '/content/'
import square_data_set_generation1
#import triangles_pieces_dataset
from torch.utils.tensorboard import SummaryWriter

from  sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import f1_score
from sklearn.metrics import classification_report

os.environ['MY_ROOT_DIR'] = '/content/drive/MyDrive/DATASET/train'
os.environ['MY_VAL_DIR'] = '/content/drive/MyDrive/DATASET/val'
os.environ['MY_TEST_DIR']='/content/drive/MyDrive/DATASET/test'

#https://pytorch.org/tutorials/beginner/finetuning_torchvision_models_tutorial.html

def retireve_the_dataset_input():
    puzzle_piece_dim = int(input("Enter puzzle_piece_dim "))
    size_of_buffer = int(input("Enter size_of_shuffle_buffer "))
    model_dim = int(input("Enter model_dim "))
    batch_size = int(input("Enter batch_size "))
    return sq_puzzle_piece_dim, size_of_buffer, model_dim, batch_size

def set_the_dataset_input(default=True):
    if default:
        puzzle_piece_dim=100
        size_of_buffer = 1000
        model_dim = 224
        batch_size = 20
    else:
        puzzle_piece_dim, size_of_buffer, model_dim, batch_size = retireve_the_dataset_input()
    return puzzle_piece_dim, size_of_buffer, model_dim, batch_size

def initialse_dataloader(root_dir,val_dir,test_dir,puzzle_piece_dim,size_of_buffer, model_dim,batch_size):
  ##ADD YOUR OWN DATASETS
     training_dataset=square_data_set_generation1.AdjacencyDataset(root_dir,puzzle_piece_dim, size_of_buffer, model_dim)
     #triangles_pieces_dataset.triangle_pieces_generator(root_dir,puzzle_piece_dim,size_of_buffer, model_dim)
     print(root_dir)
     print(puzzle_piece_dim)
  #square_data_set_generation.AdjacencyDataset(root_dir,puzzle_piece_dim, size_of_buffer, model_dim)
  ##Load the data using data loader
     train_dataset_dataloader = DataLoader(training_dataset, batch_size)
  ##Validation Data set
     validation_dataset=square_data_set_generation1.AdjacencyDataset(val_dir,puzzle_piece_dim, size_of_buffer, model_dim)
  #square_data_set_generation.AdjacencyDataset(val_dir,puzzle_piece_dim, size_of_buffer, model_dim)
     validation_dataset_dataloader = DataLoader(validation_dataset, batch_size)
  ##Add in testing dataset 
     testing_dataset=square_data_set_generation1.AdjacencyDataset(test_dir,puzzle_piece_dim, size_of_buffer, model_dim)
     test_dataset_dataloader = DataLoader(testing_dataset, batch_size)
     allTheDataloaders={'Training':train_dataset_dataloader , 'Validation': validation_dataset_dataloader,'Testing':test_dataset_dataloader}
     return allTheDataloaders



#https://pytorch.org/tutorials/beginner/saving_loading_models.html
#https://pytorch.org/tutorials/recipes/recipes/saving_and_loading_a_general_checkpoint.html
#https://towardsdatascience.com/how-to-save-and-load-a-model-in-pytorch-with-a-complete-example-c2920e617dee
def save_the_models_at_the_best_checkpoint(check_point_save,is_best,checkpoint_path,best_model_path):
    new_path=checkpoint_path
    torch.save(check_point_save,new_path)
    if is_best:
        torch.save(check_point_save, best_model_path)
    else:
        torch.save(check_point_save, checkpoint_path)



def load_the_models_at_the_best_checkpoint(new_path, model, optimizer):
    # load check point
    checkpoint = torch.load(new_path)
    # initialize state_dict from checkpoint to model
    model.load_state_dict(checkpoint['state_dict'])
    # initialize optimizer from checkpoint to optimizer
    optimizer.load_state_dict(checkpoint['optimizer'])
    # initialize valid_loss_min from checkpoint to valid_loss_min
    valid_loss_min = checkpoint['valid_loss_min']
    # return model, optimizer, epoch value, min validation loss 
    return model, optimizer, checkpoint['epoch'], valid_loss_min.item()

def set_parameter_requires_grad(model, feature_extracting):
    if feature_extracting:
        for param in model.parameters():
            param.requires_grad = False

##Initialise the model 

def initialise_the_model(model,numOfClasses,feature_extract,use_pretrained=True):
      if model=='densenet':
        model = models.densenet121(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft, feature_extract)
        num_ftrs = model_ft.classifier.in_features
        model.classifier = nn.Linear(num_ftrs, numOfClasses)
        input_size = 224
      return model
      


def create_optimizer(given_model_parameters, learning_rate, momentum):
    optimizer = optim.SGD(given_model_parameters, lr = learning_rate, momentum = momentum)
    return optimizer

model_names = ["Densenet"]

def get_model_details():
    i = int(input("Press 0 for Densenet "))
    model_name = model_names[i]
    if i==1:
        j = int(input("Press 0 for FineTuning and 1 for FeatureExtracting "))
        feature_extracting=(j==1)
    else:
        feature_extracting=False
    print("************")
    print(f"Using {model_name}")
    print(f"feature_extracting : {feature_extracting}")
    return model_name, feature_extracting

def set_parameter_requires_grad(model, feature_extracting):
    if feature_extracting:
        for param in model.parameters():
            param.requires_grad = False

def reshape_denseNet(no_of_classes, feature_extract, use_pretrained=True):
    model_dense = None
    input_size = 0
    model_dense = models.densenet161(pretrained=True)
    set_parameter_requires_grad(model_dense, feature_extract)
    no_of_features = model_dense.classifier.in_features #CHANGE
    model_dense.classifier = nn.Linear(no_of_features, no_of_classes)
     #nn.Linear(1024, num_classes) = nn.Linear(no_of_features, no_of_classes) #CHANGE TO CLASSIFER    
    return model_dense

def parameters_to_update(model_name, model, feature_extract=False):
    params = list(model.parameters())
    if model_name=="Densenet":#check with the model name created
        if feature_extract:
            print("Feature extracting from Densenet - Expect less number of parameters to learn!")
            params = []
            for name,param in model.named_parameters():
                if param.requires_grad == True:
                    params.append(param)
                    print("\t",name)
        else:
            print("Fine tuning Densenet - Expect more number of parameters to learn!")
            for name,param in model.named_parameters():
                if param.requires_grad == True:
                    print("\t",name)
    print(f"No_of_parameters to learn : {len(params)}")
    return params

def make_loss_criterion(model_name):
     # if model_name=="Densenet":
      loss_criterions = nn.CrossEntropyLoss()
      return loss_criterions

##CREATE A PARAMATERS UPTO DATE FUNCTION

def make_model_lc_optimizer(model,learning_rate, momentum,
                            feature_extract=False,no_of_classes=2):
    model =reshape_denseNet(no_of_classes, feature_extract, use_pretrained=True)
    params_to_update = parameters_to_update(model, model, feature_extract)
    loss_criterion = make_loss_criterion(model)
    optimizer = create_optimizer(params_to_update, learning_rate, momentum)
    return model, loss_criterion, optimizer


def get_hyperparameters(default=True):
    if default:
        learning_rate=0.001
        momentum = 0.9
    else:
        learning_rate = float(input("Enter learning rate "))
        momentum = float(input("Enter momentum "))
    return learning_rate, momentum


def train_it(no_of_epochs, starting_epoch, 
              model_name,model,loss_criterion, optimizer,
              batch_size, allTheDataloaders,board_writer,device,batches_per_epoch=100,
              is_best=False,min_validation_loss=math.inf):

    last_checkpoint_path = f"./last_checkpoint_for_{model_name}.pt"
    best_model_path=f"./best_model_for_{model_name}.pt"
    
    for epoch in range(starting_epoch,starting_epoch+no_of_epochs):
        print(f"Epoch : {epoch}")
        start_time = time()

        model.train()

     
        print("Training")
        train_loss_in_this_epoch = 0
        no_of_batches_in_this_epoch = 0
        train_correct_in_this_epoch = 0
        for train_batch_data, train_batch_labels in allTheDataloaders["Training"]:
                train_batch_data, train_batch_labels = train_batch_data.to(device), train_batch_labels.to(device)
                no_of_batches_in_this_epoch+= 1
                optimizer.zero_grad()
                train_batch_outputs = model(train_batch_data)
                #Compute loss for this batch
                train_batch_loss = loss_criterion(train_batch_outputs, train_batch_labels)
                train_loss_in_this_batch = train_batch_loss.item()
                train_loss_in_this_epoch += train_loss_in_this_batch 
                train_batch_loss.backward()
                optimizer.step()
                with torch.no_grad():
                    new_pred=torch.max(train_batch_outputs, axis = 1) 
                    train_score, train_predictions = torch.max(train_batch_outputs, axis = 1)   
                    train_correct_in_this_batch = torch.sum(train_predictions == train_batch_labels.data).item()
                    train_correct_in_this_epoch += train_correct_in_this_batch
                    train_batch_labels = train_batch_labels.detach().cpu().numpy()
                    train_score = train_score.detach().cpu().numpy()


                if (no_of_batches_in_this_epoch % (batches_per_epoch//10)) == 0:
                    print(f"Training #{no_of_batches_in_this_epoch} Batch Acc : {train_correct_in_this_batch}/{batch_size}, Batch Loss: {train_loss_in_this_batch}")
                if no_of_batches_in_this_epoch == batches_per_epoch:
                    print(f"Epoch : {epoch}, Training Batch: {no_of_batches_in_this_epoch}")
                    break
 

        board_writer.add_scalar(f'Training/Loss/Average', train_loss_in_this_epoch/no_of_batches_in_this_epoch, epoch)
        board_writer.add_scalar(f'Training/Accuracy/Average', train_correct_in_this_epoch/(no_of_batches_in_this_epoch*batch_size), epoch)
        board_writer.add_scalar(f'Training/TimeTakenInMinutes', (time()-start_time)/60, epoch)
        board_writer.flush()
        print(f"Training average accuracy : {train_correct_in_this_epoch/(no_of_batches_in_this_epoch*batch_size)}")
        print(f"Training average loss : {train_loss_in_this_epoch/no_of_batches_in_this_epoch}")
            
        #create f measure
        model.eval()
        print("Validation")
        val_loss_in_this_epoch = 0
        no_of_batches_in_this_epoch = 0
        val_correct_in_this_epoch = 0
        with torch.no_grad():
            for val_batch_data, val_batch_labels in allTheDataloaders["Validation"]:
                val_batch_data, val_batch_labels = val_batch_data.to(device), val_batch_labels.to(device)
                no_of_batches_in_this_epoch+= 1
                val_batch_outputs = model(val_batch_data)
                #Compute loss for this batch
                val_batch_loss = loss_criterion(val_batch_outputs, val_batch_labels)
                val_loss_in_this_batch = val_batch_loss.item()
                val_loss_in_this_epoch += val_loss_in_this_batch 
                val_score, val_predictions = torch.max(val_batch_outputs, axis = 1)   
                val_correct_in_this_batch = torch.sum(val_predictions == val_batch_labels.data).item()
                val_correct_in_this_epoch += val_correct_in_this_batch
                if (no_of_batches_in_this_epoch % (batches_per_epoch//10)) == 0:
                    print(f"Validation #{no_of_batches_in_this_epoch} Batch Acc : {val_correct_in_this_batch}/{batch_size}, Batch Loss: {val_loss_in_this_batch}")
                if no_of_batches_in_this_epoch == batches_per_epoch:
                    print(f"Epoch : {epoch}, Validation Batch: {no_of_batches_in_this_epoch}")
                    break
            board_writer.add_scalar(f'Validation/Loss/Average', val_loss_in_this_epoch/no_of_batches_in_this_epoch, epoch)
            board_writer.add_scalar(f'Validation/Accuracy/Average', val_correct_in_this_epoch/(no_of_batches_in_this_epoch*batch_size), epoch)
            board_writer.add_scalar(f'Validation/TimeTakenInMinutes', (time()-start_time)/60, epoch)
            board_writer.flush()
            print(f"Validation average accuracy : {val_correct_in_this_epoch/(no_of_batches_in_this_epoch*batch_size)}")
            print(f"Validation average loss : {val_loss_in_this_epoch/no_of_batches_in_this_epoch}")
            if  min_validation_loss >= val_loss_in_this_epoch:
                    is_best = True
                    min_validation_loss = min(min_validation_loss,val_loss_in_this_epoch)
                    checkpoint = {
                        'epoch': epoch + 1,
                        'min_validation_loss': min_validation_loss,
                        'state_dict': model.state_dict(),
                        'optimizer': optimizer.state_dict(),
                    }
                    save_the_models_at_the_best_checkpoint(checkpoint, is_best, last_checkpoint_path, best_model_path)
                    print(f"In epoch number {epoch}, average validation loss decreased to {val_loss_in_this_epoch/no_of_batches_in_this_epoch}")
            load_the_models_at_the_best_checkpoint = {
                    'epoch': epoch + 1,
                    'min_validation_loss': min_validation_loss,
                    'state_dict': model.state_dict(),
                    'optimizer': optimizer.state_dict(),
                     }
            save_the_models_at_the_best_checkpoint(load_the_models_at_the_best_checkpoint, False, last_checkpoint_path, best_model_path)

    board_writer.close()
    #from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
   # print(confusion_matrix(t_labels,t_predicitions))
    #print(classification_report(t_labels,scores))
   # print(metrics.classification_report (t_labels, t_predicitions))
   # print(accuracy_score(t_labels, t_predicitions))
    t_labels=[]
    t_predicitions=[]
    with torch.no_grad():
        model.eval()
        for test_batch_data,test_batch_labels in allTheDataloaders["Testing"]:
            test_batch_data, test_batch_labels = test_batch_data.to(device), test_batch_labels.to(device)
            y_test_pred=model(test_batch_data)
            _, y_pred_targets = torch.max(y_test_pred, dim = 1)
            t_predicitions.append(y_pred_targets.cpu().numpy())
    
    t_predicitions=[t.squeeze().tolist() for t in t_predicitions]
    print(classification_report(test_batch_data, t_predicitions))
           
 ##Add in classification report to this section and check if it works https://stackabuse.com/introduction-to-pytorch-for-classification/

##Variables
root_dir = os.getenv("MY_ROOT_DIR")
val_dir = os.getenv("MY_VAL_DIR")
test_dir=os.getenv("MY_TEST_DIR")

#Change this to False if you want to set the variables instead of using default
default_setting_for_dataset = True

puzzle_piece_dim,size_of_buffer,model_dim,batch_size = set_the_dataset_input(default_setting_for_dataset)

print(f"my_puzzle_piece_dim = {puzzle_piece_dim}")
print(f"my_size_of_buffer = {size_of_buffer}")
print(f"my_model_dim = {model_dim}")
print(f"my_batch_size = {batch_size}")

my_dataloaders = initialse_dataloader(root_dir,val_dir,test_dir, puzzle_piece_dim,size_of_buffer, model_dim,batch_size)

model_name, feature_extract = get_model_details()

default_setting_for_hyperparameters = True

learning_rate,momentum = get_hyperparameters(default_setting_for_hyperparameters)

#Change the number 
epoch=3

model,loss_criterion,optimizer=make_model_lc_optimizer(model_name,learning_rate, momentum,feature_extract)

if torch.cuda.is_available():
    device = torch.device("cuda:0")   
    print("Running on the GPU")
    #putting model on gpu
    model.to(device)
else:
    device = torch.device("cpu")
    print("Running on the CPU")

tensorboard_dir=f"Training_{model_name}"
board_writer = SummaryWriter(tensorboard_dir)


train_it(epoch, 0, 
              model_name,model,loss_criterion, optimizer,
              batch_size, 
              my_dataloaders,
              board_writer,
              device,
              batches_per_epoch=500)

/%load_ext tensorboard
%tensorboard --logdir="$tensorboard_dir"

I have placed test_batch_data but I know it should not be there as I got the following error.

Any guidance would be appreciated as I am a bit lost.

Based on your code it seems you are trying to pass the predictions from the complete testing epoch to classification_report, while only a single test_batch_data is used, which would most likely contain less samples.
Also, based on the docs for sklearn.metrics.classification_report, 1d array-like inputs are expected, while you are passing a nested list to it, so you might also need to fix this.

1 Like

Hi thank you for your response.

I replaced the first argument with the test data(used tutorial pages online).
I received the following error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/usr/local/lib/python3.7/dist-packages/sklearn/utils/validation.py in _num_samples(x)
    158     try:
--> 159         return len(x)
    160     except TypeError:

8 frames
/usr/local/lib/python3.7/dist-packages/torch/utils/data/dataloader.py in __len__(self)
    390             # Cannot statically verify that dataset is Sized
--> 391             length = self._IterableDataset_len_called = len(self.dataset)  # type: ignore
    392             if self.batch_size is not None:  # IterableDataset doesn't allow custom sampler or batch_sampler

/content/drive/MyDrive/square_data_set_generation1.py in __len__(self)
    212         iterator_len= self.puzzle_piece_pair_iterator()
--> 213         return len(shuffle_buffer_iterator(iterator_len, self.size_of_buffer))
    214 

TypeError: object of type 'generator' has no len()

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-33-acd6e6d62fc6> in <module>()
      5               board_writer,
      6               device,
----> 7               batches_per_epoch=500)

<ipython-input-20-02e3c875a1cb> in train_it(no_of_epochs, starting_epoch, model_name, model, loss_criterion, optimizer, batch_size, allTheDataloaders, board_writer, device, batches_per_epoch, is_best, min_validation_loss)
    140     y_test=allTheDataloaders["Testing"]
    141     t_predicitions=[t.squeeze().tolist() for t in t_predicitions]
--> 142     print(classification_report(y_test, t_predicitions))
    143 
    144 

/usr/local/lib/python3.7/dist-packages/sklearn/metrics/_classification.py in classification_report(y_true, y_pred, labels, target_names, sample_weight, digits, output_dict, zero_division)
   1969     """
   1970 
-> 1971     y_type, y_true, y_pred = _check_targets(y_true, y_pred)
   1972 
   1973     labels_given = True

/usr/local/lib/python3.7/dist-packages/sklearn/metrics/_classification.py in _check_targets(y_true, y_pred)
     78     y_pred : array or indicator matrix
     79     """
---> 80     check_consistent_length(y_true, y_pred)
     81     type_true = type_of_target(y_true)
     82     type_pred = type_of_target(y_pred)

/usr/local/lib/python3.7/dist-packages/sklearn/utils/validation.py in check_consistent_length(*arrays)
    206     """
    207 
--> 208     lengths = [_num_samples(X) for X in arrays if X is not None]
    209     uniques = np.unique(lengths)
    210     if len(uniques) > 1:

/usr/local/lib/python3.7/dist-packages/sklearn/utils/validation.py in <listcomp>(.0)
    206     """
    207 
--> 208     lengths = [_num_samples(X) for X in arrays if X is not None]
    209     uniques = np.unique(lengths)
    210     if len(uniques) > 1:

/usr/local/lib/python3.7/dist-packages/sklearn/utils/validation.py in _num_samples(x)
    159         return len(x)
    160     except TypeError:
--> 161         raise TypeError(message)
    162 
    163 

TypeError: Expected sequence or array-like, got <class 'torch.utils.data.dataloader.DataLoader'>

The Adjancey dataset consists of a len:
(This file is written is from github and alterations were made)

from PIL import Image

import matplotlib.pyplot as plt

import matplotlib.ticker as plticker

import os

import pprint

import itertools

from collections import defaultdict

# generate random integer values

from random import seed

from random import randint

import numpy as np

#from pylab import array

from random import sample

import math

#pytorch modules

import torch

from torch.utils.data import Dataset, DataLoader, IterableDataset

from torchvision import transforms, utils

#TODO:FIX THE BLACK ISSUE PART

from google.colab import drive

drive.mount('/content/drive')

os.environ['MY_ROOT_DIR'] = '/content/drive/MyDrive/path_to_directory/train'

def shuffle_buffer_iterator(actual_iterator, size_of_buffer):

    shuffle = []

    while(True):

        size = 0

        while(size < size_of_buffer):

            try:

                shuffle.append(next(actual_iterator))

                size +=1

            except StopIteration:

                shuffle = sample(shuffle, len(shuffle))    

                for s in shuffle:

                    yield s

                return

        

        shuffle = sample(shuffle, len(shuffle))    

        for s in shuffle:

            yield s

        shuffle = []

class AdjacencyDataset(IterableDataset):

    def __init__(self, root_dir, sq_puzzle_piece_dim, size_of_buffer, model_dim):

        super(IterableDataset).__init__()

        self.root_dir = root_dir

        self.sq_puzzle_piece_dim = sq_puzzle_piece_dim

        self.size_of_buffer = size_of_buffer

        self.model_dim = model_dim

        

    def make_the_puzzle_grid(self, rows, cols):

        list_of_labels = []

        for x in range(rows):

            for y in range(cols):

                list_of_labels.append((x,y))

        dist_dict = defaultdict(list)

        for pos, (x, y) in enumerate(list_of_labels):

            for a,b in list_of_labels[pos+1: ]:

                d = (a-x)**2 + (b-y)**2

                dist_dict[d].append([(x,y), (a,b)])

        size_dist_dict = {}

        for d in dist_dict:

            size_dist_dict[d] = len(dist_dict[d])

        no_of_non_adjacent_pairs = 0

        for d in size_dist_dict:

            no_of_non_adjacent_pairs += size_dist_dict[d]

        no_of_non_adjacent_pairs -= size_dist_dict[1]

        no_of_adjacent_pairs = size_dist_dict[1]

        #There are no_of_non_adjacent_pairs non-adjacent pairs.

        #How to choose no_of_adjacent_pairs  pairs of non-adjacent pieces ?

        #no_of_non_adjacent_pairs*x = no_of_adjacent_pairs

        x  = no_of_adjacent_pairs/no_of_non_adjacent_pairs

        no_of_rep = {}

        for d in size_dist_dict:

            no_of_rep[d] = math.ceil(size_dist_dict[d]*x)

        no_of_rep[1] = size_dist_dict[1]

        return list_of_labels, dist_dict, size_dist_dict, no_of_rep

    

    def transform_input(self, piece_1, piece_2):

        width = self.model_dim

        height = self.model_dim

        piece_1 = piece_1.resize((width, height))

        piece_2 = piece_2.resize((width, height))

        juxtaposed = Image.new('RGB', (2*width, height), color=0)

        #juxtaposed.paste(piece_i ,

        #(left_upper_row, left_upper_col, 

        #right_lower_row, right_lower_col))

        juxtaposed.paste(piece_1,(0,0,width, height))

        juxtaposed.paste(piece_2,(width,0,2*width, height))

        juxtaposed = juxtaposed.crop((width//2, 0,width//2 + width,height))

        return transforms.ToTensor()(juxtaposed)

#Ref:https://stackoverflow.com/questions/54799457/force-pillow-to-generate-an-image-with-the-truecolor-type-while-i-only-use-blac

#Images do not match error

#https://note.nkmk.me/en/python-pillow-concat-images/

    def join_pieces_h(self,piece_1,piece_2):

         width=50

         height=50

         juxtaposed_h = Image.new('RGB', (piece_1.width + piece_2.width, piece_1.height))

         juxtaposed_h.paste(piece_1, (0, 0))

         juxtaposed_h.paste(piece_2, (piece_1.width, 0))

         return transforms.ToTensor()(juxtaposed_h)

    def transform_input_black_image(self,piece_1,piece_2):

        width = self.model_dim

        height = self.model_dim

        #piece_1 = piece_1.resize((width, height))

        #piece_2 = piece_2.resize((width, height))

        juxtaposed_black_background=Image.new('RGB',(width,height)(0,0,0)) 

        juxtaposed_black_background_copy=juxtaposed_black_background.copy()

        juxtaposed_black_background_copy.paste()

##the image is pasted continue by pasting the squares ontop 

        juxtaposed_black.paste(piece_1,(0,0,width, height))

        juxtaposed_black.paste(piece_2,(width,0,2*width, height))

        juxtaposed_black = juxtaposed_black.crop((width, 0,width + width,height))

        return transforms.ToTensor()(juxtaposed_black)  

                        

#/content/drive/MyDrive/path_to_directory/train/1/image_06734.jpg

    def puzzle_piece_pair_iterator(self):

        for folder in sample(os.listdir(self.root_dir), len(os.listdir(self.root_dir))):

            folder_path = self.root_dir+"/"+folder

            print(folder_path)

            for image in sample(os.listdir(folder_path), len(os.listdir(folder_path))):

                current_image = Image.open(folder_path + "/"+image)

                

                original_image_height = current_image.size[1]

                original_image_width =  current_image.size[0] 

                

                puzzle_piece_height = self.sq_puzzle_piece_dim

                puzzle_piece_width = self.sq_puzzle_piece_dim

                

                rows = round(original_image_height/puzzle_piece_height)

                cols = round(original_image_width/puzzle_piece_width)

                

                list_of_labels, dist_dict, size_dist_dict, no_of_rep = self.make_the_puzzle_grid(rows,cols) 

                

                new_image_height = rows*puzzle_piece_height

                new_image_width = cols*puzzle_piece_width

                

                current_image = current_image.resize((new_image_width, new_image_height))

                

                puzzle_pieces = []

                i = 0

                j = 0

                while(i < rows):

                    row_puzzle_pieces = []

                    row_puzzle_pieces_torchtensor = []

                    while(j < cols):

                        crop_piece = current_image.crop((j*puzzle_piece_width,i*puzzle_piece_height,(j+1)*puzzle_piece_width,(i+1)*puzzle_piece_height))

                        row_puzzle_pieces.append(crop_piece)

                        j += 1

                    puzzle_pieces.append(row_puzzle_pieces)

                    i += 1

                    j = 0

                puzzle_piece_crop_list = []

                for d in dist_dict:

                    puzzle_piece_crop_list.extend(sample(dist_dict[d], no_of_rep[d]))

                

                for label_pairs in sample(puzzle_piece_crop_list, len(puzzle_piece_crop_list)):

                    x, y = label_pairs[0]

                    a, b = label_pairs[1]

                    are_adjacent = (((x-a)**2 + (y-b)**2)==1)

                    piece_1 = puzzle_pieces[x][y]

                    piece_2 = puzzle_pieces[a][b]

                    if are_adjacent:

                        if abs(a-x)==1:

                            #rotate piece_1_torchtensor counterclockwise by 90

                            #rotate piece_2_torchtensor counterclockwise by 90

                            piece_1 = puzzle_pieces[x][y].rotate(90)

                            piece_2 = puzzle_pieces[a][b].rotate(90)

                    if are_adjacent:

                        label = 1

                    else:

                        label = 0

                    

                    juxtaposed_pieces_torchtensor = self.join_pieces_h(piece_1, piece_2)

                    yield (juxtaposed_pieces_torchtensor,label)

            

    def __iter__(self):

        my_iterator = self.puzzle_piece_pair_iterator()

        return shuffle_buffer_iterator(my_iterator, self.size_of_buffer)

    def __len__(self):

        iterator_len= self.puzzle_piece_pair_iterator()

        return len(shuffle_buffer_iterator(iterator_len, self.size_of_buffer))

The train method of the model:


def train_it(no_of_epochs, starting_epoch, 
              model_name,model,loss_criterion, optimizer,
              batch_size, allTheDataloaders,board_writer,device,batches_per_epoch=100,
              is_best=False,min_validation_loss=math.inf):

    last_checkpoint_path = f"./last_checkpoint_for_{model_name}.pt"
    best_model_path=f"./best_model_for_{model_name}.pt"
    
    #to_track_info = ["epoch", "total time", "train loss"]
    #f val_loader is not None:
      #  to_track_info.append("val loss")
    #for eval_score in score_funcs:
     #   to_track_info.append("train " + eval_score )
      #  if val_loader is not None:
       #     to_track_info.append("val " + eval_score )
    
   # results={}

    #for j in to_track_info:
     #  results[j]=[]
    for epoch in range(starting_epoch,starting_epoch+no_of_epochs):
        print(f"Epoch : {epoch}")
        start_time = time()

        model.train()

     
        print("Training")
        train_loss_in_this_epoch = 0
        no_of_batches_in_this_epoch = 0
        train_correct_in_this_epoch = 0
        for train_batch_data, train_batch_labels in allTheDataloaders["Training"]:
                train_batch_data, train_batch_labels = train_batch_data.to(device), train_batch_labels.to(device)
                no_of_batches_in_this_epoch+= 1
                optimizer.zero_grad()
                train_batch_outputs = model(train_batch_data)
                #Compute loss for this batch
                train_batch_loss = loss_criterion(train_batch_outputs, train_batch_labels)
                train_loss_in_this_batch = train_batch_loss.item()
                train_loss_in_this_epoch += train_loss_in_this_batch 
                train_batch_loss.backward()
                optimizer.step()
                with torch.no_grad():
                    new_pred=torch.max(train_batch_outputs, axis = 1) 
                    train_score, train_predictions = torch.max(train_batch_outputs, axis = 1)   
                    train_correct_in_this_batch = torch.sum(train_predictions == train_batch_labels.data).item()
                    train_correct_in_this_epoch += train_correct_in_this_batch
                    train_batch_labels = train_batch_labels.detach().cpu().numpy()
                    train_score = train_score.detach().cpu().numpy()


                if (no_of_batches_in_this_epoch % (batches_per_epoch//10)) == 0:
                    print(f"Training #{no_of_batches_in_this_epoch} Batch Acc : {train_correct_in_this_batch}/{batch_size}, Batch Loss: {train_loss_in_this_batch}")
                if no_of_batches_in_this_epoch == batches_per_epoch:
                    print(f"Epoch : {epoch}, Training Batch: {no_of_batches_in_this_epoch}")
                    break
     #  results["epoch"].append( epoch )
      # results["total time"].append( time()-start_time) )
       #results["train loss"].append( train_loss_in_this_epoch )
     #   t_predicitions = np.asarray(t_predicitions)
        
#        if t_predicitions.shape[1] > 1: #We have a classification problem, convert to labels
     #   t_predicitions = np.argmax(t_predicitions, axis=1)
            
      #  for name, score_func in score_cal.items():
       #     results["train " + name].append( score_cal(t_labels, t_predicitions) )

        board_writer.add_scalar(f'Training/Loss/Average', train_loss_in_this_epoch/no_of_batches_in_this_epoch, epoch)
        board_writer.add_scalar(f'Training/Accuracy/Average', train_correct_in_this_epoch/(no_of_batches_in_this_epoch*batch_size), epoch)
        board_writer.add_scalar(f'Training/TimeTakenInMinutes', (time()-start_time)/60, epoch)
        board_writer.flush()
        print(f"Training average accuracy : {train_correct_in_this_epoch/(no_of_batches_in_this_epoch*batch_size)}")
        print(f"Training average loss : {train_loss_in_this_epoch/no_of_batches_in_this_epoch}")
            
        #create f measure
        model.eval()
        print("Validation")
        val_loss_in_this_epoch = 0
        no_of_batches_in_this_epoch = 0
        val_correct_in_this_epoch = 0
        with torch.no_grad():
            for val_batch_data, val_batch_labels in allTheDataloaders["Validation"]:
                val_batch_data, val_batch_labels = val_batch_data.to(device), val_batch_labels.to(device)
                no_of_batches_in_this_epoch+= 1
                val_batch_outputs = model(val_batch_data)
                #Compute loss for this batch
                val_batch_loss = loss_criterion(val_batch_outputs, val_batch_labels)
                val_loss_in_this_batch = val_batch_loss.item()
                val_loss_in_this_epoch += val_loss_in_this_batch 
                val_score, val_predictions = torch.max(val_batch_outputs, axis = 1)   
                val_correct_in_this_batch = torch.sum(val_predictions == val_batch_labels.data).item()
                val_correct_in_this_epoch += val_correct_in_this_batch
                if (no_of_batches_in_this_epoch % (batches_per_epoch//10)) == 0:
                    print(f"Validation #{no_of_batches_in_this_epoch} Batch Acc : {val_correct_in_this_batch}/{batch_size}, Batch Loss: {val_loss_in_this_batch}")
                if no_of_batches_in_this_epoch == batches_per_epoch:
                    print(f"Epoch : {epoch}, Validation Batch: {no_of_batches_in_this_epoch}")
                    break
            board_writer.add_scalar(f'Validation/Loss/Average', val_loss_in_this_epoch/no_of_batches_in_this_epoch, epoch)
            board_writer.add_scalar(f'Validation/Accuracy/Average', val_correct_in_this_epoch/(no_of_batches_in_this_epoch*batch_size), epoch)
            board_writer.add_scalar(f'Validation/TimeTakenInMinutes', (time()-start_time)/60, epoch)
            board_writer.flush()
            print(f"Validation average accuracy : {val_correct_in_this_epoch/(no_of_batches_in_this_epoch*batch_size)}")
            print(f"Validation average loss : {val_loss_in_this_epoch/no_of_batches_in_this_epoch}")
            if  min_validation_loss >= val_loss_in_this_epoch:
                    is_best = True
                    min_validation_loss = min(min_validation_loss,val_loss_in_this_epoch)
                    checkpoint = {
                        'epoch': epoch + 1,
                        'min_validation_loss': min_validation_loss,
                        'state_dict': model.state_dict(),
                        'optimizer': optimizer.state_dict(),
                    }
                    save_the_models_at_the_best_checkpoint(checkpoint, is_best, last_checkpoint_path, best_model_path)
                    print(f"In epoch number {epoch}, average validation loss decreased to {val_loss_in_this_epoch/no_of_batches_in_this_epoch}")
            load_the_models_at_the_best_checkpoint = {
                    'epoch': epoch + 1,
                    'min_validation_loss': min_validation_loss,
                    'state_dict': model.state_dict(),
                    'optimizer': optimizer.state_dict(),
                     }
            save_the_models_at_the_best_checkpoint(load_the_models_at_the_best_checkpoint, False, last_checkpoint_path, best_model_path)

    board_writer.close()
    #from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
   # print(confusion_matrix(t_labels,t_predicitions))
    #print(classification_report(t_labels,scores))
   # print(metrics.classification_report (t_labels, t_predicitions))
   # print(accuracy_score(t_labels, t_predicitions))
    t_labels=[]
    t_predicitions=[]
    with torch.no_grad():
        model.eval()
        for test_batch_data,test_batch_labels in allTheDataloaders["Testing"]:
            test_batch_data, test_batch_labels = test_batch_data.to(device), test_batch_labels.to(device)
            y_test_pred=model(test_batch_data)
            _, y_pred_targets = torch.max(y_test_pred, dim = 1)
            t_predicitions.append(y_pred_targets.cpu().numpy())
    y_test=allTheDataloaders["Testing"]
    t_predicitions=[t.squeeze().tolist() for t in t_predicitions]
    print(classification_report(y_test, t_predicitions))

Sorry I am new to python,pytorch and machine learning.
Any explanations or guidance would be useful.

Thank you.

You cannot pass the DataLoader object directly to classification_report as numpy arrays are expected, so you would need to store the targets in e.g. a list as was done for t_predictions and then convert it to e.g. a numpy array.

1 Like

Hi do you know if there are any specific reasons why the classification report does not print.

    t_predicitions=[t.squeeze().tolist() for t in t_predicitions]
   # print(classification_report(t_labels, t_predicitions))
    for y_test,y_test_labels in allTheDataloaders["Testing"]:
          return y_test,y_test_labels
    y_test_new=y_test.cpu().numpy()
    print(classification_report(y_test_new, t_predicitions))

I got the return values for the y_Test and y_Test labels but not the classification report

(tensor([[[[0.9804, 0.9961, 1.0000,  ..., 0.0588, 0.0549, 0.0510],
           [0.9569, 0.9804, 1.0000,  ..., 0.0549, 0.0510, 0.0471],
           [0.9608, 0.9686, 0.9843,  ..., 0.0471, 0.0471, 0.0431],
           ...,
           [0.7020, 0.7098, 0.6980,  ..., 0.0667, 0.0667, 0.0667],
           [0.6980, 0.7020, 0.6902,  ..., 0.0667, 0.0667, 0.0667],
           [0.6941, 0.6980, 0.6863,  ..., 0.0667, 0.0667, 0.0667]],
 
          [[0.0000, 0.0000, 0.0000,  ..., 0.0549, 0.0510, 0.0471],
           [0.0000, 0.0000, 0.0078,  ..., 0.0510, 0.0471, 0.0431],
           [0.0078, 0.0039, 0.0078,  ..., 0.0431, 0.0431, 0.0392],
           ...,
           [0.7529, 0.7529, 0.7333,  ..., 0.0824, 0.0824, 0.0824],
           [0.7490, 0.7451, 0.7294,  ..., 0.0824, 0.0824, 0.0824],
           [0.7451, 0.7412, 0.7255,  ..., 0.0824, 0.0824, 0.0824]],
 
          [[0.0941, 0.0902, 0.0824,  ..., 0.0392, 0.0353, 0.0392],
           [0.0824, 0.0863, 0.0941,  ..., 0.0353, 0.0314, 0.0353],
           [0.0941, 0.0863, 0.0863,  ..., 0.0275, 0.0353, 0.0314],
           ...,
           [0.5098, 0.5059, 0.4863,  ..., 0.0235, 0.0235, 0.0275],
           [0.5059, 0.4980, 0.4824,  ..., 0.0235, 0.0235, 0.0275],
           [0.5020, 0.4941, 0.4784,  ..., 0.0235, 0.0235, 0.0275]]],
 
 
         [[[0.4039, 0.4118, 0.4235,  ..., 0.0706, 0.0784, 0.0863],
           [0.4196, 0.4275, 0.4392,  ..., 0.0706, 0.0784, 0.0863],
           [0.4431, 0.4471, 0.4588,  ..., 0.0706, 0.0824, 0.0863],
           ...,
           [0.2784, 0.3333, 0.4471,  ..., 0.8431, 0.5804, 0.2431],
           [0.3333, 0.4902, 0.6431,  ..., 0.8314, 0.5412, 0.2392],
           [0.4745, 0.6431, 0.7569,  ..., 0.7725, 0.4588, 0.2549]],
 
          [[0.2863, 0.2941, 0.3059,  ..., 0.0784, 0.0863, 0.0941],
           [0.3020, 0.3098, 0.3216,  ..., 0.0784, 0.0863, 0.0941],
           [0.3255, 0.3294, 0.3412,  ..., 0.0784, 0.0902, 0.0941],
           ...,
           [0.3216, 0.3725, 0.4824,  ..., 0.8824, 0.6235, 0.2863],
           [0.3765, 0.5255, 0.6784,  ..., 0.8745, 0.5843, 0.2863],
           [0.5216, 0.6863, 0.8000,  ..., 0.8157, 0.5059, 0.3020]],
 
          [[0.1843, 0.1922, 0.2039,  ..., 0.0275, 0.0353, 0.0392],
           [0.2000, 0.2078, 0.2196,  ..., 0.0275, 0.0353, 0.0431],
           [0.2235, 0.2275, 0.2392,  ..., 0.0275, 0.0392, 0.0431],
           ...,
           [0.2039, 0.2745, 0.4039,  ..., 0.7765, 0.5059, 0.1569],
           [0.2784, 0.4431, 0.6118,  ..., 0.7569, 0.4471, 0.1451],
           [0.4353, 0.6196, 0.7451,  ..., 0.6824, 0.3647, 0.1529]]],
 
 
         [[[0.6314, 0.6353, 0.6353,  ..., 0.0549, 0.0549, 0.0549],
           [0.6314, 0.6314, 0.6353,  ..., 0.0588, 0.0588, 0.0588],
           [0.6275, 0.6275, 0.6314,  ..., 0.0627, 0.0627, 0.0588],
           ...,
           [0.3490, 0.3490, 0.3569,  ..., 0.2824, 0.2667, 0.2431],
           [0.3569, 0.3569, 0.3569,  ..., 0.3176, 0.2941, 0.2667],
           [0.3569, 0.3529, 0.3529,  ..., 0.3216, 0.2980, 0.2706]],
 
          [[0.3176, 0.3216, 0.3216,  ..., 0.0471, 0.0471, 0.0471],
           [0.3176, 0.3176, 0.3216,  ..., 0.0510, 0.0510, 0.0510],
           [0.3137, 0.3137, 0.3176,  ..., 0.0549, 0.0549, 0.0510],
           ...,
           [0.0118, 0.0157, 0.0118,  ..., 0.1882, 0.1686, 0.1529],
           [0.0118, 0.0118, 0.0118,  ..., 0.2235, 0.1961, 0.1765],
           [0.0118, 0.0078, 0.0118,  ..., 0.2275, 0.2039, 0.1804]],
 
          [[0.5529, 0.5569, 0.5569,  ..., 0.0510, 0.0510, 0.0510],
           [0.5569, 0.5569, 0.5608,  ..., 0.0549, 0.0549, 0.0549],
           [0.5529, 0.5529, 0.5569,  ..., 0.0588, 0.0588, 0.0549],
           ...,
           [0.2510, 0.2471, 0.2392,  ..., 0.1490, 0.1412, 0.1294],
           [0.2471, 0.2471, 0.2392,  ..., 0.1843, 0.1686, 0.1529],
           [0.2392, 0.2353, 0.2275,  ..., 0.1882, 0.1647, 0.1490]]],
 
 
         ...,
 
 
         [[[0.6745, 0.7176, 0.7294,  ..., 0.8235, 0.8118, 0.8353],
           [0.7843, 0.7765, 0.7294,  ..., 0.7961, 0.7922, 0.8314],
           [0.8510, 0.7961, 0.7059,  ..., 0.7804, 0.7961, 0.8431],
           ...,
           [0.8157, 0.7804, 0.7882,  ..., 0.9333, 0.9608, 0.9176],
           [0.8471, 0.8078, 0.7961,  ..., 0.8392, 0.9098, 0.9333],
           [0.9020, 0.8275, 0.7922,  ..., 0.8118, 0.8824, 0.9373]],
 
          [[0.3216, 0.3569, 0.3686,  ..., 0.1922, 0.1922, 0.2235],
           [0.4157, 0.4039, 0.3608,  ..., 0.1725, 0.1843, 0.2196],
           [0.4627, 0.4118, 0.3216,  ..., 0.1608, 0.1843, 0.2392],
           ...,
           [0.2235, 0.1882, 0.2000,  ..., 0.5843, 0.6157, 0.5725],
           [0.2471, 0.2078, 0.1961,  ..., 0.4902, 0.5647, 0.5843],
           [0.2941, 0.2275, 0.1882,  ..., 0.4706, 0.5451, 0.5961]],
 
          [[0.6118, 0.6510, 0.6706,  ..., 0.3529, 0.3490, 0.3804],
           [0.7059, 0.7020, 0.6667,  ..., 0.3216, 0.3333, 0.3725],
           [0.7490, 0.7059, 0.6235,  ..., 0.2980, 0.3255, 0.3882],
           ...,
           [0.3922, 0.3647, 0.3765,  ..., 0.9137, 0.9451, 0.9020],
           [0.4196, 0.3804, 0.3765,  ..., 0.8196, 0.8941, 0.9098],
           [0.4588, 0.4000, 0.3608,  ..., 0.8078, 0.8824, 0.9255]]],
 
 
         [[[0.2392, 0.2235, 0.2039,  ..., 0.7098, 0.7059, 0.7020],
           [0.2471, 0.2353, 0.2196,  ..., 0.7059, 0.6980, 0.6941],
           [0.2549, 0.2392, 0.2235,  ..., 0.6980, 0.6941, 0.6902],
           ...,
           [0.2314, 0.2353, 0.2392,  ..., 0.1059, 0.1020, 0.1020],
           [0.2196, 0.2235, 0.2314,  ..., 0.1059, 0.1020, 0.1020],
           [0.2157, 0.2157, 0.2196,  ..., 0.1059, 0.1020, 0.1020]],
 
          [[0.1686, 0.1608, 0.1529,  ..., 0.7137, 0.7098, 0.7020],
           [0.1804, 0.1647, 0.1529,  ..., 0.7098, 0.7020, 0.6980],
           [0.1804, 0.1725, 0.1608,  ..., 0.7020, 0.6980, 0.6941],
           ...,
           [0.2667, 0.2706, 0.2745,  ..., 0.1294, 0.1255, 0.1216],
           [0.2588, 0.2627, 0.2667,  ..., 0.1294, 0.1255, 0.1216],
           [0.2549, 0.2549, 0.2588,  ..., 0.1294, 0.1255, 0.1216]],
 
          [[0.1137, 0.1020, 0.0902,  ..., 0.6941, 0.6902, 0.6941],
           [0.1176, 0.1098, 0.0980,  ..., 0.6902, 0.6824, 0.6784],
           [0.1216, 0.1098, 0.1020,  ..., 0.6784, 0.6745, 0.6706],
           ...,
           [0.0431, 0.0471, 0.0510,  ..., 0.0275, 0.0235, 0.0314],
           [0.0235, 0.0275, 0.0392,  ..., 0.0275, 0.0235, 0.0314],
           [0.0196, 0.0196, 0.0235,  ..., 0.0275, 0.0235, 0.0314]]],
 
 
         [[[0.1059, 0.1059, 0.1059,  ..., 0.5216, 0.5569, 0.5843],
           [0.1137, 0.1137, 0.1137,  ..., 0.5333, 0.5569, 0.5804],
           [0.1098, 0.1098, 0.1098,  ..., 0.5490, 0.5647, 0.5804],
           ...,
           [0.0549, 0.0549, 0.0549,  ..., 0.4824, 0.4627, 0.4471],
           [0.0549, 0.0549, 0.0549,  ..., 0.5059, 0.4863, 0.4706],
           [0.0549, 0.0549, 0.0549,  ..., 0.5098, 0.4902, 0.4745]],
 
          [[0.0824, 0.0824, 0.0824,  ..., 0.2745, 0.2824, 0.2980],
           [0.0784, 0.0784, 0.0784,  ..., 0.2863, 0.2824, 0.2941],
           [0.0745, 0.0745, 0.0745,  ..., 0.2980, 0.2863, 0.2902],
           ...,
           [0.0471, 0.0471, 0.0471,  ..., 0.3294, 0.3176, 0.3020],
           [0.0471, 0.0471, 0.0471,  ..., 0.3490, 0.3333, 0.3176],
           [0.0471, 0.0471, 0.0471,  ..., 0.3569, 0.3333, 0.3176]],
 
          [[0.0902, 0.0902, 0.0902,  ..., 0.5490, 0.5647, 0.5843],
           [0.0902, 0.0902, 0.0902,  ..., 0.5725, 0.5725, 0.5843],
           [0.0863, 0.0863, 0.0863,  ..., 0.5961, 0.5843, 0.5843],
           ...,
           [0.0510, 0.0510, 0.0510,  ..., 0.2784, 0.2667, 0.2588],
           [0.0510, 0.0510, 0.0510,  ..., 0.3020, 0.2824, 0.2706],
           [0.0510, 0.0510, 0.0510,  ..., 0.2980, 0.2863, 0.2706]]]]),
 tensor([1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0]))

Apologies for asking soo many questions.
Once again thank you for helping me so far.

I’m not completely sure, if you are trying to pass the raw logits/probabilities to the classification_report, but as the docs explain a 1D array containing the predictions is expected.
Here is a small example for 10 classes using 100 samples:

y = np.random.randint(0, 10, (100,))
pred = np.random.randint(0, 10, (100,))

print(classification_report(y, pred))
>               precision    recall  f1-score   support
  
             0       0.12      0.08      0.10        13
             1       0.00      0.00      0.00        10
             2       0.20      0.10      0.13        10
             3       0.07      0.08      0.07        12
             4       0.38      0.27      0.32        11
             5       0.07      0.07      0.07        14
             6       0.29      0.29      0.29         7
             7       0.00      0.00      0.00         4
             8       0.08      0.11      0.10         9
             9       0.17      0.10      0.12        10

      accuracy                           0.11       100
     macro avg       0.14      0.11      0.12       100
  weighted avg       0.14      0.11      0.12       100

If you are dealing with a multi-class classification and your model outputs logits or (log)probabilities, use preds = torch.argmax(output, dim=1) to get the predicted class labels.
Afterwards flatten both tensors, if the method raises a shape error.

1 Like