动手学强化学习(三):动态规划算法 (Dynamic Programming)

  • 1. 简介
  • 2. 悬崖漫步环境
  • 3. 策略迭代算法
    • 3.1 策略评估
    • 3.2 策略提升
    • 3.3 策略迭代算法
  • 4.价值迭代算法
  • 5. 冰湖环境
  • 6. 小结
  • 7. 扩展
    • 7.1 策略迭代
    • 7.2 价值迭代

文章转于 伯禹学习平台-动手学强化学习 (强推)
更多Ai资讯:公主号AiCharm

与君共勉,一起学习。

1. 简介

  动态规划(dynamic programming)是程序设计算法中非常重要的内容,能够高效解决一些经典问题,例如背包问题和最短路径规划。动态规划的基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到目标问题的解。动态规划会保存已解决的子问题的答案,在求解目标问题的过程中,需要这些子问题答案时就可以直接利用,避免重复计算。本章介绍如何用动态规划的思想来求解在马尔可夫决策过程中的最优策略。

  基于动态规划的强化学习算法主要有两种:一是策略迭代(policy iteration),二是价值迭代(value iteration)。其中,策略迭代由两部分组成:策略评估(policy evaluation)和策略提升(policy improvement)。具体来说,策略迭代中的策略评估使用贝尔曼期望方程来得到一个策略的状态价值函数,这是一个动态规划的过程;而价值迭代直接使用贝尔曼最优方程来进行动态规划,得到最终的最优状态价值。

  基于动态规划的这两种强化学习算法要求事先知道环境的状态转移函数和奖励函数,也就是需要知道整个马尔可夫决策过程。在这样一个白盒环境中,不需要通过智能体和环境的大量交互来学习,可以直接用动态规划求解状态价值函数。但是,现实中的白盒环境很少,这也是动态规划算法的局限之处,我们无法将其运用到很多实际场景中。另外,策略迭代和价值迭代通常只适用于有限马尔可夫决策过程,即状态空间和动作空间是离散且有限的。

2. 悬崖漫步环境

  本节使用策略迭代和价值迭代来求解悬崖漫步(Cliff Walking)这个环境中的最优策略。接下来先简单介绍一下该环境。

  悬崖漫步是一个非常经典的强化学习环境,它要求一个智能体从起点出发,避开悬崖行走,最终到达目标位置。如图 4-1 所示,有一个 4×12 的网格世界,每一个网格表示一个状态。智能体的起点是左下角的状态,目标是右下角的状态,智能体在每一个状态都可以采取 4 种动作:上、下、左、右。如果智能体采取动作后触碰到边界墙壁则状态不发生改变,否则就会相应到达下一个状态。环境中有一段悬崖,智能体掉入悬崖或到达目标状态都会结束动作并回到起点,也就是说掉入悬崖或者达到目标状态是终止状态。智能体每走一步的奖励是 −1,掉入悬崖的奖励是 −100。

图4-1 Cliff Walking环境示意图

  接下来一起来看一看 Cliff Walking 环境的代码吧。

import copyclass CliffWalkingEnv:""" 悬崖漫步环境"""def __init__(self, ncol=12, nrow=4):self.ncol = ncol  # 定义网格世界的列self.nrow = nrow  # 定义网格世界的行# 转移矩阵P[state][action] = [(p, next_state, reward, done)]包含下一个状态和奖励self.P = self.createP()def createP(self):# 初始化P = [[[] for j in range(4)] for i in range(self.nrow * self.ncol)]# 4种动作, change[0]:上,change[1]:下, change[2]:左, change[3]:右。坐标系原点(0,0)# 定义在左上角change = [[0, -1], [0, 1], [-1, 0], [1, 0]]for i in range(self.nrow):for j in range(self.ncol):for a in range(4):# 位置在悬崖或者目标状态,因为无法继续交互,任何动作奖励都为0if i == self.nrow - 1 and j > 0:P[i * self.ncol + j][a] = [(1, i * self.ncol + j, 0,True)]continue# 其他位置next_x = min(self.ncol - 1, max(0, j + change[a][0]))next_y = min(self.nrow - 1, max(0, i + change[a][1]))next_state = next_y * self.ncol + next_xreward = -1done = False# 下一个位置在悬崖或者终点if next_y == self.nrow - 1 and next_x > 0:done = Trueif next_x != self.ncol - 1:  # 下一个位置在悬崖reward = -100P[i * self.ncol + j][a] = [(1, next_state, reward, done)]return P

3. 策略迭代算法

  策略迭代是策略评估和策略提升不断循环交替,直至最后得到最优策略的过程。本节分别对这两个过程进行详细介绍。

3.1 策略评估

  策略评估这一过程用来计算一个策略的状态价值函数。回顾一下之前学习的贝尔曼期望方程:
V π ( s ) = ∑ a ∈ A π ( a ∣ s ) ( r ( s , a ) + γ ∑ s ′ ∈ S p ( s ′ ∣ s , a ) V π ( s ′ ) ) V^{\pi}(s)=\sum_{a \in A} \pi(a \mid s)\left(r(s, a)+\gamma \sum_{s^{\prime} \in S} p\left(s^{\prime} \mid s, a\right) V^{\pi}\left(s^{\prime}\right)\right) Vπ(s)=a∈A∑​π(a∣s)(r(s,a)+γs′∈S∑​p(s′∣s,a)Vπ(s′)) 子问题,把计算当前状态的价值看作当前问题。在得知子问题的解后,就可以求解当前问题。更一般的,考虑所有的状态,就变成了用上一轮的状态价值函数来计算当前这一轮的状态价值函数,即
V k + 1 ( s ) = ∑ a ∈ A π ( a ∣ s ) ( r ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V k ( s ′ ) ) V^{k+1}(s)=\sum_{a \in A} \pi(a \mid s)\left(r(s, a)+\gamma \sum_{s^{\prime} \in S} P\left(s^{\prime} \mid s, a\right) V^{k}\left(s^{\prime}\right)\right) Vk+1(s)=a∈A∑​π(a∣s)(r(s,a)+γs′∈S∑​P(s′∣s,a)Vk(s′))
  我们可以选定任意初始值 V 0 V^{0} V0 。根据贝尔曼期望方程,可以得知 V k = V π V^{k}=V^{\pi} Vk=Vπ 是以上更新公式的一个不动点 (fixed point) 。事实上,可以证明当 k → ∞ k \rightarrow \infty k→∞ 时,序列 { V k } \left\{V^{k}\right\} {Vk} 会收敛到 V π V^{\pi} Vπ ,所以可以据此来计算得到一个策略的状态价值函 数。可以看到,由于需要不断做贝尔曼期望方程达代,策略评估其实会耗费很大的计算代价。在实际的实现过程中,如果某一轮 max ⁡ s ∈ S ∣ V k + 1 ( s ) − V k ( s ) ∣ \max _{s \in \mathcal{S}}\left|V^{k+1}(s)-V^{k}(s)\right| maxs∈S​ ​Vk+1(s)−Vk(s) ​ 的值非常小,可以提前结束策略评估。这样做可以提升效率,并且得到的 价值也非常接近真实的价值。

3.2 策略提升

  使用策略评估计算得到当前策略的状态价值函数之后,我们可以据此来改进该策略。假设此时对于策略 π \pi π ,我们已经知道其价值 V π V^{\pi} Vπ ,也就是知道了在策略 π \pi π 下每一个状态 s s s 出发最终得到的期望 回报。我们要如何改变策略来获得在状态 s s s 下更高的期望回报呢? 假设智能体在状态 s s s 下采取动作 a a a ,之后的动作依旧遵循策略 π \pi π ,此时得到的期望回报其实就是动作价值 Q π ( s , a ) Q^{\pi}(s, a) Qπ(s,a) 。如果我们有 Q π ( s , a ) > V π ( s ) Q^{\pi}(s, a)>V^{\pi}(s) Qπ(s,a)>Vπ(s) ,则说明在状态 s s s 下采取动作 a a a 会比原来的策略 π ( a ∣ s ) \pi(a \mid s) π(a∣s) 得到更高的期望回报。以上假设只是针对一个状态,现在假设存在一个确定性策略 π ′ \pi^{\prime} π′ ,在任意一个状态 s s s 下,都满足
Q π ( s , π ′ ( s ) ) ≥ V π ( s ) Q^{\pi}\left(s, \pi^{\prime}(s)\right) \geq V^{\pi}(s) Qπ(s,π′(s))≥Vπ(s)
于是在任意状态 s s s 下,我们有
V π ′ ( s ) ≥ V π ( s ) V^{\pi^{\prime}}(s) \geq V^{\pi}(s) Vπ′(s)≥Vπ(s)
  这便是策略提升定理(policy improvement theorem)。于是我们可以直接贪心地在每一个状态选择动作价值最大的动作,也就是
π ′ ( s ) = arg ⁡ max ⁡ a Q π ( s , a ) = arg ⁡ max ⁡ a { r ( s , a ) + γ ∑ s ′ P ( s ′ ∣ s , a ) V π ( s ′ ) } \pi^{\prime}(s)=\arg \max _{a} Q^{\pi}(s, a)=\arg \max _{a}\left\{r(s, a)+\gamma \sum_{s^{\prime}} P\left(s^{\prime} \mid s, a\right) V^{\pi}\left(s^{\prime}\right)\right\} π′(s)=argamax​Qπ(s,a)=argamax​{r(s,a)+γs′∑​P(s′∣s,a)Vπ(s′)} 明策略迭代达到了收敛,此时 π \pi π 和 π ′ \pi^{\prime} π′ 就是最优策略。
V π ( s ) ≤ Q π ( s , π ′ ( s ) ) = E π ′ [ R t + γ V π ( S t + 1 ) ∣ S t = s ] ≤ E π ′ [ R t + γ Q π ( S t + 1 , π ′ ( S t + 1 ) ) ∣ S t = s ] = E π ′ [ R t + γ R t + 1 + γ 2 V π ( S t + 2 ) ∣ S t = s ] ≤ E π ′ [ R t + γ R t + 1 + γ 2 R t + 2 + γ 3 V π ( S t + 3 ) ∣ S t = s ] ⋮ \begin{aligned} V^{\pi}(s) & \leq Q^{\pi}\left(s, \pi^{\prime}(s)\right) \\ &=\mathbb{E}_{\pi^{\prime}}\left[R_{t}+\gamma V^{\pi}\left(S_{t+1}\right) \mid S_{t}=s\right] \\ & \leq \mathbb{E}_{\pi^{\prime}}\left[R_{t}+\gamma Q^{\pi}\left(S_{t+1}, \pi^{\prime}\left(S_{t+1}\right)\right) \mid S_{t}=s\right] \\ &=\mathbb{E}_{\pi^{\prime}}\left[R_{t}+\gamma R_{t+1}+\gamma^{2} V^{\pi}\left(S_{t+2}\right) \mid S_{t}=s\right] \\ & \leq \mathbb{E}_{\pi^{\prime}}\left[R_{t}+\gamma R_{t+1}+\gamma^{2} R_{t+2}+\gamma^{3} V^{\pi}\left(S_{t+3}\right) \mid S_{t}=s\right] \\ & \vdots \end{aligned} Vπ(s)​≤Qπ(s,π′(s))=Eπ′​[Rt​+γVπ(St+1​)∣St​=s]≤Eπ′​[Rt​+γQπ(St+1​,π′(St+1​))∣St​=s]=Eπ′​[Rt​+γRt+1​+γ2Vπ(St+2​)∣St​=s]≤Eπ′​[Rt​+γRt+1​+γ2Rt+2​+γ3Vπ(St+3​)∣St​=s]⋮​
  可以看到,推导过程中的每一个时间步都用到局部动作价值优势 V π ( S t + 1 ) ≤ Q π ( S t + 1 , π ′ ( S t + 1 ) ) V^{\pi}\left(S_{t+1}\right) \leq Q^{\pi}\left(S_{t+1}, \pi^{\prime}\left(S_{t+1}\right)\right) Vπ(St+1​)≤Qπ(St+1​,π′(St+1​)) ,累积到无穷步或者终止状态时,我们就得到了整个策略价值提升的不等式。

