Hogyan használhatjuk az AI-t a Sonic the Hedgehog játékához. SZERETETLEN!

Nemzedékről nemzedékre az emberek alkalmazkodtak ahhoz, hogy jobban illeszkedjenek a környezetünkhöz. Főemlősökként indultunk, akik az enni vagy elfogyasztott világban élnek. Végül olyanokká fejlődtünk, akik ma vagyunk, tükrözve a modern társadalmat. Az evolúció során okosabbá válunk. Képesek vagyunk jobban együttműködni a környezetünkkel, és elérni, amire szükségünk van.

Az evolúció útján történő tanulás fogalma alkalmazható a mesterséges intelligenciára is. Képezhetjük az AI-ket bizonyos feladatok elvégzésére a NEAT, az Augmented Topologies Neuroevolution segítségével. Egyszerűen fogalmazva, a NEAT egy olyan algoritmus, amely egy AI-t (genomokat) vesz fel egy adott feladat végrehajtására. A legjobban teljesítő AI-k „szaporodnak”, hogy létrehozzák a következő generációt. Ez a folyamat addig folytatódik, amíg nem lesz olyan generációnk, amely képes teljesíteni a szükséges dolgokat.

A NEAT elképesztő, mert kiküszöböli az AI-k kiképzéséhez szükséges, már meglévő adatok szükségességét. A NEAT és az OpenAI Gym Retro erejét felhasználva megtanítottam egy AI-t, hogy játsszon Sonic the Hedgehogot a SEGA Genesis számára. Tanuljuk meg, hogyan!

NEAT neurális hálózat (Python implementáció)

GitHub-tárház

Vedant-Gupta523 / sonicNEAT

Hozzon létre hozzájárulást a Vedant-Gupta523 / sonicNEAT fejlesztéséhez egy fiók létrehozásával a GitHubon. github.com

Megjegyzés: A cikkben szereplő összes kód és a fenti repo Lucas Thompson Sonic AI Botjának kissé módosított változata, az Open-AI és a NEAT YouTube oktatóanyagok és kódok használatával.

Az OpenAI tornaterem megértése

Ha még nem ismeri az OpenAI Gym-et, nézze át az alábbi terminológiát. A cikkben gyakran használják őket.

ügynök - Az AI játékos. Ebben az esetben Sonic lesz.

környezet - Az ügynök teljes környezete. A játék környezete.

cselekvés - Valamire az ügynöknek lehetősége van megtenni (azaz balra mozogni, jobbra mozogni, ugrani, semmit sem csinálni).

lépés - 1 művelet végrehajtása.

állapot - A környezet kerete. Az AI jelenlegi helyzete.

megfigyelés - Amit az AI megfigyel a környezetből.

fitnesz - Milyen jól teljesít az AI.

kész - Amikor az AI teljesítette feladatát, vagy nem tudja tovább folytatni.

A függőségek telepítése

Az alábbiakban az OpenAI és a NEAT GitHub linkjei találhatók telepítési utasításokkal.

OpenAI : //github.com/openai/retro

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

Pip telepítési könyvtárak, például cv2, numpy, savanyúság stb.

Könyvtárak importálása és a környezet beállítása

A kezdéshez be kell importálnunk az összes használni kívánt modult:

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

Meghatározzuk környezetünket is, amely a játékból és az állapotból áll:

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

Ahhoz, hogy egy AI-t betanítson a Sonic the Hedgehog játékához, szüksége lesz a játék ROM-jára (játékfájlra). A legegyszerűbb módja az, ha megvásárolja a játékot a Steam-től 5 dollárért. A ROM ingyenes online letöltését is megtalálhatja, bár ez illegális, ezért ne tegye ezt.

Az OpenAI tárházban a retro / retro / data / stabil / címen talál egy mappát a Sonic the Hedgehog Genesis számára. Helyezze ide a játék ROM-ját, és győződjön meg róla, hogy rom.md-nek hívják. Ez a mappa tartalmaz .state fájlokat is. Kiválaszthatja az egyiket, és az állapotparamétert megadhatja azzal. A GreenHillZone Act 1-et választottam, mivel ez a játék legelső szintje.

A data.json és a scenario.json megértése

A Sonic the Hedgehog mappában ez a két fájl lesz:

adatok.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"  } }

forgatókönyv.json

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

Mindkét fájl fontos információkat tartalmaz a játékkal és annak oktatásával kapcsolatban.

Ahogy hangzik, a data.json fájl információkat / adatokat tartalmaz a különböző játékspecifikus változókról (azaz Sonic x-helyzetéről, életeinek számáról stb.).

A scenario.json fájl lehetővé teszi számunkra, hogy az adatváltozók értékeivel szinkronban végezzünk műveleteket. Például jutalmazhatjuk a Sonic 10.0-t minden alkalommal, amikor az x-pozíciója növekszik. Azt is megtehetjük, hogy az elvégzett feltételünk igaz, amikor Sonic élete 0-ra rúg.

A NEAT előremenő konfigurációjának megértése

A config-feedforward fájl megtalálható a fent linkelt GitHub-tárban. Úgy működik, mint egy beállítási menü az edzésünk beállításához. Néhány egyszerű beállítás bemutatásához:

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

Rengeteg beállítással kísérletezhet, hogy lássa, milyen hatással van az AI edzésére! Ha többet szeretne megtudni a NEAT-ról és a feedfoward konfigurációjának különböző beállításairól, nagyon ajánlom, hogy olvassa el a dokumentációt

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) is an algorithm used to train AI to perform certain tasks. It is modeled after genetic evolution.
  2. NEAT eliminates the need for pre-existing data when training AI.
  3. The process of implementing OpenAI and NEAT usingPython to train an AI to play any game.