本文首发于:行者AI

Unity 是寰球最受欢迎的游戏开发引擎之一,有大量的游戏开发者在应用Unity开发他们的游戏。在这个AI、大数据等风行词遍布各行各业的时代,Unity也没有被潮流抛下,推出了他们本人的基于深度强化学习来训练游戏AI的工具包Unity ML-agents。这个工具包功能丰富,非常弱小。能够帮忙你在你的游戏内实现一个新的AI算法,并且疾速的用到你的游戏当中。这么弱小的工具包难以在一篇文章外面概括其所有性能。本文就先抛砖引玉,略微讨论一下Unity ML-agents训练的时候须要用到的各种参数的意义,其罕用的取值又是如何。

本文所有内容参考Unity ML-agents的官网文档(地址:https://github.com/Unity-Tech...)

1. 训练参数设置

在你开始你的训练之前,你须要针对你的训练任务设定一个训练参数文件(个别是一个.yaml文件)。

接下来就简略介绍一下ml-agents环境里的参数设置概要。本文次要参考ml-agents最新版本对于参数设置的官网文档,做了一些概括性的翻译并退出肯定集体了解。

具体文档地址:https://github.com/Unity-Tech...

训练参数次要分为罕用训练参数(Common Trainer Configurations), 训练形式专用参数(Trainer-specific Configurations),超参数(hyper-parameters) ,处分信号参数(Reward Signals), 行为克隆(Behavioral Cloning),应用RNN加强智能体记忆能力的参数(Memory-enhanced Agents using Recurrent Neural Networks),以及自我反抗训练参数(Self-Play)这几个大的模块。这几个模块上面又有一些小的模块,在后文会进一步阐明,而且这些模块并不需要总是全都去设定。事实上,除了前三个模块是简直每个环境训练必须的参数之外,其余的模块仅用在须要应用到对应性能的训练任务。接下来具体阐明每个参数的含意。

2. 罕用训练参数模块(Common Trainer Configurations)

  • trainer_type: (default = ppo) 这个参数决定了应用什么智能体训练算法,当初临时只反对Proximal Policy Gradient(PPO,具体应为OpenAI版本的PPO2),Soft Actor-Critic(SAC),以及MA-POCA。前两种都只是单智能体训练算法。 留神:在你改变了训练算法后,记得去调整一下前面的相应参数。对于不同的算法,上面的参数也往往有不同的适用范围,并非无缝连接的。上面会具体阐明。
  • summary_freq: (default = 50000) 这个参数决定了多少步数(step)之后,开始记录咱们的训练统计数据。
  • time_horizon: (default = 64) 这个参数决定了在多少步数之后,开始把收集到的教训数据放入到教训池(experience buffer)。这个量同样也决定了应用多少步后的采样来对以后动作的预期处分进行训练。简略来说,这个值如果越大,就相当于你更靠近于一局(episode)游戏的实在回报,从而偏差更小。然而因为要进行一局游戏能力更新一个动作的处分预期,这个过程相当的长,并且每局游戏可能状况变化很大。不同局之间,做同样的动作可能最终收益天壤之别(因为这个动作可能其实对这个游戏的影响基本没有那么大),从而导致方差较大。反过来,当你采样的步数太小,可能对最终的处分预估会偏差很大,然而可能带来较小的方差。其实这也跟机器学习外面经典的简略模型简单模型(过拟合欠拟合)问题一样,须要在方差和偏差当中取一个均衡。官网倡议当你的环境太大(跑一步耗时太长)或者你设置的处分比拟密集的时候,能够把这个值设的低一点,反之则须要增大。比方在足球比赛这样处分十分稠密的工作当中,范例文档设置的该参数值为1000。 留神,这个参数决定了采样的步数,和batch_size、 buffer_size、 epoch等参数亦有分割。前面提到这些参数的时候会再对其中关系加以阐明。常见范畴:32 - 2048
  • max_steps: (default = 500000) 这个参数决定了本次训练任务总共会进行多少步数。如果你有多个同样动作的智能体,他们每个的步数都会计入到这个总步数当中;同样的,如果你有多个环境并行的在多台服务器上运行,所有环境里的智能体的总步数都会计入思考。所以,当你并行训练多agent算法的时候,务必将这个值设的更大一些。常见范畴:5e5 - 1e7
  • keep_checkpoints: (default = 5) 这个参数决定了保留多少个训练时候产生的checkpoint,其中每一个checkpoint都是在checkpoint_interval步数后产生的。
  • checkpoint_interval: (default = 500000) 如前文所说,这个参数决定了每多少步数当前,你的模型会存储一个节点。
  • init_path: (default=None) 这个参数决定了你的模型是否从某个之前训练好的模型存储点持续训练。须要提供模型的确切地位,比如说,./models/{run-id}/{behavior_name}。其实在训练的时候,应用--initialize-from这个CLI参数就足以让所有的训练任务从同一个存储模型持续训练,提供这个参数是为了不便让不同的训练从不同的模型持续训练(须要一一设定)。很少用到
  • threaded:(default = false) 开启python的多线程性能来实现一边训练一边存储模型,防止I/O耗费太多工夫。官网倡议在开启self-play性能的时候尽量避免应用该性能。

3. 接下来是一些常见超参数(hyper-parameters)的具体设定

  • hyperparameters → learning_rate: (default = 3e-4),这个参数决定了梯度降落的学习率。当该值过大时训练会变的不稳固(reward不能稳步回升,时常大幅震荡)。常见范畴:1e-5 - 1e-3
  • hyperparameters → batch size:这个参数决定了每次更新参数的时候,会有多少步的(state,action, reward...) 状态元组被用来进行学习。留神:这个参数应该永远是buffer_size的几分之一(因为实际上程序会先将buffersize拿来切分成batchsize大小的几个batches。所以buffer_size永远要能被batch_size整除)。 对于一个间断动作空间的训练任务,这个参数应该设定在1000以上这个级别(因为动作空间须要尽可能多的采样来失去不同的数据),如果是离散空间,这个值往往设定在几十到几百就好了(依据你动作空间的大小来定)。常见范畴:(间断-PPO)512 - 5120;(间断-SAC)128 - 1024;(离散,PPO&SAC):32 - 512.
  • hyperparameters → buffer size: (default = 10240 for PPO and 50000 for SAC) 。 PPO:对于PPO算法来说,程序先要集满buffer_size那么多步数之后才会开启一轮训练。而后如前文所说,每次收集够了buffer_size个状态元组之后,咱们把buffer外面的状态分成buffer/batch_size个batch,而后每个batch进行一次训练更新参数, 这个过程反复epoch(epoch也是一个超参数)次。所以实际上每过一个buffer_size的采样之后,参数都会进行num_epoch * buffer/batch次数的更新。通常一个较大的buffer_size会带来一个更加稳固的训练后果。 SAC:对于SAC算法来说,通常来说教训池要是其设episode长度的几千倍,从而能让它训练的时候同时利用到较旧和最近的采样。常见范畴:(PPO)2048 - 409600;(SAC) 50000 - 1000000
  • hyperparameters → learning_rate_schedule: (default = linear for PPO and constant for SAC) 这个参数决定了是否应用学习率衰减的方法来稳固训练。两个可选的模式别离是linear和constant,前者会对你的学习率进行线性递加,后者则不会扭转。通常来说,学习率越大,往往容易呈现训练不稳固,学习率越小则容易呈现长时间训练不收敛的状况。所以应用学习率衰减先用较大的学习率疾速的找到一个极值点方向,而后再逐渐膨胀学习率使得训练稳固在极值左近,而不会来回摆动。官网倡议,对PPO开启linear模式,进行线性递加,以达到更快的收敛速度。对SAC来说,则倡议维持学习率不变。

4. 接下来介绍一些罕用的网络模型的超参数

  • twork_settings → hidden_units:(default = 128) 这个参数决定了你的训练网络暗藏层的神经元数量,或者说它的维度。这个数值的大小决定了神经网络对游戏状态的表达能力。简略来说,较大的暗藏层往往对更大的察看空间有着较好的表达能力。所以这个值应该随着察看空间的维度变大而变大。常见范畴:32 - 512
  • network_settings → num_layers: (default = 2) 这个参数决定了你的训练网络的层数。这个数字越大,你的模型越深。尽管多层叠加可能进步模型对环境的表达能力。然而模型并不是越深越好,过深的层数往往会带来梯度隐没的问题,并且会使得训练速度变缓。倡议优先加大hiddent_unitys再加大本参数。常见范畴:1 - 3
  • network_settings → normalize: (default = false) 这个参数决定了模型是否对输出的察看向量进行归一化(normalization)。具体公式大略为 (obs - mean) / std,其中mean和std别离是observation的平均值和标准差。官网倡议,对于简单的间断动作空间工作,应用normalization可能有帮忙,然而对于简略的离散工作应用normalization则可能带来负作用。
  • network_settings → vis_encode_type: (default = simple) 这个参数决定了你的编码器的构造。留神,ppo也好,sac也好,只是一个训练架构,不同的工作你应用ppo也须要不同的编码器。比如说一个卡牌类游戏,你能够把所有的察看向量用一般的全连贯层解决,然而如果是一个动作游戏,你的察看可能是一张图片,那么这个时候你最好应用CNN作为你的特征提取编码器。这个参数就是在让你抉择应用何种编码器。simple是一个两层的卷积网络;Nature CNN则是应用Human Level Reinforcement Learning这篇文章的实现;resent则是应用IMPALA RESNET这种架构,这个网络的特点在于提取pattern能力强,不易梯度隐没。match3则是更适宜于卡牌游戏的一种CNN构造,特点是更小的构造然而能够捕获空洞空间的示意信息。fully_connected则是一个单层全连贯层。 因为卷积核大小的匹配要求,每种编码方式有一个最小输出维度的上限。比方simple最小20 20;nature_cnn最小反对36 36;resent最小反对15 *
    15,match3最小反对5 * 5, 留神:应用match3来解决超大的输出维度可能会拖慢训练速度。
  • network_settings → contioning_type: (default = hyper) 这个参数决定了是否应用hypernetwork来解决工作指标的信息。hyper网络的参数比拟多,当应用hyper网络的时候请缩小暗藏网络的层数。

5. Trainer-specific Configurations

接下来咱们介绍一下针对不同训练算法的专门参数。

5.1 PPO-specific Configurations (PPO专门参数)

  • beta: (default = 5.0e-3) 这个参数决定了激励摸索多样化策略的熵正则项的强度(entropy regularization)。简略来说,熵正则化通常是为了丰盛咱们的策略函数摸索不同策略和动作,咱们应用一个KL散度去掂量新的策略和老策略的相似性,并通过减少entropy来让动作策略更加随机。换句话说,当beta越大,越激励摸索。调节这个参数要联合TensorBoard外面的entropy和reward来看。当你的entropy降落的时候,reward依然没有起色,那就把这个beta增大使得entropy可能再继续一段时间。常见范畴:1e-4 - 1e-2
  • epsilon: (default = 0.2) 这个参数决定了策略更新的速度。这个参数就是ppo2论文外面的clip范畴,这个范畴限度了每一次参数更新偏离范畴,以保障ppo可能依附importance sampling作为一个on policy的办法持续训练。 能够发现当epsilon越大,咱们的旧策略参数theta’变动较小。这能够使得训练更加稳固,然而随之而来的就是更慢的收敛速度。常见范畴:0.1 - 0.3
  • lambd: (default = 0.95) 这个参数依据官网文档阐明是决定了咱们的算法多大程度上依赖预估的处分值,又多大程度上依赖理论的处分值。实际上这个laambda指的是GAE办法中的一个超参数lambda。GAE办法是在策略梯度降落中罕用的一种Advantage,用于更新管制policy在gradient方向上的更新幅度。GAE办法简略来说就是求TD(0), TD(1) 始终到TD无穷(即蒙特卡洛采样)的一个加权平均值。lambda这个值介于0到1之间,当lambda等于0时就是TD(0)预计,当lambda等于1时就是蒙特卡洛采样。常见范畴:0.9 - 0.95
  • num_epoch:(default = 3) 这个参数决定了每次进行梯度降落更新的次数。详见前文buffersize的局部。常见范畴:3 - 10

6. Reward Signals

处分信号可分为两种,一种是外在的(extrinsic)来自于环境的处分,一种是外在的(intrinsic)来自于外部的处分(比方好奇心处分等)。不论是外部还是内部处分信号,都至多要设定两个参数,一个是信号强度(strength),一个是信号衰减率(gamma)。并且,你须要至多设定一种处分,不然没方法训练。

6.1 Extrinsic Rewards

  • extrinsic → strength: (default = 1.0) 这个参数决定了模型收到的外部环境处分信号的强度。 常见范畴:1.00
  • extrinsic → gamma:(default = 0.99) 这个参数决定了远期处分的衰减率。简略来说,退出咱们的模型在某一步收到了100的处分,那么咱们前一步的处分应该是多少呢?如果上一步没有失去其余的处分,那么上一步咱们的收益就应该是gamma 100 = 99, 同理,再上一步的收益就是gamma^2 100, 以此类推。直观的了解,gamma约靠近一,那么较前期的收益也能反馈到后期的动作。反之就是动作策略进行学习的时候会更加倚重于短期内的回报。对于那种处分较为稠密,必须通过一系列动作之后能力取得一次处分的工作,务必将这个值设定得更靠近于一,反之则能够略微小一些。常见范畴:0.8 - 0.995

6.2 Intrinsic Reward

  • curiosity → strength: (default = 1.0) 这个参数决定了好奇心处分的强度。这个比例须要调整到一个刚好的水平,使得好奇心处分既不会吞没了内部处分的信号,又不会和内部处分比起来过于不值一提。常见范畴:0.001 - 0.1
  • curiosity → gamma: (default = 0.99)如前所述,这个参数决定了远期处分的衰减率。详见上文。
  • curiosity → network_settings: 这个参数次要是用来决定ICM模型的暗藏层维度的。即不能太大也不能太小。(64 - 256)
  • curiosity → learning_rate: (default = 0.99) 这个参数决定了你的ICM模型的学习率。过大的学习率会导致训练不稳固,过小的学习率会导致收敛迟缓。常见范畴:1e-5 - 1e-3

7. Memory-enhanced Agents Using Recurrent Neural Networks

7.1 能够通过减少记忆模块的方法来减少模型的表达能力。留神,memory section要加在network上面

  • network_settings → memory → memory_size: (default=128) 这个参数决定了你的LSTM网络的暗藏层的维度。这个值必须是偶数。大小视你的状态的复杂程度而定。最好要可能足够大,能力学习到如何记忆之前的状况。常见范畴:32 - 256
  • network_settings → memory → sequence_length: (default = 64) 这个参数决定了你的记忆网络RNN循环的次数或者说是序列长度。为了可能训练这么长的序列,咱们的采集到的教训也须要有这么长。所以依据我的猜想,只管文档没有明说,然而这个参数肯定要小于time_horizon的值。另外,这个数如果设定的太小,那么可能他无奈记住太多的货色,反过来,如果太大,训练会很慢。

7.2 应用记忆网络须要留神以下几点

  • LSTM 网络在间断动作空间工作上体现不佳,官网倡议更多的用在离散动作空间的工作下面。
  • 增加了一个RNN层会减少神经网络的复杂度,务必适度升高神经网络的层数。
  • 肯定要记住把memory_size设定为偶数。

8. Self Play 参数设置

self play 这个section只有在对抗性训练的时候须要应用,如果仅仅只有一个agent,或者多个agent中没有任何意义上的交互,则不须要设定这一个参数。Unity ml-agent也是利用self play参数的退出来启动它自带的对抗性训练模块。

参考(https://github.com/Unity-Tech...)

  • trainer_steps 和 ghost steps : 在了解self play参数之前咱们须要先了解两个概念,trainer_steps 和 ghost_steps。在一个反抗训练当中,咱们往往须要固定住一些agent的参数,在肯定的步骤外面让他们作为对手去训练咱们的agents。那么咱们的learning agents进行的步数就是trainer_steps,而与之绝对的,那些固定参数的对手所走的步数就是ghost_steps,为什么这两个值要别离计数呢?因为有些游戏并不是对称反抗训练(asymmetrical game),比方咱们训练一个2v1的场景,这时候在学习的队伍是2个agent,对手可能就是1个agent。在这种状况下,trainer_steps的增长就会两倍快于ghost_steps,因为咱们计步的时候都是计算总和。了解了这两个概念之后,再来看上面的参数设定就会分明很多,不然会一头雾水。
  • save_steps: 这个值决定了咱们的learning agents,每save_steps个trainer steps会去存储一个以后策略的参数。另外,如果save_steps足够大,比方咱们把方才例子里的save_steps改成20480,那么在存储一次快照之前,参数就要进行至多80次更新,这样每个快照之间的难度曲线就会更平缓,使得每次训练的不稳定性增大,然而带来的可能是更好的最终后果,以及在简单工作上更好的体现。
  • team_change和swap_steps:方才咱们曾经探讨过了什么是trainer steps,什么是ghost steps。当初来看一下这两个值怎么在反抗训练中决定咱们更换对手的频率。team_change 参数是决定咱们要用同一个learning agent训练多少次的参数。比方咱们当初有红蓝两队球队,如果咱们设定team_change=10000,那红队就会先训练10000个trainer steps才会轮到蓝队。而swap_steps则决定了咱们在一次team change之中,要更换几次对手。用下面的例子来看,就是红队在这10000个trainer steps外面要面对几个不同的蓝队的过来的快照。这里有一个简略的公式能够计算这种关系,假如咱们当初有设定team change为t,而后想要切换对手的次数为x,而咱们的队伍有a1个agents,对手的队伍有a2个agents,则咱们的swap_steps = (a2/a1) * (t / x), 如果这是一个对称反抗游戏,则上式能够简化为 t/x。 能够看见,team_changes 和 swap_steps,独特决定了一个更换对手的频率,这个频率越大,如同咱们后面剖析过的那样,咱们可能会遇到更多不同等级和策略的对手,从而会学到更多货色,但也造成了训练不稳固,参数难以收敛的问题。然而每个learning agent学到的策略可能更加不局限于某种对手,更加通用,不会过拟合。
  • play_against_latest_model_ratio: (default = 0.5) 这个参数决定了你和本人以后的模型对决的概率。这个值越大概容易和以后的本人的策略对决,也就更少的和本人以往的snapshot交战。
behaviors:  SoccerTwos: #游戏的名字    trainer_type: ppo #选定应用何种训练算法    hyperparameters: #PPO算法的超参数设置      batch_size: 2048       buffer_size: 20480 # buffer大小必须是batch大小的整数倍,这里是十倍      learning_rate: 0.0003      beta: 0.005  #熵正则的超参数      epsilon: 0.2 #PPO算法的clip范畴      lambd: 0.95  #GAE算法的lambda      num_epoch: 8 #每次更新训练多少次      learning_rate_schedule: linear #学习率衰减形式,这里是线性衰减    network_settings: #解决observation信息的网络结构设置      normalize: false       hidden_units: 256      num_layers: 2      vis_encode_type: simple     reward_signals: #处分超参数设置      extrinsic:        gamma: 0.99        strength: 1.0    keep_checkpoints: 5 #一共保留最近的五个checkpoint    checkpoint_interval: 100000 #每100000个timestep保留一个checkpoint    max_steps: 50000000 #最多训练这么多不(留神,这是多个agent加起来的值)    time_horizon: 1000    summary_freq: 5000     threaded: false # 是否应用线程,在应用self-play性能时最好关掉    self_play: #self-play相干参数设定      save_steps: 50000      team_change: 250000      swap_steps: 2000      window: 10 #一共保留十个过来过来的snapshot      play_against_latest_model_ratio: 0.5      initial_elo: 1200.0