[PYTHON] Classification CIFAR-10 implémentée dans près de 60 lignes dans PyTorch

Aperçu

Je n'ai pas encore implémenté le deep learning, donc j'aimerais mettre en place le deep learning pour le moment! Ceci est un article pour ceux qui disent.

Cette fois, nous avons tout mis en œuvre, de la lecture des données d'image à la sortie des erreurs d'entraînement et des erreurs de généralisation dans un graphique simple en 60 lignes.

"Réel" signifie que vous ne considérez pas les sauts de ligne ou les instructions de commentaire pour rendre le code plus facile à lire, et le code réel est d'environ 100 lignes.

** Je mettrai le code complet à la fin de l'article **

Flux de processus

En gros, le flux est le suivant.

Jetons un coup d'œil au code source.

Quoi importer

Tout d'abord, importons d'abord la bibliothèque, etc. utilisée cette fois.

test.py


import torch
import numpy as np
import torch.nn as nn
from torch import optim
import torch.nn.init as init
import torchvision.transforms as transforms
from torchvision import models
from torch.utils.data import Dataset,DataLoader
import torchvision.datasets as dsets
import matplotlib.pyplot as plt

Il y a 10 lignes à lui seul (rires)

Préparation des données

Les données d'image utilisent un célèbre jeu de données appelé CIFAR-10.

10 signifie qu'il y a 10 classes, donc 50 000 images de formation (5 000 pour chaque classe) et 10 000 images de test (1 000 pour chaque classe) sont préparées.

Vous pouvez charger CIFAR-10 comme suit.

test.py


#Chargement des images
batch_size = 100

train_data = dsets.CIFAR10(root='./tmp/cifar-10', train=True, download=False, transform=transforms.Compose([transforms.RandomHorizontalFlip(p=0.5), transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]), transforms.RandomErasing(p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=0, inplace=False)]))

train_loader = DataLoader(train_data,batch_size=batch_size,shuffle=True)

test_data = dsets.CIFAR10(root='./tmp/cifar-10', train=False, download=False, transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]))

test_loader = DataLoader(test_data,batch_size=batch_size,shuffle=False)

Définissez download = True pour la première fois. L'ensemble de données CIFAR-10 sera téléchargé.

Il y a un point long avec transform = transforms.Compose ([...]), mais c'est un élément pour traiter les données d'image de différentes manières.

--RandomHorizonalFlip: Retourner l'image à gauche et à droite --ToTensor: conversion Tensol --Normaliser: normaliser --RandomErasing: ajoute du bruit à une partie des données

Je me sens dit. Il a pour effet de faciliter le calcul et d'éviter le surapprentissage par l'augmentation des données.

Il existe de nombreuses autres transformations, veuillez donc vous référer à ici.

Vérifiez si le GPU peut être utilisé

Avant de définir le modèle, vérifiez s'il peut être calculé à l'aide du GPU. Il est recommandé de pouvoir utiliser le GPU car il sera plusieurs fois plus rapide.

test.py


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

Si le GPU peut être utilisé, il sera sorti en tant que cuda, et si seul le CPU peut être utilisé, il sera sorti en tant que cpu.

Définition du modèle

C'est un modèle essentiel pour l'apprentissage en profondeur, mais vous pouvez désormais gérer d'excellents modèles sans avoir à penser au modèle vous-même.

Cette fois, nous utiliserons un modèle appelé Resnet.

test.py


model_ft = models.resnet50(pretrained=True)
model_ft.fc = nn.Linear(model_ft.fc.in_features, 10)
net = model_ft.to(device)

models.resnet50 (pretrained = True) vous permet d'utiliser les modèles entraînés de Resnet. C'est facile ...

Au fait, si vous définissez pretrained = False, vous pouvez utiliser Resnet que vous n'avez pas encore appris, mais il est recommandé de le définir sur True car le temps d'apprentissage est long.

La deuxième ligne a une couche de sortie de 10. Cela peut être 40 ou 100.

La troisième ligne affecte le modèle à une variable appelée net. Dans .to (appareil), si vous pouvez utiliser le GPU, il sera calculé par GPU (divers)

Définition de la fonction de perte / méthode d'optimisation

