基于MADDPG的多无人机协同围捕:从算法原理到PyTorch实战
发布时间:2026/9/5 20:39:25来源:尧图网络
简介本资源是一个面向人工智能与机器人方向研究者、高校师生及强化学习实践者的多无人机协同围捕仿真项目聚焦于解决多智能体在动态环境中协同决策与目标围捕的核心挑战。项目基于MADDPG算法在自定义Gymnasium仿真环境上训练3架无人机智能体协同围捕5个移动目标完整覆盖环境建模、策略网络Actor/Critic设计、经验回放与分布式训练全流程并通过PyTorch实现全部深度神经网络模块。压缩包共53个文件含9个核心Python源码如sim_env.py、maddpg.py、networks.py、25个预训练模型权重文件按agent编号与target/non-target区分、CSV训练日志、README说明文档、LICENSE及附赠的Word技术说明与PNG系统示意图整体大小为3.79MB。已有149人学习下载资源结构清晰、模块解耦合理提供可直接运行的训练/评估入口main.py与main_evaluate.py配套缓冲区管理、数学工具封装与分数历史记录等实用组件便于复现、调试与二次开发。1. 项目概述与核心价值最近在复现和优化一个多无人机协同围捕的项目核心是基于MADDPG算法在自定义的Gymnasium环境中训练多个无人机智能体让它们学会协同决策高效地围捕一个动态目标。这个项目听起来很酷但真正动手做起来从环境搭建、算法实现到训练调参每一步都充满了挑战。如果你也对多智能体强化学习MARL或者无人机集群控制感兴趣想找一个能跑通、能理解、还能自己动手改的实战项目那这个项目绝对值得你花时间研究。它不仅仅是一个算法实现更是一个完整的仿真系统涵盖了从环境交互、智能体设计到分布式训练的全流程。为什么说这个项目有代表性首先多无人机协同围捕是一个典型的合作式多智能体任务智能体之间既有竞争都想靠近目标又需要合作形成包围圈这比单智能体任务复杂得多。其次MADDPG算法是多智能体深度强化学习领域的一个里程碑式的工作它巧妙地解决了非平稳环境、信用分配等经典难题。最后整个项目基于PyTorch和Gymnasium这两个目前最主流、最灵活的框架这意味着代码结构清晰易于扩展和移植到其他任务上。无论是为了发论文、做比赛还是纯粹想深入理解MARL这个项目都能给你提供一个扎实的起点和丰富的实践经验。2. 项目整体架构与设计思路2.1 核心问题定义多无人机协同围捕我们先明确要解决什么问题。想象一个二维或三维的仿真空间里面有一个高速移动的“逃逸者”目标和多个由我们控制的“追捕者”无人机。追捕者的目标是在最短时间内通过协同运动对逃逸者形成合围并将其限制在一个很小的区域内。这里的关键是“协同”。单个无人机再快也很难单独抓住一个灵活的目-标必须依靠团队配合有人拦截有人驱赶有人封堵退路。这个任务抽象成强化学习问题包含几个要素环境 (Environment)我们自定义的Gymnasium环境。它定义了状态空间所有无人机和目标的位置、速度等、动作空间每个无人机的控制指令如加速度、角速度、状态转移动力学物理引擎模拟移动、奖励函数引导智能体学习围捕行为以及终止条件成功围捕或超时。智能体 (Agent)每个无人机对应一个智能体。它们共享相同的策略网络结构但在训练和执行的输入不同。算法 (Algorithm)我们采用MADDPG。其核心思想是“集中式训练分布式执行”。在训练时每个智能体的Critic网络可以观察到全局状态所有智能体的动作和状态信息从而能更好地评估联合动作的价值但在执行时每个智能体只根据自己的局部观测做出决策这符合实际分布式系统的要求。2.2 技术栈选型与理由为什么选择PyTorch、Gymnasium和MADDPG这个组合PyTorch作为深度学习框架其动态图特性非常适合强化学习这种需要频繁交互、调试的研究场景。我们可以像写普通Python代码一样构建网络在前向传播中插入打印语句调试非常直观。此外PyTorch的自动求导和丰富的优化器让我们能专注于算法逻辑本身。Gymnasium作为OpenAI Gym的官方分支和继承者它提供了强化学习环境的标准接口reset,step,render等拥有庞大的社区和丰富的第三方环境。自定义环境只需继承gym.Env类并实现几个关键方法就能无缝接入各种主流算法库兼容性极佳。MADDPG算法对于连续动作空间的多智能体合作-竞争任务MADDPG是经过大量验证的有效方法。相比传统的DDPG直接应用到多智能体场景会因环境非平稳而失效MADDPG通过让Critic使用额外信息其他智能体动作来稳定训练。相比更复杂的算法如QMIX适用于离散动作MADDPG在连续控制上更自然且代码结构相对清晰易于理解和修改。注意这个项目对算力有一定要求。虽然仿真环境本身不重但MADDPG训练需要大量样本训练周期较长。建议使用带有GPU的机器进行训练可以显著缩短时间。CPU也能跑但需要耐心。2.3 项目文件结构解析一个组织良好的项目结构是成功的一半。典型的项目目录可能如下multi_uav_pursuit/ ├── envs/ # 环境定义 │ ├── __init__.py │ └── pursuit_env.py # 核心自定义围捕环境 ├── maddpg/ # 算法实现 │ ├── __init__.py │ ├── actor.py # 演员网络 (策略网络) │ ├── critic.py # 评论家网络 (价值网络) │ ├── maddpg_agent.py # 单个智能体类包含Actor和Critic │ └── replay_buffer.py # 经验回放池 ├── configs/ # 配置文件 │ └── pursuit_config.yaml # 超参数配置学习率、折扣因子等 ├── models/ # 保存训练好的模型 │ └── checkpoint_10000.pth ├── logs/ # 训练日志用于TensorBoard可视化 │ └── events.out.tfevents.xxx ├── train.py # 主训练脚本 ├── eval.py # 模型评估脚本 └── requirements.txt # 项目依赖包列表这种结构将环境、算法、配置、模型分离符合“高内聚、低耦合”的原则方便我们单独调试环境或修改算法。3. 核心模块深度解析与实现3.1 自定义Gymnasium环境构建这是项目的基石。我们需要在pursuit_env.py中创建一个继承自gym.Env的类。3.1.1 定义观测空间和动作空间对于连续控制我们通常使用Box空间。import gymnasium as gym import numpy as np class MultiUAVPursuitEnv(gym.Env): def __init__(self, num_pursuers3, world_size100.0): super().__init__() self.num_pursuers num_pursuers self.world_size world_size # 动作空间每个追捕者的二维加速度 (ax, ay)范围[-1, 1] # 假设有3个追捕者动作空间形状就是 (3, 2) self.action_space gym.spaces.Box( low-1.0, high1.0, shape(num_pursuers, 2), dtypenp.float32 ) # 状态空间对Critic包含所有追捕者和逃逸者的位置、速度。 # 例如3个追捕者(位置xy, 速度xy) 1个逃逸者(位置xy, 速度xy) 状态维度 (3*4 1*4) 16 state_dim num_pursuers * 4 4 # 4: px, py, vx, vy self.state_space gym.spaces.Box( low-np.inf, highnp.inf, shape(state_dim,), dtypenp.float32 ) # 观测空间对Actor每个追捕者只能看到局部信息例如自身和逃逸者的相对位置、速度。 # 这里简化让每个追捕者看到逃逸者的相对位置和自身速度。 obs_dim_per_agent 4 # 2 (相对位置) 2 (自身速度) self.observation_space gym.spaces.Box( low-np.inf, highnp.inf, shape(obs_dim_per_agent,), dtypenp.float32 )这里的关键区别是state_space和observation_space。state是全局的用于训练时的Critic网络obs是局部的用于每个智能体的Actor网络和执行。3.1.2 设计奖励函数奖励函数是指引智能体学习的“指挥棒”。设计好坏直接决定最终效果。一个有效的围捕奖励可以包含以下几部分距离奖励鼓励追捕者靠近逃逸者。例如reward_distance -alpha * distance距离越近惩罚越小奖励越大。围捕成功奖励当所有追捕者与逃逸者的距离都小于某个阈值形成包围圈时给予一个大的正奖励如100并结束本轮。时间惩罚每一步给予一个小的负奖励如-0.1鼓励快速完成任务。碰撞惩罚可选如果追捕者之间发生碰撞给予负奖励避免智能体挤在一起。协同奖励进阶可以设计奖励来鼓励分散包围例如奖励追捕者与逃逸者连线的角度分布更加均匀。在step函数中我们需要计算每个智能体的奖励。MADDPG通常需要为每个智能体提供独立的奖励。一个简单的实现可以是所有追捕者共享基于全局状态的团队奖励也可以为每个追捕者设计包含个人贡献的奖励。3.1.3 实现状态转移动力学在step函数中我们需要根据智能体的动作加速度更新所有实体的状态。这通常涉及简单的物理模拟def step(self, actions): # actions: shape (num_pursuers, 2) dt 0.1 # 时间步长 # 1. 更新追捕者状态 for i in range(self.num_pursuers): # 根据加速度更新速度 (假设质量1) self.pursuer_vel[i] actions[i] * dt # 限制最大速度 speed np.linalg.norm(self.pursuer_vel[i]) if speed self.max_speed: self.pursuer_vel[i] self.pursuer_vel[i] / speed * self.max_speed # 更新位置 self.pursuer_pos[i] self.pursuer_vel[i] * dt # 边界处理反弹或穿越 self.pursuer_pos[i] np.clip(self.pursuer_pos[i], -self.world_size, self.world_size) # 2. 更新逃逸者状态简单规则远离最近的追捕者 # ... 逃逸者策略实现 ... # 3. 计算观测、状态、奖励、是否结束 obs self._get_obs() # 获取每个智能体的局部观测 state self._get_state() # 获取全局状态 rewards self._get_reward() # 计算每个智能体的奖励 done self._check_done() # 检查是否围捕成功或超时 # 4. 可选的额外信息 info {} return obs, state, rewards, done, info_get_obs方法为每个追捕者计算其局部观测例如[target_rel_x, target_rel_y, self_vx, self_vy]。_get_state方法将所有实体的位置和速度拼接成一个一维向量。实操心得物理模型的复杂度需要权衡。过于简单如直接位置更新可能使问题太简单学不到真正动力学过于复杂如完整的无人机动力学模型会大幅增加仿真计算量拖慢训练。对于算法验证一个带速度、加速度和简单阻尼的二阶积分模型通常是个不错的起点。边界处理也很重要直接穿越边界可能会让智能体“作弊”反弹规则更符合物理直觉。3.2 MADDPG算法原理与PyTorch实现MADDPG的核心是每个智能体拥有两套网络Actor策略和Critic价值并且都有对应的目标网络用于稳定训练。3.2.1 Actor网络与Critic网络设计Actor网络 (actor.py)输入是智能体的局部观测obs_i输出是该智能体的连续动作action_i。通常是一个多层感知机MLP最后一层用tanh激活函数将输出限制在动作范围内如[-1, 1]。import torch.nn as nn import torch.nn.functional as F class Actor(nn.Module): def __init__(self, obs_dim, action_dim, hidden_dim256): super().__init__() self.fc1 nn.Linear(obs_dim, hidden_dim) self.fc2 nn.Linear(hidden_dim, hidden_dim) self.fc3 nn.Linear(hidden_dim, action_dim) def forward(self, obs): x F.relu(self.fc1(obs)) x F.relu(self.fc2(x)) # 使用tanh将输出映射到[-1, 1] action torch.tanh(self.fc3(x)) return actionCritic网络 (critic.py)输入是所有智能体的动作和全局状态state输出是对应智能体在该状态-联合动作下的Q值估计。这是MADDPG与DDPG的关键区别——Critic能看到其他智能体的动作。class Critic(nn.Module): def __init__(self, state_dim, total_action_dim, hidden_dim256): # total_action_dim num_agents * action_dim_per_agent super().__init__() input_dim state_dim total_action_dim self.fc1 nn.Linear(input_dim, hidden_dim) self.fc2 nn.Linear(hidden_dim, hidden_dim) self.fc3 nn.Linear(hidden_dim, 1) # 输出单个Q值 def forward(self, state, actions): # actions: 所有智能体动作拼接起来的向量 x torch.cat([state, actions], dim-1) x F.relu(self.fc1(x)) x F.relu(self.fc2(x)) q_value self.fc3(x) return q_value3.2.2 智能体类封装 (maddpg_agent.py)每个智能体类需要管理自己的Actor、Critic以及它们对应的目标网络并实现动作选择、网络更新等方法。class MADDPGAgent: def __init__(self, obs_dim, state_dim, action_dim, agent_id, args): self.obs_dim obs_dim self.state_dim state_dim self.action_dim action_dim self.id agent_id # 网络 self.actor Actor(obs_dim, action_dim).to(device) self.actor_target Actor(obs_dim, action_dim).to(device) self.actor_optimizer torch.optim.Adam(self.actor.parameters(), lrargs.lr_actor) # Critic的输入维度全局状态 所有智能体的动作 total_action_dim args.num_agents * action_dim self.critic Critic(state_dim, total_action_dim).to(device) self.critic_target Critic(state_dim, total_action_dim).to(device) self.critic_optimizer torch.optim.Adam(self.critic.parameters(), lrargs.lr_critic) # 硬更新目标网络或后续使用软更新 self.hard_update(self.actor_target, self.actor) self.hard_update(self.critic_target, self.critic) def select_action(self, obs, noiseNone): 根据观测选择动作训练时可添加探索噪声 obs torch.FloatTensor(obs).unsqueeze(0).to(device) action self.actor(obs).cpu().data.numpy().flatten() if noise is not None: action noise return np.clip(action, -1.0, 1.0) def update(self, agents_replay_buffer, agent_list): 核心更新函数从回放池采样并更新网络 # 1. 从共享的经验回放池采样一个批次的数据 obs_batch, state_batch, action_batch, reward_batch, next_obs_batch, next_state_batch, done_batch agents_replay_buffer.sample(args.batch_size) # 2. 转换为Tensor obs_batch torch.FloatTensor(obs_batch).to(device) # [batch, num_agents, obs_dim] state_batch torch.FloatTensor(state_batch).to(device) # ... 其他数据转换 ... # 3. 计算Critic损失 # 3.1 计算目标Q值 r gamma * Q_target(s, a_1, ..., a_n)其中a_i由目标Actor网络根据next_obs生成 next_actions [] for i, agent in enumerate(agent_list): next_obs_i next_obs_batch[:, i, :] next_action_i agent.actor_target(next_obs_i).detach() # 注意detach next_actions.append(next_action_i) next_actions torch.cat(next_actions, dim1) # 拼接所有智能体的下一个动作 next_state_value self.critic_target(next_state_batch, next_actions).detach() target_q reward_batch[:, self.id].unsqueeze(1) args.gamma * next_state_value * (1 - done_batch[:, self.id].unsqueeze(1)) # 3.2 计算当前Q值 current_q self.critic(state_batch, action_batch) # 3.3 Critic损失MSE critic_loss F.mse_loss(current_q, target_q) self.critic_optimizer.zero_grad() critic_loss.backward() # 可选梯度裁剪防止爆炸 torch.nn.utils.clip_grad_norm_(self.critic.parameters(), args.max_grad_norm) self.critic_optimizer.step() # 4. 计算Actor损失 # 4.1 重新计算当前状态下智能体i的动作其他智能体动作固定为采样数据中的动作 # 目的是优化Actor使得Critic给出的Q值最大 current_actions [] for i, agent in enumerate(agent_list): if i self.id: # 对于当前智能体使用Actor网络重新生成动作需要梯度 new_action_i agent.actor(obs_batch[:, i, :]) else: # 对于其他智能体使用采样数据中的动作不需要梯度 new_action_i action_batch[:, i*action_dim:(i1)*action_dim].detach() current_actions.append(new_action_i) current_actions torch.cat(current_actions, dim1) # 4.2 Actor损失-Q(s, a_1, ..., a_i(new), ..., a_n)即最大化Q值 actor_loss -self.critic(state_batch, current_actions).mean() self.actor_optimizer.zero_grad() actor_loss.backward() torch.nn.utils.clip_grad_norm_(self.actor.parameters(), args.max_grad_norm) self.actor_optimizer.step() def hard_update(self, target, source): 硬更新目标网络参数 for target_param, param in zip(target.parameters(), source.parameters()): target_param.data.copy_(param.data)这是一个高度简化的核心流程。实际实现中还需要考虑软更新soft_update每次用微小比例更新目标网络训练更稳定、经验回放池的共享与采样策略、探索噪声如OU噪声的添加与衰减等细节。3.2.3 共享经验回放池多智能体场景下一个常用的技巧是使用一个共享的经验回放池存储格式为(obs_all, state, action_all, reward_all, next_obs_all, next_state, done_all)。这样每个智能体在更新自己的Critic时都能从所有智能体的交互经验中学习提高了数据利用率也帮助Critic更好地理解联合动作的价值。4. 训练流程与核心调参技巧4.1 主训练循环 (train.py)训练脚本的骨架如下def train(): # 1. 初始化环境 env MultiUAVPursuitEnv(num_pursuersargs.num_agents) # 2. 初始化智能体列表 agents [MADDPGAgent(...) for i in range(args.num_agents)] # 3. 初始化共享经验回放池 replay_buffer ReplayBuffer(args.buffer_size) total_steps 0 for episode in range(args.max_episodes): obs, state env.reset() episode_reward 0 for step in range(args.max_episode_len): # 4. 每个智能体根据当前观测选择动作添加探索噪声 actions [] for i, agent in enumerate(agents): action agent.select_action(obs[i], noise_process[i]) actions.append(action) actions np.array(actions) # shape (num_agents, action_dim) # 5. 环境执行一步 next_obs, next_state, rewards, done, _ env.step(actions) # 6. 将经验存入回放池 replay_buffer.push(obs, state, actions.flatten(), rewards, next_obs, next_state, done) obs next_obs state next_state episode_reward np.sum(rewards) # 累计团队总奖励 total_steps 1 # 7. 如果回放池数据足够开始训练 if len(replay_buffer) args.batch_size: for agent in agents: agent.update(replay_buffer, agents) # 每个智能体独立更新 # 8. 定期软更新目标网络 if total_steps % args.target_update_interval 0: for agent in agents: agent.soft_update() if done: break # 9. 记录日志保存模型 if episode % args.log_interval 0: print(fEpisode {episode}, Total Reward: {episode_reward:.2f}, Steps: {step}) # 使用TensorBoard记录奖励、损失等 # writer.add_scalar(Reward/Episode, episode_reward, episode) if episode % args.save_interval 0: save_models(agents, episode)4.2 超参数调优经验谈MADDPG的训练对超参数比较敏感。以下是一些关键参数和我的调参经验参数典型范围/值作用与影响调参心得学习率 (lr_actor, lr_critic)1e-4 到 1e-3Actor和Critic网络的更新步长。Critic的学习率通常比Actor稍大如1e-3 vs 5e-4因为Critic需要更快地收敛来提供准确的Q值估计。如果训练不稳定奖励剧烈震荡尝试同时降低两者。折扣因子 (gamma)0.95 到 0.99衡量未来奖励的重要性。对于围捕这种有明确终止状态的任务可以设高一些0.98-0.99鼓励智能体考虑长远收益完成围捕。软更新系数 (tau)0.005 到 0.01控制目标网络更新速度。θ_target τ * θ (1-τ) * θ_target这是一个非常关键的稳定训练的参数。值越小如0.005目标网络更新越慢训练越稳定但可能收敛慢值越大如0.05则反之。通常从0.01开始尝试。回放池大小 (buffer_size)1e5 到 1e6存储经验的数量。越大越好但受内存限制。对于多智能体由于样本复杂度高建议至少1e6。确保在开始更新前池中有足够多样本如1e4。批次大小 (batch_size)256 到 1024每次更新从回放池采样的样本数。较大的批次如512通常能提供更稳定的梯度估计但会增加计算量。GPU内存允许的情况下建议使用较大的批次。探索噪声OU噪声参数theta~0.15, sigma~0.2为动作添加随机性促进探索。初期需要较大的探索sigma可设0.3随着训练进行可以线性衰减sigma。OU噪声比高斯噪声在惯性系统上探索效率更高。网络隐藏层维度128, 256, 512神经网络中间层的神经元数量。任务越复杂需要越大的网络容量。对于我们的围捕任务两层256的MLP通常足够。可以先从128开始如果学习能力不足再增加。踩坑记录我最开始训练时奖励一直不增长在零附近徘徊。排查后发现是奖励函数设计不合理。我最初只给了到达目标的大奖励但中间步骤没有奖励稀疏奖励导致智能体根本探索不到成功状态。后来加入了基于距离的稠密奖励每一步都根据与目标的距离给予惩罚学习立刻就有了进展。奖励函数的形状reward shaping是多智能体强化学习成功的关键有时甚至比算法本身更重要。5. 实战调试与性能优化5.1 训练过程监控与可视化“黑箱”训练是痛苦的。必须要有有效的监控手段。TensorBoard记录每个episode的总奖励、每个智能体的平均奖励、Critic和Actor的损失值。观察奖励曲线是否上升、损失是否收敛。如果奖励曲线剧烈抖动可能是学习率太高或批次大小太小。定期渲染测试每隔一定训练代数用当前策略运行一个episode并渲染出来直观地看智能体的行为。你会发现训练初期智能体像无头苍蝇后期逐渐学会包抄和拦截。这是最直接的验证方式。关键指标监控平均围捕时间成功围捕所需的平均步数越短越好。成功率在测试的N个episode中成功围捕的比例。智能体间平均距离避免智能体挤成一团这个距离应保持在一个合理范围。5.2 常见训练问题与排查问题现象可能原因排查与解决思路奖励不上升一直很低1. 奖励函数设计问题稀疏奖励。2. 探索不足智能体没找到好策略。3. 网络结构太简单或学习率太低。1.检查奖励函数加入稠密奖励引导。可以先用一个简单的规则控制器如直接飞向目标在环境中跑看看奖励是多少作为一个基准。2.增加探索增大噪声的sigma或使用熵正则化等探索鼓励方法。3.调整网络和超参尝试增大网络隐藏层适当提高学习率。奖励曲线剧烈震荡1. 学习率过高。2. 批次大小太小。3. 目标网络更新太快tau太大。1.降低学习率特别是Actor的学习率。2.增大批次大小。3.减小tau如从0.01调到0.005让目标网络更稳定。训练后期性能突然崩溃1. 过拟合或策略坍塌。2. 探索噪声衰减过快策略陷入局部最优。3. 经验回放池中旧数据过多。1.减缓噪声衰减甚至保留一个最小噪声。2. 使用优先级经验回放让算法更关注那些TD误差大的、还没学好的经验。3. 定期保存模型快照如果崩溃可以回滚到之前的版本。智能体学会“偷懒”或奇怪行为奖励函数存在漏洞被智能体找到“捷径”。仔细审查奖励函数。例如如果只奖励靠近目标智能体可能学会一直跟在目标后面但永不包围。需要增加对“包围态势”的奖励比如奖励智能体分布在目标的不同方向。5.3 性能优化技巧向量化操作在环境step函数和网络前向传播中尽量使用NumPy/PyTorch的向量化操作避免Python循环可以极大提升仿真和训练速度。GPU加速确保PyTorch安装了CUDA版本并将网络和张量放到GPU上.to(device)。对于大规模网络和批次GPU加速效果显著。并行环境采样如果CPU核心多可以使用SubprocVecEnv等工具创建多个环境实例并行采样数据能大幅提升数据收集效率这是加速强化学习训练的常用手段。梯度裁剪在Critic和Actor的优化器step之前使用torch.nn.utils.clip_grad_norm_对梯度进行裁剪能有效防止训练因梯度爆炸而崩溃。6. 项目扩展与进阶思考这个基础项目可以作为一个平台向多个方向扩展环境复杂度升级从2D到3D将环境扩展到三维空间动作空间变为三维加速度这更贴近真实无人机。加入障碍物在场景中设置静态或动态障碍物智能体需要学会避障的同时进行围捕。更复杂的逃逸者策略让逃逸者也使用一个预训练的策略或者基于规则的更智能策略如强化学习对手增加挑战性。算法升级尝试其他MARL算法如MATD3MADDPG的改进版解决了过估计问题、MAPPO基于策略梯度的多智能体算法等在这个环境上对比效果。引入通信机制让智能体之间可以传递简单的消息学习何时通信、通信什么实现更高级的协同。分层强化学习高层策略决定战术如“包抄”、“驱赶”底层策略执行具体动作。从仿真到现实Sim2Real动力学模型精细化接入更真实的无人机动力学模型如PX4的软件在环仿真。加入传感器噪声在观测中加入高斯噪声提高策略的鲁棒性。域随机化在训练时随机化环境的一些参数如无人机质量、风阻系数使得训练出的策略能适应现实中的参数变化。这个项目最吸引我的地方在于它像一座桥梁连接了强化学习的理论算法和具挑战性的多智能体协同控制问题。当你看到最初乱撞的无人机们经过数万轮训练后能像猎犬一样默契地分工、拦截、合围时那种成就感是无与伦比的。过程中你会深刻理解信用分配、环境非平稳性、探索-利用权衡这些MARL核心概念。我建议你在跑通基础版本后一定要尝试修改奖励函数你会发现智能体行为的变化直接反映了你设计的“价值观”这或许是强化学习最富哲学趣味的一点。本文还有配套的精品资源点击获取
网站建设高端定制企业官网