JavaScript 深度学习(四)(3)

简介: JavaScript 深度学习(四)

JavaScript 深度学习(四)(2)https://developer.aliyun.com/article/1516979

第十一章:深度强化学习的基础知识

本章内容

  • 强化学习与前面几章讨论的监督学习有什么不同
  • 强化学习的基本范例:智能体、环境、行动和奖励以及它们之间的交互
  • 解决强化学习问题的两种主要方法背后的一般思想:基于策略和基于值的方法

到目前为止,在本书中,我们主要关注一种叫做监督学习的机器学习方法。在监督学习中,我们通过给出一个输入来训练模型给我们正确的答案。无论是给输入图像赋予一个类别标签(第四章)还是根据过去的天气数据预测未来温度(第八章和第九章),这种模式都是一样的:将静态输入映射到静态输出。在我们访问的第九章和第十章中生成序列的模型要稍微复杂一些,因为输出是一系列项而不是单个项。但是通过将序列拆分成步骤,这些问题仍然可以归结为一对一的输入输出映射。

在本章中,我们将介绍一种非常不同的机器学习类型,称为强化学习(RL)。在强化学习中,我们的主要关注点不是静态输出;相反,我们训练一个模型(或者在强化学习术语中称为智能体)在一个环境中采取行动,目的是最大化称为奖励的成功指标。例如,RL 可以用于训练一个机器人在建筑物内航行并收集垃圾。实际上,环境不一定是物理环境;它可以是任何一个智能体采取行动的真实或虚拟空间。国际象棋棋盘是训练智能体下棋的环境;股票市场是训练智能体交易股票的环境。强化学习范式的普遍性使其适用于广泛的实际问题(图 11.1)。另外,深度学习革命中一些最为引人瞩目的进展涉及将深度学习的能力与强化学习相结合。这包括可以以超人的技巧打败 Atari 游戏的机器人和可以在围棋和国际象棋游戏中击败世界冠军的算法^([1])。

¹

David Silver 等人,“通过自我对弈用通用强化学

图 11.1。强化学习的实际应用示例。左上:解决象棋和围棋等棋类游戏。右上:进行算法交易。左下:数据中心的自动资源管理。右下:机器人的控制和行动规划。所有图像均为免费许可证,并从www.pexels.com下载。

引人入胜的强化学习话题在一些基本方式上与我们在前几章中看到的监督学习问题有所不同。与监督学习中学习输入-输出映射不同,强化学习是通过与环境交互来发现最优决策过程。在强化学习中,我们没有给定标记的训练数据集;相反,我们被提供了不同类型的环境来探索。此外,时间是强化学习问题中不可或缺且基础性的维度,与许多监督学习问题不同,后者要么缺乏时间维度,要么将时间更多地视为空间维度。由于强化学习的独特特征,本章将涉及一种与前几章非常不同的词汇和思维方式。但不要担心。我们将使用简单而具体的例子来说明基本概念和方法。此外,我们的老朋友,深度神经网络及其在 TensorFlow.js 中的实现,将仍然与我们同在。它们将构成本章中我们将遇到的强化学习算法的重要支柱(尽管不是唯一的!)。

在本章结束时,您应该熟悉强化学习问题的基本公式化,理解强化学习中两种常用神经网络(策略网络和 Q 网络)背后的基本思想,并知道如何使用 TensorFlow.js 的 API 对这些网络进行训练。

11.1. 强化学习问题的制定

图 11.2 描绘了强化学习问题的主要组成部分。代理是我们(强化学习从业者)直接控制的对象。代理(例如在建筑物中收集垃圾的机器人)以三种方式与环境交互:

  • 在每一步中,代理程序采取一种 行动,这改变了环境的状态。例如,在我们的垃圾收集机器人的背景下,可供选择的行动集可能是{前进,后退,左转,右转,抓取垃圾,将垃圾倒入容器}
  • 偶尔,环境会向代理程序提供一个 奖励,在人性化的术语中,可以理解为即时愉悦或满足的衡量。但更抽象地说,奖励(或者,如我们稍后将看到的,一段时间内的奖励总和)是一个代理试图最大化的数字。它是一个重要的数值,以类似于损失值引导监督学习算法的方式引导强化学习算法。奖励可以是正的或负的。在我们的垃圾收集机器人的例子中,当一袋垃圾成功倒入机器人的垃圾容器时,可以给予正奖励。此外,当机器人撞倒垃圾桶,撞到人或家具,或者在容器外倒垃圾时,应给予负奖励。
  • 除了奖励外,代理还可以通过另一个渠道观察环境的状态,即观察。这可以是环境的完整状态,也可以只是代理可见的部分,可能通过某个不完美的渠道而失真。对于我们的垃圾收集机器人来说,观察包括来自其身体上的相机和各种传感器的图像和信号流。
图 11.2:强化学习问题的基本公式的示意图。在每个时间步,代理从可能的行动集合中选择一个行动,从而导致环境状态的变化。环境根据其当前状态和选择的行动向代理提供奖励。代理可以部分或完全观察到环境的状态,并将使用该状态来决定未来的行动。

