Как я учил нейросеть в дудл джамп играть (Попытка 1)
Недавно пришла ко мне одна идея. Что если попробовать обучить нейросеть использовать класификацию чтобы научить ее играть в дудл джамп. Идея была такая: поиграть в игру самому, делая скриншоты игры и называя скриншот также как и нажатая в данный момент клавиша. Для простоты обошелся клавишами Влево, Вправа и ничего не нажимать. Далее нагенерировал много таких картинок используя браузер и плейрайт, загрузил в конволюш нейронную сеть, сделал модельку и сделал такой же метод для плейрайта чтобы он нажимал то что предсказывает модель.
Далее я приведу код. Кроме данные, получилось 2 файла: main.py
и train.ipynb
чтобы код сработал нужно установить playwright и fastai
pip install playwright fastai
main.py
import uuid
from playwright.sync_api import sync_playwright
from fastai.vision.all import *
def train():
with sync_playwright() as p:
browser = p.webkit.launch(headless=False)
page = browser.new_page(viewport=None)
page.goto("https://doodlejumporiginal.com/")
page.evaluate("""
document.addEventListener('keyup', e => {
document.pressed = null
console.log(e)
})
document.addEventListener('keyup', e => {
document.pressed = e.key
})
""")
loc = page.locator("canvas")
while True:
button = page.evaluate("document.pressed")
loc.screenshot(
path="./screenshots/"+ str(button) + "_"+ str(uuid.uuid4()) +".png",
caret="initial",
scale="css",
animations="allow",
quality=3,
type="jpeg",
)
def make_label(x): return (x.split("_"))[0]
def play():
learn_inf = load_learner('model.pkl', cpu=True)
with sync_playwright() as p:
browser = p.webkit.launch(headless=False)
page = browser.new_page(viewport=None)
page.goto("https://doodlejumporiginal.com/")
loc = page.locator("canvas")
key = "Backquote"
while True:
scr = "./screenshotsVal/"+ str(uuid.uuid4()) +".png"
loc.screenshot(
path=scr,
caret="initial",
scale="css",
animations="allow",
quality=3,
type="jpeg",
)
key = learn_inf.predict(scr)
key = key[0]
print(key)
if(key == "None"):
key = "Backquote"
key = key + "+"
page.keyboard.press(key*200 + "Backquote")
play()
# or train() to generate screenshots for training
train
- генерировал скриншоты для последующего обучения модели
play
- играл в дудл джамп. Нужно нажать на плей в открывшемся браузере чтобы игра началась
Последовательность такая:
- train() - для генерации скриншотов
- запуск train.ipynb для обучения модели
- play() - чтобы нейросеть играла в игру
Ноутбук для обучения выглядел так:
train.ipynb
from fastai.vision.all import *
# prepare data
def make_label(x): return (x.split("_"))[0]
dls = ImageDataLoaders.from_name_func('.',
get_image_files("screenshots"), valid_pct=0.2, seed=42,
label_func=make_label,
item_tfms=Resize(192)
)
dls.train.show_batch(max_n=4, nrows=1, unique=True)
# fine tune model
learn = vision_learner(dls, resnet18, metrics=error_rate)
learn.fine_tune(3)
# export model
learn.export('model.pkl')
# see confusion matrix
interp = ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix()
Запустив игру, найлучший результат который получился это чуть больше трех тысяч очков, что довольно плохо.
Какие выводы я вынес
Нейросеть классифицировала текущих ход, однако это не лучший следующий ход. В какой-то момент она поняла что если дудл носом повернут вправо, то это Правая категория, если влево, то Левая. И начал прыгать только вправо или только влево. Следующим шагом можно будет подумать, какую класификацию или метрику придумать чтобы она означала лучший следующий ход. Также нужно придумать как указать сколько раз нажимать влево или право. Одиночное нажатие сдвигает дудла на пару пикселей. По умолчанию я захордкодил 200 нажатий