update ch4

This commit is contained in:
qiwang067
2023-03-15 21:36:30 +08:00
parent 2eb72354eb
commit 5f2cef6aee

View File

@@ -6,14 +6,14 @@
<img width="550" src="../img/ch4/4.1.png"/> <img width="550" src="../img/ch4/4.1.png"/>
</div> </div>
<div align=center>图 4.1 强化学习的组成部分</div> <div align=center>图 4.1 强化学习的组成部分</div>
策略一般记作 $\pi$。假设我们使用深度学习来做强化学习,策略就是一个网络。网络里面有一些参数,我们用 $\theta$ 来代表 $\pi$ 的参数。网络的输入是智能体看到的东西,如果让智能体玩视频游戏,智能体看到的东西就是游戏的画面。智能体看到的东西会影响我们训练的效果。例如,在玩游戏的时候, 也许我们觉得游戏的画面是前后相关的所以应该让策略去看从游戏开始到当前这个时间点之间所有画面的总和。因此我们可能会觉得要用到循环神经网络recurrent neural networkRNN来处理它不过这样会比较难处理。我们可以用向量或矩阵来表示智能体的观测并将观测输入策略网络策略网络就会输出智能体要采取的动作。图 4.2 就是具体的例子,策略是一个网络;输入是游戏的画面,它通常是由像素组成的;输出是我们可以执行的动作,有几个动作,输出层就有几个神经元。假设我们现在可以执行的动作有 3 个,输出层就有 3 个神经元,每个神经元对应一个可以采取的动作。输入一个东西后,网络会给每一个可以采取的动作一个分数。我们可以把这个分数当作概率,演员根据概率的分布来决定它要采取的动作,比如 0.7 的概率向左走、0.2 的概率向右走、0.1的概率开火等。概率分布不同,演员采取的动作就会不一样。 策略一般记作 $\pi$。假设我们使用深度学习来做强化学习,策略就是一个网络。网络里面有一些参数,我们用 $\theta$ 来代表 $\pi$ 的参数。网络的输入是智能体看到的东西,如果让智能体玩视频游戏,智能体看到的东西就是游戏的画面。智能体看到的东西会影响我们训练的效果。例如,在玩游戏的时候, 也许我们觉得游戏的画面是前后相关的所以应该让策略去看从游戏开始到当前这个时间点之间所有画面的总和。因此我们可能会觉得要用到循环神经网络recurrent neural networkRNN来处理它不过这样会比较难处理。我们可以用向量或矩阵来表示智能体的观测并将观测输入策略网络策略网络就会输出智能体要采取的动作。图 4.2 就是具体的例子,策略是一个网络;输入是游戏的画面,它通常是由像素组成的;输出是我们可以执行的动作,有几个动作,输出层就有几个神经元。假设我们现在可以执行的动作有 3 个,输出层就有 3 个神经元,每个神经元对应一个可以采取的动作。输入一个东西后,网络会给每一个可以采取的动作一个分数。我们可以把这个分数当作概率,演员根据概率的分布来决定它要采取的动作,比如 0.7 的概率向左走、0.2 的概率向右走、0.1的概率开火等。概率分布不同,演员采取的动作就会不一样。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.2.png"/> <img width="550" src="../img/ch4/4.2.png"/>
</div> </div>
<div align=center>图 4.2 演员的策略</div> <div align=center>图 4.2 演员的策略</div>
接下来我们用一个例子来说明演员与环境交互的过程。如图 4.3 所示,首先演员会看到一个视频游戏的初始画面,接下来它会根据内部的网络(内部的策略)来决定一个动作。假设演员现在决定的动作是向右,决定完动作以后,它就会得到一个奖励,奖励代表它采取这个动作以后得到的分数。 接下来我们用一个例子来说明演员与环境交互的过程。如图 4.3 所示,首先演员会看到一个视频游戏的初始画面,接下来它会根据内部的网络(内部的策略)来决定一个动作。假设演员现在决定的动作是向右,决定完动作以后,它就会得到一个奖励,奖励代表它采取这个动作以后得到的分数。
@@ -37,7 +37,7 @@
<img width="550" src="../img/ch4/4.5.png"/> <img width="550" src="../img/ch4/4.5.png"/>
</div> </div>
<div align=center>图 4.5 演员和环境</div> <div align=center>图 4.5 演员和环境</div>
在一场游戏里面,我们把环境输出的 $s$ 与演员输出的动作 $a$ 全部组合起来,就是一个轨迹,即 在一场游戏里面,我们把环境输出的 $s$ 与演员输出的动作 $a$ 全部组合起来,就是一个轨迹,即
$$ $$
\tau=\left\{s_{1}, a_{1}, s_{2}, a_{2}, \cdots, s_{t}, a_{t}\right\} \tau=\left\{s_{1}, a_{1}, s_{2}, a_{2}, \cdots, s_{t}, a_{t}\right\}
@@ -64,12 +64,12 @@ $$
$$ $$
我们要穷举所有可能的轨迹 $\tau$ 每一个轨迹 $\tau$ 都有一个概率。 我们要穷举所有可能的轨迹 $\tau$ 每一个轨迹 $\tau$ 都有一个概率。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.6.png"/> <img width="550" src="../img/ch4/4.6.png"/>
</div> </div>
<div align=center>图 4.6 期望的奖励</div> <div align=center>图 4.6 期望的奖励</div>
比如 $\theta$ 对应的模型很强,如果有一个回合 $\theta$ 很快就死掉了,因为这种情况很少会发生,所以该回合对应的轨迹 $\tau$ 的概率就很小;如果有一个回合 $\theta$ 一直没死,因为这种情况很可能发生,所以该回合对应的轨迹 $\tau$ 的概率就很大。我们可以根据 $\theta$ 算出某一个轨迹 $\tau$ 出现的概率,接下来计算 $\tau$ 的总奖励。总奖励使用 $\tau$ 出现的概率进行加权,对所有的 $\tau$ 进行求和,就是期望值。给定一个参数,我们可以计算期望值为 比如 $\theta$ 对应的模型很强,如果有一个回合 $\theta$ 很快就死掉了,因为这种情况很少会发生,所以该回合对应的轨迹 $\tau$ 的概率就很小;如果有一个回合 $\theta$ 一直没死,因为这种情况很可能发生,所以该回合对应的轨迹 $\tau$ 的概率就很大。我们可以根据 $\theta$ 算出某一个轨迹 $\tau$ 出现的概率,接下来计算 $\tau$ 的总奖励。总奖励使用 $\tau$ 出现的概率进行加权,对所有的 $\tau$ 进行求和,就是期望值。给定一个参数,我们可以计算期望值为
@@ -96,6 +96,8 @@ $$
\frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)}= \nabla \log p_{\theta}(\tau) \frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)}= \nabla \log p_{\theta}(\tau)
$$ $$
注:对数函数 $f(x)=\log x$ 的导数为 $\frac{1}{x}$。
如式(4.2)所示,我们对 $\tau$ 进行求和,把 $R(\tau)$ 和 $\log p_{\theta}(\tau)$ 这两项使用 $p_{\theta}(\tau)$ 进行加权, 既然使用 $p_{\theta}(\tau)$ 进行加权 ,它们就可以被写成期望的形式。也就是我们从 $p_{\theta}(\tau)$ 这个分布里面采样 $\tau$ 去计算 $R(\tau)$ 乘 $\nabla\log p_{\theta}(\tau)$,对所有可能的 $\tau$ 进行求和就是期望的值expected value 如式(4.2)所示,我们对 $\tau$ 进行求和,把 $R(\tau)$ 和 $\log p_{\theta}(\tau)$ 这两项使用 $p_{\theta}(\tau)$ 进行加权, 既然使用 $p_{\theta}(\tau)$ 进行加权 ,它们就可以被写成期望的形式。也就是我们从 $p_{\theta}(\tau)$ 这个分布里面采样 $\tau$ 去计算 $R(\tau)$ 乘 $\nabla\log p_{\theta}(\tau)$,对所有可能的 $\tau$ 进行求和就是期望的值expected value
$$ $$
\begin{aligned} \begin{aligned}
@@ -150,7 +152,7 @@ $$
<img width="550" src="../img/ch4/4.8.png"/> <img width="550" src="../img/ch4/4.8.png"/>
</div> </div>
<div align=center>图 4.7 策略梯度</div> <div align=center>图 4.7 策略梯度</div>
更新完模型以后,我们要重新采样数据再更新模型。注意,一般**策略梯度policy gradientPG**采样的数据只会用一次。我们采样这些数据,然后用这些数据更新参数,再丢掉这些数据。接着重新采样数据,才能去更新参数。 更新完模型以后,我们要重新采样数据再更新模型。注意,一般**策略梯度policy gradientPG**采样的数据只会用一次。我们采样这些数据,然后用这些数据更新参数,再丢掉这些数据。接着重新采样数据,才能去更新参数。
@@ -163,7 +165,7 @@ $$
<img width="550" src="../img/ch4/4.9.png"/> <img width="550" src="../img/ch4/4.9.png"/>
</div> </div>
<div align=center>图 4.8 策略梯度实现细节</div> <div align=center>图 4.8 策略梯度实现细节</div>
我们在解决分类问题的时候目标函数就是最大化或最小化的对象因为我们现在是最大化似然likelihood所以其实是最大化我们要最大化 我们在解决分类问题的时候目标函数就是最大化或最小化的对象因为我们现在是最大化似然likelihood所以其实是最大化我们要最大化
$$ $$
\frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right)
@@ -191,12 +193,12 @@ $$
如图 4.10 所示,假设我们在某一个状态有 3 个动作 a、b、c可以执行。根据式(4.6),我们要把这 3 个动作的概率,对数概率都提高。 但是它们前面的权重$R(\tau)$是不一样的。权重是有大有小的,权重小的,该动作的概率提高的就少;权重大的,该动作的概率提高的就多。 因为对数概率是一个概率,所以动作 a、b、c 的对数概率的和是 0。 所以提高少的在做完归一化normalize以后动作 b 的概率就是下降的;提高多的,该动作的概率才会上升。 如图 4.10 所示,假设我们在某一个状态有 3 个动作 a、b、c可以执行。根据式(4.6),我们要把这 3 个动作的概率,对数概率都提高。 但是它们前面的权重$R(\tau)$是不一样的。权重是有大有小的,权重小的,该动作的概率提高的就少;权重大的,该动作的概率提高的就多。 因为对数概率是一个概率,所以动作 a、b、c 的对数概率的和是 0。 所以提高少的在做完归一化normalize以后动作 b 的概率就是下降的;提高多的,该动作的概率才会上升。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.12.png"/> <img width="550" src="../img/ch4/4.12.png"/>
</div> </div>
<div align=center>图 4.10 动作的概率的例子</div> <div align=center>图 4.10 动作的概率的例子</div>
$$ $$
@@ -205,12 +207,12 @@ $$
这是一个理想的情况但是实际上我们是在做采样本来这边应该是一个期望expectation对所有可能的$s$与$a$的对进行求和。 但我们真正在学习的时候,只是采样了少量的$s$与$a$的对。 因为我们做的是采样,所以有一些动作可能从来都没有被采样到。如图 4.11 所示,在某一个状态,虽然可以执行的动作有 a、b、c但我们可能只采样到动作 b 或者 只采样到动作 c没有采样到动作 a。但现在所有动作的奖励都是正的所以根据式(4.6)在这个状态采取a、b、c的概率都应该要提高。我们会遇到的问题是因为 a 没有被采样到所以其他动作的概率如果都要提高a 的概率就要下降。 所以a不一定是一个不好的动作 它只是没有被采样到。但因为 a 没有被采样到,它的概率就会下降,这显然是有问题的。要怎么解决这个问题呢?我们会希望奖励不总是正的。 这是一个理想的情况但是实际上我们是在做采样本来这边应该是一个期望expectation对所有可能的$s$与$a$的对进行求和。 但我们真正在学习的时候,只是采样了少量的$s$与$a$的对。 因为我们做的是采样,所以有一些动作可能从来都没有被采样到。如图 4.11 所示,在某一个状态,虽然可以执行的动作有 a、b、c但我们可能只采样到动作 b 或者 只采样到动作 c没有采样到动作 a。但现在所有动作的奖励都是正的所以根据式(4.6)在这个状态采取a、b、c的概率都应该要提高。我们会遇到的问题是因为 a 没有被采样到所以其他动作的概率如果都要提高a 的概率就要下降。 所以a不一定是一个不好的动作 它只是没有被采样到。但因为 a 没有被采样到,它的概率就会下降,这显然是有问题的。要怎么解决这个问题呢?我们会希望奖励不总是正的。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.13.png"/> <img width="550" src="../img/ch4/4.13.png"/>
</div> </div>
<div align=center>图 4.11 采样动作的问题</div> <div align=center>图 4.11 采样动作的问题</div>
为了解决奖励总是正的的问题,我们可以把奖励减 $b$,即 为了解决奖励总是正的的问题,我们可以把奖励减 $b$,即
@@ -240,7 +242,7 @@ $$
<img width="550" src="../img/ch4/4.15.png"/> <img width="550" src="../img/ch4/4.15.png"/>
</div> </div>
<div align=center>图 4.12 分配合适的分数</div> <div align=center>图 4.12 分配合适的分数</div>
分配合适的分数这一技巧可以表达为 分配合适的分数这一技巧可以表达为
$$ $$
@@ -265,12 +267,12 @@ $$
相比蒙特卡洛方法一个回合更新一次时序差分方法是每个步骤更新一次即每走一步更新一次时序差分方法的更新频率更高。时序差分方法使用Q函数来近似地表示未来总奖励 $G_t$。 相比蒙特卡洛方法一个回合更新一次时序差分方法是每个步骤更新一次即每走一步更新一次时序差分方法的更新频率更高。时序差分方法使用Q函数来近似地表示未来总奖励 $G_t$。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.20.png"/> <img width="550" src="../img/ch4/4.20.png"/>
</div> </div>
<div align=center>图 4.13 蒙特卡洛方法与时序差分方法</div> <div align=center>图 4.13 蒙特卡洛方法与时序差分方法</div>
我们介绍一下策略梯度中最简单的也是最经典的一个算法**REINFORCE**。REINFORCE 用的是回合更新的方式,它在代码上的处理上是先获取每个步骤的奖励,然后计算每个步骤的未来总奖励 $G_t$,将每个 $G_t$ 代入 我们介绍一下策略梯度中最简单的也是最经典的一个算法**REINFORCE**。REINFORCE 用的是回合更新的方式,它在代码上的处理上是先获取每个步骤的奖励,然后计算每个步骤的未来总奖励 $G_t$,将每个 $G_t$ 代入
@@ -294,12 +296,12 @@ $$
$$ $$
然后针对每个动作计算梯度 $\nabla \log \pi(a_t|s_t,\theta)$ 。在代码上计算时我们要获取神经网络的输出。神经网络会输出每个动作对应的概率值比如0.2、0.5、0.3),然后我们还可以获取实际的动作$a_t$把动作转成独热one-hot向量比如[0,1,0])与 $\log [0.2,0.5,0.3]$ 相乘就可以得到 $\log \pi(a_t|s_t,\theta)$ 。 然后针对每个动作计算梯度 $\nabla \log \pi(a_t|s_t,\theta)$ 。在代码上计算时我们要获取神经网络的输出。神经网络会输出每个动作对应的概率值比如0.2、0.5、0.3),然后我们还可以获取实际的动作$a_t$把动作转成独热one-hot向量比如[0,1,0])与 $\log [0.2,0.5,0.3]$ 相乘就可以得到 $\log \pi(a_t|s_t,\theta)$ 。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.22.png"/> <img width="550" src="../img/ch4/4.22.png"/>
</div> </div>
<div align=center>图 4.14 REINFORCE算法</div> <div align=center>图 4.14 REINFORCE算法</div>
>独热编码one-hot encoding通常用于处理类别间不具有大小关系的特征。 例如血型一共有4个取值A型、B型、AB型、O型独热编码会把血型变成一个4维稀疏向量A型血表示为1,0,0,0B型血表示为0,1,0,0AB型血表示为0,0,1,0O型血表示为0,0,0,1 >独热编码one-hot encoding通常用于处理类别间不具有大小关系的特征。 例如血型一共有4个取值A型、B型、AB型、O型独热编码会把血型变成一个4维稀疏向量A型血表示为1,0,0,0B型血表示为0,1,0,0AB型血表示为0,0,1,0O型血表示为0,0,0,1
@@ -308,12 +310,12 @@ $$
如图 4.15 所示,手写数字识别是一个经典的多分类问题,输入是一张手写数字的图片,经过神经网络处理后,输出的是各个类别的概率。我们希望输出的概率分布尽可能地贴近真实值的概率分布。因为真实值只有一个数字 9所以如果我们用独热向量的形式给它编码也可以把真实值理解为一个概率分布9 的概率就是1其他数字的概率就是 0。神经网络的输出一开始可能会比较平均通过不断地迭代、训练优化之后我们会希望输出9 的概率可以远高于输出其他数字的概率。 如图 4.15 所示,手写数字识别是一个经典的多分类问题,输入是一张手写数字的图片,经过神经网络处理后,输出的是各个类别的概率。我们希望输出的概率分布尽可能地贴近真实值的概率分布。因为真实值只有一个数字 9所以如果我们用独热向量的形式给它编码也可以把真实值理解为一个概率分布9 的概率就是1其他数字的概率就是 0。神经网络的输出一开始可能会比较平均通过不断地迭代、训练优化之后我们会希望输出9 的概率可以远高于输出其他数字的概率。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.23.png"/> <img width="550" src="../img/ch4/4.23.png"/>
</div> </div>
<div align=center>图 4.15 监督学习例子:手写数字识别</div> <div align=center>图 4.15 监督学习例子:手写数字识别</div>
如图 4.16 所示,我们所要做的就是提高输出 9 的概率,降低输出其他数字的概率,让神经网络输出的概率分布能够更贴近真实值的概率分布。我们可以用交叉熵来表示两个概率分布之间的差距。 如图 4.16 所示,我们所要做的就是提高输出 9 的概率,降低输出其他数字的概率,让神经网络输出的概率分布能够更贴近真实值的概率分布。我们可以用交叉熵来表示两个概率分布之间的差距。
@@ -322,44 +324,44 @@ $$
<img width="550" src="../img/ch4/4.24.png"/> <img width="550" src="../img/ch4/4.24.png"/>
</div> </div>
<div align=center>图 4.16 提高数字9的概率</div> <div align=center>图 4.16 提高数字9的概率</div>
我们看一下监督学习的优化流程,即怎么让输出逼近真实值。如图 4.17 所示,监督学习的优化流程就是将图片作为输入传给神经网络,神经网络会判断图片中的数字属于哪一类数字,输出所有数字可能的概率,再计算交叉熵,即神经网络的输出 $Y_i$ 和真实的标签值 $Y_i'$ 之间的距离 $-\sum Y_{i}^{\prime} \cdot \log \left(Y_{i}\right)$。我们希望尽可能地缩小这两个概率分布之间的差距,计算出的交叉熵可以作为损失函数传给神经网络里面的优化器进行优化,以自动进行神经网络的参数更新。 我们看一下监督学习的优化流程,即怎么让输出逼近真实值。如图 4.17 所示,监督学习的优化流程就是将图片作为输入传给神经网络,神经网络会判断图片中的数字属于哪一类数字,输出所有数字可能的概率,再计算交叉熵,即神经网络的输出 $Y_i$ 和真实的标签值 $Y_i'$ 之间的距离 $-\sum Y_{i}^{\prime} \cdot \log \left(Y_{i}\right)$。我们希望尽可能地缩小这两个概率分布之间的差距,计算出的交叉熵可以作为损失函数传给神经网络里面的优化器进行优化,以自动进行神经网络的参数更新。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.25.png"/> <img width="550" src="../img/ch4/4.25.png"/>
</div> </div>
<div align=center>图 4.17 优化流程</div> <div align=center>图 4.17 优化流程</div>
类似地,如图 4.18 所示,策略梯度预测每一个状态下应该要输出的动作的概率,即输入状态 $s_t$,输出动作$a_t$的概率,比如 0.02、0.08、0.9。实际上输出给环境的动作是随机选择一个动作比如我们选择向右这个动作它的独热向量就是0,0,1。我们把神经网络的输出和实际动作代入交叉熵的公式就可以求出输出动作的概率和实际动作的概率之间的差距。但实际的动作 $a_t$ 只是我们输出的真实的动作,它不一定是正确的动作,它不能像手写数字识别一样作为一个正确的标签来指导神经网络朝着正确的方向更新,所以我们需要乘一个奖励回报 $G_t$。$G_t$相当于对真实动作的评价。如果 $G_t$ 越大,未来总奖励越大,那就说明当前输出的真实的动作就越好,损失就越需要重视。如果 $G_t$ 越小,那就说明动作 $a_t$ 不是很好,损失的权重就要小一点儿,优化力度也要小一点儿。通过与手写数字识别的一个对比,我们就知道为什么策略梯度损失会构造成这样。 类似地,如图 4.18 所示,策略梯度预测每一个状态下应该要输出的动作的概率,即输入状态 $s_t$,输出动作$a_t$的概率,比如 0.02、0.08、0.9。实际上输出给环境的动作是随机选择一个动作比如我们选择向右这个动作它的独热向量就是0,0,1。我们把神经网络的输出和实际动作代入交叉熵的公式就可以求出输出动作的概率和实际动作的概率之间的差距。但实际的动作 $a_t$ 只是我们输出的真实的动作,它不一定是正确的动作,它不能像手写数字识别一样作为一个正确的标签来指导神经网络朝着正确的方向更新,所以我们需要乘一个奖励回报 $G_t$。$G_t$相当于对真实动作的评价。如果 $G_t$ 越大,未来总奖励越大,那就说明当前输出的真实的动作就越好,损失就越需要重视。如果 $G_t$ 越小,那就说明动作 $a_t$ 不是很好,损失的权重就要小一点儿,优化力度也要小一点儿。通过与手写数字识别的一个对比,我们就知道为什么策略梯度损失会构造成这样。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.26.png"/> <img width="550" src="../img/ch4/4.26.png"/>
</div> </div>
<div align=center>图 4.18 策略梯度损失</div> <div align=center>图 4.18 策略梯度损失</div>
如图 4.19 所示,实际上我们在计算策略梯度损失的时候,要先对实际执行的动作取独热向量,再获取神经网络预测的动作概率,将它们相乘,我们就可以得到 $\log \pi(a_t|s_t,\theta)$,这就是我们要构造的损失。因为我们可以获取整个回合的所有的轨迹,所以我们可以对这一条轨迹里面的每个动作都去计算一个损失。把所有的损失加起来,我们再将其“扔”给 Adam 的优化器去自动更新参数就好了。 如图 4.19 所示,实际上我们在计算策略梯度损失的时候,要先对实际执行的动作取独热向量,再获取神经网络预测的动作概率,将它们相乘,我们就可以得到 $\log \pi(a_t|s_t,\theta)$,这就是我们要构造的损失。因为我们可以获取整个回合的所有的轨迹,所以我们可以对这一条轨迹里面的每个动作都去计算一个损失。把所有的损失加起来,我们再将其“扔”给 Adam 的优化器去自动更新参数就好了。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.27.png"/> <img width="550" src="../img/ch4/4.27.png"/>
</div> </div>
<div align=center>图 4.19 损失计算</div> <div align=center>图 4.19 损失计算</div>
图 4.20 所示为REINFORCE 算法示意,首先我们需要一个策略模型来输出动作概率,输出动作概率后,通过 **sample()** 函数得到一个具体的动作,与环境交互后,我们可以得到整个回合的数据。得到回合数据之后,我们再去执行 **learn()** 函数,在 **learn()** 函数里面,我们就可以用这些数据去构造损失函数,“扔”给优化器优化,更新我们的策略模型。 图 4.20 所示为REINFORCE 算法示意,首先我们需要一个策略模型来输出动作概率,输出动作概率后,通过 **sample()** 函数得到一个具体的动作,与环境交互后,我们可以得到整个回合的数据。得到回合数据之后,我们再去执行 **learn()** 函数,在 **learn()** 函数里面,我们就可以用这些数据去构造损失函数,“扔”给优化器优化,更新我们的策略模型。
<div align=center> <div align=center>
<img width="550" src="../img/ch4/4.28.png"/> <img width="550" src="../img/ch4/4.28.png"/>
</div> </div>
<div align=center>图 4.20 REINFORCE算法示意</div> <div align=center>图 4.20 REINFORCE算法示意</div>
## 参考文献 ## 参考文献
* [Intro to Reinforcement Learning (强化学习纲要)](https://github.com/zhoubolei/introRL) * [Intro to Reinforcement Learning (强化学习纲要)](https://github.com/zhoubolei/introRL)
* [神经网络与深度学习](https://nndl.github.io/) * [神经网络与深度学习](https://nndl.github.io/)