刚定义的公式有些抽象。让我们看看一些具体的强化学习问题,并了解公式所涵盖的可能范围。在此过程中,我们还将浏览所有强化学习问题的分类。首先让我们考虑一下行动。代理可以选择的行动空间可以是离散的,也可以是连续的。例如,玩棋盘游戏的强化学习代理通常有离散的行动空间,因为在这种问题中,只有有限的移动选择。然而,一个涉及控制虚拟类人机器人的强化学习问题需要在双足行走时使用连续的行动空间,因为关节上的扭矩是连续变化的。在本章中,我们将介绍关于离散行动空间的示例问题。请注意,在某些强化学习问题中,可以通过离散化将连续的行动空间转化为离散的。例如,DeepMind 的《星际争霸 II》游戏代理将高分辨率的 2D 屏幕划分成较粗的矩形,以确定将单位移动到哪里或在哪里发起攻击。

²

查看 OpenAI Gym 中的 Humanoid 环境:gym.openai.com/envs/Humanoid-v2/

³

Oriol Vinyals 等,“星际争霸 II:强化学习的新挑战”,提交日期:2017 年 8 月 16 日,arxiv.org/abs/1708.04782

奖励在强化学习问题中起着核心作用,但也呈现出多样性。首先,有些强化学习问题仅涉及正奖励。例如,正如我们稍后将看到的,一个强化学习代理的目标是使一个杆保持在移动的推车上,则它只会获得正奖励。每次它保持杆竖立时,它都会获得少量正奖励。然而,许多强化学习问题涉及正负奖励的混合。负奖励可以被看作是“惩罚”或“处罚”。例如,一个学习向篮筐投篮的代理应该因进球而获得正奖励,而因投篮失误而获得负奖励。

奖励的发生频率也可能不同。一些强化学习问题涉及连续的奖励流。比如前文提到的倒立摆问题:只要杆子还没倒下,智能体每一个时间步长都会获得(正面的)奖励。而对于下棋的强化学习智能体,则只有在游戏结束(胜利、失败或平局)时才会获得奖励。两种极端之间还有其他强化学习问题。例如,我们的垃圾收集机器人在两次成功垃圾转移之间可能完全没有任何奖励——也就是在从 A 点到 B 点的移动过程中。此外,训练打 Atari 游戏 Pong 的强化学习智能体也不会在电子游戏的每一步(帧)都获得奖励;相反,在球拍成功击中乒乓球并将其反弹到对手处时,才会每隔几步(帧)获得正面的奖励。本章我们将介绍一些奖励频率高低不同的强化学习问题。

观察是强化学习问题中的另一个重要因素。它是一个窗口,通过它智能体可以看到环境的状态,并且基于这个状态做出决策,而不仅仅是依据任何奖励。像动作一样,观察可以是离散的(例如在棋盘游戏或者扑克游戏中),也可以是连续的(例如在物理环境中)。你可能会问:为什么我们的强化学习公式将观察和奖励分开,即使它们都可以被看作是环境向智能体提供反馈的形式?答案是为了概念上的清晰和简单易懂。尽管奖励可以被视为观察,但它是智能体最终“关心”的。而观察可以包含相关和无关的信息,智能体需要学会过滤并巧妙地使用。

一些强化学习问题通过观察向智能体揭示环境的整个状态,而另一些问题则仅向智能体提供部分状态信息。第一类问题的例子包括棋类游戏(如棋类和围棋)。对于后一类问题,德州扑克等纸牌游戏是一个很好的例子,在这种游戏中你无法看到对手的手牌,而股票交易也是其中的一个例子。股票价格受许多因素的影响,例如公司的内部运营和市场上其他股票交易者的想法。但是,智能体只能观察到股票价格的逐时历史记录,可能还加上公开的信息,如财经新闻。

这个讨论建立了强化学习发生的平台。关于这个表述值得指出的一个有趣的事情是,代理与环境之间的信息流是双向的:代理对环境进行操作;环境反过来提供给代理奖励和状态信息。这使得强化学习与监督学习有所不同,监督学习中信息流主要是单向的:输入包含足够的信息,使得算法能够预测输出,但输出并不会以任何重要的方式影响输入。

强化学习问题的另一个有趣而独特的事实是,它们必须沿着时间维度发生,以便代理-环境交互由多个轮次或步骤组成。时间可以是离散的或连续的。例如,解决棋盘游戏的 RL 代理通常在离散的时间轴上操作,因为这类游戏是在离散的回合中进行的。视频游戏也是如此。然而,控制物理机器人手臂操纵物体的 RL 代理面临着连续的时间轴,即使它仍然可以选择在离散的时间点采取行动。在本章中,我们将专注于离散时间 RL 问题。

这个关于强化学习的理论讨论暂时就够了。在下一节中,我们将开始亲手探索一些实际的强化学习问题和算法。

