Vous êtes sur la page 1sur 13

Nom : GLEYZE

Master 1 SD, SIME Prénom : Alexandre


Master 2 SIME
Apprentissage profond

Séance de TP 5
Réseaux récurrents pour la classification de texte

1- Expliquez chaque étape de la méthode unicodeToAscii()**

La méthode unicodeToAscii() convertit une chaîne Unicode en une chaîne ASCII en


suivant plusieurs étapes. Voici une explication détaillée de chaque étape :

Normalisation Unicode (NFD) :

La normalisation Unicode est une étape importante pour traiter les caractères Unicode
de manière uniforme. La méthode unicodedata.normalize('NFD', s) prend une chaîne
Unicode s et la normalise selon la forme de décomposition canonique (NFD). Cela
signifie que les caractères Unicode composés sont décomposés en une séquence de
caractères de base et de caractères diacritiques.
Filtrage des caractères non désirés :

Après la normalisation, la fonction itère sur chaque caractère de la chaîne normalisée


et effectue deux filtrages :
Filtrage des caractères diacritiques (non-combining) : Les caractères diacritiques (ou
"combining marks") sont éliminés en vérifiant que la catégorie Unicode du caractère
(unicodedata.category(c)) n'est pas celle des caractères diacritiques (catégorie 'Mn').
Filtrage des caractères non autorisés : Seuls les caractères autorisés définis dans la
variable all_letters sont conservés. Cette variable contient une liste de caractères
ASCII autorisés, comprenant les lettres majuscules et minuscules, ainsi que certains
caractères de ponctuation tels que l'espace, le point, la virgule et les apostrophes.
Retour de la chaîne filtrée :

Une fois que tous les caractères non désirés ont été filtrés, la méthode retourne la
chaîne résultante, qui est une version ASCII de la chaîne Unicode d'origine, ne
contenant que des caractères autorisés.
En résumé, la méthode unicodeToAscii() normalise d'abord la chaîne Unicode en
utilisant la forme de décomposition canonique, puis filtre les caractères diacritiques et
non autorisés, pour finalement retourner une version ASCII de la chaîne initiale.

2- Expliquez chaque étape de la méthode lineToTensor()

La méthode lineToTensor() prend une liste de mots en entrée et la convertit en un


tenseur pouvant être utilisé comme entrée pour un modèle d'apprentissage profond.
Voici les étapes impliquées dans la méthode :

1. Tokenisation : La première étape consiste à tokeniser la liste d'entrée de mots. Cela


