FR / EN

Projet de Robot Bipède 3D

Introduction

Dans le cadre de ma formation en intelligence artificielle (IA), j'ai choisi de réaliser un projet visant à développer un robot bipède en 3D capable de marcher, se relever après une chute et monter ou descendre des escaliers. Pour ce faire, j'ai utilisé le moteur de jeu Unity et la plateforme ML-Agents d'OpenAI. Ce projet a présenté plusieurs défis, notamment en termes d'apprentissage et d'optimisation des mouvements du robot. Le présent document détaille les différentes étapes du projet, les problèmes rencontrés et les solutions mises en œuvre.

Pour ce projet, je suis parti de zéro en ce qui concerne les connaissances sur Unity et Blender. Je n'avais jamais modélisé de modèles 3D autres que des pièces mécaniques sur Inventor, donc l'apprentissage a pris un certain temps. Ensuite, l'assemblage des pièces créées et la configuration des articulations ont également pris du temps.

Premiers projets

Afin de me familiariser avec Unity et ML-Agents, j'ai commencé par un projet plus modeste dont le tutoriel peuvent être trouvés sur Internet.

Puis je l'ai complexifié pour avoir une meilleure idée des capacité de ML-Agents

Premier projet réalisé dont le tutoriel se trouve sur internet

L'agent possède la position de sa target et se déplace en X Z pour l'atteindre

Second projet hérité du premier ou l'agent se déplace d'avant en arrière et se retourne

Il utilise cette fois des sensors afin de se déplacer

Troisième projet qui reprend le second mais en demandant à l'agent de récupérer 3 target dans un ordre spécifique.

Dans l'ordre: Rouge, Jaune puis Vert

Conception et Développement du Robot

Moteur Graphique et Outils Utilisés

À ma connaissance, il existe peu d'environnements permettant de faire du reinforcement learning comme le fait Unity avec ML-Agents, qui offre une interface permettant une communication entre TensorFlow et le moteur graphique. Cette communication est loin d'être parfaite et j'ai dû modifier la bibliothèque de ML-Agents afin d'améliorer la communication et permettre de faire du curriculum learning.

Pour la création des modèles 3D, j'ai utilisé Blender. Blender est un logiciel complet de modélisation gratuit et open source. Assez compliqué à prendre en main, il dispose cependant de très nombreuses ressources en ligne et d'une grande communauté.

Unity Blender

Modélisation de l’Agent

Le robot a été modélisé en 3D dans Unity, avec une structure articulée comprenant 39 axes de rotation répartis en 17 articulations. Chaque articulation est dotée de contraintes et de forces pour simuler des mouvements réalistes.

L’agent possède 365 capteurs lui permettant de comprendre son environnement ainsi que sa propre position, en plus de 20 capteurs de rayons placés sur ses tibias et sa tête pour détecter les obstacles et le sol.

Une capsule a été placée au niveau de sa tête. Cette dernière permet d'afficher, à travers la couleur et l'intensité de sa couleur, les performances du robot. Elle est blanche par défaut si l'agent ne reçoit aucune récompense. Si elle est verte, cela signifie qu'il performe bien. Si elle est rouge, cela signifie qu'il reçoit beaucoup de pénalités.

Évolution du design du robot au fil du temps.

On peut voir sur cet extrait les capteurs (rayons) utilisés par le robot pour comprendre son environnement.

1. Articulation de la tête (X Y Z)
2. Articulation des fesses (X Y Z)
3. Articulation de la cuisse (X)
4. Articulation du genou (X)

5. Articulation de la cheville (X Y Z)
6. Articulation de l'épaule (X Y Z)
7. Articulation des vertebres et torse (X Y Z)
8. Articulation du coude (X)

9. Capteurs de la tête
10. Capteurs au niveau des tibias
11. Articulation de la cheville (X Y Z)

12. Centre de gravité
13. Centre de gravité projeté au sol
14. Cercle entre les pieds

Modélisation de l'environnement

