Aller au contenu
English

La perte : à quel point le réseau se trompe-t-il?

  • Leçon 7
  • 50 min
  • Module 3 : Comment les réseaux de neurones apprennent

Ce que vous saurez faire

Mesurez les erreurs du réseau de billets de soutien avec un nombre que l’entraînement peut réduire : la perte. L’exactitude compte seulement les bonnes réponses. Elle ne distingue donc pas une réponse chanceuse d’une réponse certaine, et le réseau ne peut pas apprendre avec elle.

Carnet JupyterFaites cette leçon dans un carnet JupyterColab · Kaggle · GitHub · en anglais

Le carnet (notebook) Jupyter contient chaque cellule de code, tâche et vérification de cette leçon. Il calcule softmax à la main, la perte du réseau de billets non entraîné, puis la perte et l’exactitude côte à côte. Il montre aussi l’erreur d’appliquer softmax deux fois. Ses cellules de préparation téléchargent les billets et le code du cours. Aucune installation locale n’est donc nécessaire. Environ 25 minutes.

Le carnet est en anglais. Colab et Kaggle ouvrent votre propre copie. Il faut un compte Google ou Kaggle gratuit. Vous êtes bloqué ? Consultez le carnet de solution.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 50 minutes

Ce que vous devez savoir

  • La propagation avant du réseau de billets : fréquences des mots → 64 neurones cachés avec ReLU → 5 scores, un par équipe, dans La propagation avant.
  • La perte logarithmique, −ln p, dans Logarithmes des probabilités du cours de mathématiques.
  • La fonction logistique, qui transforme un score en nombre de 0 à 1, dans Comprendre la classification du cours d’apprentissage automatique.

Ce qu’il vous faut sur votre ordinateur

  • Rien si vous utilisez le carnet.
  • Pour travailler localement : PyTorch et le dossier ticket-router avec data/ et ticketnet.py, présentés dans Installer PyTorch. La section Les billets sous forme de nombres, ci-dessous, donne les lignes de préparation qui commencent chaque fichier de code de ce module. Si import torch échoue, préparez de nouveau l’environnement comme le montre cette leçon.

Testé avec Python 3.12 et PyTorch 2.14.1 sur un processeur.

Deux applications météo font une prévision pour demain. La première annonce « 90 % de probabilité de pluie ». La deuxième annonce « 55 % de probabilité de pluie ». Il pleut. Les deux applications jugeaient la pluie plus probable que son absence. Si vous comptez seulement les bonnes et les mauvaises réponses, les deux avaient raison.

Mais vous faites davantage confiance à la première application. Elle était certaine, et elle avait raison. S’il n’avait pas plu, vous lui reprocheriez aussi davantage son erreur : elle était certaine, et elle avait tort. Un score équitable tient compte de la probabilité attribuée à ce qui s’est réellement produit, pas seulement du résultat gagnant.

Le problème : les scores ne sont pas des probabilités

Section intitulée « Le problème : les scores ne sont pas des probabilités »

Le réseau de billets de La propagation avant produit cinq nombres, un pour chaque équipe. Pour le premier billet de validation, le réseau non entraîné donne ceci :

Équipe delivery returns payment warranty account
Score −0.129 0.023 0.107 0.024 0.065

Ces nombres ne sont pas des probabilités. L’un est négatif, et leur somme n’est pas 1. Vous ne pouvez donc pas dire « le réseau est certain à 10 % que c’est payment ».

La bonne équipe pour ce billet est payment, et payment a le score le plus élevé. Si vous comptez les bonnes et les mauvaises réponses, le réseau a donc bien classé ce billet. Mais le réseau a des poids aléatoires et n’a rien appris. Il a eu de la chance, et l’exactitude ne le détecte pas. L’entraînement a besoin d’un nombre qui mesure à quel point le réseau était certain de la bonne équipe.

