OpenAI Интеграция пользовательской игры в среду тренажерного зала

[Введение] Я новичок в OpenAI, я создал собственную игру, в которую хочу внедрить самообучающийся агент. Я следовал этому руководству, чтобы настроить репозиторий на GitHub, однако я не понимаю, как я мог отформатировать свой код для работы с содержимым gym-foo/gym_foo/envs/foo_env.py

[Вопрос] Может ли кто-нибудь подсказать, как структурировать мой код, чтобы он был совместим с:

class FooEnv(gym.Env):
metadata = {'render.modes': ['human']}

def __init__(self):
  ...
def step(self, action):
  ...
def reset(self):
...
def render(self, mode='human', close=False):
  ...

[Код]

import pygame
import time
import random
from pygame.locals import *

pygame.init()

display_width = 1002
display_height = 720

black = (0,0,0)
white = (255,255,255)
red = (220,0,0)
blue = (53,155,255)
green = (0,190,0)
bright_red = (255,0,0)
bright_green = (0,255,0)
dark_blue = (0,102,204)
yellow = (255, 255, 0)

gameDisplay = pygame.display.set_mode((display_width,display_height)) #creates surface/ display
pygame.display.set_caption('Blob Arena') #name of project
clock = pygame.time.Clock() #sets a clock

#________________________________________________________________________________________

blobImage = pygame.image.load('blob2.png')
blobIcon = pygame.image.load('blob_img.png')
bulletpicture = pygame.image.load("bullet.png")
pygame.display.set_icon(blobIcon)
pause = True
blob_width = 51
blob_height = 51
bullet_width = 12
bullet_height = 5

bullets=[]
bullets2=[]

def blob(x,y):
    gameDisplay.blit(blobImage,(x,y)) #drawing to background

def bullets_hit(count):
    font = pygame.font.SysFont(None, 25)
    text = font.render("Score: "+str(count), True, black)
    gameDisplay.blit(text,(0,20))

def player_lives(count):
    font = pygame.font.SysFont(None, 25)
    text = font.render("Lives Left: "+str(count), True, bright_red)
    gameDisplay.blit(text,(0,0))

def game_intro():
    intro = True
    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        gameDisplay.fill(dark_blue)
        largeText = pygame.font.Font('freesansbold.ttf', 110)
        TextSurf, TextRect = text_objects("Blob Arena", largeText)  # Returns text surface and rectangle
        TextRect.center = ((display_width / 2), (display_height / 2.5))
        gameDisplay.blit(TextSurf, TextRect)
        button("Training 1", 200, 430, 140, 53, green, bright_green, game_loop)
        button("Training 2", 431, 430, 140, 53, green, bright_green, game_loop)
        button("Training 3", 662, 430, 140, 53, green, bright_green, game_loop)
        button("Human vs AI", 315.5, 550, 140, 53, green, bright_green, game_loop)
        button("Quit", 546.5, 550, 140, 53, red, bright_red, quit_game)

        pygame.display.update()
        clock.tick(15)

def button(msg,x,y,w,h,ic,ac,action=None):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed() #collects mouse left, right and middle button
    if x + w > mouse[0] > x and y + h > mouse[1] > y:
        pygame.draw.rect(gameDisplay, ac, (x, y, w, h))
        if click[0] == 1 and action!= None:
            action()
    else:
        pygame.draw.rect(gameDisplay, ic, (x, y, w, h))

    smallText = pygame.font.Font("freesansbold.ttf", 20)
    textSurf, textRect = text_objects(msg, smallText)
    textRect.center = ((x + (w / 2)), (y + (h / 2)))
    gameDisplay.blit(textSurf, textRect)

def unpause():
    global pause
    pause = False

def paused():
    largeText = pygame.font.Font('freesansbold.ttf', 110)
    TextSurf, TextRect = text_objects("Paused", largeText)  # Returns text surface and rectangle
    TextRect.center = ((display_width / 2), (display_height / 2.5))
    gameDisplay.blit(TextSurf, TextRect)

    while pause:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        button("Continue", 315.5, 450, 140, 53, green, bright_green, unpause)
        button("Quit", 546.5, 450, 140, 53, red, bright_red, quit_game)

        pygame.display.update()
        clock.tick(15)

