Автоматизация Doom с глубоким Q-обучением: реализация в Tensorflow. |
||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2020-07-21 15:00 машинное обучение python, реализация искусственного интеллекта Введение Методы онлайнового обучения машин (ОО) — это семейство динамических алгоритмов обучения с подкреплением, которое стоит за кулисами многих достижений во всей области ИИ за последние десять лет. Методы ОО относятся к классу обучения на сэмплах из раздела методов с подкреплением. Они позволяют определять значения состояния благодаря простым повторяющимся наблюдениям. Подходы ОО (в отличие от своих “офлайновых” братьев) позволяют по нарастающей обновлять значения состояний и поведения внутри, так называемых, пространственных эпизодов. Еще с ними удобно наблюдать за растущим постоянно уровнем производительности. Эволюция в УВР (учёт временной разницы) привела к возрастающим оценкам и улучшению значений состояний и поведения. О Q-обучении узнали как о базе для подходов сферы обучения с подкреплением. Оно было нужно для симуляций игровых пространств, например, на таких платформах-“спортзалах”, как OpenAI Gym. Но в этой статье не будет обсуждения теоретических аспектов. Способы ОО подходят высокодинамичным окружениям, где значения состояний и поведения постоянно обновляются во времени и в наборах оценок из-за быстрой ответной реакции внутри эпизодов (в том числе УВР). Возможно, самое важное то, что УВР — это основа Q-обучения, более продвинутого алгоритма для тренировки агентов, который имеет дело с игровыми окружениями, которые можно увидеть в OpenAI Atari Gym. В этом материале изучим, как можно использовать Q-обучение для агента, который играет в классический шутер от первого лица вроде Doom. Будем делать это с помощью открытой библиотеки-враппера Vizdoomgym. Мы настроим вашего первого агента, а также заложим базу для дальнейшней работы. Эволюция классики, которая всегда вне времени. Ну а мы сосредоточимся на версии 1993-го года, с выпуска которой прошло почти 30 лет. Выходя за пределы УВР: SARSA и Q-обучение В УВР поведение агента циклично в пространстве в последовательности состояний (State), действий (Action) и наград (Reward). В процессе УВР мы можем обновить значение предыдущего состояния сразу же, как только достигаем следующей стадии. Дальше мы расширяем объем своей модели, чтобы в нее входили значения состояния-действия, согласно подходу SARSA (“состояние-действие-награда-состояние-действие”), регламентированному алгоритму управления УВР, который нужен для оценки значений поведения. В процессе SARSA мы непрерывно оцениваем значения действий при инкрементальных временных шагах согласно текущей политике. Эта информация нужна, чтобы изменить правила по отношению к жадному алгоритму со значениями действий. Давайте сравним уравнения обновлений состояния-действия и состояния-значения УВР: Q-обучение отличается от SARSA принудительным выбором действия с текущим максимальным значением в процессе обновления. Так же происходит и в похожем подходе, который наблюдается в уравнениях оптимальности Беллмана. Изучим алгоритм SANSA и Q-обучение на фоне метода Беллмана и его уравнений оптимальности: Любопытно, как обеспечивается полное исследование пространства состояний-действий, из-за чего нужно постоянно выбирать действия (с максимальным из существующих значений действий) для состояния. Теоретически мы можем игнорировать оптимальные действия, просто не проводя их оценку в первую очередь. Чтобы продолжить обучение, мы можем следовать политике эпсилон-жадного затухающего алгоритма. Они по сути принуждают агента выбирать очевидное неоптимальное действие по вероятности затухания, чтобы лучше изучить его значение. С затухающим значением мы можем ограничить изучение, когда оценим все состояния. А после этого мы постоянно будем выбирать оптимальные действия для каждого состояния. Теория закончилась, переходим к реализации. Реализация Наша реализация в Colaboratory от Google написана на Python с помощью Tensorflow. Ее можно найти на GradientCrescent Github. Реализация с таким подходом достаточно непростая, поэтому давайте обобщим порядок необходимых действий:
2. Так как для Q-обучения мы должны знать и текущие, и следующие состояния, нам стоит начать с генерации данных. Мы “скармливаем” предварительно обработанные входные изображения игровому пространству, предоставляем исходные состояния s нашей нейронной сети и получаем исходную вероятность распределения действий или Q-значений. До тренировки эти значения будут появляться случайно и неоптимально. 3. С тензором вероятностей мы готовы выбрать действие с текущей высшей вероятностью при помощи функции argmax() и использовать ее для создания правил эпсилон-жадного алгоритма. 4. Используя наши правила мы выбираем действие a, и оцениваем наше решение в окружении gym — чтобы получить информацию по новому состоянию s' , награде r и информацию о том, закончился ли эпизод. 5. Мы сохраняем это сочетание информации в буфер в формате списка <s,a,r,s’,d> и повторяем шаги 2–4 для пресета с числами в промежутке времени, чтобы создать достаточно большой буферный датасет. 6. Как будет закончен 5-й шаг, двигаемся к генерации целевых y-значений, R' и A’. Они нужны для расчета ошибки. Предыдущее — это просто уменьшенное значение R. А мы получаем A`, передавая S` в сеть. 7. У нас есть все компоненты пространства и мы готовы рассчитать ошибку для тренировки сети. 8. По окончании тренировки мы оцениваем производительность нашего агента в новом игровом эпизоде и записываем её. Приступим-с. Вместе с Tensorflow 2 и окружениями из Colaboratory мы конвертировали код в совместимый с TF2 формат. Нам помог новый пакет compat. Помните, что этот код не является нативным для TF2. Импортируем все пакеты, без которых не обойтись, в том числе окружения OpenAI и Vizdoomgym, а также Tensorflow: import gym Определяем функцию предварительной обработки для нормализации и изменения наблюдений из нашего окружения gym, конвертируем их в одномерные тензоры: from skimage.color import rgb2gray #предварительно обработаем uint8-фрейм (240, 320, 3) в плавающий одномерный вектор 30x40 img_gray = rgb2gray(img) Инициализируем окружение gym. Будем пользоваться сценарием получения здоровья Vizdoomgym. Его цель — собрать максимально возможное количество коробок здоровья, чтобы остаться в живых, пока он перемещается в квадратной комнате с опасной кислотой на полу. env = gym.make(‘VizdoomHealthGathering-v0’) observation = env.reset() import tensorflow as tf for i in range(22): observation, _, _, _ = env.step(1) Мы можем изучить скрин геймплея и просмотреть три доступных действия внутри игрового пространства, а именно: поворот налево, направо и движение вперёд. Конечно, эта информация недоступна нашему агенту. Воспользуемся этим шансом для сравнения нашего оригинала и предварительно обработанных вводных изображений: Теперь нам понадобится компоновка исходного фрейма в стек и композиция фрейма в конвейер предварительной обработки. Эти две техники появились в 2015 году благодаря Deepmind. Они нужны, чтобы давать временные и поведенческие ориентиры для вводных данных. Применяем компоновку фрейма так: берём два исходных фрейма и возвращаем сумму поэлементных максимумов maxframe от них двух. Затем эти скомпонованные фреймы сохраняются в двухсторонней очереди или стеке, который автоматически убирает устаревшие записи с появлением новых. stack_size = 4 # Всего в стеке 4 скомпонованных фрейма stacked_frames = deque([np.zeros((60,80), dtype=np.int) for i in range(stack_size)], maxlen=4) def stack_frames(stacked_frames, state, is_new_episode): # Создаем состояние стека (первое измерение определяет разные фреймы) Давайте определим нашу модель глубокой Q-нейросети. По сути это трёхслойная свёрточная нейросеть, которая получает на вход предварительно обработанные наблюдения вместе со сгенерированным плоским выводом, скормленным полносвязному слою, а в результате генерирует вероятность каждого действия в игровом пространстве. Заметьте, что здесь нет слоев активации, иначе на выходе бы было бы бинарное распределение. tf.compat.v1.reset_default_graph() def q_network(X, name_scope): with tf.compat.v1.variable_scope(name_scope) as scope: # Инициализация сверточного слоя # Переменные будут хранить параметры сети, например, веса Теперь давайте определим гиперпараметры нашей модели и тренировочного процесса. Обратите внимание, что X_shape (None, 60, 80, 4) сейчас находится в расчете нашего стека с фреймами. num_episodes = 1000 input_shape = (None, 60, 80, 1) learning_rate = 0.002 global_step = 0 Вспомните, что Q-обучение требует, чтобы мы выбирали действия с самыми высокими значениями. Чтобы убедиться в том, что мы всё ещё смотрим каждую отдельную возможную комбинацию состояний-действий, мы сделаем так, чтобы наш агент следовал многослойным правилам эпсилон-жадной стратегии с долей обучения в 5%. epsilon = 0.5 def epsilon_greedy(action, step): Вспоминаем из уравнений выше, что обновление функции для Q-обучения требуют следующего:
Чтобы поддерживать эти параметры на значимом уровне, нам нужно оценить свои текущие правила для набора параметров и сохранить все переменные в буфер. А уже оттуда во время тренировки мы будем визуализировать данные небольшими партиями. Давайте теперь создадим буфер с простой функцией сэмплирования: buffer_len = 20000 def sample_memories(batch_size): Дальше копируем параметры веса нашей исходной сети в итоговую сеть. Подход с двумя сетями позволяет генерировать данные во время тренировки при помощи существующих правил в процессе, в то время как параметры оптимизируются для итерации с новыми правилами, уменьшая колебания ошибки. # строим сеть Q, которая принимает на входе X и генерирует Q-значения для всех действий внутри состояния # чтобы оценить правила, мы создаём итоговую сеть Q похожим образом copy_op = [tf.compat.v1.assign(main_name, targetQ[var_name]) for var_name, main_name in mainQ.items()] В конце мы также определим ошибку. Это всего-навсего квадратная разница целевого (с наивысшим значением действия) и предсказанного действий. Мы будем использовать оптимизатор ADAM (адаптивная оценка момента), чтобы минимизировать ошибку в процессе тренировки: # определяем плейсхолдер для нашего вывода, например, действия # вычисляем значение ошибки - разницу между текущим и предсказанным значениями # для оптимизации ошибки пользуемся оптимизатором adam optimizer init = tf.compat.v1.global_variables_initializer() Давайте же запустим нашу нейросеть и пройдем тренировку. Мы определили большую часть его в первоначальных итогах, но давайте вспомним для потомков.
with tf.compat.v1.Session() as sess: # пока состояние не переходное #После определенных шагов тренируем нашу сеть Q с примерами из буфера повтора опыта # собираем все итоги и записываем их в файл # после некоторого интервала мы копируем веса нашей главной сети Q в итоговую Q-сеть obs = next_obs Когда обучение завершается, мы можем вывести распределение наград и инкрементальные эпизоды. Ниже показываю первую тысячу эпизодов: Результат принимается с видимыми зачатками улучшения, данными в таком виде, который предлагает оригинальная документация Vizdoom. Для более значительного улучшения понадобятся сотни тысяч эпизодов. img_array=[] # передаем экран игры и получаем значения Q для каждого действия # получаем действие # выбираем действие согласно эпсилон-жадному правилу Наконец, мы можем взять наш список фреймов и “скормить” их библиотеке from random import choice import numpy as np out_video = np.empty([len(img_array), 240, 320, 3], dtype = np.uint8) for i in range(len(img_array)): Посмотрим на нашего агента в действии! Обратите внимание, как агент приостанавливается, когда замечает ящик здоровья прямо перед тем, как начинает двигаться к нему. Ну и просто веселья ради мы натренировали агента по базовому сценарию, где цель — поразить монстра как можно скорее. Лучшее время пока что: около 1,3 секунды, показываем его ниже на одном из более ранних эпизодов. Такая вот упаковка имплементации Q-обучения. Надеюсь, вам понравилось читать и вы захотите погрузиться в теоретические аспекты применения ИИ. Читайте также:
Источник: m.vk.com Комментарии: |
|