多智能体强化学习(二)MAPPO算法详解

更新时间:2023-07-13 23:07:13 阅读: 评论:0

多智能体强化学习(⼆)MAPPO 算法详解
⽂章⽬录  MAPPO 论⽂全称为:The Surprising Effectiveness of MAPPO in Cooperative, Multi-Agent Games
  这篇⽂章属于典型的,我看完我也不知道具体是在哪⾥创新的,是不是我漏读了什么,是不是我没有把握住,论⽂看⼀半直接看代码去了,因此后半截会有⼀段代码的解析。其实⼯作更多的我觉得是⼯程上的trick ,思想很简单,暴⼒出奇迹。多智能体的合作和协同完全体现在对于观测空间的穷举。
  这篇⽂章更多的提出的是⼀些⼯程上的trick ,并且有较详细对⽐协作式多智能体的⼀些⽂章。
  多智能体强化学习算法⼤致上可以分为两类,中⼼式和分散式。中⼼式的思想是考虑⼀个合作式的环境,直接将单智能体算法扩展,让其直接学习⼀个联合动作的输出,但是并不好给出单个智能体该如何进⾏决策。分散式是每个智能体独⽴学习⾃⼰的奖励函数,对于每个智能体来说,其它智能体就是环境的⼀部分,因此往往需要去考虑环境的⾮平稳态。并且分散式学习到的并不是全局的策略。  最近的⼀些⼯作提出了两种框架连接中⼼式和分散式这两种极端⽅法,从⽽得到折衷的办法:中⼼式训练分散式执⾏(centealized training and decentralized execution CTDE )和值分解(value decomposition VD )。  CETD 的⽅式通过学习⼀个全局的Critic 来减少值函数的⽅差,这类⽅法的代表作有MADDPG 和COMA ;VD 通过对局部智能体的Q 函数进⾏组合来得到⼀个联合的Q 函数。  MAPPO 采⽤⼀种中⼼式的值函
数⽅式来考虑全局信息,属于CTDE 框架范畴内的⼀种⽅法,通过⼀个全局的值函数来使得各个单个的PPO 智能体相互配合。它有⼀个前⾝IPPO ,是⼀个完全分散式的PPO 算法,类似IQL 算法。  MAPPO 中每个智能体基于局部观测和⼀个共享策略(这⾥的共享策略是针对智能体是同类型的情况⽽⾔的,对于⾮同类型的,可以拥有⾃⼰独⽴的actor 和critic ⽹络)去⽣成⼀个动作来最⼤化折扣累积奖励:。基于全局的状态来学习⼀个中⼼式的值函数。
PPO 实战技巧
火影忍者的片尾曲  对于单个智能体来说,PPO 中实战的技巧也都有采⽤过来:
1. Generalized Advantage Estimation :这个技巧来⾃⽂献:Hign-dimensional continuous control using generalized advantage estimation。
2. Input Normalization
3. Value Clipping :与策略截断类似,将值函数进⾏⼀个截断。
4. Relu activation with Orthogonal Initialization :
5. Gredient Clipping :梯度更新不要太⼤。
6. Layer Normalization :这个技巧来⾃⽂献:Regularization matters in policy optimization-an empirical study on continuous control。
7. Soft Trust-Region Penalty :这个技巧来⾃⽂件:Revisiting design choices in proximal policy optimization。
MAPPO 算法伪代码详解  MAPPO 算法的伪代码如下所⽰:
  也就是说有两个⽹络,策略和值函数。(作者在⽂献附录中有谈到说如果智能体是同种类的就采⽤相同的⽹络参数,对于每个智能体内部也可以采⽤各⾃的actor 和critic ⽹络,但是作者为了符号的便利性,直接就⽤的⼀个⽹络参数来表⽰)。值函数需要学习⼀个映射:。策略函数学习⼀个映射从观测到⼀个范围的分布或者是映射到⼀个⾼斯函数的动作均值和⽅差⽤于之后采样动作。i o i π(a ∣o )θi i a i J (θ)=E γR s ,a a ,s t t [∑t t (t t )]s V (s )ϕπθV ϕV ϕS →R πθo t (a )
Actor ⽹络优化⽬标为:
  其中优势函数是采⽤GAE ⽅法的,表⽰策略的熵,是控制熵系数的⼀个超参数。
