Скрытые прыжки динозавров в Chrome были легко освоены искусственным интеллектом

искусственный интеллект Нейронные сети Chrome игра
Ся И, Го Ипу, из Concave Temple Quantum Produced | Публичный аккаунт QbitAI

Какие! Не подключен к Интернету! !

Очевидно, что он подключен к Интернету, почему я хочу посетить страницу

никто! Закон! ударил! открыть!

Успокаивать.

Как пользователь Google Chrome, не расстраивайтесь, увидев страницу выше. Если вы подумаете об этом с другой стороны, внутри стены будет больше игрового времени~

Вы заметили маленького динозавра на картинке?

Когда вы сталкиваетесь с веб-страницей, которую невозможно открыть, вам просто нужно снова щелкнуть страницу (мобильный телефон) или нажать пробел (компьютер) и осторожно прыгнуть с маленьким динозавром——

Открылся новый мир.

Этот «прыжок динозавра» на самом деле является пасхальным яйцом, спрятанным в браузере Chrome уже много лет. Маленький динозавр был Tyrannosaurus rex (T-Rex).

В 2013 году Chrome начал заменять надоедливые страницы 404 изображениями этого маленького динозавра. Осенью 2014 года этот динозавр был официально превращен в мини-игру с боковой прокруткой. Спрятано в новом браузере Chrome в виде пасхальных яиц.

Эй, если вы еще не знакомы с этим пасхальным яйцом, попробуйте. Например--

  • Посетите веб-страницу, которую вы не можете прочитать, не перелезая через стену

  • Или введите напрямую: chrome://dino

  • Или посетите: https://chromedino.com/ (нужно перевернуть стену)

Позже эта небольшая игра также стала объектом многих практик ИИ.

Например, кто-то недавно разместил на YouTube видео, показывающее, как он использовал нейронную сеть + генетический алгоритм, чтобы система искусственного интеллекта выделялась в браузерах.

Мы перехватили суть части, которая заключается в следующем видео.

Анимационная версия:

Это достаточно быстро, чтобы летать

Видео версия:

В общем, одним словом, этот ИИ может легко игратьболее 20 000 баллов...

Как далеко вы можете играть? Есть большая вероятность, что вы не сможете отыграть эту партитуру. В конце концов, на странице chromedino.com рекордный результат для игрока-человека составляет18842.

Однако автор, выложивший это видео, не стал подробно раскрывать использованный им метод и, конечно же, не дал адрес в открытом доступе. Но не волнуйтесь, другие публично поделились более подробной информацией.

Например, на GitHub есть открытый исходный код «IAMDinosaur», который также использует нейронную сеть + генетический алгоритм, чтобы заставить динозавров прыгать.

Адрес здесь: https://github.com/ivanseidel/IAMDinosaur

Ложка дегтя в том, что приведенный выше проект не сопровождается слишком подробной интерпретацией. Однако хорошая новость заключается в том, что недавно появился иностранный брат Рави Мунде, который опубликовал очень подробный учебник.

Метод, используемый в этом руководстве, — это Q-обучение в обучении с подкреплением, которое больше подходит для начинающих и не требует мощного оборудования.

Это руководство по работе с кубитами выглядит следующим образом.

Q-обучение понимать/пересматривать

Способность подкреплять обучение является врожденной у животных. Возьмем, к примеру, детей, которые учатся ходить: если ребенок делает первый шаг с трудом, родители его поощряют — это могут быть аплодисменты или конфета, но если ребенок настроен не учиться ходить, то родители не дадут ему конфету. Обучение с подкреплением строится на основе такого мотивационного поведения.

В этой игре для нашего маленького ИИ-динозавра обучение с подкреплением должно позволить ему сначала распознать результаты различных действий без присмотра и получить наивысший стимул для высоких результатов.

Типичный замкнутый цикл обучения с подкреплением

Рави Мунде использовал Q-обучение для имитации специальной функции, которая заставляет ИИ делать правильный выбор в различных ситуациях.

Q-обучение - это безмодельная реализация обучения с подкреплением.По значению Q в каждом состоянии судят о том, какое вознаграждение можно получить, если в это время будет предпринято действие. Пример Q-таблицы дает нам представление о структуре данных. В игре про динозавров паркур состоянием является текущий скриншот игры, а действие, которое можно предпринять, — прыгать или не прыгать [0,1].

Пример Q-таблицы

Рави Мунде решил использовать глубокую нейронную сеть, чтобы определить, когда маленький динозавр взлетел, и ввести различные параметры, чтобы помочь ему на основе простейшей реализации обучения с подкреплением.

