获取更多资讯,赶快关注上面的公众号吧!

【强化学习系列】

  • 第一章 强化学习及OpenAI Gym介绍-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第二章 马尔科夫决策过程和贝尔曼等式-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第三章 动态规划-基于模型的RL-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第四章 蒙特卡洛方法-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第五章 基于时序差分和Q学习的无模型预测与控制-强化学习理论学习与代码实现(强化学习导论第二版)
  • (本文)第六章 函数逼近-强化学习理论学习与代码实现(强化学习导论第二版)

文章目录

  • 第六章 函数逼近
    • 6.1 学习目标
    • 6.2 值函数近似
    • 6.2 增量式方法
      • 6.2.1 梯度下降
        • 梯度下降
        • 随机梯度下降的值函数近似
      • 6.2.2 线性函数逼近
        • 特征向量
        • 线性值函数近似
        • 查表特征
      • 6.2.3 增量预测算法
        • 增量预测算法
        • 基于值函数近似的蒙特卡洛
        • 基于值函数近似的TD学习
        • 基于值函数近似的TD(λ\lambdaλ)
      • 6.2.4 增量控制算法
        • 基于值函数近似的控制
        • 动作值函数近似
        • 线性动作值函数近似
        • 增量控制算法
    • 6.3 代码实现

第六章 函数逼近

在前面的章节中我们介绍的都是表格型强化学习,但是当问题的状态空间很大,表格型强化学习需要为每一个状态存储其每一个可选动作的估计值,势必需要很大的内存占用,例如西洋双陆棋的状态空间为102010^{20}1020,计算机围棋的状态空间为1017010^{170}10170,甚至像直升机控制这样的问题其状态空间为无限大。那么该如何才能将之前讲的无模型预测和控制扩展到这种情况呢?这就是本部分要讲的函数近似或逼近

6.1 学习目标

  • 理解相较于查表法函数逼近的动机;
  • 理解如何将函数逼近集成到现有的算法中;
  • 代码实现线性函数逼近的Q学习。

6.2 值函数近似

之前的内容是通过查表法来表达值函数,一种方式就是记录每个状态的值V(s),另一种就是状态-动作值函数Q(s,a),但是面对大规模MDPs时,可能会有太多的状态或动作而无法内存存储,哪怕能存储,对于这么大的一张表格进行学习,速度也是很慢的。因此一种简单的方式就是建立参数近似函数来逼近真正的价值。
v^(s,w)≈vπ(s)\hat{v}(s, \mathbf{w}) \approx v_{\pi}(s)v^(s,w)≈vπ​(s)
or q^(s,a,w)≈qπ(s,a)\text { or } \hat{q}(s, a, \mathbf{w}) \approx q_{\pi}(s, a) or q^​(s,a,w)≈qπ​(s,a)
其中w\mathbf{w}w表示权重,或者说是逼近器的参数,通过对特征基进行加权求和。
通过这样的方式,只要给定状态或状态-动作对,就能给出相应的近似值,一方面减少了内存占用,更重要的是可以预测未知状态下的价值,从而大大增强泛化性。而w\mathbf{w}w可以借助MC或TD学习进行更新。

值函数近似就像是一个黑盒子,只要给定输入就能得到输出,根据输入和输出的不同,可以分为三种类型,如图1所示。

  1. 输入状态,输出值函数;
  2. 输入状态和动作,输出状态-动作值函数;
  3. 输入状态,输出每个动作的状态-动作值函数。

图1 值函数近似的不同类型

应该选择什么样的函数逼近器呢?目前有很多方式可以实现,如下所示,但一般考虑选择可微分的函数逼近器,例如下面的线性特征组合和神经网络。除此之外,还需要一种适用于非平稳、非独立同分布数据的训练方法。

  1. 线性特征组合
  2. 神经网络
  3. 决策树
  4. 最近邻域
  5. 傅里叶/小波基
  6. ……

6.2 增量式方法

6.2.1 梯度下降

梯度下降