3.3 策略迭代算法

  总体来说,策略迭代算法的过程如下:对当前的策略进行策略评估,得到其状态价值函数,然后根据该状态价值函数进行策略提升以得到一个更好的新策略,接着继续评估新策略、提升策略……直至最后收敛到最优策略:
π 0 ⟶ 策略评估  V π 0 ⟶ 策略提升  π 1 ⟶ 策略评估  V π 1 ⟶ 策略提升  π 2 ⟶ 策略评估  … ⟶ 策略提升  π ∗ \pi^{0} \stackrel{\text { 策略评估 }}{\longrightarrow} V^{\pi^{0}} \stackrel{\text { 策略提升 }}{\longrightarrow} \pi^{1} \stackrel{\text { 策略评估 }}{\longrightarrow} V^{\pi^{1}} \stackrel{\text { 策略提升 }}{\longrightarrow} \pi^{2} \stackrel{\text { 策略评估 }}{\longrightarrow} \ldots \stackrel{\text { 策略提升 }}{\longrightarrow} \pi^{*} π0⟶ 策略评估 ​Vπ0⟶ 策略提升 ​π1⟶ 策略评估 ​Vπ1⟶ 策略提升 ​π2⟶ 策略评估 ​…⟶ 策略提升 ​π∗
  结合策略评估和策略提升,我们得到以下策略迭代算法:

  • 随机初始化策略 π ( s ) \pi(s) π(s) 和价值函数 V ( s ) V(s) V(s)
  • while Δ > θ \Delta>\theta Δ>θ do:(策略评估循环)
  • Δ < − 0 \quad \Delta<-0 Δ<−0
  • 对于每一个状态 s ∈ S s \in \mathcal{S} s∈S;
  • v ← V ( S ) \quad v \leftarrow V(S) v←V(S)
  • V ( s ) ← r ( s , π ( s ) ) + γ ∑ s ′ P ( s ′ ∣ s , π ( s ) ) V ( s ′ ) \quad V(s) \leftarrow r(s, \pi(s))+\gamma \sum_{s^{\prime}} P\left(s^{\prime} \mid s, \pi(s)\right) V\left(s^{\prime}\right) V(s)←r(s,π(s))+γ∑s′​P(s′∣s,π(s))V(s′)
  • Δ ← max ⁡ ( Δ , ∣ v − V ( s ) ∣ ) \quad \Delta \leftarrow \max (\Delta,|v-V(s)|) Δ←max(Δ,∣v−V(s)∣)
  • end while
  • π old  ← π \pi_{\text {old }} \leftarrow \pi πold ​←π
  • 对于每一个状态 s ∈ S s \in \mathcal{S} s∈S :
  • π ( s ) ← arg ⁡ max ⁡ a r ( s , a ) + γ ∑ s ′ P ( s ′ ∣ s , a ) V ( s ′ ) \quad \pi(s) \leftarrow \arg \max _{a} r(s, a)+\gamma \sum_{s^{\prime}} P\left(s^{\prime} \mid s, a\right) V\left(s^{\prime}\right) π(s)←argmaxa​r(s,a)+γ∑s′​P(s′∣s,a)V(s′)
  • 若 π old  = π \pi_{\text {old }}=\pi πold ​=π, 则停止算法并返回 V V V 和 π \pi π; 否则转到策略评估循环
    策略迭代算法的代码实现过程。
class PolicyIteration:""" 策略迭代算法 """def __init__(self, env, theta, gamma):self.env = envself.v = [0] * self.env.ncol * self.env.nrow  # 初始化价值为0self.pi = [[0.25, 0.25, 0.25, 0.25]for i in range(self.env.ncol * self.env.nrow)]  # 初始化为均匀随机策略self.theta = theta  # 策略评估收敛阈值self.gamma = gamma  # 折扣因子def policy_evaluation(self):  # 策略评估cnt = 1  # 计数器while 1:max_diff = 0new_v = [0] * self.env.ncol * self.env.nrowfor s in range(self.env.ncol * self.env.nrow):qsa_list = []  # 开始计算状态s下的所有Q(s,a)价值for a in range(4):qsa = 0for res in self.env.P[s][a]:p, next_state, r, done = resqsa += p * (r + self.gamma * self.v[next_state] *(1 - done))# 本章环境比较特殊,奖励和下一个状态有关,所以需要和状态转移概率相乘qsa_list.append(self.pi[s][a] * qsa)new_v[s] = sum(qsa_list)  # 状态价值函数和动作价值函数之间的关系max_diff = max(max_diff, abs(new_v[s] - self.v[s]))self.v = new_vif max_diff < self.theta: break  # 满足收敛条件,退出评估迭代cnt += 1print("策略评估进行%d轮后完成" % cnt)def policy_improvement(self):  # 策略提升for s in range(self.env.nrow * self.env.ncol):qsa_list = []for a in range(4):qsa = 0for res in self.env.P[s][a]:p, next_state, r, done = resqsa += p * (r + self.gamma * self.v[next_state] *(1 - done))qsa_list.append(qsa)maxq = max(qsa_list)cntq = qsa_list.count(maxq)  # 计算有几个动作得到了最大的Q值# 让这些动作均分概率self.pi[s] = [1 / cntq if q == maxq else 0 for q in qsa_list]print("策略提升完成")return self.pidef policy_iteration(self):  # 策略迭代while 1:self.policy_evaluation()old_pi = copy.deepcopy(self.pi)  # 将列表进行深拷贝,方便接下来进行比较new_pi = self.policy_improvement()if old_pi == new_pi: break

  现在我们已经写好了环境代码和策略迭代代码。为了更好地展现最终的策略,接下来增加一个打印策略的函数,用于打印当前策略在每个状态下的价值以及智能体会采取的动作。对于打印出来的动作,我们用^o<o表示等概率采取向左和向上两种动作,ooo>表示在当前状态只采取向右动作。