11.2. 策略网络和策略梯度:车杆示例

我们将解决的第一个强化学习问题是模拟一个物理系统,在该系统中,一个装有杆的小车在一维轨道上移动。这个问题被恰如其名地称为车杆问题,它是由安德鲁·巴托(Andrew Barto)、理查德·萨顿(Richard Sutton)和查尔斯·安德森(Charles Anderson)在 1983 年首次提出的。自那时以来,它已经成为控制系统工程的基准问题(在某种程度上类似于 MNIST 数字识别问题用于监督学习),因为它的简单性和良好构建的物理学和数学,以及解决它并非完全微不足道。在这个问题中,代理的目标是通过施加左右方向的力来控制小车的运动,以尽可能长时间地保持杆的平衡。

安德鲁·G·巴托(Andrew G. Barto)、理查德·S·萨顿(Richard S. Sutton)和查尔斯·W·安德森(Charles W. Anderson),“可以解决困难学习控制问题的类神经自适应元件”,IEEE 系统、人类和控制论交易,1983 年 9 月/10 月,页码 834–846,mng.bz/Q0rG

11.2.1. 作为强化学习问题的车杆

在进一步探讨之前,你应该通过玩车杆示例来直观地理解这个问题。车杆问题简单轻便,我们完全可以在浏览器中进行模拟和训练。图 11.3 提供了车杆问题的可视化描述,你可以在通过yarn watch命令打开的页面中找到。要查看和运行示例,请使用

git clone https://github.com/tensorflow/tfjs-examples.git
cd tfjs-examples/cart-pole
yarn && yarn watch
图 11.3. 小车杆问题的视觉渲染。A 面板:四个物理量(小车位置x,小车速度x′,杆倾角 θ 和杆角速度 θ’)构成环境状态和观察。在每个时间步长,代理可以选择向左施加力或向右施加力的行动,这将相应地改变环境状态。B 和 C 面板:导致游戏结束的两个条件——要么小车向左或向右移动太多(B),要么杆从垂直位置倾斜太多(C)。

点击“创建模型”按钮,然后再点击“训练”按钮。然后您应该在页面底部看到一个动画,显示一个未经训练的代理执行车杆任务。由于代理模型的权重被初始化为随机值(关于模型的更多信息稍后再说),它的表现会非常糟糕。从游戏开始到结束的所有时间步有时在 RL 术语中称为一个episode。我们在这里将术语gameepisode互换使用。

正如图 11.3 中的 A 面板所示,任何时间步中小车沿轨道的位置由称为x的变量捕获。它的瞬时速度表示为x’。此外,杆的倾斜角由另一个称为 θ 的变量捕获。杆的角速度(θ 变化的速度和方向)表示为 θ’。因此,这四个物理量(xx’,θ 和 θ’)每一步都由代理完全观察到,并构成此 RL 问题的观察部分。

模拟在满足以下任一条件时结束:

  • x 的值超出预先指定的边界,或者从物理角度来说,小车撞到轨道两端的墙壁之一(图 11.3 的 B 面板)。
  • 当 θ 的绝对值超过一定阈值时,或者从物理角度来说,杆过于倾斜,偏离了垂直位置(图 11.3 的 C 面板)。

环境还在第 500 个模拟步骤后终止一个 episode。这样可以防止游戏持续时间过长(一旦代理通过学习变得非常擅长游戏,这种情况可能会发生)。步数的上限在用户界面中是可以调整的。直到游戏结束,代理在模拟的每一步都获得一个单位的奖励(1)。因此,为了获得更高的累积奖励,代理需要找到一种方法来保持杆站立。但是代理如何控制小车杆系统呢?这就引出了这个 RL 问题的行动部分。

如图 11.3 A 面板中的力箭头所示,智能体在每一步只能执行两种可能的动作:在小车上施加向左或向右的力。智能体必须选择其中一种力的方向。力的大小是固定的。一旦施加了力,模拟将执行一组数学方程来计算环境的下一个状态(xx’、θ 和 θ’ 的新值)。详细内容涉及熟悉的牛顿力学。我们不会详细介绍这些方程,因为在这里理解它们并不重要,但是如果您感兴趣,可以在 cart-pole 目录下的 cart-pole/cart_pole.js 文件中找到它们。

类似地,渲染小车摆杆系统的 HTML 画布的代码可以在 cart-pole/ui.js 中找到。这段代码突显了使用 JavaScript(特别是 TensorFlow.js)编写 RL 算法的优势:UI 和学习算法可以方便地用同一种语言编写,并且彼此紧密集成。这有助于可视化和直观理解问题,并加速开发过程。为了总结小车摆杆问题,我们可以用经典强化学习框架来描述它(参见 table 11.1)。

