hot_rod
hot_rod

Reputation: 1

PyTorch: Confusion Matrix for Transfer Learning

I've been trying to plot a confusion matrix for the below code - check def train_alexnet(). But I keep getting this error:

IndexError: only integers, slices (`:`), ellipsis (`...`), None and long or byte Variables are valid indices (got float)

So, I tried converting my tensors to an integer tensor but then got the error:

ValueError: only one element tensors can be converted to Python scalars

Can someone suggest me what can be done to convert the tensors 'all_preds' and 'source_value' to tensors containing integer values? I found the torch no grad option but I am unaware as to how to use it because I'm new to pytorch.

Here's the link of the github repo that I'm trying to work with: https://github.com/syorami/DDC-transfer-learning/blob/master/DDC.py

from __future__ import print_function

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "1"

import warnings
warnings.filterwarnings('ignore')

import math
import model
import torch
import dataloader
import matplotlib.pyplot as plt
import numpy as np

import seaborn as sns
from sklearn.metrics import confusion_matrix
from plotcm import plot_confusion_matrix

from torch import nn
from torch import optim
from torch.autograd import Variable

cuda = torch.cuda.is_available()


def step_decay(epoch, learning_rate):
    
    # learning rate step decay
    # :param epoch: current training epoch
    # :param learning_rate: initial learning rate
    # :return: learning rate after step decay
    
    initial_lrate = learning_rate
    drop = 0.8
    epochs_drop = 10.0
    lrate = initial_lrate * math.pow(drop, math.floor((1 + epoch) / epochs_drop))
    return lrate



def train_alexnet(epoch, model, learning_rate, source_loader):
    
    # train source on alexnet
    # :param epoch: current training epoch
    # :param model: defined alexnet
    # :param learning_rate: initial learning rate
    # :param source_loader: source loader
    # :return:
    
    log_interval = 10
    LEARNING_RATE = step_decay(epoch, learning_rate)
    print(f'Learning Rate: {LEARNING_RATE}')
    optimizer = optim.SGD([
        {'params': model.features.parameters()},
        {'params': model.classifier.parameters()},
        {'params': model.final_classifier.parameters(), 'lr': LEARNING_RATE}
    ], lr=LEARNING_RATE / 10, momentum=MOMENTUM, weight_decay=L2_DECAY)

    # enter training mode
    model.train()

    iter_source = iter(source_loader)
    num_iter = len(source_loader)

    correct = 0
    total_loss = 0
    clf_criterion = nn.CrossEntropyLoss()
    all_preds = torch.tensor([])
    source_value = torch.tensor([])
    for i in range(1, num_iter):
        source_data, source_label = iter_source.next()

          
        # print("source label: ", source_label)
        if cuda:
            source_data, source_label = source_data.cuda(), source_label.cuda()
        source_data, source_label = Variable(source_data), Variable(source_label)

        optimizer.zero_grad()
        

        ##
        
        source_preds = model(source_data)
        
        

        preds = source_preds.data.max(1, keepdim=True)[1]
        correct += preds.eq(source_label.data.view_as(preds)).sum()
        
        
        #prediction label
        all_preds = torch.cat(
            (all_preds, preds)
            ,dim=0
            )
        
        #actual label
        source_value = torch.cat(
            (source_value,source_label)
            ,dim=0
        )
         
        loss = clf_criterion(source_preds, source_label)
        total_loss += loss


        loss.backward()
        optimizer.step()

        if i % log_interval == 0:
            print('Train Epoch {}: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, i * len(source_data), len(source_loader) * BATCH_SIZE,
                100. * i / len(source_loader), loss.item()))

    total_loss /= len(source_loader)
    acc_train = float(correct) * 100. / (len(source_loader) * BATCH_SIZE)

    # print('all preds= ',int(all_preds))
    # print("source value", int(source_value))
    stacked = torch.stack(
    (
        source_value
        ,(all_preds.argmax(dim=1))
    )
    ,dim=1
    
)   


            
    print("stacked",stacked)
    
    cmt = torch.zeros(3
        ,3, dtype=torch.float64)
    with torch.no_grad():
        for p in stacked:
            tl, pl = p.tolist()
            cmt[tl, pl] = cmt[tl, pl] + 1
    print("cmt: ",cmt)
    print('{} set: Average loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)'.format(
        SOURCE_NAME, total_loss.item(), correct, len(source_loader.dataset), acc_train))
    
  


def test_alexnet(model, target_loader):
    
    # test target data on fine-tuned alexnet
    # :param model: trained alexnet on source data set
    # :param target_loader: target dataloader
    # :return: correct num
    
    # enter evaluation mode
    clf_criterion = nn.CrossEntropyLoss()

    model.eval()
    test_loss = 0
    correct = 0

    


    
    for data, target in target_test_loader:
        if cuda:
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data, volatile=True), Variable(target)
        target_preds = model(data)
        


        test_loss += clf_criterion(target_preds, target) # sum up batch loss
        pred = target_preds.data.max(1)[1] # get the index of the max log-probability
        correct += pred.eq(target.data.view_as(pred)).cpu().sum()
        
        
    stacked = torch.stack(
    (
        target
        ,target_preds.argmax(dim=1)
    )
    ,dim=1
)
    print("stacked target",stacked)    

    test_loss /= len(target_loader)
    print('{} set: Average loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)\n'.format(
        TARGET_NAME, test_loss.item(), correct, len(target_loader.dataset),
        100. * correct / len(target_loader.dataset)))
    return correct



def compute_confusion_matrix(preds, y):
    #round predictions to the closest integer
    rounded_preds = torch.round(torch.sigmoid(preds))
    return confusion_matrix(y, rounded_preds)



if __name__ == '__main__':

    ROOT_PATH = './v1234_combined/pets'
    SOURCE_NAME = 'v123'
    TARGET_NAME = 'v4'

    BATCH_SIZE = 15
    TRAIN_EPOCHS = 1
    learning_rate = 1e-2
    L2_DECAY = 5e-4
    MOMENTUM = 0.9

    source_loader = dataloader.load_training(ROOT_PATH, SOURCE_NAME, BATCH_SIZE)
    #target_train_loader = dataloader.load_training(ROOT_PATH, TARGET_NAME, BATCH_SIZE)
    target_test_loader = dataloader.load_testing(ROOT_PATH, TARGET_NAME, BATCH_SIZE)
    print('Load data complete')


    alexnet = model.Alexnet_finetune(num_classes=3)
    print('Construct model complete')

    # load pretrained alexnet model
    alexnet = model.load_pretrained_alexnet(alexnet)
    print('Load pretrained alexnet parameters complete\n')

    

    if cuda: alexnet.cuda()

    for epoch in range(1, TRAIN_EPOCHS + 1):
        print(f'Train Epoch {epoch}:')
        train_alexnet(epoch, alexnet, learning_rate, source_loader)
        correct = test_alexnet(alexnet, target_test_loader)
    print(len(source_loader.dataset))
    
    
  


Upvotes: 0

Views: 541

Answers (1)

Shai
Shai

Reputation: 114926

In oder to conver all elements of a tensor from floats to ints, you need to use .to():

all_preds_int = all_preds.to(torch.int64)

Note that it appears as if your all_preds are the predicted class probabilities and not the actual labels. You might need to torch.argmax along the appropriate dimension. (BTW, the output of argmax is int - no need to convert).

Upvotes: 0

Related Questions