СЕРИЯ НЕПРЕРЫВНОГО ОБУЧЕНИЯ

Как мы попали в 1% лучших виртуальных трасс AWS DeepRacer

Часть 2/2 - Состав высокопроизводительной модели

В предыдущем блоге мы впервые описали нашу мотивацию к участию в конкурсе AWS DeepRacer Virtual Circuit. Затем мы обрисовали в общих чертах три основных способа, с помощью которых можно обучать модели обучения с подкреплением (RL). Наконец, мы представили пошаговое руководство о том, как можно использовать настройку DeepRacer For Cloud (DRFC) для обучения этих моделей.

Несмотря на эти детали, в предыдущем блоге мы упустили одну важную часть головоломки. Хотя мы описали, как можно использовать настройку DRFC для обучения модели RL для DeepRacer, мы не рассказали, как можно обучить высокопроизводительную модель RL. В этом блоге мы подробно рассмотрим эту концепцию.

Начнем с того, что обучение высокопроизводительной модели RL представляет собой итеративный многоэтапный процесс. Все начинается с выбора подходящего пространства действий. За этим следует разработка и итеративное уточнение подходящей функции вознаграждения. Наконец, необходимо определить правильный набор гиперпараметров для алгоритма обучения.

Этот блог дополняет картину, собирая воедино все эти недостающие части. Мы представляем все шаги, которые мы предприняли для получения первого процентиля в рейтинге соревнований на время в августе 2020 года.

Вначале мы хотели бы заявить, что методы, описанные в этом блоге, помогли нам достичь вышеуказанного результата в августе 2020 года. Поскольку конкурс AWS DeepRacer привлекает все больше людей, которые, в свою очередь, принимают аналогичный набор методов, может стать все труднее попасть в верхний 1 процентиль, полагаясь исключительно на них. Следовательно, мы рекомендуем рассматривать этот блог как набор руководящих принципов, а не как набор инструкций для попадания в первую процентиль AWS DeepRacer.

Технические навыки проверены DeepRacer

Прежде чем мы углубимся в методы решения, давайте сначала внимательно рассмотрим определение проблемы и метод ранжирования. AWS DeepRacer, по сути, проверяет навыки формирования вознаграждения.

Задача состоит в том, чтобы обучить автомобиль, который может научиться проехать 3 круга по моделируемой гоночной трассе за самое быстрое возможное время. На каждом временном шаге автомобиль получает набор 2D-изображений от своей передней камеры и должен выбирать из набора дискретных действий. Алгоритм обучения - PPO (Proximal Policy Optimization - по сути, метод градиента политики со стабильными обновлениями политики). Этот алгоритм реализован для всех участников, поэтому они не имеют прямого контроля над действием, выбранным автомобилем на определенном временном шаге.

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

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

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

Характеристики высокопроизводительной модели

Первый шаг к созданию высокопроизводительной модели - понять, как она должна работать после обучения. Чтобы упростить эту задачу, AWS DeepRacer позволяет нам просматривать видеоролики гонок с лучшими моделями, представленными каждым участником, в интерактивной таблице лидеров. В любой момент соревнования, если мы изучим видео 10 лучших моделей, мы, вероятно, увидим следующие общие черты:

  1. Излишне говорить, что автомобили, оснащенные всеми моделями из Топ-10, быстры. Это хорошо видно на прямых участках трассы. Более того, эти автомобили способны выполнять крутые повороты на высоких скоростях.
  2. Кажется, что все машины следуют какой-то неизвестной гоночной линии. Более того, похоже, что каждая из этих машин пытается следовать той же линии гонок. Отличительной чертой 10 лучших представленных работ является их способность точно следовать за этой неизвестной линией гонки.
  3. И, наконец, количество раз, когда каждая из этих машин выходит за пределы трассы за три круга, очень мало. Обычно это не так.

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

Руководство по обучению высокопроизводительной модели

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

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

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

  1. Определение области действия.
  2. Указание функции вознаграждения.
  3. Задание набора гиперпараметров для алгоритма обучения PPO.