Отсутствие помеченных данных делает обучение с подкреплением очень нестабильным. Чтобы получить данные, подходящие для этой игры, брат Мунде решил позволить маленькому динозавру прыгать самостоятельно тысячи раз, записать обратную связь о каждом действии, а затем случайным образом выбрать некоторые из данных для обучения модели.

Но позже Мунде обнаружил, что тренировал упрямую модель — модель твердо верила, что прыгать лучше, чем не прыгать. Поэтому, чтобы позволить модели больше пробовать между прыжками и не прыжками во время обучения, он ввел функцию ɛ для определения случайности действия, а затем постепенно уменьшал ее значение, чтобы уменьшить случайность, и, наконец, отпустил модель. Выберите действие, которое с наибольшей вероятностью будет вознаграждено.

Проблема присвоения кредитов может запутать модель — из какого прошлого поведения исходит нынешнее вознаграждение? В игре паркур с динозаврами маленький динозавр не может снова прыгать после прыжка в воздухе, но модель может отдать команду прыжка, когда динозавр находится в воздухе, что позволяет динозавру очень легко врезаться в землю. кактус.

В этом случае отрицательная обратная связь «удар по кактусу» на самом деле была результатом последнего решения о прыжке, а не результатом прыжка, который динозавр только что совершил, находясь в воздухе.

Перед лицом этой проблемы можно ввести коэффициент дисконтирования (γ), чтобы определить, насколько далеко смотрит модель при совершении действия. γ косвенно решает проблему распределения похвалы.В этой игре, когда γ = 0,99, модель признает, что небрежный прыжок при отсутствии препятствия заставит ее оказаться в воздухе, когда она действительно встретит препятствие и не сможет продолжать прыгать.

Кроме этих двух параметров, в дальнейшем почти не нужны никакие параметры.

#game parameters
GAMMA = 0.99 # decay rate of past observations original 0.99
OBSERVATION = 50000. # timesteps to observe before training
EXPLORE = 100000 # frames over which to anneal epsilon
FINAL_EPSILON = 0.0001 # final value of epsilon
INITIAL_EPSILON = 0.1 # starting value of epsilon
REPLAY_MEMORY = 50000 # number of previous transitions to remember
BATCH = 32 # size of minibatch
FRAME_PER_ACTION = 1скопировать код

Что вам нужно подготовить, так это

  • Python 3.6

  • Selenium

  • OpenCV

  • PIL

  • Chromium driver for Selenium

  • Keras

Небольшое объяснение этих инструментов.

Создание этой модели ИИ требует программирования на Python. И игра написана на JavaScript. Таким образом, вы должны использовать некоторые инструменты, чтобы общаться лучше.

SeleniumЭто популярный инструмент автоматизации браузера, используемый для отправки инструкций по эксплуатации в браузер и получения различных параметров игры.

С интерфейсом покончено, и нам нужно найти способ сделать скриншот игры. Selenium тоже работает, но очень медленно, чтобы сделать снимок экрана и обработать его, требуется около 1 секунды.

Скриншоты и предварительная обработка изображений могут быть лучше выполнены с помощью PIL и OpenCV, а частота кадров может достигать 5 кадров в секунду. Вы можете подумать, что это все еще медленно, но этого достаточно для этой игры.

игровой модуль

Следующий модуль реализует связь между Python и браузером (с использованием Selenium).

'''
* Game class: Selenium interfacing between the python and browser
* __init__(): Launch the broswer window using the attributes in chrome_options
* get_crashed() : return true if the agent as crashed on an obstacles. Gets javascript variable from game decribing the state
* get_playing(): true if game in progress, false is crashed or paused
* restart() : sends a signal to browser-javascript to restart the game
* press_up(): sends a single to press up get to the browser
* get_score(): gets current game score from javascript variables.
* pause(): pause the game
* resume(): resume a paused game if not crashed
* end(): close the browser and end the game
'''
class Game:
  def __init__(self,custom_config=True):
    chrome_options = Options()
    chrome_options.add_argument("disable-infobars")
    self._driver = webdriver.Chrome(executable_path = chrome_driver_path,chrome_options=chrome_options)
    self._driver.set_window_position(x=-10,y=0)
    self._driver.set_window_size(200, 300)
    self._driver.get(os.path.abspath(game_url))
    #modifying game before training
    if custom_config:
      self._driver.execute_script("Runner.config.ACCELERATION=0")
  def get_crashed(self):
    return self._driver.execute_script("return Runner.instance_.crashed")
  def get_playing(self):
    return self._driver.execute_script("return Runner.instance_.playing")
  def restart(self):
    self._driver.execute_script("Runner.instance_.restart()")

    time.sleep(0.25)# no actions are possible 
            # for 0.25 sec after game starts, 
            # skip learning at this time and make the model wait
  def press_up(self):
    self._driver.find_element_by_tag_name("body").send_keys(Keys.ARROW_UP)
  def get_score(self):
    score_array = self._driver.execute_script("return Runner.instance_.distanceMeter.digits")
    score = ''.join(score_array) # the javascript object is of type array with score in the formate[1,0,0] which is 100.
    return int(score)
  def pause(self):
    return self._driver.execute_script("return Runner.instance_.stop()")
  def resume(self):
    return self._driver.execute_script("return Runner.instance_.play()")
  def end(self):
    self._driver.close()скопировать код

