0 引言
利用神经网络对值函数或动作-状态值函数进行逼近的做法,从90年代开始就有了。但是那个时候总是会出现不稳定、不收敛的情况,因此并没有得到很多的应用。直到DeepMind在2015年出手,利用DQN解决了这个难题。
1 抽象Agent基类
Sarsa和Sarsa($\lambda$)所用的Agent类具有执行一个策略、执行一个动作和学习三个主要方法。但是,在连续状态空间的问题中,需要用到值函数逼近,那么就要求Agent具备记忆一定数量已经经历过的状态转换对象的功能,另外还要具备从记忆中随机获取一定数量的状态转换对象以供批量学习的功能。为此,Agent基类设计如下:
|
|
agent相关概念的建模
状态转换(Transition)类
状态转换记录了:agent的当前状态s0、agent在当前状态下执行的动作a0、个体在状态s0时执行a0后环境反馈的即时奖励值reward以及新状态s1,此外用一个bool型变量记录状态s1是不是一个终止状态,以此表明包含该状态转换的Episode是不是一个完整的Episode。
|
|
场景片段(Episode)类
Episode类的主要功能是记录一系列的Episode,这些Episode就是由一系列的有序Transition对象构成,同时为了便于分析,我们额外增加一些功能,比如在记录一个Transition对象的同时,累加其即时奖励值以获得个体在经历一个Episode时获得的总奖励;又比如我们可以从Episode中随机获取一定数量、无序的Transition,以提高离线学习的准确性;此外由于一个Episode是不是一个完整的Episode在强化学习里是一个非常重要的信息,为此特别设计了一个方法来执行这一功能。
经历(Experience)类
一个个Episode组成了agent的经历(Experience)。也有一些模型使用一个叫“Memory”的概念来记录agent个体既往的经历,其建模思想是Memory仅无序存储一系列的Transition,不使用Episode这一概念,不反映Transition对象之间的关联,这是可以完成基于记忆的离线学习的强化学习算法的,甚至其随机采样过程更简单。但是文献还是跟随[2]的思想,使用Episode作为中间数据结构,以后根据实践的情况再做调整。
一般来说,经历或者记忆的容量是有限的,为此需要设定一个能够表示记录Transition对象的最大上限,称为容量(capacity).一旦agent经历的Transition数量超过该容量,则将抹去最早期的Transition,为最近期的Transition腾出空间。可以想象,一个Experience类应该至少具备如下功能:移除早期的Transition;记住一个Transition;从Experience中随机采样一定数量的Transition。
|
|
2 PuckWorld
在[1]中第七讲提到了PuckWorld,就是让一个“搞怪的小妖精”去抓取目标,目标随机出现在区域的一个位置,并且每隔30秒刷新一次。
PuckWorld问题的强化学习模型描述如下:
状态空间:puck的位置、速度和目标的位置,即{$p_x,p_y,v_x,v_y,d_x,d_y$}
动作空间:上、下、左、右以及不作为
奖励函数:离目标越近,奖励值越大
下面展示PuckWorld的实现:
“物理引擎”实现如下:
“图像引擎”实现如下:
“重置函数”实现:
3 DQN算法实现
把使用神经网络近似表示价值函数的功能封装到一个Approximator类中,然后再实现包含此价值函数的继承自Agent基类的个体类:ApproxQAgent,最后观察其在PuckWorld和CartPole环境中的训练效果。基于深度学习的部分使用PyTorch库。
Approximator类的实现
Approximator类作为价值函数的近似函数,其要实现的功能很简单:一是输出基于一个状态-动作对$\langle s,a \rangle$在参数w描述的环境下的价值$Q(s,a,w)$;二是调整参数来更新状态-动作对$\langle s,a \rangle$的价值。
在本例中,使用第三种值函数逼近方式,也就是输入为状态,输出为s与不同动作组成的状态-动作值函数值。在init构造函数中声明基于一个隐含层的神经网络。
前向传输,预测状态x对应的价值:
利用fit方法来训练,更新网络参数:
还需要设计一个方法_prepare_data来对输入数据进行一定的修饰
同时,为了使得agent在使用近似函数时更加简洁,可以为Approximator类写一个call方法,使得可以像执行函数一样来使用该类提供的方法:
最后一个比较重要的事情,由于一些高级的DQN算法使用两个近似函数+经验回放的机制来训练agent,因此会产生将一个近似函数的神经网络参数拷贝给另一个近似函数的神经网络的过程,也就是拷贝网络的过程,我们也需要提供一个能完成此功能的方法:
ApproxQAgent类的实现
构造函数:
从经历中学习:
学习方法:
添加一些重要的辅助方法
最后,还需要一个方法来将一直在更新参数的近似函数网络的参数拷贝给评估网络:
观察DQN在PuckWorld和CartPole环境中的表现
测试代码:
参考文献
[1] David Silver, reinforcement learning lecture 6 and 7
[2] 叶强, David Silver强化学习公开课中文讲解及实践, 知乎专栏
[3] Mnih V, Kavukcuoglu K, Silver D, et al. Human-level control through deep reinforcement learning[J]. Nature, 2015, 518(7540): 529-533.