В контексте настройки DRFC это включает обеспечение того, чтобы три файла - model_metadata.json (для спецификации пространства действий), reward_function.py (для спецификации функции вознаграждения) и hyperparameters.json (для спецификации гиперпараметров PPO) - присутствовали внутри deepracer-for-cloud/custom_files directory.

Шаг 1. Определение набора действий

Чтобы полностью указать пространство действий модели, необходимо указать следующие три вещи

  1. Глубина сети политик
  2. Список датчиков
  3. Список действий

Чтобы указать глубину политики сети, в model_metadata.json one необходимо установить для параметра “neural_network”: значение “DEEP_CONVOLUTIONAL_NETWORK_SHALLOW" или “DEEP_CONVOLUTIONAL_NETWORK_DEEP”. Первый относится к использованию 3-уровневой CNN в качестве сети политики, а второй относится к использованию вместо этого 5-уровневой CNN. Если у кого-то нет очень веских причин не делать этого, участникам настоятельно рекомендуется выбрать первый вариант. Трёхслойная CNN обучается намного быстрее, чем 5-слойная CNN. В контексте события AWS DeepRacer Time Trial политики, представленные трехуровневой CNN, неоднократно получали высокие места в таблице лидеров. Наши собственные эксперименты также подтверждают эту мудрость сообщества.

Точно так же выбор списка датчиков также прост. Для события Гонка на время настоятельно рекомендуется, чтобы участник выбрал “FRONT_FACING_CAMERA” в качестве единственного “sensor”. Если в процессе обучения вы заметите, что модель не работает должным образом, то очень маловероятно, что производительность улучшится за счет простого увеличения количества слоев CNN или добавления дополнительных датчиков. Мы настоятельно рекомендуем участникам сэкономить много времени на обучение и вычислительные затраты, выбрав эти параметры по умолчанию.

Напротив, выбор списка действий не является однозначным; это требует внимательного рассмотрения. В AWS DeepRacer каждое действие представляет собой кортеж(speed, turning angle). При скорости от 0 до 5 м / с угол поворота может составлять от +90 до -90 градусов. Положительный угол поворота указывает на левый поворот, а отрицательный угол поворота - на правый. Поскольку можно вводить любое число с плавающей запятой в соответствующих диапазонах как для скорости, так и для угла поворота, существует бесконечный набор возможностей для выбора набора действий.

Однако выбор правильного набора действий имеет решающее значение для производительности модели. Во-первых, общее количество действий в области действий напрямую влияет на количество времени, необходимое для схождения политики. Большой набор из 20 действий обеспечит автомобилю точный контроль над скоростью и углом поворота. Это позволяет ему своевременно вносить незначительные корректировки, которые имеют решающее значение для того, чтобы он оставался на гоночной трассе. Однако последующая политика может потребовать от 3 до 5 тысяч итераций обучения, чтобы сойтись. Это можно легко перевести примерно на неделю тренировок. С другой стороны, небольшая модель с 5–8 действиями может сойтись за день. Однако политика, к которой он сходится, может не работать так же хорошо, как «более широкая» модель с большим количеством действий.

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

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

Мы обнаружили, что следы с резкими изгибами шпильки можно было пройти с самой низкой скоростью около 1,25 м / с. Для трека Альберта (т.е. виртуального трека августа 2020 года) эта скорость составила 2 м / с. Для большинства гусениц максимальный угол поворота 30 градусов оказался достаточным. На треке Альберта мы добавили дополнительное действие с углом поворота 45 градусов, чтобы автомобиль мог делать более крутые правые повороты. Устанавливаем максимальную скорость модели 4 м / с. Мы обнаружили, что эта скорость достаточно высока, чтобы позволить машине двигаться быстро, не теряя управления. Затем мы разделили скорость и интервалы поворота, чтобы получить следующие model_metadata.json