Softmax transforme toute liste de scores en probabilités, en deux étapes. Prenez trois scores inventés pour trois équipes : 2,0, 1,0 et 0,1.

  1. Rendez chaque score positif : calculez e à la puissance du score (exp), où e ≈ 2,718. Vous obtenez 7,389, 2,718 et 1,105. Un score plus élevé donne toujours un nombre plus élevé.
  2. Divisez chaque résultat par leur somme, 11,212. Vous obtenez 0,659, 0,242 et 0,099, dont la somme est 1.

Le premier score vaut deux fois le deuxième, mais sa probabilité est 2,7 fois plus grande. Softmax tient compte des différences entre les scores : un point de plus multiplie toujours la probabilité par e ≈ 2,718. Ajouter le même nombre à chaque score ne change donc rien.

Le nom décrit son fonctionnement. Le simple « max » des scores choisit un gagnant et lui donne tout. Softmax est une version plus douce : le gagnant reçoit la plus grande part, et les autres gardent une part plus petite. Avec seulement deux équipes, softmax correspond à la fonction logistique de la régression logistique du cours d’apprentissage automatique.

L’entropie croisée : la surprise devant la bonne réponse

Section intitulée « L’entropie croisée : la surprise devant la bonne réponse »

Passons maintenant au score de la prévision. Prenez la probabilité p que le réseau a attribuée à la bonne équipe, et calculez −ln p. C’est la perte d’un exemple : un nombre qui mesure à quel point le réseau se trompe. C’est la perte logarithmique que vous avez vue dans Mathématiques et statistiques essentielles pour l’IA.

Lisez la courbe de droite à gauche. Une bonne réponse certaine (p proche de 1) coûte presque rien. Une réponse au hasard entre cinq équipes (p = 0,2) coûte 1,609. Une mauvaise réponse certaine (p proche de 0) coûte beaucoup, et ce coût n’a aucune limite supérieure.

La perte d'un exemple, −ln p, selon la probabilité p que le réseau a attribuée à la bonne équipe. Elle vaut 0 quand p = 1 et augmente sans limite quand p descend vers 0.
Description textuelle du graphique

La courbe commence haut à gauche : à p = 0,01, la perte vaut 4,6; à p = 0,02, elle vaut 3,9. Elle descend vite, puis lentement : 1,609 à p = 0,2 (un choix au hasard entre cinq équipes) et 0,693 à 0,5. Puis 0,417 à 0,659, 0,105 à 0,9 et 0 à p = 1.

Dans l’exemple à trois équipes, si la bonne équipe est la première, la perte est −ln 0,659 = 0,417. Si la bonne équipe est la troisième, la perte est −ln 0,099 = 2,317. Le réseau était certain de la mauvaise équipe, alors il est très surpris.

Cette perte s’appelle entropie croisée. Le mot « entropie » vient de la théorie de l’information, où −ln p mesure la surprise d’un événement de probabilité p. « Croisée » signifie qu’elle compare deux choses : les probabilités du réseau et la bonne réponse. Pour un ensemble de billets, la perte est la moyenne des pertes de chaque billet. Voici la formule, où s représente les scores et « right » la bonne équipe :

pi=esi∑jesjloss=−ln⁡prightp_i = \frac{e^{s_i}}{\sum_j e^{s_j}} \qquad \text{loss} = -\ln p_{\text{right}}

Le code de ce module utilise les billets sous forme de fréquences de mots, comme dans La propagation avant. Cette fois, le fichier ticketnet.py du cours les construit avec le même code que vous y avez écrit. Dans le carnet, les cellules de préparation exécutent ces lignes pour vous. Sur votre ordinateur, placez-les au début de chaque fichier de code de ce module, dans le dossier ticket-router :

