论文笔记

Multi-agent Actor-Critic for Mixed Cooperative-Competitive Environments

pytorch-maddpg在下面的场景中实现了MADDPG,所以就结合程序来说明MADDPG的原理和运行过程。

场景及设置介绍

论文笔记_第1张图片
运行场景

如上图,红点是毒药,蓝点和黑线都是捕猎者Pursuers,绿点为猎物Evaders,为蓝点的食物,青色的为障碍物Obstacles。图中两个蓝点需要学习合作策略,最大化共同的reward。

  1. Reward 设置如下:

    food_reward = 10.
    poison_reward = -1.
    encounter_reward = 0.01   //蓝点相遇时的reward,
    n_coop = 2   //表示需要训的合作的agent个数。
    

Reward为2x2的numpy.ndarray,个数为蓝点捕猎者的个数,在本场景中为2。
全局和局部的计算方法分别为:

   if self.reward_mech == 'global':
       rewards += (
           (len(ev_caught) * self.food_reward) + (len(po_caught) * self.poison_reward) +
           (len(ev_encounters) * self.encounter_reward))
   else:
       rewards[which_pursuer_caught_ev] += self.food_reward
       rewards[which_pursuer_caught_po] += self.poison_reward
       rewards[which_pursuer_encounterd_ev] += self.encounter_reward

全局:遇到#的次数 * # reward的总和。

局部:分别更新第一个或第二个蓝点的reward,遇到食物增加food_reward等。

  1. Action表示为2x2的FloatTensor,用于改变agent的速度和位置。

  2. 每一步的状态Obs由2x213的FloatTensor表示,为从环境中提取的各个agent的位置和速度等信息。环境的观测值由长度为2的list,用obs_表示,list中每个元素为numpy.ndarray,ndarray长度为213。

  3. Agent的网络结构定义为:

     class Actor(nn.Module):
       def __init__(self, dim_observation, dim_action):
       super(Actor, self).__init__()
       self.FC1 = nn.Linear(dim_observation, 500)
       self.FC2 = nn.Linear(500, 128)
       self.FC3 = nn.Linear(128, dim_action)
    
       # action output between -2 and 2
       def forward(self, obs):
       result = F.relu(self.FC1(obs))
       result = F.relu(self.FC2(result))
       result = F.tanh(self.FC3(result))
       return result
    

输入观察,输出动作。这也就是图中蓝点的网络,调用父类的初始化操作,使用pytorch默认的随机初始化方法。初始化之后就可以用到游戏当中。

  1. Critic的网络结构为:

     class Critic(nn.Module):
       def __init__(self, n_agent, dim_observation, dim_action):
         super(Critic, self).__init__()
         self.n_agent = n_agent
         self.dim_observation = dim_observation
         self.dim_action = dim_action
         obs_dim = dim_observation * n_agent
         act_dim = self.dim_action * n_agent
    
         self.FC1 = nn.Linear(obs_dim, 1024)
         self.FC2 = nn.Linear(1024+act_dim, 512)
         self.FC3 = nn.Linear(512, 300)
         self.FC4 = nn.Linear(300, 1)
    
         # obs: batch_size * obs_dim
         def forward(self, obs, acts):
         result = F.relu(self.FC1(obs))
         combined = th.cat([result, acts], 1)
         result = F.relu(self.FC2(combined))
         return self.FC4(F.relu(self.FC3(result)))
    

输入观察和动作,输出每个agent的Q值。也是使用随机初始化方法。这个网络在上图中不表示任何实物,因为它只在训练过程中出现,每个actor都有一个critic,收集所有agent的观察和动作,输出单个actor的Q值,用于更新actor。

训练

  1. 开始游戏

指定episode数目n_episode、每个episode最大steps max_steps、开始训练之前玩的局数episodes_before_train,初始化观测obs,total_reward,batch_size。
对一局游戏的每一个steps,根据Agent网络输出动作,根据动作得到reward。将动作前后的状态,动作本身,reward 即(x,x’,a,r) 都保存到reply buffer D用于接下来的训练(,)。当完成episodes_before_train局数,收集到足够的reply buffer后,就可以开始训练了。设置episodes_before_train是为了满足训练中minibatch的要求。
并且为了更好的探索动作,每个step,网络输出动作后增加一个随机过程。

  1. 训练过程
论文笔记_第2张图片
训练过程

对于每一个agent,从reply buffer D中随机抽取minibatch的S个(x,x’,a,r)的样本。
如图所示,输入到critic网络中,输出的Q值反馈给actor。

  • 目标函数

公式中的Q由上面提到的critic网络输出,r为单个agent即蓝点的reward。用于计算loss。

  • 更新critic的loss为:

程序中的实现为:

# 使用从D中取到某一个step的x和a,输出critic计算的Q值。
# 由于每个step都有一个Q和r值,程序中一个episode有max_steps = 1000,
# 所以Q和r都是1000 x 1的FloatTensor。 agent代表当前训练中的agent。
current_Q = self.critics[agent](whole_state, whole_action)  
# batch是从D中取到的四元组
non_final_mask = ByteTensor(list(map(lambda s: s is not None,batch.next_states)))
# 输入x’,a’使用critic计算出Q’,critics_target是前一step的critic
self.critics_target = deepcopy(self.critics)
target_Q[non_final_mask] = self.critics_target[agent](
non_final_next_states.view(-1, self.n_agents * self.n_states),
non_final_next_actions.view(-1,self.n_agents * self.n_actions))
# self.GAMMA = 0.95, scale_reward: to scale reward in Q functions.
# reward_batch中存的是两个蓝点1000步的reward,是1000 x 2的FloatTensor
target_Q = (target_Q * self.GAMMA) + (reward_batch[:, agent] * scale_reward)
# torch.nn.MSELoss() 为平方损失函数,detch返回新的Variable,使其跟以前的Q
# 分离
loss_Q = nn.MSELoss()(current_Q, target_Q.detach())
  • Actor接收到Q值后,结合本身的网络计算策略梯度用于优化参数:


    程序中处理如下:

     actor_loss = -self.critics[agent](whole_state, whole_action)
     actor_loss = actor_loss.mean()
     actor_loss.backward()
     self.actor_optimizer[agent].step()
    

Critic和actor更新参数的部分写在MADDPG类的update_policy()中,主函数中每执行一个step,就会调用一次,每一步都会更新参数并保存critic前一个step的参数,用于计算loss。

  • 对每个agent都完成上述操作后,防止θ更新太快,做一些微调:

然后重新开始一局,让agent用现在已更新的网络加上随机化过程来选择动作,对一局中的每个step,存储(x,x’,a,r),然后对每个agent做上述(1)-(4)的操作。反复训练,直到达到合适的效果,让两个蓝点学会竞争合作,就可以使用训练好的模型来玩游戏了。

你可能感兴趣的:(论文笔记)