{
"action_space": [
  { "steering_angle": -45, "speed": 2.00},
  { "steering_angle": -30, "speed": 2.00},
  { "steering_angle": -20, "speed": 2.50},
  { "steering_angle": -10, "speed": 3.30},
  { "steering_angle": -10, "speed": 3.70},
  { "steering_angle": 0,   "speed": 4.0},
  { "steering_angle": 0,   "speed": 3.70},
  { "steering_angle": 0,   "speed": 3.30},
  { "steering_angle": 0,   "speed": 3.00},
  { "steering_angle": 0,   "speed": 2.75},
  { "steering_angle": 0,   "speed": 2.50},
  { "steering_angle": 0,   "speed": 2.25},
  { "steering_angle": 0,   "speed": 2.00},
  { "steering_angle": 10,  "speed": 3.70},
  { "steering_angle": 10,  "speed": 3.30},
  { "steering_angle": 20,  "speed": 2.50},
  { "steering_angle": 30,  "speed": 2.00}],
"sensor": ["FRONT_FACING_CAMERA"],
"neural_network": "DEEP_CONVOLUTIONAL_NETWORK_SHALLOW"
}

Следует признать, что после установки максимальной скорости поворота и угла поворота дальнейшее разделение пространства действия руководствовалось интуицией, а не каким-либо теоретически обоснованным принципом. Наша цель состояла в том, чтобы добиться как можно большего числа движений по прямой (т.е. угол поворота 0). Это позволит агенту точно контролировать скорость автомобиля без изменения направления.

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

Шаг 2. Укажите функцию вознаграждения

После определения области действия следующим шагом будет определение функции вознаграждения в reward_function.py.. В этом разделе мы представляем ингредиенты нашей функции вознаграждения. Вначале мы хотели бы предупредить читателей, что процесс написания функции вознаграждения очень итеративен. В нашем случае нам пришлось изменить функцию вознаграждения, которую мы сначала написали 8 раз. После 5к тренировочных итераций мы поняли, что это не сработает. Пришлось тогда начинать с нуля. И только после дополнительных 6 доработок в течение 4 тыс. Итераций обучения мы смогли прийти к модели, которая вывела нас в топ-10.

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

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

Мы вернемся к этому вопросу в следующем разделе. А пока давайте исследуем составляющие нашей функции вознаграждения.

Ингредиент 1. Способность запоминать прошлое состояние.

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

class PARAMS:
    prev_speed = None
    prev_steering_angle = None 
    prev_steps = None
    prev_direction_diff = None
    prev_normalized_distance_from_route = None
def reward_function(params):
    
    # Read input parameters
    heading = params['heading']
    distance_from_center = params['distance_from_center']
    steps = params['steps']
    steering_angle = params['steering_angle']
    speed = params['speed']
# Reinitialize previous parameters if it is a new episode
    if PARAMS.prev_steps is None or steps < PARAMS.prev_steps:
        PARAMS.prev_speed = None
        PARAMS.prev_steering_angle = None
        PARAMS.prev_direction_diff = None
        PARAMS.prev_normalized_distance_from_route = None
    #Check if the speed has dropped
    has_speed_dropped = False
    if PARAMS.prev_speed is not None:
        if PARAMS.prev_speed > speed:
            has_speed_dropped = True
    #Penalize slowing down without good reason on straight portions
    if has_speed_dropped and not is_turn_upcoming: 
        speed_maintain_bonus = min( speed / PARAMS.prev_speed, 1 )
    #Penalize making the heading direction worse
    heading_decrease_bonus = 0
    if PARAMS.prev_direction_diff is not None:
        if is_heading_in_right_direction:
            if abs( PARAMS.prev_direction_diff / direction_diff ) > 1:
                heading_decrease_bonus = min(10, abs( PARAMS.prev_direction_diff / direction_diff ))
    #has the steering angle changed
    has_steering_angle_changed = False
    if PARAMS.prev_steering_angle is not None:
        if not(math.isclose(PARAMS.prev_steering_angle,steering_angle)):
            has_steering_angle_changed = True
    steering_angle_maintain_bonus = 1 
    #Not changing the steering angle is a good thing if heading in the right direction
    if is_heading_in_right_direction and not has_steering_angle_changed:
        if abs(direction_diff) < 10:
            steering_angle_maintain_bonus *= 2
        if abs(direction_diff) < 5:
            steering_angle_maintain_bonus *= 2
        if PARAMS.prev_direction_diff is not None and abs(PARAMS.prev_direction_diff) > abs(direction_diff):
            steering_angle_maintain_bonus *= 2
    #Reward reducing distance to the race line
    distance_reduction_bonus = 1
    if PARAMS.prev_normalized_distance_from_route is not None and PARAMS.prev_normalized_distance_from_route > normalized_distance_from_route:
        if abs(normalized_distance_from_route) > 0:
            distance_reduction_bonus = min( abs( PARAMS.prev_normalized_distance_from_route / normalized_distance_from_route ), 2)
    # Before returning reward, update the variables
    PARAMS.prev_speed = speed
    PARAMS.prev_steering_angle = steering_angle
    PARAMS.prev_direction_diff = direction_diff
    PARAMS.prev_steps = steps
    PARAMS.prev_normalized_distance_from_route = normalized_distance_from_route