def text_objects(text, font):
    textSurface = font.render(text, True, black)
    return textSurface, textSurface.get_rect()

def quit_game():
    pygame.quit()
    quit()

def game_over():
    largeText = pygame.font.Font('freesansbold.ttf', 110)
    TextSurf, TextRect = text_objects("Game Over", largeText)  # Returns text surface and rectangle
    TextRect.center = ((display_width / 2), (display_height / 2.5))
    gameDisplay.blit(TextSurf, TextRect)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        button("Play Again", 280.5, 450, 140, 53, green, bright_green,game_loop)
        button("Quit", 581.5, 450, 140, 53, red, bright_red,quit_game)

        pygame.display.update()
        clock.tick(15)

def game_loop():
    global pause
    x = (display_width * 0.08)
    y = (display_height * 0.2)

    x_change = 0
    y_change = 0

    blob_speed = 2

    velocity = [2, 2]

    score = 0
    lives = 3

    pos_x = display_width/1.2
    pos_y = display_height/1.2

    previous_time = pygame.time.get_ticks()
    previous_time2 = pygame.time.get_ticks()

    gameExit = False
    while not gameExit:
        for event in pygame.event.get():#monitors hardware movement/ clicks
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        pos_x += velocity[0]
        pos_y += velocity[1]

        if pos_x + blob_width > display_width or pos_x < 601:
            velocity[0] = -velocity[0]

        if pos_y + blob_height > display_height or pos_y < 0:
            velocity[1] = -velocity[1]

        for b in range(len(bullets2)):
            bullets2[b][0] -= 6

        for bullet in bullets2:
            if bullet[0] < 0:
                bullets2.remove(bullet)


        current_time2 = pygame.time.get_ticks()
        #ready to fire when 500 ms have passed.
        if current_time2 - previous_time2 > 500:
            previous_time2 = current_time2
            bullets2.append([pos_x+25, pos_y+24])

# Checks to see if any keys are held down and remembers them with the variable keys.
        keys = pygame.key.get_pressed()

        for b in range(len(bullets)):
            bullets[b][0] += 6

        for bullet in bullets:
            if bullet[0] > 1005:
                bullets.remove(bullet)

        if keys[pygame.K_SPACE]:
            current_time = pygame.time.get_ticks()
            #ready to fire when 500 ms have passed.
            if current_time - previous_time > 500:
                previous_time = current_time
                bullets.append([x+25, y+24])

# If the player is holding down one key or the other the blob moves in that direction
        if x < 0:
            x = 0
        if keys[pygame.K_a]:
            x_change = -blob_speed
        if x > 401 - blob_width:
            x = 401 - blob_width
        if keys[pygame.K_d]:
            x_change = blob_speed
        if keys[pygame.K_p]:
            pause = True
            paused()


# If the player is holding down both or neither of the keys the blob stops
        if keys[pygame.K_a] and keys[pygame.K_d]:
            x_change = 0
        if not keys[pygame.K_a] and not keys[pygame.K_d]:
            x_change = 0

        if y < 0:
            y = 0
        if keys[pygame.K_w]:
            y_change = -blob_speed
        if y > display_height - blob_height:
            y = display_height - blob_height
        if keys[pygame.K_s]:
            y_change = blob_speed


        if keys[pygame.K_w] and keys[pygame.K_s]:
            y_change = 0
        if not keys[pygame.K_w] and not keys[pygame.K_s]:
            y_change = 0


        #print(event)
        # Reset x and y to new position
        x += x_change
        y += y_change

        gameDisplay.fill(blue)  #changes background surface
        bullets_hit(score)
        player_lives(lives)
        pygame.draw.line(gameDisplay, black, (601, display_height), (601, 0), 3)
        pygame.draw.line(gameDisplay, black, (401, display_height), (401, 0), 3)
        blob(pos_x, pos_y)
        blob(x, y)

        for bullet in bullets:
            gameDisplay.blit(bulletpicture, pygame.Rect(bullet[0], bullet[1], 0, 0))
            if bullet[0] > pos_x and bullet[0] < pos_x + blob_width:
                if bullet[1] > pos_y and bullet[1] < pos_y + blob_height or bullet[1] + bullet_height > pos_y and bullet[1] + bullet_height < pos_y + blob_height:
                    bullets.remove(bullet)
                    score+=1

        for bullet in bullets2:
            gameDisplay.blit(bulletpicture, pygame.Rect(bullet[0], bullet[1], 0, 0))
            if bullet[0] + bullet_width < x + blob_width and bullet[0] > x:
                if bullet[1] > y and bullet[1] < y + blob_height or bullet[1] + bullet_height > y and bullet[1] + bullet_height < y + blob_height:
                    bullets2.remove(bullet)
                    lives-=1

        if lives == 0:
            game_over()


        pygame.display.update() #update screen
        clock.tick(120)#moves frame on (fps in parameters)