def print_agent(agent, action_meaning, disaster=[], end=[]):print("状态价值:")for i in range(agent.env.nrow):for j in range(agent.env.ncol):# 为了输出美观,保持输出6个字符print('%6.6s' % ('%.3f' % agent.v[i * agent.env.ncol + j]),end=' ')print()print("策略:")for i in range(agent.env.nrow):for j in range(agent.env.ncol):# 一些特殊的状态,例如悬崖漫步中的悬崖if (i * agent.env.ncol + j) in disaster:print('****', end=' ')elif (i * agent.env.ncol + j) in end:  # 目标状态print('EEEE', end=' ')else:a = agent.pi[i * agent.env.ncol + j]pi_str = ''for k in range(len(action_meaning)):pi_str += action_meaning[k] if a[k] > 0 else 'o'print(pi_str, end=' ')print()env = CliffWalkingEnv()
action_meaning = ['^', 'v', '<', '>']
theta = 0.001
gamma = 0.9
agent = PolicyIteration(env, theta, gamma)
agent.policy_iteration()
print_agent(agent, action_meaning, list(range(37, 47)), [47])# 策略评估进行60轮后完成
# 策略提升完成
# 策略评估进行72轮后完成
# 策略提升完成
# 策略评估进行44轮后完成
# 策略提升完成
# 策略评估进行12轮后完成
# 策略提升完成
# 策略评估进行1轮后完成
# 策略提升完成
# 状态价值:
# -7.712 -7.458 -7.176 -6.862 -6.513 -6.126 -5.695 -5.217 -4.686 -4.095 -3.439 -2.710
# -7.458 -7.176 -6.862 -6.513 -6.126 -5.695 -5.217 -4.686 -4.095 -3.439 -2.710 -1.900
# -7.176 -6.862 -6.513 -6.126 -5.695 -5.217 -4.686 -4.095 -3.439 -2.710 -1.900 -1.000
# -7.458  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
# 策略:
# ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovoo
# ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovoo
# ooo> ooo> ooo> ooo> ooo> ooo> ooo> ooo> ooo> ooo> ooo> ovoo
# ^ooo **** **** **** **** **** **** **** **** **** **** EEEE

  经过 5 次策略评估和策略提升的循环迭代,策略收敛了,此时将获得的策略打印出来。用贝尔曼最优方程去检验其中每一个状态的价值,可以发现最终输出的策略的确是最优策略。

4.价值迭代算法

  从上面的代码运行结果中我们能发现,策略迭代中的策略评估需要进行很多轮才能收敛得到某一策略的状态函数,这需要很大的计算量,尤其是在状态和动作空间比较大的情况下。我们是否必须要完全等到策略评估完成后再进行策略提升呢?试想一下,可能出现这样的情况:虽然状态价值函数还没有收敛,但是不论接下来怎么更新状态价值,策略提升得到的都是同一个策略。如果只在策略评估中进行一轮价值更新,然后直接根据更新后的价值进行策略提升,这样是否可以呢?答案是肯定的,这其实就是本节将要讲解的价值迭代算法,它可以被认为是一种策略评估只进行了一轮更新的策略迭代算法。需要注意的是,价值迭代中不存在显式的策略,我们只维护一个状态价值函数。

确切来说,价值迭代可以看成一种动态规划过程,它利用的是贝尔曼最优方程:
V ∗ ( s ) = max ⁡ a ∈ A { r ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V ∗ ( s ′ ) } V^{*}(s)=\max _{a \in \mathcal{A}}\left\{r(s, a)+\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) V^{*}\left(s^{\prime}\right)\right\} V∗(s)=a∈Amax​{r(s,a)+γs′∈S∑​P(s′∣s,a)V∗(s′)}
将其写成迭代更新的方式为
V k + 1 ( s ) = max ⁡ a ∈ A { r ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V k ( s ′ ) } V^{k+1}(s)=\max _{a \in \mathcal{A}}\left\{r(s, a)+\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) V^{k}\left(s^{\prime}\right)\right\} Vk+1(s)=a∈Amax​{r(s,a)+γs′∈S∑​P(s′∣s,a)Vk(s′)}
  价值迭代便是按照以上更新方式进行的。等到 V k + 1 V^{k+1} Vk+1 和 V k V^{k} Vk 相同时,它就是贝尔曼最优方程的不动点,此时对应着最优状态价值函数 V ∗ V^{*} V∗ 。然后我 们利用 π ( s ) = arg ⁡ max ⁡ a { r ( s , a ) + γ ∑ s ′ p ( s ′ ∣ s , a ) V k + 1 ( s ′ ) } \pi(s)=\arg \max _{a}\left\{r(s, a)+\gamma \sum_{s^{\prime}} p\left(s^{\prime} \mid s, a\right) V^{k+1}\left(s^{\prime}\right)\right\} π(s)=argmaxa​{r(s,a)+γ∑s′​p(s′∣s,a)Vk+1(s′)} ,从中恢复出最优策略即可。