Ингредиент 2: понятие гоночной трассы

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

На каждом шаге он тянет точку к прямой линии, проходящей через его двух соседей. Полезно представить это как уменьшение высоты треугольника, слегка потянув его верхнюю вершину к основанию. При этом алгоритм гарантирует, что полученная путевая точка не выйдет за границы трека. Мы рекомендуем читателям, которые хотят лучше понять основные технические детали, пройти Ph.D. Реми Кулом. Тезис".

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

Ограничение гоночной линии внутренними 60% гоночной трассы, как показано на рисунке ниже, оказалось плодотворным. Мы предполагаем, что лучше начать с гоночной трассы, которая ограничена только внутренними участками трассы. После того, как модель научится точно следовать этой гоночной линии, можно постепенно увеличивать ее ограниченную область, чтобы включить всю гоночную трассу. Однако для этой стратегии может потребоваться гораздо больше времени на обучение. Было бы разумно сначала подумать, оправдывает ли потенциальное улучшение производительности дополнительные вычислительные затраты.

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

Второй - это долгосрочный компонент (LC), который определяется на основе общего прогресса, достигнутого автомобилем на гоночной трассе. Непосредственный компонент дополнительно состоит из компонента скорости (SC), компонента расстояния (DC) и компонента заголовка (HC). Аналогичным образом, долгосрочный компонент выводится из бонуса за кривую, бонуса за прямой участок и бонуса за промежуточный прогресс. В конце концов, мы объединяем все эти компоненты, как показано ниже, чтобы вернуть одно число с плавающей запятой. Это награда, которая возвращается на текущем временном шаге.

#heading component of reward
HC = ( 10 * heading_reward * steering_angle_maintain_bonus )
#distance component of reward
DC = ( 10 * distance_reward * distance_reduction_bonus )
#speed component of reward
SC = ( 5 * speed_reward * speed_maintain_bonus )
#Immediate component of reward
IC = ( HC + DC + SC ) ** 2 + ( HC * DC * SC ) 
#If an unpardonable action is taken, then the immediate reward is 0
if PARAMS.unpardonable_action:
  IC = 1e-3
#Long term component of reward
LC = ( curve_bonus + intermediate_progress_bonus + straight_section_bonus )
return max(IC + LC,1e-3)

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

  1. (HC + DC + SC) ² = HC² + DC² + SC² + 2.HC.DC + 2.DC.SC + 2.HC.SC: отдельные квадратные элементы гарантируют, что важно максимизировать направление, расстояние и независимые друг от друга компоненты скорости ИС для получения высокого вознаграждения. Перекрестные условия гарантируют, что также важно максимизировать каждую парную комбинацию для получения высокого вознаграждения. т.е. поддерживать правильную скорость при движении в правильном направлении и т. д.
  2. Наконец, добавление термина HC.DC.SC гарантирует, что для получения максимально возможного вознаграждения важно одновременно максимизировать все три этих компонента.

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

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

Ингредиент 3. Составляющая вознаграждения, связанная со скоростью

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

Мы используем C = 1,5 как нашу константу и 5 как наш опережающий коэффициент. Затем мы рассмотрим участки маршрута, на которых наша модель постоянно отклоняется от маршрута. После вычисления оценки оптимальной скорости в каждой путевой точке мы сохраняем ее в виде списка в нашем class PARAMS.

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