implique de diviser les mots en tokens individuels, tels que des caractères individuels
ou des signes de ponctuation.
2. Encodage one-hot : Une fois les mots tokenisés, la prochaine étape consiste à
effectuer un encodage one-hot sur chaque token. Cela implique de créer un vecteur
binaire pour chaque token, où chaque élément dans le vecteur représente la présence
ou l'absence de ce token dans la liste d'entrée.
3. Concaténation : Après avoir encodé one-hot chaque token, l'étape suivante consiste
à concaténer tous les vecteurs binaires en un seul tenseur. Cela crée un tenseur avec
une forme de (# mots, # tokens).
4. Remodelage : L'étape suivante consiste à remodeler le tenseur en une forme de (#
mots, # tokens * dim), où dim est la dimensionnalité de l'espace d'entrée. Cela est fait
en répétant le tenseur le long de la première dimension.
5. Normalisation : Enfin, le tenseur est normalisé pour avoir une moyenne de 0 et un
écart-type de 1. Cela est fait en utilisant la fonction torch.nn.functional.normalize().

Le tenseur résultant est alors prêt à être utilisé comme entrée pour un modèle
d'apprentissage profond.

3- Que représente le tenseur output ?

output est le vecteur de probabilité de chaque langue possible pour une entrée donnée.
Il est produit par la première couche linéaire avec softmax activation, et est utilisé pour
déterminer la prédiction finale du réseau récurrent.
4- Expliquez chaque ligne de la méthode categoryFromOutput()

1. top_n = output.topk(1) : Cette ligne utilise la fonction topk() de PyTorch pour obtenir
les n éléments les plus probables de la sortie output. Dans ce cas, n est défini sur 1, ce
qui signifie que seul l'élément le plus probable sera renvoyé.
2. category_index = top_n[1][0].item() : Cette ligne récupère l'indice du résultat le plus
probable (stocké dans top_n[1][0]) et le convertit en un entier Python (avec la méthode
item()).
3. return category_index : Enfin, la fonction renvoie l'indice de la catégorie la plus
probable, qui correspond à la langue prédite pour l'entrée actuelle.

5- Que réalise la fonction randomTrainingExample() ?

La fonction `randomTrainingExample()` crée un exemple d'entrée aléatoire pour


l'entraînement du réseau de classification de texte. Elle effectue les étapes suivantes :

1. Récupère une liste de noms de langues aléatoires (`languages`) et un nom de


langue aléatoire (`language`) parmi celles-ci.
2. Choisit un nom aléatoire (`name`) dans le fichier de données de la langue
sélectionnée.
3. Retourne le nom (`name`) et son indice de langue associé (`index`) dans le
dictionnaire des langues (`category_lines`).
Cet exemple aléatoire est utilisé pour former un lot d'entraînement et mettre à jour les
poids du réseau récurrent.

6- A quoi correspond le critère pytorch nn.NLLLoss ?

Le critère `nn.NLLLoss` dans PyTorch est une fonction de perte pour la classification
des problèmes à classes multiples. Il correspond à la fonction de perte négative log-
vraisemblance (NLL) qui calcule la perte entre la prédiction du modèle et la véritable
distribution des classes d'un exemple.

Le critère `nn.NLLLoss` attend en entrée un tenseur d'une forme spécifique :

* Le tenseur d'entrée doit avoir la forme `(N, C)`, où `N` est le nombre d'exemples et `C`
est le nombre de classes possibles.
* Le tenseur cible doit avoir la forme `(N)` et contenir les indices des classes vraies pour
chaque exemple.

Le critère `nn.NLLLoss` calcule la perte pour chaque exemple et retourne la perte


totale pour le lot. Il effectue une somme sur les pertes de chaque exemple et divise par
le nombre d'exemples pour obtenir une perte moyenne. Cette fonction de perte est
largement utilisée pour l'entraînement des réseaux de neurones dans les problèmes
de classification.
7- Expliquez toutes les étapes de la méthode train()

Voici une explication de chaque étape de la méthode train() :

1. input_tensor, target_tensor = get_input_target_pair() : Cette ligne appelle la fonction


get_input_target_pair() pour obtenir une paire d'entrée et de cible aléatoire pour former
un lot d'entraînement.
2. optimizer.zero_grad() : Cette ligne appelle la fonction zero_grad() de l'optimiseur
pour remettre les gradients à zéro. Cela permet d'éviter l'accumulation des gradients
entre les itérations.
3. output = model(input_tensor) : Cette ligne passe l'entrée aléatoire (input_tensor) à
travers le modèle récurrent pour obtenir la sortie du réseau (output).
4. loss = criterion(output, target_tensor) : Cette ligne calcule la perte en utilisant la
fonction de perte (criterion) et la sortie du réseau (output) et la cible (target_tensor).
5. loss.backward() : Cette ligne effectue l'opération de rétro-propagation pour calculer
les gradients des poids du réseau en fonction de la perte calculée à l'étape précédente.
6. optimizer.step() : Cette ligne met à jour les poids du réseau en fonction des gradients
calculés à l'étape précédente.
7. if epoch % 100 == 0: : Cette ligne vérifie si l'itération actuelle est un multiple de 100.
8. print('epoch {}, loss {:.6f}' .format(epoch, loss.item())) : Si c'est le cas, cette ligne
affiche la valeur actuelle de l'époque et de la perte.
9. all_losses.append(loss.item()) : Cette ligne stocke la valeur actuelle de la perte dans
la liste all_losses pour la visualiser plus tard.
La méthode train() entraîne le modèle récurrent en itérant sur les exemples
d'entraînement, en calculant la perte et en mettant à jour les poids du réseau en
fonction des gradients calculés. Elle affiche également la perte à chaque itération et
stocke les pertes pour une visualisation ultérieure.

8- Expliquez la structure de la boucle principale du programme


La boucle principale du programme se compose des étapes suivantes :

1. Initialiser le modèle avec des poids aléatoires.


2. Initialiser les listes pour stocker la perte d'entraînement et le nombre d'époques
d'entraînement.
3.Pour un nombre d'époques spécifié, effectuer les étapes suivantes :
a. Itérer sur l'ensemble de données d'entraînement et effectuer les tâches suivantes
pour chaque lot :
i. Mettre à zéro les gradients des paramètres du modèle.
ii. Passe avant : faire passer l'entrée à travers le modèle et calculer la sortie.
iii. Calculer la perte en utilisant la sortie et les vraies étiquettes.
iv. Passe arrière : calculer les gradients de la perte par rapport aux paramètres du
modèle.
v. Mettre à jour les paramètres du modèle en utilisant les gradients calculés et un
optimiseur (par exemple, SGD ou Adam).
b. Enregistrer la perte d'entraînement pour cette époque.
4. Après avoir terminé la boucle d'entraînement, vous pouvez visualiser la progression
de l'entraînement en traçant la perte d'entraînement au fil des époques.
5. Évaluer les performances du modèle en utilisant la fonction evaluate() et visualiser la
matrice de confusion.

Dans cette structure, les variables suivantes sont mémorisées et visualisées :

- Perte d'entraînement au fil des époques


- Matrice de confusion pour l'évaluation
Ces variables aident à suivre les performances du modèle et le progrès de
l'apprentissage pendant l'entraînement.
9- Précisez le rôle de la fonction evaluate()

La fonction evaluate() calcule l'exactitude des prédictions du modèle sur un ensemble


de données donné. Elle compare les étiquettes prédites aux étiquettes réelles et
calcule le pourcentage de prédictions correctes. Cette fonction est utilisée pour évaluer
les performances du modèle après l'entraînement et peut également être utilisée pour
tester le modèle sur de nouvelles données invisibles. Elle permet d'avoir une idée de la
capacité du modèle à généraliser à de nouveaux exemples. De plus, elle peut être
utilisée pour comparer les performances de différents modèles ou architectures.

10- Quel est le principal défaut de cette évaluation ?


Le principal inconvénient de cette méthode d'évaluation est qu'elle ne fournit qu'une
idée générale des performances du modèle en calculant la matrice de confusion. Elle
ne donne pas des informations plus détaillées telles que l'exactitude, la précision ou le
rappel du modèle pour chaque langue. De plus, elle ne fournit pas d'informations sur
les performances globales du modèle sur de nouvelles données non vues. Pour mieux
comprendre les performances du modèle, il convient de considérer d'autres méthodes
d'évaluation telles que le calcul de l'exactitude, de la précision et du rappel, ainsi que la
réalisation d'une validation croisée.

De plus, elle n'évalue le modèle que sur l'ensemble de données d'entraînement, il est
important d'évaluer le modèle sur un ensemble de données de test distinct pour
s'assurer que le modèle ne surajuste pas les données d'entraînement et est capable de
généraliser correctement à de nouvelles données non vues.
En outre, la matrice de confusion peut être trompeuse si la distribution des classes est
déséquilibrée, car elle ne prend pas en compte le nombre d'instances dans chaque
classe. Par conséquent, des métriques d'évaluation supplémentaires telles que le
score F1, qui prend en compte à la fois la précision et le rappel, doivent être utilisées
pour évaluer les performances du modèle sur des ensembles de données
déséquilibrés.
11- Quelles sont les langues les moins bien identifiées ? Quelles sont les
principales confusions ?
Après execution des cellules, nous obtenons le tableau suivant :

Les langues les moins bien identifiées, selon l’image, semblent être le japonais, le
vietnamien, le chinois et le grec, car elles ont des couleurs plus claires indiquant une
faible précision dans l’identification.

Le japonais utilise un système d'écriture complexe combinant des caractères chinois


(kanji), des syllabaires (hiragana et katakana), ainsi que des alphabets romains
(romaji). Cette complexité rend l'identification automatique plus difficile.
Le vietnamien utilise l'alphabet latin, mais il comporte des tons qui peuvent changer
complètement le sens des mots. Ces nuances tonales rendent la reconnaissance
automatique moins précise.
Le grec utilise un alphabet différent de celui de nombreuses autres langues
européennes, ce qui peut poser des défis pour les systèmes d'identification
automatique, en particulier s'ils ne sont pas spécifiquement formés sur cette langue.

Le chinois utilise des caractères logographiques (hanzi) qui représentent des mots ou
des morphèmes, ce qui est très différent de l'alphabet latin utilisé dans de nombreuses
autres langues. La reconnaissance des caractères chinois peut être complexe en
raison du grand nombre de caractères et de la similarité entre certains d'entre eux.

12- Expliquez les différentes étapes de la méthode predict()

Le méthode predict() suit ces étapes :

1. Tout d'abord, elle initialise l'état caché du réseau récurrent, généralement réglé à
zéro ou à une valeur fixe.
2. Ensuite, elle itère sur chaque caractère de la séquence d'entrée, fournissant le
caractère encodé one-hot actuel et l'état caché précédent au réseau.
3. Le réseau produit un vecteur de probabilités pour chaque langue, et la langue avec
la probabilité la plus élevée est sélectionnée comme la langue prédite pour le nom
d'entrée.
4. La langue prédite est ensuite renvoyée en tant que sortie.

Ce processus est effectué pour chaque nom dans l'ensemble de données d'entrée,
permettant au modèle de prédire la langue d'origine de chaque nom.
Pour améliorer les résultats en faisant évoluer l'architecture du réseau, nous pouvons
envisager les modifications suivantes :

- Ajouter plus de couches linéaires :


* Ajouter plus de couches cachées entre l'entrée et la couche récurrente.
* Ajouter plus de couches entièrement connectées (dense) après la couche
récurrente.
Cela peut aider le modèle à apprendre des représentations plus complexes des
données d'entrée et à améliorer ses performances.

- Empiler plusieurs couches récurrentes :


* Empiler plusieurs couches récurrentes les unes sur les autres.
* Utiliser des techniques telles que les "réseaux neuronaux récurrents profonds" ou
les "réseaux neuronaux récurrents à autoroute" pour améliorer le flux d'informations
entre les couches empilées.
L'empilement de plusieurs couches récurrentes peut aider le modèle à capturer les
dépendances à long terme et à apprendre des motifs plus complexes dans les
données.

Vous aimerez peut-être aussi