Модуль агента динозавров

Этот модуль используется для управления движениями маленького динозавра с помощью игрового модуля.

class DinoAgent:
  def __init__(self,game): #takes game as input for taking actions
    self._game = game; 
    self.jump(); #to start the game, we need to jump once
    time.sleep(.5) # no action can be performed for the first time when game starts
  def is_running(self):
    return self._game.get_playing()
  def is_crashed(self):
    return self._game.get_crashed()
  def jump(self):
    self._game.press_up()
  def duck(self):
    self._game.press_down()скопировать код

модуль состояния игры

Нейронные сети используют этот модуль напрямую для выполнения операций и приобретения новых состояний.

'''
get_state(): accepts an array of actions, 
       performs the action on the agent 
returns : new state, reward and if the game ended.
'''
class Game_sate:
  def __init__(self,agent,game):
    self._agent = agent
    self._game = game
  def get_state(self,actions):
    score = self._game.get_score() 
    reward = 0.1*score/10 # dynamic reward calculation
    is_over = False #game over
    if actions[1] == 1: #else do nothing
      self._agent.jump()
      reward = 0.1*score/11
    image = grab_screen() 

    if self._agent.is_crashed():
      self._game.restart()
      reward = -11/score
      is_over = True
    return image, reward, is_over #return the Experience tupleскопировать код

предварительная обработка

модификация игры

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

С этой целью автор модифицировал исходный код игры, упростил ситуацию, убрал некоторые визуальные элементы (облака, лучшие результаты в истории и т. д.), а скорость бега динозавров оставила неизменной.

исходное изображение

после модификации

Обработка изображения

Исходный скриншот имеет разрешение 1200×300 и содержит три канала. Авторы планируют использовать 4 последовательных скриншота в качестве одного входа в модель размером 1200×300×3×4.

Проблема в том, что у этого парня доступен только процессор i7, поэтому его компьютер не может обрабатывать ввод такого размера и одновременно играть в игры. Поэтому вам придется продолжать использовать библиотеку OpenCV для настройки размера скриншота, кадрирования и т. д. Окончательный размер входного изображения составляет 40 × 20 пикселей, один канал, края выделены с помощью Canny.

def grab_screen(_driver = None):
  #bbox = region of interest on the entire screen
  screen = np.array(ImageGrab.grab(bbox=(40,180,440,400))) 
  image = process_img(screen)#processing image as required
  return image

def process_img(image):
  #game is already in grey scale canvas, canny to get only edges and reduce unwanted objects(clouds)
  # resale image dimensions
  image = cv2.resize(image, (0,0), fx = 0.15, fy = 0.10) 
  #crop out the dino agent from the frame
  image = image[2:38,10:50] #img[y:y+h, x:x+w] 
  image = cv2.Canny(image, threshold1 = 100, threshold2 = 200) #apply the canny edge detection
  return imageскопировать код

Затем сложите 4 графика, чтобы создать один вход, то есть: 40 × 20 × 4. Обратите внимание, что здесь также вырезаны маленькие динозавры, ведь весь процесс обучения требует только знания препятствий и расстояния от края.

Архитектура модели

Теперь, когда входные данные доступны, есть также способ использовать выходные данные модели для игры.Единственная разница заключается в архитектуре модели.

Младший брат решил сгладить 3 сверточных слоя и соединить их в плотный слой из 512 нейронов. Слой пула напрямую отсекается, эта штука очень полезна в задачах классификации изображений, но при игре в Дино нейросети нужно знать только расположение препятствий, а слой пула ни на что не влияет.

Многоуровневая сетевая архитектура

