未完成,不代表最终质量
同时有大量的实验数据没有收集或者整理。
初赛#
去年的任务是在地图里面尽量找到更多宝箱并更快到达终点。官方默认 agent template 是 dpn 算法。
今年的任务是在地图里两只怪物的高压追逐上尽量达到生存分数的最优:
官方默认使用两层 mlp 的 ppo 算法。在默认配置(300 步生成第二只怪,500 步怪物狂暴,接下来我们采用 B300S500 表示这类环境配置)下取得了 600 分的成绩。
默认 agent pipeline 如下:
原始游戏数据
↓
[observation / feature] ← preprocessor.py + definition.py
↓
[model] ← model.py(神经网络,输出动作和价值)
↓
[action] ← 从模型输出里采样得到实际动作
↓
[environment] ← 游戏执行动作,返回 reward
↓
[sample] ← 把一步步数据打包成训练样本
↓
[algorithm] ← algorithm.py(计算损失,更新参数)
↓
[workflow] ← train_workflow.py(把所有模块串起来)
↓
[agent] ← agent.py(对外接口,kaiwudrl 框架调用的入口)text特征工程#
第一周,我们主要在做特征工程。
官方的初始特征只用到了
- 英雄局部状态
- 两只怪物的局部信息
- 局部地图的一小块
- 前 8 维合法动作
- episode 是否结束
没有用到的是环境提供的视野范围(),得分信息,观测信息和额外信息。
我们有理由相信,增加特征能够提高模型的表现。
同时我们也必须考虑到,用怎样的先验结构才能更优地利用好这些特征。
模型设计#
我们尝试了 CNN 和 RNN 的结合来处理视觉信息和时间序列信息。
CNN 取得了很大的成功,但是 RNN 的收敛速度显著慢于 CNN,甚至在某些环境配置下完全不收敛。
此外最重要的,初赛只允许在 windows/mac pc 上进行训练而不能用服务器,我们没有那么大的算力和数据(纯 RL)去 scaling。 这一点我第二周才意识到。
训练环境#
RL 算法改进#
我坚决认为,我们的 Reward 需要和最终的 Score 优化目标对齐。
在早期为了防止模型因为惩罚过重,奖励系数而变得过于保守,我们在 reward 里面加入了探索奖励。
同时,我们为了引导模型吃到稀疏的奖励(宝箱),我们在 reward 里面加入了趋向宝箱的稠密奖励。
这些奖励在早期确实帮助模型学会了基本的生存技能和吃到宝箱的能力,但是在后期我们发现,这些奖励不适合乱加,我们的先验可能并没有考虑到所有的情况,模型在不健全的 reward 下会有 reward hacking 的风险。
出于以上原因,我先后引入了 SIL 自模仿学习和 Risk-Constrained RL 给 Actor-Critic 加入了一个 risk 预测头。
SIL 自模仿学习#
对于简单的 mlp + ting CNN 效果不明显,但是对于较大的 RNN 模型,能够显著加快早期训练速度。
但是如果不加退火,会让模型变得过于保守,过于依赖之前的经验,导致模型在后期很难突破局部最优。
Risk-Constrained RL#
如果撤掉所有非 score 相关奖励,模型很快就会陷入到疯狂吃宝箱但是不注重生存的局面,是高压阶段生存难度大的主要原因。
为此,我们在 Actor-Critic 模型的基础上加入了一个 risk 预测头,来预测当前状态下被怪物追上的短期风险。
PPO 的置信区间#
PPO 的核心是一个 clipped surrogate objective:
其中 是当前策略和旧策略的概率比, 是优势函数。
可观测性指标#
最终的评测分数只和平均数有关,然而我们在训练过程中发现,平均数并不能全面体现一个 model 的表现。
e.g. 一个被我训崩了的 LSTM 模型,平均分在 B300S500 环境下只有 1000 分出头,但是实际上它分数低主要是因为高短死率,训了 45000 步仍然保持着 20% 以上的高短死率,虽然有 10% 的 1600 分样本,但是一但到了平均就全部被短死拉下去了。
所以我引入了 p40 p60 p80 这三个指标来分别衡量模型在不同分数段的表现,来更全面地评估模型的表现。
其实应该不太够来着,我们应该用一些统计学里面被广泛验证过的指标来评估模型的表现,比如说分位数,方差,甚至是一些更复杂的指标来评估模型的表现。
可观测性是为了我们建立对模型输出的 Actor 分布的直观理解,来指导我们后续的模型设计和训练。