表 11.1. 在经典强化学习框架中描述了小车摆杆问题
抽象 RL 概念 在小车摆杆问题中的实现
环境 一个运载杆子并在一维轨道上移动的小车。
动作 (离散)在每一步中,在左侧施加力和右侧施加力之间进行二进制选择。力的大小是固定的。
奖励 (频繁且仅为正值)对于游戏每一步,智能体会收到固定的奖励(1)。当小车撞到轨道一端的墙壁,或者杆子从直立位置倾斜得太厉害时,该情节就会结束。
观测 (完整状态,连续)每一步,智能体可以访问小车摆杆系统的完整状态,包括小车位置(x)和速度(x’),以及杆倾斜角(θ)和角速度(θ’)。
11.2.2. 策略网络

现在小车摆杆强化学习问题已经描述完毕,让我们看看如何解决它。从历史上看,控制理论家们曾经为这个问题设计过巧妙的解决方案。他们的解决方案基于这个系统的基本物理原理。[5] 但是在本书的背景下,我们不会这样来解决这个问题。在本书的背景下,这样做有点类似于编写启发式算法来解析 MNIST 图像中的边缘和角落,以便对数字进行分类。相反,我们将忽略系统的物理特性,让我们的智能体通过反复试错来学习。这符合本书其余部分的精神:我们不是在硬编码算法,也不是根据人类知识手动设计特征,而是设计了一种允许模型自主学习的算法。

如果您对传统的、非 RL 方法解决小车-杆问题感兴趣,并且不怕数学,可以阅读麻省理工学院 Russ Tedrake 的控制理论课程的开放课程 Ware:mng.bz/j5lp

我们如何让代理在每一步决定动作(向左还是向右的力)?鉴于代理可用的观察和代理每一步需要做出的决定,这个问题可以被重新制定为一个简单的输入输出映射问题,就像在监督学习中那样。一个自然的解决方案是构建一个神经网络,根据观察来选择一个动作。这是策略网络背后的基本思想。

这个神经网络将一个长度为 4 的观察向量(xx’,θ和θ’)作为输入,并输出一个可以转化为左右决定的数字。该网络架构类似于我们在第三章中为仿冒网站构建的二元分类器。抽象地说,每一步,我们将查看环境,并使用我们的网络决定采取哪些行动。通过让我们的网络玩一些回合,我们将收集一些数据来评价那些决定。然后,我们将发明一种方法来给这些决定分配质量,以便我们可以调整我们的网络的权重,使其在将来做出更像“好”的决定,而不像“坏”的决定。

该系统的细节与我们之前的分类器工作在以下方面有所不同:

  • 模型在游戏过程中多次被调用(在每个时间步长)。
  • 模型的输出(图 11.4 中的策略网络框中的输出)是对数而不是概率分数。通过 S 形函数将对数值转换为概率分数。我们之所以不直接在策略网络的最后(输出)层中包含 S 形非线性,是因为我们需要对数值进行训练,我们很快就会看到原因。
    图 11.4。策略网络如何融入我们解决小车-杆问题的解决方案。策略网络是一个 TensorFlow.js 模型,通过使用观察向量(xx’,θ和θ’)作为输入,输出左向力动作的概率。通过随机抽样将概率转换为实际行动。

  • 由 S 形函数输出的概率必须转换为具体的动作(向左还是向右)。这是通过随机抽样tf.multinomial()函数调用完成的。回想一下,在 lstm-text-generation example 中,我们使用tf.multinomial()来对字母表上的 softmax 概率进行抽样以抽取下一个字符。在这里的情况稍微简单一些,因为只有两个选择。

最后一点有着更深层次的含义。考虑到我们可以直接将 tf.sigmoid() 函数的输出通过应用阈值(例如,当网络的输出大于 0.5 时选择左侧动作,否则选择右侧动作)转换为一个动作。为什么我们更倾向于使用 tf.multinomial() 的更复杂的随机抽样方法,而不是这种更简单的方法?答案是我们希望tf.multinomial() 带来的随机性。在训练的早期阶段,策略网络对于如何选择力的方向一无所知,因为其权重是随机初始化的。通过使用随机抽样,我们鼓励它尝试随机动作并查看哪些效果更好。一些随机试验将会失败,而另一些则会获得良好的结果。我们的算法会记住这些良好的选择,并在将来进行更多这样的选择。但是除非允许代理随机尝试,否则这些良好的选择将无法实现。如果我们选择了确定性的阈值方法,模型将被困在其初始选择中。

这将我们带入了强化学习中一个经典而重要的主题,即探索与利用探索指的是随机尝试;这是 RL 代理发现良好行动的基础。利用意味着利用代理已学到的最优解以最大化奖励。这两者是相互不兼容的。在设计工作 RL 算法时,找到它们之间的良好平衡非常关键。起初,我们想要探索各种可能的策略,但随着我们逐渐收敛于更好的策略,我们希望对这些策略进行微调。因此,在许多算法中,训练过程中的探索通常会逐渐减少。在 cart-pole 问题中,这种减少是隐含在 tf.multinomial() 抽样函数中的,因为当模型的置信水平随着训练增加时,它会给出越来越确定的结果。

