Предыдущая статья — Играем в GTA V c Python. Часть XI: Обучение нейронной сети для автопилота.
Добро пожаловать в двенадцатую часть серии статей про применение методов машинного обучения в игре Grand Theft Auto V. Мы продолжаем создавать наш беспилотный автомобиль в этой игре.
В предыдущей статье мы обучили нашу нейронную сеть на игровых данных и теперь мы готовы посмотреть, что из этого вышло. В процессе обучения нейронной сети мы сохраняли результаты в отдельном файле. Это позволит нам в любой момент вернуться к уже обученной модели и даже дообучить ее, если потребуется.
Чтобы загрузить эти данные из файла, нам нужно иметь уже заданную модель TensorFlow. Дело в том, что этот записанный файл содержит только сохраненные веса, соответствующие нашей модели нейронной сети, и ничего более. Поэтому, чтобы это все работало, модель нашей нейронной сети должна быть определена заранее.
Мы уже сохраняли эту модель в отдельный файл, но на всякий случай напомним еще раз:
# alexnet.py import tflearn from tflearn.layers.conv import conv_2d, max_pool_2d from tflearn.layers.core import input_data, dropout, fully_connected from tflearn.layers.estimator import regression from tflearn.layers.normalization import local_response_normalization def alexnet(width, height, lr): network = input_data(shape=[None, width, height, 1], name='input') network = conv_2d(network, 96, 11, strides=4, activation='relu') network = max_pool_2d(network, 3, strides=2) network = local_response_normalization(network) network = conv_2d(network, 256, 5, activation='relu') network = max_pool_2d(network, 3, strides=2) network = local_response_normalization(network) network = conv_2d(network, 384, 3, activation='relu') network = conv_2d(network, 384, 3, activation='relu') network = conv_2d(network, 256, 3, activation='relu') network = max_pool_2d(network, 3, strides=2) network = local_response_normalization(network) network = fully_connected(network, 4096, activation='tanh') network = dropout(network, 0.5) network = fully_connected(network, 4096, activation='tanh') network = dropout(network, 0.5) network = fully_connected(network, 3, activation='softmax') network = regression(network, optimizer='momentum', loss='categorical_crossentropy', learning_rate=lr, name='targets') model = tflearn.DNN(network, checkpoint_path='model_alexnet', max_checkpoints=1, tensorboard_verbose=2, tensorboard_dir='log') return model
Далее давайте создадим новый файл под названием test_model.py:
# test_model.py import numpy as np from PIL import ImageGrab import cv2 import time from directkeys import PressKey,ReleaseKey, W, A, S, D from alexnet import alexnet WIDTH = 80 HEIGHT = 60 LR = 1e-3 EPOCHS = 8 MODEL_NAME = 'pygta5-car-{}-{}-{}-epochs.model'.format(LR, 'alexnetv2',EPOCHS)
Затем наша модель будет выводить [1,0,0]
, [0,1,0]
или [0,0,1]
. Эти выходные данные соответствуют левому повороту, движению вперед или правому повороту, поэтому мы хотим, чтобы эти исходы были сопоставлены с некоторыми фактическими действиями, вот они:
def straight(): PressKey(W) ReleaseKey(A) ReleaseKey(D) def left(): PressKey(W) PressKey(A) ReleaseKey(D) def right(): PressKey(W) PressKey(D) ReleaseKey(A)
Эти сопоставления — только начало. Обратите внимание, что на самом деле мы всегда нажимаем «W
», что означает нажатие на газ. Возможно, со временем нам потребуется настроить это по-другому, но на данный момент это так.
Теперь определим модель и загрузим наши обученные веса:
model = alexnet(WIDTH, HEIGHT, LR) model.load(MODEL_NAME)
Теперь мы начинаем цикл движения, который очень похож на нашу предыдущую поездку с беспилотным автомобилем. Отличие состоит в том, что мы принимаем решения, исходящие от нашей модели, через метод model.predict
:
def main(): last_time = time.time() for i in list(range(4))[::-1]: print(i+1) time.sleep(1) while(True): # 800x600 windowed mode screen = np.array(ImageGrab.grab(bbox=(0,40,800,640))) print('loop took {} seconds'.format(time.time()-last_time)) last_time = time.time() screen = cv2.cvtColor(screen, cv2.COLOR_BGR2GRAY) screen = cv2.resize(screen, (80,60)) cv2.imshow('',screen) moves = list(np.around(model.predict([screen.reshape(80,60,1)])[0])) print(moves) if moves == [1,0,0]: left() elif moves == [0,1,0]: straight() elif moves == [0,0,1]: right() if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break
Мы обнаружили, что в отличие от предыдущего сценария автономного вождения, этот, вероятно, следует сразу запускать на полной скорости. Вы должны запустить его, сразу же перейти к игре и начать действовать как можно быстрее.
В реальности, на скорости наша модель ведет себя весьма неплохо. Что довольно впечатляюще, так как после балансировки наш набор обучающих данных сократился до 20,000
фреймов.
Есть одна вещь, которая может всех раздражать — это запуск / остановка нашего AI в процессе тестирования. Сразу понятно, что эта штука требует доработки, посколько мы хотим иметь возможность быстро остановить автопилот и перейти к самостоятельному вождению. Поэтому давайте внесем небольшие изменения в наш файл test_model.py:
from getkeys import key_check
Теперь у нас есть возможность использовать определенную кнопку клавиатуры для приостановки работы автопилота. Далее давайте слегка изменим основную функцию программы:
def main(): last_time = time.time() for i in list(range(4))[::-1]: print(i+1) time.sleep(1) paused = False while(True): if not paused: # 800x600 windowed mode screen = np.array(ImageGrab.grab(bbox=(0,40,800,640))) print('loop took {} seconds'.format(time.time()-last_time)) last_time = time.time() screen = cv2.cvtColor(screen, cv2.COLOR_BGR2GRAY) screen = cv2.resize(screen, (80,60)) moves = list(np.around(model.predict([screen.reshape(80,60,1)])[0])) if moves == [1,0,0]: left() elif moves == [0,1,0]: straight() elif moves == [0,0,1]: right() keys = key_check() # p pauses game and can get annoying. if 'T' in keys: if paused: paused = False time.sleep(1) else: paused = True ReleaseKey(A) ReleaseKey(W) ReleaseKey(D) time.sleep(1)
Для остановки автопилота мы произвольно выбрали клавишу ‘T
‘. Мы могли бы взять и ‘P
‘, но тогда на паузу ставилась бы вся игра, чего нам бы не хотелось. Мы хотим остановить AI, сбросить все данные и начать все сначала без остановки самой игры. Поэтому пусть будет ‘T
‘. Мы не очень этим заморачиваемся, но иногда действительно нужно поставить все на паузу и затем начать сначала. Для продолжения достаточно просто нажать эту клавишу еще раз.
Как бы то ни было, наш искусственный интеллект конечно не самый лучший, но вполне справляется с управлением даже на затемненных дорогах с отчетливо видимой разметкой. Для начала неплохо: видно, что мы на правильном пути.
Следующая статья — Играем в GTA V c Python. Часть XIII: улучшаем наш автопилот.