L'environnement joue un rôle important dans l'apprentissage de l'agent. Il doit être varié et permettre plusieurs types d'apprentissage sans nécessiter de modifications pour chaque session. L'environnement que j'ai créé (après de nombreuses itérations) contient les éléments suivants :

  • Une grande salle dont la moitié a un sol plat permettant d'apprendre à réaliser les premiers pas, et l'autre moitié a un sol irrégulier composé de pentes, de dévers et de trois obstacles.
  • Une partie extérieure offrant des pentes et des dévers plus importants.
  • Un escalier reliant les deux zones.

L'environnement dispose également de deux types d'écrans pour surveiller l'agent. Voici les informations affichées dans l'ordre sur l'écran au fond à gauche:

  • RUN #X : Le numéro de la simulation (imprécis avec les instances de Unity).
  • STAND UP : La position de l'agent (Stand Up, On Face, On Back).
  • HEAD : La hauteur de sa tête en valeur normalisée.
  • COG : La distance entre la position moyenne de ses pieds et son centre de gravité placé à Y=0.
  • ANGLE : Son inclinaison si l'agent n'est pas debout.
  • SPEED : Sa vitesse par rapport à la vitesse demandée.
  • FOOT : Une valeur indiquant si un pied est dominant par rapport à l'autre.
  • REWARD : La moyenne des récompenses perçues sur les derniers pas (steps).

Ces indications ont été très utiles pour déterminer si l'agent cherche à effectuer une tâche inattendue ou s'il a trouvé une faille.

Le second type d'écran est utilisé pour surveiller la fatigue musculaire de chaque articulation. Bien que moins utile, il permet de constater rapidement si un muscle est mal paramétré ou connecté. Cela peut vite arriver avec le nombre de modifications réalisées durant le projet et peut entraîner une perte de plusieurs dizaines d'heures.

Type d'Algorithme et Hyperparamètres

Dans cette section, les range de valeurs utilisé seront indiqué en bleu.

Type d'Algorithme

PPO

Il existe plusieurs types d'algorithmes d'entraînement :

  • PPO : Utilise l'apprentissage sur la politique, ce qui signifie qu'il apprend sa fonction de valeur à partir des observations faites par la politique actuelle explorant l'environnement.
  • SAC : Utilise l'apprentissage hors politique, ce qui signifie qu'il peut utiliser les observations faites lors de l'exploration de l'environnement par des politiques antérieures. SAC utilise cependant beaucoup plus de ressources.

J'ai commencé par utiliser les algorithmes PPO car ce sont ceux par défaut et le SAC avait des problèmes de librairies. Cependant, après quelques modifications, j'ai réussi à utiliser les algorithmes SAC.

L'apprentissage avec SAC est très rapide et fonctionne très bien pour des actions simples. Cependant, il n'est pas possible de suivre visuellement l'évolution de l'agent étant donné les ressources demandées. J'ai également constaté de moins bonnes performances sur les apprentissages complexes et une plus grande tendance à exploiter la moindre mécanique défaillante.

Je suis donc repassé sur les algorithmes PPO car ils sont plus stables dans l'apprentissage et j'utilise le SAC uniquement pour tester une reward ou une action simple afin de gagner du temps.

Les Hyperparamètres

Dans le domaine de l'apprentissage par reinforcement, les hyperparamètres sont des réglages externes à un modèle de machine learning, qui influencent le processus d'apprentissage. Contrairement aux paramètres internes d'un modèle, qui sont appris pendant l'entraînement, les hyperparamètres doivent être définis avant le début de l'entraînement.

Lorsque vous utilisez Unity ML-Agents pour entraîner des agents intelligents, il est essentiel de bien comprendre et régler les hyperparamètres pour obtenir de bons résultats. Voici quelques-uns des hyperparamètres les plus importants dans Unity ML-Agents avec les valeurs que j'ai utilisées pour mon modèle :

