Q-learning

1,058 阅读12分钟
原文链接: blog.csdn.net
版权声明:转载请注明 https://blog.csdn.net/weixin_41923961/article/details/87885640

本文将讲述经典的强化学习三部曲:Q-learning、DQN以及Double-DQN

Q-learning

故事案例:骑士和公主

假设你是一名骑士,并且你需要拯救上面的地图里被困在城堡中的公主。

你每次可以移动一个方块的距离。敌人是不能移动的,但是如果你和敌人落在了同一个方块中,你就会死。你的目标是以尽可能快的路线走到城堡去。这可以使用一个「按步积分」系统来评估。

你在每一步都会失去 1 分(每一步失去的分数帮助智能体训练的更快)如果碰到了一个敌人,你会失去 100 分,并且训练 episode 结束。如果进入到城堡中,你就获胜了,获得 100 分。

那么问题来了:如何才能够创建这样的智能体呢?

下面我将介绍第一个策略。假设智能体试图走遍每一个方块,并且将其着色。绿色代表「安全」,红色代表「不安全」。

同样的地图,但是被着色了,用于显示哪些方块是可以被安全访问的。

接着,我们告诉智能体只能选择绿色的方块。

但问题是,这种策略并不是十分有用。当绿色的方块彼此相邻时,我们不知道选择哪个方块是最好的。所以,智能体可能会在寻找城堡的过程中陷入无限的循环。

Q-Table 简介

下面我将介绍第二种策略:创建一个表格。通过它,我们可以为每一个状态(state)上进行的每一个动作(action)计算出最大的未来奖励(reward)的期望。

得益于这个表格,我们可以知道为每一个状态采取的最佳动作。

每个状态(方块)允许四种可能的操作:左移、右移、上移、下移。

「0」代表不可能的移动(如果你在左上角,你不可能向左移动或者向上移动!)

在计算过程中,我们可以将这个网格转换成一个表。

这种表格被称为 Q-table(「Q」代表动作的「质量」)。每一列将代表四个操作(左、右、上、下),行代表状态。每个单元格的值代表给定状态和相应动作的最大未来奖励期望。

每个 Q-table 的分数将代表在给定最佳策略的状态下采取相应动作获得的最大未来奖励期望。

为什么我们说「给定的策略」呢?这是因为我们并不实现这些策略。相反,我们只需要改进 Q-table 就可以一直选择最佳的动作。

将这个 Q-table 想象成一个「备忘纸条」游戏。得益于此,我们通过寻找每一行中最高的分数,可以知道对于每一个状态(Q-table 中的每一行)来说,可采取的最佳动作是什么。

太棒了!我解决了这个城堡问题!但是,请等一下... 我们如何计算 Q-table 中每个元素的值呢?

为了学习到 Q-table 中的每个值,我们将使用 Q-learning 算法。

Q-learning 算法:学习动作值函数(action value function)

动作值函数(或称「Q 函数」)有两个输入:「状态」和「动作」。它将返回在该状态下执行该动作的未来奖励期望。

我们可以把 Q 函数视为一个在 Q-table 上滚动的读取器,用于寻找与当前状态关联的行以及与动作关联的列。它会从相匹配的单元格中返回 Q 值。这就是未来奖励的期望。

在我们探索环境(environment)之前,Q-table 会给出相同的任意的设定值(大多数情况下是 0)。随着对环境的持续探索,这个 Q-table 会通过迭代地使用 Bellman 方程(动态规划方程)更新 Q(s,a) 来给出越来越好的近似。

Q-learning 算法流程

Q-learning 算法的伪代码

步骤 1:初始化 Q 值。我们构造了一个 m 列(m = 动作数 ),n 行(n = 状态数)的 Q-table,并将其中的值初始化为 0。

步骤 2:在整个生命周期中(或者直到训练被中止前),步骤 3 到步骤 5 会一直被重复,直到达到了最大的训练次数(由用户指定)或者手动中止训练。

步骤 3:选取一个动作。在基于当前的 Q 值估计得出的状态 s 下选择一个动作 a。

但是……如果每个 Q 值都等于零,我们一开始该选择什么动作呢?在这里,我们就可以看到探索/利用(exploration/exploitation)的权衡有多重要了。

思路就是,在一开始,我们将使用 epsilon 贪婪策略:

我们指定一个探索速率「epsilon」,一开始将它设定为 1。这个就是我们将随机采用的步长。在一开始,这个速率应该处于最大值,因为我们不知道 Q-table 中任何的值。这意味着,我们需要通过随机选择动作进行大量的探索。生成一个随机数。如果这个数大于 epsilon,那么我们将会进行「利用」(这意味着我们在每一步利用已经知道的信息选择动作)。否则,我们将继续进行探索。在刚开始训练 Q 函数时,我们必须有一个大的 epsilon。随着智能体对估算出的 Q 值更有把握,我们将逐渐减小 epsilon。

步骤 4-5:评价!采用动作 a 并且观察输出的状态 s' 和奖励 r。现在我们更新函数 Q(s,a)。

我们采用在步骤 3 中选择的动作 a,然后执行这个动作会返回一个新的状态 s' 和奖励 r。

接着我们使用 Bellman 方程去更新 Q(s,a):

如下方代码所示,更新 Q(state,action):

 

 

New Q value = Current Q value + lr * [Reward + discount_rate * (highest Q value between possible actions from the new state s’ ) — Current Q value ]

让我们举个例子:

一块奶酪 = +1两块奶酪 = +2一大堆奶酪 = +10(训练结束)吃到了鼠药 = -10(训练结束)

步骤 1:初始化 Q-table

初始化之后的 Q-table

步骤 2:选择一个动作。从起始点,你可以在向右走和向下走其中选择一个。由于有一个大的 epsilon 速率(因为我们至今对于环境一无所知),我们随机地选择一个。例如向右走。

我们随机移动(例如向右走)

我们发现了一块奶酪(+1),现在我们可以更新开始时的 Q 值并且向右走,通过 Bellman 方程实现。

步骤 4-5:更新 Q 函数

首先,我们计算 Q 值的改变量 ΔQ(start, right)。接着我们将初始的 Q 值与 ΔQ(start, right) 和学习率的积相加。

可以将学习率看作是网络有多快地抛弃旧值、生成新值的度量。如果学习率是 1,新的估计值会成为新的 Q 值,并完全抛弃旧值。

更新后的 Q-table

太好了!我们刚刚更新了第一个 Q 值。现在我们要做的就是一次又一次地做这个工作直到学习结束。

实现 Q-learning 算法

既然我们知道了它是如何工作的,我们将一步步地实现 Q-learning 算法。代码的每一部分都在下面的 Jupyter notebook 中直接被解释了。

项目地址:https://github.com/simoninithomas/Deep_reinforcement_learning_Course/blob/master/Q%20learning/Q%20Learning%20with%20FrozenLake.ipynb

回顾

Q-learning 是一个基于值的强化学习算法,利用 Q 函数寻找最优的「动作—选择」策略。它根据动作值函数评估应该选择哪个动作,这个函数决定了处于某一个特定状态以及在该状态下采取特定动作的奖励期望值。目的:最大化 Q 函数的值(给定一个状态和动作时的未来奖励期望)。Q-table 帮助我们找到对于每个状态来说的最佳动作。通过选择所有可能的动作中最佳的一个来最大化期望奖励。Q 作为某一特定状态下采取某一特定动作的质量的度量。函数 Q(state,action)→返回在当前状态下采取该动作的未来奖励期望。这个函数可以通过 Q-learning 算法来估计,使用 Bellman 方程迭代地更新 Q(s,a)在我们探索环境之前:Q-table 给出相同的任意的设定值→ 但是随着对环境的持续探索→Q 给出越来越好的近似。

就是这些了!不要忘记自己去实现代码的每一部分——试着修改已有的代码是十分重要的。

试着增加迭代次数,改变学习率,并且使用一个更复杂的环境(例如:8*8 方格的 Frozen-lake)。祝你玩的开心!

原文链接:https://medium.freecodecamp.org/diving-deeper-into-reinforcement-learning-with-q-learning-c18d0db58efe

维度灾难

在上面的分析中,我们使用表格来表示Q(s,a),但是这个在现实的很多问题上是几乎不可行的,因为状态实在是太多。使用表格的方式根本存不下。

怎么办呢?就是用一个函数来表示Q(s,a)。即

Q(s,a) = f(s,a)

f 可以是任意类型的函数,比如线性函数:

Q(s,a) = w_1s + w_2a + b 其中w_1,w_2,b是函数f的参数。

通过函数表示,我们就可以无所谓s到底是多大的维度,反正最后都通过矩阵运算降维输出为单值的Q。

如果我们就用w来统一表示函数f的参数,那么就有

Q(s,a) = f(s,a,w)

高维输入低维输出表示