Pour que le modèle apprenne, la fonction de perte doit donner une erreur de la bonne réponse. Et la méthode pour réduire l'erreur est l'optimisation.

Ici, nous utilisons l'entropie croisée pour la fonction de perte et SGD pour l'algorithme d'optimisation.

test.py


criterion = nn.CrossEntropyLoss()

optimizer = optim.SGD(net.parameters(),lr=0.01,momentum=0.9,weight_decay=0.00005)

lr est le taux d'apprentissage, qui ne peut être ni trop grand ni trop petit. Ici, il est défini sur 0,01.

weight_decay est appelé "atténuation du poids" et est également l'une des méthodes de régularisation pour éviter le surapprentissage.

Apprentissage / raisonnement

Maintenant que nous sommes prêts, nous allons entrer dans la phase d'apprentissage / raisonnement.

test.py


loss,epoch_loss,count = 0,0,0
acc_list = []
loss_list = []
for i in range(50):
  
  #Apprenez d'ici
  net.train()
  
  for j,data in enumerate(train_loader,0):
    optimizer.zero_grad()

    #1:Lire les données d'entraînement
    inputs,labels = data
    inputs = inputs.to(device)
    labels = labels.to(device)

    #2:calculer
    outputs = net(inputs)

    #3:Trouvez l'erreur
    loss = criterion(outputs,labels)

    #4:Apprendre de l'erreur
    loss.backward()
    optimizer.step()

    epoch_loss += loss
    count += 1
    print('%d: %.3f'%(j+1,loss))

  print('%depoch:mean_loss=%.3f\n'%(i+1,epoch_loss/count))
  loss_list.append(epoch_loss/count)

  epoch_loss = 0
  count = 0
  correct = 0
  total = 0
  accuracy = 0.0

  #Déduit d'ici
  net.eval()
 
  for j,data in enumerate(test_loader,0):

    #Préparer les données de test
    inputs,labels = data
    inputs = inputs.to(device)
    labels = labels.to(device)

    #calculer
    outputs = net(inputs)

    #Trouvez la valeur prévue
    _,predicted = torch.max(outputs.data,1)

    #Calculer la précision
    correct += (predicted == labels).sum()
    total += batch_size

  accuracy = 100.*correct / total
  acc_list.append(accuracy)

  print('epoch:%d Accuracy(%d/%d):%f'%(i+1,correct,total,accuracy))
  torch.save(net.state_dict(),'Weight'+str(i+1))

C'est un peu long.

La phase d'apprentissage va de net.train () à avant net.eval (), et la phase d'inférence est après net.eval ().

Phase d'apprentissage

Dans le code ci-dessus, la phase d'apprentissage est

  1. Lire les données d'entraînement
  2. Calculez
  3. Trouvez la différence entre la valeur prévue et la valeur réelle
  4. Apprenez de l'erreur de 3

C'est devenu un flux.

Les images sont chargées par batch_size (← défini dans "Preparing data") dans une boucle de l'instruction for. L'instruction for se termine lorsque toutes les images d'entraînement sont chargées.

(Exemple) S'il y a 50 000 données d'apprentissage et que la taille du lot est de 100, le nombre de boucles est de 500.

Phase d'inférence

Dans le code ci-dessus, la phase d'inférence est

  1. Lire les données de test
  2. Calculez
  3. Trouvez la valeur prévue
  4. Trouvez la précision (taux de réponse correct)

C'est devenu un flux.

1 et 2 sont les mêmes que lors de l'apprentissage.

En 3, la valeur prédite est calculée. C'est comme "Cette image est de classe 5!" En fait, la valeur obtenue dans le calcul de 2 est ** la probabilité que l'image lue soit classée dans chaque classe **.

Par exemple, si vous lisez une image et sortez [0.01,0.04,0.95],

La probabilité d'être en classe 1 est de 0,01 (1%) La probabilité d'être en classe 2 est de 0,04 (4%) La probabilité d'être en classe 3 est de 0,95 (95%)

Cela signifie que.

Et dans ce cas, la valeur prédite est la classe 3.

torch.save (net.state_dict (), 'Weight' + str (i + 1)) peut sauvegarder les poids appris.

Sortie graphique