loss.py
import torch
from torch import nn
from ticketnet import * # the course's code: TEAMS, load_split, Vocab, bag_of_words, labels, BagOfWordsNet, set_seed, evaluate, train ...
train_rows, valid_rows = load_split("data/train.csv"), load_split("data/valid.csv")
vocab = Vocab([r["text"] for r in train_rows]) # the vocabulary: training tickets only
x_train, y_train = bag_of_words(train_rows, vocab), labels(train_rows)
x_valid, y_valid = bag_of_words(valid_rows, vocab), labels(valid_rows)
loss_fn = nn.CrossEntropyLoss() # the loss of this lesson
print("x_train", tuple(x_train.shape), " x_valid", tuple(x_valid.shape), " vocabulary", len(vocab))

La sortie :

x_train (4696, 2864) x_valid (600, 2864) vocabulary 2864

labels() transforme l’équipe de chaque billet en sa position dans TEAMS, de 0 (delivery) à 4 (account). BagOfWordsNet est le réseau de La propagation avant, et set_seed(0) lui donne les mêmes poids de départ.

Passons maintenant au vrai billet. Le schéma suit les quatre étapes pour le premier billet de validation, avec les vrais nombres du réseau non entraîné.

Un tableau de cinq équipes. Colonne 1, les scores : delivery −0,129, returns 0,023, payment 0,107, warranty 0,024, account 0,065. Colonne 2, exp de chaque score : 0,879, 1,023, 1,113, 1,024, 1,067, somme 5,107. Colonne 3, chaque valeur divisée par la somme : 0,172, 0,200, 0,218, 0,201, 0,209, somme 1. La ligne payment est mise en évidence. Étape 4 : la bonne équipe est payment, p = 0,218, perte = −ln 0,218 = 1,523.
Des cinq scores du réseau non entraîné à la perte d'un billet : exp, division par la somme, puis −ln de la probabilité de la bonne équipe.
Description textuelle du diagramme

Le premier billet de validation passe dans le réseau non entraîné. Étape 1, les cinq scores : delivery −0,129, returns 0,023, payment 0,107, warranty 0,024, account 0,065. Étape 2, exp de chaque score : 0,879, 1,023, 1,113, 1,024 et 1,067; leur somme est 5,107. Étape 3, chaque valeur divisée par la somme donne les probabilités 0,172, 0,200, 0,218, 0,201 et 0,209. Leur somme est 1. Étape 4, la bonne équipe est payment, donc p = 0,218 et la perte est −ln 0,218 = 1,523.

Dans PyTorch, torch.softmax(scores, dim=1) calcule les probabilités selon la dimension 1, soit les cinq équipes de chaque billet. nn.CrossEntropyLoss() calcule la perte. Cette fonction prend les scores, pas les probabilités, et l’indice de la bonne équipe; elle applique elle-même softmax. Priya exécute les deux fonctions sur le premier billet de validation :

loss.py
set_seed(0)
model = BagOfWordsNet(len(vocab))
scores = model(x_valid[:1])
print("scores: ", scores)
print("probabilities:", torch.softmax(scores, dim=1))
print("right team: ", TEAMS[y_valid[0]])
print("loss: ", loss_fn(scores, y_valid[:1]))

La sortie :

scores: tensor([[-0.1288, 0.0228, 0.1072, 0.0242, 0.0647]],
grad_fn=<AddmmBackward0>)
probabilities: tensor([[0.1722, 0.2003, 0.2180, 0.2006, 0.2089]], grad_fn=<SoftmaxBackward0>)
right team: payment
loss: tensor(1.5234, grad_fn=<NllLossBackward0>)

La partie grad_fn=… est une note que PyTorch garde pour l’entraînement; La rétropropagation et autograd l’explique. La perte est de 1,523, comme dans le calcul à la main. Passons maintenant à toutes les données de validation. La fonction evaluate() du fichier ticketnet.py du cours renvoie la perte moyenne et l’exactitude :

loss.py
import math
valid_loss, valid_acc = evaluate(model, x_valid, y_valid)
print("validation loss:", round(valid_loss, 4), "| ln 5 =", round(math.log(5), 4))
print("validation accuracy:", round(valid_acc, 4))

