系统学习机器学习之增强学习(五)--马尔可夫决策过程策略TD求解(SARSA)
转自:https://www.cnblogs.com/pinard/p/9529828.html1.时间差分法(temporal difference)蒙特卡洛方法,需要所有的采样序列都是经历完整的状态序列。如果我们没有完整的状态序列,那么就无法使用蒙特卡罗法求解了。本文我们就来讨论可以不使用完整状态序列求解强化学习问题的方法:时序差分(Temporal-Difference, TD)。...
转自:https://www.cnblogs.com/pinard/p/9529828.html
1.时间差分法(temporal difference)
蒙特卡洛方法,需要所有的采样序列都是经历完整的状态序列。如果我们没有完整的状态序列,那么就无法使用蒙特卡罗法求解了。本文我们就来讨论可以不使用完整状态序列求解强化学习问题的方法:时序差分(Temporal-Difference, TD)。
1. 时序差分TD简介
时序差分法和蒙特卡罗法类似,都是不基于模型的强化学习问题求解方法。所以在上一篇定义的不基于模型的强化学习控制问题和预测问题的定义,在这里仍然适用。
预测问题:即给定强化学习的5个要素:状态集S, 动作集A, 即时奖励R,衰减因子γ, 给定策略π, 求解该策略的状态价值函数v(π)
控制问题:也就是求解最优的价值函数和策略。给定强化学习的5个要素:状态集S, 动作集A, 即时奖励R,衰减因子γ, 探索率ϵ, 求解最优的动作价值函数q∗和最优策略π∗
回顾蒙特卡罗法中计算状态收获的方法是:
而对于时序差分法来说,我们没有完整的状态序列,只有部分的状态序列,那么如何可以近似求出某个状态的收获呢?回顾贝尔曼方程:
这启发我们可以用Rt+1+γv(St+1)来近似的代替收获Gt, 一般我们把Rt+1+γV(St+1)称为TD目标值。Rt+1+γV(St+1)−V(St)Rt+1+γV(St+1)−V(St)称为TD误差,将用TD目标值近似代替收获G(t)的过程称为引导(bootstrapping)。这样我们只需要两个连续的状态与对应的奖励,就可以尝试求解强化学习问题了。
现在我们有了自己的近似收获Gt的表达式,那么就可以去求解时序差分的预测问题和控制问题了。
2. 时序差分TD的预测问题求解
时序差分的预测问题求解和蒙特卡罗法类似,但是主要有两个不同点。一是收获Gt的表达式不同,时序差分G(t)的表达式为:
二是迭代的式子系数稍有不同,回顾蒙特卡罗法的迭代式子是:
由于在时序差分我们没有完整的序列,也就没有对应的次数N(St),一般就用一个[0,1]的系数α代替。这样时序差分的价值函数迭代式子是:
这里我们用一个简单的例子来看看蒙特卡罗法和时序差分法求解预测问题的不同。
假设我们的强化学习问题有A,B两个状态,模型未知,不涉及策略和行为。只涉及状态转化和即时奖励。一共有8个完整的状态序列如下:
① A,0,B,0 ②B,1 ③B,1 ④ B,1 ⑤ B,1 ⑥B,1 ⑦B,1 ⑧B,0
只有第一个状态序列是有状态转移的,其余7个只有一个状态。设置衰减因子γ=1。
首先我们按蒙特卡罗法来求解预测问题。由于只有第一个序列中包含状态A,因此A的价值仅能通过第一个序列来计算,也就等同于计算该序列中状态A的收获:
V(A)=G(A)=RA+γRB=0
对于B,则需要对其在8个序列中的收获值来平均,其结果是6/8。
再来看看时序差分法求解的过程。其收获是在计算状态序列中某状态价值时是应用其后续状态的预估价值来计算的,对于B来说,它总是终止状态,没有后续状态,因此它的价值直接用其在8个序列中的收获值来平均,其结果是6/8。
对于A,只在第一个序列出现,它的价值为:
V(A)=RA+γV(B)=6/8
从上面的例子我们也可以看到蒙特卡罗法和时序差分法求解预测问题的区别。
一是时序差分法在知道结果之前就可以学习,也可以在没有结果时学习,还可以在持续进行的环境中学习,而蒙特卡罗法则要等到最后结果才能学习,时序差分法可以更快速灵活的更新状态的价值估计,这在某些情况下有着非常重要的实际意义。
二是时序差分法在更新状态价值时使用的是TD 目标值,即基于即时奖励和下一状态的预估价值来替代当前状态在状态序列结束时可能得到的收获,是当前状态价值的有偏估计,而蒙特卡罗法则使用实际的收获来更新状态价值,是某一策略下状态价值的无偏估计,这一点蒙特卡罗法占优。
三是虽然时序差分法得到的价值是有偏估计,但是其方差却比蒙特卡罗法得到的方差要低,且对初始值敏感,通常比蒙特卡罗法更加高效。
从上面的描述可以看出时序差分法的优势比较大,因此现在主流的强化学习求解方法都是基于时序差分的。后面的文章也会主要基于时序差分法来扩展讨论。
3. n步时序差分
在第二节的时序差分法中,我们使用了用Rt+1+γv(St+1)来近似的代替收获Gt。即向前一步来近似我们的收获Gt,那么能不能向前两步呢?当然可以,这时我们的收获Gt的近似表达式为:
从两步,到三步,再到n步,我们可以归纳出n步时序差分收获G(n)t表达式为:
当n越来越大,趋于无穷,或者说趋于使用完整的状态序列时,n步时序差分就等价于蒙特卡罗法了。
对于n步时序差分来说,和普通的时序差分的区别就在于收获的计算方式的差异。那么既然有这个n步的说法,那么n到底是多少步好呢?如何衡量n的好坏呢?我们在下一节讨论。
4. TD(λ)
n步时序差分选择多少步数作为一个较优的计算参数是需要尝试的超参数调优问题。为了能在不增加计算复杂度的情况下综合考虑所有步数的预测,我们引入了一个新[0,1]的参数λ,定义λ−收获是n从1到∞所有步的收获乘以权重的和。每一步的权重是(1−λ)λ^(n−1),这样λ−收获的计算公式表示为:
进而我们可以得到TD(λ)的价值函数的迭代公式:
每一步收获的权重定义为(1−λ)λ^(n−1)的原因是什么呢?其图像如下图所示,可以看到随着n的增大,其第n步收获的权重呈几何级数的衰减。当在T时刻到达终止状态时,未分配的权重全部给予终止状态的实际收获值。这样可以使一个完整的状态序列中所有的n步收获的权重加起来为1,离当前状态越远的收获其权重越小。
从前向来看TD(λ), 一个状态的价值V(St)由Gt得到,而Gt又间接由所有后续状态价值计算得到,因此可以认为更新一个状态的价值需要知道所有后续状态的价值。也就是说,必须要经历完整的状态序列获得包括终止状态的每一个状态的即时奖励才能更新当前状态的价值。这和蒙特卡罗法的要求一样,因此TD(λ)有着和蒙特卡罗法一样的劣势。当λ=0时,就是第二节讲到的普通的时序差分法,当λ=1时,就是蒙特卡罗法。
从反向来看TD(λ),它可以分析我们状态对后续状态的影响。比如老鼠在依次连续接受了3 次响铃和1 次亮灯信号后遭到了电击,那么在分析遭电击的原因时,到底是响铃的因素较重要还是亮灯的因素更重要呢?如果把老鼠遭到电击的原因认为是之前接受了较多次数的响铃,则称这种归因为频率启发(frequency heuristic) 式;而把电击归因于最近少数几次状态的影响,则称为就近启发(recency heuristic) 式。
如果给每一个状态引入一个数值:效用(eligibility, E) 来表示该状态对后续状态的影响,就可以同时利用到上述两个启发。而所有状态的效用值总称为效用迹(eligibility traces,ES)。定义为:
E0(s)=0
此时我们TD(λ)的价值函数更新式子可以表示为:
也许有人会问,这前向的式子和反向的式子看起来不同啊,是不是不同的逻辑呢?其实两者是等价的。现在我们从前向推导一下反向的更新式子。
可以看出前向TD误差和反向的TD误差实际上一致的。
5. 时序差分的控制问题求解
现在我们回到普通的时序差分,来看看它控制问题的求解方法。回想上一篇蒙特卡罗法在线控制的方法,我们使用的是ϵ−贪婪法来做价值迭代。对于时序差分,我们也可以用ϵ−贪婪法来价值迭代,和蒙特卡罗法在线控制的区别主要只是在于收获的计算方式不同。时序差分的在线控制(on-policy)算法最常见的是SARSA算法。
而除了在线控制,我们还可以做离线控制(off-policy),离线控制和在线控制的区别主要在于在线控制一般只有一个策略(最常见的是ϵ−贪婪法)。而离线控制一般有两个策略,其中一个策略(最常见的是ϵ−贪婪法)用于选择新的动作,另一个策略(最常见的是贪婪法)用于更新价值函数。时序差分的离线控制算法最常见的是Q-Learning算法,我们在下篇单独讲解。
5.1. SARSA算法的引入
SARSA算法是一种使用时序差分求解强化学习控制问题的方法,回顾下此时我们的控制问题可以表示为:给定强化学习的5个要素:状态集S, 动作集A, 即时奖励R,衰减因子γ, 探索率ϵ, 求解最优的动作价值函数q∗和最优策略π∗。
这一类强化学习的问题求解不需要环境的状态转化模型,是不基于模型的强化学习问题求解方法。对于它的控制问题求解,和蒙特卡罗法类似,都是价值迭代,即通过价值函数的更新,来更新当前的策略,再通过新的策略,来产生新的状态和即时奖励,进而更新价值函数。一直进行下去,直到价值函数和策略都收敛。
我们的SARSA算法,属于在线控制这一类,即一直使用一个策略来更新价值函数和选择新的动作,而这个策略是ϵ−贪婪法,在系统学习机器学习之增强学习(四)--马尔可夫决策过程策略MC求解中,我们对于ϵ−贪婪法有详细讲解,即通过设置一个较小的ϵ值,使用1−ϵ的概率贪婪地选择目前认为是最大行为价值的行为,而用ϵ的概率随机的从所有m个可选行为中选择行为。用公式可以表示为:
2. SARSA算法概述
作为SARSA算法的名字本身来说,它实际上是由S,A,R,S,A几个字母组成的。而S,A,R分别代表状态(State),动作(Action),奖励(Reward),这也是我们前面一直在使用的符号。这个流程体现在下图:
在迭代的时候,我们首先基于ϵ−贪婪法在当前状态S选择一个动作A,这样系统会转到一个新的状态S′, 同时给我们一个即时奖励R, 在新的状态S′,我们会基于ϵ−贪婪法在状态S‘′选择一个动作A′,但是注意这时候我们并不执行这个动作A′,只是用来更新的我们的价值函数,价值函数的更新公式是:
其中,γ是衰减因子,α是迭代步长。这里和蒙特卡罗法求解在线控制问题的迭代公式的区别主要是,收获Gt的表达式不同,对于时序差分,收获Gt的表达式是R+γQ(S′,A′)。
除了收获Gt的表达式不同,SARSA算法和蒙特卡罗在线控制算法基本类似。
3. SARSA算法流程
下面我们总结下SARSA算法的流程。
算法输入:迭代轮数T,状态集S, 动作集A, 步长α,衰减因子γ, 探索率ϵ,
输出:所有的状态和动作对应的价值Q
1. 随机初始化所有的状态和动作对应的价值Q. 对于终止状态其Q值初始化为0.
2. for i from 1 to T,进行迭代。
a) 初始化S为当前状态序列的第一个状态。设置A为ϵ−贪婪法在当前状态S选择的动作。
b) 在状态S执行当前动作A,得到新状态S′和奖励R
c) 用ϵ−贪婪法在状态S′选择新的动作A′
d) 更新价值函数Q(S,A):
e) S=S′,A=A′
f) 如果S′是终止状态,当前轮迭代完毕,否则转到步骤b)
这里有一个要注意的是,步长α一般需要随着迭代的进行逐渐变小,这样才能保证动作价值函数Q可以收敛。当Q收敛时,我们的策略ϵ−贪婪法也就收敛了。
4. SARSA算法实例:Windy GridWorld
下面我们用一个著名的实例Windy GridWorld来研究SARSA算法。
如下图一个10×7的长方形格子世界,标记有一个起始位置 S 和一个终止目标位置 G,格子下方的数字表示对应的列中一定强度的风。当个体进入该列的某个格子时,会按图中箭头所示的方向自动移动数字表示的格数,借此来模拟世界中风的作用。同样格子世界是有边界的,个体任意时刻只能处在世界内部的一个格子中。个体并不清楚这个世界的构造以及有风,也就是说它不知道格子是长方形的,也不知道边界在哪里,也不知道自己在里面移动移步后下一个格子与之前格子的相对位置关系,当然它也不清楚起始位置、终止目标的具体位置。但是个体会记住曾经经过的格子,下次在进入这个格子时,它能准确的辨认出这个格子曾经什么时候来过。格子可以执行的行为是朝上、下、左、右移动一步,每移动一步只要不是进入目标位置都给予一个 -1 的惩罚,直至进入目标位置后获得奖励 0 同时永久停留在该位置。现在要求解的问题是个体应该遵循怎样的策略才能尽快的从起始位置到达目标位置。
逻辑并不复杂,完整的代码在我的github。这里我主要看一下关键部分的代码。
算法中第2步步骤a,初始化SS,使用ϵ−ϵ−贪婪法在当前状态SS选择的动作的过程:
# initialize state
state = START
# choose an action based on epsilon-greedy algorithm
if np.random.binomial(1, EPSILON) == 1:
action = np.random.choice(ACTIONS)
else:
values_ = q_value[state[0], state[1], :]
action = np.random.choice([action_ for action_, value_ in enumerate(values_) if value_ == np.max(values_)])
算法中第2步步骤b,在状态SS执行当前动作AA,得到新状态S′S′的过程,由于奖励不是终止就是-1,不需要单独计算:
def step(state, action):
i, j = state
if action == ACTION_UP:
return [max(i - 1 - WIND[j], 0), j]
elif action == ACTION_DOWN:
return [max(min(i + 1 - WIND[j], WORLD_HEIGHT - 1), 0), j]
elif action == ACTION_LEFT:
return [max(i - WIND[j], 0), max(j - 1, 0)]
elif action == ACTION_RIGHT:
return [max(i - WIND[j], 0), min(j + 1, WORLD_WIDTH - 1)]
else:
assert False
算法中第2步步骤c,用ϵ−ϵ−贪婪法在状态S‘S‘选择新的动作A′A′的过程:
next_state = step(state, action)
if np.random.binomial(1, EPSILON) == 1:
next_action = np.random.choice(ACTIONS)
else:
values_ = q_value[next_state[0], next_state[1], :]
next_action = np.random.choice([action_ for action_, value_ in enumerate(values_) if value_ == np.max(values_)])
算法中第2步步骤d,e, 更新价值函数Q(S,A)Q(S,A)以及更新当前状态动作的过程:
# Sarsa update
q_value[state[0], state[1], action] += \
ALPHA * (REWARD + q_value[next_state[0], next_state[1], next_action] -
q_value[state[0], state[1], action])
state = next_state
action = next_action
代码很简单,相信大家对照算法,跑跑代码,可以很容易得到这个问题的最优解,进而搞清楚SARSA算法的整个流程。
5. SARSA(λ)
在系统学习机器学习之增强学习(五)--马尔可夫决策过程策略TD求解中我们讲到了多步时序差分TD(λ)的价值函数迭代方法,那么同样的,对应的多步时序差分在线控制算法,就是我们的SARSA(λ)。
TD(λ)有前向和后向两种价值函数迭代方式,当然它们是等价的。在控制问题的求解时,基于反向认识的 SARSA(λ)算法将可以有效地在线学习,数据学习完即可丢弃。因此 SARSA(λ)算法默认都是基于反向来进行价值函数迭代。
在上一篇我们讲到了TD(λ)状态价值函数的反向迭代,即:
对应的动作价值函数的迭代公式可以找样写出,即:
除了状态价值函数Q(S,A)的更新方式,多步参数λ以及反向认识引入的效用迹E(S,A),其余算法思想和SARSA类似。这里我们总结下SARSA(λ)的算法流程。
算法输入:迭代轮数T,状态集S, 动作集A, 步长α,衰减因子γ, 探索率ϵ, 多步参数λ
输出:所有的状态和动作对应的价值Q
1. 随机初始化所有的状态和动作对应的价值Q. 对于终止状态其Q值初始化为0.
2. for i from 1 to T,进行迭代。
a) 初始化所有状态动作的效用迹E为0,初始化S为当前状态序列的第一个状态。设置A为ϵ−贪婪法在当前状态S选择的动作。
b) 在状态S执行当前动作A,得到新状态S′和奖励R
c) 用ϵ−贪婪法在状态S′选择新的动作A′
d) 更新效用迹函数E(S,A)和TD误差δ:
e) 对当前序列所有出现的状态s和对应动作a, 更新价值函数Q(s,a)和效用迹函数E(s,a):
f) S=S′,A=A′
g) 如果S′是终止状态,当前轮迭代完毕,否则转到步骤b)
对于步长α,和SARSA一样,一般也需要随着迭代的进行逐渐变小才能保证动作价值函数Q收敛。
6. SARSA小结
SARSA算法和动态规划法比起来,不需要环境的状态转换模型,和蒙特卡罗法比起来,不需要完整的状态序列,因此比较灵活。在传统的强化学习方法中使用比较广泛。
但是SARSA算法也有一个传统强化学习方法共有的问题,就是无法求解太复杂的问题。在 SARSA 算法中,Q(S,A)的值使用一张大表来存储的,如果我们的状态和动作都达到百万乃至千万级,需要在内存里保存的这张大表会超级大,甚至溢出,因此不是很适合解决规模很大的问题。当然,对于不是特别复杂的问题,使用SARSA还是很不错的一种强化学习问题求解方法。
下一篇我们讨论SARSA的姊妹算法,时序差分离线控制算法Q-Learning。
7. 时序差分小结
时序差分和蒙特卡罗法比它更加灵活,学习能力更强,因此是目前主流的强化学习求解问题的方法,现在绝大部分强化学习乃至深度强化学习的求解都是以时序差分的思想为基础的。因此后面我们会重点讨论。
更多推荐
所有评论(0)