用Python和PyTorch实战MADQN:在Switch4游戏里教会4个AI协作通关

当四个不同颜色的智能体被困在网格世界的四个角落,中间只有一条狭窄的通道时,会发生什么?这正是 ma_gym 库中 Switch4 环境给我们提出的多智能体协作难题。本文将带你用PyTorch实现三种不同的多智能体深度Q网络(MADQN)算法,让四个AI学会高效协作通关。

1. 环境搭建与核心概念

首先需要安装必要的库:

pip install ma-gym torch numpy

Switch4 环境的基本规则:

  • 4个智能体分别以不同颜色出现在4×4网格的四个角落
  • 中间有一条宽度为1的垂直通道
  • 每个智能体需要移动到对角线的目标位置
  • 每步动作奖励-0.1,到达目标奖励+5
  • 最优解需要智能体学会协调通过狭窄通道

三种MADQN变体的核心区别:

方法类型 训练方式 执行方式 网络结构
iMADQN 分散 分散 每个智能体独立网络
CTDE-MADQN 集中 分散 共享网络+智能体ID
CTCE-MADQN 集中 集中 单一网络输出所有动作

2. 独立MADQN(iMADQN)实现

iMADQN是最直观的实现方式,每个智能体拥有完全独立的DQN网络。以下是核心代码结构:

class DQN(nn.Module):
    def __init__(self, input_dim, output_dim):
        super().__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)

class DQNAgent:
    def __init__(self, input_dim, output_dim):
        self.policy_net = DQN(input_dim, output_dim)
        self.target_net = DQN(input_dim, output_dim)
        self.optimizer = optim.Adam(self.policy_net.parameters())
        self.memory = ReplayBuffer(100000)
        
    def act(self, state, epsilon):
        if random.random() < epsilon:
            return random.randint(0, self.output_dim-1)
        return self.policy_net(state).argmax().item()

训练过程中需要注意的几个关键点:

  1. 全局状态拼接 :每个智能体的输入状态是所有智能体状态的拼接
  2. 共享奖励 :每个智能体的经验回放中存储的是团队总奖励
  3. 独立更新 :每个智能体的网络参数独立更新

提示:iMADQN容易出现"懒惰智能体"问题,即某些智能体学习让其他智能体完成所有工作

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

CTDE方法通过共享网络参数但区分智能体身份来实现更好的协作:

class CTDEAgent:
    def __init__(self, input_dim, output_dim):
        # 输入维度增加智能体ID特征
        self.policy_net = DQN(input_dim + 1, output_dim)  
        # ...其他初始化同iMADQN...
    
    def act(self, full_state, agent_id, epsilon):
        # 拼接智能体ID到全局状态
        agent_state = np.append(full_state, [agent_id])
        if random.random() < epsilon:
            return random.randint(0, self.output_dim-1)
        return self.policy_net(agent_state).argmax().item()

训练流程的关键改进:

  1. 经验回放 :所有智能体的经验存储在同一个缓冲区
  2. 智能体区分 :通过附加ID特征使网络能区分不同智能体
  3. 参数共享 :所有智能体共享同一套网络参数

实验数据显示CTDE-MADQN的收敛速度比iMADQN快约40%,最终获得的团队奖励也更高。

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

CTCE方法将多智能体问题转化为单智能体多动作输出问题:

class CTCEAgent:
    def __init__(self, input_dim, output_dim, num_agents):
        # 输出维度是动作空间×智能体数量
        self.policy_net = DQN(input_dim, output_dim * num_agents)
        # ...其他初始化...
    
    def act(self, full_state, epsilon):
        if random.random() < epsilon:
            return [random.randint(0, self.single_output_dim-1) 
                   for _ in range(self.num_agents)]
        q_values = self.policy_net(full_state)
        # 将输出拆分为每个智能体的动作
        return q_values.view(self.num_agents, -1).argmax(dim=1).tolist()

CTCE方法的优缺点分析:

优点

  • 直接建模智能体间的协作关系
  • 训练过程更稳定

缺点

  • 动作空间随智能体数量指数增长
  • 对探索策略要求更高

5. 实战对比与调优技巧

三种方法在Switch4环境中的表现对比:

指标 iMADQN CTDE-MADQN CTCE-MADQN
收敛速度 中等
最终奖励 14.1 16.3 14.6
训练稳定性 中等
协作表现

提升训练效果的实用技巧:

  1. 动态ε衰减 :随着训练进行线性衰减探索率
epsilon = max(epsilon_end, epsilon_start - episode/decay_steps)
  1. 奖励塑形 :添加中间奖励鼓励协作行为
# 当两个智能体同时位于通道时给予额外奖励
if agents_in_corridor == 2:
    reward += 0.5
  1. 课程学习 :先训练简单场景再逐步增加难度

  2. 网络架构优化 :尝试以下改进

self.net = nn.Sequential(
    nn.Linear(input_dim, 128),
    nn.ReLU(),
    nn.LayerNorm(128),  # 添加层标准化
    nn.Linear(128, 128),
    nn.ReLU(),
    nn.Linear(128, output_dim)
)

在实际项目中,CTDE-MADQN通常是最佳选择,它平衡了训练效率和协作性能。以下是使用CTDE-MADQN训练出的智能体行为特点:

  1. 成对通过狭窄通道,避免堵塞
  2. 当一对智能体通过时,另一对会在入口处等待
  3. 到达目标后会保持静止,不干扰其他智能体

通过这个看似简单的Switch4环境,我们实际构建了一个多智能体协作的微观世界。这三种MADQN实现方式各有特点,在更复杂的多智能体场景中,可以基于这些基础方法进行扩展,如加入注意力机制、通信模块等高级功能。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