清单 11.1(摘自 cart-pole/index.js)展示了创建策略网络的 TensorFlow.js 调用。清单 11.2 中的代码(同样摘自 cart-pole/index.js)将策略网络的输出转换为代理的动作,并返回用于训练目的的对数概率。与我们在前几章遇到的监督学习模型相比,这里的模型相关代码并没有太大不同。

然而,这里根本不同的是,我们没有一组可以用来教模型哪些动作选择是好的,哪些是坏的标记数据集。如果我们有这样的数据集,我们可以简单地在策略网络上调用 fit()fitDataset() 来解决问题,就像我们在前几章中对模型所做的那样。但事实是我们没有,所以智能体必须通过玩游戏并观察到的奖励来弄清楚哪些动作是好的。换句话说,它必须“通过游泳学会游泳”,这是 RL 问题的一个关键特征。接下来,我们将详细看一下如何做到这一点。

策略网络 MLP:基于观察选择动作
createModel(hiddenLayerSizes) {                      ***1***
    if (!Array.isArray(hiddenLayerSizes)) {
      hiddenLayerSizes = [hiddenLayerSizes];
    }
    this.model = tf.sequential();
    hiddenLayerSizes.forEach((hiddenLayerSize, i) => {
      this.model.add(tf.layers.dense({
        units: hiddenLayerSize,
        activation: 'elu',
        inputShape: i === 0 ? [4] : undefined        ***2***
      }));
    });
    this.model.add(tf.layers.dense({units: 1}));     ***3***
  }
}
  • hiddenLayerSize 控制策略网络除最后一层(输出层)之外的所有层的大小。
  • inputShape 仅在第一层需要。
  • 最后一层被硬编码为一个单元。单个输出数字将被转换为选择左向力动作的概率。
从策略网络输出获取 logit 和动作的方法示例
getLogitsAndActions(inputs) {
  return tf.tidy(() => {
    const logits = this.policyNet.predict(inputs);
    const leftProb = tf.sigmoid(logits);         ***1***
    const leftRightProbs = tf.concat(            ***2***
        [leftProb, tf.sub(1, leftProb)], 1);     ***2***
    const actions = tf.multinomial(              ***3***
        leftRightProbs, 1, null, true);          ***3***
    return [logits, actions];
  });
}
  • 将 logit 转换为左向动作的概率值
  • 计算两个动作的概率值,因为 tf.multinomial() 需要它们。
  • 根据概率值随机抽样动作。四个参数分别是概率值、抽样数量、随机种子(未使用),以及一个指示概率值是否归一化的标志。
训练策略网络:REINFORCE 算法

现在关键问题是如何计算哪些动作是好的,哪些是坏的。如果我们能回答这个问题,我们就能够更新策略网络的权重,使其在未来更有可能选择好的动作,这与监督学习类似。很快能想到的是我们可以使用奖励来衡量动作的好坏。但是车杆问题涉及奖励:1)总是有一个固定值(1);2)只要剧集没有结束,就会在每一步发生。所以,我们不能简单地使用逐步奖励作为度量标准,否则所有动作都会被标记为同样好。我们需要考虑每个剧集持续的时间。

一个简单的方法是在一个剧集中求所有奖励的总和,这给了我们剧集的长度。但是总和能否成为对动作的良好评估?很容易意识到这是不行的。原因在于剧集末尾的步骤。假设在一个长剧集中,智能体一直很好地平衡车杆系统,直到接近结束时做了一些不好的选择,导致剧集最终结束。简单的总和方法会将最后的不良动作和之前的良好动作平等评估。相反,我们希望将更高的分数分配给剧集早期和中间部分的动作,并将较低的分配给靠近结尾的动作。

这引出了 奖励折扣 的概念,一个简单但在 RL 中非常重要的概念:某一步的价值应等于即时奖励加上预期未来奖励。未来奖励可能与即时奖励同等重要,也可能不那么重要。可以通过折扣系数 γ 来量化相对平衡。γ 通常设置为接近但略小于 1 的值,如 0.95 或 0.99。我们可以用公式表示:

公式 11.1。

在 公式 11.1 中,v[i] 表示第 i 步状态的总折扣奖励,可以理解为该特定状态的价值。它等于在该步骤给予智能体的即时奖励 (r[i]),加上下一步奖励 (r[i][+1]) 乘以折扣系数 γ,再加上再后两步的折扣奖励,以此类推,直到该事件结束(第 N 步)。

为了说明奖励折扣,我们展示了这个公式如何将原始奖励转换为更有用的价值度量方式,如 图 11.5 所示。面板 A 的顶部图显示了来自一段短情节的所有四步原始奖励。底部图显示了根据 公式 11.1 计算的折扣奖励。为了比较,面板 B 显示了来自长度为 20 的更长情节的原始和折扣总奖励。从两个面板可以看出,折扣总奖励值在开头较高,在结尾较低,这是有意义的,因为我们要为一个游戏结束的动作分配较低的值。此外,长情节的开头和中段的值(面板 B)高于短情节的开头(面板 A)。这也是有意义的,因为我们要为导致更长情节的动作分配更高的值。