价值迭代算法流程如下:

  • 随机初始化 V ( s ) V(s) V(s)
  • while Δ > θ \Delta>\theta Δ>θ do :
  • Δ ← 0 \Delta \leftarrow 0 Δ←0
  • 对于每一个状态 s ∈ S s \in \mathcal{S} s∈S :
  • v < V ( s ) \quad v<V(s) v<V(s)
  • V ( s ) ← max ⁡ a r ( s , a ) + γ ∑ s ′ P ( s ′ ∣ s , a ) V ( s ′ ) V(s) \leftarrow \max _{a} r(s, a)+\gamma \sum_{s^{\prime}} P\left(s^{\prime} \mid s, a\right) V\left(s^{\prime}\right) V(s)←maxa​r(s,a)+γ∑s′​P(s′∣s,a)V(s′)
  • Δ ← max ⁡ ( Δ , ∣ v − V ( s ) ∣ ) \Delta \leftarrow \max (\Delta,|v-V(s)|) Δ←max(Δ,∣v−V(s)∣)
  • end while
  • 返回一个确定性策略 π ( s ) = arg ⁡ max ⁡ a { r ( s , a ) + γ ∑ s ′ P ( s ′ ∣ s , a ) V ( s ′ ) } \pi(s)=\arg \max _{a}\left\{r(s, a)+\gamma \sum_{s^{\prime}} P\left(s^{\prime} \mid s, a\right) V\left(s^{\prime}\right)\right\} π(s)=argmaxa​{r(s,a)+γ∑s′​P(s′∣s,a)V(s′)}
    我们现在来编写价值迭代的代码。
class ValueIteration:""" 价值迭代算法 """def __init__(self, env, theta, gamma):self.env = envself.v = [0] * self.env.ncol * self.env.nrow  # 初始化价值为0self.theta = theta  # 价值收敛阈值self.gamma = gamma# 价值迭代结束后得到的策略self.pi = [None for i in range(self.env.ncol * self.env.nrow)]def value_iteration(self):cnt = 0while 1:max_diff = 0new_v = [0] * self.env.ncol * self.env.nrowfor s in range(self.env.ncol * self.env.nrow):qsa_list = []  # 开始计算状态s下的所有Q(s,a)价值for a in range(4):qsa = 0for res in self.env.P[s][a]:p, next_state, r, done = resqsa += p * (r + self.gamma * self.v[next_state] *(1 - done))qsa_list.append(qsa)  # 这一行和下一行代码是价值迭代和策略迭代的主要区别new_v[s] = max(qsa_list)max_diff = max(max_diff, abs(new_v[s] - self.v[s]))self.v = new_vif max_diff < self.theta: break  # 满足收敛条件,退出评估迭代cnt += 1print("价值迭代一共进行%d轮" % cnt)self.get_policy()def get_policy(self):  # 根据价值函数导出一个贪婪策略for s in range(self.env.nrow * self.env.ncol):qsa_list = []for a in range(4):qsa = 0for res in self.env.P[s][a]:p, next_state, r, done = resqsa += r + p * self.gamma * self.v[next_state] * (1 - done)qsa_list.append(qsa)maxq = max(qsa_list)cntq = qsa_list.count(maxq)  # 计算有几个动作得到了最大的Q值# 让这些动作均分概率self.pi[s] = [1 / cntq if q == maxq else 0 for q in qsa_list]# env = CliffWalkingEnv()
# action_meaning = ['^', 'v', '<', '>']
# theta = 0.001
# gamma = 0.9
# agent = ValueIteration(env, theta, gamma)
# agent.value_iteration()
# print_agent(agent, action_meaning, list(range(37, 47)), [47])# 价值迭代一共进行14轮
# 状态价值:
# -7.712 -7.458 -7.176 -6.862 -6.513 -6.126 -5.695 -5.217 -4.686 -4.095 -3.439 -2.710
# -7.458 -7.176 -6.862 -6.513 -6.126 -5.695 -5.217 -4.686 -4.095 -3.439 -2.710 -1.900
# -7.176 -6.862 -6.513 -6.126 -5.695 -5.217 -4.686 -4.095 -3.439 -2.710 -1.900 -1.000
# -7.458  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000  0.000
# 策略:
# ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovoo
# ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovo> ovoo
# ooo> ooo> ooo> ooo> ooo> ooo> ooo> ooo> ooo> ooo> ooo> ovoo
# ^ooo **** **** **** **** **** **** **** **** **** **** EEEE

  可以看到,解决同样的训练任务,价值迭代总共进行了数十轮,而策略迭代中的策略评估总共进行了数百轮,价值迭代中的循环次数远少于策略迭代。

5. 冰湖环境

  除了悬崖漫步环境,本章还准备了另一个环境——冰湖(Frozen Lake)。冰湖环境的状态空间和动作空间是有限的,我们在该环境中也尝试一下策略迭代算法和价值迭代算法,以便更好地理解这两个算法。

  冰湖是 OpenAI Gym 库中的一个环境。OpenAI Gym 库中包含了很多有名的环境,例如 Atari 和 MuJoCo,并且支持我们定制自己的环境。在之后的章节中,我们还会使用到更多来自 OpenAI Gym 库的环境。如图 4-2 所示,冰湖环境和悬崖漫步环境相似,也是一个网格世界,大小为 4 × 4 4×4 4×4。每一个方格是一个状态,智能体起点状态 S S S在左上角,目标状态 G G G在右下角,中间还有若干冰洞 H H H。在每一个状态都可以采取上、下、左、右 4 个动作。由于智能体在冰面行走,因此每次行走都有一定的概率滑行到附近的其它状态,并且到达冰洞或目标状态时行走会提前结束。每一步行走的奖励是 0,到达目标的奖励是 1。

图4-2 Frozen Lake环境示意图   我们先创建 OpenAI Gym 中的 FrozenLake-v0 环境,并简单查看环境信息,然后找出冰洞和目标状态。