设J(w)J(\mathbf{w})J(w)为参数向量w\mathbf{w}w的可微函数,J(w)J(\mathbf{w})J(w)的梯度定义为对J(w)J(\mathbf{w})J(w)在w\mathbf{w}w的各个维度上分别进行偏微分,即
∇wJ(w)=(∂J(w)∂w1⋮∂J(w)∂wn)\nabla_{\mathbf{w}} J(\mathbf{w})=\left(\begin{array}{c} \frac{\partial J(\mathbf{w})}{\partial \mathbf{w}_{1}} \\ \vdots \\ \frac{\partial J(\mathbf{w})}{\partial \mathbf{w}_{n}} \end{array}\right)∇w​J(w)=⎝⎜⎜⎛​∂w1​∂J(w)​⋮∂wn​∂J(w)​​⎠⎟⎟⎞​
为了找到J(w)J(\mathbf{w})J(w)的局部最小值,只需要沿着负梯度方向更新w\mathbf{w}w即可:
Δw=−12α∇wJ(w)\Delta \mathbf{w}=-\frac{1}{2} \alpha \nabla_{\mathbf{w}} J(\mathbf{w})Δw=−21​α∇w​J(w)
其中α\alphaα为步长参数。

随机梯度下降的值函数近似

一个好的逼近器就是要尽量减少近似值和真实值之间的误差,因此函数逼近的目标就是找到一个参数向量w\mathbf{w}w,使得近似值v^(s,w)\hat{v}(s, \mathbf{w})v^(s,w)和vπ(s)v_{\pi}(s)vπ​(s)之间的均方误差最小:
J(w)=Eπ[(vπ(S)−v^(S,w))2]J(\mathbf{w})=\mathbb{E}_{\pi}\left[\left(v_{\pi}(S)-\hat{v}(S, \mathbf{w})\right)^{2}\right]J(w)=Eπ​[(vπ​(S)−v^(S,w))2]
通过使用梯度下降,可以按照如下进行参数更新:
Δw=−12α∇wJ(w)=αEπ[(vπ(S)−v^(S,w))∇wv^(S,w)]\begin{aligned} \Delta \mathbf{w} &=-\frac{1}{2} \alpha \nabla_{\mathbf{w}} J(\mathbf{w}) \\ &=\alpha \mathbb{E}_{\pi}\left[\left(v_{\pi}(S)-\hat{v}(S, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{v}(S, \mathbf{w})\right] \end{aligned}Δw​=−21​α∇w​J(w)=αEπ​[(vπ​(S)−v^(S,w))∇w​v^(S,w)]​
而在实际更新时并不是使用全梯度下降,而是随机采样一个状态,去评判该状态下的真实价值与近似值之间的误差:
Δw=α(vπ(S)−v^(S,w))∇wv^(S,w)\Delta \mathbf{w}=\alpha\left(v_{\pi}(S)-\hat{v}(S, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{v}(S, \mathbf{w})Δw=α(vπ​(S)−v^(S,w))∇w​v^(S,w)

6.2.2 线性函数逼近

特征向量

可以使用一组特征向量来表达状态,特征向量中每个元素都是状态的一个具体表现:
x(S)=(x1(S)⋮xn(S))\mathbf{x}(S)=\left(\begin{array}{c} \mathbf{x}_{1}(S) \\ \vdots \\ \mathbf{x}_{n}(S) \end{array}\right)x(S)=⎝⎜⎛​x1​(S)⋮xn​(S)​⎠⎟⎞​
例如:

  • 机器人与地标的距离
  • 股票市场的走势
  • 象棋中车和卒的局面

线性值函数近似

使用特征向量的最简单的方法就是对这些特征进行线性组合来表达近似值函数:
v^(S,w)=x(S)⊤w=∑j=1nxj(S)wj\hat{v}(S, \mathbf{w})=\mathbf{x}(S)^{\top} \mathbf{w}=\sum_{j=1}^{n} \mathbf{x}_{j}(S) \mathbf{w}_{j}v^(S,w)=x(S)⊤w=j=1∑n​xj​(S)wj​
同样目标函数是真实值与近似值之间的均方误差:
J(w)=Eπ[(vπ(S)−x(S)⊤w)2]J(\mathbf{w})=\mathbb{E}_{\pi}\left[\left(v_{\pi}(S)-\mathbf{x}(S)^{\top} \mathbf{w}\right)^{2}\right]J(w)=Eπ​[(vπ​(S)−x(S)⊤w)2]
同样采用随机梯度下降,可以得到如下很简单的参数更新规则:
∇wv^(S,w)=x(S)Δw=α(vπ(S)−v^(S,w))x(S)\begin{aligned} \nabla_{\mathbf{w}} \hat{v}(S, \mathbf{w}) &=\mathbf{x}(S) \\ \Delta \mathbf{w} &=\alpha\left(v_{\pi}(S)-\hat{v}(S, \mathbf{w})\right) \mathbf{x}(S) \end{aligned}∇w​v^(S,w)Δw​=x(S)=α(vπ​(S)−v^(S,w))x(S)​
因此,在线性值函数近似情况下,更新规则可以概括为:
Update === step-size ×\times× prediction error ×\times× feature value

查表特征

查表实际上是线性值函数近似的一种特殊情况,查表特征可以表示为:
xtable(S)=(1(S=s1)⋮1(S=sn))\mathbf{x}^{\text {table}}(S)=\left(\begin{array}{c} \mathbf{1}\left(S=s_{1}\right) \\ \vdots \\ \mathbf{1}\left(S=s_{n}\right) \end{array}\right)xtable(S)=⎝⎜⎛​1(S=s1​)⋮1(S=sn​)​⎠⎟⎞​
对于状态1,如果处在状态1,则对应位置的值为1否则为0,其他状态以此类推(类似于独热编码)。
只要给定参数向量w\mathbf{w}w,就可以通过查表特征与权重的点积计算近似值函数。
v^(S,w)=(1(S=s1)⋮1(S=sn))⋅(w1⋮wn)\hat{v}(S, \mathbf{w})=\left(\begin{array}{c} \mathbf{1}\left(S=s_{1}\right) \\ \vdots \\ \mathbf{1}\left(S=s_{n}\right) \end{array}\right) \cdot\left(\begin{array}{c} \mathbf{w}_{1} \\ \vdots \\ \mathbf{w}_{n} \end{array}\right)v^(S,w)=⎝⎜⎛​1(S=s1​)⋮1(S=sn​)​⎠⎟⎞​⋅⎝⎜⎛​w1​⋮wn​​⎠⎟⎞​

6.2.3 增量预测算法

增量预测算法

前面讲的两种方法(梯度下降和线性逼近)其实有一个前提,就是真实价值函数是已知的,这样就变成了监督学习,但是很遗憾的是,真实值函数往往不能提前已知,并且强化学习中也只能给出奖励值,最基本的方法就是利用之前的蒙特卡洛方法和时序差分方法来设立真实值函数的目标。

  • 对于MC,目标就是回报值GtG_{t}Gt​,则对应更新为:
    Δw=α(Gt−v^(St,w))∇wv^(St,w)\Delta \mathbf{w}=\alpha\left(G_{t}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right)Δw=α(Gt​−v^(St​,w))∇w​v^(St​,w)
  • 对于TD(0),目标为TD目标Rt+1+γv^(St+1,w)R_{t+1}+\gamma \hat{v}\left(S_{t+1}, \mathbf{w}\right)Rt+1​+γv^(St+1​,w):
    Δw=α(Rt+1+γv^(St+1,w)−v^(St,w))∇wv^(St,w)\Delta \mathbf{w}=\alpha\left(R_{t+1}+\gamma \hat{v}\left(S_{t+1}, \mathbf{w}\right)-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right)Δw=α(Rt+1​+γv^(St+1​,w)−v^(St​,w))∇w​v^(St​,w)
  • 对于TD(λ\lambdaλ),目标为λ\lambdaλ回报GtλG_{t}^{\lambda}Gtλ​:
    Δw=α(Gtλ−v^(St,w))∇wv^(St,w)\Delta \mathbf{w}=\alpha\left(G_{t}^{\lambda}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right)Δw=α(Gtλ​−v^(St​,w))∇w​v^(St​,w)

基于值函数近似的蒙特卡洛

其实上面讲的设定目标的过程和监督学习很相近,当使用蒙特卡洛方法时,主要使用的是returnGtG_{t}Gt​,这个过程就是完善建立训练数据,但这个过程是逐渐累积完成的,首先看到了状态S1S_{1}S1​,在该状态下有一个轨迹,然后得到一个回报G1G_{1}G1​,接下来状态S2S_{2}S2​得到回报G2G_{2}G2​,以此类推直到结束状态。
⟨S1,G1⟩,⟨S2,G2⟩,…,⟨ST,GT⟩\left\langle S_{1}, G_{1}\right\rangle,\left\langle S_{2}, G_{2}\right\rangle, \ldots,\left\langle S_{T}, G_{T}\right\rangle⟨S1​,G1​⟩,⟨S2​,G2​⟩,…,⟨ST​,GT​⟩
现在需要做的基本上和监督学习一下,把上述过程生成的数据看成真实数据,只需要调整值函数近似模型去不断逼近这些数值即可。
例如使用线性蒙特卡洛策略评估的更新方式如下:
Δw=α(Gt−v^(St,w))∇wv^(St,w)=α(Gt−v^(St,w))x(St)\begin{aligned} \Delta \mathbf{w} &=\alpha\left(G_{t}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right) \\ &=\alpha\left(G_{t}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \mathbf{x}\left(S_{t}\right) \end{aligned}Δw​=α(Gt​−v^(St​,w))∇w​v^(St​,w)=α(Gt​−v^(St​,w))x(St​)​
在蒙特卡洛中GtG_{t}Gt​是无偏的,通过随机梯度下降,蒙特卡洛评估总能收敛到最优,但是学习过程会比较漫长。

基于值函数近似的TD学习

TD学习同样采用了相同的思想,只不过现在的TD目标Rt+1+γv^(St+1,w)R_{t+1}+\gamma \hat{v}\left(S_{t+1}, \mathbf{w}\right)Rt+1​+γv^(St+1​,w)是有偏的,但仍然可以将监督学习应用以下训练数据:
⟨S1,R2+γv^(S2,w)⟩,⟨S2,R3+γv^(S3,w)⟩,…,⟨ST−1,RT⟩\left\langle S_{1}, R_{2}+\gamma \hat{v}\left(S_{2}, \mathbf{w}\right)\right\rangle,\left\langle S_{2}, R_{3}+\gamma \hat{v}\left(S_{3}, \mathbf{w}\right)\right\rangle, \ldots,\left\langle S_{T-1}, R_{T}\right\rangle⟨S1​,R2​+γv^(S2​,w)⟩,⟨S2​,R3​+γv^(S3​,w)⟩,…,⟨ST−1​,RT​⟩
例如对于线性TD(0),更新如下:
Δw=α(R+γv^(S′,w)−v^(S,w))∇wv^(S,w)=αδx(S)\begin{aligned} \Delta \mathbf{w} &=\alpha\left(R+\gamma \hat{v}\left(S^{\prime}, \mathbf{w}\right)-\hat{v}(S, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{v}(S, \mathbf{w}) \\ &=\alpha \delta \mathbf{x}(S) \end{aligned}Δw​=α(R+γv^(S′,w)−v^(S,w))∇w​v^(S,w)=αδx(S)​
线性TD(0)能收敛或接近全局最优。

基于值函数近似的TD(λ\lambdaλ)

GtλG_{t}^{\lambda}Gtλ​也是真实值函数的有偏估计,可以将监督学习应用到以下训练数据:
⟨S1,G1λ⟩,⟨S2,G2λ⟩,…,⟨ST−1,GT−1λ⟩\left\langle S_{1}, G_{1}^{\lambda}\right\rangle,\left\langle S_{2}, G_{2}^{\lambda}\right\rangle, \ldots,\left\langle S_{T-1}, G_{T-1}^{\lambda}\right\rangle⟨S1​,G1λ​⟩,⟨S2​,G2λ​⟩,…,⟨ST−1​,GT−1λ​⟩
例如对于前向视角线性TD(λ\lambdaλ),更新如下:
Δw=α(Gtλ−v^(St,w))∇wv^(St,w)=α(Gtλ−v^(St,w))x(St)\begin{aligned} \Delta \mathbf{w} &=\alpha\left(G_{t}^{\lambda}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right) \\ &=\alpha\left(G_{t}^{\lambda}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \mathbf{x}\left(S_{t}\right) \end{aligned}Δw​=α(Gtλ​−v^(St​,w))∇w​v^(St​,w)=α(Gtλ​−v^(St​,w))x(St​)​
对于后向视角线性TD(λ\lambdaλ),更新如下:
δt=Rt+1+γv^(St+1,w)−v^(St,w)Et=γλEt−1+x(St)Δw=αδtEt\begin{aligned} \delta_{t} &=R_{t+1}+\gamma \hat{v}\left(S_{t+1}, \mathbf{w}\right)-\hat{v}\left(S_{t}, \mathbf{w}\right) \\ E_{t} &=\gamma \lambda E_{t-1}+\mathbf{x}\left(S_{t}\right) \\ \Delta \mathbf{w} &=\alpha \delta_{t} E_{t} \end{aligned}δt​Et​Δw​=Rt+1​+γv^(St+1​,w)−v^(St​,w)=γλEt−1​+x(St​)=αδt​Et​​
但是对于前向和后向线性TD(λ\lambdaλ)是等效的。

6.2.4 增量控制算法

基于值函数近似的控制

控制部分采用广义迭代策略的概念,先进行策略评估,这里运用的是近似策略评估q^(⋅,⋅,w)≈qπ\hat{q}(\cdot, \cdot, \mathbf{w}) \approx q_{\pi}q^​(⋅,⋅,w)≈qπ​,然后进行ϵ\epsilonϵ-greedy策略改进。

动作值函数近似

这里同样使用参数向量w\mathbf{w}w来近似表达动作值函数:
q^(S,A,w)≈qπ(S,A)\hat{q}(S, A, \mathbf{w}) \approx q_{\pi}(S, A)q^​(S,A,w)≈qπ​(S,A)
目标函数就是最小化近似动作值函数q^(S,A,w)\hat{q}(S, A, \mathbf{w})q^​(S,A,w)与真实动作值函数qπ(S,A)q_{\pi}(S, A)qπ​(S,A)之间的均方误差:
J(w)=Eπ[(qπ(S,A)−q^(S,A,w))2]J(\mathbf{w})=\mathbb{E}_{\pi}\left[\left(q_{\pi}(S, A)-\hat{q}(S, A, \mathbf{w})\right)^{2}\right]J(w)=Eπ​[(qπ​(S,A)−q^​(S,A,w))2]
使用随机梯度下降进行参数更新,找到局部最优:
−12∇wJ(w)=(qπ(S,A)−q^(S,A,w))∇wq^(S,A,w)Δw=α(qπ(S,A)−q^(S,A,w))∇wq^(S,A,w)\begin{aligned} -\frac{1}{2} \nabla_{\mathbf{w}} J(\mathbf{w}) &=\left(q_{\pi}(S, A)-\hat{q}(S, A, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{q}(S, A, \mathbf{w}) \\ \Delta \mathbf{w} &=\alpha\left(q_{\pi}(S, A)-\hat{q}(S, A, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{q}(S, A, \mathbf{w}) \end{aligned}−21​∇w​J(w)Δw​=(qπ​(S,A)−q^​(S,A,w))∇w​q^​(S,A,w)=α(qπ​(S,A)−q^​(S,A,w))∇w​q^​(S,A,w)​

线性动作值函数近似

使用特征向量表达状态和动作:
x(S,A)=(x1(S,A)⋮xn(S,A))\mathbf{x}(S, A)=\left(\begin{array}{c} \mathbf{x}_{1}(S, A) \\ \vdots \\ \mathbf{x}_{n}(S, A) \end{array}\right)x(S,A)=⎝⎜⎛​x1​(S,A)⋮xn​(S,A)​⎠⎟⎞​
通过特征的加权线性组合可以表达动作值函数:
q^(S,A,w)=x(S,A)⊤w=∑j=1nxj(S,A)wj\hat{q}(S, A, \mathbf{w})=\mathbf{x}(S, A)^{\top} \mathbf{w}=\sum_{j=1}^{n} \mathbf{x}_{j}(S, A) \mathbf{w}_{j}q^​(S,A,w)=x(S,A)⊤w=j=1∑n​xj​(S,A)wj​
随机梯度下降更新如下:
∇wq^(S,A,w)=x(S,A)Δw=α(qπ(S,A)−q^(S,A,w))x(S,A)\begin{aligned} \nabla_{\mathbf{w}} \hat{q}(S, A, \mathbf{w}) &=\mathbf{x}(S, A) \\ \Delta \mathbf{w} &=\alpha\left(q_{\pi}(S, A)-\hat{q}(S, A, \mathbf{w})\right) \mathbf{x}(S, A) \end{aligned}∇w​q^​(S,A,w)Δw​=x(S,A)=α(qπ​(S,A)−q^​(S,A,w))x(S,A)​

增量控制算法

  • 对于MC,目标是GtG_{t}Gt​,更新如下:
    Δw=α(Gt−q^(St,At,w))∇wq^(St,At,w)\Delta \mathbf{w}=\alpha\left(G_{t}-\hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)Δw=α(Gt​−q^​(St​,At​,w))∇w​q^​(St​,At​,w)
  • 对于TD(0),目标是TD目标Rt+1+γQ(St+1,At+1)R_{t+1}+\gamma Q\left(S_{t+1}, A_{t+1}\right)Rt+1​+γQ(St+1​,At+1​),更新如下:
    Δw=α(Rt+1+γq^(St+1,At+1,w)−q^(St,At,w))∇wq^(St,At,w)\Delta \mathbf{w}=\alpha\left(R_{t+1}+\gamma \hat{q}\left(S_{t+1}, A_{t+1}, \mathbf{w}\right)-\hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)Δw=α(Rt+1​+γq^​(St+1​,At+1​,w)−q^​(St​,At​,w))∇w​q^​(St​,At​,w)
  • 对于前向TD(λ)T D(\lambda)TD(λ),目标为动作值λ\lambdaλ-回报,更新如下:
    Δw=α(qtλ−q^(St,At,w))∇wq^(St,At,w)\Delta \mathbf{w}=\alpha\left(q_{t}^{\lambda}-\hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)Δw=α(qtλ​−q^​(St​,At​,w))∇w​q^​(St​,At​,w)
  • 对于后向TD(λ)T D(\lambda)TD(λ),等效的更新如下:
    δt=Rt+1+γq^(St+1,At+1,w)−q^(St,At,w)Et=γλEt−1+∇wq^(St,At,w)Δw=αδtEt\begin{aligned} \delta_{t} &=R_{t+1}+\gamma \hat{q}\left(S_{t+1}, A_{t+1}, \mathbf{w}\right)-\hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right) \\ E_{t} &=\gamma \lambda E_{t-1}+\nabla_{\mathbf{w}} \hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right) \\ \Delta \mathbf{w} &=\alpha \delta_{t} E_{t} \end{aligned}δt​Et​Δw​=Rt+1​+γq^​(St+1​,At+1​,w)−q^​(St​,At​,w)=γλEt−1​+∇w​q^​(St​,At​,w)=αδt​Et​​

6.3 代码实现

代码实现部分我们选用Mountain Car作为环境,环境使用位置和速度表达状态,动作有3个:向左,不动和向右。下面给出了线性逼近的Q学习算法代码。

import gym
import itertools
import matplotlib
import numpy as np
import sys
import sklearn.pipeline
import sklearn.preprocessingif "../" not in sys.path:sys.path.append("../")from Lib import plotting
from sklearn.linear_model import SGDRegressor
from sklearn.kernel_approximation import RBFSamplermatplotlib.style.use('ggplot')env = gym.envs.make("MountainCar-v0")# 特征预处理:归一化为均值为0,方差为1
# 从观察空间中采样部分样本
observation_examples = np.array([env.observation_space.sample() for x in range(10000)])
scaler = sklearn.preprocessing.StandardScaler()
scaler.fit(observation_examples)# 用于将状态转换成特征表达
# 使用不同方差的RBF核来覆盖空间的不同部分
featurizer = sklearn.pipeline.FeatureUnion([("rbf1", RBFSampler(gamma=5.0, n_components=100)),("rbf2", RBFSampler(gamma=2.0, n_components=100)),("rbf3", RBFSampler(gamma=1.0, n_components=100)),("rbf4", RBFSampler(gamma=0.5, n_components=100))])
featurizer.fit(scaler.transform(observation_examples))class Estimator():"""值函数逼近器."""def __init__(self):# 为环境的动作空间中的每个动作创建一个单独的模型。或者,我们可以以某种方式将动作编码到特性中,但是这样更容易编码。self.models = []for _ in range(env.action_space.n):model = SGDRegressor(learning_rate="constant")# 需要调用一次partial_fit来初始化模型# 或者在预测时获取NotFittedErrormodel.partial_fit([self.featurize_state(env.reset())], [0])self.models.append(model)def featurize_state(self, state):"""返回状态的特征化表达."""scaled = scaler.transform([state])featurized = featurizer.transform(scaled)return featurized[0]def predict(self, s, a=None):"""进行值函数预测.参数:s: 需要预测的状态a: (可选) 需要预测的动作返回值:如果给定了动作a,则返回一个数值作为预测结果如果没有给定a,则返回一个向量来预测环境中的所有动作,其中pred[i]为对动作i的预测"""features = self.featurize_state(s)if not a:return np.array([m.predict([features])[0] for m in self.models])else:return self.models[a].predict([features])[0]def update(self, s, a, y):"""给定状态和动作,更新逼近器参数以靠近目标y"""features = self.featurize_state(s)self.models[a].partial_fit([features], [y])def make_epsilon_greedy_policy(estimator, epsilon, nA):"""根据给定的Q函数逼近器和epsilon,创建epsilon贪婪策略.参数:逼近器: 返回给定状态下的q值epsilon: 随机选择动作的概率between 0 and 1nA: 环境中动作数量返回值:返回一个函数,以观察为参数,以长度为nA的numpy数组的形式返回每个动作的概率"""def policy_fn(observation):A = np.ones(nA, dtype=float) * epsilon / nAq_values = estimator.predict(observation)best_action = np.argmax(q_values)A[best_action] += (1.0 - epsilon)return Areturn policy_fndef q_learning(env, estimator, num_episodes, discount_factor=1.0, epsilon=0.1, epsilon_decay=1.0):"""使用函数逼近进行离策略TD控制的Q学习.遵循epsilon贪婪策略以寻找最优贪婪策略.参数:env: OpenAI环境.estimator: 动作值函数逼近器num_episodes: 迭代次数.discount_factor: Gamma折扣因子.epsilon: 随机选择动作的概率betwen 0 and 1.epsilon_decay: 每个片段中,epsilon都以该因子进行衰减返回值:一个片段状态对象,包括两个numpy数组,用于分别存放片段长度和片段奖励."""# 进行必要的统计stats = plotting.EpisodeStats(episode_lengths=np.zeros(num_episodes),episode_rewards=np.zeros(num_episodes))for i_episode in range(num_episodes):# 正在遵循的策略policy = make_epsilon_greedy_policy(estimator, epsilon * epsilon_decay ** i_episode, env.action_space.n)last_reward = stats.episode_rewards[i_episode - 1]sys.stdout.flush()# 重置环境state = env.reset()# 只针对SARSA有用next_action = None# 环境中迭代执行每一步for t in itertools.count():# 选择动作# 如果使用的时SARSA,next_action在前一步已经确定了if next_action is None:action_probs = policy(state)action = np.random.choice(np.arange(len(action_probs)), p=action_probs)else:action = next_action# 单步执行next_state, reward, done, _ = env.step(action)# 更细统计stats.episode_rewards[i_episode] += rewardstats.episode_lengths[i_episode] = t# TD更新q_values_next = estimator.predict(next_state)# 学习Q-Learning的TD目标td_target = reward + discount_factor * np.max(q_values_next)# 使用下面的代码进行SARSA在策略控制# next_action_probs = policy(next_state)# next_action = np.random.choice(np.arange(len(next_action_probs)), p=next_action_probs)# td_target = reward + discount_factor * q_values_next[next_action]# 使用目标更新函数逼近器estimator.update(state, action, td_target)print("\rStep {} @ Episode {}/{} ({})".format(t, i_episode + 1, num_episodes, last_reward), end="")if done:breakstate = next_statereturn statsestimator = Estimator()
# 注意: 对于Mountain Car游戏,不必保证epsilon>0.0
# 因为对所有状态的初始估计太过乐观,从而导致对所有状态进行探索.
stats = q_learning(env, estimator, 100, epsilon=0.0)plotting.plot_cost_to_go_mountain_car(env, estimator)
plotting.plot_episode_stats(stats, smoothing_window=25)

最终学习到的位置和速度与值函数的关系如下。

整体上随着迭代次数的增多,小车爬上山坡需要的部属逐渐下降,如下所示。

随着迭代次数的增加,片段奖励呈现上升趋势,如下所示。

第六章 函数逼近-强化学习理论学习与代码实现(强化学习导论第二版)相关推荐

  1. python程序设计与基础教程第六章上机实验_《Python程序设计与算法基础教程(第二版)》江红 余青松 课后代码题详解...

    (还在更新中-) 这本书对Python的知识点的描述很详细,而且排版看的很舒服 几个例题: 假装自己从零开始学,将一些有代表性.有意思的例题抽取出来 部分复习题: 遇到有意思的复习题,我会拿出来,并且 ...

  2. Python 精要参考(第二版) 第六章 函数与函数编程

    1. 第六章 函数与函数编程 为便于代码维护,绝大多数子程序都被分解并重新组织为函数以使代码模块化. 在 Python中定义一个函数很简单,Python从其它函数编程语言中借鉴了很多有用的思路用来简化 ...

  3. 【数理知识】《数值分析》李庆扬老师-第3章-函数逼近与快速傅里叶变换

    第2章 回到目录 第4章 第3章-函数逼近与快速傅里叶变换 3.1 函数逼近的基本概念 3.2 正交多项式 3.3 最佳平方逼近 3.4 曲线拟合的最小二乘法 3.5 有利逼近 3.6 三角多项式逼近 ...

  4. python第六章函数课后答案_浙大PTA-Python题库 函数题(6-1~6-6)题解

    其他各章题解链接如下 浙大PTA-Python题库 编程题第一章(1-1~1-3)题解 https://blog.csdn.net/zimuzi2019/article/details/1070206 ...

  5. 给定一个函数做其最佳平方逼近c语言,第三章 函数逼近 — 最佳平方逼近.

    第三章 函数逼近 - 最佳平方逼近 内容提要 最佳平方逼近 最佳平方逼近函数.多项式 利用正交多项式计算最佳平方逼近多项式 Chebyshev 级数与最佳一致逼近 最佳平方逼近 什么是最佳平方逼近 设 ...

  6. C++ Primer 第六章—— 函数 思维导图

    C++ Primer 第六章-- 函数 思维导图 前言:该博文的定位是,您已经对C语言的基础知识和C++ Primer该书或C++知识有了基本了解.而在阅读C++ Primer(第五版)之后,感觉知识 ...

  7. MICK-SQL基础教程(第二版) 第六章 函数、谓词、CASE表达式

    第六章 函数.谓词.CASE表达式 函数 函数大致可以分为以下几种: 算术函数(用来进行数值计算的函数) 字符串函数(用来进行字符串操作的函数) 日期函数(用来进行日期操作的函数) 转换函数(用来转换 ...

  8. 《动手学深度学习(Dive into Deeplearning)》(第二版)——第二章 _2.3 线性代数

    <动手学深度学习(Dive into Deeplearning)>(第二版)--第二章 _2.3 线性代数 第二章 预备知识 § 前情回顾 § 2.3 线性代数 2.3.1 标量 2.3. ...

  9. 《C++ Primer》读书笔记—第六章 函数

    声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程 一.函数基础 1.一个典型的函数定义包括以下内容:返回 ...

  10. 学习最新《微信小程序实战入门第二版》PDF+源程序代码+刘明洋

    学习了第2版的微信小程序实战入门,还是比较容易上手的,通过案例学习小程序语言的实战技巧,更容易理解,并能马上学以致用.对于每一部分具体内容,都设计了相应的示例程序,一方面可以帮助加深理解,另一方面也可 ...

最新文章

  1. Hibernate程序性能优化的考虑要点
  2. Node.js v7 Beta版引入citgm
  3. html5基础知识点制作图片
  4. 图像算法中常用的数学概念
  5. 使用Android手机进行开发的尝试
  6. JavaWeb项目开发流程
  7. canon l11121e驱动_佳能L11121e驱动
  8. python爬取京东书籍_利用Python爬取当当、京东、亚马逊图书信息代码实例源码
  9. 有限状态机代码生成器 FsmCrater
  10. 《从0到1上线微信小游戏》第九节 个人申请国家软件著作证书详细流程
  11. PNAS|助人为乐—助人行为能减轻自身身体疼痛
  12. 毕业设计——基于WEB的BBS论坛
  13. Win10笔记本扩展显示屏模糊处理办法
  14. python 仪表盘数据显示_Python制作仪表盘图,比Excel快速百倍
  15. 用 Wasm 为数据库增加用户定义函数
  16. 警告Warning: Nashorn engine is planned to be removed from a future JDK release
  17. 2012-03-28-1
  18. c语言a++与++a的区别
  19. 太极链老了,及四个统计服务比较
  20. 程序猿容易轻视的注释和送礼的八项原则

热门文章

  1. 文件备份软件 FreeFileSync
  2. 11. 数值的整数次方
  3. 19. Treat class design as type design
  4. jenkins忘记密码和常用插件的下载
  5. buffer sort Oracle,SQL执行计划中的BUFFER SORT是什么意思呢,请高手指点.
  6. php mysql delimiter,MySql delimiter的作用是什么_MySQL
  7. 使用vagrant快速创建Linux(centos/7)
  8. spring新注解说明
  9. mysql考试会自动给我们放好路径吗_Jsp struts mysql实现的在线考试系统项目源码附带视频运行教程...
  10. python设置excel的格式_python 操作Excel 设置格式