Выход этой модели имеет ту же форму, что и количество возможных операций. Модель предсказывает значение Q различных операций, также называемое будущим вознаграждением со скидкой, а затем мы выбираем операцию с наибольшим значением.

Следующий код вызовет модель, созданную с помощью Keras на бэкэнде TensorFlow:

#model hyper parameters
LEARNING_RATE = 1e-4
img_rows , img_cols = 40,20
img_channels = 4 #We stack 4 frames
ACTIONS = 2
def buildmodel():
  print("Now we build the model")
  model = Sequential()
  model.add(Conv2D(32, (8, 8), strides=(4, 4), padding='same',input_shape=(img_cols,img_rows,img_channels))) #20*40*4
  model.add(Activation('relu'))
  model.add(Conv2D(64, (4, 4), strides=(2, 2), padding='same'))
  model.add(Activation('relu'))
  model.add(Conv2D(64, (3, 3), strides=(1, 1), padding='same'))
  model.add(Activation('relu'))
  model.add(Flatten())
  model.add(Dense(512))
  model.add(Activation('relu'))
  model.add(Dense(ACTIONS))
  adam = Adam(lr=LEARNING_RATE)
  model.compile(loss='mse',optimizer=adam)
  print("We finish building the model")
  return modelскопировать код

начать обучение

Теперь пришло время стать свидетелем чуда~~

То есть использовать кусок кода для обучения модели Задача этого кода:

  • Начните без операции, получите начальное состояние начального состояния (s_t)

  • Наблюдайте за процессом игры, НАБЛЮДЕНИЕ в коде обозначает количество шагов.

  • Прогнозировать эффект от операции

  • Хранить опыт в памяти воспроизведения

  • На этапе обучения случайным образом выберите группу из памяти воспроизведения и используйте ее для обучения модели.

  • Если игра окончена, перезапустите игру

Для получения более подробной информации вы можете увидеть этот код с собственными комментариями:

''' 
Parameters:
* model => Keras Model to be trained
* game_state => Game State module with access to game environment and dino
* observe => flag to indicate wherther the model is to be trained(weight updates), else just play
'''
def trainNetwork(model,game_state):
  # store the previous observations in replay memory
  D = deque() #load from file system
  # get the first state by doing nothing
  do_nothing = np.zeros(ACTIONS)
  do_nothing[0] =1 #0 => do nothing,
           #1=> jump

  x_t, r_0, terminal = game_state.get_state(do_nothing) # get next step after performing the action
  s_t = np.stack((x_t, x_t, x_t, x_t), axis=2).reshape(1,20,40,4) # stack 4 images to create placeholder input reshaped 1*20*40*4 

  OBSERVE = OBSERVATION
  epsilon = INITIAL_EPSILON
  t = 0
  while (True): #endless running

    loss = 0
    Q_sa = 0
    action_index = 0
    r_t = 0 #reward at t
    a_t = np.zeros([ACTIONS]) # action at t

    #choose an action epsilon greedy
    if random.random() <= epsilon: #randomly explore an action
      print("----------Random Action----------")
      action_index = random.randrange(ACTIONS)
      a_t[action_index] = 1
    else: # predict the output
      q = model.predict(s_t)    #input a stack of 4 images, get the prediction
      max_Q = np.argmax(q)     # chosing index with maximum q value
      action_index = max_Q 
      a_t[action_index] = 1    # o=> do nothing, 1=> jump

    #We reduced the epsilon (exploration parameter) gradually
    if epsilon > FINAL_EPSILON and t > OBSERVE:
      epsilon -= (INITIAL_EPSILON - FINAL_EPSILON) / EXPLORE 

    #run the selected action and observed next state and reward
    x_t1, r_t, terminal = game_state.get_state(a_t)
    last_time = time.time()
    x_t1 = x_t1.reshape(1, x_t1.shape[0], x_t1.shape[1], 1) #1x20x40x1
    s_t1 = np.append(x_t1, s_t[:, :, :, :3], axis=3) # append the new image to input stack and remove the first one

    # store the transition in D
    D.append((s_t, action_index, r_t, s_t1, terminal))
    D.popleft() if len(D) > REPLAY_MEMORY

    #only train if done observing; sample a minibatch to train on
    trainBatch(random.sample(D, BATCH)) if t > OBSERVE
    s_t = s_t1 
    t = t + 1
    print("TIMESTEP", t, "/ EPSILON", epsilon, "/ ACTION", action_index, "/ REWARD", r_t,"/ Q_MAX " , np.max(Q_sa), "/ Loss ", loss)скопировать код