game_intro()
game_loop()
pygame.quit()
quit()

[Дополнительная информация] Я буду использовать алгоритм обучения с подкреплением из https://github.com/Hvass-Labs/TensorFlow-Tutorials/blob/master/reinforcement_learning.py, который, насколько я понимаю, требует среды тренажерного зала, чтобы гимнастика.make() могла Работа. Любая помощь будет принята с благодарностью, если что-то еще нужно, пожалуйста, сообщите мне.


person Rokas98765    schedule 03.04.2018    source источник


Ответы (1)


У меня нет опыта работы с библиотекой pygame и я не знаю ее внутренней работы, которая может иметь некоторое влияние на то, какой код должен запускаться и где, поэтому я не уверен на 100% во всем этом. Но хорошо бы просто начать с некоторого интуитивного понимания примерного того, что должно происходить, где:

  • __init__() должен выполнять любую разовую настройку. Я могу предположить, что что-то вроде pygame.init() должно быть здесь, но я не уверен на 100%, потому что я не знаком с pygame.
  • step() следует вызывать всякий раз, когда агент выбирает действие, а затем запускать один «кадр» игры, перемещая его вперед, учитывая действие, выбранное агентом. В качестве альтернативы, если у вас есть игра, в которой одно действие занимает несколько кадров, вы должны запустить здесь несколько кадров. По сути: продолжайте движение игры вперед, пока не достигнете точки, когда агент должен снова выбрать новое действие, а затем вернуть текущее состояние игры.
  • reset() следует... ну, сбросить игру. Итак, вернитесь к исходному (или произвольному, как хотите) состоянию игры, запустите любую очистку, которая может потребоваться. Я мог бы, например, также вообразить, что pygame.init() находится здесь. Это зависит от того, что именно делает эта функция. Если его нужно запустить только один раз, он принадлежит __init__(). Если его нужно запускать в начале каждой новой игры/"эпизода", он принадлежит reset().
  • render(), вероятно, должен содержать большую часть кода, связанного с графикой. Вы можете попробовать черпать вдохновение, например, из окружение тележки в тренажерном зале, которое также рисует здесь довольно простую графику. Похоже, он должен рисовать ровно один кадр.

Теперь, глядя на код, с которого вы начинаете, кажется, что в нем содержится значительное количество кода пользовательского интерфейса... все виды кода, связанные с кнопками, паузой/возобновлением паузы, причудливым (анимированным?) вступлением в начале игра. Я не знаю, сможете ли вы позволить себе избавиться от всего этого? Если вы занимаетесь исключительно обучением с подкреплением, вы, вероятно, можете. Если вам все еще нужно взаимодействие с пользователем, вы, вероятно, не можете, и тогда все становится намного сложнее, поскольку все эти вещи не очень хорошо вписываются в структуру gym.

Я могу попытаться сделать несколько обоснованных предположений о нескольких оставшихся частях кода и о том, куда он должен идти, но вы все равно должны тщательно все проверить, основываясь на более общих рекомендациях, приведенных выше:

def reset(self):
    # all the following code seems to define the initial game state
    x = (display_width * 0.08)
    y = (display_height * 0.2)

    x_change = 0
    y_change = 0

    blob_speed = 2

    velocity = [2, 2]

    score = 0
    lives = 3

    pos_x = display_width/1.2
    pos_y = display_height/1.2

    bullets=[]
    bullets2=[]

