前言
本文讲解多智能体强化学习(Multi-agent Reinforcement Learning,MARL)中最最经典的一篇论文MADDPG,以及它的复现,超详细的!大家往下看吧~
MADDPG的论文链接如下:
[1706.02275] Multi-Agent Actor-Critic for Mixed Cooperative-Competitive Environments (arxiv.org)
这篇文章需要有一些单智能体的先验知识,可参考之前的文章:
1. MADDPG模型介绍
MADDPG算法以DDPG为基础,提出了一种集中式训练分布式执行的多智能体深度强化学习算法,本方法既可以应用于包含通信信道的协作场景,也可以应用于智能体之间只存在物理交互的竞争性场景中。
- 场景:环境部分可观、完全协作(共用同一奖励)/竞争(目标相互冲突)
- 训练方法:集中训练、分布执行(CTDE)
- 研究点:研究协作或协作竞争混合场景下的多智能体深度强化学习算法算法
- 创新点:提出了一种actor-critic方法的适应,考虑其他智能体的行动策略,并能成功地学习需要复杂多智能体协调的策略
1.1 模型框架
MADDPG的模型框架如下:
如上图,在MADDPG的框架中,每个智能体都需要学习一个Actor网络与一个Q网络,其中Q网络在训练阶段接收所有智能体的观测所组成的环境信息X,以及所有智能体的动作作为输入,以此集中式地计算该智能体的动作-价值函数;而Actor网络则以智能体的局部观测为输入,输出其动作。由于每个智能体都会单独学习一个Q值,因此每个智能体都能够设计任意属于自己的奖励。
MADDPG算法基于以下几个基本的约束:
- 每个智能体在执行的动作的过程中,只能根据自己的局部观测计算出动作值;
- 不考虑环境动力学微分方程模型;
- 不考虑智能体之间特定的通信协议或者方法。
基于上述约束,为各个模块设计目标函数并计算梯度。
在图中,表示N个智能体的策略,分别由的N个Actor网络来拟合。在DDPG算法中,目标函数的定义为:
其策略梯度为:
其中,D表示数据集,在MADDPG中定义每个智能体的目标函数为:
对每个智能体的策略梯度可由下式计算:
梯度的计算思路是一样的,本质上就是梯度计算的链式法则,只是在实际操作的过程中,actor网络和critic网络的更新是分开的。
注意:在计算 Q 函数时,要将所有智能体的观测和动作值都作为输入,即 o 和 a 。否则,信息不全,计算出来的Q值就会不准确,导致训练过程不稳定。这就是“集中式训练”的关键所在。
1.2 模型扩展
本文还提出了MADDPG的两种扩展模式:
1.2.1 预测其它智能体的策略
原始MADDPG中,每个智能体的Q网络均需要接收所有智能体的动作(策略)作为输入,此时每个智能体 可以通过对其他智能体的策略进行估计而替代其他智能体 真实的策略,即除了学习Actor网络和Q网络之外,还需要学习其余所有智能体策略的估计,使用一个熵正则化器
其中,H是策略分布的熵,可以用下式计算近似值来替代:
1.2.2 从单一策略优化到策略集优化
为了进一步增强模型应对敌对智能体策略改变所导致的环境非平稳性,作者提出每个智能体可以训练得到由 K 个不同子策略组成的策略集合,即每个智能体的策略 是K个不同子策略的组合,每个子策略都拥有一个经验回访池,单独训练。对智能体 ,其目标函数就可以改成:
表示子策略索引集,相应的策略梯度可改写为:
1.3 结论&模型缺点
本文将DDPG算法扩展到多智能体强化学习中,通过“集中式训练分布式执行”的思路,计算出每个智能体的最优策略。该算法中智能体根据所有智能体的观察和动作学习一个集中的critic。在多种合作和竞争的多智能体环境下,该方法优于传统的RL算法。我们可以通过集合策略来训练智能体来进一步提高我们方法的性能。
缺点是当智能体数量比较大的时候,Q网络的输入空间随着智能体数目线性增加,无法扩展到大规模智能体系统中。
2. MADDPG模型复现
2.1 MPE环境安装
MPE(Multi-Agent Particle Environment)是由 OpenAI 开源的一款多智能体强化学习实验平台,以 OpenAI 的 gym 为基础,使用 Python 编写而成。它创造了一个简单的多智能体粒子世界,粒子们可以进行连续的观察和离散的动作。
2.1.1 前期准备
- 在GitHub网站下载MPE的安装包:github.com/openai/mult…
- 安装anaconda,通过conda创建虚拟环境,好处是便于创建我们需要的不同版本的python环境,很方便,不用重复安装不同版本的python
- conda虚拟环境配置如下(常用命令):
查看安装了哪些包:conda list
查看存在哪些虚拟环境:conda env list
Python创建虚拟环境:conda create -n your_env_name python=x.x
激活虚拟环境:source activate your_env_name
查看当前Python版本:python --version
安装相应的包:conda install package_name=x.xx
或者pip install package_name==x.xx
关闭虚拟环境:conda deactivate
2.1.2 MPE安装环境要求
下载 Multi-Agent Particle Environment 源码,阅读 README.md 可知需要先配置:
- python(3.5.4),openAI gym(0.10.5),tensorflow(1.8.0),numpy(1.14.5)
2.1.3 开始安装
在 Pycharm 自带的 terminal 或进入 cmd,打开终端,将路径cd到multiagent-particle-envs文件夹下(即含有setup.py文件的文件夹下)执行pip install -e .
(不要忽略这个“.”)
multiagent环境安装完成。
同样的,将路径再cd到maddpg文件夹下(即含有setup.py文件的文件夹下),执行pip install -e .
(不要忽略这个“.”)。maddpg安装完成。
2.2 环境测试
安装完成后,输入测试命令
-
cd到/maddpg/experiments文件夹下:
cd experiments
-
运行train.py文件,默认环境为simple先在该目录下进行切换:
python train.py --scenario simple
第一遍运行的时候,训练只会出现训练数据,如下:
第一遍运行没有动画,运行完毕,如果报错:
直接修改下格式就好:修改train.py第182行为
rew_file_name = str(arglist.plots_dir) + str(arglist.exp_name) +'_rewards.pkl'
第185行为
agrew_file_name = str(arglist.plots_dir) + str(arglist.exp_name) +'_agrewards.pkl'
运行第二遍,输入:python train.py --scenario simple --display
,就可以进行可视化,如下图:
2.3 核心代码解读
Actor-Critic结构
- 给Actor输入环境的观察值obs,输出的就是动作;
- 把Actor输出的动作和对应的环境的观察值obs输入给Critir,最后输出Q值。
# Actor
def predict(self, obs):
""" input:
obs: observation, shape([B] + shape of obs_n[agent_index])
output:
act: action, shape([B] + shape of act_n[agent_index])
"""
this_policy = self.model.policy(obs)
this_action = SoftPDistribution(
logits=this_policy,
act_space=self.act_space[self.agent_index]).sample()
return this_action
def predict_next(self, obs):
""" input: observation, shape([B] + shape of obs_n[agent_index])
output: action, shape([B] + shape of act_n[agent_index])
"""
next_policy = self.target_model.policy(obs)
next_action = SoftPDistribution(
logits=next_policy,
act_space=self.act_space[self.agent_index]).sample()
return next_action
# Critic
def Q(self, obs_n, act_n):
""" input:
obs_n: all agents' observation, shape([B] + shape of obs_n)
output:
act_n: all agents' action, shape([B] + shape of act_n)
"""
return self.model.value(obs_n, act_n)
def Q_next(self, obs_n, act_n):
""" input:
obs_n: all agents' observation, shape([B] + shape of obs_n)
output:
act_n: all agents' action, shape([B] + shape of act_n)
"""
return self.target_model.value(obs_n, act_n)
这一部分描述了Actor具体怎么输出动作,以及Critir怎么打分。
Actor网络的参数更新
以下代码体现的是多个Actor网络的更新:
def _actor_learn(self, obs_n, act_n):
i = self.agent_index
this_policy = self.model.policy(obs_n[i])
sample_this_action = SoftPDistribution(
logits=this_policy,
act_space=self.act_space[self.agent_index]).sample()
action_input_n = act_n + []
action_input_n[i] = sample_this_action
eval_q = self.Q(obs_n, action_input_n)
act_cost = layers.reduce_mean(-1.0 * eval_q)
act_reg = layers.reduce_mean(layers.square(this_policy))
cost = act_cost + act_reg * 1e-3
fluid.clip.set_gradient_clip(
clip=fluid.clip.GradientClipByNorm(clip_norm=0.5),
param_list=self.model.get_actor_params())
optimizer = fluid.optimizer.AdamOptimizer(self.lr)
optimizer.minimize(cost, parameter_list=self.model.get_actor_params())
return cost
MADDPG算法核心
MADDPG算法是对DDPG算法为适应多Agent环境的改进,最核心的部分就是每个Agent的Critic部分能够获取其余所有Agent的动作信息,进行中心化训练和非中心化执行,即在训练的时候,引入可以观察全局的Critic来指导Actor训练,而测试的时候只使用有局部观测的actor采取行动。
def learn(self, agents):
self.global_train_step += 1
# only update parameter every 100 steps
if self.global_train_step % 100 != 0:
return 0.0
if self.rpm.size() <= self.min_memory_size:
return 0.0
batch_obs_n = []
batch_act_n = []
batch_obs_new_n = []
rpm_sample_index = self.rpm.make_index(self.batch_size)
for i in range(self.n):
batch_obs, batch_act, _, batch_obs_new, _ \
= agents[i].rpm.sample_batch_by_index(rpm_sample_index)
batch_obs_n.append(batch_obs)
batch_act_n.append(batch_act)
batch_obs_new_n.append(batch_obs_new)
_, _, batch_rew, _, batch_isOver \
= self.rpm.sample_batch_by_index(rpm_sample_index)
# compute target q
target_q = 0.0
target_act_next_n = []
for i in range(self.n):
feed = {'obs': batch_obs_new_n[i]}
target_act_next = agents[i].fluid_executor.run(
agents[i].next_a_program, # 每个Agent单独采样
feed=feed,
fetch_list=[agents[i].next_action])[0]
target_act_next_n.append(target_act_next)
feed_obs = {'obs' + str(i): batch_obs_new_n[i] for i in range(self.n)}
feed_act = {'act' + str(i): target_act_next_n[i]for i in range(self.n)}
feed = feed_obs.copy()
feed.update(feed_act) # merge two dict
target_q_next = self.fluid_executor.run(
self.next_q_program, # 可以观测全局的Critic的目标网络,专门用来稳定Q_target
feed=feed,
fetch_list=[self.next_Q])[0]
target_q += (
batch_rew + self.alg.gamma * (1.0 - batch_isOver) * target_q_next)
feed_obs = {'obs' + str(i): batch_obs_n[i] for i in range(self.n)}
feed_act = {'act' + str(i): batch_act_n[i] for i in range(self.n)}
target_q = target_q.astype('float32')
feed = feed_obs.copy()
feed.update(feed_act)
feed['target_q'] = target_q
critic_cost = self.fluid_executor.run(
self.learn_program, # 训练可以观测全局的Critic
feed=feed,
fetch_list=[self.critic_cost])[0]
self.alg.sync_target()
return critic_cost
总结
以上就是MADDPG算法的所有内容啦,喜欢的不要忘记一键三连呐~