Является ли значение вознаграждения в псевдокоде MuZero смещенным? - PullRequest
2 голосов
/ 15 февраля 2020

MuZero , методика глубокого обучения, была только что выпущена, и я пытался реализовать ее, взглянув на псевдокод и это полезное руководство на Medium.

Однако меня смущает то, как обрабатываются награды во время обучения в псевдокоде, и было бы здорово, если бы кто-то мог проверить, правильно ли я читаю код, и если да, объясните, почему работает этот алгоритм обучения.

Вот функция обучения (из псевдокода 1012 *):

def update_weights(optimizer: tf.train.Optimizer, network: Network, batch,
                   weight_decay: float):
  loss = 0
  for image, actions, targets in batch:
    # Initial step, from the real observation.
    value, reward, policy_logits, hidden_state = network.initial_inference(
        image)
    predictions = [(1.0, value, reward, policy_logits)]

    # Recurrent steps, from action and previous hidden state.
    for action in actions:
      value, reward, policy_logits, hidden_state = network.recurrent_inference(
          hidden_state, action)
      predictions.append((1.0 / len(actions), value, reward, policy_logits))

      hidden_state = tf.scale_gradient(hidden_state, 0.5)

    for prediction, target in zip(predictions, targets):
      gradient_scale, value, reward, policy_logits = prediction
      target_value, target_reward, target_policy = target

      l = (
          scalar_loss(value, target_value) +
          scalar_loss(reward, target_reward) +
          tf.nn.softmax_cross_entropy_with_logits(
              logits=policy_logits, labels=target_policy))

      loss += tf.scale_gradient(l, gradient_scale)

  for weights in network.get_weights():
    loss += weight_decay * tf.nn.l2_loss(weights)

  optimizer.minimize(loss)

Меня интересует reward в потере конкретно. Обратите внимание, что потеря получает все свои значения из predictions. Первый reward, добавленный к predictions, относится к функции network.initial_inference. После этого к predictions добавлены len(actions) дополнительные награды, все из которых поступают от функции network.recurrent_inference.

На основе учебника функции initial_inference и recurrent_inference построены из 3 различных Функции:

  1. Прогноз Ввод: внутреннее состояние игры. Вывод: политика, значение (прогнозируемая сумма наилучших возможных будущих наград)
  2. Динамика Вход: внутреннее состояние игры, действие. Вывод: награда за выполнение этого действия, новое внутреннее состояние игры.
  3. Представление Вход: внешнее состояние игры. Вывод: внутреннее состояние игры

Функция initial_inference принимает внешнее игровое состояние, использует функцию representation, чтобы превратить его во внутреннее состояние, а затем использует функцию prediction на этом внутреннем игровом состоянии. Он выводит внутреннее состояние, политику и значение.

Функция recurrent_inference принимает внутреннее игровое состояние и действие. Он использует функцию dynamics, чтобы получить новое внутреннее игровое состояние и вознаграждение от старого игрового состояния и действия. Затем он применяет функцию prediction к новому внутреннему игровому состоянию, чтобы получить политику и значение этого нового внутреннего состояния. Таким образом, конечный результат - это новое внутреннее состояние, вознаграждение, политика и значение.

Однако в псевдокоде функция initial_inference также возвращает вознаграждение .

Моя основная проблема: Что означает это вознаграждение?

В учебном пособии они просто неявно предполагают, что вознаграждение от функции initial_inference равно 0. (См. это изображение из учебника.) Так что же происходит? Разве на самом деле нет награды, поэтому initial_inference просто всегда возвращает 0 для награды?

Давайте предположим, что это так.

В этом предположении первая награда в Список predictions будет равен 0, который функция initial_inference вернет за вознаграждение. Затем в потере этот 0 будет сравниваться с первым элементом списка target.