图 11.5。面板 A:对四步情节的奖励进行奖励折扣(公式 11.1)。面板 B:与面板 A 相同,但来自一个包含 20 步的情节(即比面板 A 的情节长五倍)。由于折扣,与靠近结尾的动作相比,为每个情节的开始动作分配更高的值。

奖励折扣公式为我们提供了一组比单纯地求和更有意义的值。但我们仍然面临着如何使用这些折扣奖励价值来训练策略网络的问题。为此,我们将使用一种名为 REINFORCE 的算法,该算法由罗纳德·威廉姆斯在 1992 年发明。^([6]) REINFORCE 的基本思想是调整策略网络的权重,使其更有可能做出良好的选择(选择分配更高的折扣奖励)并减少做出不良选择(分配更低的折扣奖励)。

Ronald J. Williams,“Simple Statistical Gradient-Following Algorithms for Connectionist Reinforcement Learning,” Machine Learning, vol. 8, nos. 3–4, pp. 229–256, mng.bz/WOyw.

为了达到此目的,我们需要计算改变参数的方向,以使给定观察输入更有可能进行动作。这是通过 代码清单 11.3(摘自 cart-pole/index.js)实现的。函数 getGradientsAndSaveActions() 在游戏的每个步骤中被调用。它比较逻辑回归(未归一化的概率得分)和该步骤选择的实际动作,并返回相对于策略网络权重的两者不一致性的梯度。这可能听起来很复杂,但直观上是相当简单的。返回的梯度告诉策略网络如何更改其权重,以使选择更类似于实际选择。这些梯度与训练集的奖励一起构成了我们强化学习方法的基础。这就是为什么该方法属于被称为 策略梯度 的强化学习算法家族的原因。

代码清单 11.3 通过比较逻辑回归和实际动作来获取权重的梯度。
getGradientsAndSaveActions(inputTensor) {
    const f = () => tf.tidy(() => {
      const [logits, actions] =
          this.getLogitsAndActions(inputTensor);                       ***1***
      this.currentActions_ = actions.dataSync();
      const labels =
          tf.sub(1, tf.tensor2d(this.currentActions_, actions.shape));
      return tf.losses.sigmoidCrossEntropy(                            ***2***
          labels, logits).asScalar();                                  ***2***
    });
    return tf.variableGrads(f);                                        ***3***
  }
  • 1 getLogitsAndActions() 在 代码清单 11.2 中定义。
  • 2 sigmoid 交叉熵损失量化其在游戏中实际执行的动作与策略网络输出的逻辑回归之间的差异。
  • 3 计算损失相对于策略网络权重的梯度。

在训练期间,我们让代理对象玩一些游戏(比如 N 个游戏),并根据 方程式 11.1 收集所有折扣奖励以及所有步骤中的梯度。然后,我们通过将梯度与折扣奖励的归一化版本相乘来结合折扣奖励和梯度。奖励归一化在这里是一个重要的步骤。它线性地转移和缩放了 N 个游戏中所有折扣奖励,使得它们的总体均值为 0 和总体标准偏差为 1。图 11.6 显示了在折扣奖励上应用此归一化的示例。它说明了短剧集(长度为 4)和较长剧集(长度为 20)的归一化、折扣奖励。从这张图中可以明确 REINFORCE 算法所偏向的步骤是什么:它们是较长剧集的早期和中间部分的动作。相比之下,所有来自较短(长度为 4)剧集的步骤都被赋予 值。负的归一化奖励意味着什么?这意味着当它用于稍后更新策略网络的权重时,它将使网络远离未来给定相似状态输入时进行类似动作的选择。这与正的归一化奖励相反,后者将使策略网络向未来在类似的输入条件下做出相似的动作方向

图 11.6. 对两个长度为 4(面板 A)和 20(面板 B)的情节中的折现奖励进行归一化。我们可以看到,归一化的折现奖励在长度为 20 的情节开始部分具有最高值。策略梯度方法将使用这些折现奖励值来更新策略网络的权重,这将使网络更不可能选择导致第一个情节(长度 = 4)中不良奖励的动作选择,并且更有可能选择导致第二个情节开始部分(长度 = 20)中良好奖励的选择(在相同的状态输入下,即)。

对折现奖励进行归一化,并使用它来缩放梯度的代码有些冗长但不复杂。它在 cart-pole/index.js 中的 scaleAndAverageGradients() 函数中,由于篇幅限制这里不列出。缩放后的梯度用于更新策略网络的权重。随着权重的更新,策略网络将对从分配了更高折现奖励的步骤中的动作输出更高的 logits,并对从分配了较低折现奖励的步骤中的动作输出较低的 logits。

