Eseguire il training del modello di classificatore di immagini con PyTorch
Nella fase precedente di questa esercitazione è stato acquisito il set di dati che verrà usato per eseguire il training del classificatore di immagini con PyTorch. Ora è il momento di inserire i dati da usare.
Per eseguire il training del classificatore di immagini con PyTorch, è necessario completare i passaggi seguenti:
- Caricare i dati. Se il passaggio precedente di questa esercitazione è già stato eseguito, questo è già stato gestito.
- Definire una rete neurale convoluzione.
- Definire una funzione di perdita.
- Eseguire il training del modello sui dati di training.
- Testare la rete sui dati di test.
Definire una rete neurale convoluzione.
Per creare una rete neurale con PyTorch, si userà il torch.nn
pacchetto . Questo pacchetto contiene moduli, classi estendibili e tutti i componenti necessari per creare reti neurali.
In questo caso si creerà una rete neurale convoluzione di base (CNN) per classificare le immagini dal set di dati CIFAR10.
Una cnn è una classe di reti neurali, definite come reti neurali a più livelli progettate per rilevare funzionalità complesse nei dati. Vengono usati più comunemente nelle applicazioni di visione artificiale.
La nostra rete sarà strutturata con i 14 livelli seguenti:
Conv -> BatchNorm -> ReLU -> Conv -> BatchNorm -> ReLU -> MaxPool -> Conv -> BatchNorm -> ReLU -> Conv -> BatchNorm -> ReLU -> Linear
.
Livello di convoluzione
Il livello di convoluzione è un livello principale della CNN che ci aiuta a rilevare le funzionalità nelle immagini. Ognuno dei livelli ha un numero di canali per rilevare funzionalità specifiche nelle immagini e un certo numero di kernel per definire le dimensioni della funzionalità rilevata. Pertanto, un livello di convoluzione con 64 canali e dimensioni del kernel pari a 3 x 3 rileverebbe 64 caratteristiche distinte, ognuna delle dimensioni 3 x 3. Quando si definisce un livello di convoluzione, si specifica il numero di canali, il numero di canali out e le dimensioni del kernel. Il numero di canali out nel livello funge da numero di canali al livello successivo.
Ad esempio: un livello di convoluzione con in-channels=3, out-channels=10 e kernel-size=6 otterrà l'immagine RGB (3 canali) come input e applicherà 10 rilevatori di funzionalità alle immagini con le dimensioni del kernel pari a 6x6. Le dimensioni del kernel più piccole ridurranno il tempo di calcolo e la condivisione del peso.
Altri livelli
Nella rete sono coinvolti gli altri livelli seguenti:
- Il
ReLU
livello è una funzione di attivazione per definire tutte le funzionalità in ingresso da 0 o superiore. Quando si applica questo livello, qualsiasi numero minore di 0 viene modificato in zero, mentre altri vengono mantenuti uguali. - il
BatchNorm2d
livello applica la normalizzazione negli input per avere zero media e varianza unità e aumentare l'accuratezza della rete. - Il
MaxPool
livello ci aiuterà a garantire che la posizione di un oggetto in un'immagine non influirà sulla capacità della rete neurale di rilevare le sue caratteristiche specifiche. - Il
Linear
livello è il livello finale della rete, che calcola i punteggi di ognuna delle classi. Nel set di dati CIFAR10 sono disponibili dieci classi di etichette. L'etichetta con il punteggio più alto sarà quella prevista dal modello. Nel livello lineare è necessario specificare il numero di funzionalità di input e il numero di funzionalità di output che devono corrispondere al numero di classi.
Come funziona una rete neurale?
La CNN è una rete di inoltro dei feed. Durante il processo di training, la rete elabora l'input attraverso tutti i livelli, calcola la perdita per comprendere quanto l'etichetta stimata dell'immagine sta cadendo da quella corretta e propaga le sfumature nella rete per aggiornare i pesi dei livelli. Eseguendo l'iterazione su un set di dati enorme di input, la rete "apprendo" per impostare i suoi pesi per ottenere i risultati migliori.
Una funzione forward calcola il valore della funzione di perdita e la funzione indietro calcola le sfumature dei parametri appresi. Quando si crea la rete neurale con PyTorch, è sufficiente definire la funzione forward. La funzione all'indietro verrà definita automaticamente.
- Copiare il codice seguente nel
PyTorchTraining.py
file in Visual Studio per definire il CCN.
import torch
import torch.nn as nn
import torchvision
import torch.nn.functional as F
# Define a convolution neural network
class Network(nn.Module):
def __init__(self):
super(Network, self).__init__()
self.conv1 = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=5, stride=1, padding=1)
self.bn1 = nn.BatchNorm2d(12)
self.conv2 = nn.Conv2d(in_channels=12, out_channels=12, kernel_size=5, stride=1, padding=1)
self.bn2 = nn.BatchNorm2d(12)
self.pool = nn.MaxPool2d(2,2)
self.conv4 = nn.Conv2d(in_channels=12, out_channels=24, kernel_size=5, stride=1, padding=1)
self.bn4 = nn.BatchNorm2d(24)
self.conv5 = nn.Conv2d(in_channels=24, out_channels=24, kernel_size=5, stride=1, padding=1)
self.bn5 = nn.BatchNorm2d(24)
self.fc1 = nn.Linear(24*10*10, 10)
def forward(self, input):
output = F.relu(self.bn1(self.conv1(input)))
output = F.relu(self.bn2(self.conv2(output)))
output = self.pool(output)
output = F.relu(self.bn4(self.conv4(output)))
output = F.relu(self.bn5(self.conv5(output)))
output = output.view(-1, 24*10*10)
output = self.fc1(output)
return output
# Instantiate a neural network model
model = Network()
Nota
Per altre informazioni sulla rete neurale, vedere PyTorch? Vedere la documentazione di PyTorch
Definire una funzione di perdita
Una funzione di perdita calcola un valore che stima la distanza dell'output dalla destinazione. L'obiettivo principale è ridurre il valore della funzione di perdita modificando i valori del vettore di peso tramite backpropagation nelle reti neurali.
Il valore della perdita è diverso dall'accuratezza del modello. La funzione di perdita offre la comprensione del comportamento di un modello dopo ogni iterazione dell'ottimizzazione nel set di training. L'accuratezza del modello viene calcolata sui dati di test e mostra la percentuale della stima corretta.
In PyTorch il pacchetto di rete neurale contiene varie funzioni di perdita che costituiscono i blocchi predefiniti delle reti neurali profonde. In questa esercitazione si userà una funzione di perdita di classificazione basata su Definire la funzione di perdita con la perdita tra entropia di classificazione e Adam Optimizer. La frequenza di apprendimento (lr) imposta il controllo della quantità di peso che si sta regolando i pesi della rete rispetto al gradiente di perdita. Verrà impostato come 0.001. Più basso è, più lento sarà il training.
- Copiare il codice seguente nel
PyTorchTraining.py
file in Visual Studio per definire la funzione di perdita e un ottimizzatore.
from torch.optim import Adam
# Define the loss function with Classification Cross-Entropy loss and an optimizer with Adam optimizer
loss_fn = nn.CrossEntropyLoss()
optimizer = Adam(model.parameters(), lr=0.001, weight_decay=0.0001)
Eseguire il training del modello sui dati di training.
Per eseguire il training del modello, è necessario eseguire il ciclo sull'iteratore dei dati, inserire gli input nella rete e ottimizzare. PyTorch non ha una libreria dedicata per l'uso della GPU, ma è possibile definire manualmente il dispositivo di esecuzione. Il dispositivo sarà una GPU Nvidia, se presente nel computer, o la CPU in caso contrario.
- Aggiungere il codice seguente al
PyTorchTraining.py
file
from torch.autograd import Variable
# Function to save the model
def saveModel():
path = "./myFirstModel.pth"
torch.save(model.state_dict(), path)
# Function to test the model with the test dataset and print the accuracy for the test images
def testAccuracy():
model.eval()
accuracy = 0.0
total = 0.0
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
with torch.no_grad():
for data in test_loader:
images, labels = data
# run the model on the test set to predict labels
outputs = model(images.to(device))
# the label with the highest energy will be our prediction
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
accuracy += (predicted == labels.to(device)).sum().item()
# compute the accuracy over all test images
accuracy = (100 * accuracy / total)
return(accuracy)
# Training function. We simply have to loop over our data iterator and feed the inputs to the network and optimize.
def train(num_epochs):
best_accuracy = 0.0
# Define your execution device
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print("The model will be running on", device, "device")
# Convert model parameters and buffers to CPU or Cuda
model.to(device)
for epoch in range(num_epochs): # loop over the dataset multiple times
running_loss = 0.0
running_acc = 0.0
for i, (images, labels) in enumerate(train_loader, 0):
# get the inputs
images = Variable(images.to(device))
labels = Variable(labels.to(device))
# zero the parameter gradients
optimizer.zero_grad()
# predict classes using images from the training set
outputs = model(images)
# compute the loss based on model output and real labels
loss = loss_fn(outputs, labels)
# backpropagate the loss
loss.backward()
# adjust parameters based on the calculated gradients
optimizer.step()
# Let's print statistics for every 1,000 images
running_loss += loss.item() # extract the loss value
if i % 1000 == 999:
# print every 1000 (twice per epoch)
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 1000))
# zero the loss
running_loss = 0.0
# Compute and print the average accuracy fo this epoch when tested over all 10000 test images
accuracy = testAccuracy()
print('For epoch', epoch+1,'the test accuracy over the whole test set is %d %%' % (accuracy))
# we want to save the model if the accuracy is the best
if accuracy > best_accuracy:
saveModel()
best_accuracy = accuracy
Testare il modello sui dati di test.
È ora possibile testare il modello con batch di immagini dal set di test.
- Aggiungere il codice seguente al file
PyTorchTraining.py
.
import matplotlib.pyplot as plt
import numpy as np
# Function to show the images
def imageshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
# Function to test the model with a batch of images and show the labels predictions
def testBatch():
# get batch of images from the test DataLoader
images, labels = next(iter(test_loader))
# show all images as one image grid
imageshow(torchvision.utils.make_grid(images))
# Show the real labels on the screen
print('Real labels: ', ' '.join('%5s' % classes[labels[j]]
for j in range(batch_size)))
# Let's see what if the model identifiers the labels of those example
outputs = model(images)
# We got the probability for every 10 labels. The highest (max) probability should be correct label
_, predicted = torch.max(outputs, 1)
# Let's show the predicted labels on the screen to compare with the real ones
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
for j in range(batch_size)))
Aggiungere infine il codice principale. Verrà avviato il training del modello, salvato il modello e verranno visualizzati i risultati sullo schermo. Verranno eseguite solo due iterazioni [train(2)]
sul set di training, quindi il processo di training non richiederà troppo tempo.
- Aggiungere il codice seguente al file
PyTorchTraining.py
.
if __name__ == "__main__":
# Let's build our model
train(5)
print('Finished Training')
# Test which classes performed well
testAccuracy()
# Let's load the model we just created and test the accuracy per label
model = Network()
path = "myFirstModel.pth"
model.load_state_dict(torch.load(path))
# Test with batch of images
testBatch()
Eseguiamo il test. Assicurarsi che i menu a discesa nella barra degli strumenti superiore siano impostati su Debug. Impostare Solution Platform su x64 per eseguire il progetto nel computer locale se il dispositivo è a 64 bit o x86 se è a 32 bit.
La scelta del numero di periodo (il numero di completamento passa attraverso il set di dati di training) uguale a due ([train(2)]
) comporterà l'iterazione due volte nell'intero set di dati di test di 10.000 immagini. Il completamento del training sulla CPU Intel di 8 generazione richiederà circa 20 minuti e il modello dovrebbe raggiungere più o meno il 65% della percentuale di successo nella classificazione di dieci etichette.
- Per eseguire il progetto, fai clic sul pulsante Avvia debug sulla barra degli strumenti oppure premi F5.
Verrà visualizzata la finestra della console e sarà possibile visualizzare il processo di training.
Come definito, il valore di perdita verrà stampato ogni 1.000 batch di immagini o cinque volte per ogni iterazione nel set di training. Si prevede che il valore di perdita diminuisca con ogni ciclo.
Si noterà anche l'accuratezza del modello dopo ogni iterazione. L'accuratezza del modello è diversa dal valore di perdita. La funzione di perdita offre la comprensione del comportamento di un modello dopo ogni iterazione dell'ottimizzazione nel set di training. L'accuratezza del modello viene calcolata sui dati di test e mostra la percentuale della stima corretta. In questo caso, indica quante immagini del set di test di 10.000 immagini sono state in grado di classificare correttamente dopo ogni iterazione di training.
Al termine del training, si dovrebbe prevedere di visualizzare l'output simile al seguente. I numeri non saranno esattamente uguali, a seconda di molti fattori e non restituiranno sempre risultati identificali, ma dovrebbero essere simili.
Dopo l'esecuzione di soli 5 periodi, la percentuale di successo del modello è del 70%. Questo è un buon risultato per un modello di base sottoposto a training per un breve periodo di tempo.
Il test con il batch di immagini, il modello ha ottenuto correttamente 7 immagini dal batch di 10. Non è affatto male e coerente con la percentuale di successo del modello.
È possibile verificare le classi che il modello può stimare al meglio. Aggiungere semplicemente l'esecuzione del codice seguente:
- Facoltativo : aggiungere la funzione seguente
testClassess
nelPyTorchTraining.py
file , aggiungere una chiamata di questa funzione all'internotestClassess()
della funzione main -__name__ == "__main__"
.
# Function to test what classes performed well
def testClassess():
class_correct = list(0. for i in range(number_of_labels))
class_total = list(0. for i in range(number_of_labels))
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs, 1)
c = (predicted == labels).squeeze()
for i in range(batch_size):
label = labels[i]
class_correct[label] += c[i].item()
class_total[label] += 1
for i in range(number_of_labels):
print('Accuracy of %5s : %2d %%' % (
classes[i], 100 * class_correct[i] / class_total[i]))
L'output è il seguente:
Passaggi successivi
Ora che è disponibile un modello di classificazione, il passaggio successivo consiste nel convertire il modello nel formato ONNX