以下是 repo 中 DDQN 的实现,可以看到target NN 在计算下一个状态的 next Q value的时候,使用的 action 并不是用self.model得到的,而是直接用 target NN 在下一个状态时最大的价值的动作,这种实现方式是基本的target network + DQN 而不是真正的 DDQN
class DoubleDQN:
def __init__(self, dim_obs=None, num_act=None, discount=0.9):
self.discount = discount
self.model = QNet(dim_obs, num_act)
self.target_model = QNet(dim_obs, num_act)
self.target_model.load_state_dict(self.model.state_dict())
def get_action(self, obs):
qvals = self.model(obs)
return qvals.argmax()
def compute_loss(self, s_batch, a_batch, r_batch, d_batch, next_s_batch):
# Compute current Q value based on current states and actions.
qvals = self.model(s_batch).gather(1, a_batch.unsqueeze(1)).squeeze()
# next state的value不参与导数计算,避免不收敛。
next_qvals, _ = self.target_model(next_s_batch).detach().max(dim=1)
loss = F.mse_loss(r_batch + self.discount * next_qvals * (1 - d_batch), qvals)
return loss
真正的 DDQN 应该改写成
def ddqn_compute_loss(self, s_batch, a_batch, r_batch, d_batch, next_s_batch):
# Compute current Q value based on current states and actions.
qvals = self.model(s_batch).gather(1, a_batch.unsqueeze(1)).squeeze()
next_s_action = self.model(next_s_batch).argmax(dim=1)
next_qvals, _ = self.target_model(next_s_batch).gather(1, next_s_action.unsqueeze(1)).detach().max(dim=1)
loss = F.mse_loss(r_batch + self.discount * next_qvals * (1 - d_batch), qvals)
return loss
经过原始代码测试,eval 时前者平均 reward 是-142.57142857142858,后者是-138.25
可见确实是 DDQN 的效果更好,但是经过观察,DDQN 训练可能需要更多的时间,如果我把max step 设置成 20W
结果反而是 DDQN 更差,这非常诡异
诡异 2:我重新测试了一次 max step = 10w,结果发现这次原compute loss 的方法直接训崩了,avg reward = -200,DDQN 的 avg reward 高达-136,这得出第二个结论,DQN 的训练太不稳定了
我把 ER 改成 PER,结果依然非常不稳定,有时候 PER 更好,有时候 ER 更好,就离谱,RL 真的太不稳定了,哪怕是我这里的 DDQN 也不一定比前面那个版本更好
以下是 repo 中 DDQN 的实现,可以看到target NN 在计算下一个状态的 next Q value的时候,使用的 action 并不是用
self.model得到的,而是直接用 target NN 在下一个状态时最大的价值的动作,这种实现方式是基本的target network + DQN 而不是真正的 DDQN真正的 DDQN 应该改写成
经过原始代码测试,eval 时前者平均 reward 是-142.57142857142858,后者是-138.25
可见确实是 DDQN 的效果更好,但是经过观察,DDQN 训练可能需要更多的时间,如果我把max step 设置成 20W
结果反而是 DDQN 更差,这非常诡异
诡异 2:我重新测试了一次 max step = 10w,结果发现这次原compute loss 的方法直接训崩了,avg reward = -200,DDQN 的 avg reward 高达-136,这得出第二个结论,DQN 的训练太不稳定了
我把 ER 改成 PER,结果依然非常不稳定,有时候 PER 更好,有时候 ER 更好,就离谱,RL 真的太不稳定了,哪怕是我这里的 DDQN 也不一定比前面那个版本更好