Critic ⽹络优化⽬标为:  其中是折扣奖励。表⽰batch_size 的⼤⼩,表⽰智能体的数量。MAPPO 实战技巧
1. Value Normalization:  PopArt 这个算法本来是⽤来处理多任务强化学习算法中,不同任务之间的奖励不⼀样的这样⼀个问题。例如,在吃⾖⼈(Ms. Pac-Man )游戏中,智能体的⽬标是收集⼩球,收集⼀颗奖励10 分,⽽吃掉幽灵则奖励200到1600分,这样智能体对于不同任务就会有偏重喜好。MAPPO 中采⽤这个技巧是⽤来稳定Value 函数的学习,通过在Value Estimates 中利⽤⼀些统计数据来归⼀化⽬标,值函数⽹络回归的⽬标就是归⼀化的⽬标值函数,但是当计算GAE 的时候,⼜采⽤反归⼀化使得其放⼤到正常值。
  这个技巧来⾃⽂献:Multi-task Deep Reinforcement Learning with popart 。
2. Agent-Specific Global State:
  对于多智能体算法⽽⾔,⼤部分的⼯作都在处理值函数这⼀块,因为⼤部分算法都是通过值函数来实现各个⼦智能体的相互配合。值函数的输⼊通常也是直接给全局的状态信息使得⼀个部分可观测马尔可夫决策问题(POMDP )转化为了⼀个马尔可夫决策问题(MDP )。  Multi-agent actor-critic for mixed cooperative-competitive environment 中提出将所有智能体地局部观测信息拼接起来作为Critic 的输⼊,存在的问题就是智能体数量太多之后,尤其是值函数的输⼊维度远⾼于策略函数的输⼊维度的时候,会使得值函数的学习变得更加困难。  SMAC 环境有提供⼀个包含所有智能体和敌⽅的全局信息,但是这个信息并不完整。虽然每个智能体的局部信息中会缺失敌⽅的信息,但是会有⼀些智能体
特有的信息,像智能体的ID 、可选动作、相对距离等等,这些在全局状态信息中是没有的。因此作者构建了⼀个带有智能体特征的全局状态信息,包含所有的全局信息和⼀些必须的局部智能体特有的状态特征。
3. Training Data Usage:
  通常训练单个智能体的时候,我们会将数据切分成很多个mini-batch ,并且在⼀个epoch 中将其多次训练来提⾼数据的利⽤效率,但是作者在实践中发现,可能是由于环境的⾮平稳态问题,如果数据被反复利⽤训练的话效果会不太好,因此建议对于简单的task ⽤15个epoch ,⽐较困难的任务⽤10个或者5个epoch ,并且不要将数据切分成多个mini-batch 。当然也不是绝对的,作者说到了对于SMAC 中的⼀个环境,将数据切分成两个mini-batch 的时候有提⾼性能,对此作者给出了解释说有帮助跳出局部最优,还引⽤了⼀篇参考⽂献。这⼀波说辞不是⾃相⽭盾么。。。。