1. Learning Rate (Taux d'apprentissage)

1×10−4 - 3×10−4

Le learning rate détermine la vitesse à laquelle le modèle met à jour ses paramètres internes en fonction des erreurs observées pendant l'entraînement. Un taux d'apprentissage trop élevé peut rendre l'apprentissage instable, tandis qu'un taux trop bas peut le rendre trop lent. Au début de l'apprentissage, l'agent commence avec un learning rate de 0.0003 et termine avec 0.0001. Cette valeur a une décroissance linéaire pour chaque apprentissage.

2. Batch Size (Taille du lot)

4096

La batch size correspond au nombre d'exemples de données que le modèle traite avant de mettre à jour ses paramètres internes. Des lots plus grands peuvent rendre l'apprentissage plus stable, mais nécessitent plus de mémoire. La valeur de 4096 m'a semblé être le meilleur compromis entre les ressources nécessaires et la stabilité de l'apprentissage.

3. Buffer Size (Taille du buffer)

40960

Le buffer size détermine combien de pas de temps sont stockés avant que le modèle ne mette à jour ses paramètres. Une taille de buffer plus grande peut aider à stabiliser l'apprentissage, mais augmente également les besoins en mémoire. Une valeur de 40960 a été utilisée, ce qui est le double de la valeur par défaut, réduisant le nombre d'agents entraînés simultanément.

4. Gamma

0.995 - 0.998

Gamma est le facteur de discount, qui détermine l'importance des récompenses futures par rapport aux récompenses immédiates. Un gamma élevé signifie que l'agent accorde plus d'importance aux récompenses futures. Une valeur oscillante entre 0.995 et 0.998 a été utilisée.

5. Lambda

0.95

Lambda est utilisé dans le calcul de l'avantage généralisé (GAE) pour contrôler le biais-variance dans les estimations de l'avantage. Un lambda plus élevé peut réduire le biais mais augmenter la variance. Dans notre cas, cette valeur est de 0.95, ce qui est le paramètre par défaut.

6. Beta

0.001 - 0.005

Dans les algorithmes de politique, Beta est utilisé pour l'exploration. Un Beta élevé favorise l'exploration de nouvelles actions, tandis qu'un Beta bas favorise l'exploitation des actions connues. Une valeur Beta élevée (0.005) permet à l'agent d'apprendre rapidement à marcher. Cependant, garder une valeur aussi élevée une fois les premiers pas réalisés est contre-productif. Afin de pouvoir marcher, l'agent doit réaliser un enchaînement de mouvements complexes. Si un seul de ces mouvements est mal exécuté, l'agent perd l'équilibre et chute. Si pour chacun des 39 muscles l'agent a un pourcentage trop élevé de réaliser une action aléatoire (découverte), il a peu de chances de parvenir à réaliser un mouvement dépassant son précédent record. Donc cette valeur est mise à 0.005 jusqu'à ce que l'agent réalise ses trois premiers pas, puis est mise à 0.001. Cette valeur a une décroissance linéaire pour chaque apprentissage.

7. Epsilon

0.1 - 0.6

Epsilon correspond au seuil acceptable de divergence entre l'ancienne et la nouvelle politique lors de la mise à jour de la descente de gradient. Définir cette valeur sur une valeur faible entraînera des mises à jour plus stables, mais ralentira également le processus de formation. J'ai trouvé qu'une très forte valeur (0.6) est nécessaire pour les premiers pas et permet de grandement accélérer l'apprentissage, mais que cette valeur doit être abaissée à 0.1 dès que les premiers pas ont été réalisés. Le problème avec le premier pas est que l'agent a peu de chances de le réaliser au hasard et ne fait que peu de points avant cela. Comme pour l'hyperparamètre Beta, l'agent a peu de chances de parvenir à faire son premier et second pas uniquement au hasard. Il est donc préférable qu'il puisse rapidement mettre à jour son modèle une fois le premier et le second pas réalisés.

8. Num Layers (Nombre de couches)

4

Le nombre de couches dans le réseau neuronal détermine la profondeur du modèle. Des réseaux plus profonds peuvent capturer des relations plus complexes, mais sont également plus susceptibles de surajuster les données d'entraînement et de partir en overfitting. Pour mon robot, j'ai commencé l'apprentissage avec 3 couches de 256 neurones. Mais ce qui semble le mieux fonctionner est 4 couches de 256 neurones avec une couche possédant un dropout de 0.5. Le dropout consiste à désactiver aléatoirement une fraction des neurones pendant l'entraînement et permet de rendre le modèle plus robuste en le forçant à ne pas se reposer uniquement sur un chemin neuronal. L'ajout du dropout a été fait à la base pour éviter l'overfitting (surapprentissage), mais j'ai constaté que l'agent apprenait bien plus rapidement avec et gardait une meilleure stabilité.

Visualisation d'un model neuronale composé de 2 couches denses de respectivement 2 et 3 neurones

9. Hidden Units (Unités cachées)

256

C'est le nombre de neurones par couche (Num layers). Le nombre d'unités cachées par couche dans le réseau neuronal affecte la capacité du modèle à apprendre des représentations complexes des données d'entrée. Plus d'unités cachées augmentent la capacité de modélisation mais nécessitent plus de données et de calculs. Les modèles testés avec plus de 256 neurones (512 et 1024) ont donné de bons résultats au début, mais partent trop vite en overfitting et prennent trop de temps d'apprentissage. Avec 128 neurones, l'agent apprend très vite, mais il se retrouve limité dans le nombre d'actions qu'il peut apprendre.

10. num_epoch

3 - 6

num_epoch est le nombre de passages à travers le buffer d'expérience pendant la descente de gradient. Diminuer cette valeur garantira des mises à jour plus stables, au prix d’un apprentissage plus lent. J'utilise une valeur de 3 pour un entraînement normal et 6 quand je dois faire des tests et que seul le temps d'apprentissage compte.

Visualisation de la descente de gradient, un algorithme d'optimisation couramment utilisé en apprentissage automatique et en apprentissage par renforcement.

11. Fonction d'activation

ReLu

Normalement, Unity ne propose pas de modifier la fonction d'activation et utilise la fonction ReLu (f(x)=max(0,x)).

ReLU (Rectified Linear Unit) f(x) = max(0, x)

ReLU est une fonction simple et efficace, définie comme le maximum entre 0 et l'entrée x. Elle aide à atténuer les problèmes de gradient explosif ou disparaissant et introduit de la sparsity dans le réseau, ce qui peut améliorer l'efficacité du modèle.

Swish f(x) = x · sigmoid(x)

Swish est définie comme le produit de l'entrée x et de la fonction sigmoïde de x. Swish est une fonction lisse, offrant des gradients plus stables et pouvant améliorer les performances et la vitesse de convergence dans certains contextes d'apprentissage.

Avantages de Swish

  • Lissage : Fournit des gradients plus stables.
  • Performance : Peut offrir de meilleures performances que ReLU dans certaines applications.
  • Flexibilité : Meilleure flexibilité dans l'apprentissage de relations complexes dans les données.

Par manque de temps, je n'ai pas implémenté la fonction Swish (f(x)=x⋅sigmoid(x)) dans la version finale. Mais j'ai cependant testé cette fonction qui semble donner de bons résultats et vais sans doute poursuivre dans cette direction

Rewards

Le système de récompense en apprentissage par renforcement (reinforcement learning) consiste à attribuer des points (récompenses) à un agent en fonction de ses actions. Ces récompenses peuvent être positives ou négatives. Les récompenses positives encouragent les actions qui mènent à des résultats désirés, tandis que les récompenses négatives (pénalités) découragent les actions indésirables. L'objectif est d'inciter l'agent à maximiser ses gains cumulés sur le long terme, en apprenant à choisir les actions les plus bénéfiques et à éviter celles qui sont néfastes.

Vitesse * Direction

La principale récompense utilisée dans ce projet consiste à récompenser l'agent lorsqu'il se déplace à une vitesse spécifique dans une direction spécifique. Pour ce faire, on prend la vélocité et le vecteur moyen de son corps, que l’on multiplie par sa direction par rapport à la cible. Ces deux valeurs étant normalisées, l’agent réalise 1 point s’il bouge à la bonne vitesse et dans la bonne direction. Cette valeur est clampée de manière à ne jamais devenir négative.

Accélération de la Vitesse d’Apprentissage de la Marche

Pour accélérer la vitesse d’apprentissage de la marche, j’ai ajouté un coefficient dans la formule de reward de vitesse x direction. Ce coefficient est le suivant :

  • Si les deux pieds touchent le sol en simultané : 0.1
  • Si aucun des pieds ne touche le sol : -1
  • Si un seul des pieds touche le sol : 1
  • Si le pied qui ne touche pas le sol est différent du dernier pied en avant : 5

Cette récompense permet de réduire drastiquement le temps d’apprentissage, le faisant passer de 24 heures à 2 heures en moyenne.

Se Relever

Je n’ai malheureusement pas trouvé de reward magique qui incite l’agent à se relever d’une manière propre. La reward que j’ai utilisée consiste en un coefficient de la hauteur de la tête de l’agent allant de 0 à 1. L’autre reward est une valeur que l’agent reçoit une fois debout, qui arrête la simulation et qui subit un decay rate afin de l’inciter à se relever le plus rapidement possible.

Fatigue musculaire

Sur les premières versions du robot, ses mouvements étaient très saccadés. J'ai donc cherché un moyen de limiter ces mouvements intempestifs.
Afin de régler ce problème, un système de fatigue musculaire a été ajouté. Au début de la simulation, chaque articulation commence avec une valeur de 0 et possède un coefficient de récupération. Si l'agent n'utilise pas cette articulation, sa valeur peut monter jusqu'à 100. À l'inverse, s'il l'utilise intensivement, elle descendra jusqu'à atteindre -100.
L'agent reçoit en récompense 1/100 de la fatigue moyenne de ses articulations.
On peut voir la fatigue musculaire de chaque articulation sur les deux écrans présents au fond à droite et au milieu de la salle.
L'objectif est d'inciter l'agent à n'utiliser que les muscles nécessaires à l'accomplissement d'une tâche rapportant plus de points que ne coûte sa fatigue musculaire, et ainsi supprimer les mouvements indésirables.

Difficultés Rencontrées

Mais comment le faire bouger ?

La toute première difficulté rencontrée a été de déterminer comment faire bouger mon agent. Devait-il déplacer ses membres directement ? Utiliser des tendons ? Des points de rotation ? N'ayant jamais touché à un moteur de jeu, j'ai dû explorer les différentes solutions qui s'offraient à moi. La première solution que j'ai testée est la seule que j'avais utilisée avec mon précédent projet : un simple déplacement du membre sur les axes X, Y et Z. Donc, donner à l'agent le choix de la direction et de la force à appliquer. J'ai très vite compris que ce n'était pas la bonne solution quand j'ai vu mes agents s'envoler au bout de 10 minutes d'entraînement. J'ai ensuite testé les simples joints. Très simples à configurer, ils n'offrent cependant pas la même liberté de mouvement qu'une épaule et sont donc inutilisables pour un humanoïde. Puis, je suis passé aux Character Joints pensant qu'avec ce nom, ils étaient faits pour le job. Ils sont plus compliqués à configurer que de simples joints, mais n'offrent toujours pas la liberté que je recherche. J'ai fini par utiliser des Configurable Joints. Bien qu'imparfaits et plus complexes, ces derniers offrent une bonne liberté dans la programmation des limites min et max, d'élasticité, des tampons et de force.

Je dois vraiment tout recommencer ?

Une des plus grosses difficultés que j'ai rencontrées est le fait que si j'entraîne un modèle à marcher, changer la moindre valeur en entrée, une limite dans ses articulations ou légèrement incliner un de ses capteurs me force à tout recommencer. Souhaiter rendre le robot capable de se relever en plus de marcher nécessite plus de liberté dans ses articulations et des valeurs d'entrée supplémentaires. À plusieurs reprises, j'ai appris à mon robot à marcher, puis arrivé à l'étape de se relever, je constatais qu'une valeur d'articulation gagnerait à être plus stricte ou lâche et tout le processus devait recommencer.

Lève-toi et ne marche surtout pas !

La troisième difficulté est très proche de la seconde. Il s'agit de trouver un compromis entre la liberté de mouvement, qui entraîne un temps d'apprentissage de la marche bien plus long, et l'ajout de contraintes strictes, qui empêchent le robot de se relever mais simplifient grandement l'apprentissage de la marche.
De plus, donner plus de liberté de mouvement à travers des joints ou des axes supplémentaires provoque également un effet de "ressort" sur les membres.
Par exemple, pour les jambes, j'ai été contraint d'ajouter une articulation au niveau des cuisses. Mais si je donne 3 axes de rotation à cette articulation, l'effet ressort empêche l'agent de faire ses premiers pas.
La seule solution que j'ai trouvée est de limiter le plus possible le nombre d'axes par articulation.
Donc :

  • 1. Fesses : 3 axes de rotation (X, Y, Z)
  • 2. Cuisses : 1 axe (X)
  • 3. Genoux : 1 axe (X)
  • 4. Pieds : 3 axes (X, Y, Z)

Quaternion et gimbal lock

Pour les articulations, j'ai choisi de faire des mouvements relatifs avec des limites inscrites dans le code afin de les rendre dynamiques. Le problème est que les articulations peuvent se retrouver bloquées par ce qu'on appelle le gimbal lock. Afin de résoudre ce problème, j'ai dû utiliser des quaternions à la place des angles d'Euler pour la rotation des articulations. Le principe des quaternions est qu'on définit la rotation d'un objet avec 4 valeurs (X, Y, Z, W). Le problème apparaît au moment où on commence à limiter la valeur qu'un angle peut avoir. Imaginons que je limite mes axes Y et Z à 30° et que je veuille donner un angle de 110° à mon axe X. Afin que l'axe X dépasse 90°, les axes Y et Z doivent passer de 0 à 180°, ce qui ne rentre pas dans les limites que j'ai fixées et pose donc un problème. Il y a également le fait que dès qu'un axe n'est pas parfaitement à 0°, la rotation d'un autre axe changera sa valeur. La solution que j'ai trouvée est de :

  • 1. Prendre la rotation actuelle de l'articulation en angle d'Euler.
  • 2. Limiter l'addition à 10% de la tolérance max/min.
  • 3. Clamper l'addition de la rotation actuelle et additionnelle par rapport aux limites min/max une fois le tout normalisé avec la fonction suivante :

while (angle > 180f) angle -= 360f;

while (angle < -180f) angle +=360f;

Suicide de l'IA

C'est un problème que je n'ai malheureusement pas enregistré, mais que j'ai à plusieurs reprises expérimenté. Si l'agent est trop lourdement pénalisé et qu'il trouve une issue de sortie, il la prendra. Cela peut être dû au fait qu'il n'a juste pas encore découvert la bonne solution ou que le système de récompense n'est pas bien équilibré. La solution est relativement simple : éviter les pénalités trop fortes tant que l'agent n'a pas trouvé toute ou une partie de la solution. Je pense que les pénalités lourdes sont surtout bonnes pour l'optimisation du modèle et non pour son apprentissage depuis un état vierge.

Un gâteau empoisonné

Un des soucis que j'ai souvent rencontrés est une mauvaise récompense. Mal dosée ou à côté de la plaque, elle peut totalement empêcher un apprentissage. Je prendrai pour exemple une de mes premières récompenses pour inciter mon agent à se déplacer vers sa cible. Au début de la session d'entraînement, j'enregistrais la distance entre mon agent et sa cible afin de savoir la part de distance qu'il a parcourue et je normalise cette valeur de 0 quand mon agent est à son point de départ et 1 quand il est sur la cible. À chaque étape de l'entraînement, l'agent reçoit en récompense la proportion de distance parcourue. Cette récompense fonctionne plutôt bien au début. Mais très vite, l'agent comprend que s'il attend bêtement à côté de sa cible, il fera beaucoup plus de points que s'il la touche et met fin à la simulation. La solution dans ce cas aurait été simple : donner une récompense quand l'agent touche la cible plus importante que celle qu'il aurait en restant à côté. Par exemple :

reward = (maxStep - currentStep) * 0.8

Ce qui l'incite à faire le parcours le plus rapidement possible.

On constate que l'agent apprend bien à se déplacer vers sa cible (boule rouge). Mais qu'une fois atteinte il reste à proximité

Comment savoir si je suis sur le cul ?

Une des difficultés a été la création d'un algorithme permettant de savoir dans quelle position se trouve l'agent. Pour savoir si l'agent est debout, c'est assez simple. Je considère qu'il est debout si :

  • 1. La valeur normalisée de la hauteur de sa tête est supérieure à 0.8.
  • 2. L'angle entre son torse.forward et un Vector3.up est supérieur à 65° et inférieur à 140°.
  • 3. La distance entre la position moyenne de ses pieds et son centre de gravité placé à Y = 0 est inférieure à 1.

Par contre, savoir si l'agent est sur sa face avant ou sur son dos est une autre paire de manches. Il ne suffit pas d'observer l'orientation d'un membre pour savoir si l'agent est sur sa face avant ou sur son dos. Si on prend par exemple le torse, on peut se dire que s'il pointe vers le sol, c'est que l'agent est sur sa face avant. Mais il peut aussi bien être assis et juste assez penché en avant. La solution que j'ai trouvée est de prendre la moyenne de l'orientation des cuisses, tibias, bassin et torse, puis de faire un produit scalaire entre cette valeur et un Vector3.Down. Si le produit scalaire est supérieur à 0.2, on considère qu'il est face au sol. Sinon, c'est qu'il est sur le dos.

Tu te prends pour un soldat en parade ?

L'un des problèmes avec le reinforcement learning est que l'agent doit tester un grand nombre d'actions avant de trouver une combinaison qui lui rapporte des points. Pour faire le premier pas, l'agent doit parvenir à activer certains muscles dans un certain ordre. Une fois qu'il a découvert la combinaison nécessaire pour son premier pas, il a tendance à exacerber ce mouvement avant de comprendre comment faire le second pas. Si l'agent apprend à placer le pied droit en premier, ce pied tend à dominer le pied gauche.

Pour inciter l'agent à alterner les pieds, j'ai essayé plusieurs approches :

  • Je lui fournis une valeur indiquant quel pied était en avant en dernier.
  • Je bloque le pied qui a été en avant en dernier. (aucuns résultats)
  • Je ne récompense que lorsque le pied qui était en retrait passe en avant. Cette méthode donne de bons résultats pour lui apprendre à marcher et réduit la dominance d'un pied. Cependant, l'agent reste incapable de commencer en alternant le premier pied en avant.

Pour éviter que l'agent ne s'élance avec un pied en avant de manière asymétrique, j'ai ajouté une pénalité si le pied part trop loin ou trop haut. Cette pénalité est ajoutée en tant que coefficient dans les récompenses précédentes et permet d'obtenir une marche plus symétrique, bien que ce ne soit jamais totalement parfait.

Sur cet extrait, on constate que l'agent lance en avant son pied droit, tandis que le pied gauche se contente de rattraper le droit.

Processus d'Entraînement

Entraînement de la Marche

Il y a eu beaucoup d'itérations sur la manière d'entraîner le robot à marcher. Au début, je n'utilisais que la récompense basée sur la vitesse de déplacement multipliée par l'orientation. Cette méthode fonctionne très bien, mais nécessite beaucoup de temps d'entraînement. Initialement, il fallait près de 24 heures d'entraînement sur 12 agents avec une vitesse multipliée par 10. Cela correspond à environ 120 jours d'entraînement avec un seul agent à une vitesse normale.

Avec l'amélioration des récompenses mentionnées précédemment, le temps moyen d'apprentissage a été réduit à entre 2 et 4 heures (10 à 20 jours) pour que l'agent soit capable de marcher.

Un autre point est l'inclinaison sur l'axe Y de l'agent. Au début de l'entraînement, je fais commencer l'agent avec une valeur aléatoire comprise entre 0° et 30°. Une fois les premiers pas réalisés, j'augmente cette valeur jusqu'à 90° afin de lui apprendre à se tourner sans chuter.

Cet extrait vidéo présente l'évolution du modèle dans l'apprentissage de la marche.
Bien que le terme de génération n'existe pas dans ce type d'apprentissage, il permet de représenter l'évolution au fil du temps.

Entraînement aux Escaliers

L'entraînement pour monter et descendre les escaliers ne demande pas de récompense particulière, c'est la même récompense que celle utilisée pour la marche.

Le seul paramètre qui peut changer est la hauteur maximale des pieds.

Cet entraînement peut cependant prendre beaucoup de temps, voire être impossible si l'agent a appris à marcher sans lever suffisamment les pieds.

Entraînement pour se Relever

Un gros problème rencontré est qu'en apprenant à l'agent à se relever après lui avoir appris à marcher, celui-ci oublie comment marcher. Ce problème est connu sous le nom de "catastrophic forgetting" ou "catastrophic interference".

J'ai tenté plusieurs modifications des hyperparamètres, un apprentissage en parallèle et le curriculum learning. Ce qui semble le mieux fonctionner est d'ajouter une couche de neurones et de réaliser un apprentissage en parallèle asymétrique. Cela consiste à commencer par apprendre à l'agent à marcher et faire ses premiers pas avant d'alterner entre se relever et marcher.

Mais même avec cette méthode, l'agent dégénère très vite et a du mal à marcher.

La solution que j'ai trouvée est de créer trois modèles neuronaux spécifiques à chaque action, qui sont appelés en fonction des besoins.

L'entraînement pour permettre à l'agent de se relever est plus compliqué que pour la marche. Inciter l'agent à se relever n'est pas un problème en soi, le problème réside dans le fait que l'agent finira par trouver un moyen d'exploiter la physique du moteur Unity pour se lever d'une manière qui ne semble pas naturelle.

La seule parade que j'ai trouvée est de placer un coefficient inverse à la vélocité moyenne de l'agent au moment où il est debout, ainsi qu'une lourde pénalité si ses pieds ne sont pas en contact avec le sol.

Conclusion

Points d'amélioration

Bien que je sois très content de mon robot, j'aurais aimé y apporter quelques modifications. Par exemple, au niveau de ses capteurs sur la tête. J'ai l'impression qu'il penche la tête sur le côté car ces derniers ne lui permettent pas de voir le sol à proximité par manque de flexibilité dans l'orientation de la tête. Donc, les incliner de 30° serait, selon moi, quelque chose à tester dans une future version.

Futurs projets

Au moment de choisir un projet, j'avais hésité entre un robot humanoïde capable de se relever et un avant-bras muni d'une main pour manipuler des objets. J'ai finalement choisi le robot humanoïde. Mais le projet de la main reste en suspens. Cette main devrait, par exemple, prendre un dé qu'elle devrait retourner pour afficher une valeur spécifique. Ou simplement prendre un objet et le déplacer ailleurs.

Conclusion

Ce projet est l'aboutissement de quatre mois d'apprentissage. Que ce soit sur la création d'une IA, l'utilisation d'Unity ou encore Blender, j'ai beaucoup appris. Le domaine de l'IA est passionnant, offrant des possibilités très vastes qui évoluent constamment. Au premier abord, ce qui est faisable ou qui gagnerait à être réalisé par une IA n'est pas très intuitif. Le sous-domaine de l'IA qu'est le reinforcement learning est, selon moi, le plus passionnant, même s'il est pour l'instant considéré comme la solution de dernier recours pour de nombreux projets.

Fixed Image