Pytorch: Como criar uma regra de atualização que não vem de derivativo
Eu quero implementar o seguinte algoritmo, retirado deeste livro, seção 13.6:
Não entendo como implementar a regra de atualização no pytorch (a regra para w é bastante semelhante à do theta
Até onde eu sei, a tocha requer uma perda paraloss.backwward()
.
Este formulário parece não se aplicar ao algoritmo citad
inda tenho certeza de que existe uma maneira correta de implementar essas regras de atualização no pytorc
Apreciaria muito um trecho de código de como os pesos w devem ser atualizados, dado que V (s, w) é a saída da rede neural, parametrizada por w.
EDITAR Chris Holland sugeriu uma maneira de implementar, e eu a implementei. Ele não converge no Cartpole, e me pergunto se fiz algo errad
O crítico converge na solução para a funçãogamma*f(n)=f(n)-1
que é a soma da sériegamma+gamma^2+...+gamma^inf
significado, gama = 1 diverge. gama = 0,99 converge em 100, gama = 0,5 converge em 2 e assim por diante. Independentemente do ator ou política.
O código
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()
EDIT 2: solução de Chris Holland funciona. O problema se originou de um bug no meu código que causou a linha
if s_t1 is not None:
expected_reward_from_t1 = self.critic_nn(s_t1)
para sempre ser chamado, assimexpected_reward_from_t1
nunca foi zero e, portanto, nenhuma condição de parada foi especificada para a recursão da equação de bellma
Sem engenharia de recompensa,gamma=1
, lambda=0.6
, e uma única camada oculta do tamanho 128 para ator e crítico, isso convergiu para uma política ideal bastante estável em 500 episódio
Muito mais rápido comgamma=0.99
, como mostra o gráfico (a melhor recompensa com episódio com desconto é de cerca de 86,6
BIG, obrigado a Chris Holland, que "fez uma tentativa"