diff --git a/docs/ch5/main.md b/docs/ch5/main.md index c2d8bc3..b535fcb 100644 --- a/docs/ch5/main.md +++ b/docs/ch5/main.md @@ -1,8 +1,8 @@ -# 免模型控制 +# 第 5 章 免模型控制 $\qquad$ 回顾前面讲的控制,即给定一个马尔可夫决策过程,输出最优策略以及对应的最优价值函数。而免模型则是指不需要知道环境的状态转移概率的一类算法,实际上很多经典的强化学习算法都是免模型控制的。本章会重点介绍两种基础的免模型算法,$\text{Q-learning}$ 和 $\text{Sarsa}$ ,也都是基于时序差分的方法。 -## Q-learning 算法 +## 5.1 Q-learning 算法 $\qquad$ 在时序差分方法的章节中我们讲的是状态价值函数的时序差分,其目的是为了预测每个状态的价值。而在预测与控制的内容中我们提到了控制的方法是需要输出最优策略的同时,也会输出对应的状态价值函数,预测的方法也是为了帮助解决控制问题做一个铺垫。不知道读者还记不记得,策略与状态价值函数之间是存在一个联系的,这个联系就是动作价值函数,如式 $\text(5.1)$ 所示: @@ -29,7 +29,7 @@ $$ $\qquad$ 我们会发现两者的更新方式是一样的,都是基于时序差分的更新方法。不同的是,动作价值函数更新时是直接拿最大的未来动作价值的 $\gamma\max _{a}Q(s_{t+1},a)$ 来估计的,而在状态价值函数更新中相当于是拿对应的平均值来估计的。这就会导致这个估计相当于状态价值函数中的估计更不准确,一般称为 **Q 值的过估计**,当然这个过估计仅仅限于以 $\text{Q-learning}$ 为基础的算法,不同的算法为了优化这个问题使用了不同的估计方式,其中就包括本章后面会讲的 Sarsa 算法,暂时先不详细展开。 -### Q 表格 +### 5.1.1 Q 表格 $\qquad$ 回到 $\text{Q-learning}$ 算法本身,其实到这里我们已经把 $\text{Q-learning}$ 算法的核心内容讲完了,即上面的更新公式 $\text(4.5)$。但是有必要提到几个概念,$\text{Q}$ 表格和探索策略,以便帮助读者加深理解。 @@ -121,7 +121,7 @@ $\qquad$ 表格的横和列对应状态和动作,数值表示对应的 $Q$ 值 $\qquad$ 现在我们讲讲 $Q$ 值的更新过程,其实跟前面讲的状态价值更新是类似的。但不一样的是,前面讲状态价值的更新是蒙特卡洛方法,这次是时序差分方法。具体的做法是,我们会让机器人自行在网格中走动,走到一个状态,就把对应的 $Q$ 值 更新一次,这个过程就叫做 **探索** 。这个探索的过程也是时序差分方法结合了蒙特卡洛方法的体现。当然探索的方式有很多种,很难在读者初学的阶段一次性就全部倒腾出来,这也是为什么在前面讲时序差分方法的时候我们只讲了更新公式而没有讲实际是怎么操作的原因,之后会结合具体情况一一道来,下面我们讲讲 $\text{Q-learning}$ 算法中智能体是怎么探索的。 -### 探索策略 +### 5.1.2 探索策略 $\qquad$ 按理说来,直接根据 $Q$ 函数(即每次选择 $Q$ 值最大对应的动作)来探索是没有问题的。但是由于在探索的过程中 $Q$ 值也是估计出来的,然后还需要利用先前的估计值来更新 $Q$ 值(也就是自举的过程),换句话说,由于自举依赖于先前的估计值,因此这可能会导致估计出的价值函数存在某种程度上的偏差。 @@ -142,7 +142,7 @@ $\qquad$ 讲到这里,我们就可以贴出 $\text{Q-learning}$ 算法的伪 -## Sarsa 算法 +## 5.2 Sarsa 算法 $\qquad$ $\text{Sarsa}$ 算法虽然在刚提出的时候被认为是 $\text{Q-learning}$ 算法的改进,但在今天看来是非常类似,但是模式却不同的两类算法,$\text{Q-learning}$ 算法被认为是 $\text{Off-Policy}$ 算法,而 $\text{Sarsa}$ 算法相对地则是 $\text{On-policy}$ 的,具体我们后面会展开说明。我们先来看 $\text{Sarsa}$ 算法,我们讲到 $\text{Sarsa}$ 算法跟 $\text{Q-learning}$ 算法是非常类似的,这是因为两者之间在形式上只有 $Q$ 值更新公式是不同的,如式 $\text(5.4)$ 所示: @@ -158,16 +158,16 @@ $\qquad$ 也就是说,$\text{Sarsa}$ 算法是直接用下一个状态和动
图 $\text{5.4}$ $\text{Sarsa}$ 算法伪代码
-## 同策略与异策略 +## 5.3 同策略与异策略 $\qquad$ 尽管 $\text{Q-learning}$ 算法和 $\text{Sarsa}$ 算法仅在一行更新公式上有所区别,但这两种算法代表的是截然不同的两类算法。我们注意到,$\text{Sarsa}$ 算法在训练的过程中当前策略来生成数据样本,并在其基础上进行更新。换句话说,策略评估和策略改进过程是基于相同的策略完成的,这就是**同策略算法**。相应地,像 $\text{Q-learning}$ 算法这样从其他策略中获取样本然后利用它们来更新目标策略,我们称作**异策略算法**。也就是说,异策略算法基本上是从经验池或者历史数据中进行学习的。这两类算法有着不同的优缺点,同策略相对来说更加稳定,但是效率较低,如同我们实战中展示的那样。而异策略通常来说更加高效,但是需要让获取样本的策略和更新的策略具备一定的分布匹配条件,以避免偏差。 -## 实战:Q-learning 算法 +## 5.4 实战:Q-learning 算法 $\qquad$ 本节开始我们的第一个算法实战,由于是第一个实战,所以会讲得偏详细一些,后面的算法实战部分可能会讲得越来越粗,如果读者们有不明白的地方,欢迎随时交流讨论。实战的思路会跟理论学习有所区别,并且因人而异,因此读者们在学习实战的时候做个参考即可,最重要的是有自己的想法。 $\qquad$ 此外,笔者认为**对于实战来说最重要的一点就是写好伪代码**。如果说理论部分是数学语言,实战部分就是编程语言,而伪代码则是从数学语言到编程语言之间的一个过渡,这也是笔者为什么在讲解每个算法的时候尽可能贴出伪代码的原因。在每个算法实战的内容中,笔者基本会按照定义算法,定义训练,定义环境,设置参数以及开始训练等步骤为读者们展开,这是笔者个人的编程习惯。由于这次我们是第一次讲到实战,所以会先讲一下定义训练,因为其中涉及到一个所有强化学习通用的训练模式。 -### 定义训练 +### 5.4.1 定义训练 $\qquad$ 回顾一下伪代码的第二行到最后一行,我们会发现一个强化学习训练的通用模式,首先我们会迭代很多个($M$)回合,在每回合中,首先重置环境回到初始化的状态,智能体根据状态选择动作,然后环境反馈中下一个状态和对应的奖励,同时智能体会更新策略,直到回合结束。这其实就是马尔可夫决策过程中智能体与环境互动的过程,写成一段通用的代码如下: @@ -190,11 +190,11 @@ for i_ep in range(train_eps): # 遍历每个回合 break ``` -### 定义算法 +### 5.4.2 定义算法 $\qquad$ 强化学习中有几个要素,智能体、环境、经验池(经回放),在实践中也需要逐一定义这些要素。我们一般首先定义智能体,或者说算法,在 $\text{Python}$ 中一般定义为类即可。再考虑一下智能体在强化学习中主要负责哪些工作。 -#### 采样动作 +#### 5.4.2.1 采样动作 $\qquad$ 首先在训练中我需要采样动作与环境交互,于是我们可以定义一个类方法,命名为 `sample_action` ,如下: @@ -216,7 +216,7 @@ class Agent: return action ``` -在这里我们用了 $\varepsilon-greedy$ 策略,其中 $\varepsilon$ 会随着采样的步数指数衰减,感兴趣的读者也可以直接设置固定的 $\varepsilon=0.1$ 试试。 +$\qquad$ 在这里我们用了 $\varepsilon-greedy$ 策略,其中 $\varepsilon$ 会随着采样的步数指数衰减,感兴趣的读者也可以直接设置固定的 $\varepsilon=0.1$ 试试。 在 $\text{Q-learning}$ 算法中还有一个重要的元素,即 $Q$ 表,$Q$ 表的作用是输入状态和动作,输出一个即可,这样一来我们可以用一个二维的数组来表示,比如 `Q_table[0][1] = 0.1`可以表示 $Q(s_0,a_1)=0.1$ (注意 $\text{Python}$ 中下标是从 $\text{0}$ 开始)。而在我们的示例代码中用了一个默认字典来表示,如下: ```python @@ -225,7 +225,7 @@ self.Q_table = defaultdict(lambda: np.zeros(n_actions)) 这样的好处是从数据结构上来说,默认字典是哈希表结构,二维数组是线性表结构,从哈希表拿出数据的速度会比线性表快。 -#### 预测动作 +#### 5.4.2.2 预测动作 $\qquad$ 此外对于每个智能体在训练中和在测试中采取动作的方式一般是不一样的,因为在训练中需要增加额外的探索策略,而在测试中只需要输出 $Q$ 值对应最大的动作即可,如下: @@ -240,7 +240,7 @@ class Agent: return action ``` -#### 更新方法 +#### 5.4.2.3 更新方法 $\qquad$ 所有强化学习算法的采样动作和预测动作方式几乎是比较固定的,对于每个智能体来说最核心的还是更新网络的方式,在 $\text{Q-learning}$ 算法中的更新方式较为简单,而且不需要经验回放(具体会在 $\text{DQN}$ 算法中展开),如下: @@ -256,7 +256,7 @@ def update(self, state, action, reward, next_state, terminated): 其中 `self.lr` 就是更新公式中的 $alpha$(学习率),到这里我们就定义好了智能体,完整的内容可参考附书代码。 -### 定义环境 +### 5.4.3 定义环境 $\qquad$ 在本节中我们选择了一个叫做 $\text{CliffWalking-v0}$ 的环境(中文名叫 “悬崖寻路” ),跟前面动态规划章节中举的机器人最短路径是类似的,只是要更加复杂一些。 @@ -296,7 +296,7 @@ print(f"状态数:{n_states}, 动作数:{n_actions}") 符合我们前面的分析结果。 -### 设置参数 +### 5.4.4 设置参数 智能体、环境和训练的代码都写好之后,就是设置参数了,由于 $\text{Q-learning}$ 算法的超参数(需要人工调整的参数)比较少,其中 $\gamma$ (折扣因子)比较固定,设置在 $0.9$ 到 $0.999$ 之间,一般设置成 $0.99$ 即可。而学习率 $alpha$ 在本章节中设置的比较大,为 $0.1$,实际更复杂的环境和算法中学习率是小于 $0.01$,因为太大很容易发生过拟和的问题,只是本节的环境和算法都比较简单,为了收敛得更快点所以设置得比较大。此外由于我们探索策略中的 $\varepsilon$ 是会随着采样步数衰减的,在实践过程中既不能让它衰减得太快也不能让它衰减得太慢,因此需要合理设置如下参数: @@ -306,7 +306,7 @@ self.epsilon_end = 0.01 # e-greedy策略中epsilon的最终值 self.epsilon_decay = 200 # e-greedy策略中epsilon的衰减率 ``` -### 开始训练 +### 5.4.5 开始训练 准备工作做好之后,就可以开始训练了,得到的训练曲线如图 $\text{5.6}$ 所示,曲线横坐标表示回合数($\text{episode}$),纵坐标表示每回合获得的总奖励,可以看出曲线其实从大约 $\text{50}$ 个回合的时候就开始收敛了,也就是我们的智能体学到了一个最优策略。 @@ -338,7 +338,7 @@ $\qquad$ 如图 $\text{5.7}$ 所示,我们测试了 $10$ 个回合,发现每
图 $\text{5.7}$ $\text{CliffWalking-v0}$ 环境 $\text{Q-learning}$ 算法测试曲线
-### 结果分析 +### 5.4.6 结果分析 $\qquad$ 那么问题来了,为什么学到的策略每回合的奖励是 $-13$ 呢?回顾一下我们在前面介绍环境的时候讲到,我们一眼就能看出来最优的策略应当是从起点向上沿着 $24$ 号网格直线走到 $35$ 号网格最后到达终点,而这中间要走多少个网格呢?读者们可以数一下,不包括终点(走到终点得到的奖励是 $0$)的话正好就是 $13$ 步,每一步会得到 $-1$ 的奖励,总共加起来正好也是 $-13$ ,这说明智能体学到的策略很有可能就是最优的。具体我们还需要把智能体在测试的时候每回合每步的动作打印出来验证一下,打印结果如下: @@ -349,7 +349,7 @@ $\qquad$ 那么问题来了,为什么学到的策略每回合的奖励是 $-13$ $\qquad$ 可以看到智能体学到的策略是先往上(即动作 $0$),然后一直往右(即动作 $1$)走十二格,最后再往下(即动作 $2$),这其实就是我们肉眼就能看出来的最优策略! -### 消融实验 +### 5.4.7 消融实验 $\qquad$ 为了进一步探究 $\varepsilon$ 是随着采样步数衰减更好些,还是恒定不变更好,我们做了一个消融( $\text{Ablation}$ )实验,即将 $\varepsilon$ 设置为恒定的 $0.1$,如下: @@ -395,11 +395,11 @@ $\qquad$ 测试曲线如图 $\text{5.11}$ 所示: $\qquad$ 我们发现相比于 $\text{Q-learning}$ 算法的 $300$ 回合收敛,$\text{Sarsa}$ 算法需要额外的 $100$ 个回合收敛,但是收敛之后会更稳定,没有一些波动过大的值。 -## 本章小结 +## 5.5 本章小结 $\qquad$ 本章主要介绍了两种经典的传统强化学习算法,即 $\text{Q-learning}$ 和 $\text{Sarsa}$ 算法。同时,这两种算法虽然非常近似,但本质上是两类不同的蒜贩,前者为 $\text{off-policy}$ 算法,后者为 $\text{on-policy}$ 算法。虽然这两种算法在目前强化学习实践中几乎不怎么用到,但却是后面 $\text{DQN}$ 算法的基础,读者需要熟练掌握。 -## 练习题 +## 5.6 练习题 1. 什么是 $Q$ 值的过估计?有什么缓解的方法吗? 2. $\text{on-policy}$ 与 $\text{off-policy}$ 之间的区别是什么?