引自:https://zhuanlan.zhihu.com/c_1060499676423471104
第一部分探讨了很多基于表格(table-based method)的方法。但是实际中,由于状态空间太大,表格型的方法基本上没法用的。其一是因为我们没有足够的内存来存储如此大量的状态值。更重要的原因也是因为我们没有足够的时间和数据来获得精确的值函数。在基于表格的方法中,往往我们只需要记录下状态的值,决策仅仅是一个查值比较的过程。可是面临的问题状态空间很大时,我们几乎不可能访问同一个状态两次,你怎么查表?你可能想到能不能利用周围已知状态的值来近似新状态的值。这个直觉是对的,但是这种近似到底靠谱不靠呢?这就涉及到了ML中一个最为核心的问题:泛化性。
所幸的是,已经有了大量的方法解决从样本中泛化的问题。我们只需要结合RL和现存的泛化方法就行。这就是本部分介绍的值函数近似(function approximation)方法。为什么叫值函数近似呢?首先我们要学的目标是值函数,其次我们希望将有限样本上的值泛化到整个状态空间(近似)。熟悉ML的都知道,这不就是一个曲线拟合或者说监督学习问题吗?确实如此,这就是一个监督学习问题。我们可以用机器学习,神经网络,模式识别和曲线拟合中任何回归方法来解决这个问题。
但是,基于RL的函数近似也有一些新的问题。比如:非静态性,自举,延迟目标。本部分就这些问题展开讨论。
首先对于策略预测方法来讲,我们的目标还是求解值函数,同时这里添加了近似的意思。这里的“近似”的含义,也就是说我们不再把 V π V_\pi Vπ表示为一个表格,而是以一个向量 w ∈ R d w∈\mathbb{R}_d w∈Rd为参数的函数。所以$ \hat{v}(s,w)≈v_\pi(s) , , ,\hat{v}(s,w)$是估计值,是状态s和参数w的函数。w是状态特征向量的权重,也可以是一个神经网络。w是网络的权重系数。通常来说,参数w的维度d远远小于状态数|s|,因此只需要存d个参数即可获得所有状态的值。但是存在一个问题就是,一个参数的改变可能会影响很多状态的值。这种泛化性使得问题难以处理和理解。
值函数近似的一个优势就是可以处理部分可观测的MDP问题,PROMDP。部分可观测指的是我们只知道部分状态的值,值函数近似本身就是用部分值去代替整个状态空间的值,所以也适用于PROMDP。
本书中涉及到的预测方法都可以描述为对当前估计的值函数的更新,其更新过程是朝着某个状态s的备份值backup value,这个备份值就是更新目标update target,记作 s ↦ u s\mapsto u s↦u。
因此基于MC的值预测就是 S t ↦ G t S_t\mapsto G_t St↦Gt;
基于TD(0)的值预测就是 S t ↦ R t + 1 + γ v ^ ( S t + 1 , w t ) S_t\mapsto R_{t+1}+\gamma \hat{v}(S_{t+1},w_t) St↦Rt+1+γv^(St+1,wt);基于n-step TD更新的值预测就是 S t ↦ G t : t + n S_t\mapsto G_{t:t+n} St↦Gt:t+n;基于DP的值预测就是 s ↦ E π [ R t + 1 + γ v ^ ( S t + 1 , w t ) ∣ S t = s ] s\mapsto \mathbb{E}_\pi[R_{t+1}+\gamma \hat{v}(S_{t+1},w_t)|S_t = s] s↦Eπ[Rt+1+γv^(St+1,wt)∣St=s].因为使用的是值近似的方法,所以这里的值函数是估计的。
每个update都可以理解为是值函数的一个期望输入和一个期望输出,我们的目标就是让s尽可能的逼近u。在机器学习中这样输入-输出的样例构成一个训练样本,这是一个监督学习问题。如果输出的是数值的话,那么就叫做函数拟合,我们这里称作值函数近似。
如果我们把上述这样的更新看做是一个传统的训练样本的话,就可以用很多值函数近似的方法解决预测问题。比如神经网络、多元回归等等。但是要适用于rl的值函数近似方法有一定的要求。首先就是算法能够高效的进行增量式学习 ,其次就是要能够处理非静态目标 。在GPI中策略是不断变化的,所以我们的目标也就是不断变化的。即使策略不变,那么更新目标也会因为自举发生一定的变化。因此,无法处理这种非静态性的方法不适用于RL。
尽管有很多值函数近似的方法可以供我们直接使用,但是在预测过程中我们总要有个预测目标对吧。既然是近似,那么我们的目标自然就是update target越接近目标值越好,也就是要评判近似的程度。什么样的近似是好的。在监督学习中指的就是用什么样的损失函数,在值函数近似中,叫做值误差 value error。
在基于表格的方法中,每个状态的值是解耦的,相互之间并无关系,但是对于值函数近似的rl来说,状态之间是耦合的,一个状态的改变可能会影响其余多个状态,因此在近似的过程中,我们无法保证每个状态的状态值都是精确的,这主要是因为参数w的数目远远小于状态的数量。所以这就需要我们只关注我们关心的状态,因此需要定义一个损失函数,使得算法知道我们关心哪些状态。
最简单的误差指标就是MSE, v ^ ( s , w ) \hat{v}(s,w) v^(s,w)是估计值,真实值是 v π ( s ) v_\pi(s) vπ(s),均方误差定义为$ \frac{1}{n} \sum_{s \in \mathcal{S}} \left[v_{\pi}(s)-\hat{v}(s, \mathbf{w})\right]^{2} . 这 样 就 会 出 现 一 个 问 题 , 就 是 我 们 认 为 每 个 状 态 样 本 的 重 要 性 是 一 样 的 , 因 为 其 权 重 系 数 是 均 等 的 .这样就会出现一个问题,就是我们认为每个状态样本的重要性是一样的,因为其权重系数是均等的 .这样就会出现一个问题,就是我们认为每个状态样本的重要性是一样的,因为其权重系数是均等的\frac{1}{n} . 要 想 让 每 个 状 态 的 重 要 性 不 同 且 符 合 我 们 实 际 任 务 的 需 求 , 因 此 我 们 可 以 乘 以 一 个 权 重 分 布 系 数 , 因 此 可 以 定 义 一 个 状 态 分 布 .要想让每个状态的重要性不同且符合我们实际任务的需求,因此我们可以乘以一个权重分布系数,因此可以定义一个状态分布 .要想让每个状态的重要性不同且符合我们实际任务的需求,因此我们可以乘以一个权重分布系数,因此可以定义一个状态分布\mu(s) 表 示 对 不 同 状 态 s 的 关 注 程 度 。 表示对不同状态s的关注程度。 表示对不同状态s的关注程度。\mu(s) 满 足 满足 满足\mu(s) ≥0,\sum_{s} \mu(s)=1$.所以最终我们得到的是加权MSE:
V E ‾ ( w ) ≐ ∑ s ∈ S μ ( s ) [ v π ( s ) − v ^ ( s , w ) ] 2 \overline{\mathrm{VE}}(\mathbf{w}) \doteq \sum_{s \in \mathcal{S}} \mu(s)\left[v_{\pi}(s)-\hat{v}(s, \mathbf{w})\right]^{2} VE(w)≐s∈S∑μ(s)[vπ(s)−v^(s,w)]2
下面还有一个问题就是, μ ( s ) \mu(s) μ(s)到底该如何确定呢?一个办法就是根据状态的访问频率来确定其权重系数。正常来说,状态出现的越频繁,所以我们就越发关注它的误差,所以要给它一个大的权重系数。访问频率和policy有关,对于on-policy来说, μ ( s ) \mu(s) μ(s)实际上就是on-policy distribution,在continuing task中是一个确定的平稳的分布。对于episodic task来说就有些复杂:其on-policy distribution和episode的初始状态的选择有一定关系。假设我们使用 h ( s ) h(s) h(s)来表示每个episode初始状态的s的分布,用 η ( s ) \eta(s) η(s)表示每个episode中在状态s停留的平均时间。这个时候无非两种状态:要么就是一开始就是这个状态;要么就是是从别的状态转移到这个状态的。
所以状态s的平均逗留时间就可以表示为:
η ( s ) = h ( s ) + ∑ s ‾ η ( s ‾ ) ∑ a π ( a ∣ s ‾ ) p ( s ∣ s ‾ , a ) , for all s ∈ S \eta(s)=h(s)+\sum_{\overline{s}} \eta(\overline{s}) \sum_{a} \pi(a | \overline{s}) p(s | \overline{s}, a), \text { for all } s \in \mathcal{S} η(s)=h(s)+s∑η(s)a∑π(a∣s)p(s∣s,a), for all s∈S
然后可以对上式作归一化处理,即可得到episodic task在policy上的分布:
μ ( s ) = η ( s ) ∑ s ′ η ( s ′ ) , 对所有 s ∈ S \mu(s)=\frac{\eta(s)}{\sum_{s^{\prime}} \eta(s^{\prime})}, \quad \text { 对所有 } s \in \mathcal{S} μ(s)=∑s′η(s′)η(s), 对所有 s∈S
上面我们一直在讨论value error,但是这个指标作为损失函数是否合理。我们要预测值函数,是为了找到一个最大的值从而找到一个最优策略。但是最小化value error和和这个目标是不一致的。但是目前还没有找到更好的选择,暂且先使用这种方式。
一个最理想的目标就是能够找到全局最优的 w ∗ \mathbf{w}^{*} w∗,使其满足 V E ‾ ( w ∗ ) ≤ V E ‾ ( w ) \overline{VE}(\mathbf{w}^{*})≤\overline{VE}(\mathbf{w}) VE(w∗)≤VE(w),这对于一些简单的线性拟合器来说是有可能的,但是对于比较复杂的情况来说是不可能的。因此我们只能用局部代替最优,对于非线性近似器来讲做到这一地步已经可以了。后面会介绍一些approximator,主要是基于梯度的线性近似器。
随机梯度下降stochastic gradient descent,SGD在函数拟合问题中应用广泛,也适用于online RL。w是一个列向量, w ≐ ( w 1 , w 2 , … , w d ) ⊤ \mathbf{w} \doteq(w_{1}, w_{2}, \ldots, w_{d})^{\top} w≐(w1,w2,…,wd)⊤,且每个元素都是实数,值函数 v ^ ( s , w ) \hat{v}(s, \mathbf{w}) v^(s,w)实际上是w的微分方程,在每个离散的时间步长更新w,记做 w t w_t wt.假设在t时刻,我们观察到了一个样本数据 S t ↦ v π ( S t ) S_t\mapsto v_\pi(S_t) St↦vπ(St),我们的目标是更新 w t w_t wt使其当前状态的值和 v π ( S t ) v_\pi(S_t) vπ(St)之间的误差尽可能的小。但是由于近似器的表征能力有限,所以不可能存在w使得所有样本都精确的等于真实值。即使能够这样做,也尽可能避免这样做,因为这样做会导致过拟合。
回到我们的问题上来,我们的目标是最小化这样的值误差:
V E ‾ ( w ) ≐ ∑ s ∈ S μ ( s ) [ v π ( s ) − v ^ ( s , w ) ] 2 \overline{\mathrm{VE}}(\mathbf{w}) \doteq \sum_{s \in \mathcal{S}} \mu(s)\left[v_{\pi}(s)-\hat{v}(s, \mathbf{w})\right]^{2} VE(w)≐s∈S∑μ(s)[vπ(s)−v^(s,w)]2
SGD的想法是对于每个样本,都能够沿着最大的减小误差的方向(梯度方向)调整一小步权重:
w t + 1 ≐ w t − 1 2 α ∇ [ v π ( S t ) − v ^ ( S t , w t ) ] 2 = w t + α [ v π ( S t ) − v ^ ( S t , w t ) ] ∇ v ^ ( S t , w t ) \begin{aligned} \mathbf{w}_{t+1} & \doteq \mathbf{w}_{t}-\frac{1}{2} \alpha \nabla\left[v_{\pi}\left(S_{t}\right)-\hat{v}\left(S_{t}, \mathbf{w}_{t}\right)\right]^{2} \\ &=\mathbf{w}_{t}+\alpha\left[v_{\pi}\left(S_{t}\right)-\hat{v}\left(S_{t}, \mathbf{w}_{t}\right)\right] \nabla \hat{v}\left(S_{t}, \mathbf{w}_{t}\right) & \end{aligned} wt+1≐wt−21α∇[vπ(St)−v^(St,wt)]2=wt+α[vπ(St)−v^(St,wt)]∇v^(St,wt)
这里的 α \alpha α就是步长因子,上述式子实际上就是一个简单的求导过程。对一个函数参数是向量的函数,对该向量求导就等于函数对向量的每个分量求偏导,结果也就是一个向量:
∇ f ( w ) ≐ ( ∂ f ( w ) ∂ w 1 , ∂ f ( w ) ∂ w 2 , … , ∂ f ( w ) ∂ w d ) ⊤ \nabla f(\mathbf{w}) \doteq\left(\frac{\partial f(\mathbf{w})}{\partial w_{1}}, \frac{\partial f(\mathbf{w})}{\partial w_{2}}, \dots, \frac{\partial f(\mathbf{w})}{\partial w_{d}}\right)^{\top} ∇f(w)≐(∂w1∂f(w),∂w2∂f(w),…,∂wd∂f(w))⊤
随机梯度下降中的“随机”的意思指的是我们的更新过程,总是基于单个的样本来说的,或者说是批样本,而这些样本是随机选择的。
更新为什么是一小步的进行更新? 我们的目标就是要让value error更小,如果我们的更新步长 α \alpha α直接等于1,不就意味着我们的更新过程可以一步到位,让我们的估计值直接接近目标值,使得误差为0.但一般来说不这样做,由于基于值函数近似的rl方法的各个状态之间是相互耦合的,不可能使得每个状态都是精确的,因此倘若我们在这个状态下得到了一个非常精确的近似器,那么势必会在其他状态下得到一个很差劲的近似器。因此我们的目标并不是得到对每个状态都可以精确近似的近似器,我们的目标是可以得到一个能够很好的平衡各个状态的近似器 ,这样一来我们算法的泛化性就会更好一点。实际上,SGD的收敛性要求 α \alpha α随着时间递减。
广义梯度方法
上述关于参数w的更新还存在一定的问题,那就是我们的更新目标中的 v π ( S t ) v_\pi(S_t) vπ(St)实际上是未知的,一般的我们可以使用一个近似值 U t U_t Ut来表示更新目标,它有可能是一个含有噪声的 v π ( S t ) v_\pi(S_t) vπ(St),或者说是通过bootstrap得到的一个近似值。因此上述关于 w t + 1 w_{t+1} wt+1的更新表达式就变为 了:
w t + 1 ≐ w t + α [ U t − v ^ ( S t , w t ) ] ∇ v ^ ( S t , w t ) \mathbf{w}_{t+1} \doteq \mathbf{w}_{t}+\alpha\left[U_{t}-\hat{v}\left(S_{t}, \mathbf{w}_{t}\right)\right] \nabla \hat{v}\left(S_{t}, \mathbf{w}_{t}\right) wt+1≐wt+α[Ut−v^(St,wt)]∇v^(St,wt)
如果 U t U_t Ut是一个无偏估计的话, E [ U t ∣ S t = s ] = v π ( S t ) \mathbb{E}\left[U_{t} | S_{t}=s\right]=v_{\pi}(S_{t}) E[Ut∣St=s]=vπ(St),那么 w t w_t wt是可以保证收敛到局部最优的。
我们知道基于MC估计的值函数是无偏的,所以我们就可以得到一个基于MC的值预测方法,梯度MC方法。
基于MC得到回报,然后拟合一个估计函数 v ^ \hat{v} v^,使其在每个状态的值都接近 G t G_t Gt。执行过程就是不断的sample trajectory,利用MC方法计算 G t G_t Gt,然后再进行SGD。
什么是半梯度方法?
如果我们之前定义的 U t U_t Ut是有偏估计的话,比如是通过bootstrap得到的估计,例如DP的更新目标 ∑ a , s ′ , r π ( a ∣ S t ) p ( s ′ , r ∣ S t , a ) [ r + γ v ^ ( s ′ , w t ) ] \sum_{a,s^{\prime},r}\pi(a | S_{t}) p(s^{\prime}, r | S_{t}, a)\left[r+\gamma \hat{v}(s^{\prime}, \mathbf{w}_{t})\right] ∑a,s′,rπ(a∣St)p(s′,r∣St,a)[r+γv^(s′,wt)],此时DP的更新依赖于当前的权重值,但是这个权重值不是最优的或者说与真值是有差别的,所以估计得到的目标是有偏的。或者我们可以这么理解,要想求导之后得到这个式子,
w t + 1 ≐ w t + α [ U t − v ^ ( S t , w t ) ] ∇ v ^ ( S t , w t ) \mathbf{w}_{t+1} \doteq \mathbf{w}_{t}+\alpha\left[U_{t}-\hat{v}\left(S_{t}, \mathbf{w}_{t}\right)\right] \nabla \hat{v}\left(S_{t}, \mathbf{w}_{t}\right) wt+1≐wt+α[Ut−v^(St,wt)]∇v^(St,wt)
那就说明 U t U_t Ut必须与 w t w_t wt相互独立,但是对于bootstrap来说, U t U_t Ut也是 w t w_t wt的函数,因此估计得到的目标也是有偏的。所以上式就已经不是一个真正的梯度下降了。因为 w t w_t wt仅仅考虑了对于状态估计的影响,但是并没有考虑对于 U t U_t Ut的影响。换句话说仅仅考虑了部分梯度,所以说这是一种半梯度方法 。
虽然半梯度方法在收敛特性上没有梯度方法鲁棒,但是这种收敛也是有保证的,因为采用了自举,所以使得半梯度方法能够在线并且更快的学习。
半梯度方法的伪代码如下,与梯度MC不同的是更新的时候采用TD(0)来近似求解 U t U_t Ut, U t ≐ R t + 1 + γ v ^ ( S t + 1 , w ) U_{t} \doteq R_{t+1}+\gamma \hat{v}(S_{t+1}, \mathbf{w}) Ut≐Rt+1+γv^(St+1,w):
半梯度方法可以在每步上进行更新。
状态聚合state-aggregation: 状态聚合指的是一组状态共享一个估计值,并且只与权重向量w的一个分量有关。因此当某个组中的一个样本被更新的时候,只会影响当前组,状态聚合是SGD的一个特例,是一个比较特殊的梯度方法。在更新的时候,只有 S t S_t St所在的组的梯度值不为0,其他的都是0.
何谓线性模型?
近似函数 v ^ ( ⋅ , w ) \hat{v}(\cdot, \mathbf{w}) v^(⋅,w)是关于向量 w w w的一个线性函数,就说这是一个线性的近似器。具体来说就是,对于任意一个状态s来说,存在一个特征向量 x ( s ) ≐ ( x 1 ( s ) , x 2 ( s ) , … , x d ( s ) ) ⊤ \mathbf{x}(s) \doteq(x_{1}(s), x_{2}(s), \ldots, x_{d}(s))^{\top} x(s)≐(x1(s),x2(s),…,xd(s))⊤,其维度与w相同。因此线性的近似器就可以表示为w和x(s)的内积。
v ^ ( s , w ) ≐ w ⊤ x ( s ) ≐ ∑ i = 1 d w i x i ( s ) \hat{v}(s, \mathbf{w}) \doteq \mathbf{w}^{\top} \mathbf{x}(s) \doteq \sum_{i=1}^{d} w_{i} x_{i}(s) v^(s,w)≐w⊤x(s)≐i=1∑dwixi(s)
x(s)就是状态s的特征向量。特征向量的每个分量 x i x_i xi都是从状态s到 R \mathbb{R} R的一个映射。对于线性方法,每个特征映射实际上是一个基函数,他们定义了一组值函数空间的一组基。构造d维特征向量的过程其实就是选择一组基函数的过程。 特征可以有很多种定义方式,比如我们把某个点的二维坐标作为特征。把特征映射定义为求该点到原点的欧氏距离。这就是一个特征工程。也就是说,我们得到特征,然后根据定义好的特征映射得到一个结果,这个结果往往就是我们想要的或者就是接下来要进行评估的。当前比较流行的特征构造的方法就是使用神经网络。
SGD求解线性模型参数
使用SGD对上述的线性近似器进行求导得:$ \nabla \hat{v}(s, \mathbf{w})=\mathbf{x}(s)$,带入到之前的参数更新表达式中即可得到:
w t + 1 ≐ w t + α [ U t − v ^ ( S t , w t ) ] x ( S t ) \mathbf{w}_{t+1} \doteq \mathbf{w}_{t}+\alpha\left[U_{t}-\hat{v}\left(S_{t}, \mathbf{w}_{t}\right)\right] \mathbf{x}\left(S_{t}\right) wt+1≐wt+α[Ut−v^(St,wt)]x(St)
线性SGD的全局最优性
线性拟合器中只有一个最优解,所以局部最优就是全局最优。比如对于梯度MC算法,如果 α \alpha α满足收敛性条件的话,那么value error就能收敛到全局最优。
上节我们提到的半梯度TD(0)在线性拟合器上也可以收敛到一个全局最优解。
在线性近似器下,w的更新公式为:
w t + 1 ≐ w t + α ( R t + 1 + γ w t ⊤ x t + 1 − w t ⊤ x t ) x t = w t + α ( R t + 1 x t − x t ( x t − γ x t + 1 ) ⊤ w t ) \mathbf{w}_{t+1} \doteq \mathbf{w}_{t}+\alpha\left(R_{t+1}+\gamma \mathbf{w}_{t}^{\top} \mathbf{x}_{t+1}-\mathbf{w}_{t}^{\top} \mathbf{x}_{t}\right) \mathbf{x}_{t} \\ \;\;\;\;\;\;\;\;\;\;\; =\mathbf{w}_{t}+\alpha\left(R_{t+1} \mathbf{x}_{t}-\mathbf{x}_{t}\left(\mathbf{x}_{t}-\gamma \mathbf{x}_{t+1}\right)^{\top} \mathbf{w}_{t}\right) wt+1≐wt+α(Rt+1+γwt⊤xt+1−wt⊤xt)xt=wt+α(Rt+1xt−xt(xt−γxt+1)⊤wt)
如果上式收敛了,那么就说明前后两次的权重参数应该就不会发生改变了,因此下一次权重参数的期望就可以表示为: E [ w t + 1 ∣ w t ] = w t + α ( b − A w t ) \mathbb{E}\left[\mathbf{w}_{t+1} | \mathbf{w}_{t}\right]=\mathbf{w}_{t}+\alpha\left(\mathbf{b}-\mathbf{A} \mathbf{w}_{t}\right) E[wt+1∣wt]=wt+α(b−Awt), 其中:
b ≐ E [ R t + 1 x t ] ∈ R d 和 A ≐ E [ x t ( x t − γ x t + 1 ) ⊤ ] ∈ R d × R d \mathbf{b} \doteq \mathbb{E}\left[R_{t+1} \mathbf{x}_{t}\right] \in \mathbb{R}^{d} \quad \text { 和 } \quad \mathbf{A} \doteq \mathbb{E}\left[\mathbf{x}_{t}\left(\mathbf{x}_{t}-\gamma \mathbf{x}_{t+1}\right)^{\top}\right] \in \mathbb{R}^{d} \times \mathbb{R}^{d} b≐E[Rt+1xt]∈Rd 和 A≐E[xt(xt−γxt+1)⊤]∈Rd×Rd
如果收敛的话那么 E [ w t + 1 ∣ w t ] = w t \mathbb{E}\left[\mathbf{w}_{t+1} | \mathbf{w}_{t}\right]=\mathbf{w}_{t} E[wt+1∣wt]=wt,假设收敛的时候参数值是 w T D w_{TD} wTD,所以
b − A w T D = 0 ⇒ b = A w T D ⇒ w T D ≐ A − 1 b \mathbf{b}-\mathbf{A} \mathbf{w}_{\mathrm{TD}} =\mathbf{0} \\ \Rightarrow \mathbf{b}=\mathbf{A} \mathbf{w}_{\mathrm{TD}} \\ \Rightarrow \mathbf{w}_{\mathrm{TD}} \doteq \mathbf{A}^{-1} \mathbf{b} b−AwTD=0⇒b=AwTD⇒wTD≐A−1b
收敛的点叫做TD不动点(fixed point)。
线性TD(0)的收敛性证明如下:
来源:https://zhuanlan.zhihu.com/c_1060499676423471104
在TD fixed point还可以得到其 V E ‾ ( w T D ) \overline{VE}(w_{TD}) VE(wTD)与梯度下降MC方法 m i n w V E ‾ ( w T D ) min_w\overline{VE}(w_{TD}) minwVE(wTD)的不等式关系:
V E ‾ ( w T D ) ≤ 1 1 − γ min w V E ‾ ( w ) \overline{\mathrm{VE}}\left(\mathbf{w}_{\mathrm{TD}}\right) \leq \frac{1}{1-\gamma} \min _{\mathbf{w}} \overline{\mathrm{VE}}(\mathbf{w}) VE(wTD)≤1−γ1wminVE(w)
但是因为 γ \gamma γ比较接近1,所以上界很大,但是TD方法的方差很小。这个收敛界限的结论也适用于其他on-policy bootstrap的方法,比如线性的半梯度DP方法,one-step半梯度动作值方法,半梯度Sarsa(0)等等。这些收敛性结论的一个重要前提是状态的更新必须是on-policy 。
n-step半梯度TD算法
算法伪代码如下:
就是把表格型的值函数换成了线性近似器,值函数的更新变为了对参数w的更新。
两个关键步骤:
线性方法有很多优点,比如可以进行高效的计算,并且可以收敛到全局最优点。但是其最终的效果还依赖于如何根据状态构造特征。
大多数情况下状态的表示都是一个具象的数字,比如机械臂控制中的关节角度、租车问题中每个场所车辆的数目等等。这些问题之中,我们所说的函数近似问题和通常所说的插值或者回归问题都很类似。而多项式就是其中的一种特征表示方式。
比如某个RL问题的状态是二维的,每个维度都是数值类型的,那么我们就可以直接用二维数值来表示状态s的特征。但是这个特征是无法表征这两个维度(两个数值)之间的交互关系,除此之外,如果这两个值都是0的话,那么特征就是0,这不一定满足我们的期望。为了解决上述问题,我们可以引入常数项和耦合项,比如在之前二维数组的基础上新增一个常数1,以及一个包含上述两个维度的关系表达式,比如s1+s2。新设计的特征可以是更高维度的,比如 x ( s ) = ( 1 , s 1 , s 2 , s 1 s 2 , s 1 2 , s 2 2 , s 1 s 2 2 , s 1 2 s 2 , s 1 2 s 2 2 ) x(s)=(1,s_1,s_2,s_1s_2,s_1^2,s_2^2,s_1s_2^2,s_1^2s_2,s_1^2s_2^2) x(s)=(1,s1,s2,s1s2,s12,s22,s1s22,s12s2,s12s22)。利用这样的特征就可以表示任何的二次函数。但是值函数近似器相对于权重系数来说是线性的。推广到多项式特征构造的一般形式 。
假设状态s是k维数值向量 s 1 , s 2 , s 3 , . . . , s k s_1,s_2,s_3,...,s_k s1,s2,s3,...,sk,那么一个n阶的多项式基特征就可以表示为:
x i ( s ) = Π j = 1 k s j c i , j x_{i}(s)=\Pi_{j=1}^{k} s_{j}^{c_{i, j}} xi(s)=Πj=1ksjci,j
其中 c i , j c_{i, j} ci,j是集合 0 , 1 , 2... n {0,1,2...n} 0,1,2...n中的一个整数。要注意,这里的 x i x_i xi是特征向量中的一个维度,如果是n阶多项式,那么理论上来说这个特征向量就应该是 ( n + 1 ) k (n+1)^k (n+1)k维的。 上面的二维二阶多项式就是(2+1)的平方;其次多项式是几阶取决于每个特征中状态分量的最高阶是多少,并不是特征的幂次。比如二阶多项式中的特征 s 1 2 s 2 2 s_1^2s_2^2 s12s22的幂次是4,但实际上是二阶多项式的基。
尽管高阶多项式基可以获得更复杂的函数,从而可以得到更加精确的近似效果。但是特征的维度是随着状态的维度指数次增长的。所以一般情况下我们选择部分特征作为函数近似。
傅里叶级数:对于任意一个周期函数来说,可以将其分解为n个不同频率的正弦波和余弦波信号的叠加。 下图展示了傅里叶分解的动态过程:
对于周期为 τ \tau τ的函数,那么傅里叶级数的频率就是 1 / τ 1/\tau 1/τ的整数倍。但是我们的值函数多数情况下不是一个周期函数,但是是有界的(假设区间长度为 τ \tau τ),那么我们就可以通过复制的方式将其变为一个周期函数。每个周期的长度都等于这个区间长度 τ \tau τ。
根据上面的逻辑,如果 τ = 2 \tau=2 τ=2,就可以近似区间[0,1]上的值函数,此时对应的一个一维n-阶傅里叶余弦基包含n+1个特征:
x i ( s ) = cos ( i π s ) , s ∈ [ 0 , 1 ] x_{i}(s)=\cos (i \pi s), \quad s \in[0,1] xi(s)=cos(iπs),s∈[0,1]
其中 i = 0 , … , n i=0, \dots, n i=0,…,n.第一个特征i=0,是一个常数,i=1,2,3,4时对应的特征如下图所示:
如果将其推广到n维状态空间的话,就得到了一般的傅里叶基的定义。
基于傅里叶基的特征构造 :假设我们的状态s是k维的数值向量, s = ( s 1 , s 2 , … , s k ) ⊤ \mathbf{s}=(s_{1},s_{2},\ldots,s_{k})^{\top} s=(s1,s2,…,sk)⊤,其中 s i ∈ [ 0 , 1 ] s_{i}\in[0,1] si∈[0,1].那么n阶傅里叶余弦基的特征 x i x_i xi就可以表示为:
x i ( s ) = cos ( π s ⊤ c i ) x_{i}(s)=\cos (\pi \mathbf{s}^{\top} \mathbf{c}^{i}) xi(s)=cos(πs⊤ci)
其中 c i = ( c 1 i , … , c k i ) ⊤ \mathbf{c}^{i}=(c_{1}^{i}, \ldots, c_{k}^{i})^{\top} ci=(c1i,…,cki)⊤,每个分量 c i j c_{i}^{j} cij都可能取到0到n中的任意一个整数。所以同多项式基一样,也有 ( n + 1 ) k (n+1)^k (n+1)k个特征。
二维傅里叶基实例
对于k=2, s = ( s 1 , s 2 ) ⊤ s=(s_1,s_2)^\top s=(s1,s2)⊤.傅里叶阶数是2的话,那么向量 c = ( c 1 , c 2 ) ⊤ c=(c_1,c_2)^\top c=(c1,c2)⊤就有9种取值可能, c 1 c_1 c1中的任意一个维度的c为0就说明这个维度的值不会发生改变。比如 c = ( 0 , c 2 ) ⊤ c=(0,c_2)^\top c=(0,c2)⊤表示横轴不变, c = ( c 1 , 0 ) ⊤ c=(c_1,0)^\top c=(c1,0)⊤表示纵轴不变。都不为0的话表示两个轴都会发生变化。
(疑问:这里c的值为什么可以取到5呢?c的值不应该是在[0,2]的范围内吗? )
使用傅里叶特征时,学习算法最好针对不同的特征选择不同的更新步长。按照一定的规则 α i = α / ( c 1 i ) 2 + ⋯ + ( c k i ) 2 \alpha_i = \alpha / \sqrt{(c_{1}^{i})^{2}+\cdots+(c_{k}^{i})^{2}} αi=α/(c1i)2+⋯+(cki)2,当所有 c j i = 0 c_j^i=0 cji=0,在这种情况下 α i = α \alpha_{i}=\alpha αi=α. 同时,在选择基的时候,要根据值函数某个方向的泛化特性来适当的选择c的值。
结合傅里叶余弦特征的Sarsa可以产生比多项式基和径向基函数更好的性能表现,但是傅里叶特征对于处理非连续问题有一定困难。
n阶傅里叶特征的数量是随着状态维度的增长指数增长的,如果状态维度k比较小的话,那么就可以使用所有的傅里叶特征。如果状态维度很大的话,就必须选择这些特征中的一个子集,可以利用某些先验知识或者利用自动化的方法来选择。
傅里叶特征有一定的优点 ,可以通过合理的选择 c i c^i ci引入可能状态维度之间的关联,或者限制其向量的值从而过滤掉高频噪音。同时傅里叶表征的是全局性质,无法表征局部性质。
如下图为傅里叶基和多项式基拟合随机游走问题所得到的value error:
原理: 对于连续的状态空间而言,我们可以把状态空间用一些相互重叠的区域来表示。具体怎么做呢?假设我们用○来表示一块块的区域,如果某个状态s落在某个区域中,那么对应的值就是1,否则就是0.这样就把一个状态转换为了只有0和1的向量,称作是二值特征binary feature。这个二值向量可以表示这个状态在哪个区域内,从而粗略的估计出当前状态的位置所在。用相互重叠的区域编码状态的方式就叫做coarse coding 。
如上图所示,对于状态 s , s ′ s,s' s,s′。假设我们的区域有10块,编号从0到9,状态s处于1,2,3的交界,状态s‘处于3和4的交界,所以对于状态s的特征向量来说就是 x ( s ) = ( 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ) T x(s)=(0,1,1,1,0,0,0,0,0,0)^T x(s)=(0,1,1,1,0,0,0,0,0,0)T,对于状态s’的特征向量来说就是 x ( s ) = ( 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 ) T x(s)=(0,0,0,1,1,0,0,0,0,0)^T x(s)=(0,0,0,1,1,0,0,0,0,0)T.这样一来状态就是一个二值特征向量了。并且状态之间可以泛化。比如上图中的两个状态都在3号区域内,他们的特征向量对应的3号位置的值都是1,说明它们之间有一定的相似之处。基于这种相似性就可以实现某些特性的泛化功能。
尽管这种方法可以对状态进行二值编码,但是其位置也就是某个状态的特征向量的表示会受到形状的影响。因此coarse coding的泛化也受到感受野(区域,也就是某个状态的影响范围,是某个状态所在的圆的并集)的大小、密度以及形状的影响。
左图的感受野比较小,因此其泛化能力比较差,中间的感受野比较大,泛化能力比较大;最右边的感受野不是对称的,在纵轴方向上的泛化能力比较好一点。
感受野越大泛化范围越大,但同时也会影响值函数近似的精度。这就会带来一个比较矛盾的问题,为了得到期望的近似特性,该如何选择感受野的大小和形状?好在初期近似性能受到这些因素的影响,但是最终的近似效果更多的取决于特征的数量多少。
tile coding是coarse coding中的一种,是coarse coding在多维连续空间上的扩展。tile:瓦片的意思,tile-coding的原理类似于瓦片的工作机制,就是层层累叠在一起。所有tile-coding也是很多层叠加在一起,然后共同决定某个点是否激活。
tile-coding中,特征被分组为多个分割,每个分割都完整的覆盖整个状态空间。这种分割叫做tiling。 每个tiling中可以有很多个tile。这些tile的作用和之前的coarse coding中的○的作用是一样的,只不过现在是矩形并且没有交叠,通常情况下把每个tiling中的tile都保持均匀分配即可。如上图所示,由于每一层tiling中的tile是不重叠的,那么为了达到coarse-coding的效果我们就需要多层tiling,这也是为什么之前说,tile-coding是coarse-coding的一种特殊形式。如果只构建一层的话,由于tiling层中的tile没有交叠,所以状态最终只会落在一个唯一的tile上,此时就不是一个coarse-coding问题了,而是一个聚类问题。
如果一个tiling我们划分为4x4的网格的话,构造4层,那么特征数量就是4x4x4=64个。从上图可以看出多个tilings的优势。
为什么说堆编码的计算更加高效呢? 假设有n个tiling,对于二值特征向量来说只有n个值为1,其他都是0,因为每个tiling都是全覆盖整个状态空间的,所以每个tiling中有且仅有一个值为1。所以计算线性近似值函数时 v ^ ( s , w ) ≐ w T x ( s ) ≐ ∑ i = 1 d w i x i ( s ) \hat{v}(s,w) \doteq w^Tx(s) \doteq \sum_{i=1}^{d}w_ix_i(s) v^(s,w)≐wTx(s)≐∑i=1dwixi(s).实际上只需要计算n个tile位置的权重向量和即可,比执行d次(d>>n)乘积加和运算高效许多。d表示的是特征总数,比如之前的4层4x4的tilings的特征总数就是64.
tile-coding还有一个优点 就是,present的特征数量是恒定的(present的概念就是如果某个状态在某个区域内,那么其值就是1,说白了就是区域存在状态就叫做一个present),每个tiling一个,所以我们的更新步长就可以设置为固定值,比如 α = 1 / n \alpha = 1/n α=1/n,其中n表示的是tilings的数量,这样就可以一步到位的学习到值函数,也就是无论 v ^ ( s , w t ) \hat{v}(s,w_t) v^(s,wt)是多少,那么一定会有 v ^ ( s , w t + 1 ) = v \hat{v}(s,w_{t+1})=v v^(s,wt+1)=v,这个性质叫做one-trail learning。如果要考虑到泛化性,我们希望能够逐渐逼近值函数,所以可以把步长设置为 α = 1 / 10 n \alpha = 1/10n α=1/10n.
tile-coding的泛化
tile-coding的泛化和不同tiling之间的偏移有关。
为了降低内存消耗使用hashing方法。也就是,首先我们把状态空间分成比较碎的块,然后使用hash算法把碎块分配到粒度更大的几个集合中,每个集合包括整个状态空间中不相邻的一些碎块,如下图所示,就表示了一个hashing集合。注意这也是能覆盖所有状态空间的。hashing方法缓解了维度诅咒的问题,同时还不需要针对具体任务特殊处理。开源实现中往往包含了hashing方法。
径向基函数RBFs是coarse coding向连续值特征的扩展,也就是说特征值不再是0和1,而是[0,1]的区间内的数。一个典型的RBF特征就是高斯函数。
x i ( s ) ≐ exp ( − ∥ s − c i ∥ 2 2 σ i 2 ) x_{i}(s) \doteq \exp \left(-\frac{\|s-c_{i}\|^{2}}{2 \sigma_{i}^{2}}\right) xi(s)≐exp(−2σi2∥s−ci∥2)
c i c_i ci是在该维度上特征的中心或均值, δ i \delta_i δi是特征的宽度或者标准差。
∥ s − c i ∥ 2 \|s-c_{i}\|^{2} ∥s−ci∥2衡量的是状态之间的相似度,用距离标准进行衡量。比如欧氏距离、马氏距离、切比雪夫距离等等。下面是一个欧氏距离的例子:
我们可以把上图中的一个高斯函数曲线比作是coarse coding中的一个○,只不过这里状态值不再是单纯的0和1,而是等于高斯函数的自变量对应的函数值。
RBF相对于coarse coding来说可以产生十分光滑和可微的近似函数。但在实际中并没有太大作用,反而增加了RBF的计算复杂度,导致在高维度上表现不好。
大多数随机梯度方法都需要设计合理的步长参数 α \alpha α.根据之前提到的随机近似理论,步长参数必须满足两个收敛条件(这里就不再写公式,在第二章)。但这个理论仅仅在理论上说的通,在实际应用中,一般不可能同时满足随机近似理论的两个条件,并且同时满足这两个条件的步长参数,会导致算法收敛很慢。比较简单的方法是直接让 α t = 1 / t \alpha_t = 1/t αt=1/t,但是这种方法仅适用于MC,并不适用于TD、nonstationary问题以及使用函数近似的方法。对于线性方法而言,可以使用迭代最小二乘法来设置最优矩阵步长参数。但是这种方法需要 O ( d 2 ) O(d^2) O(d2)的步长参数。
按照一般的更新规则来看,如果我们把步长参数设置为1的话,那么就可以一步到位的消除误差,但是为了保证其泛化性,一般的我们都是希望其能够渐进的逼近我们的目标。比如 α = 1 / τ \alpha =1/\tau α=1/τ的话,那么就意味着需要 τ \tau τ次才能够使其更新到期望目标。因此我们可以根据 τ \tau τ来设置步长参数,也就是说我们希望它多少步之后就能够更新到期望目标。
但是对于函数近似的情况来讲,是没有明确的状态更新经验次数的说法,这是因为函数近似的方法中,各个状态之间是耦合的,一个状态的更新会影响其他状态,这就很难说明这个状态更新了多少次。同时bootstrap也会造成一定的影响。但是对于线性函数近似依然可以有上述类似的结论,比如假设对于相似的特征向量我们希望通过 τ \tau τ次更新来收敛到期望目标值。那么选择步长参数的表达式就是:
α ≐ ( τ E [ x ⊤ x ] ) − 1 \alpha \doteq\left(\tau \mathbb{E}\left[\mathbf{x}^{\top} \mathbf{x}\right]\right)^{-1} α≐(τE[x⊤x])−1
x是根据特征向量分布采样的一个特征向量样本。当特征向量的模长比较稳定的时候,(也就是不同特征向量的模长比较相似,这样就会使得 x ⊤ x \mathbf{x}^{\top} \mathbf{x} x⊤x相对来说是固定的或者一个常数,)其表现效果最好。
上一节介绍了很多特征构造的方法,以及之前提到的值函数近似方法。通过合适的特征表征使得即使采用线性model也可以得到很不错的效果。但是毕竟非线性函数表征能力更强并且更贴近实际。
前向神经网络
前向神经网络是最基础的NN,如果神经网络的拓扑结构中有环,那么就是循环神经网络RNN。前向神经网络的拓扑图如下:
前向神经网络由输入层、隐含层、输出层组成。每层都由基本单元–神经元组成。它是以上一层信号的加权和作为输入,施加一定形式的非线性变换(激活函数)后作为输出。权重就是我们要学习的参数。
理论证明,没有隐含层的NN只能表示一小部分函数,但是仅有一个隐含层的多个非线性神经元的NN可以近似任何连续函数。所以其具有很强的表征能力。
权重学习
对于NN来说,我们要知道权重是如何变化的,以及如何影响网络的输出,所以要知道目标函数对于网络权重参数的偏导数。这个就是SGD的方法。在NN中使用反向传播算法更新权重,在前向过程中计算每个神经元的输出,反向过程就是计算偏导。借助BP算法,浅层NN比较好用,对于深层NN就要考虑过拟合等一些问题。过拟合通常就是在训练的过程中效果很好,但是实际测试的时候效果很差。常见的解决过拟合的方法有: 加入正则化项;dropout减少参数;批标准化;等等。
具体的关于NN的相关理论以及BP的计算推导这里就不写了。现在NN发展的如火如荼,但始终还是一个黑盒子,这些东西我认为在使用的时候看一看怎么使用就可以了,把这个当做一个工具即可。
之前第4节中讲了基于线性近似的TD(0)算法,证明了在线性近似的情况下,线性model的权重系数渐进收敛到TD fixed point。 w T D = A − 1 b \mathbf{w}_{\mathrm{TD}}=\mathbf{A}^{-1} \mathbf{b} wTD=A−1b,其中$ \mathbf{A} \doteq \mathbb{E}\left[\mathbf{x}{t}\left(\mathbf{x}{t}-\gamma \mathbf{x}{t+1}\right)^{\top}\right] \quad \text { and } \quad \mathbf{b} \doteq \mathbb{E}\left[R{t+1} \mathbf{x}_{t}\right]$
要估计权重参数就必须计算A和b这两个值,然后我们看A和b发现,这两个值的估计都依赖于当前时刻的状态和回报。也就是说我们必须每个step都估计一次,如此迭代进行 。那么就有一个问题,如果我们可以直接估算出A和b,然后根据之前的计算公式不就可以直接得到权重参数的值了吗?LSTD就是来做这个事情的。
LSTD利用所有样本估计A和b,其估计表达式为:
A ^ t ≐ ∑ k = 0 t − 1 x k ( x k − γ x k + 1 ) ⊤ + ε I and b ^ t ≐ ∑ k = 0 t − 1 R k + 1 x k \widehat{\mathbf{A}}_{t} \doteq \sum_{k=0}^{t-1} \mathbf{x}_{k}\left(\mathbf{x}_{k}-\gamma \mathbf{x}_{k+1}\right)^{\top}+\varepsilon \mathbf{I} \quad \text { and } \quad \widehat{\mathbf{b}}_{t} \doteq \sum_{k=0}^{t-1} R_{k+1} \mathbf{x}_{k} A t≐k=0∑t−1xk(xk−γxk+1)⊤+εI and b t≐k=0∑t−1Rk+1xk
ϵ \epsilon ϵ是一个很小的正的常数,加上后面这一项主要是为了保证A是可逆的。上式是在t次时间内的估计求和。正常来说, A t ^ \widehat {\mathbf{A}_t} At 和 b t ^ \widehat {\mathbf{b}_t} bt 要除以t之后才能得到估计的A和b,但是这个操作在计算$ \mathbf{w}{t} \doteq \widehat{\mathbf{A}}{t}^{-1} \widehat{\mathbf{b}}_{t}$的时候被抵消掉了。
上述算法对于样本的利用率很高,但同时计算量也很大。对于半梯度TD(0)来说,每一步所需的内存大小是O(d),对于LSTD来说,随着t的增加,上式计算越来越复杂,并且每次都需要从头开始计算,因此可以考虑改为增量实现形式。这样一来每一步的复杂度大小就一样了。但是每次估计 A t A_t At的值还是需要计算矩阵,所以计算复杂度以及内存需求都是 O ( d 2 ) O(d^2) O(d2),最后求解参数 w t w_t wt的时候还需要进行矩阵求逆,此时计算复杂度就变为了 O ( d 3 ) O(d^3) O(d3).索性由于矩阵 A t A_t At是特殊形式,可以写成外积和的形式,所以求逆也可以增量式进行,
A ^ t − 1 = ( A ^ t − 1 + x t − 1 ( x t − 1 − γ x t ) ⊤ ) − 1 = A ^ t − 1 − 1 − A ^ t − 1 − 1 x t − 1 ( x t − 1 − γ x t ) ⊤ A ^ t − 1 − 1 1 + ( x t − 1 − γ x t ) ⊤ A ^ t − 1 − 1 x t − 1 \begin{aligned} \widehat{\mathbf{A}}_{t}^{-1} &=\left(\widehat{\mathbf{A}}_{t-1}+\mathbf{x}_{t-1}\left(\mathbf{x}_{t-1}-\gamma \mathbf{x}_{t}\right)^{\top}\right)^{-1} \\ &=\widehat{\mathbf{A}}_{t-1}^{-1}-\frac{\widehat{\mathbf{A}}_{t-1}^{-1} \mathbf{x}_{t-1}\left(\mathbf{x}_{t-1}-\gamma \mathbf{x}_{t}\right)^{\top} \widehat{\mathbf{A}}_{t-1}^{-1}}{1+\left(\mathbf{x}_{t-1}-\gamma \mathbf{x}_{t}\right)^{\top} \widehat{\mathbf{A}}_{t-1}^{-1} \mathbf{x}_{t-1}} \end{aligned} A t−1=(A t−1+xt−1(xt−1−γxt)⊤)−1=A t−1−1−1+(xt−1−γxt)⊤A t−1−1xt−1A t−1−1xt−1(xt−1−γxt)⊤A t−1−1
此时只涉及矩阵与向量乘积或者向量与向量之间的乘积,所以其复杂度是 O ( d 2 ) O(d^2) O(d2)。其算法伪代码如下:
总的来说LSTD通过牺牲计算复杂度来换取样本利用率。实际情况中该使用半梯度TD(0)还是LSTD需要结合具体任务背景考量。LSTD的一个优点就是不需要步长参数这个超参数,但是需要一个 w p s i l o n wpsilon wpsilon。LSTD不需要步长参数说明其不会遗忘历史数据,会使用历史数据来估计权重,这样对于策略变化的动态问题来说会有问题。
在这之前我们所提到的方法是参数化方法 ,通过算法不断调整参数然后得到值函数。每次更新都是一个训练样本,基于这些数据进行学习,更新完成之后这些训练样本就可以丢弃了。需要函数拟合近似的时候利用最后得到的参数,输入状态,即可输出估计的值。
本节所讲到的基于记忆的函数近似方法是一种非参数化的方法 。它只保留训练样本,并不更新参数,在需要使用model的时候就使用存储起来的数据计算一个估计值,这种方法也叫做lazy learning,因为是在查询的时候进行的更新。这种非参数化的方法,其拟合函数的形式不局限于可参数化的函数,是直接由训练样本所决定的。记忆的样本越多估计得越准确。
目前有很多不同的基于记忆的方法,主要是存储样本的方式以及利用样本查询的方式不同。本节只讨论局部学习的方法(局部学习就是基于一定的准则找到距离待查询状态最近的样本),也就是只使用附近的样本求出查询结果,然后再计算出查询状态query state的估计值,返回后就丢弃这个值。最简单的方法就是最近邻法
最近邻方法nearest neighbor
最近邻方法就是以最近的样本点的值作为查询状态query state的输出。比如我们要查询状态s,在样本集中与其最接近的状态是s1,其对应的值是g,那么我们就把g作为状态s的估计值。另一种方法就是加权均值法,返回的是一个近邻样本的集合,然后以这些样本对应的值的加权和作为查询状态query state的值,权重大小与样本状态和query state的距离大小呈反比。还有一种方法是局部加权回归,LWR。LWR方法需要我们在近邻集合上利用参数近似的方法拟合一个曲面,以拟合曲面在query state的评估值作为它的值。
基于记忆的非参数方法的优点
非参方法不受限于事先声明的函数形式,因为其仅仅与训练样本有关。
基于记忆的局部近似方法适用于RL,RL中的状态空间一般很大,但我们真正感兴趣的只有一小部分,这种局部方法就可以专注于这个局部区域的近似效果。
其次,基于记忆的非参数方法可以局部近似,从而避免全局估计,那么就可以在一定程度上解决维度灾难问题。
基于记忆方法中的经验会立即对当前状态的领域产生作用。
但是基于记忆的非参数方法也存在一定的缺点,当样本数目很大的时候,那么搜索最近样本的复杂度就会很高,目前有一些方法用来解决这些问题,比如并行计算,还有就是使用特别的数据结果存储训练数据集,比如k-d树。
上一节基于记忆的函数近似的最近邻方法中,我们提到了加权平均和局部加权回归的方法。这两者的一个共同点就是需要分配一个权重,该权重一般与状态之间的距离呈反比。具体该权重如何给,就是本节的内容。
核函数kernel function是一个映射k: S × S → R \mathcal{S} \times \mathcal{S} \rightarrow \mathbb{R} S×S→R .将两个状态映射为一个实数。这个实数的大小反映这两个状态之间的相关性 。也就是说核函数k(s,s’)表达的是状态s’泛化到状态s的泛化强度的度量。之前讲到的堆编码也可以当做是一种核函数,这个核函数是均匀分布经过非对称偏移得到的。
核回归就是一种基于记忆的核加权均值法,假设D是样本,g(s’)表示的是D中某个状态s’的目标值。核回归通过以下算式近似目标函数:
v ^ ( s , D ) = ∑ s ′ ∈ D k ( s , s ′ ) g ( s ′ ) \hat{v}(s, \mathcal{D})=\sum_{s^{\prime} \in \mathcal{D}} k\left(s, s^{\prime}\right) g\left(s^{\prime}\right) v^(s,D)=s′∈D∑k(s,s′)g(s′)
核回归可以看作是加权均值法的一种推广;之前的近邻加权均值法可以看作是核回归的特例,因为仅在状态s的邻域才取到非零值。
常用的核函数有RBF高斯径向基函数,之前讲到的RBF用来构造特征,目标函数是RBF加权和的形式。这个权重的更新是通过随机梯度或者半梯度的方法来学习到的。所以之前的方法是参数化的线性函数近似法。这里的RBF是将其当做核函数来使用,目标函数依然是通过上式的近似目标函数计算得到的。基于RBF的核回归则与RBF特征提取有两点不同:1. 核回归是基于记忆的方法;2.核回归是非参数的,没有要学习的参数。
根据理论证明,任何带有特征表示的线性参数回归方法都可以重写成核回归的形式,只需要设定核函数为特征向量 x ( s ) = ( x 1 ( s ) , x 2 ( s ) , … , x d ( s ) ) ⊤ \mathbf{x}(s)=(x_{1}(s), x_{2}(s), \ldots, x_{d}(s))^{\top} x(s)=(x1(s),x2(s),…,xd(s))⊤ 的内积即可:
k ( s , s ′ ) = x ( s ) ⊤ x ( s ′ ) k\left(s, s^{\prime}\right)=\mathbf{x}(s)^{\top} \mathbf{x}\left(s^{\prime}\right) k(s,s′)=x(s)⊤x(s′)
除了构建特征和线性参数拟合器,我们还可以直接构建核函数,从而省略提取特征的过程,直接得到其特征的内积,这在支持向量机(SVM)中用得很多。对于很多特征向量集合,上述这种使用核函数的方法复杂度要比带特征向量的使用线性参数的方法相比低很多,这叫做核技巧,在状态维度很高时效果很好。
目前本章中我们所讲到的算法都是同等的对待每个样本状态。实际情况中我们可能只会关心部分状态。比如在episodic task中,我们对前面的state更感兴趣,因为期望折扣累积回报在这些states上相当于是first-visit的,所以可能更加转却;再比如在动作值函数学习的过程中,那些值比较小的动作可能没有greedy的动作重要。所以我们如果更加侧重我们关注的状态或者重要的状态,那么值函数近似算法的效果可能会有所改善。
为了表示这些重要性,需要引入一些新的概念。
有了上述的度量指标,那么我们之前关于权重参数w的更新公式就可以写作:
w t + n ≐ w t + n − 1 + α M t [ G t : t + n − v ^ ( S t , w t + n − 1 ) ] ∇ v ^ ( S t , w t + n − 1 ) , 0 ≤ t < T \mathbf{w}_{t+n} \doteq \mathbf{w}_{t+n-1}+\alpha M_{t}\left[G_{t : t+n}-\hat{v}\left(S_{t}, \mathbf{w}_{t+n-1}\right)\right] \nabla \hat{v}\left(S_{t}, \mathbf{w}_{t+n-1}\right), \quad 0 \leq t
M t M_t Mt通过 I t I_t It进行迭代式的更新,更新公式为:
M t = I t + γ n M t − n , 0 ≤ t < T M_{t}=I_{t}+\gamma^{n} M_{t-n}, \quad 0 \leq t
该总结来自:https://blog.csdn.net/u013695457/article/details/90721961#62_158
如果希望RL方法能应用到AI或者工程应用中,则必须具有泛化能力。为了达成这个目的,需要借助监督学习中已有的技巧,并把每个update当作一个训练样例。
最适用的监督学习方法是那些使用参数化函数拟合器的,即策略通过权重向量w参数化。虽然权重向量拥有很多参数,但是通常状态空间是比这些参数大得多的,因此我们必须要定义目标,以计算梯度。常采用value error(VE)作为参数向量w与on-policy分布μ下的误差。
为了找到好的参数向量,最常用的方法是随机梯度下降SGD及其变体逐渐更新参数向量w。本章我们聚焦于确定的on-policy策略,讨论的是prediction/evaluation问题。比较自然的方法是n-step 半梯度 TD,包括MC方法和半梯度TD(0)。半梯度TD方法不是真正的梯度方法,因为求偏导的时候,由于bootstrapping,更新目标也是与权重向量有关的。但是实际效果还是不错的。
为了效果更好,常将状态转化为一些特征,并把这些特征乘权重相加,构成基于特征的线性拟合器。如何选择特征则要结合具体问题的领域先验知识,可以选择多项式、傅里叶、粗糙编码、瓦片编码、径向基函数等特征。LSTD是数据利用最高效的TD预测方法,但是需要和权重数量平方关系的计算复杂度;非线性方法包括ANN拟合器,近年来由于深度学习的发展展现出了很强的潜力。
线性半梯度n-step TD方法在标准条件下、对于任意的n是收敛的,且能保证value error(VE)有界。当n越大,界区间越小,但是学习越慢。因此一定程度的bootstrapping是必须的。