Une liste appelée acc_list et loss_list a été définie dans la phase d'apprentissage / inférence, mais il s'agit d'une liste qui stocke l'erreur d'apprentissage et la précision pour chaque époque.

Pour représenter graphiquement cela, procédez comme suit:

test.py


plt.plot(acc_list)
plt.show(acc_list)
plt.plot(loss_list)
plt.show(loss_list)

Il s'agit de la méthode de sortie graphique la plus simple.

À propos, la sortie du graphique lorsque ce code est exécuté est la suivante. précision acc_short.png Erreur d'entraînement loss_short.png

La précision chute pendant un moment autour de 8,9 époques. La précision est inférieure à 88%.

finalement

Cette fois, il s'agissait d'un article sur la mise en œuvre d'une série de flux d'apprentissage profond en 60 lignes.

** Bien sûr, plus d'ingéniosité est nécessaire pour améliorer la précision **, mais si vous souhaitez implémenter l'infrastructure pour le moment, veuillez vous y référer.

Enfin, je vais mettre tout le code ici.

test.py


import torch
import numpy as np
import torch.nn as nn
from torch import optim
import torch.nn.init as init
import torchvision.transforms as transforms
from torchvision import models
from torch.utils.data import Dataset,DataLoader
import torchvision.datasets as dsets
import matplotlib.pyplot as plt

#Chargement des images
batch_size = 100
train_data = dsets.CIFAR10(root='./tmp/cifar-10', train=True, download=False, transform=transforms.Compose([transforms.RandomHorizontalFlip(p=0.5), transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]), transforms.RandomErasing(p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=0, inplace=False)]))
train_loader = DataLoader(train_data,batch_size=batch_size,shuffle=True)
test_data = dsets.CIFAR10(root='./tmp/cifar-10', train=False, download=False, transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]))
test_loader = DataLoader(test_data,batch_size=batch_size,shuffle=False)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

model_ft = models.resnet50(pretrained=True)
model_ft.fc = nn.Linear(model_ft.fc.in_features, 10)
net = model_ft.to(device)

criterion = nn.CrossEntropyLoss()

optimizer = optim.SGD(net.parameters(),lr=0.01,momentum=0.9,weight_decay=0.00005)

loss, epoch_loss, count = 0, 0, 0
acc_list = []
loss_list = []

#Formation / raisonnement
for i in range(50):
  
  #Apprenez d'ici
  net.train()
  
  for j,data in enumerate(train_loader,0):
    optimizer.zero_grad()

    #1:Lire les données d'entraînement
    inputs,labels = data
    inputs = inputs.to(device)
    labels = labels.to(device)

    #2:calculer
    outputs = net(inputs)

    #3:Trouvez l'erreur
    loss = criterion(outputs,labels)

    #4:Apprendre de l'erreur
    loss.backward()
    optimizer.step()

    epoch_loss += loss
    count += 1
    print('%d: %.3f'%(j+1,loss))

  print('%depoch:mean_loss=%.3f\n'%(i+1,epoch_loss/count))
  loss_list.append(epoch_loss/count)

  epoch_loss, count = 0, 0
  correct,total = 0, 0
  accuracy = 0.0

  #Déduit d'ici
  net.eval()
 
  for j,data in enumerate(test_loader,0):

    #Préparer les données de test
    inputs,labels = data
    inputs = inputs.to(device)
    labels = labels.to(device)

    #calculer
    outputs = net(inputs)

    #Trouvez la valeur prévue
    _,predicted = torch.max(outputs.data,1)

    #Calculer la précision
    correct += (predicted == labels).sum()
    total += batch_size

  accuracy = 100.*correct / total
  acc_list.append(accuracy)

  print('epoch:%d Accuracy(%d/%d):%f'%(i+1,correct,total,accuracy))
  torch.save(net.state_dict(),'Weight'+str(i+1))

plt.plot(acc_list)
plt.show(acc_list)
plt.plot(loss_list)
plt.show(loss_list)

Recommended Posts

Classification CIFAR-10 implémentée dans près de 60 lignes dans PyTorch
[PyTorch] Classification des images du CIFAR-10
Implémenté en Python PRML Chapitre 4 Classification par algorithme Perceptron
Implémentation de SimRank en Python
Implémentation hard-swish avec Keras
Implémentation de Shiritori en Python