#Calculate the speed reward
MIN_SPEED = 2.0
MAX_SPEED = 4.0
optimal_speed = 0
#chosen such that 6 standard deviations covers the entire range
sigma_speed = abs(MAX_SPEED - MIN_SPEED)/6.0
i = closest_route_point
nsteps = 5
if i+nsteps < len(PARAMS.waypoints):
   optimal_speed = min( PARAMS.optimal_speed[i:(i+nsteps)%len(PARAMS.waypoints)] )
else:
   optimal_speed = min( min(PARAMS.optimal_speed[i:]), min(PARAMS.optimal_speed[:(i+nsteps)%len(PARAMS.waypoints)+1]) )
    
#PARAMS.optimal speed is unbounded and hence must be bounded from above to reflect action space realities
optimal_speed = min(MAX_SPEED,optimal_speed)
speed_reward = math.exp(-0.5*abs(speed-optimal_speed)**2 / sigma_speed**2)

Ключевой идеей здесь является использование ненормализованного распределения Гаусса с оптимальной скоростью в качестве среднего и одной шестой всего диапазона скоростей в качестве стандартного отклонения. Мы снова вернемся к этой идее при вычислении составляющей расстояния.

Ингредиент 4. Компонент вознаграждения, связанный с расстоянием

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

#distance reward is value of the standard normal scaled back to 1. #Hence the 1/2*pi*sigma term is cancelled out
distance_reward = 0
if "center" in bearing: #i.e. on the route line
   distance_from_route = 0
   distance_reward = 1
elif "right" in bearing: #i.e. on right side of the route line
    sigma=abs(normalized_route_distance_from_inner_border / 4) 
    distance_reward = math.exp(-0.5*abs(normalized_car_distance_from_route)**2/sigma**2)
elif "left" in bearing: #i.e. on left side of the route line
    sigma=abs(normalized_route_distance_from_outer_border / 4) 
    distance_reward = math.exp(-0.5*abs(normalized_car_distance_from_route)**2/sigma**2)

Ингредиент 5. Заголовок награды

Заголовок награды призван помочь автомобилю указывать в правильном направлении. Для расчета этого компонента курса в качестве целевого местоположения используются координаты точки маршрута на 5 шагов впереди ближайшей точки маршрута. Разница между углом курса к цели и текущим углом курса автомобиля отмечается как разница в направлении. Вознаграждение за заголовок рассчитывается на основе разницы в направлениях следующим образом.

heading = params['heading']
vehicle_x = params['x']
vehicle_y = params['y']
# Calculate the direction in radius, arctan2(dy, dx), the result is (-pi, pi) in radians between target and current vehicle position
route_direction = math.atan2(next_route_point_y - vehicle_y, next_route_point_x - vehicle_x) 
# Convert to degree
route_direction = math.degrees(route_direction)
# Calculate the difference between the track direction and the heading direction of the car
direction_diff = route_direction - heading
#Check that the direction_diff is in valid range
#Then compute the heading reward
heading_reward = math.cos( abs(direction_diff ) * ( math.pi / 180 ) ) ** 10
if abs(direction_diff) <= 20:
   heading_reward = math.cos( abs(direction_diff ) * ( math.pi / 180 ) ) ** 4

Ингредиент 6. Набор непростительных состояний и действий

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

  1. Расстояние от центральной линии превышает половину ширины колеи.
  2. Разница в направлениях превышает 30 градусов.
  3. Автомобиль движется не в правильном направлении. то есть он указывает за пределы конуса, образованного автомобилем, и путевой точки опережения на внутренней и внешней границах пути.
  4. Автомобиль в настоящее время движется в правильном направлении, но поворачивает рулевое управление, которое сбивает его с курса.
  5. Автомобиль поворачивает налево, когда должен повернуть направо.
  6. Автомобиль поворачивает направо, хотя должен был повернуть налево.
  7. Скорость автомобиля при повороте как минимум на 1 м / с превышает его оптимальную скорость. По сути, машина слишком быстро поворачивает.
  8. Скорость автомобиля на 1,5 м / с ниже оптимальной скорости на прямом участке. По сути, машина слишком медленно движется на прямых участках.