La sortie :

validation loss: 1.624 | ln 5 = 1.6094
validation accuracy: 0.1817

Un réseau qui attribue exactement 0,2 à chaque équipe a une perte de −ln 0,2 = ln 5 = 1,609. Le réseau non entraîné atteint 1,624, une valeur très proche : il choisit presque au hasard, avec des probabilités égales. Son exactitude de 18,2 % est aussi un résultat dû au hasard; même « toujours delivery » atteint 27,5 %. L’entraînement doit réduire la perte. Après l’entraînement dans ce module, le même réseau atteint une perte de validation d’environ 0,06.

Pourquoi entraîner avec la perte, mais présenter l’exactitude

Section intitulée « Pourquoi entraîner avec la perte, mais présenter l’exactitude »

Omar demande : « Les clients veulent des bonnes réponses. Pourquoi ne pas entraîner le réseau avec l’exactitude? » Priya lui montre une expérience. Elle change un nombre du réseau non entraîné, le biais du score de payment, de −3 à 3. Pour chaque valeur, elle mesure la perte et l’exactitude sur les 4 696 billets d’entraînement.

La perte du réseau non entraîné sur les billets d'entraînement quand un seul nombre change : le biais du score de payment. La courbe est lisse, donc chaque petit changement apparaît.
Description textuelle du graphique

La perte forme une vallée lisse. À un biais de −3, elle vaut 2,06; à 0, elle vaut 1,624, son minimum; à 3, elle vaut 2,54. Le vrai biais du réseau, 0,087, est proche du minimum.

L'exactitude du même réseau sur le même intervalle. Elle est constante presque partout, avec un seul saut.
Description textuelle du graphique

L’exactitude reste à 14,7 % pour un biais allant de −3 à environ 0. Entre environ 0 et 0,3, elle saute à 21,3 %, puis reste constante jusqu’à 3. À 21,3 %, le réseau répond « payment » pour chaque billet.

Partout, la perte répond à la question « ce petit changement améliore-t-il ou aggrave-t-il un peu le résultat? ». L’exactitude reste constante : sur la majeure partie de l’intervalle, un petit changement ne la modifie pas du tout. Elle ne peut donc pas indiquer dans quelle direction aller. Priya montre la même chose en code. Elle réduit le score de payment de chaque billet de 0,3, 0,2 et 0,1. Cela revient à réduire le biais de payment :

loss.py
scores = model(x_train)
for change in [-0.3, -0.2, -0.1]:
shifted = scores.clone()
shifted[:, 2] += change # every ticket's payment score, a little lower
loss = loss_fn(shifted, y_train).item()
accuracy = (shifted.argmax(dim=1) == y_train).float().mean().item()
print(f"change {change:.2f} loss {loss:.5f} accuracy {accuracy:.4f}")

La sortie :

change -0.30 loss 1.63139 accuracy 0.1469
change -0.20 loss 1.62730 accuracy 0.1469
change -0.10 loss 1.62467 accuracy 0.1469

scores.clone() crée une copie, donc les scores d’origine restent intacts. .item() transforme un tenseur contenant un seul nombre en nombre Python. La perte indique que −0,1 est meilleur que −0,2; l’exactitude ne distingue pas les trois cas. La prochaine leçon utilise précisément cela : l’entraînement suit la pente de la perte, et une ligne horizontale n’a aucune pente.

La perte voit aussi ce que l’exactitude cache. Après deux époques d’entraînement (passages sur tous les billets d’entraînement), le réseau du cours a une exactitude de validation de 98,2 %. Sa perte est de 0,206. Après douze époques, l’exactitude est presque identique, à 98,3 %, mais la perte est de 0,063. Le réseau est devenu beaucoup plus certain de ses bonnes réponses, et seule la perte le montre. Donc :

  • Entraînez avec la perte. Elle varie de façon lisse avec chaque poids et récompense les bonnes réponses certaines.
  • Présentez l’exactitude (et les autres mesures du cours d’apprentissage automatique) aux gens. « 98 billets sur 100 arrivent à la bonne équipe » veut dire quelque chose pour Grace; « une perte de 0,063 », non.