这基本上就是 REINFORCE 算法的工作原理。基于 REINFORCE 的 cart-pole 示例的核心训练逻辑显示在 列表 11.4 中。它是前面描述的步骤的重述:

  1. 调用策略网络以基于当前代理观察获得 logits。
  2. 基于 logits 随机采样一个动作。
  3. 使用采样的动作更新环境。
  4. 记住以下内容以备后续更新权重(步骤 7):logits 和所选动作,以及损失函数相对于策略网络权重的梯度。这些梯度被称为 策略梯度
  5. 从环境中接收奖励,并将其记住以备后用(步骤 7)。
  6. 重复步骤 1–5 直到完成 numGames 情节。
  7. 一旦所有 numGames 情节结束,对奖励进行折扣和归一化,并使用结果来缩放步骤 4 中的梯度。然后使用缩放后的梯度来更新策略网络的权重。(这是策略网络的权重被更新的地方。)
  8. (未在 列表 11.4 中显示)重复步骤 1–7 numIterations 次。

将这些步骤与代码中的步骤进行比较(从 cart-pole/index.js 中摘录),以确保您能够看到对应关系并按照逻辑进行。

列表 11.4. Cart-pole 示例中实现 REINFORCE 算法的训练循环
async train(
      cartPoleSystem, optimizer, discountRate, numGames, maxStepsPerGame) {
    const allGradients = [];
    const allRewards = [];
    const gameSteps = [];
    onGameEnd(0, numGames);
    for (let i = 0; i < numGames; ++i) {                              ***1***
      cartPoleSystem.setRandomState();                                ***2***
      const gameRewards = [];
      const gameGradients = [];
      for (let j = 0; j < maxStepsPerGame; ++j) {                     ***3***
        const gradients = tf.tidy(() => {
          const inputTensor = cartPoleSystem.getStateTensor();
          return this.getGradientsAndSaveActions(                     ***4***
              inputTensor).grads;                                     ***4***
        });
        this.pushGradients(gameGradients, gradients);
        const action = this.currentActions_[0];
        const isDone = cartPoleSystem.update(action);                 ***5***
        await maybeRenderDuringTraining(cartPoleSystem);
        if (isDone) {
          gameRewards.push(0);
          break;
        } else {
          gameRewards.push(1);                                        ***6***
        }
      }
      onGameEnd(i + 1, numGames);
      gameSteps.push(gameRewards.length);
      this.pushGradients(allGradients, gameGradients);
      allRewards.push(gameRewards);
      await tf.nextFrame();
    }
    tf.tidy(() => {
      const normalizedRewards =                                       ***7***
          discountAndNormalizeRewards(allRewards, discountRate);      ***7***
      optimizer.applyGradients(                                       ***8***
          scaleAndAverageGradients(allGradients, normalizedRewards)); ***8***
    });
    tf.dispose(allGradients);
    return gameSteps;
  }
  • 1 循环指定次数的情节
  • 2 随机初始化一个游戏情节
  • 3 循环游戏的步骤
  • 4 跟踪每步的梯度以备后续 REINFORCE 训练
  • 5 代理在环境中采取一个动作。
  • 6 只要游戏尚未结束,代理每步都会获得一个单位奖励。
  • 7 对奖励进行折扣和归一化(REINFORCE 的关键步骤)
  • 8 使用来自所有步骤的缩放梯度更新策略网络的权重

要看到 REINFORCE 算法的运行情况,请在演示页面上指定 25 个时期,并单击“训练”按钮。默认情况下,训练期间实时显示环境的状态,以便您可以看到学习代理的重复尝试。要加快训练速度,请取消选中“训练期间渲染”复选框。在合理更新的笔记本电脑上,25 个时期的训练需要几分钟,并且应足以达到天花板性能(默认设置下游戏每轮 500 步)。图 11.7 显示了典型的训练曲线,该曲线将平均每轮长度作为训练迭代的函数绘制出来。请注意,训练进度显示出一些戏剧性的波动,平均步数随着迭代次数以非单调和高度嘈杂的方式变化。这种波动在强化学习训练工作中并不罕见。

图 11.7. 一条曲线显示了智能体在车杆问题的每个训练迭代中生存的平均步数与训练迭代次数的关系。在约第 20 次迭代时达到完美分数(在本例中为 500 步)。这个结果是在隐藏层大小为 128 的情况下获得的。曲线的高度非单调和波动形状在强化学习问题中并不罕见。

训练完成后,单击“测试”按钮,您应该会看到代理在许多步骤上很好地保持车杆系统平衡的表现。由于测试阶段不涉及最大步数(默认为 500 步),因此代理可以保持游戏进行超过 1,000 步。如果持续时间过长,您可以单击“停止”按钮终止模拟。

