Entraîner votre modèle d’analyse de données avec PyTorch
Dans l’étape précédente de ce tutoriel, nous avons acquis le jeu de données dont nous avons besoin pour entraîner notre modèle d’analyse des données avec PyTorch. À présent, il est temps d’utiliser ces données.
Pour entraîner le modèle d’analyse des données avec PyTorch, vous devez effectuer les étapes suivantes :
- Chargez les données. Si vous avez effectué l’étape précédente de ce didacticiel, vous les avez déjà gérées.
- Définissez un réseau neuronal.
- Définissez une fonction de perte.
- Formez le modèle sur les données de formation.
- Testez le réseau sur les données de test.
Définir un réseau neuronal
Dans ce tutoriel, vous allez créer un modèle de réseau neuronal de base qui comporte trois couches linéaires. La structure du modèle est la suivante :
Linear -> ReLU -> Linear -> ReLU -> Linear
Une couche linéaire applique une transformation linéaire aux données entrantes. Vous devez spécifier le nombre de caractéristiques d’entrée et le nombre de caractéristiques de sortie qui doivent correspondre au nombre de classes.
Une couche ReLU est une fonction d’activation permettant de définir toutes les caractéristiques entrantes à une valeur supérieure ou égale à 0. Aussi, quand une couche ReLU est appliquée, tout nombre inférieur à 0 est changé en valeur zéro, tandis que les autres nombres restent inchangés. Nous appliquerons la couche d’activation sur les deux couches masquées, mais nous n’appliquerons aucune activation sur la dernière couche linéaire.
Paramètres du modèle
Les paramètres du modèle diffèrent selon l’objectif recherché et les données d’entraînement disponibles. La taille d’entrée dépend du nombre de caractéristiques qui alimentent le modèle (il y en a quatre dans notre exemple). La taille de sortie est de trois, car il y a trois types d’iris possibles.
Avec trois couches linéaires ((4,24) -> (24,24) -> (24,3)
), le réseau aura 744 pondérations (96 + 576 + 72).
Le taux d’apprentissage (lr pour learning rate) définit le contrôle de la quantité d’ajustement des pondérations de notre réseau en respectant le gradient de perte. Plus l’opération est faible, plus la formation sera lente. Vous définirez le taux lr sur 0,01 dans ce tutoriel.
Fonctionnement du réseau
Ici, nous créons un réseau à propagation avant. Au cours du processus de formation, le réseau traite l’entrée à travers toutes les couches, calcule la perte pour comprendre dans quelle mesure l’étiquette prédite de l’image s’éloigne de l’étiquette correcte, et propage les gradients dans le réseau pour mettre à jour les pondérations des couches. En effectuant une itération sur un jeu de données d’entrées volumineux, le réseau « apprend » à définir ses pondérations pour obtenir les meilleurs résultats.
Une fonction forward calcule la valeur de la fonction de perte et une fonction backward calcule les gradients des paramètres apprenables. Lorsque vous créez notre réseau neuronal avec PyTorch, vous devez définir la fonction Forward. La fonction Backward est définie automatiquement.
- Copiez le code suivant dans le fichier
DataClassifier.py
dans Visual Studio pour définir les paramètres du modèle et le réseau neuronal.
# Define model parameters
input_size = list(input.shape)[1] # = 4. The input depends on how many features we initially feed the model. In our case, there are 4 features for every predict value
learning_rate = 0.01
output_size = len(labels) # The output is prediction results for three types of Irises.
# Define neural network
class Network(nn.Module):
def __init__(self, input_size, output_size):
super(Network, self).__init__()
self.layer1 = nn.Linear(input_size, 24)
self.layer2 = nn.Linear(24, 24)
self.layer3 = nn.Linear(24, output_size)
def forward(self, x):
x1 = F.relu(self.layer1(x))
x2 = F.relu(self.layer2(x1))
x3 = self.layer3(x2)
return x3
# Instantiate the model
model = Network(input_size, output_size)
Vous devez également définir l’appareil d’exécution en fonction de celui qui est disponible sur votre ordinateur. PyTorch n’a pas de bibliothèque dédiée pour le GPU, mais vous pouvez définir manuellement l’appareil d’exécution. L’appareil sera un GPU NVIDIA s’il existe sur votre ordinateur, ou votre CPU à défaut.
- Copiez le code suivant pour définir l’appareil d’exécution :
# 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\n")
model.to(device) # Convert model parameters and buffers to CPU or Cuda
- Pour finir, définissez une fonction qui enregistre le modèle :
# Function to save the model
def saveModel():
path = "./NetModel.pth"
torch.save(model.state_dict(), path)
Remarque
Vous souhaitez en savoir plus sur le réseau neuronal avec PyTorch ? Consultez la documentation PyTorch.
Définir une fonction de perte
Une fonction de perte calcule une valeur qui estime la distance entre la sortie et la cible. L’objectif principal est de réduire la valeur de la fonction de perte en modifiant les valeurs de vecteur de pondération par le biais de la rétropropagation dans les réseaux neuronaux.
La valeur de perte est différente de la précision du modèle. La fonction de perte montre de quelle façon notre modèle se comporte après chaque itération d’optimisation sur le jeu d’entraînement. La justesse du modèle est calculée sur les données de test ; elle indique le pourcentage de prédictions qui sont exactes.
Dans PyTorch, le package de réseau neuronal contient différentes fonctions de perte qui forment les éléments constitutifs des réseaux neuronaux profonds. Si vous souhaitez en savoir plus sur ces spécificités, commencez par lire la remarque ci-dessus. Ici, nous allons utiliser les fonctions existantes optimisées pour la classification, comme celle-ci, ainsi qu’une fonction de perte d’entropie croisée de classification et un optimiseur Adam. Dans l’optimiseur, le taux d’apprentissage (lr) définit le contrôle de la quantité d’ajustement des pondérations de notre réseau en respectant le gradient de perte. Vous définirez ce taux sur 0,001 ici (plus il est bas, plus l’entraînement est lent).
- Copiez le code suivant dans le fichier
DataClassifier.py
dans Visual Studio pour définir la fonction de perte et un optimiseur.
# 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)
Formez le modèle sur les données de formation.
Pour former le modèle, vous devez effectuer une boucle sur notre itérateur de données, alimenter les entrées sur le réseau et effectuer l’optimisation. Pour valider les résultats, comparez simplement les étiquettes prédites avec les étiquettes réelles dans le jeu de données de validation après chaque époque d’entraînement.
Le programme affiche la perte d’entraînement, la perte de validation et la justesse du modèle pour chaque époque ou pour chaque itération complète sur le jeu d’entraînement. Il enregistre le modèle présentant la justesse la plus élevée et, après dix époques, il affiche la justesse finale.
- Ajoutez le code suivant au fichier
DataClassifier.py
# Training Function
def train(num_epochs):
best_accuracy = 0.0
print("Begin training...")
for epoch in range(1, num_epochs+1):
running_train_loss = 0.0
running_accuracy = 0.0
running_vall_loss = 0.0
total = 0
# Training Loop
for data in train_loader:
#for data in enumerate(train_loader, 0):
inputs, outputs = data # get the input and real species as outputs; data is a list of [inputs, outputs]
optimizer.zero_grad() # zero the parameter gradients
predicted_outputs = model(inputs) # predict output from the model
train_loss = loss_fn(predicted_outputs, outputs) # calculate loss for the predicted output
train_loss.backward() # backpropagate the loss
optimizer.step() # adjust parameters based on the calculated gradients
running_train_loss +=train_loss.item() # track the loss value
# Calculate training loss value
train_loss_value = running_train_loss/len(train_loader)
# Validation Loop
with torch.no_grad():
model.eval()
for data in validate_loader:
inputs, outputs = data
predicted_outputs = model(inputs)
val_loss = loss_fn(predicted_outputs, outputs)
# The label with the highest value will be our prediction
_, predicted = torch.max(predicted_outputs, 1)
running_vall_loss += val_loss.item()
total += outputs.size(0)
running_accuracy += (predicted == outputs).sum().item()
# Calculate validation loss value
val_loss_value = running_vall_loss/len(validate_loader)
# Calculate accuracy as the number of correct predictions in the validation batch divided by the total number of predictions done.
accuracy = (100 * running_accuracy / total)
# Save the model if the accuracy is the best
if accuracy > best_accuracy:
saveModel()
best_accuracy = accuracy
# Print the statistics of the epoch
print('Completed training batch', epoch, 'Training Loss is: %.4f' %train_loss_value, 'Validation Loss is: %.4f' %val_loss_value, 'Accuracy is %d %%' % (accuracy))
Testez le modèle sur les données de test.
Maintenant que nous avons entraîné le modèle, nous pouvons le tester avec le jeu de données de test.
Nous allons ajouter deux fonctions de test. La première teste le modèle que vous avez enregistré dans la partie précédente. Elle teste le modèle avec le jeu de données de test de 45 éléments, puis affiche la justesse du modèle. La seconde est une fonction facultative qui teste la confiance du modèle dans la prédiction de chacune des trois espèces d’iris, représentée par la probabilité d’une classification réussie de chaque espèce.
- Ajoutez le code suivant au fichier
DataClassifier.py
.
# Function to test the model
def test():
# Load the model that we saved at the end of the training loop
model = Network(input_size, output_size)
path = "NetModel.pth"
model.load_state_dict(torch.load(path))
running_accuracy = 0
total = 0
with torch.no_grad():
for data in test_loader:
inputs, outputs = data
outputs = outputs.to(torch.float32)
predicted_outputs = model(inputs)
_, predicted = torch.max(predicted_outputs, 1)
total += outputs.size(0)
running_accuracy += (predicted == outputs).sum().item()
print('Accuracy of the model based on the test set of', test_split ,'inputs is: %d %%' % (100 * running_accuracy / total))
# Optional: Function to test which species were easier to predict
def test_species():
# Load the model that we saved at the end of the training loop
model = Network(input_size, output_size)
path = "NetModel.pth"
model.load_state_dict(torch.load(path))
labels_length = len(labels) # how many labels of Irises we have. = 3 in our database.
labels_correct = list(0. for i in range(labels_length)) # list to calculate correct labels [how many correct setosa, how many correct versicolor, how many correct virginica]
labels_total = list(0. for i in range(labels_length)) # list to keep the total # of labels per type [total setosa, total versicolor, total virginica]
with torch.no_grad():
for data in test_loader:
inputs, outputs = data
predicted_outputs = model(inputs)
_, predicted = torch.max(predicted_outputs, 1)
label_correct_running = (predicted == outputs).squeeze()
label = outputs[0]
if label_correct_running.item():
labels_correct[label] += 1
labels_total[label] += 1
label_list = list(labels.keys())
for i in range(output_size):
print('Accuracy to predict %5s : %2d %%' % (label_list[i], 100 * labels_correct[i] / labels_total[i]))
Enfin, nous allons ajouter le code principal. Cette opération lance la formation du modèle, enregistre le modèle et affiche les résultats à l’écran. Nous n’exécuterons que deux itérations [num_epochs = 25]
sur l’ensemble de formations de sorte que le processus de formation ne prendra pas trop de temps.
- Ajoutez le code suivant au fichier
DataClassifier.py
.
if __name__ == "__main__":
num_epochs = 10
train(num_epochs)
print('Finished Training\n')
test()
test_species()
Nous allons exécuter le test ! Assurez-vous que les menus déroulants de la barre d’outils supérieure sont définis sur Debug
. Remplacez Solution Platform
par x64
pour exécuter le projet sur votre ordinateur local si votre appareil est 64 bits, ou x86
s’il est 32 bits.
- Pour exécuter le projet, cliquez sur le bouton
Start Debugging
dans la barre d’outils ou appuyez surF5
.
Dans la fenêtre de la console qui s’affiche, vous pouvez voir le processus d’entraînement. Comme vous l’avez défini, la valeur de perte est affichée pour chaque époque. En principe, la valeur de perte diminue à chaque boucle.
Une fois la formation terminée, vous devez vous attendre à voir la sortie similaire à celle ci-dessous. Vos chiffres ne seront pas exactement les mêmes, car l’entraînement dépend de nombreux facteurs et ne donne pas toujours des résultats identiques, mais ils devraient être similaires.
Étapes suivantes
Maintenant que nous disposons d’un modèle de classification, l’étape suivante consiste à convertir le modèle au format ONNX.