Я хочу реализовать следующий алгоритм, взятый из этой книги, раздел 13.6 :
Я непонять, как реализовать правило обновления в pytorch (правило для w довольно похоже на правило тэты).
Насколько я знаю, torch требует потери для loss.backwward()
.
Эта форма, по-видимому, не подходит для цитируемого алгоритма.
Я все еще уверен, что есть правильный способ реализации таких правил обновления в pytorch.
Буду очень признателен за фрагмент кода того, каквеса w должны быть обновлены, учитывая, что V (s, w) - это выход нейронной сети, параметризованный как w.
РЕДАКТИРОВАТЬ: Крис Холланд предложил способреализовать, и я реализовал это.Он не сходится на Картполе, и мне интересно, сделал ли я что-то не так.
Критик сходится к решению функции 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Голландия, которая «попробовала»