import gym
env = gym.make("FrozenLake-v0")  # 创建环境
env = env.unwrapped  # 解封装才能访问状态转移矩阵P
env.render()  # 环境渲染,通常是弹窗显示或打印出可视化的环境holes = set()
ends = set()
for s in env.P:for a in env.P[s]:for s_ in env.P[s][a]:if s_[2] == 1.0:  # 获得奖励为1,代表是目标ends.add(s_[1])if s_[3] == True:holes.add(s_[1])
holes = holes - ends
print("冰洞的索引:", holes)
print("目标的索引:", ends)for a in env.P[14]:  # 查看目标左边一格的状态转移信息print(env.P[14][a])# [41mS[0mFFF
# FHFH
# FFFH
# HFFG
# 冰洞的索引: {11, 12, 5, 7}
# 目标的索引: {15}
# [(0.3333333333333333, 10, 0.0, False), (0.3333333333333333, 13, 0.0, False),
#  (0.3333333333333333, 14, 0.0, False)]
# [(0.3333333333333333, 13, 0.0, False), (0.3333333333333333, 14, 0.0, False),
#  (0.3333333333333333, 15, 1.0, True)]
# [(0.3333333333333333, 14, 0.0, False), (0.3333333333333333, 15, 1.0, True),
#  (0.3333333333333333, 10, 0.0, False)]
# [(0.3333333333333333, 15, 1.0, True), (0.3333333333333333, 10, 0.0, False),
#  (0.3333333333333333, 13, 0.0, False)]

  首先,我们发现冰洞的索引是{ 5,7,11,12 }(集合 set 的索引是无序的),起点状态(索引为 0)在左上角,和悬崖漫步环境一样。其次,根据第 15 个状态(即目标左边一格,数组下标索引为 14)的信息,我们可以看到每个动作都会等概率“滑行”到 3 种可能的结果,这一点和悬崖漫步环境是不一样的。我们接下来先在冰湖环境中尝试一下策略迭代算法。

# 这个动作意义是Gym库针对冰湖环境事先规定好的
action_meaning = ['<', 'v', '>', '^']
theta = 1e-5
gamma = 0.9
agent = PolicyIteration(env, theta, gamma)
agent.policy_iteration()
print_agent(agent, action_meaning, [5, 7, 11, 12], [15])# 策略评估进行25轮后完成
# 策略提升完成
# 策略评估进行58轮后完成
# 策略提升完成
# 状态价值:
#  0.069  0.061  0.074  0.056
#  0.092  0.000  0.112  0.000
#  0.145  0.247  0.300  0.000
#  0.000  0.380  0.639  0.000
# 策略:
# <ooo ooo^ <ooo ooo^
# <ooo **** <o>o ****
# ooo^ ovoo <ooo ****
# **** oo>o ovoo EEEE

  这个最优策略很看上去比较反直觉,其原因是这是一个智能体会随机滑向其他状态的冰冻湖面。例如,在目标左边一格的状态,采取向右的动作时,它有可能会滑到目标左上角的位置,从该位置再次到达目标会更加困难,所以此时采取向下的动作是更为保险的,并且有一定概率能够滑到目标。我们再来尝试一下价值迭代算法。

action_meaning = ['<', 'v', '>', '^']
theta = 1e-5
gamma = 0.9
agent = ValueIteration(env, theta, gamma)
agent.value_iteration()
print_agent(agent, action_meaning, [5, 7, 11, 12], [15])# 价值迭代一共进行60轮
# 状态价值:
#  0.069  0.061  0.074  0.056
#  0.092  0.000  0.112  0.000
#  0.145  0.247  0.300  0.000
#  0.000  0.380  0.639  0.000
# 策略:
# <ooo ooo^ <ooo ooo^
# <ooo **** <o>o ****
# ooo^ ovoo <ooo ****
# **** oo>o ovoo EEEE

  可以发现价值迭代算法的结果和策略迭代算法的结果完全一致,这也互相验证了各自的结果。

6. 小结

  本章讲解了强化学习中两个经典的动态规划算法:策略迭代算法和价值迭代算法,它们都能用于求解最优价值和最优策略。动态规划的主要思想是利用贝尔曼方程对所有状态进行更新。需要注意的是,在利用贝尔曼方程进行状态更新时,我们会用到马尔可夫决策过程中的奖励函数和状态转移函数。如果智能体无法事先得知奖励函数和状态转移函数,就只能通过和环境进行交互来采样(状态-动作-奖励-下一状态)这样的数据,我们将在之后的章节中讲解如何求解这种情况下的最优策略。

7. 扩展

7.1 策略迭代

  策略迭代的过程如下:
π 0 ⟶ 策略评估  V π 0 ⟶ 策略提升  π 1 ⟶ 策略评估  V π 1 ⟶ 策略提升  π 2 ⟶ 策略评估  … ⟶ 策略提升  π ∗ \pi^{0} \stackrel{\text { 策略评估 }}{\longrightarrow} V^{\pi^{0}} \stackrel{\text { 策略提升 }}{\longrightarrow} \pi^{1} \stackrel{\text { 策略评估 }}{\longrightarrow} V^{\pi^{1}} \stackrel{\text { 策略提升 }}{\longrightarrow} \pi^{2} \stackrel{\text { 策略评估 }}{\longrightarrow} \ldots \stackrel{\text { 策略提升 }}{\longrightarrow} \pi^{*} π0⟶ 策略评估 ​Vπ0⟶ 策略提升 ​π1⟶ 策略评估 ​Vπ1⟶ 策略提升 ​π2⟶ 策略评估 ​…⟶ 策略提升 ​π∗
  根据策略提升定理,我们知道更新后的策略的价值函数满足单调性,即 V π k + 1 ≥ V π k V^{\pi^{k+1}} \geq V^{\pi^{k}} Vπk+1≥Vπk 。所以只要所有可能的策略个数是有限的,策略迭代就能收敛到最优策略。假设 MDP 的状态空间大小为 ∣ S ∣ |\mathcal{S}| ∣S∣ ,
