Πώς να χρησιμοποιήσετε το AI για να παίξετε το Sonic the Hedgehog. ΚΑΘΕ!

Από γενιά σε γενιά, οι άνθρωποι έχουν προσαρμοστεί για να γίνουν πιο κατάλληλοι με το περιβάλλον μας. Ξεκινήσαμε ως πρωτεύοντες που ζουν σε έναν κόσμο φαγητού ή φαγητού. Τελικά εξελίχσαμε σε αυτό που είμαστε σήμερα, αντανακλώντας τη σύγχρονη κοινωνία. Μέσα από τη διαδικασία της εξέλιξης γινόμαστε πιο έξυπνοι. Είμαστε σε θέση να εργαστούμε καλύτερα με το περιβάλλον μας και να επιτύχουμε ό, τι χρειαζόμαστε.

Η έννοια της μάθησης μέσω της εξέλιξης μπορεί επίσης να εφαρμοστεί στην Τεχνητή Νοημοσύνη. Μπορούμε να εκπαιδεύσουμε τα AI να εκτελούν συγκεκριμένες εργασίες χρησιμοποιώντας NEAT, Neuroevolution of Augmented Topologies. Με απλά λόγια, το NEAT είναι ένας αλγόριθμος που παίρνει μια παρτίδα AIs (γονιδιώματα) προσπαθώντας να ολοκληρώσει μια δεδομένη εργασία. Η κορυφαία απόδοση «φυλή» για τη δημιουργία της επόμενης γενιάς. Αυτή η διαδικασία συνεχίζεται έως ότου έχουμε μια γενιά που είναι ικανή να ολοκληρώσει αυτό που χρειάζεται.

Το NEAT είναι εκπληκτικό επειδή εξαλείφει την ανάγκη για προϋπάρχοντα δεδομένα που απαιτούνται για την εκπαίδευση των AIs μας. Χρησιμοποιώντας τη δύναμη του NEAT και του OpenAI's Gym Retro, εκπαίδεψα ένα AI για να παίξω το Sonic the Hedgehog για το SEGA Genesis. Ας μάθουμε πώς!

ΝΕΟ ΝΕΥΡΙΚΟ ΔΙΚΤΥΟ (Εφαρμογή Python)

Αποθήκη GitHub

Vedant-Gupta523 / sonicNEAT

Συνεισφέρετε στην ανάπτυξη Vedant-Gupta523 / sonicNEAT δημιουργώντας έναν λογαριασμό στο GitHub. github.com

Σημείωση: Όλος ο κωδικός σε αυτό το άρθρο και το repo παραπάνω είναι μια ελαφρώς τροποποιημένη έκδοση του Sonic AI Bot του Lucas Thompson που χρησιμοποιεί εκπαιδευτικά προγράμματα και κώδικα Open-AI και NEAT YouTube.

Κατανόηση του γυμναστηρίου OpenAI

Εάν δεν είστε ήδη εξοικειωμένοι με το OpenAI Gym, ανατρέξτε στην παρακάτω ορολογία. Θα χρησιμοποιούνται συχνά σε όλο το άρθρο.

πράκτορας - Η συσκευή αναπαραγωγής AI. Σε αυτήν την περίπτωση θα είναι Sonic.

περιβάλλον - Το πλήρες περιβάλλον του πράκτορα. Το περιβάλλον του παιχνιδιού.

δράση - Κάτι που ο πράκτορας έχει την επιλογή να κάνει (π.χ. κίνηση αριστερά, κίνηση δεξιά, άλμα, δεν κάνει τίποτα).

βήμα - Εκτέλεση 1 δράσης.

κατάσταση - Ένα πλαίσιο του περιβάλλοντος. Η τρέχουσα κατάσταση στην οποία βρίσκεται το AI.

παρατήρηση - Τι παρατηρεί η ΑΠ από το περιβάλλον.

fitness - Πόσο καλά αποδίδει η AI μας.

ολοκληρωμένο - Όταν το AI έχει ολοκληρώσει την εργασία του ή δεν μπορεί να συνεχίσει περαιτέρω.

Εγκατάσταση εξαρτήσεων

Ακολουθούν οι σύνδεσμοι GitHub για OpenAI και NEAT με οδηγίες εγκατάστασης.

OpenAI : //github.com/openai/retro

NEAT : //github.com/CodeReclaimers/neat-python

Pip install βιβλιοθήκες όπως cv2, numpy, pickle κ.λπ.

Εισαγάγετε βιβλιοθήκες και ορίστε περιβάλλον

Για να ξεκινήσουμε, πρέπει να εισαγάγουμε όλες τις ενότητες που θα χρησιμοποιήσουμε:

import retro import numpy as np import cv2 import neat import pickle

Θα ορίσουμε επίσης το περιβάλλον μας, που αποτελείται από το παιχνίδι και την κατάσταση:

env = retro.make(game = "SonicTheHedgehog-Genesis", state = "GreenHillZone.Act1")

Για να εκπαιδεύσετε ένα AI για να παίξετε το Sonic the Hedgehog, θα χρειαστείτε τη ROM του παιχνιδιού (αρχείο παιχνιδιού). Ο πιο απλός τρόπος είναι να αγοράσετε το παιχνίδι από το Steam για $ 5. Θα μπορούσατε επίσης να βρείτε δωρεάν λήψεις του ROM online, ωστόσο είναι παράνομο, οπότε μην το κάνετε αυτό.

Στο αποθετήριο OpenAI στο retro / retro / data / stable / θα βρείτε ένα φάκελο για το Sonic the Hedgehog Genesis. Τοποθετήστε τη ROM του παιχνιδιού εδώ και βεβαιωθείτε ότι ονομάζεται rom.md. Αυτός ο φάκελος περιέχει επίσης αρχεία .state. Μπορείτε να επιλέξετε μία και να ορίσετε την παράμετρο κατάστασης ίση με αυτήν. Επέλεξα το GreenHillZone Act 1 αφού είναι το πρώτο επίπεδο του παιχνιδιού.

Κατανόηση του data.json και του σεναρίου.json

Στο φάκελο Sonic the Hedgehog θα έχετε αυτά τα δύο αρχεία:

data.json

{ "info": { "act":  "address": 16776721, "type": ", "level_end_bonus":  "address": 16775126, "type": ", "lives":  "address": 16776722, "type": ", "rings": { "address": 16776736, "type": ">u2" }, "score": { "address": 16776742, "type": ">u4" }, "screen_x": { "address": 16774912, "type": ">u2" }, "screen_x_end": { "address": 16774954, "type": ">u2" }, "screen_y": { "address": 16774916, "type": ">u2" }, "x": { "address": 16764936, "type": ">i2" }, "y": { "address": 16764940, "type": ">u2" }, "zone": u1"  } }

σενάριο.json

{ "done": { "variables": { "lives": { "op": "zero" } } }, "reward": { "variables": { "x": { "reward": 10.0 } } } }

Και τα δύο αυτά αρχεία περιέχουν σημαντικές πληροφορίες σχετικά με το παιχνίδι και την εκπαίδευσή του.

Όπως ακούγεται, το αρχείο data.json περιέχει πληροφορίες / δεδομένα σχετικά με διαφορετικές συγκεκριμένες μεταβλητές του παιχνιδιού (π.χ. θέση του Sonic, αριθμός ζωών που έχει, κ.λπ.).

Το αρχείοenario.json μας επιτρέπει να εκτελούμε ενέργειες σε συγχρονισμό με τις τιμές των μεταβλητών δεδομένων. Για παράδειγμα, μπορούμε να ανταμείψουμε το Sonic 10.0 κάθε φορά που η θέση του x αυξάνεται. Θα μπορούσαμε επίσης να θέσουμε την τελική μας κατάσταση σε αλήθεια όταν οι ζωές του Sonic έφτασαν στο 0

Κατανόηση της διαμόρφωσης NEAT feedforward

Το αρχείο config-feedforward μπορεί να βρεθεί στο αποθετήριο GitHub που είναι συνδεδεμένο παραπάνω. Λειτουργεί σαν ένα μενού ρυθμίσεων για τη ρύθμιση της εκπαίδευσής μας Για να επισημάνετε μερικές απλές ρυθμίσεις:

fitness_threshold = 10000 # How fit we want Sonic to become pop_size = 20 # How many Sonics per generation num_inputs = 1120 # Number of inputs into our model num_outputs = 12 # 12 buttons on Genesis controller

Υπάρχουν τόνοι ρυθμίσεων με τις οποίες μπορείτε να πειραματιστείτε για να δείτε πώς επηρεάζει την εκπαίδευση της τεχνητής νοημοσύνης σας! Για να μάθετε περισσότερα σχετικά με το NEAT και τις διαφορετικές ρυθμίσεις στη διαμόρφωση feedfoward, θα συνιστούσα ανεπιφύλακτα να διαβάσετε την τεκμηρίωση εδώ

Putting it all together: Creating the Training File

Setting up configuration

Our feedforward configuration is defined and stored in the variable config.

config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet, neat.DefaultStagnation, 'config-feedforward')

