En raison de la nature de la question, je dois inclure beaucoup d'informations de base (parce que ma question est: comment puis-je restreindre cela?) Cela dit, cela peut être résumé (à ma connaissance) comme:
Quelles méthodes existent pour trouver des optimums locaux sur des espaces de recherche combinatoire extrêmement grands?
Contexte
Dans la communauté de superplay assistée par outils, nous cherchons à fournir des entrées spécialement conçues (non générées en temps réel) à une console de jeu vidéo ou à un émulateur afin de minimiser certains coûts (généralement le délai de réalisation). La façon dont cela se fait actuellement consiste à jouer le jeu image par image et en spécifiant l'entrée pour chaque image, en refaisant souvent plusieurs fois des parties de l'analyse (par exemple, l' analyse récemment publiée pour The Legend of Zelda: Ocarina of Time a un total de 198 590 tentatives).
Faire en sorte que ces pistes atteignent leur objectif se résume généralement à deux facteurs principaux: la planification de l'itinéraire et la traversée. Le premier est beaucoup plus "créatif" que le second.
La planification de l'itinéraire consiste à déterminer dans quelle direction le joueur doit naviguer dans l'ensemble pour terminer le jeu, et est souvent la partie la plus importante de la course. Cela revient à choisir la méthode de tri à utiliser, par exemple. Le meilleur tri de bulles au monde ne va tout simplement pas surpasser un tri rapide sur 1 million d'éléments.
Cependant, dans le désir de perfection, la traversée (comment se déroule l'itinéraire) est également un facteur important. Poursuivant l'analogie, c'est ainsi que l'algorithme de tri est implémenté. Certains itinéraires ne peuvent même pas être effectués sans des cadres d'entrée très spécifiques. Il s'agit du processus d'assistance d'outils le plus fastidieux et c'est ce qui fait que la production d'un cycle complet prend des mois, voire des années. Ce n'est pas un processus difficile (pour un humain) car cela revient à essayer différentes variantes de la même idée jusqu'à ce qu'une soit jugée la meilleure, mais les humains ne peuvent essayer que de nombreuses variations de leur durée d'attention. L'application de machines à cette tâche semble appropriée ici.
Mon objectif est maintenant d'essayer d'automatiser le processus de traversée en général pour la console Nintendo 64 . L'espace de recherche pour ce problème est beaucoup trop grand pour attaquer avec une approche par force brute. Un segment à n trames d'une exécution N64 a 2 30n entrées possibles, ce qui signifie que 30 trames d'entrée (une seconde à 30 images par seconde) ont 2 900 entrées possibles; il serait impossible de tester ces solutions potentielles, sans parler de celles pour un cycle complet de deux heures.
Cependant, je ne suis pas intéressé à tenter (ou plutôt, je ne vais même pas essayer) une optimisation globale totale d'une exécution complète. Je voudrais plutôt, étant donné une entrée initiale, approximer l' optimum local pour un segment particulier d'une analyse (ou les n optimaux locaux les plus proches, pour une sorte d'optimisation semi-globale) . C'est-à-dire, étant donné une route et une traversée initiale de cette route: recherchez les voisins de cette traversée pour minimiser les coûts, mais ne dégénérez pas en essayant tous les cas qui pourraient résoudre le problème.
Mon programme devrait donc prendre un état de départ, un flux d'entrée, une fonction d'évaluation et produire l'optimum local en minimisant le résultat de l'évaluation.
État actuel
Actuellement, j'ai tout le cadre pris en charge. Cela inclut l'évaluation d'un flux d'entrée via la manipulation de l'émulateur, l'installation et le démontage, la configuration, etc. Et en tant qu'espace réservé, l'optimiseur est un algorithme génétique très basique. Il évalue simplement une population de flux d'entrée, stocke / remplace le gagnant et génère une nouvelle population en mutant le flux gagnant. Ce processus se poursuit jusqu'à ce que certains critères arbitraires soient remplis, comme l'heure ou le numéro de génération.
Notez que la partie la plus lente de ce programme sera, de loin, l'évaluation d'un flux d'entrée . En effet, cela implique d'émuler le jeu pour n images. (Si j'avais le temps, j'écrirais mon propre émulateur qui fournirait des crochets dans ce genre de choses, mais pour l'instant je me retrouve avec la synthèse des messages et la modification de la mémoire pour un émulateur existant à partir d'un autre processus.) Sur mon ordinateur principal, qui est assez moderne, l'évaluation de 200 images prend environ 14 secondes. En tant que tel, je préférerais un algorithme (étant donné le choix) qui minimise le nombre d'évaluations de fonctions.
J'ai créé un système dans le cadre qui gère les émulateurs simultanément. En tant que tel, je peux évaluer un certain nombre de flux à la fois avec une échelle de performances linéaire, mais pratiquement le nombre d'émulateurs en cours d'exécution ne peut être que de 8 à 32 (et 32 le pousse vraiment) avant que les performances du système ne se détériorent. Cela signifie (étant donné le choix), un algorithme qui peut effectuer le traitement pendant qu'une évaluation est en cours serait très bénéfique, car l'optimiseur peut faire de gros efforts pendant qu'il attend une évaluation.
A titre de test, ma fonction d'évaluation (pour le jeu Banjo Kazooie ) consistait à additionner, par image, la distance du joueur à un point de but. Cela signifiait que la solution optimale était de se rapprocher le plus rapidement possible de ce point. Limitant la mutation au stick analogique uniquement, il a fallu un jour pour obtenir une solution correcte . (C'était avant d'implémenter la simultanéité.)
Après avoir ajouté la simultanéité, j'ai activé la mutation des pressions sur le bouton A et j'ai fait la même fonction d'évaluation dans une zone qui nécessitait un saut. Avec 24 émulateurs en cours d'exécution, il a fallu environ 1 heure pour atteindre l'objectif à partir d'un flux d'entrée initialement vierge, mais il faudrait probablement qu'il s'exécute pendant des jours pour arriver à quelque chose de proche de l'optimal.
Problème
Le problème auquel je suis confronté est que je ne connais pas suffisamment le domaine de l'optimisation mathématique pour savoir comment modéliser correctement mon problème d'optimisation ! Je peux à peu près suivre l'idée conceptuelle de nombreux algorithmes tels que décrits sur Wikipedia, par exemple, mais je ne sais pas comment classer mon problème ou sélectionner l'algorithme de pointe pour cette catégorie.
D'après ce que je peux dire, j'ai un problème combinatoire avec un quartier extrêmement vaste . En plus de cela, la fonction d'évaluation est extrêmement discontinue, sans gradient et avec de nombreux plateaux . De plus, il n'y a pas beaucoup de contraintes, mais je serai heureux d'ajouter la possibilité de les exprimer si cela aide à résoudre le problème; Je voudrais permettre de spécifier que le bouton Démarrer ne doit pas être utilisé, par exemple, mais ce n'est pas le cas général.
Question
Ma question est donc: comment modéliser cela? Quel genre de problème d'optimisation essaie-je de résoudre? Quel algorithme dois-je utiliser? Je n'ai pas peur de lire des articles de recherche, alors faites-moi savoir ce que je dois lire!
Intuitivement, un algorithme génétique ne pourrait pas être le meilleur, car il ne semble pas vraiment apprendre. Par exemple, si appuyer sur Démarrer semble toujours aggraver l'évaluation (car cela met le jeu en pause), il devrait y avoir une sorte de concepteur ou de cerveau qui apprend: "appuyer sur Démarrer à tout moment est inutile." Mais même cet objectif n'est pas aussi trivial qu'il y paraît, car parfois, appuyer sur le démarrage est optimal, comme dans les soi-disant «sauts en arrière-longs sauts» dans Super Mario 64 ! Ici, le cerveau devrait apprendre un schéma beaucoup plus complexe: "appuyer sur Start est inutile, sauf lorsque le joueur est dans cet état très spécifique et continuera avec une combinaison de pressions sur les boutons ."
Il semble que je devrais (ou la machine pourrait apprendre à) représenter l'entrée d'une autre manière plus adaptée à la modification. L'entrée par image semble trop granulaire, car ce qui est vraiment nécessaire, ce sont des "actions", qui peuvent s'étendre sur plusieurs images ... pourtant de nombreuses découvertes sont faites image par image, donc je ne peux pas totalement l'exclure (le la pause susmentionnée en arrière-long-saut nécessite une précision au niveau de la trame). Il semble également que le fait que les entrées soient traitées en série devrait être quelque chose qui peut être capitalisé, mais je ne sais pas comment.
Je lis actuellement sur la recherche taboue (réactive), la recherche de quartier à très grande échelle, l'optimisation basée sur l'enseignement et l'apprentissage et l'optimisation des colonies de fourmis.
Ce problème est-il simplement trop difficile à résoudre avec autre chose que des algorithmes génétiques aléatoires? Ou s'agit-il en fait d'un problème trivial résolu depuis longtemps? Merci d'avoir lu et merci d'avance pour toutes les réponses.