Pytorch: Как создать правило обновления, не основанное на производных? - PullRequest
0 голосов
/ 17 февраля 2019

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

enter image description here

Я непонять, как реализовать правило обновления в 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).

thanks

БОЛЬШОЕ спасибо @ChrisГолландия, которая «попробовала»

1 Ответ

0 голосов
/ 18 февраля 2019

Я попробую.

.backward() не нуждается в функции потерь, просто нужен дифференцируемый скалярный вывод.Аппроксимирует градиент по отношению к параметрам модели.Давайте просто посмотрим на первый случай обновления для функции значения.

У нас есть один градиент, появляющийся для v, мы можем приблизить этот градиент на

v = model(s)
v.backward()

Это дает нам градиент v, который имеет размерность параметров вашей модели.Предполагая, что мы уже рассчитали обновления других параметров, мы можем рассчитать фактическое обновление оптимизатора:

for i, p in enumerate(model.parameters()):
    z_theta[i][:] = gamma * lamda * z_theta[i] + l * p.grad
    p.grad[:] = alpha * delta * z_theta[i]

Затем мы можем использовать opt.step() для обновления параметров модели с настроенным градиентом.

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