Pytorch:如何创建一个不是衍生品的更新规则?

Gul*_*zar 5 python machine-learning reinforcement-learning backpropagation pytorch

我想实现以下算法,取自本书第13.6节:

在此输入图像描述

我不明白如何在pytorch中实现更新规则(w的规则与theta的规则非常相似).

据我所知,火炬需要赔偿loss.backwward().

此表单似乎不适用于引用的算法.

我仍然确定在pytorch中有一种正确的方法来实现这样的更新规则.

如果V(s,w)是由w参数化的神经网络的输出,那将非常感谢w权重应该如何更新的代码片段.


编辑:克里斯荷兰提出了一种实施方式,我实施了它.它不会集中在Cartpole上,我想知道我做错了什么.

评论家确实收敛于函数的解决方案,gamma*f(n)=f(n)-1这恰好是系列gamma+gamma^2+...+gamma^inf 意义的总和,gamma = 1不同.gamma = 0.99收敛于100,gamma = 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]
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

编辑2: Chris Holland的解决方案有效.问题起源于我的代码中导致该行的错误

if s_t1 is not None:
    expected_reward_from_t1 = self.critic_nn(s_t1)
Run Code Online (Sandbox Code Playgroud)

总是被调用,因此expected_reward_from_t1从不为零,因此没有为贝尔曼方程递归指定停止条件.

由于没有奖励工程gamma=1,lambda=0.6以及既是演员又是评论家大小为128的单隐层,此聚集在500个事件中的相当稳定最优策略.

更快gamma=0.99,如图所示(最佳折扣剧集奖励约为86.6).

谢谢

非常感谢@Chris Holland,他"试了一下"

Chr*_*and 5

我要试试这个。

.backward()不需要损失函数,它只需要一个可微的标量输出。它近似于模型参数的梯度。我们只看第一种情况,即值函数的更新。

我们有一个梯度出现在 v 上,我们可以通过下式来近似这个梯度

v = model(s)
v.backward()
Run Code Online (Sandbox Code Playgroud)

这为我们提供了一个梯度,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]
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用opt.step()调整后的梯度来更新模型参数。