Utilisez l’entropie croisée quand le réseau choisit une classe parmi plusieurs, comme le routeur : une bonne équipe par billet. Pour un nombre, comme des minutes ou un prix, utilisez une perte adaptée aux nombres. Par exemple, l’erreur quadratique moyenne de Mathématiques et statistiques essentielles pour l’IA.

Ses limites : la perte est difficile à expliquer aux gens, alors présentez toujours une autre mesure à côté. De plus, une mauvaise réponse certaine coûte si cher que quelques mauvais exemples peuvent peser lourd. Un billet avec p = 0,001 pour l’équipe qui lui est attribuée coûte 6,9, autant que 66 billets à p = 0,9. Les données d’entraînement contiennent volontairement 70 billets avec une mauvaise équipe. La leçon Déboguer l’expérience utilise cet effet pour les trouver.

  1. Utilisez les probabilités du premier billet de validation : delivery 0,172, returns 0,200, payment 0,218, warranty 0,201, account 0,209.
  2. Supposez que la bonne équipe est account. Notez p pour la bonne équipe.
  3. Calculez −ln p sur une calculatrice (la touche ln, logarithme naturel) ou en Python avec -math.log(p). Vous devriez obtenir environ 1,565.
  4. Supposez maintenant que la bonne équipe est delivery. Calculez de nouveau la perte. Vous devriez obtenir environ 1,760.
  5. Dans le carnet, complétez loss_for() à la section 6. Exécutez sa cellule de vérification, qui utilise delivery comme bonne équipe.
Afficher la réponse

Pour account, p = 0,209 et la perte est −ln 0,209 = 1,565. Pour delivery, p = 0,172 et la perte est −ln 0,172 = 1,760. Le carnet donne 1,759, à partir de la probabilité non arrondie 0,1722. Delivery a la plus faible probabilité, donc la perte la plus élevée. Le réseau serait le plus surpris si le billet était destiné à delivery.

Reprenez les trois scores inventés : 2,0, 1,0 et 0,1. Avant de calculer, faites une prédiction : la perte est-elle plus grande si la bonne équipe est la deuxième ou la troisième? Calculez ensuite les deux pertes, à la main et avec loss_fn(torch.tensor([[2.0, 1.0, 0.1]]), torch.tensor([1])) (et [2] pour la troisième).

Afficher la réponse

La deuxième équipe a p = 0,242, donc la perte est −ln 0,242 = 1,417. La troisième équipe a p = 0,099, donc la perte est de 2,317. La troisième perte est plus grande : le réseau a donné la plus petite part à la bonne équipe. Il est donc le plus surpris.

Erreur courante

Softmax deux fois

Symptôme : Tomás ajoute torch.softmax() à la fin du réseau « pour qu’il donne des probabilités », et garde nn.CrossEntropyLoss(). L’entraînement fonctionne, et l’exactitude semble bonne. Mais la perte reste élevée. Quand Priya exécute sa version, après 3 époques, l’exactitude de validation atteint 98,8 %, mais la perte reste à 0,96.

Cause : nn.CrossEntropyLoss() applique elle-même softmax. Avec le changement de Tomás, les probabilités passent une deuxième fois dans softmax, et la perte est incorrecte. Dans l’exemple à trois équipes, la perte calculée à partir des scores est de 0,417. Celle calculée à partir des probabilités est de 0,802. Même une réponse parfaite, 1,0 pour la bonne équipe parmi cinq, donne ainsi une perte de 0,905. La perte ne peut donc jamais descendre sous 0,905, et tous les nombres qui l’utilisent sont incorrects.