Creating a function to evaluate each genome

We start by creating the function, eval_genomes, which will evaluate our genomes (a genome could be compared to 1 Sonic in a population of Sonics). For each genome we reset the environment and take a random action

for genome_id, genome in genomes: ob = env.reset() ac = env.action_space.sample()

We will also record the game environment’s length and width and color. We divide the length and width by 8.

inx, iny, inc = env.observation_space.shape inx = int(inx/8) iny = int(iny/8)

We create a recurrent neural network (RNN) using the NEAT library and input the genome and our chosen configuration.

net = neat.nn.recurrent.RecurrentNetwork.create(genome, config)

Finally, we define a few variables: current_max_fitness (the highest fitness in the current population), fitness_current (the current fitness of the genome), frame (the frame count), counter (to count the number of steps our agent takes), xpos (the x-position of Sonic), and done (whether or not we have reached our fitness goal).

current_max_fitness = 0 fitness_current = 0 frame = 0 counter = 0 xpos = 0 done = False

While we have not reached our done requirement, we need to run the environment, increment our frame counter, and shape our observation to mimic that of the game (still for each genome).

env.render() frame += 1 ob = cv2.resize(ob, (inx, iny)) ob = cv2.cvtColor(ob, cv2.COLOR_BGR2GRAY) ob = np.reshape(ob, (inx,iny))

We will take our observation and put it in a one-dimensional array, so that our RNN can understand it. We receive our output by feeding this array to our RNN.

imgarray = [] imgarray = np.ndarray.flatten(ob) nnOutput = net.activate(imgarray)

Using the output from the RNN our AI takes a step. From this step we can extract fresh information: a new observation, a reward, whether or not we have reached our done requirement, and information on variables in our data.json (info).

ob, rew, done, info = env.step(nnOutput)

At this point we need to evaluate our genome’s fitness and whether or not it has met the done requirement.

We look at our “x” variable from data.json and check if it has surpassed the length of the level. If it has, we will increase our fitness by our fitness threshold signifying we are done.

xpos = info['x'] if xpos >= 10000: fitness_current += 10000 done = True

Otherwise, we will increase our current fitness by the reward we earned from performing the step. We also check if we have a new highest fitness and adjust the value of our current_max_fitness accordingly.

fitness_current += rew if fitness_current > current_max_fitness: current_max_fitness = fitness_current counter = 0 else: counter += 1

Lastly, we check if we are done or if our genome has taken 250 steps. If so, we print information on the genome which was simulated. Otherwise we keep looping until one of the two requirements has been satisfied.

if done or counter == 250: done = True print(genome_id, fitness_current) genome.fitness = fitness_current

Defining the population, printing training stats, and more

The absolute last thing we need to do is define our population, print out statistics from our training, save checkpoints (in case you want to pause and resume training), and pickle our winning genome.

p = neat.Population(config) p.add_reporter(neat.StdOutReporter(True)) stats = neat.StatisticsReporter() p.add_reporter(stats) p.add_reporter(neat.Checkpointer(1)) winner = p.run(eval_genomes) with open('winner.pkl', 'wb') as output: pickle.dump(winner, output, 1)

All that’s left is the matter of running the program and watching Sonic slowly learn how to beat the level!

To see all of the code put together check out the Training.py file in my GitHub repository.

Bonus: Parallel Training

If you have a multi-core CPU you can run multiple training simulations at once, exponentially increasing the rate at which you can train your AI! Although I will not go through the specifics on how to do this in this article, I highly suggest you check the sonicTraning.py implementation in my GitHub repository.

Conclusion

That’s all there is to it! With a few adjustments, this framework is applicable to any game for the NES, SNES, SEGA Genesis, and more. If you have any questions or you just want to say hello, feel free to email me at vedantgupta523[at]gmail[dot]com ?

Also, be sure to check out Lucas Thompson's Sonic AI Bot Using Open-AI and NEAT YouTube tutorials and code to see what originally inspired this article.

Key Takeaways

  1. Το Neuroevolution of Augmenting Topologies (NEAT) είναι ένας αλγόριθμος που χρησιμοποιείται για να εκπαιδεύσει το AI για την εκτέλεση συγκεκριμένων εργασιών. Διαμορφώνεται μετά από γενετική εξέλιξη.
  2. Το NEAT εξαλείφει την ανάγκη για προϋπάρχοντα δεδομένα κατά την εκπαίδευση του AI.
  3. Η διαδικασία εφαρμογής OpenAI και NEAT χρησιμοποιώνταςPython για να εκπαιδεύσει ένα AI για να παίξει οποιοδήποτε παιχνίδι.