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 различных Функции:
- Прогноз Ввод: внутреннее состояние игры. Вывод: политика, значение (прогнозируемая сумма наилучших возможных будущих наград)
- Динамика Вход: внутреннее состояние игры, действие. Вывод: награда за выполнение этого действия, новое внутреннее состояние игры.
- Представление Вход: внешнее состояние игры. Вывод: внутреннее состояние игры
Функция 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
будет сохранена в игре за выполнение второго действия.
Итак, в целом у меня есть три вопроса, которые строятся друг на друге :
- Что представляет собой награда из
initial_inference
? (Что это?) - Если оно равно 0 и предполагается, что оно представляет собой награду, будут ли вознаграждения между
predictions
и targets
смещены? (то есть, должно ли второе вознаграждение в predictions
действительно совпадать с первым вознаграждением в targets
?) - Если они не выровнены, будет ли сеть по-прежнему работать и работать правильно?
(Еще одно любопытное замечание: несмотря на это смещение (при условии смещения) длина 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
(см. псевдокод ). Таким образом длина обоих списков одинакова.)
Что происходит?