Pytorch:如何创建不是来自衍生品的更新规则?
Pytorch: How to create an update rule that doesn't come from derivatives?
我想实现以下算法,摘自this book, section 13.6:
不明白pytorch中更新规则是怎么实现的(w的规则和theta的很相似)
据我所知,火炬需要损失 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 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:
Chris Holland 的解决方案有效。问题源于我的代码中的一个错误,该错误导致行
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 Holland,他 "gave this a try"
我要试试这个。
.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()
使用调整后的梯度更新模型参数。
我想实现以下算法,摘自this book, section 13.6:
不明白pytorch中更新规则是怎么实现的(w的规则和theta的很相似)
据我所知,火炬需要损失 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 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: Chris Holland 的解决方案有效。问题源于我的代码中的一个错误,该错误导致行
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 Holland,他 "gave this a try"
我要试试这个。
.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()
使用调整后的梯度更新模型参数。