对应一个高维状态输入,一个低维动作输出。那么怎么来表示这个函数f呢?

其实就是Q(s) \approx f(s,w),只把状态s作为输入,但是输出的时候输出每一个动作的Q值,也就是输出一个向量[Q(s,a_1),Q(s,a_2),Q(s,a_3),...,Q(s,a_n)],记住这里输出是一个值,只不过是包含了所有动作的Q值的向量而已。这样我们就只要输入状态s,而且还同时可以得到所有的动作Q值,也将更方便的进行Q-Learning中动作的选择与Q值更新。

神经网络化Q值

我们用一个深度神经网络来表示这个函数f。

以DQN为例,输入是经过处理的4个连续的84x84图像,然后经过两个卷积层,两个全连接层,最后输出包含每一个动作Q值的向量。

对于这个网络的结构,针对不同的问题可以有不同的设置。

总之,用神经网络来表示Q值非常简单,Q值也就是变成用Q网络(Q-Network)来表示。接下来就到了很多人都会困惑的问题,那就是

Q网络的loss

神经网络的训练是最优化一个损失函数loss function。因此,我们需要有样本,然后通过反向传播使用梯度下降的方法来更新神经网络的参数。

所以,我们利用Q-Learning算法为Q网络提供有标签的样本。

Q-Learning算法中,Q值的更新依靠的是利用Reward和Q计算出来的目标Q值:

R_{t+1}+\lambda \max _aQ(S_{t+1},a)

因此,我们把目标Q值作为标签,Q网络训练的损失函数就是:

上面公式是s^`,a^` 即下一个状态和动作。这里用了David Silver的表示方式,看起来比较清晰。

DQN训练

我们这里分析第一个版本的DQN,也就是NIPS 2013提出的DQN。 

è¿éåå¾çæè¿°

图1:DQN网络结构图 这个网络的输入是 4 个 84×84 的灰度游戏屏幕。这个网络的输出是是每一个可能动作的 Q 值(Atari 中有 18 个动作)。 

è¿éåå¾çæè¿°

图2:NIPS 2013 DQN算法 1、初始化replay memory D 容量为N

2、用一个深度神经网络作为Q值网络,初始化权重参数

3、设定游戏片段总数M

4、初始化网络输入,大小为84*84*4,并且计算网络输出

5、以概率ϵϵ随机选择动作atat或者通过网络输出的Q(max)值选择动作atat 6、得到执行atat后的奖励rtrt和下一个网络的输入

7、根据当前的值计算下一时刻网络的输出

8、将四个参数作为此刻的状态一起存入到D中(D中存放着N个时刻的状态)

9、随机从D中取出minibatch个状态

10、计算每一个状态的目标值(通过执行atat后的reward来更新Q值作为目标值)

11、通过SGD更新weight

我们这里分析第二个版本的DQN,也就是NIPS 2015提出的DQN。 

è¿éåå¾çæè¿°

图3:NIPS 2015 DQN算法 1、初始化replay memory D,容量是N 用于存储训练的样本

2、初始化action-value function的Q卷积神经网络 ,随机初始化权重参数θ

3、初始化 target action-value function的Q̂ Q^卷积神经网络,结构以及初始化权重θ和Q相同

4、设定游戏片段总数M

5、初始化网络输入,大小为84*84*4,并且计算网络输出

6、根据概率ϵϵ(很小)选择一个随机的动作或者根据当前的状态输入到当前的网络中 (用了一次CNN)计算出每个动作的Q值,选择Q值最大的一个动作(最优动作)

7、得到执行atat后的奖励rtrt和下一个网络的输入

8、将四个参数作为此刻的状态一起存入到D中(D中存放着N个时刻的状态)

9、随机从D中取出minibatch个状态

10、计算每一个状态的目标值(通过执行atat后的reward来更新Q值作为目标值)

11、通过SGD更新weight

12、每C次迭代后更新target action-value function网络的参数为当前action-value function的参数

Double DQN


论文:Deep Reinforcement Learning with Double Q-learning 
Double Q-learning的想法就是将选择和评估action的网络分开,这样可以减轻over estimate.Double DQN将Double Q-learning和DQN结合起来。

Double Q-learning

在double Q-learning中有两个value function,参数分别为θ、θ',每一次更新时,其中一组参数用于决定policy,另外一组参数用于计算value. 

在选择policy时,利用的是最近更新的θt,计算value时则用θ′t


Double DQN


将Double Q-learning和DQN结合起来


其中,θt是实时更新的,θt−每隔C step就copy θt.