总结这一节,图 11.8 概括了问题的表述以及 REINFORCE 策略梯度算法的作用。这张图展示了解决方案的所有主要部分。在每个步骤中,代理使用一个名为策略网络的神经网络来估计向左行动(或等效地,向右行动)是更好的选择的可能性。这种可能性通过一个随机抽样过程转换为实际行动,该过程鼓励代理早期探索并在后期遵守估计的确定性。行动驱动环境中的车杆系统,该系统反过来为代理提供奖励,直到本集的结束。这个过程重复了多个集,期间 REINFORCE 算法记住了每一步的奖励、行动和策略网络的估计。当 REINFORCE 需要更新策略网络时,它通过奖励折现和归一化区分网络中的好估计和坏估计,然后使用结果来推动网络的权重朝着未来做出更好的估计。这个过程迭代了多次,直到训练结束(例如,当代理达到阈值性能时)。

图 11.8. 展示了基于 REINFORCE 算法的解决方案对车杆问题的示意图。该图是图 11.4 中图示的扩展视图。

抛开所有优雅的技术细节,让我们退后一步,看一看这个例子中体现的 RL 的大局。基于 RL 的方法相对于非机器学习方法(如传统控制理论)具有明显的优势:普适性和人力成本的经济性。在系统具有复杂或未知特性的情况下,RL 方法可能是唯一可行的解决方案。如果系统的特性随时间变化,我们不必从头开始推导新的数学解:我们只需重新运行 RL 算法,让代理适应新情况。

RL 方法的劣势,这仍然是 RL 研究领域中一个未解决的问题,是它需要在环境中进行许多次重复试验。在车杆示例中,大约需要 400 个游戏回合才能达到目标水平的熟练程度。一些传统的、非 RL 方法可能根本不需要试验。实施基于控制理论的算法,代理应该能够从第 1 个回合就平衡杆子。对于像车杆这样的问题,RL 对于重复试验的渴望并不是一个主要问题,因为计算机对环境的模拟是简单、快速和廉价的。然而,在更现实的问题中,比如自动驾驶汽车和物体操纵机器臂,RL 的这个问题就变得更加尖锐和紧迫。没有人能承担在训练代理时多次撞车或者摧毁机器臂的成本,更不用说在这样的现实问题中运行 RL 训练算法将需要多么长的时间。

这就结束了我们的第一个 RL 示例。车杆问题具有一些特殊的特征,在其他 RL 问题中不适用。例如,许多 RL 环境并不会在每一步向代理提供正面奖励。在某些情况下,代理可能需要做出几十个甚至更多的决策,才能获得积极的奖励。在正面奖励之间的空隙中,可能没有奖励,或者只有负面奖励(可以说很多现实生活中的努力,比如学习、锻炼和投资,都是如此!)。此外,车杆系统在“无记忆”方面是“无记忆”的,即系统的动态不取决于代理过去的行为。许多 RL 问题比这更复杂,因为代理的行为改变了环境的某些方面。我们将在下一节中研究的 RL 问题将展示稀疏的正面奖励和一个随着行动历史而变化的环境。为了解决这个问题,我们将介绍另一个有用且流行的 RL 算法,称为 deep Q-learning

JavaScript 深度学习(四)(4)https://developer.aliyun.com/article/1516984

相关文章
|
24天前
|
机器学习/深度学习 JavaScript 前端开发
JavaScript 深度学习(五)(5)
JavaScript 深度学习(五)
8 0
|
24天前
|
机器学习/深度学习 JavaScript 前端开发
JavaScript 深度学习(五)(4)
JavaScript 深度学习(五)
24 0
|
24天前
|
存储 机器学习/深度学习 JavaScript
JavaScript 深度学习(五)(3)
JavaScript 深度学习(五)
22 0
|
24天前
|
机器学习/深度学习 并行计算 JavaScript
JavaScript 深度学习(五)(2)
JavaScript 深度学习(五)
29 0
|
24天前
|
机器学习/深度学习 人工智能 JavaScript
JavaScript 深度学习(五)(1)
JavaScript 深度学习(五)
25 0
|
24天前
|
机器学习/深度学习 前端开发 JavaScript
JavaScript 深度学习(四)(5)
JavaScript 深度学习(四)
12 1
|
24天前
|
机器学习/深度学习 存储 算法
JavaScript 深度学习(四)(4)
JavaScript 深度学习(四)
22 1
|
24天前
|
机器学习/深度学习 编解码 JavaScript
JavaScript 深度学习(四)(2)
JavaScript 深度学习(四)
22 1
|
24天前
|
机器学习/深度学习 自然语言处理 JavaScript
JavaScript 深度学习(四)(1)
JavaScript 深度学习(四)
12 2
|
3天前
|
机器学习/深度学习 数据采集 算法
未来研究将深入探索深度学习的应用及数据质量与安全问题
【6月更文挑战第13天】本文探讨了使用Python和机器学习预测股票价格的方法,包括数据收集与预处理(填充缺失值、处理异常值、标准化)、特征选择(技术指标、基本面指标、市场情绪)、模型选择与训练(线性回归、SVM、神经网络等)、模型评估与调优。尽管股票价格受多重因素影响,通过不断优化,可构建预测模型。未来研究将深入探索深度学习的应用及数据质量与安全问题。
19 5