Вот как создается target:

  def make_target(self, state_index: int, num_unroll_steps: int, td_steps: int,
                  to_play: Player):
    # The value target is the discounted root value of the search tree N steps
    # into the future, plus the discounted sum of all rewards until then.
    targets = []
    for current_index in range(state_index, state_index + num_unroll_steps + 1):
      bootstrap_index = current_index + td_steps
      if bootstrap_index < len(self.root_values):
        value = self.root_values[bootstrap_index] * self.discount**td_steps
      else:
        value = 0

      for i, reward in enumerate(self.rewards[current_index:bootstrap_index]):
        value += reward * self.discount**i  # pytype: disable=unsupported-operands

      if current_index < len(self.root_values):
        targets.append((value, self.rewards[current_index],
                        self.child_visits[current_index]))
      else:
        # States past the end of games are treated as absorbing states.
        targets.append((0, 0, []))
    return targets

targets возвращаемый этой функцией становится списком target в функции update_weights. Итак, первое значение в targets это self.rewards[current_index]. self.rewards - это список всех наград, полученных во время игры. Единственный раз, когда она редактируется, находится внутри этой функции apply:

  def apply(self, action: Action):
    reward = self.environment.step(action)
    self.rewards.append(reward)
    self.history.append(action)

Функция apply вызывается только здесь:

# Each game is produced by starting at the initial board position, then
# repeatedly executing a Monte Carlo Tree Search to generate moves until the end
# of the game is reached.
def play_game(config: MuZeroConfig, network: Network) -> Game:
  game = config.new_game()

  while not game.terminal() and len(game.history) < config.max_moves:
    # At the root of the search tree we use the representation function to
    # obtain a hidden state given the current observation.
    root = Node(0)
    current_observation = game.make_image(-1)
    expand_node(root, game.to_play(), game.legal_actions(),
                network.initial_inference(current_observation))
    add_exploration_noise(config, root)

    # We then run a Monte Carlo Tree Search using only action sequences and the
    # model learned by the network.
    run_mcts(config, root, game.action_history(), network)
    action = select_action(config, len(game.history), root, network)
    game.apply(action)
    game.store_search_statistics(root)
  return game

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

Проблема становится понятной, если current_index = 0 в self.rewards[current_index]. В этом случае список predictions будет иметь 0 для первого вознаграждения, потому что это всегда так. Тем не менее, список targets получит вознаграждение за выполнение первого действия.

Так что, мне кажется, что награды смещены неправильно.

Если мы продолжим, вторая награда в списке predictions будет вознаграждением от recurrent_inference за выполнение действия first . Тем не менее, вторая награда в списке targets будет сохранена в игре за выполнение второго действия.

Итак, в целом у меня есть три вопроса, которые строятся друг на друге :

  1. Что представляет собой награда из initial_inference? (Что это?)
  2. Если оно равно 0 и предполагается, что оно представляет собой награду, будут ли вознаграждения между predictions и targets смещены? (то есть, должно ли второе вознаграждение в predictions действительно совпадать с первым вознаграждением в targets?)
  3. Если они не выровнены, будет ли сеть по-прежнему работать и работать правильно?

(Еще одно любопытное замечание: несмотря на это смещение (при условии смещения) длина predictions и targets имеет одинаковую длину. Длина целей определяется линией for current_index in range(state_index, state_index + num_unroll_steps + 1) в make_target функция выше. Выше мы также вычислили, что длина predictions равна len(actions) + 1. И len(actions) определяется g.history[i:i + num_unroll_steps] в функции sample_batch (см. псевдокод ). Таким образом длина обоих списков одинакова.)

Что происходит?

1 Ответ

2 голосов
/ 21 февраля 2020

Автор здесь.

Что представляет собой награда из initial_inference?

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

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

Вычисление цели вознаграждения в псевдокоде действительно было смещено; Я только что загрузил новую версию в arXiv.

Где раньше говорилось

      if current_index < len(self.root_values):
        targets.append((value, self.rewards[current_index],
                        self.child_visits[current_index]))
      else:
        # States past the end of games are treated as absorbing states.
        targets.append((0, 0, []))

Это должно быть:

      # For simplicity the network always predicts the most recently received
      # reward, even for the initial representation network where we already
      # know this reward.
      if current_index > 0 and current_index <= len(self.rewards):
        last_reward = self.rewards[current_index - 1]
      else:
        last_reward = 0

      if current_index < len(self.root_values):
        targets.append((value, last_reward, self.child_visits[current_index]))
      else:
        # States past the end of games are treated as absorbing states.
        targets.append((0, last_reward, []))

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...