Solution : laissez le réseau renvoyer les scores bruts, et passez-les à nn.CrossEntropyLoss(). Appliquez torch.softmax() seulement quand vous voulez lire ou afficher les probabilités.

Ce que cela signifie pour un vrai service d’IA : lisez la documentation d’une fonction de perte avant de l’utiliser. Vérifiez les entrées attendues (scores ou probabilités) et les opérations qu’elle effectue elle-même. L’exactitude d’un modèle peut sembler bonne, même si toutes les pertes dans le journal d’entraînement sont incorrectes.

Vérifiez votre compréhension

Dans vos mots : que mesure la perte d'entropie croisée d'un billet? Pourquoi est-elle élevée quand le réseau choisit avec certitude la mauvaise équipe?

Afficher la réponse

Elle mesure à quel point la bonne réponse surprend le réseau : −ln p, où p est la probabilité attribuée à la bonne équipe. Si le réseau choisit avec certitude une mauvaise équipe, la bonne équipe reçoit un petit p, par exemple 0,01. Alors, −ln p est élevé (4,6), car le logarithme d’un petit nombre est un grand nombre négatif. Une bonne réponse donnée avec certitude (p proche de 1) ne coûte presque rien.

Vérifiez votre compréhension

Prédisez : un réseau donne les scores 3, 3, 3, 3, 3 aux cinq équipes. Quelles probabilités softmax donne-t-il, et quelle est la perte? Ajoutez ensuite 10 à chaque score : qu'est-ce qui change?

Afficher la réponse

Les cinq scores sont égaux, donc softmax donne 0,2 à chaque équipe. La perte est −ln 0,2 = ln 5 = 1,609, soit la perte d’une prédiction qui donne une probabilité égale à chaque équipe. Ajouter 10 à chaque score ne change rien : softmax tient compte seulement des différences entre les scores. Ces différences sont toujours de 0. Les probabilités restent à 0,2 et la perte reste à 1,609.

Vérifiez votre compréhension

Omar veut entraîner le réseau directement sur l'exactitude, car c'est ce que les clients perçoivent. Donnez une raison d'utiliser plutôt la perte pour l'entraînement.

Afficher la réponse

L’exactitude change seulement quand une réponse passe à une autre équipe. Elle reste donc inchangée pour la plupart des petits changements d’un poids. Une valeur constante ne donne aucune direction : l’entraînement ne peut pas déterminer si un petit changement améliore ou aggrave le résultat. La perte varie de façon continue avec chaque poids. Elle indique donc toujours quelle direction améliore le résultat. Elle récompense aussi le réseau quand il est plus certain des bonnes réponses, ce que l’exactitude ne montre pas. Nous présentons quand même l’exactitude aux gens, car elle est facile à comprendre.

Récapitulatif

  • Softmax transforme les scores du réseau en probabilités : l’exponentielle de chaque score, divisée par la somme de ces exponentielles. Seules les différences entre les scores comptent.
  • La perte d’un exemple est −ln p pour la bonne équipe : c’est l’entropie croisée. Elle est faible pour une bonne réponse donnée avec certitude et élevée pour une mauvaise réponse donnée avec certitude. La perte d’un ensemble est la moyenne.
  • Le réseau non entraîné pour les billets a une perte de validation de 1,624, soit environ ln 5 = 1,609. C’est la perte d’une prédiction qui donne une probabilité égale à chaque équipe. Son exactitude est de 18,2 %.
  • Entraînez sur la perte, présentez l’exactitude. La perte varie de façon continue avec chaque poids; l’exactitude reste constante entre ses sauts.
  • nn.CrossEntropyLoss() prend des scores, pas des probabilités. Appliquer softmax deux fois rend la perte incorrecte.

Ensuite, réduisez la perte : modifiez les poids par petits pas, toujours dans le sens de la descente.

Leçon suivante : La descente de gradient