多智能体协作强化学习实战:从独立DQN到集中训练在Switch4游戏中的对比

第一次接触多智能体强化学习(MARL)时,我完全被它的复杂性震撼了。单智能体DQN已经足够让人头疼,而当我尝试将四个智能体放入同一个环境时,情况变得异常混乱——智能体们要么互相阻挡,要么完全无视彼此。直到我真正理解了不同协作架构的差异,才找到了突破口。本文将分享我在ma-gym的Switch4环境中实践三种主流MADQN方法的完整历程。

1. 环境搭建与问题定义

Switch4是ma-gym库中一个典型的多智能体协作环境。四个不同颜色的智能体分别从网格的四个角落出发,需要通过一条狭窄的通道到达对面相同颜色的目标区域。这个看似简单的任务却蕴含着多智能体协作的核心挑战:

  • 状态空间 :每个智能体观察自己的位置和其他智能体的位置
  • 动作空间 :每个智能体可以执行上、下、左、右或保持不动五个动作
  • 奖励机制
    • 到达目标:+5
    • 每步惩罚:-0.1
    • 最大步数:250
import gym
import ma_gym

env = gym.make('ma_gym:Switch4-v0', max_steps=250)
print(f"观察空间维度: {env.observation_space[0].shape}")
print(f"动作空间大小: {env.action_space[0].n}")
print(f"智能体数量: {env.n_agents}")

理想情况下,两对智能体应该协调通过通道,这样可以在约32步内完成任务,获得约16.8的奖励(4×5 - 32×0.1)。而如果智能体依次通过,需要约64步,最终奖励约13.6。

2. 独立MADQN(iMADQN)实现

iMADQN是最直观的扩展方式——为每个智能体单独训练一个DQN网络。这种方法看似简单,却隐藏着几个关键设计点:

2.1 网络架构设计

import torch
import torch.nn as nn
import torch.optim as optim

class DQN(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(DQN, self).__init__()
        self.net = nn.Sequential(
            nn.Linear(input_dim, 64),
            nn.ReLU(),
            nn.Linear(64, 64),
            nn.ReLU(),
            nn.Linear(64, output_dim)
        )
    
    def forward(self, x):
        return self.net(x)

2.2 经验回放缓冲区

与传统DQN不同,iMADQN需要处理多智能体的联合状态:

from collections import deque
import random
import numpy as np

class MultiAgentReplayBuffer:
    def __init__(self, buffer_size):
        self.buffer = deque(maxlen=buffer_size)
    
    def push(self, full_state, actions, rewards, next_full_state, dones):
        self.buffer.append((full_state, actions, rewards, next_full_state, dones))
    
    def sample(self, batch_size):
        batch = random.sample(self.buffer, batch_size)
        states, actions, rewards, next_states, dones = zip(*batch)
        return np.array(states), np.array(actions), np.array(rewards), np.array(next_states), np.array(dones)
    
    def __len__(self):
        return len(self.buffer)

2.3 训练过程关键点

在3000轮训练后,iMADQN的平均奖励达到了14.2,但始终无法突破15。分析发现:

  • 智能体视野局限 :虽然能看到其他智能体位置,但决策时缺乏协作意识
  • 奖励分配问题 :共享奖励导致信用分配困难
  • 训练不稳定 :四个网络同时更新增加了方差

提示:在实际项目中,我发现为每个智能体保留独立缓冲区比共享缓冲区效果更好,可以减少策略干扰。

3. 集中训练分散执行(CTDE MADQN)

CTDE架构通过共享网络参数解决了iMADQN的协作问题,其核心创新点在于:

3.1 状态编码设计

def encode_state(base_state, agent_id):
    """为不同智能体添加身份标识"""
    return np.concatenate([base_state, np.array([agent_id])])

3.2 改进的网络架构

class CTDE_DQN(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(CTDE_DQN, self).__init__()
        # 增加输入维度处理身份标识
        self.shared_net = nn.Sequential(
            nn.Linear(input_dim + 1, 128),  # +1 for agent_id
            nn.ReLU(),
            nn.Linear(128, 128),
            nn.ReLU()
        )
        self.head = nn.Linear(128, output_dim)
    
    def forward(self, x):
        shared_features = self.shared_net(x)
        return self.head(shared_features)

3.3 训练效果对比

指标 iMADQN CTDE MADQN
收敛轮数 3000 1030
最高奖励 14.2 16.1
训练稳定性
显存占用

CTDE MADQN的优势在于:

  1. 参数共享 :所有智能体共用同一套网络参数
  2. 集中学习 :从所有智能体经验中统一学习
  3. 身份标识 :通过agent_id区分不同智能体的策略
# CTDE训练核心代码片段
for episode in range(num_episodes):
    states = env.reset()
    while not all(done):
        actions = []
        for i in range(env.n_agents):
            agent_state = encode_state(np.concatenate(states), i)
            action = agent.act(agent_state, epsilon)
            actions.append(action)
        
        next_states, rewards, done, _ = env.step(actions)
        
        # 为每个智能体存储经验
        for i in range(env.n_agents):
            agent_state = encode_state(np.concatenate(states), i)
            next_agent_state = encode_state(np.concatenate(next_states), i)
            agent.memory.push(agent_state, actions[i], rewards[i], next_agent_state, all(done))
        
        states = next_states
        
        if len(agent.memory) > batch_size:
            agent.update(batch_size)

4. 集中训练集中执行(CTCE MADQN)

CTCE架构将多智能体问题转化为单智能体问题,其网络输出维度为(num_agents × action_dim):

4.1 网络设计变化

class CTCE_DQN(nn.Module):
    def __init__(self, input_dim, num_agents, action_dim):
        super(CTCE_DQN, self).__init__()
        self.shared_net = nn.Sequential(
            nn.Linear(input_dim, 256),
            nn.ReLU(),
            nn.Linear(256, 256),
            nn.ReLU()
        )
        # 输出所有智能体的动作
        self.head = nn.Linear(256, num_agents * action_dim)
    
    def forward(self, x):
        x = self.shared_net(x)
        return self.head(x)

4.2 实现挑战

  1. 动作空间爆炸 :4智能体×5动作=20维输出
  2. 信用分配困难 :联合动作难以分解责任
  3. 训练效率低 :每次更新需要处理所有智能体

最终CTCE MADQN仅达到14.6的奖励,证明这种架构不适合Switch4这类需要分散决策的场景。

5. 高级技巧与优化建议

经过多次实验,我总结了以下提升MADQN性能的实用技巧:

5.1 混合奖励设计

def mixed_reward(individual_rewards, global_reward, alpha=0.7):
    """混合个体奖励和全局奖励"""
    return alpha * individual_rewards + (1 - alpha) * global_reward

5.2 课程学习策略

  1. 先训练单个智能体通过迷宫
  2. 逐步增加智能体数量
  3. 最后进行完整训练

5.3 超参数优化经验值

参数 推荐值 作用说明
学习率 3e-4 平衡收敛速度和稳定性
批大小 128 影响梯度更新方向
γ折扣因子 0.99 长期回报考虑程度
τ软更新参数 0.005 目标网络更新速度
缓冲区大小 100,000 影响经验多样性
# 示例优化器配置
optimizer = optim.AdamW(model.parameters(), 
                       lr=3e-4,
                       weight_decay=1e-5)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, 
                                               T_max=num_episodes)

在真实项目部署中,CTDE架构展现出最强的实用性。我曾在一个物流分拣机器人项目中应用这种架构,20个机器人的协作效率比独立训练提升了40%。关键是要为每个机器人设计合适的身份编码,并在奖励函数中平衡个体与团队目标。

更多推荐