[PYTHON] Rendre les indicateurs de performance plus visibles avec PyTorch et scikit-learn

introduction

Je l'ai écrit parce que je veux laisser un index autre que le code que je pensais facile à voir pendant que je résolvais le problème de classification.

code only Le code dans PyTorch Transfer Learning Tutorial (1) a été amélioré. Ne vous fâchez pas car l'importation n'est pas tellement ...

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
import numpy as np
import torchvision
from torchvision import datasets, models, transforms
import matplotlib.pyplot as plt
import time
import os
import copy
from PIL import Image
from sklearn.metrics import *
import pandas as pd
from torch.utils.tensorboard import SummaryWriter
import datetime


def train_model(model, criterion, optimizer, scheduler, num_epochs=25, save_model_name="vgg16_transferlearning"):
    writer = SummaryWriter()
    save_model_dir="H:\model"
    os.makedirs(save_model_dir, exist_ok=True)
    d = datetime.datetime.now()
    save_day = "{}_{}{}_{}-{}".format(d.year, d.month, d.day, d.hour, d.minute)
    since = time.time()

    best_model_wts = copy.deepcopy(model.state_dict())
    best_acc = 0.0
    best_precision = 0.0

    for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch, num_epochs - 1))
        print('-' * 10)

        # Each epoch has a training and validation phase
        for phase in ['train', 'val']:
            if phase == 'train':
                model.train()  # Set model to training mode
            else:
                model.eval()   # Set model to evaluate mode
            
            #Fonction de perte et taux de réponse correct?
            running_loss = 0.0
            running_corrects = 0

            # Iterate over data.
            for inputs, labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                # zero the parameter gradients
                optimizer.zero_grad()

                # forward
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    # row
                    axis = 1
                    _, preds = torch.max(outputs, axis)
                    #Perte en utilisant la fonction de perte(loss)Calculer
                    loss = criterion(outputs, labels) 

                    # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                #statistiques Évaluation de l'apprentissage et statistiques
                running_loss += loss.item() * inputs.size(0) # inputs.size(0) == batchsize
                running_corrects += torch.sum(preds == labels.data)
            if phase == 'train':
                scheduler.step()
                if epoch%10 == 0:
                    torch.save(model_ft.state_dict(), os.path.join(save_model_dir, save_model_name+"_{}_{}.pkl".format(epoch, save_day)))
                    print("saving model epoch :{}".format(epoch))
                    
            #Élément d'évaluation(loss, accracy, recall, precision)
            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() / dataset_sizes[phase]
            epoch_recall = recall_score(y_true=labels.cpu(), y_pred=preds.cpu(), pos_label=0)
            epoch_precision = precision_score(y_true=labels.cpu(), y_pred=preds.cpu(), pos_label=0)
            
            writer.add_scalar('Loss/{}'.format(phase), epoch_loss, epoch)
            writer.add_scalar('Accuracy/{}'.format(phase), epoch_acc, epoch)
            writer.add_scalar('Recall/{}'.format(phase), epoch_recall, epoch)
            writer.add_scalar('Precision/{}'.format(phase), epoch_precision, epoch)
            
            print('{} Loss: {:.4f} Acc: {:.4f} Recall: {:.4f} Precision: {:.4f}'.format(
                phase, epoch_loss, epoch_acc, epoch_recall, epoch_precision))

            # deep copy the model
            if phase == 'val' and epoch_acc > best_acc:
                if epoch_recall==1 and epoch_precision > best_precision:
                    torch.save(model_ft.state_dict(), 
                               os.path.join(save_model_dir, save_model_name+"_{}_{}_recall_1.0.pkl".format(epoch, save_day)))
                    print("saving model recall=1.0 epoch :{}".format(epoch))
                    recall_1_precision = epoch_precision
                best_precision = epoch_precision
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy(model.state_dict())
        print()

    time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(
        time_elapsed // 60, time_elapsed % 60))
    print('Best val Acc: {:4f}, Precision: {:.4f}'.format(best_acc, best_precision))

    # load best model weights
    model.load_state_dict(best_model_wts)
    torch.save(model_ft.state_dict(), 
               os.path.join(save_model_dir, save_model_name+"_{}_{}_best.pkl".format(epoch, save_day)))
    writer.close()
    
    return model

Courez avec ça

model_ft = model_ft.to(device)
criterion = nn.CrossEntropyLoss()
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1) #Je ne comprends pas


# Writer will output to ./runs/ directory by default
writer = SummaryWriter()
dummy_iamge = torch.rand(inputs.shape[0:])
print(dummy_iamge.shape)
dummy_iamge = dummy_iamge.to(device)
writer.add_graph(model_ft, dummy_iamge)
writer.close()
model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=25)

production

Epoch 0/24
----------
saving model epoch :0
train Loss: 0.6785 Acc: 0.5913 Recall: 1.0000 Precision: 1.0000
val Loss: 0.6839 Acc: 0.4138 Recall: 0.3012 Precision: 1.0000

Epoch 1/24
----------
train Loss: 0.5544 Acc: 0.7340 Recall: 1.0000 Precision: 1.0000
val Loss: 0.2682 Acc: 0.9475 Recall: 1.0000 Precision: 0.9765

.....

Epoch 24/24
----------
train Loss: 0.0956 Acc: 0.9738 Recall: 1.0000 Precision: 1.0000
val Loss: 0.0232 Acc: 1.0000 Recall: 1.0000 Precision: 1.0000

Training complete in 6m 10s
Best val Acc: 1.000000, Precision: 1.0000

Indicateurs de performance et outils utilisés

Raison de l'utilisation

La principale raison de déménager à Pytorch était que Tensorboard pouvait être utilisé tel quel. Cette fois, je pense principalement aux problèmes de classification, j'ai donc voulu utiliser une matrice de confusion pour obtenir le rappel et la précision. Enfin, j'ai pu confirmer l'exactitude, la perte, le rappel et la précision dans le Tensorboard, donc je suis content.

à la fin

Après tout, ce serait bien de pouvoir le visualiser lors de l'évaluation des performances ~ Les informations sont emballées en 2 dimensions plutôt qu'en 1 dimension. Cependant, soyez prudent car si vous emballez trop d'informations, les informations deviendront compliquées et illisibles.

Veuillez indiquer s'il existe une meilleure façon de l'écrire.

référence

(1) TRANSFER LEARNING FOR COMPUTER VISION TUTORIAL

Recommended Posts

Rendre les indicateurs de performance plus visibles avec PyTorch et scikit-learn
Segmentation d'image avec scikit-image et scikit-learn
Des tests plus familiers avec Selenium
Fractal pour faire et jouer avec Python
Créez un quiz de dessin avec kivy + PyTorch
Fabriquez un thermomètre avec Raspberry Pi et rendez-le visible sur le navigateur Partie 3
[# 1] Créez Minecraft avec Python. ~ Recherche préliminaire et conception ~