Примените эту модель к случайно выбранному пакету из памяти воспроизведения:

def trainBatch(minibatch):
 for i in range(0, len(minibatch)):
        loss = 0
        inputs = np.zeros((BATCH, s_t.shape[1], s_t.shape[2], s_t.shape[3]))  #32, 20, 40, 4
        targets = np.zeros((inputs.shape[0], ACTIONS))             #32, 2
        state_t = minibatch[i][0]  # 4D stack of images
        action_t = minibatch[i][1]  #This is action index
        reward_t = minibatch[i][2]  #reward at state_t due to action_t
        state_t1 = minibatch[i][3]  #next state
        terminal = minibatch[i][4]  #wheather the agent died or survided due the action
        inputs[i:i + 1] = state_t   
        targets[i] = model.predict(state_t) # predicted q values
        Q_sa = model.predict(state_t1)   #predict q values for next step

        if terminal:
          targets[i, action_t] = reward_t # if terminated, only equals reward
        else:
          targets[i, action_t] = reward_t + GAMMA * np.max(Q_sa)

      loss += model.train_on_batch(inputs, targets)скопировать код

основной метод

Вышеупомянутый процесс обучения можно запустить, вызвав следующий метод:

#argument: observe, only plays if true, else trains
def playGame(observe=False):
  game = Game()
  dino = DinoAgent(game)
  game_state = Game_sate(dino,game)
  model = buildmodel()
  trainNetwork(model,game_state)скопировать код

результат

На этой модели мой брат тренировал 2 миллиона кадров в неделю, из которых первый 1 миллион кадров использовался для настройки параметров игры для исправления ошибок, а последний 1 миллион кадров фактически использовался для обучения.

Сейчас лучший результат для этой модели — 265 баллов. Из приведенной ниже диаграммы оценки и изменения потерь видно, что потери модели постепенно становятся стабильными и относительно низкими на последних 1 миллионе кадров, но со временем они будут колебаться.

счет игры

Потеря последних 100 кадров (потеря)

текущие ограничения

Хотя позже эта модель работала довольно хорошо, она все же была намного хуже, чем люди.

Конечно, не забывайте, что этот младший брат относительно беден, у него только процессор i7.

Он считает, что модель обучается недостаточно быстро, а оценка недостаточно высока.Виноваты несколько факторов: во-первых, потому что она использует для обучения процессор, она всегда пропускает кадры, во-вторых, изображение для воспроизведения этого ИИ слишком маленький, всего 40×20, что может привести к потере функций при текущей архитектуре модели и замедлить скорость обучения.

Если вы переключитесь на GPU, может быть...

Ссылки по теме

Улучшится ли использование графического процессора, вы можете попробовать этот код:

https://github.com/ravi72munde/Chrome-Dino-Reinforcement-Learning

Оригинальный адрес:

https://medium.com/acing-ai/how-i-build-an-ai-to-play-dino-run-e37f37bdf153

One More Thing

На самом деле, позволить ИИ управлять маленьким динозавром, по сути, то же самое, что позволить ИИ управлять Flappy Bird. Если вы хотите углубиться в этот вопрос, вот еще два.

Машинное обучение играет в книгу Flappy Bird: шесть «школ» от принципа к коду

Играйте во Flappy Bird с нейронной сетью + генетический алгоритм | Учебное пособие

просто соус~

Заканчивать

регистрация на мероприятие

присоединиться к сообществу

Начали набирать группы сообщества qubit AI 16. Студенты, интересующиеся ИИ, могут добавить небольшого помощника WeChat qbitbot6, чтобы присоединиться к группе;

Кроме того, профессиональная подгруппа кубитов (Автономное вождение, резюме, НЛП, машинное обучениеи т. д.) набирают инженеров и исследователей, которые занимаются смежными областями.

Чтобы присоединиться к группе, добавьте небольшой аккаунт WeChat помощника qbitbot6, и обязательно обратите внимание на ключевые слова соответствующей группы~ После прохождения проверки мы пригласим вас присоединиться к группе. (Профессиональная групповая проверка более строгая, пожалуйста, поймите)

Искренняя вербовка

Qubit набирает редакторов/репортеров для работы в Zhongguancun, Пекин. Надеемся, что к нам присоединятся талантливые и целеустремленные студенты! Чтобы узнать подробности, ответьте на слово «вербовка» в диалоговом интерфейсе QbitAI.

КубитQbitAI · Автор, подписанный Toutiao

վ'ᴗ' ի Отслеживание новых разработок в области технологий и продуктов ИИ