step(), вероятно, должен содержать большую часть кода в этом цикле while в game_loop(). Однако код проверки ввода с клавиатуры должен быть изменен, вместо этого он должен начать использовать action, переданный в step(). Наконец, ожидается, что step() вернет кортеж, содержащий:

  • следующее игровое состояние, то, что агент может использовать, чтобы решить, каким будет следующее действие. Это могут быть необработанные пиксели, если хотите, или что-то, чему легче научиться (например, набор функций, сообщающих вам, где что находится).
  • Награда, некоторое указание на то, насколько хорошими были ваши агентские действия.
  • True, если игра окончена, False в противном случае.
  • Некоторый словарь с любой дополнительной информацией, которая вам нравится, для целей отладки. Может быть просто пустой dict {}.
person Dennis Soemers    schedule 05.04.2018
comment
Ух ты! Спасибо за подробное объяснение, стало намного легче понять. Как я могу проверить, делаю ли я какие-либо ошибки при написании? Например, будет ли запуск модуля после того, как я создам метод step(), дать мне указание на то, что я сделал неправильно внутри метода step(), или нужно ли настроить всю среду, чтобы начать проверку на наличие ошибок? - person Rokas98765; 05.04.2018
comment
@ Rokas98765 Хм, это сложно. Никто, кроме вас, не будет знать, будет ли код «правильным» после написания, уж точно внутри самого gym нет ничего, что могло бы проверить. Пользовательская среда именно такова: пользовательская, она может быть практически всем, что вы хотите. Самое главное — получить интуитивное представление о том, что должны делать различные функции. Затем вы можете попробовать поставить print() здесь и там, посмотреть, произойдет ли то, что вы ожидаете. Если вы можете запустить визуализацию, это, очевидно, тоже поможет, тогда вы можете посмотреть на экран, чтобы увидеть, что происходит. - person Dennis Soemers; 05.04.2018
comment
Большое спасибо за ваше время, была огромная помощь. - person Rokas98765; 06.04.2018
comment
@ Rokas98765 Поскольку ответ оказался полезным, пожалуйста, примите его - ответы отнимают у респондентов ценное время, особенно такие ответы... - person desertnaut; 07.04.2018
comment
@desertnaut, плохо, спасибо за напоминание. - person Rokas98765; 07.04.2018
comment
Извините за повторный вопрос, я хотел уточнить, для чего нужны метаданные? Во многих примерах, которые я рассматриваю, есть метаданные = {'render.modes': []}, и внутри добавлены такие вещи, как «human» или «rgb_array». Я пытался найти его, но не нашел объяснения. - person Rokas98765; 07.04.2018
comment
@ Rokas98765 какие метаданные? Вы имеете в виду последнее возвращаемое значение step()? Не гарантируется, что он будет содержать что-либо во всех средах, поэтому вы можете просто вернуть пустой словарь. Некоторые среды помещают туда полезную отладочную информацию, но нет гарантии, что все среды будут. Вы увидите, что большинство алгоритмов RL просто вообще не используют возвращаемое значение (например, код RL, на который вы ссылаетесь, сохраняет его в переменной info в эту строку, но вообще ее не использует. - person Dennis Soemers; 07.04.2018
comment
Я должен был включить пример, когда при создании класса первым делом настраиваются метаданные, например здесь или в другом вопросе stackoverflow с вопросом, как Создавайте новые среды. Таким образом, {} в возврате step() обращается к этим метаданным? - person Rokas98765; 08.04.2018
comment
В примерах, которые я рассматривал, «человек» берется в качестве аргумента в def _render(self, mode='human', close=False), а «rgb_array» возвращается этим методом. Хотя не уверен, какая от этого польза. - person Rokas98765; 08.04.2018
comment
@ Rokas98765 Ах, эти метаданные. Кажется, здесь есть немного документации по этому вопросу: github .com/openai/тренажерный зал/blob/ - person Dennis Soemers; 08.04.2018
comment
Не могу поверить, что я пропустил это, просматривая это, спасибо! - person Rokas98765; 08.04.2018