还有另一种类似的证明思路。在有限马尔可夫决策过程中,如果 γ < 1 \gamma<1 γ<1 ,那么很显然存在一个上界 C = R max ⁡ / ( 1 − γ ) C=R_{\max } /(1-\gamma) C=Rmax​/(1−γ) (这里的 R max ⁡ R_{\max } Rmax​ 为最大单步奖励值),使得对于任意策略 π \pi π 和状态 s s s ,其价值

7.2 价值迭代

  价值迭代的更新公式为:
V k + 1 ( s ) = max ⁡ a ∈ A { r ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V k ( s ′ ) } V^{k+1}(s)=\max _{a \in \mathcal{A}}\left\{r(s, a)+\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) V^{k}\left(s^{\prime}\right)\right\} Vk+1(s)=a∈Amax​{r(s,a)+γs′∈S∑​P(s′∣s,a)Vk(s′)}
  我们将其定义为一个贝尔曼最优算子 T \mathcal{T} T :
V k + 1 ( s ) = T V k ( s ) = max ⁡ a ∈ A { r ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V k ( s ′ ) } V^{k+1}(s)=\mathcal{T} V^{k}(s)=\max _{a \in \mathcal{A}}\left\{r(s, a)+\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) V^{k}\left(s^{\prime}\right)\right\} Vk+1(s)=TVk(s)=a∈Amax​{r(s,a)+γs′∈S∑​P(s′∣s,a)Vk(s′)}
  然后我们引入压缩算子 (contraction operator) : 若 O O O 是一个算子,如果满足 ∥ O V − O V ′ ∥ q ≤ ∥ V − V ′ ∥ q \left\|O V-O V^{\prime}\right\|_{q} \leq\left\|V-V^{\prime}\right\|_{q} ∥OV−OV′∥q​≤∥V−V′∥q​ 条件,则我们称 O O O 是一个压缩算子。其中 ∥ x ∥ q \|x\|_{q} ∥x∥q​ 表示 x x x 的 L q L_{q} Lq​ 范数,包括我们将会用到的 无穷范数 ∥ x ∥ ∞ = max ⁡ i ∣ x i ∣ ∘ \|x\|_{\infty}=\max _{i}\left|x_{i}\right|_{\circ} ∥x∥∞​=maxi​∣xi​∣∘​

  我们接下来证明当 γ < 1 \gamma<1 γ<1 时,贝尔曼最优算子 T \mathcal{T} T 是一个 γ \gamma γ-压缩算子。
∥ T V − T V ′ ∥ ∞ = max ⁡ s ∈ S ∣ max ⁡ a ∈ A { r ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V ( s ′ ) } − max ⁡ a ′ ∈ A { r ( s , a ′ ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ′ ) V ′ ( s ′ ) } ∣ ≤ max ⁡ s , a ∣ r ( s , a ) + γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V ( s ′ ) − r ( s , a ) − γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V ′ ( s ′ ) ∣ = γ max ⁡ s , a ∣ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) ( V ( s ′ ) − V ′ ( s ′ ) ) ∣ ≤ γ max ⁡ s , a ∑ s ′ ∈ S P ( s ′ ∣ s , a ) max ⁡ s ′ ∣ V ( s ′ ) − V ′ ( s ′ ) ∣ = γ ∥ V − V ′ ∥ ∞ \begin{aligned} \left\|\mathcal{T} V-\mathcal{T} V^{\prime}\right\|_{\infty} &=\max _{s \in \mathcal{S}}\left|\max _{a \in \mathcal{A}}\left\{r(s, a)+\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) V\left(s^{\prime}\right)\right\}-\max _{a^{\prime} \in \mathcal{A}}\left\{r\left(s, a^{\prime}\right)+\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a^{\prime}\right) V^{\prime}\left(s^{\prime}\right)\right\}\right| \\ & \leq \max _{s, a}\left|r(s, a)+\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) V\left(s^{\prime}\right)-r(s, a)-\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) V^{\prime}\left(s^{\prime}\right)\right| \\ &=\gamma \max _{s, a}\left|\sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right)\left(V\left(s^{\prime}\right)-V^{\prime}\left(s^{\prime}\right)\right)\right| \\ & \leq \gamma \max _{s, a} \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) \max _{s^{\prime}}\left|V\left(s^{\prime}\right)-V^{\prime}\left(s^{\prime}\right)\right| \\ &=\gamma\left\|V-V^{\prime}\right\|_{\infty} \end{aligned} ∥TV−TV′∥∞​​=s∈Smax​ ​a∈Amax​{r(s,a)+γs′∈S∑​P(s′∣s,a)V(s′)}−a′∈Amax​{r(s,a′)+γs′∈S∑​P(s′∣s,a′)V′(s′)} ​≤s,amax​ ​r(s,a)+γs′∈S∑​P(s′∣s,a)V(s′)−r(s,a)−γs′∈S∑​P(s′∣s,a)V′(s′) ​=γs,amax​ ​s′∈S∑​P(s′∣s,a)(V(s′)−V′(s′)) ​≤γs,amax​s′∈S∑​P(s′∣s,a)s′max​∣V(s′)−V′(s′)∣=γ∥V−V′∥∞​​
将 V ′ V^{\prime} V′ 设为最优价值函数 V ∗ V^{*} V∗ ,于是有:
∥ V k + 1 − V ∗ ∥ ∞ = ∥ T V k − T V ∗ ∥ ∞ ≤ γ ∥ V k − V ∗ ∥ ∞ ≤ ⋯ ≤ γ k + 1 ∥ V 0 − V ∗ ∥ ∞ \left\|V^{k+1}-V^{*}\right\|_{\infty}=\left\|\mathcal{T} V^{k}-\mathcal{T} V^{*}\right\|_{\infty} \leq \gamma\left\|V^{k}-V^{*}\right\|_{\infty} \leq \cdots \leq \gamma^{k+1}\left\|V^{0}-V^{*}\right\|_{\infty} ​Vk+1−V∗ ​∞​= ​TVk−TV∗ ​∞​≤γ ​Vk−V∗ ​∞​≤⋯≤γk+1 ​V0−V∗ ​∞​
  这意味着,在 γ ≤ 1 \gamma \leq 1 γ≤1 的情况下,随着迭代次数 k k k 越来越大, V k V^{k} Vk 会越来越接近 V ∗ V^{*} V∗ ,即 lim ⁡ k → ∞ V k = V ∗ \lim _{k \rightarrow \infty} V^{k}=V^{*} limk→∞​Vk=V∗ 。至此,价值迭代的收敛性得到证明。