4. Action Masking:
turfL (θ)=min r A ,clip r ,1−ϵ,1+ϵA [Bn 1∑i =1B ∑k =1n (θ,i (k )i (k )(θ,i (k ))i (k )
)]+σS πo , where r =.Bn 1∑i =1B ∑k =1n [θ(i (k )))]θ,i (k )πa ∣o θold (i (k )i (k ))πa ∣o θ(i (k )i (k ))A i (k )
S σL (ϕ)=max V s −,Bn
1∑i =1B ∑k =1n ([(ϕ(i (k ))R ^i )2clip V s ,V s −ε,V s +ε−((ϕ(i (k ))ϕold (i (k ))ϕold (i (k )))R ^i )2
]R
^i B n s o ,…,o (1n )
  由于游戏规则的限制,在某些情况下,某些动作就是不允许被执⾏。当计算动作概率的时候,我们将不被允许的动作直接mask 掉,这样在前向和反向传播的过程中,这些动作将永远为0,作者发现这种做法能够加速训练。
5. Death Masking:
  如果智能体死掉了的话,在Agent-Specific 特征中直接⽤⼀个0向量来描述即可。代码解析
MAPPO 官⽅代码链接:/marlbenchmark/on-policy 。
总体理解
  每个局部智能体接收⼀个局部的观察obs ,输出⼀个动作概率,所有的actor 智能体都采⽤⼀个actor
⽹络。critic ⽹络接收所有智能体的观测obs ,其中为智能体的个数,输出为⼀个值,这个值⽤于actor 的更新。actor 的loss 和PPO 的loss 类似,有添加⼀个熵的loss 。Critic 的loss 更多的是对value 的值做normalizer ,并且在计算episode 的折扣奖励的时候不是单纯的算折扣奖励,有采⽤gae 算折扣回报的⽅式。
⽹络定义
  代码定义在onpolicy/algorithms/r_mappo/algorithm/rMAPPOPolicy.py
  每⼀个智能体的观测obs_space 为⼀个14维的向量,有两个智能体,cent_obs_space 为⼀个28纬的向量,单个智能体的动作空间act_space 为⼀个离散的5个维度的向量。
1. actor
  输⼊⼀个观测,14维度,输出⼀个确切的动作actions 和这个动作对数概率,这部分代码在onpolicy/algorithms/utils/act.py 中。action_dim = action_space .n
lf .action_out = Categorical (inputs_dim , action_dim , u_orthogonal , gain )
landeraction_logits = lf .action_out (x , available_actions )
actions = action_logits .mode () if  deterministic el  action_logits .sample ()
action_log_probs = action_logits .log_probs (actions )2. critic
  critic 输⼊维度为。输出是⼀个特征值向量,也就是输出纬度为1。采样流程
初始化初始的观测
  实例化5个环境:
# all_args.n_rollout_threads
SubprocVecEnv ([get_env_fn (i ) for  i in  range (all_args .n_rollout_threads )])
  如果采⽤centralized_V 值函数的训练⽅式,则需要初始化的时候构造出多个智能体的share_obs :
obs = lf .envs .ret ()  # shape = (5, 2, 14)share_obs = obs .reshape (lf .n_rollout_threads , -1)  # shape = (5, 28)
# 指定两个智能体
share_obs = np .expand_dims (share_obs , 1).repeat (lf .num_agents , axis =1) # shape = (5, 2, 28)
  share_obs 中会将个智能体的obs 叠加在⼀起作为share_obs 。
supervisorcollect()采⽤rollout⽅式采样数据
πa ∣o θ(i i )cent _obs _space =n ×obs _space n V V cent _obs _space =n ×obs _space =28n =2
  调⽤lf.trainer.prep_rollout()函数将actor和critic都设置为eval()格式。然后⽤np.concatenate()函数将并⾏的环境的数据拼接在⼀起,这⼀步是将并⾏采样的那个纬度降掉:
value, action, action_log_prob, rnn_states, rnn_states_critic \
= lf._atenate(lf.buffer.share_obs[step]),
  上⾯的代码就是将数据传⼊总的MAPPO策略⽹络R_MAPPOPolicy(onpolicy/algorithms/r_mappo/algorithm/rMAPPOPolicy.py)中去获取⼀个时间步的数据。在get_actions()函数⾥⾯会调⽤actor去获取动作和动作的对数概率,critic⽹络去获取对于cent_obs的状态值函数的输出:
actions, action_log_probs, rnn_states_actor = lf.actor(obs,
rnn_states_actor,
澳大利亚留学满足条件有什么
masks,
available_actions,
deterministic)
  obs这⾥的shape是(5*2, 14),输出actions的shape, 和action_log_probs的shape都为(10 , 1)。
values, rnn_states_critic = lf.critic(cent_obs, rnn_states_critic, masks)
  cent_obs的shape是(5*2, 28),输出是shape=(10, 1)。
  最后将(10 , 1)的actions转换成(5, 2, 1)的形式,⽅便之后并⾏送到并⾏的环境中去,作者这⾥还将动作进⾏了one-hot编码,最后变成了(5, 2, 5)的形式送⼊到环境中去。
obs, rewards, dones, infos = lf.envs.step(actions_env)
data = obs, rewards, dones, infos, values, actions, action_log_probs, rnn_states, rnn_states_critic
# inrt data into buffer
lf.inrt(data)
  环境下⼀次输出的obs还是(5, 2, 14)的形式,之后调inrt⽅法将数据添加到buffer⾥⾯,在inrt⽅法⾥⾯会将局部观测构造⼀个全局观测share_obs其shape=(5, 2, 28)出来:
def inrt(lf, data):
obs, rewards, dones, infos, values, actions, action_log_probs, rnn_states, rnn_states_critic = data
rnn_states[dones ==True]= np.zeros(((dones ==True).sum(), lf.recurrent_N, lf.hidden_size), dty
pe=np.float32)
rnn_states_critic[dones ==True]= np.zeros(((dones ==True).sum(),*_states_critic.shape[3:]), dtype=np.float32)
masks = np.ones((lf.n_rollout_threads, lf.num_agents,1), dtype=np.float32)
masks[dones ==True]= np.zeros(((dones ==True).sum(),1), dtype=np.float32)
if lf.u_centralized_V:
share_obs = shape(lf.n_rollout_threads,-1)
layers gate
share_obs = np.expand_dims(share_obs,1).repeat(lf.num_agents, axis=1)
el:
share_obs = obs
lf.buffer.inrt(share_obs, obs, rnn_states, rnn_states_critic, actions, action_log_probs, values, rewards, masks)
  上述过程循环迭代lf.episode_length=200次。
训练流程
计算优势函数
  训练开始之前,⾸先调⽤lf.compute()函数计算这个episode的折扣回报,在计算折扣回报之前,先算这个episode最后⼀个状态的状态值函数next_values,其shape=(10, 1)然后调⽤compute_returns函数计算折扣回报:
def compute(lf):
dumbledore"""Calculate returns for the collected data."""
the avengersnext_values = lf._atenate(lf.buffer.share_obs[-1]),
next_values = np.array(np.split(_t2n(next_values), lf.n_rollout_threads))
pute_returns(next_values, lf.trainer.value_normalizer)
  有了数据之后就可以开始计算折扣回报了(这⾥有采⽤gae算折扣回报的⽅式,并且有将value做normalizer)。compute_returns函数在onpolicy/utils/shared_buffer.py⽂件中,核⼼代码如下:
lf.value_preds[-1]= next_value
for step in reverd(wards.shape[0])):
delta = lf.rewards[step]+ lf.gamma * value_normalizer.denormalize(
lf.value_preds[step +1])* lf.masks[step +1] \
- value_normalizer.denormalize(lf.value_preds[step])
gae = delta + lf.gamma * lf.gae_lambda * lf.masks[step +1]* gae
  算完折扣回报之后调⽤lf.train()函数进⾏训练:
def train(lf):
"""Train policies with data in buffer. """
train_infos = ain(lf.buffer)
lf.buffer.after_update()# 将buffer的第⼀个元素设置为其episode的最后⼀个元素
return train_infos
nasa mars  在ain(lf.buffer)函数中先基于数据,计算优势函数(优势函数是针对全局的观测信息所得到的):
advantages =urns[:-1]- lf.value_normalizer.denormalize(buffer.value_preds[:-1])
advantages_copy = py()英孚培训
advantages_copy[buffer.active_masks[:-1]==0.0]= np.nan
mean_advantages = np.nanmean(advantages_copy)# float, shape = (1)
std_advantages = np.nanstd(advantages_copy)# float, shape = (1)
advantages =(advantages - mean_advantages)/(std_advantages +1e-5)
  然后从buffer中采样数据,把线程、智能体的纬度全部降掉(onpolicy/algorithms/r_mappo/r_mappo.py):
share_obs_batch, obs_batch, rnn_states_batch, rnn_states_critic_batch, actions_batch, \
value_preds_batch, return_batch, masks_batch, active_masks_batch, old_action_log_probs_batch, \
adv_targ, available_actions_batch = sample
  拿到采样之后的数据,把obs送给actor⽹络,得到action_log_probs, dist_entropy。把cent_obs送到critic得到新的values。
计算actor的loss
  有了新⽼动作的概率分布和优势函数之后就可以更新actor⽹络了:
# actor update
imp_weights = p(action_log_probs - old_action_log_probs_batch)
surr1 = imp_weights * adv_targ
surr2 = torch.clamp(imp_weights,1.0- lf.clip_param,1.0+ lf.clip_param)* adv_targ
policy_action_loss =(-torch.sum(torch.min(surr1, surr2),
dim=-1,
keepdim=True)* active_masks_batch).sum()/ active_masks_batch.sum()
(policy_loss - dist_entropy * lf.entropy_coef).backward()
计算critic的loss

本文发布于:2023-07-13 23:07:13,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/176568.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:智能   函数   信息
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图