Ингредиент 7: награда за промежуточный прогресс

Чтобы еще больше стимулировать движение машины по трассе, мы вознаграждаем ее за каждые 10 процентов прохождения трассы. Эта награда является экспоненциальной совокупной средней скоростью, с которой она пересекает каждую такую ​​веху. Значение этого показателя также увеличивается на 0,75 на каждом этапе. Чтобы вознаграждение, полученное таким образом, оставалось значительным, важно обеспечить, чтобы оно было немного больше, чем общее вознаграждение, которое автомобиль накапливает на пути к этим этапам. Для определения точного значения этих показателей может потребоваться некоторое экспериментирование.

# Reward for making steady progress
progress_reward = 10 * progress / steps
if steps <= 5:
   progress_reward = 1 #ignore progress in the first 5 steps
# Bonus that the agent gets for completing every 10 percent of track
# Is exponential in the progress / steps. 
# exponent increases with an increase in fraction of lap completed
intermediate_progress_bonus = 0
pi = int(progress//10)
if pi != 0 and PARAMS.intermediate_progress[ pi ] == 0:
   if pi==10: # 100% track completion
      intermediate_progress_bonus = progress_reward ** 14
   else:
      intermediate_progress_bonus = progress_reward ** (5+0.75*pi)
PARAMS.intermediate_progress[ pi ] = intermediate_progress_bonus

Ингредиент 8: бонус кривой

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

Ингредиент 9: бонус прямой секции

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

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

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

Шаг 3. Указание правильных гиперпараметров

После выбора пространства действий и определения функции вознаграждения последним шагом является установка гиперпараметров алгоритма обучения PPO. В контексте настройки DRFC это включает редактирование файла deepracer-for-cloud/custom_files/hyperparameters.json. Горький урок здесь состоит в том, что разумный выбор гиперпараметров не значительно улучшит функцию плохого вознаграждения. Когда вы новичок в DeepRacer, очень часто можно увидеть, как производительность модели, измеряемая по ее среднему прогрессу на круге, неуклонно снижается с увеличением времени тренировки. Когда это происходит, возникает соблазн повозиться с гиперпараметрами. Можно снизить скорость обучения, увеличить размер пакета, уменьшить значение epsilon greedy и т. Д., А затем перезапустить обучение. Через несколько часов тренировки, возвращаясь, обнаруживаешь, что мало что изменилось. После небольшого начального улучшения производительность модели продолжает снижаться с увеличением времени обучения.

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

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

Конвергенция

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

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

Кроме того, быстрого поиска этих терминов в Google недостаточно, поскольку это может привести к неверным выводам. Прежде чем применять определения, очень важно полностью понять контекст, в котором алгоритм обучения ссылается на эти термины.

Чтобы упростить работу практикующим, не имеющим необходимой теоретической подготовки, программа обучения отслеживает лучшую контрольную точку. Это число представляет собой просто итерацию обучения, для которой автомобиль зафиксировал наибольшее значение для доли пройденного круга в настройках оценки (т. Е. Без случайного выбора действий). Сама по себе эта доля является справедливым показателем успеваемости. Теоретически это значение должно со временем увеличиваться от 0 до 100%. С помощью инструмента анализа журнала также можно отслеживать долю пройденного круга во время тренировки (т.е. при наличии случайного выбора действий).

Мы использовали каждый из этих показателей для отслеживания нашего прогресса. Мы считали, что наше обучение сходилось, если лучшая контрольная точка была более чем на 200 итераций позади нашей текущей контрольной точки обучения. На наших лучших тренировках мы наблюдали, как средняя доля пройденных кругов за итерацию выросла с 5% на начальных этапах до примерно 40% после схождения. Мы не чередовали встроенную настройку оценки DRFC с постоянным обучением. Вместо этого мы использовали автоматическую отправку моделей с использованием скриптов Selenium, чтобы напрямую отслеживать наш прогресс в таблице лидеров AWS DeepRacer.

Таким образом, нет однозначных ответов на вопрос - когда нужно прекратить тренировки? Нужно руководствоваться своим суждением и принимать решение на основе вышеуказанных показателей. Хотя эти показатели характеризуются высокой дисперсией, рекомендуется продолжать тренировку до тех пор, пока в таблице лидеров AWS DeepRacer будет заметное улучшение времени. Когда улучшение прекратится, пора проверить отправленные видео и решить общие проблемы, настроив функцию вознаграждения. Нам пришлось пройти этот процесс по крайней мере 14 раз за 9 тысяч тренировочных итераций, чтобы получить модель, которая прошла по дорожке виртуальной цепи августа 2020 года, как показано ниже.

Большая философская загадка: кормить с ложечки или не кормить с ложечки.

Используя методы, описанные в этом сообщении в блоге, мы смогли попасть в верхний 1 процентильный рейтинг конкурса AWS DeepRacer Virtual Circuit за август 2020 года. Однако способ, которым мы попали в него оставляет желать лучшего. В частности, мы не полностью удовлетворены объемом знаний о гоночной трассе и об оптимальной скорости, которые мы скармливаем агенту с помощью нашей функции вознаграждения. Как правило, среда обучения с подкреплением выдает вознаграждение только при достижении целевых состояний и не обеспечивает какого-либо промежуточного контроля, касающегося того, как эти состояния должны быть достигнуты. Последнее остается на усмотрение агента для определения методом проб и ошибок. Канонически это резюмируется как - вознаграждение за что, а не за как проблемной области. В случае AWS DeepRacer идеальная функция вознаграждения должна назначать подходящее вознаграждение только при достижении конечной цели, т. Е. Автомобиль учится проходить круг за максимально быстрое время. Строго говоря, любые дальнейшие указания о том, как это делать, противоречат духу обучения с подкреплением. Для некоторых любое увлечение формированием вознаграждения является отклонением от истинного ИИ.

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

Мы полностью согласны с этой позицией - только когда вычисления дешевы! Так может быть и с очень крупными технологическими компаниями (на самом деле, мы не уверены, насколько легко получить санкции на такие многомиллионные бюджеты и внутри этих компаний). Однако для любителей и небольших компаний бюджет на вычислительные ресурсы является важным ограничивающим фактором. Это особенно актуально во времена глобальной пандемии, которая остановила экономическую активность во всем мире. Таким образом, мы в принципе не против техник формирования вознаграждения. Мы признаем важную роль, которую они играют в распространении знаний в предметной области и сокращении затрат на вычисления.

В контексте AWS DeepRacer нам остается задаться вопросом, можно ли обучить высокопроизводительную модель с нуля - такую, которая полностью игнорирует информацию о путевых точках в любой форме и тем не менее, ему удается войти в десятку лучших. Некоторые члены сообщества AWS DeepRacer считают, что обучение такой модели действительно возможно. Однако наши собственные усилия по обучению такой модели не увенчались успехом. Мы предполагаем, что обучение такой модели потребует гораздо меньше кормления с ложечки (за счет неизвестного количества вычислений) и, таким образом, будет более верным духу обучения с подкреплением.

Наша зависимость от информации о путевых точках также проблематична по другой важной причине - это приводит к плохому обобщению. Наша «высокопроизводительная» модель для трассы Virtual Circuit за август 2020 года превращается в «посредственную» модель в момент смены базовой трассы. Затем весь процесс обучения, описанный в этом блоге, необходимо повторить для нового трека. Это означает, что тем, кто следует этой методике, придется (хотя бы частично) переобучать свои модели для каждого ежемесячного соревнования. Без этого маловероятно, что они получат высокий рейтинг. Это довольно неудовлетворительно!

Таким образом, мы хотели бы предоставить нашим читателям конкретную цель - найти способ обучить высокопроизводительную модель, не обращаясь к какой-либо конкретной информации о треке. На наш взгляд, успешная реализация этой цели была бы знаковым результатом. Анализ вычислений и производительности любого метода, который помогает достичь этой цели, принесет большую пользу сообществу AWS DeepRacer.

Приготовься. Идти!