Deep Reinforcement Learning For Visual Q
Deep Reinforcement Learning For Visual Q
Deep Reinforcement Learning For Visual Q
Encadrants :
Auteur :
Pr. Éric Moulines
Ayoub Abraich
Ing. Alice Martin
Rapport de Stage
30 août 2019
Résumé
La conception de bout en bout des systèmes de dialogue est récemment devenue un sujet de recherche
populaire grâce à des outils puissants tels que des architectures codeur-décodeur pour l’apprentissage
séquence à séquence. Pourtant, la plupart des approches actuelles considèrent la gestion du dialogue
homme-machine comme un problème d’apprentissage supervisé, visant à prédire la prochaine déclara-
tion d’un participant, compte tenu de l’historique complet du dialogue. Cette vision est aussi simpliste
pour rendre le problème de planification intrinsèque inhérent au dialogue ainsi que sa nature enracinée,
rendant le contexte d’un dialogue plus vaste que seulement l’historique. C’est la raison pour laquelle
seules les tâches de bavardage et de réponse aux questions ont été traitées jusqu’à présent en utilisant
des architectures de bout en bout. Dans ce rapport, nous présentons une méthode d’apprentissage par
renforcement profond permettant d’optimiser les dialogues axés sur les tâches, basés sur l’algorithme
policy gradient. Cette approche est testée sur un ensemble de données de 120 000 dialogues collectés
via Mechanical Turk et fournit des résultats encourageants pour résoudre à la fois le problème de la
génération de dialogues naturels et la tâche de découvrir un objet spécifique dans une image complexe.
Remerciements
Je tiens à remercier mes deux encadrants de stage Eric Moulines et Alice Martin qui m’ont guidé avec
cordialité et bienveillance durant ces quatre mois . Merci beaucoup Alice de m’avoir accordé pour votre
accueil, votre confiance , le temps passé ensemble et le partage de votre expertise au quotidien.
De même, J’adresse mes chaleureux remerciements à tous mes enseignants, qui m’ont aidé tout au
long de l’année . En particulier, Mme Agathe Guilloux et Mme Marie Luce Taupin pour leurs efforts et
leur soutien avec cordialité et bienveillance durant mon parcours à l’université Evry Val d’Essonne.
Enfin, je tiens à remercier toutes les personnes qui m’ont aidé et conseillé et relu lors de la rédaction
de ce rapport de stage : ma famille, mes camarades de classe et mes amis. Merci !
Table des matières
1 Introduction 5
1.1 État de l’art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Problématique et plan de travail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2 GuessWhat ? ! 8
2.1 Règles de jeu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2 Notations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.3 Image captioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 Visual Question Answering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.5 Dialogue dirigé par objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.6 Quelques notions et définitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.7 Environnement d’apprentisssage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.7.1 Génerations de questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.7.2 Oracle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.7.3 Devineur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.8 Génération de jeux complets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.9 GuessWhat ? ! du point de vue de RL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.9.1 GuessWhat ? ! en tant que processus de décision de Markov . . . . . . . . . . . . . 14
2.9.2 Entraı̂nement de QGen avec Policy Gradient . . . . . . . . . . . . . . . . . . . . . 15
2.9.3 Fonction de récompense . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.9.4 Procédure d’entraı̂nement complète . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.10 Expériences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.10.1 Détails de l’entraı̂nement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.10.2 Résultats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3 Apprentissage automatique 20
3.1 Généralités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2 Apprentissage supervisé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.1 Approche algorithmiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.2 Formalisme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.3 Optimisation des paramètres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.2.4 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.3 Apprentissage par renforcement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.4 Apprentissage non supervisé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.4.1 Réseaux de neurones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2
4.2.5 Fonction action-valeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.2.6 Rétropropagation de la valeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.3 Différents composants pour apprendre une politique . . . . . . . . . . . . . . . . . . . . . 35
4.4 Différentes configurations pour apprendre une politique à partir de données . . . . . . . . 35
4.4.1 Offline & online learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.4.2 Comparaison entre l’off-policy et l’on-policy learning . . . . . . . . . . . . . . . . . 36
4.5 Méthodes basées sur la valeur pour deep RL . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.5.1 Q-learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.5.2 Q-learning ajusté . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.5.3 Deep Q-networks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.5.4 Perspective distributionnelle de RL . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.5.5 Multi-step learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5 L’apprentissage profond 45
5.1 Approche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.2 Optimalité globale en apprentissage profond . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2.1 Le défi de la non convexité dans l’apprentissage en réseau de neurones . . . . . . . 47
5.3 Stabilité géométrique en apprentissage profond . . . . . . . . . . . . . . . . . . . . . . . . 48
5.4 Théorie basée sur la structure pour l’apprentissage profond . . . . . . . . . . . . . . . . . 50
5.4.1 Structure des données dans un réseau de neurones . . . . . . . . . . . . . . . . . . 50
5.5 Etat de l’art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.6 RNN standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.6.2 Limitations et motivations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.6.3 Les racines de RNN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.7 LSTM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.7.2 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.7.3 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.7.4 Variantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.7.5 Contexte & résultats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
6 Conclusion 58
Bibliography 60
3
Table des figures
4
Chapitre 1
Introduction
Je me base principalement dans ce rapport sur les articles : [1],[2],[3] et [4] , les thèses :
[5] et [6], les livres : [7] et [8], et le cours d’apprentissage statistique de l’université Paris
Sud.
5
et al., 2016a), a même mis au point une formule : intelligence artificielle = apprentissage par renforcement
+ apprentissage en profondeur (Silver, 2016).
La conception de bout en bout de systèmes de dialogue est récemment devenue un sujet de recherche
populaire grâce à des outils puissants tels que des architectures décodeur-codeur pour l’apprentissage
séquentiel. Cependant, la plupart des approches actuelles considèrent la gestion du dialogue homme-
machine comme un problème d’apprentissage supervisé, visant à prédire la prochaine déclaration d’un
participant compte tenu de l’historique complet du dialogue. Cette vision est trop simpliste pour rendre le
problème de planification intrinsèque inhérent au dialogue ainsi que sa nature ancrée, rendant le contexte
d’un dialogue plus vaste que la seule histoire. C’est pourquoi seul le bavardage et les tâches de réponse
aux questions ont jusqu’à présent été traitées à l’aide d’architectures de bout en bout. Dans cet article,
nous introduisons une méthode d’apprentissage en renforcement profond pour optimiser les dialogues
orientés tâches orientés visuellement, basés sur l’algorithme de gradient de politique. Cette approche est
testée sur un ensemble de données de 120 000 dialogues collectés via Mechanical Turk et fournit des
résultats encourageants pour résoudre à la fois le problème de la génération de dialogues naturels et la
tâche de découvrir un objet spécifique dans une image complexe.
Les systèmes de dialogue pratiques doivent mettre en oeuvre une stratégie de gestion qui définit le
comportement du système, par exemple pour décider quand fournir des informations ou demander des
éclaircissements à l’utilisateur. Bien que les approches traditionnelles utilisent des règles à motivation
linguistique [Weizenbaum, 1966], les méthodes récentes reposent sur des données et utilisent l’apprentis-
sage par renforcement (RL) [Lemon et Pietquin, 2007]. Des progrès significatifs dans le traitement du
langage naturel via des réseaux neuronaux profonds [Bengio et al., 2003] ont ont fait des architectures
codeurs-décodeurs neuronaux un moyen prometteur pour la formation d’agents conversationnels [Vinyals
and Le, 2015 ; Sordoni et al., 2015 ; Serban et al., 2016].
Le principal avantage de ces systèmes de dialogue de bout en bout est qu’ils ne font aucune hypothèse
sur le domaine d’application et qu’ils sont simplement formés de manière supervisée à partir de grands
corpus de texte [Lowe et al., 2015].
Cependant, il existe de nombreux inconvénients à cette approche. 1) Premièrement, les modèles
codeur-décodeur transforment le problème du dialogue en un apprentissage supervisé, en prédisant la
répartition entre les énoncés suivants compte tenu du discours qui a été donné jusqu’à présent. Comme
avec la traduction automatique, des dialogues incohérents et des erreurs susceptibles de s’accumuler avec
le temps peuvent en résulter. Cela est d’autant plus vrai que l’espace d’action des systèmes de dialogue est
vaste et que les jeux de données existants ne couvrent qu’un petit sous-ensemble de toutes les trajectoires,
ce qui rend difficile la généralisation à des scénarios invisibles [Mooney, 2006]. 2) Deuxièmement, le cadre
d’apprentissage supervisé ne prend pas en compte le problème intrinsèque de planification qui sous-tend
le dialogue, c’est-à-dire le processus de prise de décision séquentiel, qui rend le dialogue cohérent dans
le temps. Cela est particulièrement vrai lorsque vous vous engagez dans un dialogue axé sur les tâches.
En conséquence, l’apprentissage par renforcement a été appliqué aux systèmes de dialogue depuis la fin
des années 90 [Levin et al., 1997 ; Singh et al., 1999] et l’optimisation du dialogue a généralement été
davantage étudiée que la génération de dialogue. 3) Troisièmement, il n’intègre pas naturellement les
contextes externes (plus grands que l’historique du dialogue) qui sont le plus souvent utilisés par les
participants au dialogue pour dialoguer. Ce contexte peut être leur environnement physique, une tâche
commune qu’ils tentent d’accomplir, une carte sur laquelle ils essaient de trouver leur chemin, une base
de données à laquelle ils veulent accéder, etc. Il fait partie de ce qu’on appelle le Common Ground, bien
étudié dans la littérature [Clark et Schaefer, 1989]. Au cours des dernières décennies, le domaine de la
psychologie cognitive a également apporté des preuves empiriques du fait que les représentations humaines
sont fondées sur la perception et les systèmes moteurs [Barsalou, 2008]. Ces théories impliquent qu’un
système de dialogue doit être fondé sur un environnement multimodal afin d’obtenir une compréhension
du langage au niveau humain [Kiela et al., 2016]. Enfin, l’évaluation des dialogues est difficile car il
n’existe pas de mesure d’évaluation automatique qui soit bien corrélée avec les évaluations humaines
[Liu et al., 2016a]. D’autre part, les approches RL pourraient traiter les problèmes de planification et
de métriques non différentiables, mais requièrent un apprentissage en ligne (bien que l’apprentissage par
lots soit possible mais difficile avec de faibles quantités de données [Pietquin et al., 2011]). Pour cette
raison, la simulation utilisateur a été proposée pour explorer les stratégies de dialogue dans un contexte
RL [Eckert et al., 1997 ; Schatzmann et al., 2006 ; Pietquin et Hastie, 2013]. Cela nécessite également
6
la définition d’une mesure d’évaluation qui est le plus souvent liée à l’achèvement des tâches et à la
satisfaction des utilisateurs [Walker et al., 1997]. En outre, les applications réussies du cadre RL au
dialogue reposent souvent sur une structure prédéfinie de la tâche, telle que les tâches de remplissage
de créneaux horaires [Williams et Young, 2007] dans lesquelles la tâche peut être remplie comme si elle
remplissait un formulaire.
7
Chapitre 2
GuessWhat ? !
Nous expliquons brièvement ici le jeu GuessWhat ? ! cela servira de tâche à notre système de dialogue,
mais reportez-vous à [de Vries et al., 2016] pour plus de détails sur la tâche et le contenu exact de
l’ensemble de données. Il est composé de plus de 150 000 dialogues humains-humains en langage naturel,
rassemblés dans Mechanical Turk.
2.2 Notations
Le jeu est défini par un tuple (I, D, O, o∗ ) avec I ∈ RH×W une image de hauteur H et de largeur W,D
J
un dialogue avec J questions-réponses couples : D = qj , aj j=1 . O une liste de K objets : O = (ok )K k=1
Ij
∗ j
et o l’objet cible.De plus, chaque question qj = wi est une séquence de longueur Ij avec chaque
i=1
token wji tiré d’un vocabulaire prédéfini V. Le vocabulaire V est composé d’une liste de mots prédéfinie,
d’une étiquette de question < ? > qui termine une question et un token d’arrêt < stop > qui met fin à un
dialogue. Une réponse est restreinte pour être oui, non ou non applicable (N.A) i.e aj ∈ {< yes >, < no >
, < na >}. Pour chaque objet k, une catégorie d’objet ck ∈ {1, . . . , C} et un masque de segmentation en
pixels Sk ∈ {0, 1}H×W sont disponibles.Enfin, pour accéder aux sous-ensembles d’une liste, nous utilisons
Ij ,j i,j
les notations suivantes. Si l = lji est une liste à double indice,alors lj1:i = ljp sont les i premiers
i=1 p=1
éléments de la jeme liste si 1 6 i 6 Ij , sinon lj1:p = ∅. Ainsi, par exemple, wj1:i fait référence aux premiers
i tokens de la jeme question et (q, a)1:j réfère aux j premières paires question / réponse d’un dialogue.
8
permis de découvrir des méthodes efficaces permettant de générer automatiquement des déclarations
factuelles cohérentes sur les images. Modéliser les interactions dans GuessWhat ? ! nécessite plutôt de
modéliser le processus de poser des questions utiles sur les images.
9
L’architecture de VGG16
manquantes, des mots nouveaux manquants, la nécessité de créer et d’adapter le travail humain, il était
difficile de calculer la similarité des mots avec précision et, surtout, lorsque le vocabulaire est vaste, la
représentation vectorielle est gigantesque.
VGG16 : C’est un modèle de réseau neuronal convolutionnel proposé par K. Simonyan et A. Zisser-
man de l’Université d’Oxford dans l’article intitulé «Very Deep Convolutional Networks for Large-Scale
Image Recognition». Le modèle atteint une précision de 92,7% dans le top 5 des tests dans ImageNet,
qui est un jeu de données de plus de 14 millions d’images appartenant à 1 000 classes. C’était l’un des
fameux modèle soumis à ILSVRC-2014. Il apporte des améliorations par rapport à AlexNet en rempla-
çant les grands filtres de la taille du noyau (respectivement 11 et 5 dans la première et la deuxième
couche de convolution) par plusieurs filtres de la taille du noyau 3 × 3, l’un après l’autre. VGG16 a été
entrainé pendant des semaines et utilisait NVIDIA GPU Titan noir.[https ://neurohive.io/en/popular-
networks/vgg16/]
Problème de décodage : Les RNN sont formés pour estimer la probabilité de séquences de tokens
à partir du dictionnaire V afin de prendre une entrée x. Le RNN met à jour son état interne et estime la
distribution de la probabilité conditionnelle pour la sortie suivante en fonction de l’entrée et de tous les
tokens de sortie précédents. On note le logarithme de cette distribution de probabilité conditionnelle sur
tous les tokens (jetons) en instant t par
10
Algorithme : Diverse Beam Search
Pour simplifier la notation, on indexe θ(·) avec une seule variable yt ,mais il devrait être clair que cela
dépend des sorties précédentes y[t−1] .Le log-probabilité d’une solution partielle (c’est-à-dire la somme
des log-probabilités de tous les jetons précédents décodés) peut maintenant être écrit comme Θ y[t] =
P
τ∈[t] θ (yτ ). Le problème du décodage est alors la tâche de trouver une séquence qui maximise Θ(y).
Comme chaque sortie est conditionnée par toutes les sorties précédentes, le décodage de la séquence
optimale de longueur T dans cette configuration peut être considéré comme une inférence MAP sur la
chaı̂ne de Markov d’ordre T , les T nœuds correspondant aux jetons de sortie. Non seulement la taille
du facteur le plus important dans un tel graphique augmente-t-elle en |V|T ,mais nécessite également une
transmission inutile du RNN à plusieurs reprises pour calculer les entrées dans les facteurs. Ainsi, des
algorithmes approximatifs sont utilisés.
Beam-search : Les architectures de génération de séquences basées sur RNN modélisent la pro-
babilité conditionnelle Pr(y|x) d’une séquence de sortie y = (y1 , . . . , yT ) étant donné une entrée
x(éventuellement aussi une séquence) ; où les jetons (tokens) de sortie yt sont d’un vocabulaire fini
V. L’inférence maximale a posteriori (MAP) pour les RNN est la tâche qui consiste à trouver la sé-
quence de sortie la plus probable compte tenu de l’entrée. Comme le nombre de séquences possibles
augmente avec |V|T , l’inférence exacte étant NP-difficile, des algorithmes d’inférence approximatifs tels
que Beam Search (BS) sont couramment utilisés. Cette heuristique vise à trouver la séquence de mots
la plus probable en explorant un sous-ensemble de toutes les questions et en conservant les séquences
de B-candidats les plus prometteuses à chaque pas de temps où B est connu comme la largeur du fais-
ceau (beam width) . Notons l’ensemble
des solutions B détenues par BS au début du temps t comme
Y[t−1] = y1,[t−1] , . . . , yB,[t−1] . A chaque pas de temps, BS considère toutes les extensions possibles de
jetons uniques de ces faisceaux données par l’ensemble Yt = Y[t−1] × V et sélectionne les B-extensions les
plus probables. Plus formellement, à chaque étape,
X
Y[t] = argmax Θ yb,[t] si yi,[t] 6= yj,[t] (2.2)
y1,[t] ,...,yB,[t] ∈Yt
b∈[B]
Il existe une autre version plus optimale de cet algorithme qui se nomme : Diverse Beam Search (voir
[9] pour plus de détails), dont le pseudo-code [2.2].
Vous trouverez son implémentation par [9] sur https://github.com/ashwinkalyan/dbs.
11
Modèle de génération de questions
ezi
σ(z)i := PK (2.3)
j=1 ezj
pour i = 1, . . . , K et z = (z1 , . . . , zK ) ∈ RK
Dans notre cas, cette distribution de sortie dépend de tous les tokens de questions et réponses précé-
dents, ainsi que de l’image I :
p wji |wj1:i−1 , (q, a)1:j−1 , I (2.4)
Nous conditionnons le modèle à l’image en obtenant ses caractéristiques VGG16 FC8 et en le conca-
ténant avec l’imbrication d’entrée (input embedding) à chaque étape, comme illustré sur la Figure 2.3.
On précise quelques termes utilisés :
Nous formons le modèle en minimisant la log-vraisemblance négative conditionnelle :
Q
− log p q1:J |a1:J , I = − log Jj=1 p qj |(q, a)1:j−1, I
P PIj (2.5)
= − Jj=1 i=1 log p wji |wj1:i−1 , (q, a)1:j−1 , I
Au moment du test, nous pouvons générer un échantillon p qj |(q, a)1:j−1 , I à partir du modèle comme
suit. À partir de l’état sj1 , nous échantillonnons
un nouveau token wji à partir de la distribution σ de
sortie et alimentez le token intégré e wji retourné comme entrée au RNN. Nous répétons cette boucle
jusqu’à rencontrer un token de fin de séquence. Pour trouver approximativement la question la plus
probable,maxqj p qj |(q, a)1:j−1 , I nous utilisons la procédure Beam-Search (2.6) couramment utilisée.
2.7.2 Oracle
La tâche oracle nécessite de produire une réponse oui-non pour tout objet dans une image à partir
d’une question en langage naturel. Nous décrivons ici l’architecture de réseau de neurones qui a réalisé
la meilleure performance et nous nous référons à [de Vries et al., 2016] pour une étude approfondie de
l’impact d’autres informations d’objet et d’image. Tout d’abord, nous intégrons les informations spa-
tiales de la culture en extrayant un vecteur à 8 dimensions de l’emplacement du cadre de sélection
12
Modèle de l’Oracle
[xmin , ymin , xmax , ymax , xcenter , ycenter , wbox , hbox ] où wbox et hbox désignent respectivement la lar-
geur et la hauteur du cadre de sélection. Nous normalisons la hauteur et la largeur de l’image de telle
sorte que les coordonnées vont de -1 à 1, et plaçons l’origine au centre de l’image. Deuxièmement, nous
convertissons la catégorie d’objets c∗ en une catégorie dense incorporant une table de consultation ap-
prise. Enfin, nous utilisons un LSTM pour coder la question actuelle q. Nous concaténons ensuite les
trois imbrications en un seul vecteur et le transmettons
en entrée
à une seule couche MLP masquée qui
produit la distribution de la réponse finale p a|q, c∗ , x∗spatial en utilisant une couche softmax, illustrée
à la Fig2.4.
2.7.3 Devineur
Le modèle de devineur prend une image I et une séquence de questions et réponses (q, a)1:N , et
prédit le bon objet o∗ de l’ensemble de tous les objets. Ce modèle considère un dialogue comme une
séquence plate de tokens question-réponse et utilise le dernier état caché du codeur LSTM en tant que
représentation de dialogue. Nous effectuons un produit scalaire entre cette représentation et l’intégration
de tous les objets de l’image, suivi d’un softmax pour obtenir une distribution de prédiction sur les
objets. Les embeddings d’objets sont obtenues à partir des caractéristiques catégorielles et spatiales.
Plus précisément, nous concaténons la représentation spatiale en 8 dimensions et la recherche de catégorie
d’objet et la transmettons à travers une couche MLP pour obtenir un emmbeding de l’objet. Notez que
les paramètres MLP sont partagés pour gérer le nombre variable d’objets dans l’image. Voir la figure 2.5
pour un aperçu du devineur.
13
Modèle du Devineur
nombre maximal de questions-réponses soit atteint. Enfin, le modèle de devineur prend le dialogue généré
D et la liste des objets O et prédit le bon objet.
Pour comprendre les notions de la partie suivante plus en détail, voir le chapitre 4 .
— Sinon
le nouveau mot est ajouté à la question en cours et xt+1 =
f j J
w1 , . . . , wi , wi+1 , (q, a)1:j−1 , I .
Les questions se terminent automatiquement après Imax mots. De même, les dialogues se terminent
après Jmax questions. De plus, une récompense r(x, u) est définie pour chaque couple de réactions. Une
trajectoire τ = (xt , ut , xt+1 , r (xt , ut ))1:T est une séquence finie de tuples de longueur T qui contient un
état, une action, l’état suivant et la récompense où T 6 Jmax ∗ Imax . Ainsi, le jeu tombe dans un RL
scénario épisodique de comme le dialogue se termine après une séquence finie de paires question-réponse.
Enfin, la sortie de QGen peut être vue comme une politique stochastique πθ (u|x) paramétrée par θ qui
associe une distribution de probabilité sur les actions (c’est-à-dire des mots) pour chaque état (c’est-à-dire
un dialogue et une image intermédiaires).
14
2.9.2 Entraı̂nement de QGen avec Policy Gradient
Bien que plusieurs approches existent dans la littérature RL, nous optons pour les méthodes de
gradient de politique car elles sont connues pour s’adapter à de grands espaces d’action. Ceci est particu-
lièrement important dans notre cas car la taille du vocabulaire est d’environ 5 000 mots. L’optimisation
de la politique a pour objectif de trouver une politique πθ (u|x) qui maximise le rendement attendu,
également appelée valeur moyenne :
" T
#
X
t−1
J(θ) = Eπθ γ r (xt , ut ) (2.6)
t=1
où γ ∈ [0, 1] est le facteur d’actualisation (discount factor), T la longueur de la trajectoire et l’état de
départ x1 est tiré d’une distribution p1. Notez que γ = 1 est autorisé car nous sommes dans le scénario
épisodique [Sutton et al., 1999]. Pour améliorer la politique, ses paramètres peuvent être mis à jour dans
la direction du gradient de la valeur moyenne :
Notez que l’estimation dans Eq (1) n’est valable que si la distribution de probabilité de l’état initial x1
est uniformément distribuée. La fonction de valeur d’état-action Qπθh (x, u) peut ensuite être estimée
soit en apprenant un approximateur de fonction (méthodes acteur-critique), soit par des déploiements
de Monte-Carlo (REINFORCE [Williams, 1992]). Dans REINFORCE, la somme interne des actions est
estimée en utilisant les actions de la trajectoire. Par conséquent, l’équation (1) peut être simplifiée pour :
* T
+
X
πθh
∇J (θh ) = ∇θh log πθh (ut |xt ) (Q (xt , ut ) − b) (2.10)
t=1 Th
Enfin, en utilisant le GuessWhat ? ! notation de jeu pour Eq (2), le Policy Gradient du QGen peut s’écrire
comme suit :
* J Ij
XX E
∇J (θh ) = ∇θh log πθh wji |wj1:i−1 , (q, a)1:j−1 , I Qπθh wj1:i−1 , (q, a)1:j−1 , I , wji − b
Th
j=1 i=1
(2.11)
15
Entraı̂nement de QGen avec REINFORCE [1]
16
Précisions des modèles de la performance humaine du QGen formé avec baseline et REINFORCE. Les
nouveaux objets font référence à l’échantillonnage uniforme des objets dans l’ensemble d’apprentissage,
tandis que les nouvelles images font référence à l’ensemble de test.
2.10 Expériences
Comme déjà dit, nous avons utilisé l’ensemble de données GuessWhat ? ! comprenant 155 281 dialogues
contenant 821 955 paires question / réponse composées de 4900 mots de 66 537 images uniques et de 134
074 objets uniques. Le code source des expériences est disponible sur https://guesswhat.ai.
2.10.2 Résultats
Précision : Comme nous nous intéressons aux performances au niveau humain, nous rapportons la
précision des modèles sous forme de pourcentage des performances humaines (84,4%), estimées à partir
de l’ensemble de données. Nous reportons les scores dans le tableau 2.7, dans lesquels nous comparons
des objets d’échantillonnage de l’ensemble d’apprentissage (Nouveaux objets) et de l’ensemble d’essai
(Nouvelles images), c’est-à-dire des images invisibles. Nous rapportons l’écart type sur 5 analyses afin
de prendre en compte la stochasticité de l’échantillonnage. Sur la série de tests, la référence obtient
une précision de 45,0%, tandis que l’entraı̂nement avec REINFORCE passe à 62,0%. Il s’agit également
d’une amélioration significative par rapport à la baseline de recherche de faisceaux (beam-search baseline),
qui atteint 53,0% sur l’ensemble de tests. La procédure de recherche de faisceau (beam-search) améliore
l’échantillonnage par rapport à la baseline, mais abaisse de manière intéressante le score de REINFORCE.
Echantillons : Nous comparons qualitativement les deux méthodes en analysant quelques échantillons
générés, comme indiqué dans le tableau 2.8. Nous observons que la base de recherche de faisceaux formée
de manière supervisée ne cesse de répéter les mêmes questions, comme on peut le voir dans les deux
premiers exemples du tableau. 1. Nous avons constaté ce comportement en particulier sur l’ensemble
de tests, c’est-à-dire lorsque nous sommes confrontés à des images invisibles, ce qui peut mettre en
17
Échantillons extraits de l’ensemble de test. Le cadre bleu (resp. Violet) correspond à l’objet choisi par
le devineur pour le dialogue de recherche de faisceau - beam search- (resp. REINFORCE). La petite
description verbeuse est ajoutée pour faire référence à l’objet sélectionné par le devineur.
évidence certains problèmes de généralisation. Nous constatons également que la base de recherche de
faisceaux génère des questions plus longues (7,1 tokens en moyenne) par rapport à REINFORCE (4,0
tokens en moyenne). Cette différence qualitative est clairement visible dans l’exemple en bas à gauche, qui
souligne également que la ligne de base supervisée génère parfois des séquences de questions pertinentes
du point de vue visuel mais incohérentes. Par exemple, demander «Is it the one to the right of the
girl in ?» n’est pas une suite très logique de «Is it the one in the middle with the red umbrella ?». En
revanche, REINFORCE semble mettre en œuvre une stratégie plus fondée et plus pertinente : ”Is it girl in
white ?” est une suite raisonnable de ”Is it a person ? ?”. En général, nous observons que REINFORCE est
favorable pour énumérer les catégories d’objets («is it a person ?») ou d’informations spatiales absolues
(«Is it left ?»). Notez que ce sont également les types de questions auxquelles l’oracle est censé répondre
correctement. C’est pourquoi REINFORCE est en mesure d’adapter sa stratégie aux forces de l’oracle.
Longueur du dialogue : Pour le QGen formé à REINFORCE, nous étudions l’impact de la durée
du dialogue sur le taux de succès de la figure 2.9. Fait intéressant, REINFORCE apprend à s’arrêter
en moyenne après 4,1 questions, bien que nous n’ayons pas codé de pénalité de question dans la fonc-
tion récompense. Le devineur peut appliquer cette règle car poser des questions supplémentaires mais
bruyantes réduit considérablement la précision de prédiction du devineur comme indiqué dans Tab 2.8.
Par conséquent, le QGen apprend à ne plus poser de questions lorsqu’un dialogue contient suffisamment
d’informations pour récupérer l’objet cible. Cependant, nous observons que le QGen s’arrête parfois trop
tôt, surtout lorsque l’image contient trop d’objets de la même catégorie. Fait intéressant, nous avons
également constaté que la recherche de faisceau (beam-search) ne parvient pas à arrêter le dialogue. La
recherche par faisceau utilise une vraisemblance logarithmique normalisée en longueur pour marquer les
séquences candidates afin d’éviter un biais vers des questions plus courtes. Cependant, des questions dans
GuessWhat ? ! presque toujours commencent par «is it», ce qui augmente la log-vraisemblance moyenne
d’une question de manière significative. Le score d’une nouvelle question pourrait donc (presque) toujours
être supérieur à celui émis par un seul jeton <stop>. Notre conclusion a également été confirmée par le
fait qu’une procédure d’échantillonnage a effectivement mis fin au dialogue.
Vocabulaire : L’échantillonnage à partir de la ligne de base supervisée sur l’ensemble de tests donne 2
893 mots uniques, tandis que celui du modèle formé par REINFORCE réduit sa taille à 1 194. Cependant,
la recherche de faisceau utilise uniquement 512 mots uniques, ce qui est cohérent avec la faible variété
observée de questions.
18
Rapport d’achèvement des tâches de QGEN formé par REINFORCE en fonction de la longueur de
dialogue
19
Chapitre 3
Apprentissage automatique
Je me base principalement dans ce chapitre sur le cours d’apprentissage de M2 de Paris Sud de Sylvain
Arlot et Francis Bach , et aussi la thèse ”Apprentissage par renforcement développemental” de Matthieu
Zimmer.
3.1 Généralités
L’apprentissage automatique est basé sur la théorie des probabilités et les statistiques (Hastie et al.,
2009) et l’optimisation (Boyd et Vandenberghe, 2004), est la base du big data, la science des données
(Blei et Smyth, 2017 ; Provost et Fawcett, 2013), la modélisation prédictive (Kuhn et Johnson, 2013),
l’exploration de données, la récupération d’informations (Manning et al., 2008), etc., et devient un in-
grédient essentiel de la vision par ordinateur, du traitement du langage naturel, de la robotique, etc.
L’apprentissage par renforcement est proche du contrôle optimal (Bertsekas, 2012), et la recherche opé-
rationnelle et la gestion (Powell, 2011), et est également liée à la psychologie et aux neurosciences (Sutton
et Barto, 2017). L’apprentissage automatique est un sous-ensemble de l’intelligence artificielle (IA) et est
en train de devenir critique pour tous les domaines de l’IA.
Ce chapitre sert principalement à introduire des techniques d’apprentissage automatique que nous
utiliserons en apprentissage par renforcement dans la suite . En particulier, la régression par descente de
gradient avec des réseaux de neurones.
L’apprentissage automatique consiste à modéliser une application mesurable C : X 7→ Y à partir de
données qu’on appelle un prédicteur/classifieur . Selon les données disponibles et l’objectif , nous classons
généralement l’apprentissage automatique en apprentissage supervisé, non supervisé et par renforcement.
Dans l’apprentissage supervisé, il existe des données étiquetées ; dans l’apprentissage non supervisé, il n’y
a pas de données étiquetées ; et dans l’apprentissage par renforcement, il y a des retours d’évaluation, mais
20
pas de signaux supervisés. La classification et la régression sont deux types de problèmes d’apprentissage
supervisé, avec des sorties catégorielles et numériques respectivement.
3.2.2 Formalisme
(Cours Orsay) On dispose de n observations Dn := (Xi , Yi )16i6n qui sont i.i.d de loi inconnue P. Si
on se donne une nouvelle réalisation (Xn+1 , Yn+1 ), on veux prédire Yn+1 sachant Yn+1 en minimisant
l’erreur de prédiction. Le but du classifieur C est de fournir une étiquette C(Xn+1 ) à Xn+1 en espérant
de coı̈ncider C(Xn+1 ) avec Yn+1 .
On définit la fonction contraste pour mesurer la qualité du classifieur :
γ : S × (X × Y) → R
(c, (x, y)) 7→ γ(c, (x, y))
L’objectif est désormais de trouver c ∈ S := [ensemble des classifieurs] qui minimise la fonction perte Pγ
définie par :
Pγ (c) := E(X,Y)∼P [γ(c, (X, Y))]
On appelle prédicteur de Bayes tout prédicteur c∗ qui minimise la fonction de perte :
c∗ := argminc∈S Pγ (c)
Sachant qu’on ne peut pas trouver un meilleur prédicteur que le prédicteur de Bayes, le but est alors de
s’approcher au plus du prédicteur de Bayes au sens de minimiser la perte relative définie par :
Comme la loi P est inconnue , on doit estimer les objets introduits précédemment . On appelle estimateur
toute application mesurable qui à un n-échantillon associe un classifieur :
c^ : (X × Y)n → S
Notons que la perte Pγ (^ c, (X, Y)) | Dn ] est aléatoire. On appelle l’exces de risque l’espérance
c) := E [γ(^
∗
de la perte relative : E(l(c , c^)).
On dit qu’il y a une consistance faible pour la loi P si :
n→∞
E(l(c∗ , c^(Dn ))) → 0
Régression Dans le cas de la régression on considère que : Y = R . Ici,Y est donc continue. On peut
toujours écrire que Y et X sont reliés par la relation :
Y = η(X) + ε (3.1)
21
avec η(X) = E[Y|X]. Ceci implique que E[ε|X] = 0. On dénit le contraste des moindres carrés par :
En effet ,
Pγ(t) = E (t(X) − Y)2
= E (t(X) − η(X) − ε)2 (3.4)
= E (t(X) − η(X))2 + E ε2 − 2E[E[ε(t(X) − η(X))|X]]
Or,
E[E[ε(t(X) − η(X))|X]] = E[(t(X) − η(X))) E[ε|X]] = 0 (3.5)
| {z }
=0
∗
si bien que η = s est un prédicteur de Bayes qui réalise l’égalité.
No free lunch theorem on n’a rien sans rien. Le théorème suivant montre que dans le cas de la
classication il n’est pas possible d’avoir une consistance universelle faible uniforme pour le contraste 0-1
(γ0−1 (t, (x, y)) = γ(t, (x, y)) = 1t(x)6=y ) sur l’ensemble des lois sur X × Y lorsque X est inni.
Théorème 3.2.1. Si X est inni, Y = {0, 1}, γ = γ0−1 , alors pour tout entiern ∈ N et pour tout estimateur
s^ : (X, Y)n → S :
1
sup {EDn ∼P⊗n [ℓ (s⋆ , b
s (Dn ))]} > (3.6)
P loi sur X×Y 2
Démonstration. Soit un entierK > 1 et A1 , . . . , AK ∈ X. Pour simplier,on suppose Ai = i pour tout i.
Soit r ∈ {0, 1}K fixé.On dénit une loi Pr sur X × Y comme suit :
et Y = rX est une fonction de X uniquement. Ainsi, sous la loi Pr,s⋆ (X) = s⋆r (X) = rX et Pr γ (s⋆r ) = 0.
On écrit alors que :
{EDn ∼P⊗n [ℓ (s , b
supP loi sur X×Y s (Dn ))]}
⋆
où R est une loi quelconque sur {0, 1}K . Réécrivons la dernière probabilité écrite an de pouvoir échanger
l’ordre d’intégration (c’est-à-dire, prendre d’abord une moyenne vis-à-vis de r, et ensuite moyenner par
rapport aux Xi et à X :
22
Récapitulatif des méthodes d’optimisation et leurs hypothèses.
Donc ,
s (Dn ; X) 6= Y)
Pr∼R,Dn ∼Pr⊗ n (X, Y) ∼ Pr (b
1
> P (X ∈/ {X1 , . . . , Xn })
2
1
= E [P (X1 6= X, . . . , Xn 6= X) |X] (3.11)
2
1
= E [P (X1 6= X|X) × · · · × P (Xn 6= X) |X]
2 n
1 1
= 1−
2 K
En faisant tendre K vers + ∞, on obtient la minoration cherchée.
Plus la MSE est petite, meilleur est le modèle. Pour un modèle paramétrique Ψθ , les paramètres
optimaux θ∗MSE sont donc :
n
1X
θ∗MSE = arg min kΨθ (xi ) − yi k22
θ∈Θ n i=1
Pour résoudre ce problème d’optimisation, il existe de nombreuses méthodes ayant chacune des hypo-
thèses et garanties diérentes. On cite les méthodes les plus couramment utilisées dans la table [3.2]. Un
gradient calculable pour J signie que ∇θ J (Ψθ ) existe.
23
gradient est pertinent. Néanmoins, comme toutes méthodes dépendantes du gradient, elles sont sujettes
à rester bloquées dans un optimal local et sont lentes lorsque des plateaux surviennent dans le gradient.
On suppose que les hypothèses suivantes soient verifiées :
— H1 : Ω est un ouvert convexe de Rd .
— H2 : J est une fonction de classe C2 de Ω dans R
— H3 : ∀x ∈ Ω, z → d2 J(x)(z, z) est une forme bilinéaire définie positive.
— H4 : x0 ∈ Ω et K = {x ∈ Ω/J(x) 6 J (x0 )} est un compact de Ω et x∗ le point optimal de J.
Une conséquence de H3 et H4 est l’ellipticité de J :
aK = min d2 J(x)(z, z)
(x,z)∈K×Sd−1
qui est bien un nombre strictement positif (aK est atteint, en au moins un point (xm , zm ) par compacité
de K × Sd−1 , de plus, aK > 0 puisque d2 J (xm ) est une forme bilinéaire définie positive).
Ensuite,la compacité et la convexité de K entrainent aussi la lipschitzianité des dérivées premières :
où
AK = min d2 J(x)(z, z) = sup kHJ (x)kop
(x,z)∈K×Sd−1 x∈K
Un lemme important,
Lemme 3.2.1. Sous les hypothèses (H1), (H2), (H3), (H4), on a pour tout x ∈ K :
aK AK
kx − x∗ k2 6 J(x) − J (x∗ ) 6 kx − x∗ k2
2 2
Démonstration. La formule de Taylor à l’ordre 2 donne pout tout x ∈ K :
Z1
∗ t
J(x) = J (x ) + (X − X∗ ) HJ (x∗ + θ (x − x∗ )) (X − X∗ ) (1 − θ)dθ
0
avec :
aK kx − x∗ k2 6t (X − X∗ ) HJ (x∗ + θ (x − x∗ )) (X − X∗ ) 6 AK kx − x∗ k2
Le lemme est immédiat.
~
Une remarque importane : Si x ∈ K et si x 6= x∗ , on définit l’intervalle Ix = {t ∈ R/x − t∇J(x) ∈ Ω}.
C’est un intervalle ouvert qui contient t = 0 et au voisinage de 0 on a d’après Taylor :
~
J(x − t∇J(x)) ~
= J(x) − tk∇J(x)k 2
+ O t2
L’ensemble
~
Ax = t ∈ Ix /J(x − t∇J(x)) < J(x)
aK 2 ~ ~ ~ AK 2 ~
t k∇J(x)k2 6 J(x − t∇J(x)) − J(x) − tk∇J(x)k2
6 t k∇J(x)k2
2 2
En particulier,
2 2
6 Tx 6
AK aK
Dans l’algorithme de la descente à pas dixe , le pas ρ ne dépends pas de l’itération , et pour garantir
la stabilité dans K , on suppose de plus que 0 < ρ < A2K d’après la remarque précedente .
24
2
Théorème 3.2.2. On suppose les hypothèses H1,H2,H3 et H4 vérifiées. On fixe ρ tel que 0 < ρ < AK .
On définit xk par récurrence à partir de x0 par :
~ (xk )
xk+1 = xk − ρ∇J
~
Démonstration. On a vu que si 0 < ρ < A2K , alors, lorsque x ∈ K, x − ρ∇J(x) reste bien dans K, de sorte
′
que la suite (xk ) est bien dénie par récurrence. Supposons que J (x) 6= 0.
De plus, on a :
~ 2 AK 2 ′ 2
J(x − ρ∇J(x)) 6 J(x) − ρ kJ′ (x)k + ρ kJ (x)k
2
Donc , J (xk+1 ) 6 J (xk ). Comme (J (xk ))k∈N est décoissante et minorée par J (x∗ ), elle est convergente.
De plus, on a :
AK ρ
J′ xk) k2 6 J (xk ) − J (xk+1 )
ρ 1−
2
On en déduit que :
lim J′ (xk ) = 0
k→+∞
de sorte que
1
lim sup kxk − x∗ k 6 lim kJ′ (xk )k = 0
k→+∞ aK k→+∞
∂J (Ψθt )
θt+1 ← θt − α
∂θt
25
stabilité, il est ainsi préférable d’utiliser une partie importante de l’échantillon disponible.
Data: Un modèle paramétrique Ψθ , un critère J à minimiser,(∆max , ∆min ) ∈ R2+ : la variation
maximale et minimale sur une itération, (∆+ , ∆− ) ∈ R2+ : l’augmentation et la diminution
de la variation sur une itération,et t ∈ N : l’itération
initialization;
for θi ∈ Θ do
(t−1) (t)
z ← ∇θi J ·∇ θi J
(t−1)
(t)
min ∆θ
i ∆+ , ∆max si z < 0
∆θi ←
max ∆θ(t−1) ∆− , ∆min si z > 0
i
if z<0 then
∇θi J(t) ← 0end
end
(t) (t)
∆θi ← −∆θi signe ∇θi J(t)
(t+1) (t) (t)
θi ← θi + ∆θi
Algorithm 1: Resilient backpropagation iRPROP
Il existe de nombreuses améliorations possibles à la descente de gradient stochastique classique. Il
s’agit d’ADAM ( Adaptive Moment Estimation Optimizer), l’algorithme [] le plus utilisé qui estime la
moyenne et la variance du gradient pour chaque paramètre de façon géométriquement décroissante par
rapport au temps (Kingma et Ba, 2015). Grâce à ces estimations, la mise à jour des paramètres est plus
lisse et la variance réduite. Néanmoins, dans cet algorithme, il faut définir un taux d’apprentissage global
α. Cet algorithme est utilisé en deep learning (Goodfellow et al., 2016) et en renforcement (Lillicrap et
al., 2015).
Data: Un modèle paramétrique Ψθ , un critère J à minimiser,(∆max , ∆min ) ∈ R2+ : la variation
maximale et minimale sur une itération, (∆+ , ∆− ) ∈ R2+ : l’augmentation et la diminution
de la variation sur une itération,et t ∈ N : l’itération
for θi ∈ Θ do
(t−1) (t)
z ← ∇θi J ·∇ θi J
min ∆θ(t−1) ∆+ , ∆max si z < 0
(t)
∆θi ← i
(t−1)
max ∆θ
i ∆− , ∆min si z > 0
if z<0 then
∇θi J(t) ← 0end
end
(t) (t)
∆θi ← −∆θi signe ∇θi J(t)
(t+1) (t) (t)
θi ← θi + ∆θi
Algorithm 2: Resilient backpropagation iRPROP
Data: Un modèle paramétrique Ψθ , un critère J à minimiser,α ∈ R : le taux d’apprentissage ,
(β1 , β2 ) ∈ R2+ : taux d’apprentissage pour l’estimation exponentiellement décroissante de la
moyenne et de la variance, ζ ∈ R :décalage pour éviter une division par 0 et t ∈ N l’itération
for θi ∈ Θ do
(t) (t−1)
µi ← β1 µi + (1 − β1 ) ∇θi J(t)
(t) (t−1) 2
σi ← β2 σi + (1 − β2 ) ∇θi J(t)
√ (t)
(t+1) (t) 1−β2 q µi
θi ← θi − α 1−β1 (t)
σi +ζ
end
3.2.4 Limitations
Il existe plusieurs limitations à l’utilisation de modèles pour approcher une fonction. Nous allons
maintenant aborder les plus importantes.
26
Exemple de sur/sous-apprentissage [OpenClassrooms]
Surapprentissage ou généralisation
Lors de l’optimisation des paramètres, il est possible qu’un phénomène de surapprentissage [Fig.3.3]
survienne : il s’agit d’une mauvaise généralisation des données qui n’a pas été présentée dans le modèle
(figure 1.6 à droite). La source du surapprentissage peut provenir essentiellement de deux origines : trop
de liberté laissée au modèle (trop de neurones, de couches, de fonctions de base, etc.) ou un temps
d’apprentissage long pour certaines données. On dit d’un modèle qui a trop appris qu’il avait réussi à
apprendre le bruit présent dans l’échantillon et non la relation sous-jacente entre l’entrée et la sortie.
Pour détecter ce phénomène d’apprentissage, il est possible d’utiliser la validation croisée (Kohavi,
1995). Dans sa version la plus simple, il s’agit de couper l’échantillon, sur lequel J est calculé, en deux sous-
ensembles : l’ensemble d’apprentissage et l’ensemble de test.Les échantillons appartenant à l’ensemble
d’apprentissage seront utilisés pour mettre à jour les paramètres du modèle. Tandis que ceux appartenant
à l’ensemble de test ne serviront qu’à évaluer le modèle sans modification.
La régularisation permet de modifier le critère à optimiser de façon à privilégier les modèles avec
une complexité plus simple. La justification de cette pratique provient du principe du rasoir d’Ock-
ham. En pratique, elle permet de limiter de manière efficace le surapprentissage (Girosi et al., 1995).
Mathématiquement, on ajoute un terme au critère J à optimiser :
27
3.3 Apprentissage par renforcement
L’apprentissage par renforcement (Sutton et Barto,1998) repose sur l’utilisation de données indirecte-
ment étiquetées par des récompenses. Cet étiquetage est moins informatif qu’en apprentissage supervisé.
Comme on a vu que en apprentissage supervisé,il existe un oracle de type oracle(xi ) = yi pour étiqueter
les données à priori,pourtant en l’apprentissage par renforcement cet oracle n’est capable que de quan-
tifier une relation de type : oracle(xi , yi ) = récompense. De plus, les données (et leur ordre) présentées
à l’oracle ne sont pas maı̂trisées entièrement par l’utilisateur. L’hypothèse d’avoir des données i.i.d n’est
pas valable et il n’existe pas de base de données a priori. Or, cette hypothèse est largement utilisée dans
l’analyse formelle de nombreux algorithmes d’apprentissage automatique.[5]
Le chapitre 4 est consacré à l’apprentissage par renforcement avec des explications plus profondes.
28
Un neurone formel
29
Un perceptron multicouche avec X = R4 et une couche cachée de 3 neurones.
n
!
X
Ψθ,φ (x, j, 1) = φ1 θ0,j,1 + θi,j,1 xi
i=1
où k ∈ {1, . . . , m + 1} indice les couches, j ∈ {1, . . . , hk } indice les neurones des couches et i indice les
P
poids d’un perceptron. Le nombre de paramètres |θ| = (n + 1) · h1 + m i=2 (hi−1 + 1) · hi + hm + 1
Pour éviter le calcul répetitif de l’activation d’un même neurone , on fait un calcul couche par couche
en partant de la couche d’entrée et en gardant en mémoire chaque activation pour la couche suivante.
Dans cet exemple [Fig. 3.5], la fonction calculée est la suivante :
!!
3
X 4
X
Ψθ,φ (x) = φ2 θ0,1,2 + θj,1,2 φ1 θ0,j,1 + θi,j,1 xi
j=1 i=1
30
Chapitre 4
4.1 Introduction
L’apprentissage par renforcement est un domaine de l’apprentissage automatique qui s’intéresse à la
façon dont les agents logiciels doivent prendre des mesures dans un environnement afin de maximiser la
notion de récompense cumulative. L’apprentissage par renforcement est considéré comme l’un des trois
paradigmes d’apprentissage automatique, aux côtés de l’apprentissage supervisé et de l’apprentissage non
supervisé.
Il diffère de l’apprentissage supervisé en ce que les paires d’entrée / sortie étiquetées ne doivent pas
être présentées et que les actions sous-optimales ne doivent pas être explicitement corrigées. Au lieu de
cela, l’objectif est de trouver un équilibre entre l’exploration (d’un territoire inexploré) et l’exploitation
(du savoir actuel).
L’environnement est généralement formulé sous la forme d’un processus de décision de Markov (MDP),
car de nombreux algorithmes d’apprentissage par renforcement utilisés dans ce contexte utilisent des
techniques de programmation dynamique. La principale différence entre les méthodes classiques de pro-
grammation dynamique et les algorithmes d’apprentissage par renforcement réside dans le fait que ces
derniers ne supposent pas la connaissance d’un modèle mathématique exact du MDP et ciblent de grands
MDP où les méthodes exactes deviennent irréalisables.
Un aspect clé de RL est qu’un agent apprend un bon comportement. Cela signifie qu’il modifie ou
acquiert de nouveaux comportements et de nouvelles compétences. Un autre aspect important de RL
est qu’il utilise l’expérience des essais et des erreurs (par exemple, une programmation dynamique qui
suppose une connaissance totale de l’environnement a priori). Ainsi, l’agent RL ne nécessite pas une
connaissance ou un contrôle complet de l’environnement ; il doit seulement être capable d’interagir avec
l’environnement et de collecter des informations. En mode offline, l’expérience est acquise a priori, puis
elle est utilisée en tant que lot d’apprentissage (le paramètre en mode offline est également appelé lot
RL).
Ceci est en contraste avec le mode online où les données deviennent disponibles dans un ordre sé-
quentiel et sont utilisées pour mettre à jour progressivement le comportement de l’agent. Dans les deux
cas, les algorithmes d’apprentissage de base sont essentiellement les mêmes, mais la principale différence
est que, dans un environnement en ligne, l’agent peut influencer la manière dont il rassemble l’expérience
pour qu’il soit le plus utile pour l’apprentissage. C’est un défi supplémentaire, principalement parce que
l’agent doit faire face aux dilemme exploration / exploitation pendant l’apprentissage. Mais l’apprentis-
sage en ligne peut également constituer un avantage, car l’agent est capable de collecter des informations
spécifiques sur la partie la plus intéressante de l’environnement. Pour cette raison, même lorsque l’envi-
ronnement est parfaitement connu, les approches RL peuvent constituer l’approche la plus efficace sur le
plan des calculs par rapport à certaines méthodes de programmation dynamiques qui seraient inefficaces
en raison de ce manque de spécificité.
31
Interaction agent-environnement dans RL
4.2 Formalisation
4.2.1 Le cadre d’apprentissage du renforcement
Le problème RL général est formalisé en tant que processus de contrôle stochastique temporel discret
dans lequel un agent interagit avec son environnement de la manière suivante : l’agent démarre, dans un
état donné dans son environnement s0 ∈ S, en recueillant une première observation ω0 ∈ Ω.A chaque
pas de temps t,l’agent doit prendre une action at ∈ A. Comme illustré à la figure ??, il en résulte trois
conséquences :
1. L’agent obtient une récompense rt ∈ R.
2. La transiton de l’état st ∈ S à st+1 ∈ S
3. L’agent obtient une observation ωt+1 ∈ Ω.
Cette configuration a été proposée par Bellman, 1957b, puis étendu à l’apprentissage par Barto et al.,
1983. Sutton et Barto, 2017, traitent de manière exhaustive les principes fondamentaux de RL. Nous en
présentons ici les principaux éléments de RL.
32
— γ ∈ [0, 1[ est le facteur discount.
Le système est entièrement observable dans un MDP, ce qui signifie que l’observation est la même
que l’état de l’environnement : ωt = st . A chaque pas de temps t, la probabilité de passer à St+1 est
donnée par la fonction de transition d’état T (st , at , st+1 ) et la récompense est donnée par une fonction
de récompense bornée R (st , at ). Ceci est illustré à la figure [fig].
On définit formellement un problème d’apprentissage par renforcement comme un PDM où T et R
sont à priori inconnus.
où T est l’instant final si la vie de l’agent peut être découpée en épisodes de plusieurs pas de temps , et
on dit que les taches sont épisodiques.Autrement, on a des taches continues, dans ce cas l’instant final
serait T = ∞ et le retour Rt pourrait être infini. Donc pour borner ce dernier , on introduit la notion de
retour déprécié :
∞
X
Rt = rt+1 + γrt+2 + γ2 rt+3 + · · · = γk rt+k+1 = rt+1 + γRt+1 (4.2)
k=0
où γ ∈ [0, 1] est le facteur de dépréciation qui permet de régler l’importance accordée aux récompenses
futures vis-à-vis des récompenses immédiates.Le plus souvent, on choisit γ ∈]0, 1[.
Nous considérons le cas d’un agent RL dont le but est de trouver une politique π(s, a) ∈ Π, afin
d’optimiser le retour attendu V π (s) : S → R appelée fonction valeur (V-value) qui estime à quel point il
est bon pour l’agent d’être dans un état particulier. On a :
" ∞
#
X
π k
V (s) = E γ rt+k+1 |st = s, π (4.3)
k=0
avec :
— rt = E R (st , a, st+1 )
a∼π(st ,·)
Cette équation peut être récrite récursivement dans le cas d’un MDP :
33
V π (s) = Eπ {Rt |st = s}
∞
X
k
= Eπ γ rt+k+1 |st = s
k=0
∞
X (4.4)
k
= Eπ rt+1 + γ γ rt+k+2 |st = s
k=0
" #
X X
s′ π ′
= π(s, a) Rsa + γ Tsa V (s )
a∈A(s) s′ ∈S+
′
s
avec Tsa = T(s, a, s′ ) . Cette dernière, s’appelle l’équation de Bellman pour V π .
De plus, le retour optimal est défini par :
La particularité de la fonction action-valeur Q par rapport à la fonction valeur V est que la politique
optimale peut être obtenue directement à partir de Q∗ (s, a) :
La fonction valeur optimale V ∗ est la récompense escomptée attendue dans un état donné s tout en
suivant la politique π par la suite. La valeur optimale Q∗ (s, a) est le retour actualisé attendu dans un
état donné s et pour une action donnée a tout en suivant la politique π par la suite.
On cherche à exprimer récursivement la fonction valeur optimale V ∗ , on a :
a∈A(s)
34
Il est également possible de définir la fonction avantage :
qui décrit la qualité de l’action a par rapport au rendement attendu lors de suivi direct de la politique
π.
35
Schéma général des méthodes RL profond
également l’efficacité du calcul, qui dépend, entre autres choses, de l’efficacité d’un pas de descente de
gradient donné. Tous ces éléments seront introduits avec plus de détails dans les chapitres suivants. La
figure 4.2 présente un schéma général des différents éléments que l’on peut trouver dans la plupart des
algorithmes RL profond.
36
principaux éléments de l’algorithme DQN (deep Q-network) (Mnihet al., 2015) qui a permis un contrôle
de niveau surhumain lorsqu’il joue à des jeux ATARI à partir des pixels en utilisant des réseaux naturels
comme approximateurs de fonctions. Nous passons ensuite en revue diverses améliorations de l’algorithme
DQN et fournissons des ressources pour des détails supplémentaires. À la fin de ce chapitre et dans le
chapitre suivant, nous discutons du lien ultime entre les méthodes basées sur la valeur et les méthodes
basées sur les politiques.
4.5.1 Q-learning
où B est l’opérateur de Bellman mappant une fonction quelconque K : S× A → R dans une autre fonction
S × A → R et est défini comme suit :
X
(BK)(s, a) = T (s, a, s′ ) R (s, a, s′ ) + γ max
′
K (s′
, a ′
) (4.13)
a ∈A
s′ ∈S
L’opérateur Bellman est une contraction car il peut être démontré que pour toute paire de fonctions
bornées K, K′ : S × A → R ( l’espace des fonctions bornées est un espace métrique complet ) on a :
X
|(BK − BK′ )(s, a)| = γ T (s, a, s′ ) max K (s′ , a′ ) − max K′ (s′ , a′ ) 6 γ kK − K′ k∞ (4.14)
′ a′ ∈A a′ ∈A
s ∈S
Donc,
kBK − BK′ k∞ 6 γ kK − K′ k∞ (4.15)
Donc, d’après le théorème de point fixe de Banach ,le point fixe de l’opérateur Bellman B existe.
Dans la pratique, il existe une preuve générale de la convergence vers la fonction valeur optimale
(Watkins et Dayan, 1992) dans les conditions suivantes :
— les paires état-action sont représentées discrètement, et
— toutes les actions sont échantillonnées de manière répétée dans tous les états (ce qui garantit une
exploration suffisante, ne nécessitant donc pas d’accès au modèle de transition).
Cette méthode simple est souvent inapplicable en raison de l’espace d’action d’états de grande dimension
(éventuellement continu). Dans ce contexte, une fonction de valeur paramétrée Q(s, a; θ) est nécessaire,
où θ fait référence à certains paramètres qui définissent les Q-valeurs.
où θk fait référence à certains paramètres qui définissent les valeurs Q à la k-ème itération. Dans l’ap-
prentissage neuronal ajusté ( Neural fitted Q-learning : NFQ) (Riedmiller, 2005), l’état peut être fourni
en tant qu’entrée au Q-réseau et une sortie différente est donnée pour chacune des actions possibles. Ceci
fournit une structure efficace qui présente l’avantage d’obtenir le calcul de maxa′ ∈A Q (s′ , a′ ; θk ) en un
37
seul passage en avant dans le réseau neuronal pour un donnée s′ . Les Q-valeurs sont paramétrées avec un
réseau de neurones Q (s, a; θk ) où les paramètres θk sont mis à jour par descente de gradient stochastique
(ou une variante) en minimisant la perte :
2
LDQN = Q (s, a; θk ) − YkQ (4.17)
où α est le taux d’apprentissage. Notez que l’utilisation de la perte carrée n’est pas arbitraire. En
effet, il garantit que Q (s, a; θk ) tendra sans biais à la valeur attendue de la variable aléatoire YkQ .He,
il s’assure que Q (s, a; θk ) tendra à Q∗ (S, a) après plusieurs hypothèses dans l’hypothèse selon laquelle
le réseau de neurones est bien adapté à la tâche et que l’expérience acquise dans le jeu de données D
est suffisante (plus de détails à ce sujet au chapitre 7). Lors de la mise à jour des poids, on modifie
également la cible. En raison des capacités de généralisation et d’extrapolation des réseaux de neurones,
cette approche peut générer de grosses erreurs à différents endroits de l’espace d’état. Par conséquent, la
propriété de cartographie de contraction du Bellman de l’opérateur dans l’équation 4.2 n’est pas suffisant
pour garantir la convergence. Il est vérifié expérimentalement que ces erreurs peuvent se propager avec
cette règle actualisée et que, par conséquent, la convergence peut être lente, voire instable (Baird, 1995 ;
Tsitsiklis et Van Roy, 1997 ; Gordon, 1999 ; Riedmiller, 2005). L’utilisation d’approximateurs de fonction
est un autre effet secondaire néfaste lié au fait que les valeurs Q ont tendance à être surestimées en raison
de l’opérateur max (Van Hasseltet al., 2016). En raison des instabilités et du risque de surestimation, un
soin particulier a été apporté pour assurer un apprentissage correct.
38
Esquisse de l’algorithme DQN
fins spécifiques telles que la mise en œuvre du risque comportement conscient. Nous commençons par des
résultats théoriques à la fois dans les paramètres d’évaluation et de contrôle des politiques, ce qui révèle
une instabilité distributive importante dans ces derniers. Ensuite, on va détailler la perspective distribu-
tionnelle pour concevoir un nouvel algorithme qui applique l’équation de Bellman à l’apprentissage des
distributions de valeurs approximatives faite dans l’article [11].
Comme on l’a déja expliqué, l’un des principes majeurs de l’apprentissage par renforcement est qu’un
agent doit viser à maximiser son utilité Q ou valeur attendue (Sutton Barto, 1998). L’équation de
Bellman décrit succinctement cette valeur en termes de récompense attendue et de résultat attendu de
la transition aléatoire (x, a) → (X′ , A′ ) :
Dans la suite , nous visons à aller au-delà de la notion de valeur et d’arguments en faveur d’une perspective
distributionnelle de l’apprentissage par renforcement. Plus précisément, nous voulons étudier le retour
aléatoire Z plutot que so éspérence qui est la valeur Q . Ce retour aléatoire est également décrit par une
équation récursive, mais de nature distributive :
D
Z(x, a) = R(x, a) + γZ (X′ , A′ ) (4.20)
Notations
La métrique de Wasserstein
L’outil principal de notre analyse est la métrique de Wasserstein dp entre les fonctions de distribution
cumulatives (voir par exemple Bickel Freedman, 1981, où il s’appelle la métrique de Mallows). Pour F,G
deux f.d.r sur les réels, il est défini comme :
39
où l’inmum est pris sur toutes les paires de variables aléatoires (U, V) avec les distributions cumulatives
respectives F et G. L’inmum est atteint par l’inverse f.d.r transformation d’une variable aléatoire U
uniformément répartie sur [0, 1] :
dp (F, G) =
F−1 (U) − G−1 (U)
p (4.22)
Nous trouverons commode de concilier les variables aléatoires considérées avec leurs versions sous inf, en
écrivant :
dp (U, V) = inf kU − Vkp (4.25)
U,V
chaque fois sans ambiguı̈té ; Nous croyons que la plus grande lisibilité justifie l’inexactitude technique.
Enfin, nous étendons cette métrique aux vecteurs de variables aléatoires, telles que les distributions de
valeurs, en utilisant la norme Lp correspondante.
La métrique dp a les propriétés suivantes :
Nous aurons besoin de la propriété supplémentaire suivante dans la suite, qui ne fait aucune hypothèse
d’indépendance sur ses variables.
Lemme 4.5.1. Soit A1 , A2 , . . . des variables aléatoires décrivant une partition de Ω, c’est-à-dire
Ai (ω) ∈ {0, 1} et pour tout ω, il existe exactement un Ai avec Ai (ω) = 1. Soit U, V deux variables
aléatoires.Alors :
X
dp (U, V) 6 dp (Ai U, Ai V) (4.27)
i
Démonstration. Nous allons donner la preuve pour p < ∞,notant qu’il en va de même pour p = ∞.Soit
D D
Yi := Ai U et Zi := Ai V.D’abord noter que :
p
dp
p (Ai U, Ai V) = inf E [|Yi − Zi | ]
Yi ,Zi
(4.28)
= inf E [E [|Yi − Zi |p |Ai ]]
Yi ,Zi
Maintenant |Ai U − Ai V|p = 0 chaque fois que Ai = 0. Il s’ensuit que nous pouvons choisir Yi , Zi pour
que aussi |Yi − Zi |p = 0 à chaque fois que Ai = 0, sans augmenter la norme . Par conséquent :
dp
p (Ai U, Ai V) = inf Yi ,Zi §ePr {Ai = 1} E [|Yi − Zi |p |Ai = 1] (4.29)
Ensuite,
X X
inf Pr {Ai = 1} E [|Ai U − Ai V|p |Ai = 1] 6 inf Pr {Ai = 1} E [|Yi − Zi |p |Ai = 1]
U,V Y1 ,V2 ,...,Z1 ,Z2 ,...
i i
(4.30)
Plus précisément, le membre de gauche de l’équation est un infinimum sur toutes les variables aléatoires
dont les distributions cumulatives sont FU et FV , respectivement, tandis que le côté droit est un in
40
finimum sur les suites de variables aléatoires Y1 , Y2 , . . . et Z1 , Z2 , . . . dont les distributions cumulatives
sont FAi U , FAi V , respectivement. Pour prouver cette limite supérieure, considérons la f.d.r de U :
FU (y) = Pr{U 6 y}
X
= Pr {Ai = 1} Pr {U 6 y|Ai = 1}
i (4.31)
X
= Pr {Ai = 1} Pr {Ai U 6 y|Ai = 1}
i
D
D’autre part, la f.d.r de Yi = Ai U est :
Ensuite ,
dpp (U, V) = inf U,V kU − Vkp
= inf U,V E [|U − V|p ]
(a) P (4.33)
= inf U,V i Pr {Ai = 1} E [|U − V|p |Ai = 1]
P
= inf U,V i Pr {Ai = 1} E [|Ai U − Ai V|p |Ai = 1]
où (a) suit parce que A1 , A2 , . . . est une partition.En utilisant 4.30, cela implique :
dpp (U, V)
P
= inf U,V i Pr {Ai = 1} E [|Ai U − Ai V|p |Ai = 1]
P
6 inf Y1 ,Z2 ,... i Pr {Ai = 1} E [|Yi − Zi |p |Ai = 1] (4.34)
(b) P p
= iYi ,Zi Pr {Ai = 1} E [|Yi − Zi | |Ai = 1]
(c) P
= i dp (Ai U, Ai V)
parce que dans (b) les composants individuels de la somme sont indépendamment minimisé ; et (c) de
(4.29).
Soit Z l’espace des distributions de valeur avec borné des moments. Pour deux distributions de valeurs
Z1 , Z2 ∈ Z, nous utiliserons une forme maximale de la métrique de Wasserstein :
Démonstration. La seule propriété non triviale est l’inégalité triangulaire. Pour toute distribution de
valeurs Y ∈ Z, on a :
Évaluation de la politique
Dans le cadre de l’évaluation de la politique (Sutton Barto, 1998), nous nous intéressons à la fonction
de valeur V π associée à une politique donnée π. L’analogue ici est la distribution de la valeur Zπ . Dans
cette section, nous caractérisons Zπ et étudions le comportement de l’opérateur d’évaluation de politique
T π . Nous soulignons que Zπ décrit le caractère aléatoire intrinsèque des interactions de l’agent avec son
environnement, plutôt qu’une mesure de l’incertitude concernant l’environnement lui-même.
41
Nous considérons la fonction de récompense comme un vecteur aléatoire R ∈ Z et définissons l’opéra-
teur de transition Pπ : Z → Z :
D
Pπ Z(x, a) := Z (X′ , A′ )
(4.37)
X′ ∼ P(·|x, a), A′ ∼ π (·|X′ )
où nous utilisons des majuscules pour souligner le caractère aléatoire du prochain couple action-état
(X′ , A′ ). Nous définissons l’opérateur de distribution Bellman T π : Z → Z :
Bien que T π présente une ressemblance superficielle avec l’opérateur habituel de Bellman (2), il est
fondamentalement différent. En particulier, trois sources d’aléatoire définissent la distribution du composé
TπZ :
— Le caractère aléatoire de la récompense R,
— Le hasard dans la transition Pπ , et
— La distribution de valeur d’état suivant Z (X′ , A′ ).
En utilisant le lemme 4.5.3, nous concluons en utilisant le théorème du point fixe de Banach que T π a
un point fixe unique. Lors de l’inspection, ce point fixe doit être Zπ tel que défini précedement. Comme
nous supposons que tous les moments sont bornés, il suffit de conclure que la suite {Zk } converge vers
Z avec dp pour 1 6 p 6 ∞. Pour conclure, nous remarquons que toutes les métriques de distribution
ne sont pas égales ; Par exemple, Chung Sobel (1987) ont montré que T π n’est pas une contraction
de la distance de variation totale. Des résultats similaires peuvent être obtenus pour la divergence de
Kullback-Leibler et la distance de Kolmogorov.
Dans cette section, nous proposons un algorithme basé sur l’opérateur d’optimalité de distribution
de Bellman. Cela nécessitera en particulier de choisir une distribution approximative. Bien que le cas
gaussien ait été précédemment considéré (Morimura et al., 2010a ; Tamar et al., 2016), on va utiliser une
riche classe de distributions paramétriques considéré par (https ://arxiv.org/abs/1707.06887).
Distribution paramétrique Nous allons modéliser la distribution des valeurs en utilisant une distri-
bution discrète paramétrée par N ∈ N et VMIN , VMAX ∈ R, et dont le support est l’ensemble des atomes
−VMIN
{zi = VMIN + i△z : 0 6< N} , ∆z := VMAX N−1 . En un sens, ces atomes sont les «retours canoniques» de
notre distribution. Les probabilités atomiques sont données par un modèle paramétrique θ : X×A → RN :
eθi (x,a)
Zθ (x, a) = zi w.p. pi (x, a) := P θ (x,a) (4.39)
je
j
La distribution discrète présente les avantages d’être hautement expressif et convivial sur le plan com-
putationnel (voir par exemple Van den Oord et al., 2016).
42
Mise à jour projetée de Bellman L’utilisation d’une distribution discrète pose un problème : la mise
à jour de Bellman TZθ et la paramétrisation Zθ ont presque toujours des appuis disjoints. Il semblerait
naturel de minimiser la distance de Wasserstein (considéré comme une perte) entre TZθ et Zθ , ce qui
est également commodément robuste aux écarts dans le support. Cependant, un deuxième problème
empêche cela : dans la pratique, nous sommes généralement limités à l’apprentissage à partir de transitions
d’échantillon, ce qui n’est pas possible avec la perte de Wasserstein.
Au lieu de cela, nous projetons l’exemple de mise à jour de Bellman TZ ^ θ sur le support de Zθ (figure
1, algorithme 1), ce qui réduit efficacement la mise à jour de Bellman à la classification à plusieurs classes.
Soit π la politique gourmande (greedy policy) relativement à EZθ . Étant donné un exemple de transition
(x, a, r, x′ ), on calcule la mise à jour de Bellman Tz^ j := r + γzj pour chaque atome zj , puis on distribue sa
^ j . La i-ème composante de la mise à jour projetée
probabilité pj (x′ , π (x′ )) à les voisins immédiats de Tz
^
ΦTZθ (x, a) est :
1
^ VMAX
N−1
X Tzj VMIN − zi
^
ΦTZθ (x, a) i = 1− pj (x′ , π (x′ )) (4.40)
△z
j=0
0
où[·]b
a limite son argument dans l’intervalle [a, b]. Comme d’habitude, nous considérons la distribution
de l’état suivant comme paramétrée par un paramètre xé θ̃. La perte d’échantillon Lx,a (θ) est le terme
d’entropie croisée (cross-entropy) de la divergence de KL :
DKL ΦTZ ^ (x, a)kZθ (x, a) (4.41)
θ̃
qui est facilement minimisé, par exemple en utilisant la descente de gradient. Nous appelons ce choix
de distribution et de perte l’algorithme catégorique [algo]. Lorsque N = 2, une alternative simple à un
paramètre est :
^ θ (x, a) := E TZ
ΦTZ ^ θ (x, a) − VMMN /△z]10 (4.42)
Nous appelons cela l’algorithme de Bernoulli. Nous notons que, bien que ces algorithmes ne semblent pas
liés à la métrique de Wasserstein, des travaux récents (Bellemare et al., 2017) suggèrent une connexion
plus profonde. Voir annexe [].
Data: Une transition xt , at , rt , xt+1 , γt ∈ [0, 1]
P
Result: Cross-entropy loss :− i mi log pi (xt , at )
P
Q (xt+1 , a) := i zi pi (xt+1 ,
a∗ ← arg maxa Q (xt+1 , a)
mi = 0, i ∈ 0, . . . , N − 1
for j ∈ 0, . . . , N − 1 do
^ j sur le support {zi }
Calculer la projection de Tz
^ VMAX
Tzj ← [rt + γt zj ]VMAX
bj ← Tz ^ j − VMIN /∆z avec bj ∈ [0, N − 1]
l ← ⌊bj ⌋ , u ← ⌈bj ⌉
^ j
Distribution de la probabilité de Tz
∗
ml ← ml + pj (xt+1 , a ) (u − bj )
mu ← mu + pj (xt+1 , a∗ ) (bj − l)
end
43
(b) Esquisse (dans une version idéalisée) de
l’estimation de la distribution des valeurs
^π1 et Z
résultantes Z ^π2 ainsi que l’estima-
(a) Exemple d’un MDP ^
tion des Q-valeurs Qπ1 et Q ^ π2 . .
Pour deux politiques illustrées sur la figure (a), l’illustration sur la figure (b) donne la distribution de
Z(π) (s, a) comparée à la valeur attendue Qπ (s, a). Sur la figure de gauche, on peut voir que π1 passe avec
certitude à un état absorbant avec une récompense à chaque pas Rmax 5 , tandis que π2 se déplace avec une
probabilité de 0,2 et 0,8 dans des états absorbants avec des récompenses à chaque pas respectivement
Rmax et 0. À partir de la paire (s, a), les politiques π1 et π2 ont le même rendement attendu mais des
distributions de valeurs différentes.
où (s0 , a0 , r0 , · · · , sn−1 , an−1 , rn−1 , sn ) est toute trajectoire de n+1 pas de temps avec s = s0 et a = a0 .
Une combinaison de différentes cibles multi-étapes peut également être utilisée :
n−1 i
!
X X
YkQ,n = λi t
γ rt + γ i+1 ′
max Q (si+1 , a ; θk ) (4.44)
a′ ∈A
i=0 t=0
Pn−1
avec i=0 λi = 1. Dans la méthode appelée TD(λ) (Sutton, 1988),n → ∞ et λi suivent une loi géomé-
trique : λi ∝ λi où 0 0 6 λ 6 1. Vous trouverez un exemple d’implémentation de cette méthode dans
A.
44
Chapitre 5
L’apprentissage profond
5.1 Approche
L’apprentissage en profondeur repose sur une fonction f : X → Y paramétrée par θ ∈ Rnθ (nθ ∈ N) :
y = f(x, θ) (5.1)
Un réseau neuronal profond est caractérisé par une succession de multiples couches de traitement. Chaque
couche consiste en une transformation non linéaire et la séquence de ces transformations conduit à
l’apprentissage de différents niveaux d’abstraction (Erhan et al., 2009 ; Olah et al., 2017).
Tout d’abord, décrivons un réseau de neurones très simple avec une couche cachée entièrement connec-
tée (fig 5.1). La première couche reçoit les valeurs d’entrée (c’est-à-dire les entités en entrée) x sous la
forme d’un vecteur colonne de taille nx . Les valeurs de la couche cachée suivante sont une transformation
de ces valeurs par une fonction paramétrique non linéaire, qui est une multiplication par une matrice W1
de taille nh × nx ,plus un terme de biais b1 de taille nh , suivi d’une transformation non linéaire :
h = A (W1 · x + b1 ) (5.2)
où A est la fonction d’activation.Cette fonction d’activation non linéaire est ce qui rend la transformation
au niveau de chaque couche non linéaire, ce qui fournit finalement l’expressivité du réseau de neurones.
Les choix les plus populaires de la fonction d’activation sont [fig] :
e2x −1
— la tangente hyperbolique : tanh(x) = e2x +1
. Elle sert principalement à la classification entre deux
classes.
x
— la sigmoı̈de (ou fonction logistique) : σ(x) = 1+e1−x = exe+1 .La principale raison pour laquelle nous
utilisons cette fonction est à valeurs dans [0; 1]. Par conséquent, il est particulièrement utilisé pour
les modèles dans lesquels nous devons prédire la probabilité en tant que sortie.
— softmax 2.3 : est une fonction d’activation logistique plus généralisée utilisée pour la classification
multiclass.
— rectified linear unit (ReLU) : f(x) = x+ = max(0, x) . Elle est actuellement la fonction d’activation
la plus utilisée dans le monde. Depuis, elle est utilisée dans presque tous les réseaux de neurones
convolutifs ou d’apprentissage en profondeur.
— softplus : f(x) = log (1 + ex )
La couche cachée h peut à son tour être transformé en d’autres ensembles de valeurs jusqu’à la
dernière transformation fournissant les valeurs de sortie y. Dans ce cas :
y = (W2 · h + b2 ) (5.3)
45
Fonctions d’activations
46
Toutes ces couches sont formées pour minimiser l’erreur empirique IS [f]. La méthode la plus courante
d’optimisation des paramètres d’un réseau neuronal est basée sur la descente de gradient via l’algorithme
de rétro-propagation (Rumelhart et al., 1988). Dans le cas le plus simple, à chaque itération, l’algorithme
modifie ses paramètres internes θ afin de les adapter à la fonction souhaitée :
où ℓ(Y, Φ) est une fonction de perte (loss) qui mesure la concordance entre la sortie réelle, Y, et la
sortie prédite,Φ(X, W),Θ est une fonction de régularisation conçue pour empêcher le surajustement, par
PK
k
2 , et λ > 0 est un
exemple : la décroissance du poids via la régularisation ℓ2 ,Θ(W) = k=1 W F
paramètre d’équilibrage.
47
Exemple de points critiques d’une fonction non convexe (indiqués en rouge). (a, c) Plateaux. (b, d)
minima globaux. (e, g) maxima locaux. (f, h) Minimums locaux.
dans le cas contraire, à choisir une autre initialisation. En pratique, il a été observé que si la taille du
réseau était suffisamment grande, cette stratégie pouvait conduire à des solutions très différentes pour les
pondérations du réseau, qui donnaient presque les mêmes valeurs objectives et les mêmes performances
de classification [22]. Il a également été observé que lorsque la taille du réseau est suffisante et que la
fonction ReLU est choisie, de nombreux poids sont nuls, un phénomène appelé neurones morts (dead
neurons) et la performance de la classification s’améliore considérablement [37], [ 38], [39], [40]. Bien que
ceci suggère empiriquement que lorsque la taille du réseau est suffisante et que les non-linéarités ReLU
sont utilisées, tous les minima locaux puissent être globaux, il n’existe actuellement aucune théorie rigou-
reuse fournissant une explication mathématique précise à ces phénomènes observés expérimentalement.
[https ://arxiv.org/abs/1712.04741]
où Y est l’espace cible qui peut être considéré comme discret dans une configuration de classification
standard ( C = |Y| étant le nombre de classes), ou Y = RC dans une tâche de régression. Dans la grande
majorité des tâches de vision par ordinateur et d’analyse de la parole, la fonction inconnue f satisfait
généralement les hypothèses cruciales suivantes :
1. Stationnarité : Considérons un opérateur de translation
En fonction de la tâche, nous supposons que la fonction f est soit invariante, soit équivariante
par rapport aux translations. Dans le premier cas, nous avons f (Tv X) = f(X) pour tout X ∈
L2 (Ω) et v ∈ Ω. C’est généralement le cas dans les tâches de classification d’objets. Dans ce dernier
cas, nous avons f (Tv X) = Tv f(X),ce qui est bien défini lorsque la sortie du modèle est un espace
dans lequel les translations peuvent agir (par exemple, en cas de problèmes de localisation d’objet,
de segmentation sémantique ou d’estimation de mouvement). La définition de l’invariance ici ne
doit pas être confondue avec la notion traditionnelle de systèmes invariants de translation dans le
traitement du signal, qui correspond à l’équivariance de translation dans notre langue (car la sortie
traduit chaque fois que l’entrée est translatée).
2. Déformations locales et la séparation à l’échelle : De même, une déformation Lτ définit sur L2 (Ω)
par Lτ X(u) = X(u − τ(u)), où τ : Ω → Ω est un champ vectoriel lisse. X (u) = X (u - (u)).
48
Les déformations peuvent modéliser des translations locales, des changements de point de vue, des
rotations et des transpositions de fréquence [9]. La plupart des tâches étudiées dans la vision par
ordinateur ne sont pas seulement invariantes / équivariantes en translation, mais surtout stables
en ce qui concerne les déformations locales [52], [9]. Dans les tâches invariantes à la translation,
nous avons :
|f (Lτ X) − f(X)| ≈ k∇τk (5.9)
pour tout X, τ, où k∇τk mesure la régularité d’un champ de déformation donné. En d’autres termes,
la quantité à prédire ne change pas beaucoup si l’image d’entrée est légèrement déformée. Dans les
tâches qui sont équivariantes en translation, nous avons
Cette propriété est beaucoup plus forte que la stationnarité, car l’espace des déformations locales a
une grande dimensionnalité - de l’ordre de RD lorsque nous discrétisons des images avec D pixels,
par opposition au groupe de translation d-dimensionnel qui n’a que d = 2 dimensions dans le cas
d’images.
Les hypothèses (5.9) - (5.10) peuvent être exploitées pour se rapprocher de f à partir des entités
Φ(X) qui réduisent progressivement la résolution spatiale. En effet, extraire, démoduler et sous-
échantillonner les réponses de filtre localisées crée des résumés locaux insensibles aux traductions
locales, mais cette perte de perte de sensibilité n’affecte pas notre capacité à approcher f, grâce à
(5.9) - (5.10). Pour illustrer ce principe, notons
la distribution conjointe de deux pixels d’image décalés de v l’un de l’autre. En présence de dé-
pendances statistiques à long terme, cette distribution conjointe ne sera séparable d’aucun v. Ce-
pendant, la stabilité de la déformation antérieure indique que Z (a1 , a2 ; v) ≈ Z (a1 , a2 ; v(1 + ǫ))
pour les ǫ petits. En d’autres termes, alors que les dépendances à long terme existent bien dans
la nature et sont essentielles à la reconnaissance des objets, elles peuvent être capturées et sous-
échantillonnées à différentes échelles. Bien que ce principe de stabilité aux déformations locales ait
été exploité dans la communauté de la vision par ordinateur dans des modèles autres que les CNN,
par exemple, les modèles de pièces déformables [53], les CNN trouvent un bon équilibre en termes
de pouvoir d’approximation, d’optimisation et d’invariance.
En effet, la stationnarité et la stabilité vis-à-vis des traductions locales sont toutes deux mises
à profit dans les réseaux de neurones à convolution (CNN). Un CNN est constitué de plusieurs
couches convolutives de la forme X̃ = CW (X) agissant sur une entrée de p−dimension X(u) =
(X1 (u), . . . , Xp (u)) en appliquant une banque de filtres W = (wl,l′ ) , l = 1, . . . , q, l′ = 1, . . . , p et
une fonction non-linéaire ponctuelle ψ :
p
!
X
X̃l (u) = ψ (Xl′ ⋆ wl,l′ ) (u) (5.12)
l′ =1
et en produisant une sortie q-dimensionnelle X̃(u) = X̃1 (u), . . . , X̃q (u) souvent appelé cartes de
caractéristiques (feature maps). Ici,
Z
(X ⋆ w)(u) = X (u − u′ ) w (u′ ) du′ (5.13)
Ω
désigne la convolution standard. Selon la déformation locale préalable, les filtres W ont un support
spatial compact. De plus, une couche de sous-échantillonnage ( downsampling) ou de regroupement
(pooling) X̃ = P(X) peut être utilisé, défini comme :
où N(u) ⊂ Ω est un voisinage autour de u et P est une fonction invariante de la permutation telle
qu’un pooling moyen, énergétique ou maximal).
49
Un réseau de convolution est construit en composant plusieurs couches de convolution et éventuel-
lement de regroupement, obtenant une représentation hiérarchique générique.
50
avantages spécifiques, en fonction de l’application (par exemple, un bon compromis entre biais et sur-
ajustement dans un environnement d’apprentissage supervisé). De plus, dans un réseau de neurones
donné, un nombre arbitrairement grand de couches est possible, et la tendance ces dernières années est
d’avoir un nombre toujours croissant de couches, avec plus de 100 tâches d’apprentissage supervisées
(Szegedy et al. ., 2017). Nous décrivons simplement ici deux types de couches présentant un intérêt
particulier dans deep RL (et dans de nombreuses autres tâches).
Les couches convolutives (LeCun, Bengio et al., 1995) sont particulièrement bien adaptées aux images
et aux données séquentielles (voir Fig.), principalement en raison de leur propriété d’invariance de tra-
duction. Les paramètres de la couche consistent en un ensemble de filtres (ou noyaux) pouvant être
appris, qui ont un petit champ de réception et qui appliquent une opération de convolution à l’entrée,
transmettant le résultat à la couche suivante. En conséquence, le réseau apprend les filtres qui s’activent
lorsqu’il détecte certaines fonctionnalités spécifiques. En classification d’image,les premières couches ap-
prennent à détecter les arêtes, les textures et les motifs ; les couches suivantes sont ensuite capables de
détecter des parties d’objets et des objets entiers (Erhan et al., 2009 ; Olah et al., 2017). En fait, une
couche convolutive est un type particulier de couche à anticipation, avec la spécificité que de nombreuses
pondérations sont définies sur 0 (non pouvant être apprises) et que d’autres pondérations sont partagées.
Les couches récurrentes sont particulièrement bien adaptées aux données séquentielles (voir la figure).
Plusieurs variantes offrent des avantages particuliers dans différents contextes. Un tel exemple est le réseau
de mémoire à court terme (LSTM) (Hochreiter et Schmidhuber, 1997), capable de coder des informations
à partir de séquences longues, contrairement à un réseau de neurones récurrent de base. Les machines
de Turing neurales (MNT) (Graves et al., 2014) en sont un autre exemple. Dans de tels systèmes, une
”mémoire externe” différenciable est utilisée pour déduire des dépendances même à plus long terme que
les LSTM à faible dégradation.
Plusieurs autres architectures de réseaux de neurones spécifiques ont également été étudiées pour
améliorer la généralisation dans l’apprentissage en profondeur. Par exemple, il est possible de concevoir
une architecture de telle sorte qu’elle ne se concentre automatiquement que sur certaines parties des
entrées avec un mécanisme appelé attention (Xu et al., 2015 ; Vaswani et al., 2017). D’autres approches
visent à travailler avec des règles symboliques en apprenant à créer des programmes (Reed et De Freitas,
2015 ; Neelakantan et al., 2015 ; Johnson et al., 2017 ; Chen et al., 2017). Pour des informations sur
des sujets tels que l’importance des normalisations d’entrée, les techniques d’initialisation du poids, les
techniques de régularisation et les différentes variantes des techniques de descente de gradient, le lecteur
peut consulter plusieurs revues sur le sujet (LeCun et al., 2015 ; Schmidhuber, 2015 ; Goodfellow et al.,
2016) ainsi que des références y figurant.
Dans la suite, l’accent est mis sur l’apprentissage par renforcement, en particulier sur les méthodes
permettant d’approcher les approximateurs des fonctions de réseaux neuronaux en profondeur. Ces mé-
thodes permettent d’apprendre une grande variété de tâches de prise de décision séquentielles complexes
directement à partir d’intrants riches en dimensions.
5.6.1 Introduction
Les humains ne commencent pas à réfléchir à la seconde. En lisant ce rapport, vous comprenez chaque
mot en fonction de votre compréhension des mots précédents. Vous n’éliminez pas tout et commencez à
penser à nouveau. Vos pensées sont persévérantes. Les réseaux de neurones traditionnels ne peuvent pas
faire cela, et cela semble être une lacune majeure. Par exemple, imaginons que vous souhaitiez classer le
type d’événement qui se produit à chaque étape d’un film. On ignore comment un réseau de neurones
traditionnel pourrait utiliser son raisonnement sur les événements précédents du film pour en informer les
événements ultérieurs. Les réseaux de neurones récurrents répondent à ce problème. Ce sont des réseaux
avec des boucles, permettant aux informations de persister.
Dans le diagramme ci-dessus (5.4) , un bloc de réseau neuronal, A : examine une entrée Xt et génère
une valeur ht . Une boucle permet aux informations d’être transmises d’une étape du réseau à la suivante.
51
Exemple d’un RNN : medium.com
Un réseau de neurones récurrent peut être considéré comme plusieurs copies du même réseau, chacune
transmettant un message à un successeur. Considérez ce qui se passe si nous déroulons la boucle :
Cette nature en chaı̂ne révèle que les réseaux de neurones récurrents sont intimement liés aux sé-
quences et aux listes. C’est l’architecture naturelle du réseau de neurones à utiliser pour de telles données.
Et ils sont certainement utilisés ! Au cours des dernières années, les applications RNN ont rencontré un
succès incroyable pour une variété de problèmes : reconnaissance de la parole, modélisation du langage,
traduction, sous-titrage d’images. . . La liste est longue. Bien que ce ne soit pas obligatoire, il serait bon
que le lecteur comprenne ce que sont les WordVectors. Voici mon blog précédent sur Word2Vec, une
technique permettant de créer des vecteurs Word.
52
3. Entrée de séquence (par exemple, analyse de sentiment où une phrase donnée est classée comme
exprimant un sentiment positif ou négatif)
4. Entrée de séquence et sortie de séquence (par exemple, traduction automatique : un RNN lit une
phrase en anglais, puis en affiche une en français).
5. Entrée et sortie de séquence synchronisée (par exemple, classification vidéo où nous souhaitons
étiqueter chaque image de la vidéo).
Notez que dans tous les cas, il n’existe pas de contraintes prédéfinies sur les séquences de longueurs, car
la transformation récurrente (vert) est fixe et peut être appliquée autant de fois que nous le souhaitons.
Je me base dans la partie suivante sur [23].
où ~x(t) est le vecteur du signal d’entrée de dimension d et ~h(~s(t), ~x(t)) est une fonction à valeur vectorielle
des arguments à valeur vectorielle. Le système résultant,
d~s(t) ~ ~
= h(~s(t), ~x(t)) + φ (5.18)
dt
survient dans de nombreuses situations en physique, chimie, biologie et ingénierie. Dans certains cas,
on commence avec s et x en tant que quantités entièrement «analogiques» (c’est-à-dire, fonctions non
seulement du temps, t, mais aussi d’une autre variable continue indépendante,~ξ, désignant les coordonnées
dans un espace multidimensionnel). En utilisant cette notation, l’intensité d’un signal vidéo d’entrée
affiché sur un écran plat à 2 dimensions serait représentée par x(~ξ, t) avec ~ξ ∈ R2 . L’échantillonnage
de x(~ξ, t) sur une grille uniforme à 2 dimensions convertit ce signal en représentation x(~i, t) , où ~i est
un indice discret à 2 dimensions. Enfin, l’assemblage des valeurs de x(~i, t) pour toutes les permutations
53
des composants de l’indice,~i, dans un vecteur colonne, produit ~x(t) comme initialement présenté dans
l’équation 5.18 ci-dessus.
Une autre forme canonique de ~f(t) est :
~f(t) = a
~ (t) + ~b(t) + ~c(t) (5.19)
dont les termes constitutifs,~a(t), ~b(t), et ~c(t), sont des fonctions à valeurs vectorielles d-dimensionnelles
du temps t. Ils sont définis comme suit :
s −1
KX
~ (t) =
a ~ k (~s (t − τs (k)))
a
k=0
r −1
KX
~b(t) = ~bk (~r (t − τr (k)))
k=0
(5.20)
~r (t − τr (k)) = G (~s (t − τr (k)))
x −1
KX
~c(t) = ~ck (~x (t − τx (k)))
k=0
Notre objectif est d’encoder chaque mot en utilisant un vecteur dans Rd , de sorte que les mots ayant
une signification similaire soient proches.En raison de la disparition des gradients dans les RNN standards,
les gradients ne se propagent pas bien à travers le réseau : impossible d’apprendre les dépendances à long
terme. C’est pour cela on introduit les LSTM qui vont contournés ce problème parfaitement .
5.7 LSTM
Je me base dans cette section sur [24]
5.7.1 Introduction
Long short-term memory est une architecture de réseau de neurones récurrents artificiels (RNN) uti-
lisée dans le domaine de l’apprentissage en profondeur. Contrairement aux réseaux neuronaux à réaction
standard, le LSTM dispose de connexions de retour qui en font un ”ordinateur polyvalent” (c’est-à-dire
qu’il peut calculer tout ce que peut une machine de Turing). Il peut non seulement traiter des points de
données uniques (tels que des images), mais également des séquences complètes de données (telles que
la parole ou la vidéo). Par exemple, LSTM est applicable à des tâches telles que la reconnaissance de
l’écriture manuscrite connectée ou la reconnaissance vocale non segmentées . Bloomberg Business Week
a écrit : ”Ces pouvoirs font de LSTM le succès commercial le plus commercial de l’IA, utilisé pour tout,
de la prévision des maladies à la composition musicale” .
Une unité LSTM commune est composée d’une cellule, d’une porte d’entrée, d’une porte de sortie et
d’une porte d’oublie. La cellule se souvient des valeurs sur des intervalles de temps arbitraires et les trois
portes régulent le flux d’informations entrant et sortant de la cellule.
Les réseaux LSTM sont bien adaptés à la classification, au traitement et à la prévision sur la base
de données chronologiques, car il peut y avoir des décalages d’une durée inconnue entre les événements
importants d’une série chronologique. Les LSTM ont été développés pour traiter les problèmes de gradient
explosifs et évanescents que l’on peut rencontrer lors de la formation de RNN traditionnels. L’insensibilité
relative à la longueur de l’espace est un avantage du LSTM par rapport aux RNN, aux modèles de Markov
cachés et à d’autres méthodes d’apprentissage par séquence dans de nombreuses applications [citation
requise].
5.7.2 Principe
En théorie, les RNN classiques (ou ”à la vanilla”) peuvent suivre les dépendances arbitraires à long
terme dans les séquences d’entrée. Le problème des RNN vanillas est de nature informatique (ou pra-
tique) : lors de la formation d’un RNN vanilla en back-propagation, les gradients qui sont rétro-propagés
54
LSTM Cell
peuvent ”disparaı̂tre” (c’est-à-dire qu’ils peuvent tendre à zéro) ou ”exploser” ( c’est-à-dire qu’ils peuvent
tendre vers l’infini), en raison des calculs impliqués dans le processus, qui utilisent des nombres à préci-
sion finie. Les RNN utilisant des unités LSTM résolvent partiellement le problème de gradient de fuite,
car les unités LSTM permettent également aux gradients de circuler sans modification. Cependant, les
réseaux LSTM peuvent toujours souffrir du problème de la dégradation du gradient. [Wikipedia]
5.7.3 Architecture
Il existe plusieurs architectures d’unités LSTM. Une architecture commune est composée d’une cellule
(la partie mémoire de l’unité LSTM) et de trois ”régulateurs”, généralement appelés portes, du flux
d’informations à l’intérieur de l’unité LSTM : une porte d’entrée, une porte de sortie et une porte
d’oubli. Certaines variantes de l’unité LSTM n’ont pas une ou plusieurs de ces portes, voire d’autres. Par
exemple, les unités récurrentes gated (GRU) n’ont pas de porte de sortie.
Intuitivement, la cellule est chargée de suivre les dépendances entre les éléments de la séquence
d’entrée. La porte d’entrée contrôle dans quelle mesure une nouvelle valeur pénètre dans la cellule, la
porte oublie contrôle dans quelle mesure une valeur reste dans la cellule et la porte de sortie détermine
dans quelle mesure la valeur dans la cellule est utilisée pour calculer la sortie. activation de l’unité LSTM.
La fonction d’activation des portes LSTM est souvent la fonction logistique.
Il existe des connexions dans et hors des portes du LSTM, dont certaines sont récurrentes. Le poids
de ces connexions, qui doivent être apprises au cours de la formation, détermine le fonctionnement des
portes.[Wikipedia]
On note pour la suite :
5.7.4 Variantes
Les phrases ne sont pas une simple séquence linéaire.Notre objectif est de conserver le sens syntaxique
de la phrase . Pour cela , il existe plusieurs variantes de LSTM pour gérer ce problème :
— Child-sum tree LSTM [5.6] : Somme sur tous les enfants d’un noeud : peut être utilisé pour n’im-
porte quel nombre d’enfants. Ce modele permet de prendre en entrée des arbres d’analyse de
phrases : alors que le modèle LSTM standard permet de propager des informations séquentielle-
ment en conditionnant la cellule LTSM d’un mot xt sur l’état du mot précédent xt−1 , l’unité de
mot Child-Sum Tree-LSTM dépend des états de tous les mots enfants de ce mot.
Mêmes vecteurs de déclenchement et mêmes unités de mémoire que la cellule LSTM, mais ces
vecteurs dépendent des états de toutes les unités filles d’un mot.
55
Child-sum tree LSTM au noeud j avec les enfants k1 et k2
Pour un arbre et un noeud j, C(j) est l’ensemble des noeuds enfants du noeud j. Les équations de
transition sont alors les suivantes :
P
1. h̃j = k∈C(j) hk
2. une porte d’entrée (input gate) : ij = σ W i xj + Ui h̃j + bi
3. une porte d’oubli (forgot gate) :fjk = σ W f xj + Uf hk + bf
4. une porte de sortie (output gate) : oj = σ W o ∗ xj + Uo h̃j + bo
5. uj = tanh W u xj + Uu h̃j + bu
P
6. une cellule mémoire : cj = ij ⊙ uj + k∈C(j) fjk ⊙ ck
7. l’état caché du noeud j : hj = oj ⊙ tanh (cj )
— N-ary tree LSTM [5.7] : Utilise différents paramètres pour chaque noeud : meilleure granularité,
mais le nombre maximal d’enfants par noeud doit être fixé. La cellule de mémoire cj et l’état caché
hj sont calculés comme suit :
uj = tanh W (u) xj + U(u) h ^ j + b(u)
ij = σ W (i) xj + U(i) h ^ j + b(i)
(5.21)
oj = σ W (o) xj + U(o) h ^ j + b(o)
X
cj = ck ⊙ fjk + ij ⊙ uj
k∈C(j)
hj = oj ⊙ tanh (cj )
où h^j ∈ Rd2 nj est le vecteur obtenu en concaténant les nj vecteurs hj1 , . . . , hjnj .
(f)
Contrairement à Child-sum Tree-LSTM, les paramètres Uk ∈ Rd2 ×d2 nj ne sont pas partagés
entre les enfants .
56
N-ary Tree-LSTM
premier temps , nous implémentons cet algorithme (Qgen) [voir B] avec les données NLP Stanford
[https://nlp.stanford.edu/sentiment] pour la classification de sentiments,puis pour le problème de
géneration de questions vu comme un porblème de classification multiclass sur l’ensemble de vocabulaire
(1 194 mots unique).
Nous présentons dans le tableau ??, les résultats obtonues de nos implémentation des algorithmes
LSTM simple et Tree-LSTM child sum pour une classification binaire et multiclasse [voir B].
57
Chapitre 6
Conclusion
Dans ce rapport, nous avons proposé de créer un environnement de formation à partir des modèles
supervisés profonds afin de former un agent DeepRL afin de résoudre un problème de dialogue multimodal
axé sur les objectifs. Nous montrons la promesse de cette approche sur les données GuessWhat ? ! , et on
observe quantitativement et qualitativement une amélioration encourageante par rapport à un modèle
de référence supervisé. Alors que les modèles d’apprentissage supervisé ne génèrent pas de stratégie de
dialogue cohérente, notre méthode apprend à quel moment s’arrêter après avoir généré une séquence de
questions pertinentes.
58
Bibliographie
[1] Florian Strub, Harm de Vries, Jeremie Mary, Bilal Piot, Aaron Courville, and Olivier Pietquin.
End-to-end optimization of goal-driven and visually grounded dialogue systems, 2017.
[2] Harm de Vries, Florian Strub, Sarath Chandar, Olivier Pietquin, Hugo Larochelle, and Aaron Cour-
ville. Guesswhat ? ! visual object discovery through multi-modal dialogue, 2016.
[3] Yuxi Li. Deep reinforcement learning : An overview, 2017.
[4] Vincent Francois-Lavet, Peter Henderson, Riashat Islam, Marc G. Bellemare, and Joelle Pineau. An
introduction to deep reinforcement learning. 2018.
[5] Matthieu Zimmer. Apprentissage par renforcement développemental, 2018.
[6] Sarah Filippi. Stratégies optimistes en apprentissage par renforcement, 2011.
[7] Richard S. Sutton and Andrew G. Barto. Introduction to Reinforcement Learning. MIT Press,
Cambridge, MA, USA, 1st edition, 1998.
[8] Trevor Hastie, Robert Tibshirani, and Jerome Friedman. The Elements of Statistical Learning.
Springer Series in Statistics. Springer New York Inc., New York, NY, USA, 2001.
[9] Ashwin K Vijayakumar, Michael Cogswell, Ramprasath R. Selvaraju, Qing Sun, Stefan Lee, David
Crandall, and Dhruv Batra. Diverse beam search : Decoding diverse solutions from neural sequence
models, 2016.
[10] Ian Goodfellow, Yoshua Bengio, and Aaron Courville. Deep Learning. The MIT Press, 2016.
[11] Marc G. Bellemare, Will Dabney, and Rémi Munos. A distributional perspective on reinforcement
learning, 2017.
[12] Rene Vidal, Joan Bruna, Raja Giryes, and Stefano Soatto. Mathematics of deep learning, 2017.
[13] Michael M. Bronstein, Joan Bruna, Yann LeCun, Arthur Szlam, and Pierre Vandergheynst. Geo-
metric deep learning : going beyond euclidean data. 2016.
[14] Raja Giryes, Guillermo Sapiro, and Alex M. Bronstein. Deep neural networks with random gaussian
weights : A universal classification strategy ? 2015.
[15] Joan Bruna Estrach, Arthur Szlam, and Yann LeCun. Signal recovery from pooling representations.
In 31st International Conference on Machine Learning, ICML 2014, volume 2, pages 1585–1598.
International Machine Learning Society (IMLS), 2014.
[16] Aravindh Mahendran and Andrea Vedaldi. Understanding deep image representations by inverting
them, 2014.
[17] E. J. Candes and T. Tao. Near-optimal signal recovery from random projections : Universal encoding
strategies ? IEEE Transactions on Information Theory, 52(12) :5406–5425, Dec 2006.
[18] Venkat Chandrasekaran, Benjamin Recht, Pablo A. Parrilo, and Alan S. Willsky. The convex geo-
metry of linear inverse problems. 2010.
[19] Raja Giryes, Yonina C. Eldar, Alex M. Bronstein, and Guillermo Sapiro. Tradeoffs between conver-
gence speed and reconstruction accuracy in inverse problems, 2016.
[20] Lior Wolf and Amnon Shashua. Learning over sets using kernel principal angles. J. Mach. Learn.
Res., 4 :913–931, December 2003.
[21] E. Elhamifar and R. Vidal. Sparse subspace clustering : Algorithm, theory, and applications. IEEE
Transactions on Pattern Analysis and Machine Intelligence, 35(11) :2765–2781, Nov 2013.
59
[22] Suvro Banerjee. An introduction to recurrent neural networks.
[23] Alex Sherstinsky. Fundamentals of recurrent neural network (rnn) and long short-term memory
(lstm) network, 2018.
[24] Yusuke Shido, Yasuaki Kobayashi, Akihiro Yamamoto, Atsushi Miyamoto, and Tadayuki Matsu-
mura. Automatic source code summarization with extended tree-lstm, 2019.
60
Annexe A
class RandomWalkMDR:
""" Defines the Markov reward process
States are [0, 1, 2, 3, 4, 5, 6] = [Terminal state, A, B, C, D, E, Terminal State]
Actions are [-1, 1] for left and right steps
Returns are 0 everywhere except for landing at the right terminal state (state 6)
"""
def __init__(self):
self.all_states = np.arange(7)
self.start_state = 3 # all episodes start at the center state C (here 3)
self.reset_state()
def reset_state(self):
self.state = self.start_state
self.states_visited = [self.state]
self.rewards_received = []
return self.state
def get_states(self):
return self.all_states
def step(self):
action = [-1, 1][np.random.rand() >= 0.5] # go left or right with equal probability
next_state = self.state + action
reward = self.get_reward(next_state)
self.rewards_received.append(reward)
if not self.is_terminal(next_state):
61
self.state = next_state
self.states_visited.append(next_state)
# Initialize records for episode values (v) and values over episodes
v = np.zeros(len(mdr.get_states()))
v_over_episodes = np.empty((n_episodes+1, len(mdr.get_states())))
v_over_episodes[0] = v.copy()
62
G = sum(gamma**(i - tau) * mdr.rewards_received[i] for i in range(tau, min(ta
if tau + n < T:
state_tpn = mdr.states_visited[tau+n] # state at time step tau + na
G += gamma**n * v[state_tpn]
state_tau = mdr.states_visited[tau] # state at time step tau
v[state_tau] += alpha * (G - v[state_tau])
# episode step
t += 1
if tau == T - 1:
break
# at the end of each episode, add value estimate for current episode to the aggregate
v_over_episodes[episode] = v.copy()
# return average over the episodes for only the non-terminal states
return v_over_episodes[:,1:-1]
# --------------------
# Figure : Performance of n-step TD methods as a function of , for various values of n,
# on a 19-state random walk task
# --------------------
def fig():
mdr = RandomWalk()
true_values = np.linspace(-1, 1, 21)[1:-1]
n_runs = 10
n_episodes = 10
ns = 2**np.arange(10)
alphas = np.hstack((np.linspace(0, 0.1, 10), np.linspace(0.15, 1, 10)))
for i, n in enumerate(ns):
plt.plot(alphas, rms_error[i], label='n={}'.format(n), lw=1)
plt.xlabel(r'$\alpha$')
plt.xlim(plt.gca().get_xlim()[0], max(alphas))
plt.ylim(0.25, 0.55)
plt.ylabel('Average RMS error over {} states and first {} episodes'.format(len(mdr.all_sta
63
plt.legend()
if __name__ == '__main__':
np.random.seed(1)
fig()
In [0]:
64
# Undo the default logger and configure a new one.
gym.undo_logger_setup()
logger = logging.getLogger()
logger.setLevel(logging.WARNING)
if hasattr(cmdl, 'rescale_dims'):
state_dims = (cmdl.rescale_dims, cmdl.rescale_dims)
else:
state_dims = env.observation_space.shape[0:2]
if mode == "training":
env = PreprocessFrames(env, env_class, hist_len, state_dims, cuda)
if hasattr(cmdl, 'reward_clamp') and cmdl.reward_clamp:
env = SqueezeRewards(env)
if hasattr(cmdl, 'done_after_lost_life') and cmdl.done_after_lost_life:
env = DoneAfterLostLife(env)
print('-' * 50)
return env
def not_implemented(obj):
import inspect
method_name = inspect.stack()[1][3]
raise RuntimeError(
clr(("%s.%s not implemented nor delegated." %
(obj.name, method_name)), 'white', 'on_red'))
#### Parsing
""" Functions and classes for parsing config files and command line arguments.
"""
import argparse
import yaml
import os
from termcolor import colored as clr
65
def parse_cmd_args():
""" Return parsed command line arguments.
"""
p = argparse.ArgumentParser(description='')
p.add_argument('-l', '--label', type=str, default="default_label",
metavar='label_name::str',
help='Label of the current experiment')
p.add_argument('-id', '--id', type=int, default=0,
metavar='label_name::str',
help='Id of this instance running within the current' +
'experiment')
p.add_argument('-cf', '--config', type=str, default="catch_dev",
metavar='path::str',
help='Path to the config file.')
p.add_argument('-r', '--results', type=str, default="./experiments",
metavar='path::str',
help='Path of the results folder.')
args = p.parse_args()
return args
def to_namespace(d):
""" Convert a dict to a namespace.
"""
n = argparse.Namespace()
for k, v in d.items():
setattr(n, k, to_namespace(v) if isinstance(v, dict) else v)
return n
def check_paths(cmdl):
if not os.path.exists(cmdl.results_path):
print(
clr("%s path for saving results does not exist. Please create it."
% cmdl.results_path, 'red', attrs=['bold']))
raise IOError
else:
print(clr("Warning, data in %s will be overwritten."
% cmdl.results_path, 'red', attrs=['bold']))
def parse_config_file(path):
f = open(path)
config_data = yaml.load(f, Loader=yaml.SafeLoader)
f.close()
return to_namespace(config_data)
66
def get_config():
args = parse_cmd_args()
cmdl = parse_config_file(args.config)
cmdl = inject_args(cmdl, args)
check_paths(cmdl)
return cmdl
#### wrappers
import unittest
import logging
import torch
import numpy as np
import gym
from gym import Wrapper
from gym import ObservationWrapper
from gym import RewardWrapper
from PIL import Image
from termcolor import colored as clr
from collections import OrderedDict
from utils.torch_types import TorchTypes
logger = logging.getLogger(__name__)
class SqueezeRewards(RewardWrapper):
def __init__(self, env):
super(SqueezeRewards, self).__init__(env)
print("[Reward Wrapper] for clamping rewards to -+1")
class PreprocessFrames(ObservationWrapper):
def __init__(self, env, env_type, hist_len, state_dims, cuda=None):
super(PreprocessFrames, self).__init__(env)
self.env_type = env_type
self.state_dims = state_dims
self.hist_len = hist_len
self.env_wh = self.env.observation_space.shape[0:2]
self.env_ch = self.env.observation_space.shape[2]
self.wxh = self.env_wh[0] * self.env_wh[1]
67
self.dtype = dtype = TorchTypes(self.cuda)
self.rgb = dtype.FT([.2126, .7152, .0722])
def _reset(self):
# self.hist_state.fill_(0)
self.d = OrderedDict(
{i: torch.FloatTensor(1, 1, *self.state_dims).fill_(0)
for i in range(self.hist_len)})
observation = self.env.reset()
return self._observation(observation)
"""
def _get_concatenated_state(self, o):
hist_len = self.hist_len # eg. 4
# move frames already existent one position below
if hist_len > 1:
self.hist_state[0][0:hist_len - 1] = self.hist_state[0][1:hist_len]
# concatenate the newest frame to the top of the augmented state
self.hist_state[0][self.hist_len - 1] = o
return self.hist_state
"""
68
class DoneAfterLostLife(gym.Wrapper):
def __init__(self, env):
super(DoneAfterLostLife, self).__init__(env)
self.no_more_lives = True
self.crt_live = env.unwrapped.ale.lives()
self.has_many_lives = self.crt_live != 0
if self.has_many_lives:
self._step = self._many_lives_step
else:
self._step = self._one_live_step
not_a = clr("not a", attrs=['bold'])
def _reset(self):
if self.no_more_lives:
obs = self.env.reset()
self.crt_live = self.env.unwrapped.ale.lives()
return obs
else:
return self.__obs
if crt_live == 0:
self.no_more_lives = True
else:
self.no_more_lives = False
self.__obs = obs
return obs, reward, done, info
class EvaluationMonitor(Wrapper):
def __init__(self, env, cmdl):
super(EvaluationMonitor, self).__init__(env)
69
if self.cmdl.display_plots:
import Visdom
self.vis = Visdom()
self.plot = self.vis.line(
Y=np.array([0]), X=np.array([0]),
opts=dict(
title=cmdl.label,
caption="Episodic reward per %d steps." % self.eval_steps)
)
self.eval_cnt = 0
self.crt_training_step = 0
self.step_cnt = 0
self.ep_cnt = 1
self.total_rw = 0
self.max_mean_rw = -1000
self.eval_frame_idx = torch.LongTensor(no_of_evals).fill_(0)
self.eval_rw_per_episode = torch.FloatTensor(no_of_evals).fill_(0)
self.eval_rw_per_frame = torch.FloatTensor(no_of_evals).fill_(0)
self.eval_eps_per_eval = torch.LongTensor(no_of_evals).fill_(0)
def _reset_monitor(self):
self.step_cnt, self.ep_cnt, self.total_rw = 0, 0, 0
def _reset(self):
observation = self.env.reset()
self._after_reset(observation)
return observation
70
self.ep_cnt += 1
def _update(self):
mean_rw = self.total_rw / (self.ep_cnt - 1)
max_mean_rw = self.max_mean_rw
self.max_mean_rw = mean_rw if mean_rw > max_mean_rw else max_mean_rw
self._update_plot(self.crt_training_step, mean_rw)
self._display_logs(mean_rw, max_mean_rw)
self._update_reports(mean_rw)
self.eval_cnt += 1
self.eval_frame_idx[idx] = self.crt_training_step
self.eval_rw_per_episode[idx] = mean_rw
self.eval_rw_per_frame[idx] = self.total_rw / self.step_cnt
self.eval_eps_per_eval[idx] = (self.ep_cnt - 1)
torch.save({
'eval_frame_idx': self.eval_frame_idx,
'eval_rw_per_episode': self.eval_rw_per_episode,
'eval_rw_per_frame': self.eval_rw_per_frame,
'eval_eps_per_eval': self.eval_eps_per_eval
}, self.cmdl.results_path + "/eval_stats.torch")
class VisdomMonitor(Wrapper):
def __init__(self, env, cmdl):
super(VisdomMonitor, self).__init__(env)
if self.cmdl.display_plots:
from visdom import Visdom
self.vis = Visdom()
71
self.plot = self.vis.line(
Y=np.array([0]), X=np.array([0]),
opts=dict(
title=cmdl.label,
caption="Episodic reward per 1200 steps.")
)
self.step_cnt = 0
self.ep_cnt = -1
self.ep_rw = []
self.last_reported_ep = 0
def _reset(self):
self._before_reset()
observation = self.env.reset()
self._after_reset(observation)
return observation
def _before_reset(self):
self.ep_rw.append(0)
def _update_plot(self):
# print(self.last_reported_ep, self.ep_cnt + 1)
completed_eps = self.ep_rw[self.last_reported_ep:self.ep_cnt + 1]
ep_mean_reward = sum(completed_eps) / len(completed_eps)
if self.cmdl.display_plots:
self.vis.line(
X=np.array([self.step_cnt]),
Y=np.array([ep_mean_reward]),
win=self.plot,
update='append'
)
self.last_reported_ep = self.ep_cnt + 1
class TestAtariWrappers(unittest.TestCase):
72
def _test_env(self, env_name):
env = gym.make(env_name)
env = DoneAfterLostLife(env)
o = env.reset()
for i in range(10000):
o, r, d, _ = env.step(env.action_space.sample())
if d:
o = env.reset()
print("%3d, %s, %d" % (i, env_name, env.unwrapped.ale.lives()))
def test_pong(self):
print("Testing Pong")
self._test_env("Pong-v0")
def test_frostbite(self):
print("Testing Frostbite")
self._test_env("Frostbite-v0")
if __name__ == "__main__":
import unittest
unittest.main()
class TorchTypes(object):
A.2.2 Agents :
In [0]: ## Base
import time
from termcolor import colored as clr
73
from utils import not_implemented
class BaseAgent(object):
def __init__(self, env_space):
self.actions = env_space[0]
self.action_no = self.actions.n
self.state_dims = env_space[1].shape[0:2]
self.step_cnt = 0
self.ep_cnt = 0
self.ep_reward_cnt = 0
self.ep_reward = []
self.max_mean_rw = -100
74
self.ep_reward.clear()
def display_model_stats(self):
pass
class CategoricalDQNAgent(DQNAgent):
def __init__(self, action_space, cmdl):
DQNAgent.__init__(self, action_space, cmdl)
self.name = "Categorical_agent"
self.cmdl = cmdl
75
# compute gradients
self.policy_improvement.accumulate_gradient(*batch)
self.policy_improvement.update_model()
if self.step_cnt % self.cmdl.target_update_freq == 0:
self.policy_improvement.update_target_net()
def display_model_stats(self):
self.policy_improvement.get_model_stats()
print("MaxQ=%2.2f. MemSz=%5d. Epsilon=%.2f." % (
self.max_q, len(self.replay_memory), self.epsilon))
class DQNAgent(BaseAgent):
def __init__(self, env_space, cmdl):
BaseAgent.__init__(self, env_space)
self.name = "DQN_agent"
self.cmdl = cmdl
eps = self.cmdl.epsilon
e_steps = self.cmdl.epsilon_steps
self.dtype = TorchTypes(cmdl.cuda)
self.max_q = -1000
76
else:
return self.actions.sample()
# compute gradients
self.policy_improvement.accumulate_gradient(*batch)
self.policy_improvement.update_model()
if self.step_cnt % self.cmdl.target_update_freq == 0:
self.policy_improvement.update_target_net()
def display_model_stats(self):
self.policy_improvement.get_model_stats()
print("MaxQ=%2.2f. MemSz=%5d. Epsilon=%.2f." % (
self.max_q, len(self.replay_memory), self.epsilon))
self.max_q = -1000
class EvaluationAgent(object):
def __init__(self, env_space, cmdl):
self.name = "Evaluation"
self.actions = env_space[0]
self.action_no = action_no = self.actions.n
self.cmdl = cmdl
self.epsilon = 0.05
if cmdl.agent_type == "dqn":
self.policy = policy = get_model(cmdl.estimator, 1, cmdl.hist_len,
self.action_no, cmdl.hidden_size)
if self.cmdl.cuda:
self.policy.cuda()
self.policy_evaluation = DeterministicPolicy(policy)
elif cmdl.agent_type == "categorical":
self.policy = policy = get_model(cmdl.estimator, 1, cmdl.hist_len,
(action_no, cmdl.atoms_no),
77
hidden_size=cmdl.hidden_size)
if self.cmdl.cuda:
self.policy.cuda()
self.policy_evaluation = CategoricalPolicyEvaluation(policy, cmdl)
print("[%s] Evaluating %s agent." % (self.name, cmdl.agent_type))
self.max_q = -1000
class RandomAgent(BaseAgent):
def __init__(self, action_space, cmdl):
BaseAgent.__init__(self, action_space)
self.name = "RND_agent"
class AtariNet(nn.Module):
def __init__(self, input_channels, hist_len, out_size, hidden_size=256):
super(AtariNet, self).__init__()
self.input_channels = input_channels
self.hist_len = hist_len
self.input_depth = input_depth = hist_len * input_channels
if type(out_size) is tuple:
self.is_categorical = True
self.action_no, self.atoms_no = out_size
self.out_size = self.action_no * self.atoms_no
else:
self.is_categorical = False
self.out_size = out_size
78
self.hidden_size = hidden_size
def get_attributes(self):
return (self.input_channels, self.hist_len, self.action_no,self.hidden_size)
class CategoricalPolicyEvaluation(object):
def __init__(self, policy, cmdl):
"""Assumes policy returns an autograd.Variable"""
self.name = "CP"
self.cmdl = cmdl
self.policy = policy
79
Annexe B
return {
'Features': features,
80
'Labels': labels
}
def string_to_dict(s):
return ast.literal_eval(s)
def predicted(h):
t=[]
for i in range(len(h)):
if h[i]>= 0.5 :
t.append(1.)
else :
t.append(0.)
return torch.FloatTensor(t)
def get_accuracy(lab,pred):
correct = (pred== lab).float().sum().item()
accuracy = 100.*correct / len(lab)
return accuracy
def get_label_tensor(t):
l=[]
for i in range(len(t)):
l.append([t[i][-1]])
return torch.tensor(l)
B.1.2 Data
In [0]: ### Loading Data ; trees_bin and vocabulary
def load():
temp = open("trees_new_bin.txt",'r').readlines()
trees=[string_to_dict(l.strip('\n'+'\t')) for l in temp]
v=open("vocab_build.txt",'r').readlines()
vocab=[l.strip('\n'+'\t') for l in v]
return trees,vocab
trees,vocab=load()
def get_data():
t= open("data_lstm.txt",'r').readlines()
data=[l.strip('\n'+'\t') for l in t]
features=data[0]
labels=data[1]
return ast.literal_eval(features),ast.literal_eval(labels)
Features,Labels=get_data()
81
In [0]: ### Fonctions : padding features & labels
features[i,:] = np.array(new)
return features
labels[i,:] = np.array(new)
return labels
n=1000 ## restriction
features=pad_features(Features[:n], pad_dim)
labels=pad_labels(Labels[:n],pad_dim)
split_frac=0.8
train_x,train_y,valid_x,valid_y,test_x,test_y=split_data(split_frac)
82
In [0]: # create Tensor datasets
train_data = TensorDataset(torch.from_numpy(train_x), torch.from_numpy(train_y))
valid_data = TensorDataset(torch.from_numpy(valid_x), torch.from_numpy(valid_y))
test_data = TensorDataset(torch.from_numpy(test_x), torch.from_numpy(test_y))
# dataloaders
batch_size = 10
# make sure to SHUFFLE your data
train_loader = DataLoader(train_data, shuffle=True, batch_size=batch_size)
valid_loader = DataLoader(valid_data, shuffle=True, batch_size=batch_size)
test_loader = DataLoader(test_data, shuffle=True, batch_size=batch_size)
83
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]])
import torch.nn as nn
class SentimentLSTM(nn.Module):
"""
The RNN model that will be used to perform Sentiment analysis.
"""
self.output_size = output_size
self.n_layers = n_layers
self.hidden_dim = hidden_dim
# dropout layer
self.dropout = nn.Dropout(0.3)
84
# sigmoid function
sig_out = self.sig(out)
return hidden
model(vocab_size,output_size,embedding_dim,hidden_dim,n_layers)
SentimentLSTM(
(embedding): Embedding(20216, 400)
(lstm): LSTM(400, 256, num_layers=2, batch_first=True, dropout=0.5)
(dropout): Dropout(p=0.3)
(fc): Linear(in_features=256, out_features=1, bias=True)
(sig): Sigmoid()
(soft): Softmax()
)
criterion = nn.BCELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
val_acc=0
val_acc_list=[]
85
# training params
epochs =5 # 3-4 is approx where I noticed the validation loss stop decreasing
counter = 0
print_every = 100
clip=5 # gradient clipping
num_correct = 0
net.train()
# train for some number of epochs
for e in range(epochs):
# initialize hidden state
h = net.init_hidden(batch_size)
# batch loop
i=0
for inputs, labels in train_loader:
counter += 1
# loss stats
if counter % print_every == 0:
# Get validation loss
val_h = net.init_hidden(batch_size)
val_losses = []
net.eval()
i=0
for inputs, labels in valid_loader:
inputs = inputs.type(torch.LongTensor)
output, val_h = net(inputs, val_h)
val_loss = criterion(output.squeeze(),lab)
86
val_losses.append(val_loss.item())
#pred = torch.round(output.squeeze()) # rounds to the nearest integer
#correct_tensor = pred.eq(get_label_tensor(labels).float().squeeze().view_as(
out=output.squeeze()
#pred = torch.round(output)
pred=predicted(out)
#correct = np.squeeze(correct_tensor.cpu().numpy())
#num_correct += np.sum(correct)
print(lab,pred)
acc_val=get_accuracy(lab,pred)
print(acc_val)
val_acc+=acc_val
i+=1
net.train()
print("Epoch: {}/{}...".format(e+1, epochs),
"Step: {}...".format(counter),
"Loss: {:.6f}...".format(loss.item()),
net.eval()
# iterate over test data
i=0
for inputs, labels in test_loader:
87
# convert output probabilities to predicted class (0 or 1)
#pred = torch.round(output.squeeze()) # rounds to the nearest integer
#pred = torch.round(output)
pred=predicted(out)
acc=get_accuracy(lab,pred)
# compare predictions to true label
#correct_tensor = pred.eq(get_label_tensor(labels).float().squeeze().view_as(pred))
#correct = np.squeeze(correct_tensor.cpu().numpy())
#num_correct += np.sum(correct)
acc_mean+=acc
i+=1
# -- stats! -- ##
# avg test loss
print("Test loss: {:.3f}".format(np.mean(test_losses)))
#print(acc_mean/i,i,len(test_loader.dataset))
# accuracy over all test data
#test_acc =100.* num_correct/len(test_loader.dataset)
print("Test accuracy: {:.3f}".format(acc_mean/i))
In [0]:
import numpy as np
import numpy
import torch
from tqdm import tqdm
import random
import ast
import torch.optim as optim
from sklearn.metrics import confusion_matrix
from statistics import mean
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
88
def _gather_node_attributes(node, key):
features = node[key]
for child in node['children']:
features.extend(_gather_node_attributes(child, key))
return features
return {
'Features': features,
'Labels': labels
}
def string_to_dict(s):
return ast.literal_eval(s)
def load():
temp = open("trees_new_bin.txt",'r').readlines()
trees=[string_to_dict(l.strip('\n'+'\t')) for l in temp]
v=open("vocab_build.txt",'r').readlines()
vocab=[l.strip('\n'+'\t') for l in v]
return trees,vocab
trees,vocab=load()
In [0]: Features,Labels=get_data()
pad_dim=20
89
In [0]: def get_accuracy(lab,pred):
correct = (pred== lab).float().sum().item()
accuracy = 100.*correct / len(lab)
return accuracy
return accuracy
features[i,:] = np.array(new)
return features
In [0]: n=1000
features=pad_features(Features[:n], pad_dim)
In [0]: features.shape
90
if Labels_len <= seq_length:
zeroes = list(np.zeros(seq_length-Labels_len))
new = zeroes+label
elif Labels_len > seq_length:
new = label[0:seq_length]
labels[i,:] = np.array(new)
return labels
In [0]: labels=pad_labels(Labels[:n],pad_dim)
labels.shape
In [0]: labels.shape
return torch.tensor(l)
In [0]: get_label_tensor(labels).size()
91
dataiter = iter(train_loader)
sample_x, sample_y = dataiter.next()
print('Sample input size: ', sample_x.size()) # batch_size, seq_length
print('Sample input: \n', sample_x)
print()
print('Sample label size: ', sample_y.size()) # batch_size
print('Sample label: \n', sample_y)
import torch.nn as nn
class SentimentLSTM(nn.Module):
"""
The RNN model that will be used to perform Sentiment analysis.
"""
92
"""
Initialize the model by setting up the layers.
"""
super().__init__()
self.output_size = output_size
self.n_layers = n_layers
self.hidden_dim = hidden_dim
# dropout layer
self.dropout = nn.Dropout(0.3)
#sig_out = self.soft(out)
sig_out=out
# reshape to be batch_size first
sig_out = sig_out.view(batch_size, -1)
ln= nn.Linear(batch_size, 5)
#sig_out = sig_out[:, -1] # get last batch of labels
93
def init_hidden(self, batch_size):
''' Initializes hidden state '''
# Create two new tensors with sizes n_layers x batch_size x hidden_dim,
# initialized to zero, for hidden state and cell state of LSTM
weight = next(self.parameters()).data
return hidden
SentimentLSTM(
(embedding): Embedding(20216, 256)
(lstm): LSTM(256, 256, num_layers=4, batch_first=True, dropout=0.5)
(dropout): Dropout(p=0.3)
(fc): Linear(in_features=256, out_features=5, bias=True)
(sig): Sigmoid()
(soft): Softmax()
(relu): ReLU()
)
criterion = nn.CrossEntropyLoss()
#nn.BCELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
val_acc=0
val_acc_list=[]
loss_list=[]
# training params
epochs = 12 # 3-4 is approx where I noticed the validation loss stop decreasing
counter = 0
print_every = 100
clip=5 # gradient clipping
num_correct = 0
net.train()
# train for some number of epochs
94
for e in tqdm(range(epochs)):
# initialize hidden state
h = net.init_hidden(batch_size)
# batch loop
i=0
for inputs, labels in train_loader:
counter += 1
inputs = inputs.type(torch.LongTensor)
output, val_h = net(inputs, val_h)
val_loss = criterion(output,lab)
val_losses.append(val_loss.item())
#pred = torch.round(output.squeeze()) # rounds to the nearest integer
#correct_tensor = pred.eq(get_label_tensor(labels).float().squeeze().view_as(
#pred = torch.round(output)
pred=predicted_v2(output)
print(pred)
acc_val=get_accuracy(lab,pred)
val_acc+=acc_val
i+=1
net.train()
print(acc_val)
95
print("Epoch: {}/{}...".format(e+1, epochs),
"Step: {}...".format(counter),
"Loss: {:.6f}...".format(loss.item()),
net.eval()
# iterate over test data
i=0
for inputs, labels in test_loader:
96
# calculate loss
test_loss = criterion(out,lab)
test_losses.append(test_loss.item())
#pred = torch.round(output)
pred=predicted_v2(out)
acc=get_accuracy(lab,pred)
# compare predictions to true label
#correct_tensor = pred.eq(get_label_tensor(labels).float().squeeze().view_as(pred))
#correct = np.squeeze(correct_tensor.cpu().numpy())
#num_correct += np.sum(correct)
acc_mean+=acc
i+=1
# -- stats! -- ##
# avg test loss
print("Test loss: {:.3f}".format(np.mean(test_losses)))
#print(acc_mean/i,i,len(test_loader.dataset))
# accuracy over all test data
#test_acc =100.* num_correct/len(test_loader.dataset)
print("Test accuracy: {:.3f}".format(acc_mean/i))
In [0]: resultats=[]
criterion = nn.CrossEntropyLoss()
#nn.BCELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
val_acc=0
val_acc_list=[]
loss_list=[]
# training params
counter = 0
print_every = 100
clip=5 # gradient clipping
num_correct = 0
net.train()
# train for some number of epochs
for e in tqdm(range(epochs)):
# initialize hidden state
h = net.init_hidden(batch_size)
97
# batch loop
i=0
for inputs, labels in train_loader:
counter += 1
inputs = inputs.type(torch.LongTensor)
output, val_h = net(inputs, val_h)
val_loss = criterion(output,lab)
val_losses.append(val_loss.item())
#pred = torch.round(output.squeeze()) # rounds to the nearest integer
#correct_tensor = pred.eq(get_label_tensor(labels).float().squeeze().view
#pred = torch.round(output)
pred=predicted_v2(output)
acc_val=get_accuracy(lab,pred)
val_acc+=acc_val
i+=1
net.train()
98
"Val Loss: {:.6f}".format(np.mean(val_losses)))
print("Val_acc : ",val_acc/i)
val_acc_list.append(val_acc/i)
val_acc=0.
loss_list.append(loss)
net.eval()
# iterate over test data
i=0
for inputs, labels in test_loader:
#pred = torch.round(output)
pred=predicted_v2(out)
acc=get_accuracy(lab,pred)
# compare predictions to true label
#correct_tensor = pred.eq(get_label_tensor(labels).float().squeeze().view_as(pred))
#correct = np.squeeze(correct_tensor.cpu().numpy())
99
#num_correct += np.sum(correct)
acc_mean+=acc
i+=1
# -- stats! -- ##
# avg test loss
print("Test loss: {:.3f}".format(np.mean(test_losses)))
#print(acc_mean/i,i,len(test_loader.dataset))
# accuracy over all test data
#test_acc =100.* num_correct/len(test_loader.dataset)
print("Test accuracy: {:.3f}".format(acc_mean/i))
res={"embedding_dim":embedding_dim,"hidden_dim":hidden_dim,"n_layers":n_layers,"lr":lr,"e
resultats.append(res)
return res
In [0]: embedding_dim,hidden_dim,n_layers,lr,epochs=256,400,2,0.01,20
In [0]: evaluate(embedding_dim,hidden_dim,n_layers,lr,epochs)
100
50%| | 10/20 [07:41<07:52, 47.24s/it]
101
_______________ Test _______________
Test loss: 2.137
Test accuracy: 35.000
In [0]: get_resultat()
In [0]: resultats
102
{'Test accuracy': 36.0,
'Test loss': 1.36827712059021,
'Val_acc mean ': 40.875,
'embedding_dim': 20,
'epochs': 10,
'hidden_dim': 27,
'lr': 0.0001,
'n_layers': 1},
{'Test accuracy': 42.0,
'Test loss': 1.362808310985565,
'Val_acc mean ': 22.5,
'embedding_dim': 20,
'epochs': 10,
'hidden_dim': 20,
'lr': 0.0001,
'n_layers': 1},
{'Test accuracy': 36.0,
'Test loss': 1.3388031721115112,
'Val_acc mean ': 50.0,
'embedding_dim': 20,
'epochs': 10,
'hidden_dim': 20,
'lr': 0.0001,
'n_layers': 2},
{'Test accuracy': 40.0,
'Test loss': 1.768391615152359,
'Val_acc mean ': 49.25,
'embedding_dim': 256,
'epochs': 10,
'hidden_dim': 400,
'lr': 0.01,
'n_layers': 2},
{'Test accuracy': 35.0,
'Test loss': 2.136674439907074,
'Val_acc mean ': 42.25,
'embedding_dim': 256,
'epochs': 20,
'hidden_dim': 400,
'lr': 0.01,
'n_layers': 2}]
import numpy as np
import numpy
import torch
from tqdm import tqdm
import random
import ast
import torch.optim as optim
103
from sklearn.metrics import confusion_matrix
from statistics import mean
import seaborn as sns
import pandas as pd
parent_nodes = adjacency_list[:, 0]
child_nodes = adjacency_list[:, 1]
n = 0
while unevaluated_nodes.any():
# Find which child nodes have not been evaluated
unevaluated_mask = unevaluated_nodes[child_nodes]
node_order[nodes_to_evaluate] = n
unevaluated_nodes[nodes_to_evaluate] = False
n += 1
edge_order = node_order[parent_nodes]
104
def batch_tree_input(batch):
'''Combines a batch of tree dictionaries into a single batched dictionary for use by the T
batch - list of dicts with keys ('features', 'node_order', 'edge_order', 'adjacency_list')
returns a dict with keys ('features','Labels' , 'node_order', 'edge_order', 'adjacency_list',
'''
tree_sizes = [b['Features'].shape[0] for b in batch]
batched_adjacency_list = []
offset = 0
for n, b in zip(tree_sizes, batch):
batched_adjacency_list.append(b['adjacency_list'] + offset)
offset += n
batched_adjacency_list = torch.cat(batched_adjacency_list)
return {
'Features': batched_features,
'Labels' : batched_labels ,
'node_order': batched_node_order,
'edge_order': batched_edge_order,
'adjacency_list': batched_adjacency_list,
'tree_sizes': tree_sizes
}
105
def _gather_node_attributes(node, key):
features = [node[key]]
for child in node['children']:
features.extend(_gather_node_attributes(child, key))
return features
def _gather_adjacency_list(node):
adjacency_list = []
for child in node['children']:
adjacency_list.append([node['index'], child['index']])
adjacency_list.extend(_gather_adjacency_list(child))
return adjacency_list
return {
'Features': torch.tensor(features, device=device, dtype=torch.float32),
'Labels': torch.tensor(labels, device=device, dtype=torch.float32),
'node_order': torch.tensor(node_order, device=device, dtype=torch.int64),
'adjacency_list': torch.tensor(adjacency_list, device=device, dtype=torch.int64),
'edge_order': torch.tensor(edge_order, device=device, dtype=torch.int64),
}
###################""""
def string_to_dict(s):
return ast.literal_eval(s)
def id_tree(t,trees):
if t in trees :
return trees.index(t)
106
size_test=int(size*0.2)
size_dev=size-size_train-size_test
train_data=random.choices(trees,k=size_train)
test_data=random.choices(diff(trees,train_data),k=size_test)
dev_data=random.choices(diff(trees,train_data+test_data),k=size_dev)
return train_data,test_data,dev_data
def get_split_data(trees):
start = time.time()
train_data,test_data,dev_data=split(trees)
print("train_data processing ... ")
with open('train_data.txt', 'w') as f:
for i in tqdm(range(len(train_data))):
f.write("%s\n" % train_data[i])
print("train_data Done!")
print("test_data processing ... ")
with open('test_data.txt', 'w') as f:
for i in tqdm(range(len(test_data))):
f.write("%s\n" % test_data[i])
print("test_data Done!")
print("dev_data processing ... ")
with open('dev_data.txt', 'w') as f:
for i in tqdm(range(len(dev_data))):
f.write("%s\n" % dev_data[i])
print("dev_data Done! ")
end = time.time()
print("temps de SPLIT (s):", end - start)
trees,train_data,test_data,dev_data=data_loader()
class TreeLSTM(torch.nn.Module):
'''PyTorch TreeLSTM model that implements efficient batching.
'''
def __init__(self, in_features, out_features):
'''TreeLSTM class initializer
Takes in int sizes of in_features and out_features and sets up model Linear network l
'''
super().__init__()
107
self.in_features = in_features
self.out_features = out_features
# f terms are maintained seperate from the iou terms because they involve sums over c
# while the iou terms do not
self.W_f = torch.nn.Linear(self.in_features, self.out_features)
self.U_f = torch.nn.Linear(self.out_features, self.out_features, bias=False)
# embedding
# Retrive device the model is currently loaded on to generate h, c, and h_sum result
device = next(self.parameters()).device
return torch.sigmoid(h), c
108
# features is a tensor of size N x F
# adjacency_list is a tensor of size E x 2
# x is a tensor of size n x F
x = features[node_mask, :]
# At iteration 0 none of the nodes should have children
# Otherwise, select the child nodes needed for current iteration
# and sum over their hidden states
if iteration > 0:
# adjacency_list is a tensor of size e x 2
adjacency_list = adjacency_list[edge_mask, :]
c[node_mask, :] = i * u
# fc is a tensor of size e x M
fc = f * child_c
h[node_mask, :] = o * torch.tanh(c[node_mask])
109
In [0]: def emmb(f,emmb_dim):
fc=torch.nn.Linear(1,emmb_dim)
emmb_features=[]
for i in range(len(f)):
emmb_features.append(fc(f[i]).tolist())
return torch.tensor(emmb_features)
In [0]: ######################
## Training
######################
emmb_dim=200
net=TreeLSTM(emmb_dim,2) ##
#loss_function = torch.nn.BCELoss()
loss_function = torch.nn.CrossEntropyLoss()
lr=0.001
optimizer = optim.Adam(net.parameters(), lr=lr)
#optimizer = optim.SGD(net.parameters(), lr=lr)
batch_size=10
nbr_epoch=12
h, c = net(
emmb(data['Features'],emmb_dim),
data['node_order'],
data['adjacency_list'],
data['edge_order']
)
labels = data['Labels']
acc_class.append(get_accuracy_class(h,labels))
predicted_list.append(predicted(h))
loss = loss_function(h, labels.to(dtype=torch.long).squeeze_())
min_loss+=loss.item()/int((len(data_load)))
loss.backward()
optimizer.step()
loss_list.append(min_loss)
110
### h moyenne
In [0]: print(loss_list)
df = pd.DataFrame({'epoch':epoch_list,'loss':loss_list})
In [0]: len(loss_list)
Out[0]: 12
111
In [0]: # Get test data loss and accuracy
def frequency(l):
cl=[0.,1.,2.,3.,4.]
count=[0,0,0,0,0]
for i in range(len(l)) :
if l[i]==0. :
count[0]+=1
elif l[i]==1.:
count[1]+=1
elif l[i]==2.:
count[2]+=1
elif l[i]==3.:
count[3]+=1
elif l[i]==4.:
count[4]+=1
return np.argmax(np.array(count))
def get_trees_min(trees):
index_tree_class=[]
tree=batch_tree(trees,1)
for i in range(len(tree)):
label_i=tree[i]['Labels']
c_i=frequency(label_i)
if c_i!=2 :
index_tree_class.append([i,c_i])
return index_tree_class
112
def get_tree(trees):
trees_min=get_trees_min(trees)
trees_min_list=[]
for i,j in trees_min :
trees_min_list.append(trees[i])
return trees_min_list
def save_trees_min(N=220):
with open('trees_min.txt', 'w') as f:
for i in tqdm(range(1,N)):
f.write("%s\n" % get_tree(trees))
return torch.FloatTensor(t)
def get_accuracy(h,labels):
total = len(labels)
correct = (predicted(h) == labels).float().sum()
accuracy = 100.*correct / total
return accuracy.item()
def get_confusion_matrix(h,labels):
H=predicted(h)
H=H.tolist()
labels=labels.tolist()
c=confusion_matrix(labels, H,labels=[0,1,2,3,4])
return c
def get_accuracy_class(h,labels):
c=get_confusion_matrix(h,labels)
acc=[score_class(c,i) for i in range(0,5)]
return acc
def score_class(c,i):
if c[i,i]==0:
return 0
else :
acc=c[i,i]/c[:,i].sum()
return acc*100
def get_mean(ev):
mean=np.array([0.,0.,0.,0.,0.])
for i in range(len(ev)):
mean+=np.array(ev[i])
return mean/len(ev)
113
## evaluation d'un arbre
def eval(data):
data=convert_tree_to_tensors(data)
model_eval=model_train.eval()
h_ev, c_ev = model_eval(
data['Features'],
data['node_order'],
data['adjacency_list'],
data['edge_order']
)
labels = data['Labels']
loss_ev = loss_function(h_ev, labels.to(dtype=torch.long).squeeze_())
return {"org_labels":labels,"predicted_labels": predicted(h_ev) , "accuracy":get_accuracy(h
In [0]: distribution(predicted_list)
114
B.4 Implémentation : LSTM child sum multiclass
In [0]: #### import libraries
import numpy as np
import numpy
import torch
from tqdm import tqdm
import random
import ast
import torch.optim as optim
from sklearn.metrics import confusion_matrix
from statistics import mean
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
115
node_order = numpy.zeros(tree_size, dtype=int)
unevaluated_nodes = numpy.ones(tree_size, dtype=bool)
parent_nodes = adjacency_list[:, 0]
child_nodes = adjacency_list[:, 1]
n = 0
while unevaluated_nodes.any():
# Find which child nodes have not been evaluated
unevaluated_mask = unevaluated_nodes[child_nodes]
node_order[nodes_to_evaluate] = n
unevaluated_nodes[nodes_to_evaluate] = False
n += 1
edge_order = node_order[parent_nodes]
def batch_tree_input(batch):
'''Combines a batch of tree dictionaries into a single batched dictionary for use by the T
batch - list of dicts with keys ('features', 'node_order', 'edge_order', 'adjacency_list')
returns a dict with keys ('features','Labels' , 'node_order', 'edge_order', 'adjacency_list',
'''
tree_sizes = [b['Features'].shape[0] for b in batch]
batched_adjacency_list = []
offset = 0
for n, b in zip(tree_sizes, batch):
batched_adjacency_list.append(b['adjacency_list'] + offset)
offset += n
116
batched_adjacency_list = torch.cat(batched_adjacency_list)
return {
'Features': batched_features,
'Labels' : batched_labels ,
'node_order': batched_node_order,
'edge_order': batched_edge_order,
'adjacency_list': batched_adjacency_list,
'tree_sizes': tree_sizes
}
def _gather_adjacency_list(node):
adjacency_list = []
for child in node['children']:
adjacency_list.append([node['index'], child['index']])
adjacency_list.extend(_gather_adjacency_list(child))
return adjacency_list
117
def convert_tree_to_tensors(tree, device=torch.device('cpu')):
# Label each node with its walk order to match nodes to feature tensor indexes
# This modifies the original tree as a side effect
_label_node_index(tree)
return {
'Features': torch.tensor(features, device=device, dtype=torch.float32),
'Labels': torch.tensor(labels, device=device, dtype=torch.float32),
'node_order': torch.tensor(node_order, device=device, dtype=torch.int64),
'adjacency_list': torch.tensor(adjacency_list, device=device, dtype=torch.int64),
'edge_order': torch.tensor(edge_order, device=device, dtype=torch.int64),
}
###################""""
def string_to_dict(s):
return ast.literal_eval(s)
def id_tree(t,trees):
if t in trees :
return trees.index(t)
train_data=random.choices(trees,k=size_train)
test_data=random.choices(diff(trees,train_data),k=size_test)
dev_data=random.choices(diff(trees,train_data+test_data),k=size_dev)
return train_data,test_data,dev_data
def get_split_data(trees):
start = time.time()
train_data,test_data,dev_data=split(trees)
print("train_data processing ... ")
with open('train_data.txt', 'w') as f:
for i in tqdm(range(len(train_data))):
f.write("%s\n" % train_data[i])
print("train_data Done!")
print("test_data processing ... ")
118
with open('test_data.txt', 'w') as f:
for i in tqdm(range(len(test_data))):
f.write("%s\n" % test_data[i])
print("test_data Done!")
print("dev_data processing ... ")
with open('dev_data.txt', 'w') as f:
for i in tqdm(range(len(dev_data))):
f.write("%s\n" % dev_data[i])
print("dev_data Done! ")
end = time.time()
print("temps de SPLIT (s):", end - start)
trees,train_data,test_data,dev_data=data_loader()"""
def data_loader():
train = open("data_lstm_coc.txt",'r').readlines()
train_data=[string_to_dict(l.strip('\n'+'\t')) for l in train][:10]
temp = open("vocab.txt", 'r').readlines()
vocab = [l.strip('\n' + '\t') for l in temp]
return train_data,vocab
data,vocab=data_loader()
In [0]:
class TreeLSTM(torch.nn.Module):
'''PyTorch TreeLSTM model that implements efficient batching.
'''
def __init__(self, in_features, out_features):
'''TreeLSTM class initializer
Takes in int sizes of in_features and out_features and sets up model Linear network l
'''
super().__init__()
self.in_features = in_features
self.out_features = out_features
119
# f terms are maintained seperate from the iou terms because they involve sums over c
# while the iou terms do not
self.W_f = torch.nn.Linear(self.in_features, self.out_features)
self.U_f = torch.nn.Linear(self.out_features, self.out_features, bias=False)
# embedding
# Retrive device the model is currently loaded on to generate h, c, and h_sum result
device = next(self.parameters()).device
return torch.sigmoid(h), c
120
edge_mask = edge_order == iteration
# x is a tensor of size n x F
x = features[node_mask, :]
# At iteration 0 none of the nodes should have children
# Otherwise, select the child nodes needed for current iteration
# and sum over their hidden states
if iteration > 0:
# adjacency_list is a tensor of size e x 2
adjacency_list = adjacency_list[edge_mask, :]
c[node_mask, :] = i * u
# fc is a tensor of size e x M
fc = f * child_c
h[node_mask, :] = o * torch.tanh(c[node_mask])
121
emmb_features.append(fc(f[i]).tolist())
return torch.tensor(emmb_features)
return torch.FloatTensor(t)
def get_accuracy(h,labels):
total = len(labels)
correct = (predicted(h) == labels).float().sum()
accuracy = 100.*correct / total
return accuracy.item()
def get_confusion_matrix(h,labels):
H=predicted(h)
H=H.tolist()
labels=labels.tolist()
c=confusion_matrix(labels, H,labels=[0,1,2,3,4])
return c
def get_accuracy_class(h,labels):
c=get_confusion_matrix(h,labels)
acc=[score_class(c,i) for i in range(0,5)]
return acc
def score_class(c,i):
if c[i,i]==0:
return 0
else :
acc=c[i,i]/c[:,i].sum()
return acc*100
def get_mean(ev):
mean=np.array([0.,0.,0.,0.,0.])
for i in range(len(ev)):
mean+=np.array(ev[i])
return mean/len(ev)
122
)
labels = data['Labels']
loss_ev = loss_function(h_ev, labels.to(dtype=torch.long).squeeze_())
return {"org_labels":labels,"predicted_labels": predicted(h_ev) , "accuracy":get_accuracy(h
In [0]:
In [0]: ######################
## Training
######################
emmb_dim=1
nbr_classes=len(vocab)
# 7: 21% ,
net=TreeLSTM(emmb_dim,nbr_classes) ##
#loss_function = torch.nn.BCELoss()
loss_function = torch.nn.CrossEntropyLoss()
lr=0.001
optimizer = optim.Adam(net.parameters(), lr=lr)
#optimizer = optim.SGD(net.parameters(), lr=lr)
batch_size=4
nbr_epoch=12
123
predicted_list=[]
net.train()
data_load=batch_tree(data,batch_size)
h, c = net(
#emmb(data['Features'],emmb_dim),
data['Features'],
data['node_order'],
data['adjacency_list'],
data['edge_order']
)
labels = data['Labels']
acc_class.append(get_accuracy_class(h,labels))
predicted_list.append(predicted(h))
loss = loss_function(h, labels.to(dtype=torch.long).squeeze_())
min_loss+=loss.item()/int((len(data_load)))
loss.backward()
optimizer.step()
loss_list.append(min_loss)
### h moyenne
In [0]: resultats=[]
# 7: 21% ,
net=TreeLSTM(emmb_dim,5) ##
#loss_function = torch.nn.BCELoss()
loss_function = torch.nn.CrossEntropyLoss()
124
for epoch in tqdm(range(1,nbr_epoch+1)):
min_loss=0
h, c = net(
emmb(data['Features'],emmb_dim),
data['node_order'],
data['adjacency_list'],
data['edge_order']
)
labels = data['Labels']
acc_class.append(get_accuracy_class(h,labels))
predicted_list.append(predicted(h))
loss = loss_function(h, labels.to(dtype=torch.long).squeeze_())
min_loss+=loss.item()/int((len(data_load)))
loss.backward()
optimizer.step()
loss_list.append(min_loss)
df = pd.DataFrame({'epoch':epoch_list,'loss':loss_list})
125
res={"embedding_dim":emmb_dim,"lr":lr,"batch_size":batch_size,"epochs":nbr_epoch,"Test lo
resultats.append(res)
return resultats
In [0]: emmb_dim,batch_size,nbr_epoch,lr=7,2,10,0.001
In [0]: evaluate(emmb_dim,batch_size,nbr_epoch,lr)
In [0]: resultats
def frequency(l):
cl=[0.,1.,2.,3.,4.]
count=[0,0,0,0,0]
for i in range(len(l)) :
if l[i]==0. :
count[0]+=1
elif l[i]==1.:
count[1]+=1
elif l[i]==2.:
count[2]+=1
elif l[i]==3.:
count[3]+=1
elif l[i]==4.:
count[4]+=1
return np.argmax(np.array(count))
def get_trees_min(trees):
index_tree_class=[]
tree=batch_tree(trees,1)
for i in range(len(tree)):
126
label_i=tree[i]['Labels']
c_i=frequency(label_i)
if c_i!=2 :
index_tree_class.append([i,c_i])
return index_tree_class
def get_tree(trees):
trees_min=get_trees_min(trees)
trees_min_list=[]
for i,j in trees_min :
trees_min_list.append(trees[i])
return trees_min_list
def save_trees_min(N=220):
with open('trees_min.txt', 'w') as f:
for i in tqdm(range(1,N)):
f.write("%s\n" % get_tree(trees))
In [0]: l=batch_tree_input(batch(trees))['Labels']
l
In [0]: distribution(predicted_list)
127
questions,answers,vocab=get_data()
def to_nltk_tree(node):
if node.n_lefts + node.n_rights > 0:
return Tree(node.orth_, [to_nltk_tree(child) for child in node.children])
else:
return node.orth_
def get_tree(doc):
l=[]
for sent in doc.sents :
l.append(to_nltk_tree(sent.root))
return l
def nlp_sent(i,text):
return nlp(text[i])
def extract_tree(l):
L=[]
for t in l :
if isinstance(t, Tree):
L.append(t)
return L
def get_tree_i(i,text):
return extract_tree(get_tree(nlp_sent(i,text)))
In [0]: get_tree_i(len(questions)-1,questions)
print_tree_i(10,questions)
is
___|________
| | on
| | |
| | table
| | ____|_____
it ? the close
<IPython.core.display.HTML object>
128
In [0]: ## trees representation
def tree_to_dict(tree,answers,vocab,emmb_dim):
return {'Features': emmbeding(tree.label(),vocab,emmb_dim),'Labels':[get_label_vocab(tree.l
def tree_repr(i,questions,answers,vocab,emmb_dim):
for tree in get_tree_i(i,questions) :
d = tree_to_dict(tree,answers,vocab,emmb_dim)
return d
In [0]: len(questions)
Out[0]: 579633
In [0]: tree_repr(len(questions)-1,questions,answers,vocab,1)
In [0]:
In [0]: tree_repr(1,questions,answers,vocab,1)
129
'children': [{'Features': [2.4134552478790283],
'Labels': [6],
'children': [{'Features': [-0.6968395113945007],
'Labels': [5],
'children': []}]},
{'Features': [1.0749070644378662],
'Labels': [1197],
'children': [{'Features': [0.686913251876831],
'Labels': [3],
'children': []}]},
{'Features': [0.4419419467449188], 'Labels': [2768], 'children': []}]}
train = open("data_lstm_multi.txt",'r').readlines()
train_data=[string_to_dict(l.strip('\n'+'\t')) for l in train]
return train_data
data=data_loader()
In [0]: data[0]
130
'Labels': [3],
'children': []}]},
{'Features': [0.3830993175506592,
-0.833378255367279,
0.19006630778312683,
1.355594515800476,
-0.6927298307418823,
1.9384177923202515,
-1.1607344150543213],
'Labels': [2768],
'children': []}]}
In [0]:
131