写在前面
强化学习导论里面就已经学习过这种方法了,通过添加基线的方法,同时学习value函数和策略函数,更好的收敛,OK,开干
核心
提炼文中关于这个方法有效性的最核心的一个介绍
如果三个动作 a1,a2,a3a_1,a_2,a_3a1,a2,a3的价值Q1,Q2,Q3Q_1,Q_2,Q_3Q1,Q2,Q3,如果3的价值是负值,按照我们的策略梯度原理会学习到更多的执行动作1,2,但是如果奖励都是正的,那么策略会学习到三个动作都尝试增大,只是值更大的增加的更多,所以为了更好的学习,我们尝试减去这个平均值(更好的区分好的和坏的动作)
考虑到梯度的缩放的问题,将所有的奖励平均到均值为0的正太分布更好的梯度大小策略。
CartPole方差
带基线版本
原文中通过统计reward的值,并且计算均值来获得基线,并且在reward添加的时候修改了奖励值
reward_sum += exp.reward
baseline = reward_sum / (step_idx + 1)
writer.add_scalar("baseline", baseline, step_idx)
batch_states.append(exp.state)
batch_actions.append(int(exp.action))
if args.baseline:
batch_scales.append(exp.reward - baseline)
else:
batch_scales.append(exp.reward)
梯度迭代的时候,分了两次进行梯度计算,第一次只是进行了policy的grad,并且保存了下来,然后继续使用entropy的损失进行梯度叠加,最后一次性经过了优化器优化
optimizer.zero_grad()
logits_v = net(states_v)
log_prob_v = F.log_softmax(logits_v, dim=1)
log_p_a_v = log_prob_v[range(BATCH_SIZE), batch_actions_t]
log_prob_actions_v = batch_scale_v * log_p_a_v
loss_policy_v = -log_prob_actions_v.mean()
loss_policy_v.backward(retain_graph=True)
grads = np.concatenate([p.grad.data.numpy().flatten()
for p in net.parameters()
if p.grad is not None])
prob_v = F.softmax(logits_v, dim=1)
entropy_v = -(prob_v * log_prob_v).sum(dim=1).mean()
entropy_loss_v = -ENTROPY_BETA * entropy_v
entropy_loss_v.backward()
optimizer.step()
loss_v = loss_policy_v + entropy_loss_v
所有的节点p在net.parameters的grad,展平成numpy flatten,然后再相互concatenate成一个一维的数组
grads = np.concatenate([p.grad.data.numpy().flatten()
for p in net.parameters()
if p.grad is not None])
通过grads获取到的策略梯度,进行计算我们的l2,max,var的值,有基线的版本,显然要得到更好的收敛性
g_l2 = np.sqrt(np.mean(np.square(grads)))
g_max = np.max(np.abs(grads))
writer.add_scalar("grad_l2", g_l2, step_idx)
writer.add_scalar("grad_max", g_max, step_idx)
writer.add_scalar("grad_var", np.var(grads), step_idx)
我的本地的环境感觉更加的不稳定,所以我这边的会出现很大的熵值表大的情况,整体来说还是好了很多
A2C
其实我们前面的已经用到了这个方法了,A值策略和V值策略,但是之前好像分布的是A值的价值函数,但是V值也是价值函数,我们这里的A值返回的是策略(动作的概率),
详细的修改,类似于前面的duel的网络,这里Actor类似于前面的动作优势函数,V值表示状态的价值函数
梯度
注意这里的梯度有两个,一个是action的prob,一个是value, value直接使用了mse的损失函数,动作函数使用了真实的reward,还有熵损失
细节一:adv_v = vals_ref_v - value_v.detach(), 这里使用了detach,是为了不将这里的计算引入到value的损失函数中去
细节二: 这里减去了value,就是我们的价值函数了
细节三: entropy loss是用来改善探索的
optimizer.zero_grad()
logits_v, value_v = net(states_v)
loss_value_v = F.mse_loss(value_v.squeeze(-1), vals_ref_v)
log_prob_v = F.log_softmax(logits_v, dim=1)
adv_v = vals_ref_v - value_v.detach()
log_prob_actions_v = adv_v * log_prob_v[range(BATCH_SIZE), actions_t]
loss_policy_v = -log_prob_actions_v.mean()
prob_v = F.softmax(logits_v, dim=1)
entropy_loss_v = ENTROPY_BETA * (prob_v * log_prob_v).sum(dim=1).mean()
# calculate policy gradients only
loss_policy_v.backward(retain_graph=True)
grads = np.concatenate([p.grad.data.cpu().numpy().flatten()
for p in net.parameters()
if p.grad is not None])
# apply entropy and value gradients
loss_v = entropy_loss_v + loss_value_v
loss_v.backward()
nn_utils.clip_grad_norm_(net.parameters(), CLIP_GRAD)
optimizer.step()
结果
我跑了2个多小时的情况下,完全没有收敛,原文中,前面的大半个小时也是完全不动的,原文说跑了三个多小时,而且用的是优化后的参数
参数优化
原文的超参,包括学习率 0.003 ,熵的beta 介于0.02和0.03之间,环境数40-70,批大小16,32,64
写在后面
我的电脑是因为效率太低了还是怎么滴,反正收敛速度非常慢,我一直怀疑我的电脑环境是不是有些库没有兼容好,有没有遇到过同样的问题的人帮我看看?