更多Ai资讯:公主号AiCharm

相关资源来自:伯禹学习平台-动手学强化学习

动手学强化学习(三):动态规划算法 (Dynamic Programming)相关推荐

  1. 动手学强化学习第六章(Dyna-Q算法)

    文章目录 Dyna-Q算法 1.理论部分 2.代码实践 Dyna-Q算法 文章转载自<动手学强化学习>https://hrl.boyuai.com/chapter/intro 1.理论部分 ...

  2. 动手学强化学习第三章(马尔可夫决策过程)

    文章目录 马尔可夫决策过程 1.公式总结 2.代码实践 2.1 计算序列的回报 2.2 利用贝尔曼方程的矩阵形式计算解析解 2.3 解析法计算MDP中每个状态价值 2.4 使用蒙特卡洛方法计算MDP的 ...

  3. 【强化学习】《动手学强化学习》马尔可夫决策过程

    [强化学习]<动手学强化学习>马尔可夫决策过程 一.随机过程.马尔可夫过程.马尔可夫奖励过程 二.马尔可夫决策过程 三.蒙特卡洛方法 四.最优策略与贝尔曼最优方程 一.随机过程.马尔可夫过 ...

  4. 【动手学强化学习】DDPG+HER

    代码参考自动手学强化学习(jupyter notebook版本):https://github.com/boyu-ai/Hands-on-RL 使用pycharm打开的请查看:https://gith ...

  5. 赠书 | 干货!用 Python 动手学强化学习

    01 了解强化学习 新闻报道中很少将强化学 习与机器学习.深度学习.人工智能这些关键词区分开来,所以我们要先介绍什么是强化学习,再讲解其基本机制. 强化学习与机器学习.人工智能这些关键词之间的关系: ...

  6. ADPRL - 近似动态规划和强化学习 - Note 7 - Approximate Dynamic Programming

    Note 7 - 近似动态规划 Approximate Dynamic Programming 7. 近似动态规划 (Approximate Dynamic Programming) 7.1 近似架构 ...

  7. 动手学强化学习(一)

    第 1 章 初探强化学习 1. 强化学习的环境 强化学习的智能体是在和一个动态环境的交互中完成序贯决策的. 2. 强化学习的目标 在强化学习中,我们关注回报(return)的期望,并将其定义为价值(v ...

  8. 动态规划算法实验报告_强化学习之动态规划算法

    如今的强化学习研究大体分为了两个研究学派:一个是以Sutton,Sliver等人为代表的value-based学派,他们主要从值函数近似角度入手去研究强化学习,这也是强化学习早期最初发展起来时沿用的路 ...

  9. dqn在训练过程中loss越来越大_[动手学强化学习] 2.DQN解决CartPole-v0问题

    强化学习如何入门: 强化学习怎么入门好?​www.zhihu.com 最近在整理之前写的强化学习代码,发现pytorch的代码还是老版本的. 而pytorch今年更新了一个大版本,更到0.4了,很多老 ...

最新文章

  1. shell变量,管道符,作业控制,shell变量,以及变量配置文件
  2. plsql command window 执行批量脚本
  3. linux 标准IO缓冲机制探究
  4. Linux DNS服务配置与管理详解
  5. 你真的知道 NoSuchMethodError 发生原因和解决办法吗
  6. 使用Visual Studio 2010 一步一步创建Powershell Module 和 Cmdlet
  7. android 内部共享存储,Android共享内部存储
  8. 面向对象基础-委托与事件
  9. mysql忘记密码怎么办?
  10. http请求中必备的字符段_React Hooks中这样写HTTP请求可以避免内存泄漏
  11. 用python写行列式_用Python开发线性代数算法(一) | 手写行列式算法的实现
  12. 024、JVM实战总结:动手实验:线上部署系统时,如何设置垃圾回收相关参数?
  13. WindowsXP 下搭建PHP环境(笔记)
  14. 集群资源分配_推荐一款MySQL日常运维和集群管理的自动化平台--Arkcontrol
  15. ArcGIS几种数据格式
  16. python图灵机器人教程_Python-微信图灵机器人
  17. 微信小程序踩坑–卸载所有页面(含tabBar)跳转到指定页面
  18. 一个有启发意义的故事
  19. 解决方法 android.view.AbsSavedState$1 cannot be cast to android.widget.CompoundButton$SavedState
  20. i18n和i10n:国际化本地化--gettext

热门文章

  1. 猪八戒是个好员工——张教授
  2. 2020年第三方铁塔数据大汇总,全年新增超4900座
  3. 巧用PPOCRLabel制作DOC-VQA格式数据集
  4. 留学生在海外——Nina的幸福澳洲生活
  5. 2022.2.20考研出分最后一夜
  6. 为什么决策树模型不考虑变量之间的共线性?
  7. Android端适老化与无障碍改造
  8. 论文阅读——《动态规划》 作者 方奇
  9. SAP - 表、业务流程
  10. 异步电机模型预测磁链控制(MPFC)