Поэтому я реализовал код, как вы предложили. Это не сходится на Cartpole, что является неожиданным. Хуже того, если я заставлю актера ничего не изучать, просто критик даже не сойдет с правильной функцией значения статической политики. Я вроде не в курсе, как это отладить ... Я добавил полный код как редактирование к исходному вопросу

у реализовать следующий алгоритм, взятый изэта книга, раздел 13.6:

Я не понимаю, как реализовать правило обновления в pytorch (правило для w довольно похоже на правило тета).

Насколько я знаю, факел требует потериloss.backwward().

Эта форма, по-видимому, не относится к указанному алгоритму.

Я все еще уверен, что есть правильный способ реализации таких правил обновления в pytorch.

Был бы очень признателен за фрагмент кода того, как должны обновляться веса w, учитывая, что V (s, w) является выходом нейронной сети, параметризованной w.

РЕДАКТИРОВАТЬ: Крис Холланд предложил способ реализации, и я реализовал его. Это не сходится на Cartpole, и мне интересно, если я сделал что-то не так.

Критик сходится к решению функцииgamma*f(n)=f(n)-1 которая оказывается суммой рядаgamma+gamma^2+...+gamma^inf значение гамма = 1 расходится. гамма = 0,99 сходится на 100, гамма = 0,5 сходится на 2 и так далее. Независимо от актера или политики.

Код:

def _update_grads_with_eligibility(self, is_critic, delta, discount, ep_t):
    gamma = self.args.gamma
    if is_critic:
        params = list(self.critic_nn.parameters())
        lamb = self.critic_lambda
        eligibilities = self.critic_eligibilities
    else:
        params = list(self.actor_nn.parameters())
        lamb = self.actor_lambda
        eligibilities = self.actor_eligibilities

    is_episode_just_started = (ep_t == 0)
    if is_episode_just_started:
        eligibilities.clear()
        for i, p in enumerate(params):
            if not p.requires_grad:
                continue
            eligibilities.append(torch.zeros_like(p.grad, requires_grad=False))

    # eligibility traces
    for i, p in enumerate(params):

        if not p.requires_grad:
            continue
        eligibilities[i][:] = (gamma * lamb * eligibilities[i]) + (discount * p.grad)
        p.grad[:] = delta.squeeze() * eligibilities[i]

а также

expected_reward_from_t = self.critic_nn(s_t)
probs_t = self.actor_nn(s_t)
expected_reward_from_t1 = torch.tensor([[0]], dtype=torch.float)
if s_t1 is not None:  # s_t is not a terminal state, s_t1 exists.
    expected_reward_from_t1 = self.critic_nn(s_t1)

delta = r_t + gamma * expected_reward_from_t1.data - expected_reward_from_t.data

negative_expected_reward_from_t = -expected_reward_from_t
self.critic_optimizer.zero_grad()
negative_expected_reward_from_t.backward()
self._update_grads_with_eligibility(is_critic=True,
                                    delta=delta,
                                    discount=discount,
                                    ep_t=ep_t)
self.critic_optimizer.step()

РЕДАКТИРОВАТЬ 2: Решение Криса Холланда работает. Проблема возникла из-за ошибки в моем коде, которая вызвала строку

if s_t1 is not None:
    expected_reward_from_t1 = self.critic_nn(s_t1)

чтобы всегда звонить, таким образомexpected_reward_from_t1 никогда не был равен нулю, и, следовательно, для рекурсии уравнения Беллмана не было указано условие остановки.

Без поощрения инженеров,gamma=1, lambda=0.6и единый скрытый слой размером 128 для актера и критика, это сходилось на довольно стабильной оптимальной политике в течение 500 эпизодов.

Еще быстрее сgamma=0.99, как показывает график (лучшая скидка за эпизод составляет около 86,6).

Большое спасибо @Chris Holland, который "дал это попробовать"

Ответы на вопрос(1)

Ваш ответ на вопрос