最近更新的比较慢,因为需要处理的事务太多,而且也想不好的选题。想到之前写过一期 让 DQN 玩个锤子试试,这次准备再写一篇强化学习的拓展文章。也是因为之前刷到国外大佬写的倒车入库的强化学习视频,一直想着复现,它是基于 Unity 开发的,好不容易把 Unity 装起来,才发现他的素材还要付费,就没再继续往下做了,我还是基于 OpenAI 的 Gym 玩玩免费的好了。
这次玩的是 PPO 算法,近端策略梯度算法,收敛会比较稳定,不会向 DDPG 那样难以收敛,而且,我一直觉得 DDPG 有点笨重了,使用 PPO 算法,甚至 Double DQN 都能解决大部分场景,虽然 DQN 不太适合连续动作空间的场景。
PPO 算法是 OpenAI 在 2017 年提出的算法。网上争议比较大的是:PPO 是属于 On-Policy 还是 Off-Policy,如果去搜会发现两种答案都有,实际 PPO 也都支持这两种模式,但从大部分实现的代码来看,基本都属于 Off-Policy。
而离线策略的优势是显而易见的,不需要过多的环境数据,采用小批量更新,减少采样频率。
我这里将的 PPO,实际上是 PPO2。PPO1 是 DeepMind 提出的,用 KL 散度控制裁剪幅度,而 PPO2 优化后根据 clip 函数控制裁剪幅度,当优势 A > 0 时,决定其上界,当 A < 0 时,决定其下届,简单粗暴。
PPO 的网络结构比较简单,只有一组 Actor-Critic,而 DDPG 有两组 AC,结构的简单也意味着收敛速度的提高。
class ActorCritic(nn.Module):
def __init__(self, state_dim, action_dim, has_continuous_action_space, action_std_init):
super(ActorCritic, self).__init__()
self.has_continuous_action_space = has_continuous_action_space
if has_continuous_action_space:
self.action_dim = action_dim
self.action_var = torch.full((action_dim,), action_std_init * action_std_init).to(device)
# Actor
if has_continuous_action_space:
self.actor = nn.Sequential(
nn.Linear(state_dim, 64),
nn.Tanh(),
nn.Linear(64, 64),
nn.Tanh(),
nn.Linear(64, action_dim),
nn.Tanh()
)
else:
self.actor = nn.Sequential(
nn.Linear(state_dim, 64),
nn.Tanh(),
nn.Linear(64, 64),
nn.Tanh(),
nn.Linear(64, action_dim),
nn.Softmax(dim=-1)
)
# Critic
self.critic = nn.Sequential(
nn.Linear(state_dim, 64),
nn.Tanh(),
nn.Linear(64, 64),
nn.Tanh(),
nn.Linear(64, 1)
)
代码参考了 Nikhil Barhate 大佬的 PPO-PyTorch,可以看到他还对连续和离散动作空间的输出做了兼容处理。
class PPO:
def __init__(self, state_dim, action_dim, lr_actor, lr_critic, gamma, K_epochs, eps_clip,
has_continuous_action_space, action_std_init=0.6):
self.has_continuous_action_space = has_continuous_action_space
if has_continuous_action_space:
self.action_std = action_std_init
self.gamma = gamma
self.eps_clip = eps_clip
self.K_epochs = K_epochs
self.buffer = ReplayBuffer()
self.policy = ActorCritic(state_dim, action_dim, has_continuous_action_space, action_std_init).to(device)
self.optimizer = torch.optim.Adam([
{'params': self.policy.actor.parameters(), 'lr': lr_actor},
{'params': self.policy.critic.parameters(), 'lr': lr_critic}
])
self.policy_old = ActorCritic(state_dim, action_dim, has_continuous_action_space, action_std_init).to(device)
self.policy_old.load_state_dict(self.policy.state_dict())
self.MseLoss = nn.MSELoss()
尝试了用 PPO 算法训练 RoboschoolWalker2d,小人行走。为了能够直观的看到强化学习的训练过程,我将过程截取录屏,能够看到一个从不会站立的小人,逐渐成长为能够勇敢迈出第一步到最后健步如飞的样子。
这里我把这小人的整个强化学习训练过程直观的录成了视频,一起见证一下他的成长吧!
我想,每个人的成长过程也是与这个小人无二的,都是一次次跌倒,又一次次站起,只要有信念,困难就会成为我们的垫脚石,而非绊脚石!继续努力前行吧!
参考链接:
https://arxiv.org/pdf/1707.06347.pdf
https://di-engine-docs.readthedocs.io/en/latest/12_policies/ppo.html
https://blog.csdn.net/BruceXee/article/details/128486224
https://zhuanlan.zhihu.com/p/670659452
https://blog.csdn.net/fangchenglia/article/details/125725093