645. NeurIPS 2024 - Lux AI Season 3 | lux-ai-season-3
首先,我要感谢 Lux AI 和 Kaggle 团队组织了这次比赛。我特别喜欢新功能,例如动态环境和战争迷雾 (FoW) 的存在。我期待在(希望有的)即将到来的 Lux AI 第四季中与大家一起竞争!!
源代码 available here: https://github.com/gregorlied/lux-s3/tree/main
我的解决方案是一种基于模仿学习 (IL) 的方法,使用了来自 Flat Neurons 和 Frog Parade 团队的比赛片段。
与 aDg4b 和 YumeNeko 团队类似,我采用了两个不同的 UNet 模型:
模型是在包含来自 10 个不同代理的 11681 个比赛片段的数据集上训练的。
然而,不同的代理可能有不同的动作分布,这在训练过程中引入了不稳定性。此外,模型架构本身没有利用地图对称性,导致数据使用效率低下。为了解决这些问题,我在训练和推理过程中应用了两个技巧:
由于存在战争迷雾 (FoW) 和隐藏的奖励节点,维护全局游戏状态至关重要。该状态在每一回合用观察到的局部信息进行迭代更新。对于奖励节点检测,我使用了 Relicbound 中提出的算法。
我策划了一个包含 10 个不同代理的 11681 个比赛片段的数据集,仅选择了代理赢得游戏的片段。对于这些片段,我只保留了代理获胜的比赛。
由于 Boey 和 aDg4b 团队的代理一旦游戏达到决定状态就会停止操作,我从数据集中移除了这些比赛。在这些情况下,动作分布与未决游戏中的动作分布显著不同,可能会降低模型性能。
基于维护的全局游戏状态,我构建了 18 个地图级别特征。
| 特征 | 可能值 | 备注 |
|---|---|---|
| my_unit_positions | {0, 1} | 是否有我方单位位于该单元格 (1 是,0 否) |
| my_unit_energy | [0, 1] | 每个单位的归一化能量水平 |
| my_unit_sap_range_map | {0, 1} | 该单元格是否在我方单位的吸取范围内 (1 是,0 否) |
| opp_unit_positions | {0, 1} | 是否有对方单位位于该单元格 (1 是,0 否) |
| opp_unit_energy | [0, 1] | 每个单位的归一化能量水平 |
| is_visible | {0, 1} | 该单元格是否对我方单位可见 (1 是,0 否) |
| energy | -1 或 [0, 1] | 单元格的归一化能量水平 (未知单元格为 -1) |
| curr_tile_type_empty | {-1, 0, 1} | 该单元格是否为空地 (1 是,0 否,-1 未知) |
| curr_tile_type_nebula | {-1, 0, 1} | 该单元格是否为星云地块 (1 是,0 否,-1 未知) |
| curr_tile_type_asteroid | {-1, 0, 1} | 该单元格是否为小行星地块 (1 是,0 否,-1 未知) |
| next_tile_type_empty | {-1, 0, 1} | 漂移更新后该单元格是否为空地 (1 是,0 否,-1 未知漂移/单元格) |
| next_tile_type_nebula | {-1, 0, 1} | 漂移更新后该单元格是否为星云地块 (1 是,0 否,-1 未知漂移/单元格) |
| next_tile_type_asteroid | {-1, 0, 1} | 漂移更新后该单元格是否为小行星地块 (1 是,0 否,-1 未知漂移/单元格) |
| dist_from_center_x | [0, 1] | 相对于 x 轴距中心的距离 |
| dist_from_center_y | [0, 1] | 相对于 y 轴距中心的距离 |
| relic_nodes | {-1, 0, 1} | 该单元格是否为遗迹节点 (1 是,0 否,-1 未知) |
| reward_nodes | {-1, 0, 1} | 该单元格是否为奖励节点 (1 是,0 否,-1 未知) |
| reward_map | [0, 1] | 归一化奖励地图 |
基于维护的全局游戏状态,我构建了 32 个全局特征。
| 特征 | 可能值 | 备注 |
|---|---|---|
| steps | [0, 1] | 归一化游戏步数 |
| match_steps | [0, 1] | 归一化比赛步数 |
| next_map_update | -1 或 [0, 1] | 距下次地图更新的归一化步数 (-1 未知漂移) |
| unit_move_cost | [0, 1] | 归一化移动消耗 |
| unit_sap_cost | [0, 1] | 归一化吸取消耗 |
| unit_sap_range | [0, 1] | 归一化吸取范围 |
| unit_sensor_range | [0, 1] | 归一化传感器范围 |
| all_relics_found | {0, 1} | 是否所有遗迹节点都已发现 (1 是,0 否) |
| all_rewards_found | {0, 1} | 是否所有奖励节点都已发现 (1 是,0 否) |
| gained_reward_last_X | {0, 1} | 我方代理在过去 X 回合是否获得奖励点数,X = 1, 3, 5, 10 (1 是,0 否) |
| reward_last_X | [0, 1] | 我方代理在过去 X 回合获得的奖励点数百分比,X = 1, 3, 5, 10 |
| team_points | [0..] | 归一化队伍分数 (除以 500) |
| opp_team_points | [0..] | 归一化对方队伍分数 (除以 500) |
| nebula_tile_drift_speed_X | {0, 1} | 漂移速度是否为类型 X (1 是,0 否) |
| agent_id_X | {0, 1} | 代理 ID 是否为 X (1 是,0 否) |
UNet 架构 adopted from the 第一季第 6 名解决方案。
由于不同的代理可能有不同的动作分布,我为每个代理使用了不同的预测头以稳定训练,这个想法最初是在 第一季第 4 名解决方案 中引入的。
在比赛的最后一周,我还尝试了类似于 Diffusion Transformer 架构的单一预测头。每个 DiT 块都基于代理 ID 进行条件化。
我的最终提交包含这两种网络架构的集成。
你可以在这里找到此提交:https://github.com/gregorlied/lux-s3/releases/tag/v73a
你可以在这里找到此提交:https://github.com/gregorlied/lux-s3/releases/tag/v73b