Pytorch: 如何创建不基于导数的更新规则?

我想实现以下算法,来自这本书,第13.6节

enter image description here

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

据我所知,torch需要一个损失来使用loss.backwward()

这种形式似乎不适用于引用的算法。

我仍然确信在pytorch中实现这种更新规则是有正确方法的。

如果给定V(s,w)是神经网络的输出,由w参数化,我非常希望能看到一个关于如何更新w权重的代码片段。


编辑: Chris Holland提出了一个实现方法,我已经实现了它。它在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]

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不是终止状态,s_t1存在。    expected_reward_from_t1 = self.critic_nn(s_t1)delta = r_t + gamma * expected_reward_from_t1.data - expected_reward_from_t.datanegative_expected_reward_from_t = -expected_reward_from_tself.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:Chris Holland的解决方案有效。问题源于我代码中的一个错误,导致以下代码行

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

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

在没有奖励设计的情况下,gamma=1lambda=0.6,以及演员和评论者的单隐藏层大小为128,这在500个回合内收敛到了一个相当稳定的最优策略。

如图所示,gamma=0.99时收敛更快(最佳折扣回合奖励约为86.6)。

thanks

非常感谢@XXX,他“尝试了这个方法”


回答:

我打算试一试。

.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()来使用调整后的梯度更新模型参数。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注