Introduction
Quand j’ai rejoint Eidos–Montréal en 2018, on m’a donné carte blanche pour explorer les possibilités de l’apprentissage automatique (ML, Machine Learning) dans le cadre du rendu en temps réel, parfois appelé intelligence artificielle appliquée au graphisme. Intrigué et curieux, j’ai accepté l’offre sans hésiter et j’ai commencé à réfléchir à des applications potentielles.
Avant de débuter cet emploi, je n’avais aucune expérience de l’apprentissage automatique. Ce projet était avant tout formatif et visait à vérifier si cette technologie était prête à être employée par un développeur de jeux vidéo. Dans cette publication, je souhaite vous parler en des termes accessibles de mes débuts dans le domaine de l’intelligence artificielle appliquée au graphisme.
Après m’être familiarisé avec le monde merveilleux de l’apprentissage automatique et quelques-unes de ses bibliothèques logicielles, comme TensorFlow et PyTorch, le premier projet sur lequel j’ai décidé de travailler était inspiré par l’article sur l’occlusion ambiante par réseau de neurones (NNAO, Neural Network Ambient Occlusion) de Daniel Holden, qui me semblait assez simple pour un premier test. L’article démontre qu’il est possible d’entraîner un réseau de neurones relativement modeste à reproduire l’occlusion ambiante (AO, Ambient Occlusion) à partir de la profondeur et des normales de rendu.
occlusion AmbiantE à l’aide de réseaux de neurones
Pour y parvenir dans un environnement prototype, j’ai choisi d’utiliser Falcor, de NVIDIA. Falcor intègre un algorithme d’occlusion ambiante basée sur l’horizon (HBAO, Horizon Based Ambient Occlusion), qui sert de référence. Il prend également en charge le lancer de rayons via l’API DXR, que j’ai plus tard utilisé pour une référence d’AO de qualité encore supérieure.
Le modèle de réseau de neurones proposé est un perceptron multicouche (PMC), facile à exécuter sur un shader GPU sans opérations complexes, c’est-à-dire sans cuDNN ou DirectML. Étant spécialisé dans le rendu en temps réel, j’ai voulu aller plus loin et m’assurer que l’on pouvait entraîner vite, itérer facilement et, si possible, de façon interactive. Par ailleurs, travailler dans des environnements en 3D permet de tirer parti de moteurs de jeu et de rendre une quantité illimitée de données d’apprentissage (contrairement aux modèles d’apprentissage automatiques habituels, qui se basent sur une quantité prédéfinie d’images), collectées simplement lors de sessions de jeu.
Dans cette optique, j’ai modifié Falcor pour entraîner le modèle en continu avec des données provenant du moteur. Avec l’exécution asynchrone dans Python, il est possible de « jouer » pendant que le modèle apprend en arrière-plan en capturant les nouvelles données de l’état de rendu courant dès qu’une étape d’apprentissage définie par la personne qui l’utilise s’achève. À chaque itération, les poids d’inférence sont également actualisés à partir de l’état du modèle afin que l’on puisse contrôler de façon interactive la progression de l’apprentissage directement à l’écran avec une occlusion ambiante inférée en temps réel.
Une étape d’apprentissage dure environ 1 à 2 secondes et le modèle peut ensuite converger, c’est-à-dire donner de bons résultats, proches de la cible de référence, au bout de 30 secondes environ. On remarquera que la qualité des résultats stagne après 30 secondes, mais que le modèle s’adapte rapidement à des cas inédits quand il y est confronté.
Occlusion ambiante par tracé de rayons
J’étais satisfait de ce premier projet car il était simple à mettre en œuvre et a donné de bons résultats, avec un apprentissage extrêmement rapide. Je suis alors passé à mon deuxième projet expérimental, exploitant l’occlusion ambiante par lancer de rayons (RTAO, raytraced ambient occlusion) via la nouvelle API de lancer de rayons DXR. Pour en savoir plus sur le lancer de rayons et DXR, je vous recommande le livre numérique en ligne RaytracingGems (en anglais).
L’occlusion ambiante par lancer de rayons consiste à choisir au hasard des directions (ce qu’on appelle aussi échantillonnage ou tirage aléatoire) dans l’hémisphère entourant l’emplacement cible et à tester si les directions opposées font l’objet d’une occlusion. Malheureusement, il faut tester de nombreuses directions (échantillons) pour que le résultat converge vers la réalité du terrain, ce qui peut s’avérer excessivement coûteux.
Avec le rendu en temps réel, étant donné qu’on ne peut disposer que de quelques échantillons par image, on échantillonne aléatoirement une petite quantité, ce qui génère un bruit important à l’image. Pour contrer ce phénomène, il faut procéder à une phase de débruitage supplémentaire qui viendra lisser le résultat en supprimant le bruit de l’échantillonnage aléatoire.
Bien que la phase de débruitage introduise quelques approximations, les résultats finaux restent de très haute qualité et, en comparaison, supérieurs à ce que l’on obtient avec les méthodes appliquées à l’espace écran, comme l’HBAO testée lors du projet NNAO.
Alors que mon objectif était initialement de faire progresser le NNAO en prenant pour référence le RTAO, je me suis intéressé au potentiel des débruiteurs et j’ai décidé de recentrer mon projet sur ce filon de recherche.
Bruit à Bruit
Lors du Siggraph 2018, j’ai assisté à la présentation de Noise2Noise, par Jaakko Lehtinen, qui m’a donné envie de procéder à des tests dès mon retour au studio. En résumé, l’étude avançait qu’il était possible d’entraîner un modèle à calculer des résultats convergés en ne lui fournissant que des entrées bruitées. Contrairement à ce qui se fait habituellement avec un algorithme de débruitage, Noise2Noise recourt à un autre rendu bruité comme image cible au lieu de la sortie convergée en tracés de rayons.
Vu la facilité avec laquelle il est possible d’obtenir des images bruitées avec le lancer de rayons, j’ai pensé que c’était une opportunité de test en or pour notre occlusion ambiante par lancer de rayon. Au lieu d’attendre que le lancer de rayons converge (c’est-à-dire quelques secondes) avant de fournir le résultat au modèle, il nous serait possible d’alimenter la base de données d’apprentissage « instantanément » (en quelques millisecondes), et ainsi de gagner un temps précieux.
Comparé à celui de notre précédent projet, ce réseau de neurones est plus complexe et basé sur une architecture U-Net, qui allonge la durée d’apprentissage. Voici des résultats pendant l’entrainement du modèle, sur la scène du “Bistro” d’Amazon (sous la licence CC BY 4.0). La première rangée montre le résultat original, la deuxième représente la cible idéale et la troisième montre les résultats du réseau de neurone au fur et à mesure des itérations d’entraînement.
Bien qu’imparfaites, ces images sont plutôt impressionnantes si on considère que le modèle de réseau de neurones n’a jamais vu d’image convergée. Mes premières expériences employaient 2 ou 4 échantillons par pixel (résultats ci-dessus) mais les résultats étaient similaires avec un seul échantillon par pixel. Ce fait ouvre de nombreuses perspectives pour d’autres algorithmes en temps réel ne permettant d’avoir que quelques échantillons par pixel à chaque image.
RéSULTATS
Ce modèle est un réseau neural convolutif (RNC), c’est-à-dire qu’il est indépendant de la résolution de l’image. Ainsi, même si le modèle apprend à partir de petites portions (en 256×256) du tampon d’image, l’inférence finale peut être appliquée directement à un tampon d’image plein format avec une qualité équivalente, comme le montre la capture d’écran ci-dessous :
Bien sûr, l’apprentissage automatique n’est ni parfait ni magique. Il y a bien d’autres paramètres à prendre en compte et des cas où il ne fonctionne pas très bien (pour l’instant ?). Par exemple, la prédictibilité et la robustesse comptent, à mon sens, parmi les choses les plus difficiles à obtenir avec l’apprentissage automatique en général (bien que je ne sois clairement pas un expert en la matière et qu’il existe déjà de nombreux travaux tentant de résoudre ces problèmes). L’inférence sur de données inédites peut autant donner un bon résultat à un endroit qu’un mauvais résultat ailleurs (voir l’image ci-dessous). Même s’il était possible d’inclure ces problématiques lors de l’apprentissage, il serait probablement impossible d’anticiper tous les échecs potentiels, y compris dans le cadre limité d’un jeu vidéo AAA.
En outre, la cohérence temporelle peut aussi constituer une difficulté mais plusieurs articles semblent annoncer d’excellents résultats pour les transitions d’image à image.
Conclusion
Mon exploration à travers l’intelligence artificielle appliquée au graphisme fut convaincante et montre un grand potentiel pour de nouvelles techniques éventuelles même si les résultats sont souvent instables ou imprédictibles. Il était assez facile de mettre en place ces algorithmes d’apprentissage automatique mais il est probablement beaucoup plus complexe et long d’obtenir d’encore meilleurs résultats. Même si les limitations actuelles citées plus haut rendent difficile l’utilisation massive de réseaux de neurones dans l’industrie du rendu temps réel, je ne doute pas que ce n’est qu’une question de temps avant de voir une adoption générale, comme le fait Nvidia avec sa technologie DLSS.
Auteur
Thibault Lambert est un ingénieur en programmation graphique R&D et a rejoint Eidos-Montréal en 2018. Il a travaillé ces 13 dernières années à la fois dans l’industrie du jeux vidéo mais aussi des effets spéciaux pour films et a eu la chance de travailler sur plusieurs films renommés internationalement et des jeux AAA. Il est passionné par le rendu temps réel et est dédié à réduire autant que possible l’écart entre les rendus temps réels et les rendus pré-calculés.