TensorFlow-强化学习-全-

TensorFlow 强化学习(全)

原文:Reinforcement Learning With TensorFlow

协议:CC BY-NC-SA 4.0

零、前言

强化学习RL)使您可以在业务环境中开发智能,快速且自学的系统。 这是训练您的学习型智能体并解决人工智能中各种问题的有效方法,从游戏,自动驾驶汽车和机器人到企业应用,其范围从数据中心节能(冷却数据中心)到智能仓储解决方案。

本书涵盖了通过将深度神经网络架构与强化学习相结合而在深度强化学习中取得的主要进步和成功。 该书还向读者介绍了强化学习的概念,它的优点以及为什么它如此受欢迎。 它讨论了 MDP,蒙特卡洛树搜索,策略和值迭代,时间差异学习(例如 Q 学习)和 SARSA。 您将使用 TensorFlow 和 OpenAI Gym 来构建简单的神经网络模型,以从自己的行为中学习。 您还将看到强化学习算法如何在游戏,图像处理和 NLP 中发挥作用。

到本书结尾,您将对 TensorFlow 和 OpenAI Gym 的功能有一个深刻的了解,即什么是强化学习以及如何将您的知识付诸实践。

这本书是给谁的

如果您想以最实际的方式开始使用 TensorFlow 进行强化学习,那么本书将是有用的资源。 本书假定您具有传统机器学习和线性代数的先验知识,并且对 TensorFlow 框架有所了解。 不需要以前的强化学习和深度神经网络经验。

充分利用这本书

以下是充分利用本书的要求:

  • Python 和 TensorFlow
  • 线性代数是神经网络的前提
  • 安装包:Python,TensorFlow 和 OpenAI Gym(在第 1 章,“深度学习–架构和框架”和第 2 章中显示)

下载示例代码文件

您可以从 www.packtpub.com 的帐户中下载本书的示例代码文件。 如果您在其他地方购买了此书,则可以访问 www.packtpub.com/support 并注册以将文件直接通过电子邮件发送给您。

您可以按照以下步骤下载代码文件:

  1. 登录或登录 www.packtpub.com
  2. 选择支持选项卡。
  3. 单击代码下载和勘误。
  4. 在搜索框中输入书籍的名称,然后按照屏幕上的说明进行操作。

下载文件后,请确保使用以下最新版本解压缩或解压缩文件夹:

  • Windows 的 WinRAR/7-Zip
  • Mac 版 Zipeg/iZip/UnRarX
  • 适用于 Linux 的 7-Zip/PeaZip

本书的代码包也托管在 GitHub 上。 如果代码有更新,它将在现有的 GitHub 存储库中进行更新。

我们还从这里提供了丰富的书籍和视频目录中的其他代码包。 去看一下!

下载彩色图像

我们还提供了 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图像。 您可以在此处下载

使用约定

本书中使用了许多文本约定。

CodeInText:指示文本,数据库表名称,文件夹名称,文件名,文件扩展名,路径名,虚拟 URL,用户输入和 Twitter 句柄中的代码字。 这是一个示例:“ sigmoid(x)relu(x)分别指执行 Sigmoid 和 ReLU 激活计算的函数。”

代码块设置如下:

def discretization(env, obs):

    env_low = env.observation_space.low
    env_high = env.observation_space.high

任何命令行输入或输出的编写方式如下:

Episode 1 completed with total reward 8433.30289388 in 26839 steps
Episode 2 completed with total reward 3072.93369963 in 8811 steps
Episode 3 completed with total reward 1230.81734028 in 4395 steps
Episode 4 completed with total reward 2182.31111239 in 6629 steps

粗体:表示新术语,重要单词或您在屏幕上看到的单词。 例如,菜单或对话框中的单词会出现在这样的文本中。 这是一个示例:“从管理面板中选择系统信息。”

警告或重要提示如下所示。

提示和技巧如下所示。

一、深度学习–架构和框架

人工神经网络是一种计算系统,为我们提供了解决诸如图像识别到语音翻译等具有挑战性的机器学习任务的重要工具。 最近的突破,例如 Google DeepMind 的 AlphaGo 击败了最好的围棋玩家,或者卡内基梅隆大学的 Libratus 击败了世界上最好的职业扑克玩家,都证明了算法的进步。 这些算法像人类一样学习狭窄的智能,并达到超人水平的表现。 用通俗易懂的话说,人工神经网络是我们可以在计算机上编程的人脑的松散表示。 确切地说,这是受我们对人脑功能知识的启发而产生的一种方法。 神经网络的一个关键概念是创建输入数据的表示空间,然后在该空间中解决问题。 也就是说,从数据的当前状态开始扭曲数据,以便可以以不同的状态表示数据,从而可以解决有关的问题陈述(例如分类或回归)。 深度学习意味着多个隐藏的表示,即具有许多层的神经网络,可以创建更有效的数据表示。 每一层都会细化从上一层收到的信息。

另一方面,强化学习是机器学习的另一个方面,它是一种学习遵循一系列动作的任何类型的活动的技术。 强化学习智能体从环境中收集信息并创建状态表示; 然后执行一个导致新状态和报酬的动作(即来自环境的可量化反馈,告诉我们该动作是好是坏)。 这种现象一直持续到智能体能够将表现提高到超过特定阈值(即最大化奖励的期望值)为止。 在每个步骤中,可以随机选择这些动作,将其固定或使用神经网络进行监督。 使用深度神经网络对动作预测进行监督将打开一个新领域,称为深度强化学习。 这构成了 AlphaGo,Libratus 和人工智能领域中许多其他突破性研究的基础。

我们将在本章介绍以下主题:

  • 深度学习
  • 强化学习
  • TensorFlow 和 OpenAI Gym 简介
  • 强化学习中有影响力的研究人员和项目

深度学习

深度学习是指训练大型神经网络。 首先,让我们讨论神经网络的一些基本用例,以及即使这些神经网络已经存在数十年,为什么深度学习仍会引起如此激烈的争论。

以下是神经网络中监督学习的示例:

输入(x 输出(y 应用领域 建议的神经网络方法
房屋特征 房子的价格 房地产 在输出层中带有线性整流单元的标准神经网络
广告和点击广告的用户信息 是(1)或否(0) 在线广告 具有二分类的标准神经网络
图像对象 从 100 个不同的对象进行分类,即(1,2,.....,100) 照片标注 卷积神经网络(由于图像,即空间数据)
语音 文字笔录 语音识别 循环神经网络(因为两个输入输出都是序列数据)
英文 中文 机器翻译 循环神经网络(因为输入是序列数据)
图像,雷达信息 其他汽车的位置 自动驾驶 定制的混合/复杂神经网络

在本章的后续部分中,我们将详细介绍前面提到的神经网络,但是首先我们必须了解,根据问题陈述的目的使用了不同类型的神经网络。

监督学习是机器学习中的一种方法,其中,使用输入特征对及其对应的输出/目标值(也称为标签)来训练智能体。

传统的机器学习算法对于结构化数据非常有效,其中大多数输入特征都定义得很好。 对于非结构化数据(例如音频,图像和文本)而言,情况并非如此,其中数据分别是信号,像素和字母。 对于计算机而言,比结构化数据更难理解非结构化数据。 神经网络基于这种非结构化数据进行预测的能力是其普及并产生经济价值的关键原因。

首先,它是当前的规模,即数据,计算能力和新算法的规模,这正在推动深度学习的发展。 互联网已经过去了四十年,导致大量的数字足迹不断积累和增长。 在此期间,研究和技术发展帮助扩大了计算系统的存储和处理能力。 当前,由于这些繁重的计算系统和海量数据,我们能够验证过去三十年来在人工智能领域的发现。

现在,我们需要什么来实现深度学习?

首先,我们需要大量数据。

其次,我们需要训练一个相当大的神经网络。

那么,为什么不对少量数据训练大型神经网络呢?

回想一下您的数据结构课程,其中结构的用途是充分处理特定类型的值。 例如,您将不会在具有张量数据类型的变量中存储标量值。 类似地,鉴于大量数据,这些大型神经网络会创建不同的表示并开发理解模式,如下图所示:

请参考以下数据的图形表示与不同机器学习算法的表现的比较:

  1. 我们看到传统的机器学习算法的表现在一定时间后收敛,因为它们无法吸收超过阈值的数据量的不同表示形式。

  2. 检查图的左下角,靠近原点。 这是算法的相对顺序没有很好定义的区域。 由于数据量小,内部表示形式并没有那么明显。 结果,所有算法的表现指标都一致。 在此级别上,表现与更好的特征工程成正比。 但是这些手工设计的特征随着数据大小的增加而失败。 这就是深度神经网络的来历,因为它们能够从大量数据中捕获更好的表示。

因此,我们可以得出结论,不应该将深度学习架构应用于任何遇到的数据。 所获得数据的数量和种类表明要应用哪种算法。 有时,小数据通过传统的机器学习算法比深度神经网络更有效。

深度学习问题陈述和算法可以根据其研究和应用领域进一步细分为四个不同的部分:

  • 通用深度学习:密集连接的层或全连接网络

  • 序列模型:循环神经网络,长短期记忆网络,门控循环单元等

  • 空间数据模型(例如,图像):卷积神经网络,生成对抗网络

  • 其他:无监督学习,强化学习,稀疏编码等

当前,该行业主要由前三个部分驱动,但是人工智能的未来取决于第四部分的发展。 沿着机器学习的发展历程,我们可以看到直到现在,这些学习模型都将实数作为输出,例如电影评论(情感评分)和图像分类(类对象)。 但是现在,以及其他类型的输出也正在生成,例如,图像字幕(输入:图像,输出:文本),机器翻译(输入:文本,输出:文本)和语音识别(输入:音频, 输出:文本)。

人类水平的表现是必要的,并且通常应用于深度学习。 在一段时间内收敛到最高点之后,人员水平的准确率变得恒定。 这一点称为最佳错误率(也称为贝叶斯误差率,即对于任何随机结果分类器而言,最低的错误率)。

其背后的原因是由于数据中的噪声,许多问题在表现上都有理论上的限制。 因此,人员级别的准确率是通过进行误差分析来改进模型的好方法。 这是通过合并人为误差,训练集误差和验证集误差来估计偏差方差影响(即欠拟合和过拟合条件)来完成的。

数据规模,算法类型和表现指标是一组方法,可以帮助我们针对不同的机器学习算法确定改进水平。 因此,决定是否投资深度学习或采用传统机器学习方法的关键决策。

具有一些输入特征(下图中的三个)的基本感知器如下所示:

上图设置了神经网络的基本方法,即如果我们在第一层中有输入,而在第二层中有输出,则它看起来像。 让我们尝试解释一下。 这里:

  • X1X2X3是输入特征变量,即此处的输入维为 3(考虑到没有偏差变量)。

  • W1W2W3是与特征变量关联的相应权重。 当我们谈论神经网络的训练时,我们的意思是说权重的训练。 因此,这些构成了我们小型神经网络的参数。

  • 输出层中的函数是应用于从前一层接收的信息的聚合上的激活函数。 此函数创建一个与实际输出相对应的表示状态。 从输入层到输出层的一系列过程导致预测输出,称为正向传播。

  • 通过多次迭代,可以最小化激活函数的输出和实际输出之间的误差值。

  • 只有在我们将权重的值(从输出层到输入层)更改为可以使误差函数最小的方向时,才会使误差最小。 这个过程称为反向传播,因为我们正朝相反的方向发展。

现在,牢记这些基础知识,让我们进一步使用逻辑回归作为神经网络对神经网络进行神秘化,并尝试创建具有一个隐藏层的神经网络。

深度学习的激活函数

激活函数是人工神经网络的组成部分。 他们决定特定神经元是否被激活,即神经元接收到的信息是否相关。 激活函数对接收信号(数据)执行非线性变换。

我们将在以下各节中讨论一些流行的激活函数。

Sigmoid 函数

Sigmoid 是一种平滑且连续可微的函数。 这导致非线性输出。 Sigmoid 函数在这里表示:

请查看下图的 Sigmoid 函数观察结果。 该函数的范围是 0 到 1。观察函数的曲线,我们看到x值介于 -3 和 3 之间时,梯度非常高,但超出此范围则变得平坦。 因此,可以说这些点附近的x的微小变化将使 Sigmoid 函数的值产生较大的变化。 因此,函数目标是将 Sigmoid 函数的值推向极限。

因此,它被用于分类问题:

查看下面的 Sigmoid 函数的梯度,我们观察到取决于x的平滑曲线。 由于梯度曲线是连续的,因此很容易反向传播误差并更新参数Wb

Sigmoid 得到广泛使用,但其缺点是该函数趋于 +3 和 -3 平坦。 因此,无论何时函数落在该区域中,梯度都趋于接近零,并且我们的神经网络学习停止。

由于 Sigmoid 函数输出的值从 0 到 1,即全为正,因此它在原点周围是非对称的,并且所有输出信号都是正的,即具有相同的符号。 为了解决这个问题,已将 Sigmoid 函数缩放为 tanh 函数,我们将在下面进行研究。 而且,由于梯度导致的值很小,因此很容易遇到梯度消失的问题(我们将在本章稍后讨论)。

tanh 函数

Tanh 是围绕原点对称的连续函数。 它的范围是 -1 至 1。tanh 函数表示如下:

因此,输出信号将同时为正和负,从而增加了原点周围信号的隔离。 如前所述,它是连续的,也是非线性的,并且在所有点上都是可微的。 在下图中,我们可以在 tanh 函数的图中观察这些属性。 尽管是对称的,但它变得平坦,超过 -2 和 2:

现在看下面的 tanh 函数的梯度曲线,我们发现它比 Sigmoid 函数陡峭。 tanh 函数还具有梯度消失问题:

softmax 函数

softmax 函数主要用于处理分类问题,并且最好在输出层中使用,以输出输出类别的概率。 如前所述,在解决二进制逻辑回归时,我们看到 Sigmoid 函数只能处理两个类。 为了处理多类,我们需要一个可以为所有类生成值的函数,这些值遵循概率规则。 这个目标是通过 softmax 函数实现的,该函数将每个类别的输出缩小在 0 和 1 之间,然后将它们除以所有类别的输出总和:

例如,x ∈ {1, 2, 3, 4},其中x涉及四个类别。

然后,softmax 函数将得出结果(四舍五入到小数点后三位):

因此,我们看到了所有类别的概率。 由于每个分类器的输出都需要所有分类的概率值,因此 softmax 函数成为分类器外层激活函数的最佳候选者。

整流线性单元函数

整流线性单元(更称为 ReLU)是使用最广泛的激活函数:

ReLU 函数具有非线性的优势。 因此,反向传播很容易,因此可以堆叠由 ReLU 函数激活的多个隐藏层,其中对于x <= 0f(x) = 0,对于x > 0f(x) = x

ReLU 函数相对于其他激活函数的主要优势在于,它不会同时激活所有神经元。 这可以从前面的 ReLU 函数图中观察到,在图中我们可以看到,如果输入为负,则输出零,而神经元不会激活。 这导致网络稀疏,并且计算快速简便。

ReLU 的导数图,对于x <= 0f'(x) = 1,对于x > 0f'(x) = 0

查看前面的 ReLU 的前面的梯度图,我们可以看到该图的负侧显示了一个恒定的零。 因此,落入该区域的激活将具有零梯度,因此权重将不会更新。 这将导致节点/神经元不活动,因为它们将不会学习。 为了解决这个问题,我们提供了泄漏的 ReLU,将其修改为:

这防止了梯度在负侧变为零,并且由于a的值较低,权重训练持续但缓慢地进行。

如何选择正确的激活函数

激活函数取决于问题陈述的目的和所关注的属性。 一些推断如下:

  • Sigmoid 函数在浅层网络和二分类器的情况下效果很好。 较深的网络可能会导致梯度消失。

  • ReLU 函数是使用最广泛的函数,请尝试使用 Leaky ReLU 以避免神经元死亡的情况。 因此,从 ReLU 开始,如果 ReLU 无法提供良好的结果,则移至另一个激活函数。

  • 在外层使用 softmax 进行多类分类。

  • 避免在外层使用 ReLU。

作为神经网络的逻辑回归

逻辑回归是一种分类器算法。 在这里,我们尝试预测输出类别的概率。 具有最高概率的类别将成为预测输出。 使用交叉熵计算实际输出和预测输出之间的误差,并通过反向传播将其最小化。 检查下图,了解二进制逻辑回归和多类逻辑回归。 区别基于问题陈述。 如果输出类的唯一数量为两个,则称为二分类;如果输出类的唯一数量为两个以上,则称为多类分类。 如果没有隐藏层,我们将 Sigmoid 函数用于二分类,并获得用于二进制逻辑回归的架构。 类似地,如果没有隐藏层,并且我们使用 softmax 函数进行多类分类,则可以得到多类逻辑回归的架构。

现在出现一个问题,为什么不使用 Sigmoid 函数进行多类逻辑回归?

对于任何神经网络的所有预测输出层而言,答案都是正确的,即预测输出应遵循概率分布。 正常来说,输出具有N个类别。 对于具有例如d维的输入数据,这将导致N个概率。 因此,此一个输入数据的N概率之和应为 1,并且这些概率中的每一个应在 0 到 1 之间(含 0 和 1)。

一方面,在大多数情况下,N个不同类别的 Sigmoid 函数之和可能不为 1。 因此,在二进制的情况下,使用 Sigmoid 函数来获得一个类别的概率,即p(y = 1 | x),而对于另一个类别,则是概率,即p(y = 0 | x) = 1 - p(y = 1 | x)。 另一方面,softmax 函数的输出是满足概率分布属性的值。 在图中,σ指的是 Sigmoid 函数:

还会出现一个后续问题:如果在二进制逻辑回归中使用 softmax 怎么办?

如前所述,只要您的预测输出遵循概率分布规则,一切都会很好。 稍后,我们将讨论交叉熵以及概率分布作为解决任何机器学习问题(尤其是处理分类任务)的基础的重要性。

如果分布中所有值的概率在 0 到 1 之间(含 0 和 1)且所有这些概率的总和必须为 1,则该概率分布有效。

逻辑回归可以在很小的神经网络中查看。 让我们尝试逐步实现二进制逻辑回归,如下所示:

符号

假设数据的格式为(x^(i), y^(i)),其中:

  • x^(i) ∈ Ry^(i) ∈ {0, 1}(类数为 2,因为它是二分类)

  • x^(i)n维,即x^(i) = {x[1]^(i), x[2]^(i), ..., x[n]^(i)}(请参见上图)

  • 训练示例的数量是m。 因此,训练集如下所示:

    • m为训练数据集的大小。

    • 并且,由于x = {x[1], x[2], ..., x[m]},其中每个x^(i) = {x[1]^(i), x[2]^(i), ..., x[m]^(i)}

    • 因此,X是大小为n * m的矩阵,即特征数*训练示例数

    • Y = [y^(1), y^(2), ..., y^(m)]m个输出的向量,其中每个y^(i) ∈ {0, 1}

    • 参数:权重W ∈ R和偏差b ∈ RW = {W[1], W[2], ..., W[n]},其中Wᵢb是标量值。

目的

任何监督分类学习算法的目的都是以较高的概率预测正确的类别。 因此,对于每个给定的x^(i),我们必须计算预测的输出,即概率y_hat^(i) = P(y^(i) = 1 | x^(i))。 因此,y_hat^(i) ∈ [0, 1]

参考上图中的二进制逻辑回归:

  • 预测的输出,即y_hat^(i) = σ(Wx^(i) + b)。 在此,Sigmoid 函数将Wx^(i) + b的值缩小为 0 到 1。

  • 这意味着,当Wx^(i) + b -> +∞时,Sigmoid 函数,即σ(Wx^(i) + b) -> 1

  • Wx^(i) + b -> -∞时,它的 Sigmoid 函数即σ(Wx^(i) + b) -> 0

一旦我们计算出y_hat,即预测的输出,就完成了前向传播任务。 现在,我们将使用成本函数计算误差值,并尝试通过梯度下降来更改参数Wb的值,从而反向传播以最小化误差值。

成本函数

代价函数是一个度量,它确定关于实际训练输出和预测输出执行的机器学习算法的好坏。 如果您还记得线性回归,其中误差平方和用作损失函数,即L(y^(i), y_hat^(i)) = 1/2 (y^(i) - y_hat^(i))²。 这在凸曲线上效果更好,但是在分类的情况下,曲线是非凸曲线; 结果,梯度下降效果不好,也不会趋于全局最优。 因此,我们使用交叉熵损失作为成本函数,它更适合分类任务。

交叉熵作为损失函数(对于第i个输入数据),即:

其中C表示不同的输出类别。因此,成本函数=平均交叉熵损失(对于整个数据集),即:

在二元逻辑回归中,输出类别只有两个,即 0 和 1,因为类别值的总和始终为 1。因此(对于第i个输入数据),如果一个类别为y^(i),则其他输出类别将是1 - y^(i)。 类似地,由于类别y^(i)的概率为y_hat^(i)(预测),因此另一类别(即1 - y^(i))的概率将为1 - y_hat^(i)

因此,损失函数修改为:

其中:

  • 如果y^(i) = 1,即L(y^(i), y_hat^(i)) = -log y_hat^(i)。 因此,为了使L最小化,y_hat^(i)应该较大,即接近 1。

  • 如果y^(i) = 0,即L(y^(i), y_hat^(i)) = -log(1 - y_hat^(i))。 因此,为了使L最小化,y_hat^(i)应该较小,即接近于 0。

损失函数适用于单个示例,而成本函数适用于整个训练批量。 因此,这种情况下的成本函数为:

梯度下降算法

梯度下降算法是一种使用一阶导数查找函数最小值的优化算法,也就是说,我们仅将函数的参数微分为一阶。 在此,梯度下降算法的目的是使关于Wb的成本函数J(W, b)最小化。

此方法包括以下步骤,可进行多次迭代以最小化J(W, b)

上式中使用的α是指学习率。 学习率是学习智能体适应新知识的速度。 因此,α,即学习率是需要作为标量值或时间函数分配的超参数。 这样,在每次迭代中,Wb的值都按照上式进行更新,直到成本函数的值达到可接受的最小值为止。

梯度下降算法意味着沿斜率向下移动。 曲线的斜率由关于参数的成本函数J表示。 斜率(即斜率)给出了正斜率(如果为正)和负斜率的方向。 因此,我们必须使用负号与斜率相乘,因为我们必须与增加斜率的方向相反并朝减小斜率的方向相反。

使用最佳学习率α,可以控制下降,并且我们不会过度降低局部最小值。 如果学习率α非常小,那么收敛将花费更多时间,而如果学习率α非常高,则由于迭代次数众多,它可能会过冲并错过最小值和偏差:

计算图

基本的神经网络由前向传播和后向传播组成。 结果,它由一系列步骤组成,这些步骤包括不同节点,权重和偏差的值,以及所有权重和偏差的成本函数导数。 为了跟踪这些过程,图片中出现了计算图。 无论神经网络的深度如何,计算图还可以跟踪链式规则的微分。

使用梯度下降法解决逻辑回归的步骤

将我们刚刚介绍的所有构建模块放在一起,让我们尝试解决具有两个输入特征的二进制逻辑回归。

计算的基本步骤是:

  1. 计算Z^(i) = WX^(i) + b, ∀i

  2. 计算y_hat^(i) = σ(Z^(i)), ∀i,预测输出

  3. 计算成本函数:

假设我们有两个输入特征,即二维和m样本数据集。 因此,将是以下情况:

  1. X = {x[1], x[2]}

  2. 权重W = {w[1], w[2]}和偏差b

  3. 因此,z^(i) = w[1]x[1]^(i) + w[2]x[2]^(i) + by_hat^(i) = σ(z^(i))

  4. 计算J(W, b)(所有示例的平均损失)

  5. 计算关于w₁w₂b的导数,分别为∂J/∂w[1]∂J/∂w[2]∂J/∂b

  6. 按照前面的梯度下降部分所述修改w₁w₂b

先前m个样本数据集的伪代码为:

  1. 初始化学习率α和周期数e的值
  2. 循环遍历多个周期e(每次完整的数据集将分批通过)
  3. J(成本函数)和b(偏差)初始化为 0,对于W1W2,您可以使用随机正态或 xavier 初始化(在下一节中说明)

在此,ay_hatdw1∂J/∂w[1]dw2∂J/∂w[2]db∂J/∂b。 每个迭代都包含一个循环遍历m个示例的循环。

这里给出了相同的伪代码:

w1 = xavier initialization, w2 = xavier initialization, e = 100, α = 0.0001
for j → 1 to e :
     J = 0, dw1 = 0, dw2 = 0, db = 0
     for i → 1 to m :
         z = w1x1[i] + w2x2[i] + b
         a = σ(z)
         J = J - [ y[i] log a + (1-y) log (1-a) ]
         dw1 = dw1 + (a-y[i]) * x1[i] 
         dw2 = dw2 + (a-y[i]) * x2[i]
         db = db + (a-y[i])
     J = J / m
     dw1 = dw1 / m
     dw2 = dw2 / m
     db = db / m
     w1 = w1 - α * dw1
     w2 = w2 - α * dw2 

什么是 Xavier 初始化?

Xavier 初始化是神经网络中权重的初始化,是遵循高斯分布的随机变量,其中方差var(W)

其中,n_in是当前层中的单元数,即传入的信号单元,n_out是下一层中的单元数,即传出的结果信号单元。 简而言之,n_in * n_outW的形状。

为什么我们使用 xavier 初始化?

以下因素要求应用 xavier 初始化:

  • 如果网络中的权重开始很小,则大多数信号将收缩并在随后的层中激活函数处于休眠状态

  • 如果权重开始很大,则大多数信号将大量增长并通过后面各层的激活函数

因此,xavier 初始化有助于产生最佳权重,以使信号在最佳范围内,从而使信号变得既不会太小也不会太大的机会最小。

前述公式的推导超出了本书的范围。 请随时在此处进行搜索,并进行推导以获得更好的理解。

神经网络模型

神经网络模型类似于前面的逻辑回归模型。 唯一的区别是在输入层和输出层之间添加了隐藏层。 让我们考虑使用单个隐藏层神经网络进行分类,以了解该过程,如下图所示:

在这里,第 0 层是输入层,第 1 层是隐藏层,第 2 层是输出层。 这也称为两层神经网络,这是由于以下事实:当我们计算神经网络中的层数时,我们并不将输入层视为第一层。 因此,将输入层视为第 0 层,然后连续的层将获得第 1 层,第 2 层的表示法,依此类推。

现在,想到一个基本问题:为什么输入和输出层之间的层称为隐藏层?

这是因为在训练集中不存在隐藏层中节点的值。 如我们所见,在每个节点上都会进行两次计算。 这些是:

  • 汇总来自先前各层的输入信号

  • 对聚合信号进行激活以创建更深层的内部表示,这些表示又是相应隐藏节点的值

参考上图,我们有三个输入特征x[1], x[2], x[3]。 显示值为 1 的节点被视为偏置单元。 除输出外,每一层通常都有一个偏置单元。 偏置单元可以看作是一个拦截项,在左右激活函数中起着重要作用。 请记住,隐藏层和其中的节点的数量是我们一开始定义的超参数。 在这里,我们将隐藏层数定义为 1,将隐藏节点的数数定义为 3,a[1], a[2], a[3]。 因此,可以说我们有三个输入单元,三个隐藏单元和三个输出单元(h[1], h[2], h[3],因为我们要预测的类别是三类)。 这将为我们提供与层关联的权重和偏差的形状。 例如,第 0 层具有 3 个单元,第 1 层具有 3 个单元。与第i层相关联的权重矩阵和偏差向量的形状如下:

因此,形状如下:

  • w[0, 1]将是3x3b[0, 1]将是3

  • w[1, 2]将是3x1b[1, 2]将是1

现在,让我们了解以下符号:

  • w[a(i)]^d(i+1):此处,是指将第i层中的节点a连接到第i + 1层中的节点d的权重值

  • b[i, i+1]^d:此处,它是指将第i层中的偏置单元节点连接到第i + 1层中的节点d的偏置值。

因此,可以通过以下方式计算隐藏层中的节点:

其中,f函数是指激活函数。 记住逻辑回归,其中我们分别使用 Sigmoid 和 softmax a 激活函数进行二进制和多类逻辑回归。

类似地,我们可以这样计算输出单元:

这使我们结束了正向传播过程。 我们的下一个任务是通过反向传播训练神经网络(即训练权重和偏差参数)。

令实际输出类别为y[1], y[2], y[3]

回顾线性回归中的成本函数部分,我们使用交叉熵来表示成本函数。 由于成本函数定义为

其中,C = 3y[c] = Y[c], y_hat[c] = h[c]m为示例数

由于这是一个分类问题,因此对于每个示例,输出将只有一个输出类别为 1,其余的将为零。 例如,对于i,它将是:

因此,成本函数为:

现在,我们的目标是针对Wb将成本函数J最小化。 为了训练我们给定的神经网络,首先随机初始化Wb。 然后,我们将尝试通过梯度下降来优化J,在此我们将以以下方式以学习率α相应地更新Wb

设置好此结构后,我们必须重复执行这些优化步骤(更新Wb),以进行多次迭代以训练我们的神经网络。

这将我们带到了神经网络基础的结尾,它构成了任何浅或深的神经网络的基本构建块。 我们的下一个前沿将是了解一些著名的深度神经网络架构,例如循环神经网络RNN)和卷积神经网络CNN)。 除此之外,我们还将介绍基准的深度神经网络架构,例如 AlexNet,VGG-net 和 Inception。

循环神经网络

循环神经网络,缩写为 RNN,用于序列数据的情况下,无论是作为输入,输出还是两者。 RNN 之所以如此有效,是因为它们的架构可以汇总来自过去数据集的学习,并将其与新数据一起使用以增强学习。 这样,它可以捕获事件的顺序,这在前馈神经网络或统计时间序列分析的早期方法中是不可能的。

考虑时间序列数据,例如股票市场,音频或视频数据集,其中事件的顺序非常重要。 因此,在这种情况下,除了从整个数据中进行集体学习之外,从时间上遇到的数据中学习的顺序也很重要。 这将有助于捕捉潜在趋势。

执行基于序列的学习的能力是使 RNN 高效的原因。 让我们退后一步,尝试了解问题所在。 考虑以下数据图:

假设您有一系列事件,类似于图中的事件,并且您希望在每个时间点都按照事件序列进行决策。 现在,如果您的序列相当稳定,则可以在任何时间步长使用具有相似权重的分类器,但这就是小故障。 如果您以不同的时间步长数据分别运行同一分类器,则对于不同的时间步长,它不会训练为相似的权重。 如果在包含所有时间步数据的整个数据集上运行单个分类器,则权重将相同,但是基于序列的学习会受到阻碍。 对于我们的解决方案,我们希望在不同的时间步长上共享权重,并利用到最后一个时间步长所学到的知识,如下图所示:

根据问题,我们已经了解到我们的神经网络应该能够考虑过去的经验。 可以在前面的示意图中看到这一概念,在第一部分中,它表明在每个时间步长上,网络训练权重都应考虑从过去学习的数据,而第二部分给出解决方案。 我们使用前一个时间步的分类器输出的状态表示作为输入,并使用新的时间步数据来学习当前状态表示。 状态表示可以定义为递归直到最后一个步骤为止所发生事件的集体学习(或总结)。 状态不是分类器的预测输出。 相反,当它受到 softmax 激活函数时,它将产生预测的输出。

为了回想起更远的地方,将需要更深的神经网络。 取而代之的是,我们将使用一个汇总过去的模型,并将该信息以及新信息提供给分类器。

因此,在循环神经网络中的任何时间步长t处,都会发生以下计算:

  • W[h]b[h]是随时间共享的权重和偏差。

  • tanh是激活函数f

  • [h[t-1]; x[t]]指这两个信息的连接。 假设您的输入xₜ的形状为nxd,即n样本/行和d尺寸/列,h[t-1]n*l。 然后,您的连接将得到形状为n*(d+l)的矩阵。

由于任何隐藏状态hᵢ的形状为n*l。 因此,W[h]的形状为(d+l)*lb[h]的形状为l

以来,

在给定的时间步长t中,这些操作构成 RNN 信元单元。 让我们在时间步t可视化 RNN 单元,如下所示:

一旦完成计算直到最后一个时间步,我们的前向传播任务就完成了。 下一个任务是通过反向传播来训练我们的循环神经网络,以使总损失最小化。 一个这样的序列的总损失是所有时间步长上损失的总和,也就是说,给定X值序列及其对应的Y值输出序列,损失如下:

因此,包含m个示例的整个数据集的成本函数为(其中k表示第k个示例):

由于 RNN 合并了序列数据,因此反向传播会随时间扩展到反向传播。 在此,时间是一系列相互连接的有序时间步长,从而可以通过不同的时间步长进行反向传播。

长短期记忆网络

RNN 实际上无法处理长期依赖项。 随着输出序列中的输出数据点与输入序列中的输入数据点之间的距离增加,RNN 无法在两者之间连接信息。 这通常发生在基于文本的任务中,例如机器翻译,音频到文本,以及序列长度较长的更多任务。

长短期记忆网络也称为 LSTM(由 Hochreiter 和 Schmidhuber 引入),能够处理这些长期依赖性。 看一下此处给出的图像:

LSTM 的关键特征是单元状态Cₜ。 这有助于信息保持不变。 我们将从遗忘门层fₜ开始,该层将最后一个隐藏状态,h[t-1]xₜ的连接作为输入,并训练一个神经网络,该神经网络对于其中的每个数字得出 0 到 1 之间的数字。 最后一个单元格状态C[t-1],其中 1 表示保留该值,0 表示忘记该值。 因此,该层将识别过去要忘记的信息,并保留哪些信息。

接下来,我们进入输入门层iₜ和 tanh 层C_tilde[t],它们的任务是确定要添加到过去接收到的信息中的新信息以更新信息,即单元状态。 tanh 层创建新值的向量,而输入门层则标识用于信息更新的那些值中的哪一个。 将此新信息与使用“遗忘门”层fₜ保留的信息结合起来以更新我们的信息,即单元状态Cₜ

=

因此,新的单元状态Cₜ为:

最后,在输出门控层oₜ训练一个神经网络,返回单元状态Cₜ的哪些值作为隐藏状态hₜ输出:

因此,LSTM 单元合并了最后一个单元状态C[t-1],最后一个隐藏状态h[t-1]和当前时间步输入xₜ,并输出了更新后的单元状态Cₜ和当前隐藏状态hₜ

LSTM 是一项突破,因为人们可以通过将 RNN 合并为单元单元来对 RNN 的显着结果进行基准测试。 这是朝着解决与长期依赖有关的问题迈出的重要一步。

卷积神经网络

卷积神经网络或卷积神经网络是在计算机视觉中提供成功结果的深度神经网络。 它们的灵感来自动物视皮层中神经元的组织和信号处理,也就是说,单个皮层神经元会对其相关小区域(视野)中的刺激做出反应,称为感受域 ,并且不同神经元的这些感受域完全重叠,覆盖了整个视野。

当输入空间中的输入包含相同类型的信息时,我们将共享权重并针对这些输入共同训练这些权重。 对于空间数据(例如图像),这种权重共享会导致 CNN。 同样,对于序列数据(例如文本),我们目睹了 RNN 中的这种权重共享。

CNN 在计算机视觉和自然语言处理领域具有广泛的应用。 就行业而言,Facebook 在其自动图像标记算法中使用了它,在图像搜索中使用了 Google,在产品推荐系统中使用了亚马逊,对家用提要进行个性化的 Pinterest,以及用于图像搜索和推荐的 Instagram。

就像神经网络中的神经元(或节点)从最后一层接收输入信号的加权聚合一样,最后一层接受激活函数导致输出。 然后我们反向传播以最小化损失函数。 这是应用于任何类型的神经网络的基本操作,因此适用于 CNN。

与输入为向量形式的神经网络不同,CNN 的输入图像是多通道的,即 RGB(三个通道:红色,绿色和蓝色)。 假设有一个像素大小为a×b的图像,则实际张量表示将为a×b×3形状。

假设您的图片与此处显示的图片相似:

它可以表示为具有宽度,高度的平板,并且由于具有 RGB 通道,因此其深度为 3。 现在,拍摄此图像的小片段,例如2×2,并在其上运行一个微型神经网络,其输出深度为k。 这将导致形状为1×1×k的图形表示。 现在,在不改变权重的情况下在整个图像上水平和垂直滑动此神经网络,将生成另一幅宽度,高度和深度为k的图像(也就是说,现在有k个通道)。

这种整合任务统称为卷积。 通常,ReLU 在以下神经网络中用作激活函数:

在这里,我们将 3 个特征映射(即 RGB 通道)映射到k个特征映射

斑块在图像上的滑动运动称为步幅,而每次移动的像素数(水平或垂直)都称为步幅。 如果补丁没有超出图像空间,则将其视为有效填充。 另一方面,如果色块超出图像空间以映射色块大小,则在该空间之外的色块像素将填充零。 这称为相同填充

CNN 架构由一系列这些卷积层组成。 如果这些卷积层中的跨步值大于 1,则会导致空间缩小。 因此,步幅,斑块大小和激活函数成为超参数。 除卷积层外,有时还会添加一个重要的层,称为池化层。 这将附近的所有卷积合并起来。 池化的一种形式称为最大池化

在最大池中,特征映射会查看补丁中的所有值,并返回其中的最大值。 因此,池大小(即池补丁/窗口大小)和池跨度是超参数。 下图描述了最大池化的概念:

最大池化通常会产生更准确的结果。 类似地,我们具有平均池化,其中取最大值而不是取池窗口中值的平均值,以提供特征映射的低分辨率视图。

通过合并和全连接层来操纵卷积层的超参数和排序,已经创建了许多不同的 CNN 变体,这些变体正在研究和工业领域中使用。 其中一些著名的是 LeNet-5,Alexnet,VGG-Net 和 Inception 模型。

LeNet-5 卷积神经网络

LeNet-5 的架构,来自 LeCunn 等人的《用于文档识别的基于梯度的学习》

LeNet-5 是一个七级卷积神经网络,由 Yann LeCunn,Yoshua Bengio,Leon Bottou 和 Patrick Haffner 于 1998 年组成的团队发布,对数字进行了分类,银行将其用于识别支票上的手写数字。 这些层按以下顺序排序:

  • 输入图片 -> 卷积层 1(ReLU) -> 池化 1 -> 卷积层 2(ReLU) -> 池化 2 -> 全连接(ReLU)1 -> 全连接 2 -> 输出
  • LeNet-5 取得了令人瞩目的结果,但是处理高分辨率图像的能力需要更多的卷积层,例如在 AlexNet,VGG-Net 和 Inception 模型中。

AlexNet 模型

AlexNet 是 LeNet 的一种改进,由 SuperVision 小组设计,该小组由 Alex Krizhevsky,Geoffrey Hinton 和 Ilya Sutskever 组成。 在 2012 年 ImageNet 大规模视觉识别挑战赛中,AlexNet 的前 5 位错误率达到 15.3%,比第二名高出 10 个百分点,创造了历史记录。

该架构使用五个卷积层,三个最大池化层和最后三个全连接层,如下图所示。 该模型总共训练了 6000 万个参数,训练了 120 万张图像,在两个 NVIDIA GTX 580 3GB GPU 上花费了大约五到六天的时间。 下图显示了 AlexNet 模型:

Hinton 等人《用于 ImageNet 分类的深度卷积神经网络的 AlexNet 架构》

卷积层 1 -> 最大池化层 1 -> 归一化层 1 -> 卷积层 2 -> 最大池化层 2 -> 归一化层 2 -> 卷积层 3 -> 卷积层 4 -> 卷积层 5 -> 最大池化层 3 -> 全连接 6 -> 全连接 7 -> 全连接 8 -> 输出

VGG-Net 模型

VGG-Net 由牛津大学视觉几何组VGG)的 Karen Simonyan 和 Andrew Zisserman 引入。 他们使用大小为3 x 3的小型卷积过滤器训练深度为 16 和 19 的网络。他们的团队分别在 ImageNet Challenge 2014 的本地化和分类任务中获得了第一和第二名。

通过向模型添加更多非线性来设计更深层的神经网络的想法导致合并了较小的过滤器,以确保网络没有太多参数。 在训练时,很难收敛模型,因此首先使用预先训练的简单神经网络模型来初始化较深架构的权重。 但是,现在我们可以直接使用 xavier 初始化方法,而无需训练神经网络来初始化权重。 由于模型的深度,训练起来很慢。

Inception 模型

Inception 由 Google 团队于 2014 年创建。其主要思想是创建更广泛的网络,同时限制参数数量并避免过拟合。 下图显示了完整的 Inception 模块:

Szegedy 等人的《从卷积开始深入研究》

它为单个输入应用多个卷积层,并输出每个卷积的堆叠输出。 使用的卷积大小主要为1x13x35x5。 这种架构允许您从相同大小的输入中提取多级特征。 早期版本也称为 GoogLeNet,该版本在 2014 年赢得了 ImageNet 挑战。

深度学习的局限性

深度神经网络是权重和偏置的黑盒,它们经过大量数据训练,可以通过内部表示找到隐藏的模式。 对于人类来说这将是不可能的,即使有可能,那么可伸缩性也是一个问题。 每个神经可能都有不同的权重。 因此,它们将具有不同的梯度。

训练在反向传播期间进行。 因此,训练的方向始终是从较后的层(输出/右侧)到较早的层(输入/左侧)。 与早期的层相比,这导致后面的层学习得很好。 网络越深入,情况恶化的程度就越大。 这引起了与深度学习相关的两个可能的问题,它们是:

  • 梯度消失问题
  • 梯度爆炸问题

梯度消失问题

当早期层中存在的神经元无法学习时,梯度梯度消失是与人工神经网络训练相关的问题之一,因为训练权重的梯度缩小到零。 这是由于神经网络的深度较大,加上带有导数的激活函数导致值较低。

请尝试以下步骤:

  1. 创建一个隐藏层神经网络
  2. 一层一层地添加更多隐藏层

我们观察了所有节点的梯度,发现当我们从后面的层移动到早期的层时,梯度值变得相对较小。 随着层数的增加,这种情况变得更糟。 这表明与后一层神经元相比,前一层神经元学习缓慢。 此条件称为梯度消失问题

梯度爆炸问题

梯度爆炸问题是与训练人工神经网络有关的另一个问题,当在早期层中存在的神经元的学习发生分歧时,因为梯度变得太大而导致权重发生严重变化,从而避免了收敛。 如果权重分配不正确,通常会发生这种情况。

在遵循针对梯度消失问题提到的步骤时,我们观察到梯度在早期层中爆炸,也就是说,它们变大了。 早期层发散的现象称为梯度爆炸问题

克服深度学习的局限性

这两个可能的问题可以通过以下方法克服:

  • 减少使用 Sigmoid 和 tanh 激活函数
  • 使用基于动量的随机梯度下降
  • 权重和偏差的正确初始化,例如 xavier 初始化
  • 正则化(将正则化损失与数据损失一起添加并最小化)

有关更多详细信息,以及消失和梯度爆炸的数学表示,您可以阅读本文:《智能信号:不稳定的深度学习,为什么以及如何解决它们》

强化学习

强化学习是人工智能的一个分支,它与以状态空间和动作空间的形式感知环境信息并作用于环境的主体进行处理,从而产生新的状态并获得作为该动作的反馈的奖励 。 该收到的奖励被分配给新状态。 就像当我们必须最小化成本函数以训练我们的神经网络时一样,在这里强化学习智能体必须最大化整体奖励以找到解决特定任务的最佳策略。

这与有监督和无监督学习有何不同?

在监督学习中,训练数据集具有输入特征X及其对应的输出标签Y。 在此训练数据集上训练一个模型,将具有输入特征X'的测试用例作为输入给出,并且模型预测Y'

在无监督学习中,为训练目的给出了训练集的输入特征X。 没有关联的Y值。 目标是创建一个模型,该模型可通过了解底层模式来学习将数据隔离到不同的群集中,从而对数据进行分类以找到某种用途。 然后将该模型进一步用于输入特征X',以预测它们与聚类之一的相似性。

强化学习与有监督的和无监督的都不同。 强化学习可以指导智能体如何在现实世界中行动。 接口比训练向量更广泛,例如在有监督或无监督学习中。 这是整个环境,可以是真实的世界也可以是模拟的世界。 智能体以不同的方式进行训练,即目标是达到目标状态,这与监督学习的情况不同,后者的目的是使可能性最大化或成本最小化。

强化学习智能体会自动从环境中获得反馈,即从环境中获得奖励,这与监督学习中的标注需要耗时的人力不同。 强化学习的更大优势之一是,以目标的形式表述任何任务的目标有助于解决各种各样的问题。 例如,视频游戏智能体的目标是通过获得最高分数来赢得比赛。 这也有助于发现实现目标的新方法。 例如,当 AlphaGo 成为围棋世界冠军时,它发现了新颖独特的取胜方法。

强化学习智能体就像人一样。 人类进化非常缓慢。 智能体可以增强力量,但它可以很快完成任务。 就感知环境而言,人类和人工智能智能体都无法立即感知整个世界。 感知环境创建了一种状态,在该状态中,智能体执行操作并落入新状态,即新感知的环境不同于早期环境。 这将创建一个既可以有限也可以无限的状态空间。

对此技术感兴趣的最大部门是国防。 强化学习智能体人可以代替不仅步行,还能战斗并做出重要决定的士兵吗?

基本术语和约定

以下是与强化学习相关的基本术语:

  • 智能体:我们是通过编程创建的,因此它能够感知环境,执行动作,接收反馈并尝试获得最大回报。
  • 环境:智能体程序所在的世界。 它可以是真实的或模拟的。
  • 状态:智能体感知的环境感知或配置。 状态空间可以是有限的或无限的。
  • 奖励:座席采取任何措施后收到的反馈。 智能体的目标是最大化整体奖励,即立即和将来的奖励。 奖励是预先定义的。 因此,必须正确创建它们才能有效实现目标。
  • 操作:智能体在给定环境中能够执行的任何操作。 动作空间可以是有限的或无限的。
  • SAR 三元组:(状态,动作,奖励)称为 SAR 三元组,表示为(s, a, r)
  • 剧集:代表整个任务的一次完整运行。

让我们推断下图所示的约定:

每个任务都是一系列的 SAR 三元组。 我们从状态S(t)开始,执行动作A(t),从而收到奖励R(t + 1),然后进入新状态S(t + 1)。 当前状态和动作对为下一步提供了奖励。 由于S(t)A(t)产生了S(t + 1),因此我们有了(当前状态,作用, 新状态),即[S(t), S(t), S(t + 1)](s, a, s')

最优标准

最优性标准是根据数据创建的模型的拟合优度的度量。 例如,在监督分类学习算法中,我们将最大似然性作为最优性标准。 因此,根据问题陈述和客观最优标准不同。 在强化学习中,我们的主要目标是最大化未来的回报。 因此,我们有两个不同的最优性标准,分别是:

  • 值函数:根据未来可能的回报来量化状态
  • 策略:指导智能体在给定状态下应采取的措施

我们将在接下来的主题中详细讨论这两个方面。

最优值函数

智能体应该能够考虑立即和未来的回报。 因此,还会为每个遇到的状态分配一个值,该值也反映了此将来的信息。 这称为值函数。 延迟奖励的概念来了,目前,现在采取的行动将导致未来的潜在奖励。

V(s),即状态的值定义为,从该状态到后续状态直到智能体到达目标状态之前,所有将来在该状态下将要收到的奖励的期望值。 基本上,值函数告诉我们处于这种状态有多好。 值越高,状态越好。

分配给每个(s, a, s')三元组的奖励是固定的。 状态值不是这种情况。 它会随着剧集中的每个动作以及不同剧集而变化。

我们想到一个解决方案,而不是值函数,为什么我们不存储每个可能状态的知识呢?

答案很简单:这既耗时又昂贵,而且成本成倍增长。 因此,最好存储当前状态的知识,即V(s)

V(s) = E[all future rewards discounted | S(t)=s]

关于值函数的更多详细信息将在第 3 章,“马尔可夫决策过程和部分可观察的 MDP”中进行介绍。

最优策略模型

策略被定义为指导智能体在不同状态下进行操作选择的模型。 策略被表示为ππ本质上是在特定状态下某种动作的概率:

因此,策略图将提供给定特定状态的不同操作的概率集。 该策略与值函数一起创建了一个解决方案,可根据策略和状态的计算值来帮助智能体导航。

强化学习的 Q 学习方法

Q 学习是尝试学习在特定状态下向智能体提供的特定操作的值Q(s, a)。 考虑一个表,其中行数代表状态数,而列数代表动作数。 这称为 Q 表。 因此,我们必须学习值,以找出对于给定状态下的智能体而言,哪种行动最合适。

Q 学习涉及的步骤:

  1. 用统一的值(例如全零)初始化Q(s, a)的表。

  2. 观察当前状态s

  3. 通过 ε 贪婪或任何其他动作选择策略选择一个动作a,然后采取该动作

  4. 结果,收到了a的奖励r,并且感知到了新状态s'

  5. 使用以下 Bellman 公式更新表中(s, a)对的Q值:

    其中γ是折扣因子。

  6. 然后,将当前状态的值设置为新状态,并重复该过程以完成一个剧集,即达到终端状态

  7. 运行多个剧集来训练智能体

为简化起见,我们可以说,给定状态s和动作a的 Q 值由当前奖励r以及新状态在其所有操作中的折扣(γ)最大Q最大值。 与当前奖励相比,折扣因子延迟了来自未来的奖励。 例如,今天的 100 奖励在将来值将超过 100。 同样,将来的 100 奖励的当前值必须不到 100。 因此,我们将折扣未来的奖励。 连续重复此更新过程会导致 Q 表值收敛到给定状态下给定操作的预期未来奖励的准确率量。

当状态空间和动作空间的数量增加时,很难维护 Q 表。 在现实世界中,状态空间无限大。 因此,需要另一种无需 Q 表即可生成Q(s, a)方法。 一种解决方案是用函数替换 Q 表。 该函数将状态作为向量形式的输入,并输出给定​​状态下所有动作的 Q 值向量。 该函数逼近器可以由神经网络表示,以预测 Q 值。 因此,当状态和动作空间变大时,我们可以添加更多的层并适合于深度神经网络,以更好地预测 Q 值,这对于 Q 表来说似乎是不可能的。 这样就产生了 Q 网络,如果使用了更深层的神经网络(例如卷积神经网络),那么它会导致深度 Q 网络DQN)。

有关 Q 学习和深度 Q 网络的更多详细信息,将在第 5 章, “Q 学习和深度 Q 网络”中进行介绍。

异步优势演员评论家

A3C 算法由 Google DeepMind 和 MILA 的联合团队于 2016 年 6 月发布。 它更简单并且具有更轻的框架,该框架使用异步梯度下降来优化深度神经网络。 它速度更快,并且能够在多核 CPU 而非 GPU 上显示出良好的结果。 A3C 的一大优势是它可以在连续动作空间和离散动作空间上工作。 结果,它为许多具有复杂状态和动作空间的新挑战性难题打开了门户。

我们将在此处重点讨论,但是我们将在第 6 章,“异步方法”中进行更深入的探讨。 让我们从名称开始,即异步优势演员评论家A3C)算法,然后将其解压缩以获得该算法的基本概述:

  • 异步:在 DQN 中,您还记得我们将神经网络与我们的智能体一起使用来预测动作。 这意味着只有一个智能体,并且它正在与一个环境交互。 A3C 所做的是创建智能体环境的多个副本,以使智能体更有效地学习。 A3C 具有一个全球网络和多个工作器智能体,其中每个智能体都有其自己的一组网络参数,并且每个参数都与其环境副本同时进行交互,而无需与另一个智能体的环境进行交互。 它比单个智能体更好的原因是每个智能体的经验独立于其他智能体的经验。 因此,所有工作器智能体的总体经验导致了各种各样的训练。
  • 演员评论家:演员评论家结合了值迭代和策略迭代的优势。 因此,网络将为给定状态 s 估计值函数V(s)和策略π(s)。 函数逼近器神经网络的顶部将有两个单独的全连接层,分别输出状态的值和状态策略。 智能体使用值,该值充当批评者来更新策略,即,智能角色。
  • 优势:策略梯度使用折扣收益告诉智能体该行动是好是坏。 用优势代替它不仅可以量化操作的好坏状态,而且可以更好地鼓励和劝阻操作(我们将在第 4 章,“策略梯度”中进行讨论)。

TensorFlow 和 OpenAI Gym 简介

TensorFlow 是 Google 的 Google Brain 团队创建的数学库。 由于其数据流编程,它已被用作研究和开发部门的深度学习库。 自 2015 年成立以来,TensorFlow 已发展成为一个非常庞大的社区。

OpenAI Gym 是一个由 OpenAI 团队创建的强化学习操场,旨在提供一个简单的接口,因为创建环境本身是强化学习中的繁琐任务。 它提供了一个很好的环境列表来测试您的强化学习算法,以便您可以对它们进行基准测试。

TensorFlow 中的基本计算

TensorFlow 的基础是我们在本章前面讨论过的计算图张量。 张量是 n 维向量。 因此,标量和矩阵变量也是张量。 在这里,我们将尝试从 TensorFlow 开始的一些基本计算。 请尝试在 python IDE(例如 Jupyter 笔记本)中实现本节。

有关 TensorFlow 的安装和依赖项,请参考以下链接

通过以下命令导入tensorflow

import tensorflow as tf

tf.zeros()tf.ones()是实例化基本张量的一些函数。 tf.zeros()采用张量形状(即元组),并返回该形状的张量,所有值均为零。 同样,tf.ones()采用张量形状,但返回仅包含一个形状的该张量。 在 python shell 中尝试以下命令来创建张量:

>>> tf.zeros(3)

<tf.Tensor 'zeros:0' shape=(3,) dtype=float32>

>>>tf.ones(3)

<tf.Tensor 'ones:0' shape=(3,) dtype=float32>

如您所见,TensorFlow 返回对张量的引用,而不是张量的值。 为了获得该值,我们可以通过运行会话来使用eval()run()(张量对象的函数):

>>> a = tf.zeros(3)
>>> with tf.Session() as sess:
        sess.run(a)
        a.eval()

array([0., 0.,0.], dtype=float32)

array([0., 0.,0.], dtype=float32)

接下来是tf.fill()tf.constant()方法,以创建具有一定形状和值的张量:

>>> a = tf.fill((2,2),value=4.)
>>> b = tf.constant(4.,shape=(2,2))
>>> with tf.Session() as sess:
        sess.run(a)
        sess.run(b)

array([[ 4., 4.],
[ 4., 4.]], dtype=float32)

array([[ 4., 4.],
[ 4., 4.]], dtype=float32)

接下来,我们有一些函数可以随机初始化张量。 其中,最常用的是:

  • tf.random_normal:从指定平均值和标准差的正态分布中采样随机值
  • tf.random_uniform():从指定范围的均匀分布中采样随机值
>>> a = tf.random_normal((2,2),mean=0,stddev=1)
>>> b = tf.random_uniform((2,2),minval=-3,maxval=3)
>>> with tf.Session() as sess:
        sess.run(a)
        sess.run(b)

array([[-0.31790468, 1.30740941],
[-0.52323157, -0.2980336 ]], dtype=float32)

array([[ 1.38419437, -2.91128755],
[-0.80171156, -0.84285879]], dtype=float32)

TensorFlow 中的变量是张量的持有者,并由函数tf.Variable()定义:

>>> a = tf.Variable(tf.ones((2,2)))
>>> a

<tf.Variable 'Variable:0' shape=(2, 2) dtype=float32_ref>

如果使用变量,则评估失败,因为必须在会话中使用tf.global_variables_initializer明确初始化它们:

>>> a = tf.Variable(tf.ones((2,2)))
>>> with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        a.eval()

array([[ 1., 1.],
[ 1., 1.]], dtype=float32)

队列中的下一个,我们有矩阵。 身份矩阵是对角线为 1 且其他位置为零的正方形矩阵。 这可以通过function tf.eye()完成:

>>> id = tf.eye(4) #size of the square matrix = 4
>>> with tf.Session() as sess:
         sess.run(id)

array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]], dtype=float32)

同样,也有对角矩阵,其对角线的值和其他地方的零,如下所示:

>>> a = tf.range(1,5,1)
>>> md = tf.diag(a)
>>> mdn = tf.diag([1,2,5,3,2])
>>> with tf.Session() as sess:
        sess.run(md)
        sess.run(mdn)

array([[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]], dtype=int32)

array([[1, 0, 0, 0, 0],
[0, 2, 0, 0, 0],
[0, 0, 5, 0, 0],
[0, 0, 0, 3, 0],
[0, 0, 0, 0, 2]], dtype=int32)

我们使用tf.matrix_transpose()函数对给定矩阵进行转置,如下所示:

>>> a = tf.ones((2,3))
>>> b = tf.transpose(a)
>>> with tf.Session() as sess:
        sess.run(a)
        sess.run(b)

array([[ 1., 1., 1.],
[ 1., 1., 1.]], dtype=float32)

array([[ 1., 1.],
[ 1., 1.],
[ 1., 1.]], dtype=float32)

下一个矩阵运算是矩阵乘法函数,如下所示。 这是通过函数tf.matmul()完成的:

>>> a = tf.ones((3,2))
>>> b = tf.ones((2,4))
>>> c = tf.matmul(a,b)
>>> with tf.Session() as sess:
        sess.run(a)
        sess.run(b)
        sess.run(c)

array([[ 1., 1.],
[ 1., 1.],
[ 1., 1.]], dtype=float32)

array([[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.]], dtype=float32)

array([[ 2., 2., 2., 2.],
[ 2., 2., 2., 2.],
[ 2., 2., 2., 2.]], dtype=float32)

使用tf.reshape()函数将张量从一个重塑为另一个,如下所示:

>>> a = tf.ones((2,4)) #initial shape is (2,4)
>>> b = tf.reshape(a,(8,)) # reshaping it to a vector of size 8\. Thus shape is (8,)
>>> c = tf.reshape(a,(2,2,2)) #reshaping tensor a to shape (2,2,2)
>>> d = tf.reshape(b,(2,2,2)) #reshaping tensor b to shape (2,2,2) 
#####Thus, tensor 'c' and 'd' will be similar
>>> with tf.Session() as sess:
        sess.run(a)
        sess.run(b)
        sess.run(c)
        sess.run(d)

array([[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.]], dtype=float32)

array([ 1., 1., 1., 1., 1., 1., 1., 1.], dtype=float32)

array([[[ 1., 1.],
[ 1., 1.]],
[[ 1., 1.],
[ 1., 1.]]], dtype=float32)
&gt;
array([[[ 1., 1.],
[ 1., 1.]],
[[ 1., 1.],
[ 1., 1.]]], dtype=float32)

TensorFlow 中的计算流程表示为一个计算图,作为tf.Graph的实例。 该图包含张量和操作对象,并跟踪涉及的一系列操作和张量。 图的默认实例可以通过tf.get_default_graph()获取:

>>> tf.get_default_graph()

<tensorflow.python.framework.ops.Graph object at 0x7fa3e139b550>

在接下来的章节中,我们将在 TensorFlow 中探索复杂的操作,神经网络的创建以及更多内容。

OpenAI Gym 简介

由 OpenAI 团队创建的 OpenAI Gym 是一个在不同环境中运动的场所,您可以在其中开发和比较强化学习算法。 它与 TensorFlow 和 Theano 等深度学习库兼容。

OpenAI Gym 由两部分组成:

  • Gym 开源代码库:它包含许多环境,可以解决不同的测试问题,您可以在其中测试您的强化学习算法。 这足以满足状态和操作空间的信息。
  • OpenAI Gym 服务:这使您可以将座席的表现与其他经过训练的座席进行比较。

有关安装和依赖项,请参考以下链接

在介绍了基础知识之后,现在我们将从下面的第 2 章“使用 OpenAI Gym 训练强化学习智能体”开始使用 OpenAI Gym 实现强化学习。

强化学习的先驱与突破

在继续进行所有编码之前,让我们阐明一些在深度强化学习领域中的先驱,行业领导者和研究突破。

David Silver

David Silver 博士的 H 指数为 30,是 Google DeepMind 强化学习研究团队的负责人,也是 AlphaGo 的首席研究员。 David 共同创立了 Elixir Studios,然后在艾伯塔大学获得了强化学习博士学位,在那里他共同介绍了第一个大师级9x9围棋程序中使用的算法。 此后,他成为伦敦大学学院的讲师。 在 2013 年加入全职之前,他曾为 DeepMind 担任顾问。David 领导了 AlphaGo 项目,该项目成为在围棋游戏中击败顶级职业玩家的第一个程序。

Pieter Abbeel

Pieter Abbeel 是加州大学伯克利分校的教授,也是 OpenAI 的研究科学家。 Pieter 在 Ng 的带领下完成了计算机科学博士学位。 他目前的研究重点是机器人技术和机器学习,尤其是深度强化学习,深度模仿学习,深度无监督学习,元学习,学习到学习和 AI 安全。 Pieter 还获得了 NIPS 2016 最佳论文奖。

Google DeepMind

Google DeepMind 是一家英国人工智能公司,成立于 2010 年 9 月,并于 2014 年被 Google 收购。它们是深度强化学习和神经图灵机领域的行业领导者。 当 AlphaGo 计划击败了 9 段围棋选手 Lee Sedol 时,他们在 2016 年发布了新闻。 Google DeepMind 已将重点转移到两个大领域:能源和医疗保健。

以下是其一些项目:

  • 2016 年 7 月,Google DeepMind 与 Moorfields 眼科医院宣布合作,使用眼部扫描技术研究导致失明的疾病的早期征兆
  • 2016 年 8 月,Google DeepMind 宣布与伦敦大学学院医院合作研究和开发一种算法,以自动微分头部和颈部的健康组织和癌性组织
  • Google DeepMind AI 将 Google 的数据中心散热费用降低了 40%

AlphaGo 程序

正如 Google DeepMind 先前所述,AlphaGo 是一种计算机程序,它首先击败了 Lee Sedol,然后击败了当时在围棋中排名世界第一的 Ke Jie。 在 2017 年的改进版本中,AlphaGo Zero 发布,击败了 AlphaGo 100 场比赛至 0 局。

Libratus

Libratus 是由卡内基梅隆大学的 Tuomas Sandholm 教授带领的团队设计的人工智能计算机程序,用于玩扑克。 Libratus 和它的前身克劳迪科有着相同的含义,平衡。

2017 年 1 月,它在一场为期 20 天的马拉松比赛中击败了世界上最好的四名职业扑克选手,创造了历史。

尽管 Libratus 专注于玩扑克,但其设计师提到了它能够学习任何信息不完整且对手参与欺骗的游戏的能力。 结果,他们提出该系统可以应用于网络安全,商务谈判或医疗计划领域中的问题。

总结

在本章中,我们涵盖了构建模块,例如包括逻辑回归的浅层和深度神经网络,单隐藏层神经网络,RNN,LSTM,CNN 及其其他变体。 针对这些主题,我们还介绍了多个激活函数,正向和反向传播的工作方式以及与深度神经网络训练相关的问题,例如消失和梯度爆炸。

然后,我们涵盖了强化学习中非常基本的术语,我们将在接下来的章节中对其进行详细探讨。 这些是最优标准,即值函数和策略。 我们还了解了一些强化学习算法,例如 Q 学习和 A3C 算法。 然后,我们在 TensorFlow 框架中介绍了一些基本计算,这是 OpenAI Gym 的简介,还讨论了强化学习领域的一些有影响力的先驱者和研究突破。

在下一章中,我们将对几个 OpenAI Gym 框架环境实现基本的强化学习算法,并更好地理解 OpenAI Gym。

二、使用 OpenAI Gym 训练强化学习智能体

OpenAI Gym 提供了许多虚拟环境来训练您的强化学习智能体。 在强化学习中,最困难的任务是创造环境。 OpenAI Gym 通过提供许多玩具游戏环境为用户提供了一个平台,以训练和确定他们的强化学习智能体,从而为救援提供了帮助。

换句话说,它为强化学习智能体提供了一个学习和基准化他们的表现的场所,其中智能体必须学会从开始状态导航到目标状态,而不会遭受任何不幸。

因此,在本章中,我们将学习从 OpenAI Gym 了解和使用环境,并尝试实现基本的 Q 学习和 Q 网络,供我们的智能体学习。

OpenAI Gym 提供不同类型的环境。 它们如下:

  • 经典控制
  • 算法化
  • Atari
  • 棋盘游戏
  • Box2D
  • 参数调整
  • MuJoCo
  • 玩具文本
  • Safety
  • Minecraft
  • PyGame 学习环境
  • 足球
  • Doom

有关这些广泛的环境类别及其环境游乐场的详细信息,请访问这个页面

我们将在本章介绍以下主题:

  • OpenAI Gym 环境
  • 使用 OpenAI Gym 环境对智能体进行编程
  • 将 Q 网络用于实际应用

OpenAI Gym

为了下载并安装 OpenAI Gym,您可以使用以下任一选项:

$ git clone https://github.com/openai/gym 
$ cd gym 
$ sudo pip install -e . # minimal install

这将进行最小安装。 您以后可以运行以下命令进行完整安装:

$ sudo pip install -e .[all]

您还可以按以下说明将 Gym 作为不同 Python 版本的包来获取:

对于 Python 2.7,可以使用以下选项:

$ sudo pip install gym              # minimal install
$ sudo pip install gym[all]         # full install 
$ sudo pip install gym[atari]       # for Atari specific environment installation

对于 Python 3.5,可以使用以下选项:

$ sudo pip3 install gym              # minimal install
$ sudo pip3 install gym[all]         # full install
$ sudo pip install gym[atari]        # for Atari specific environment installation

了解 OpenAI Gym 环境

为了了解导入 Gym 包,加载环境以及与 OpenAI Gym 相关的其他重要功能的基础,这里是冰冻湖环境的示例。

通过以下方式加载冰冻湖环境:

import Gym 
env = Gym.make('FrozenLake-v0')   #make function of Gym loads the specified environment

接下来,我们来重置环境。 在执行强化学习任务时,智能体会经历多个剧集的学习。 结果,在每个剧集开始时,都需要重置环境,使其恢复到初始状态,并且智能体从开始状态开始。 以下代码显示了重置环境的过程:

import Gym 
env = Gym.make('FrozenLake-v0') 
s = env.reset()  # resets the environment and returns the start state as a value
print(s)

-----------
0                #initial state is 0

在执行每个操作之后,可能需要显示智能体在环境中的状态。 通过以下方式可视化该状态:

env.render()

------------
SFFF
FHFH
FFFH
HFFG

前面的输出显示这是一个4 x 4网格的环境,即以前面的方式排列的 16 个状态,其中SHFG表示状态的不同形式,其中:

  • S:开始块
  • F:冻结块
  • H:块有孔
  • G:目标块

在较新版本的“体育馆”中,不能直接修改环境特征。 这可以通过以下方式解开环境参数来完成:

env = env.unwrapped

每个环境都由状态空间和供智能体执行的操作空间定义。 为了构建增强学习智能体,了解状态空间和动作空间的类型(离散或连续)和大小非常重要:

print(env.action_space)
print(env.action_space.n)

----------------
Discrete(4)
4 

Discrete(4)输出表示冰冻湖环境的动作空间是一组离散值,并且具有可由智能体执行的四个不同的动作。

print(env.observation_space)
print(env.observation_space.n)

----------------
Discrete(16)
16

Discrete(16)输出表示冻结湖环境的观察(状态)空间是一组离散值,并具有 16 种要由智能体探索的不同状态。

使用 OpenAI Gym 环境对智能体编程

本节考虑的环境是 FrozenLake-v0。 有关环境的实际文档可以在这个页面中找到。

此环境由代表一个湖泊的4 x 4网格组成。 因此,我们有 16 个网格块,其中每个块可以是开始块(S),冻结块(F),目标块(G)或孔块(H)。 因此,智能体程序的目标是学会从头到尾进行导航而不会陷入困境:

import Gym
env = Gym.make('FrozenLake-v0')    #loads the environment FrozenLake-v0
env.render()                       # will output the environment and position of the agent

-------------------
SFFF
FHFH
FFFH
HFFG

在任何给定状态下,智能体都有四个要执行的动作,分别是上,下,左和右。 除了导致目标状态的那一步外,每一步的奖励都是 0,那么奖励将是 1。我们从S状态开始,我们的目标是达到G状态而不以最优化的路径通过F状态降落到H状态。

Q 学习

现在,让我们尝试使用 Q 学习对增强学习智能体进行编程。 Q 学习由一个 Q 表组成,该表包含每个状态动作对的 Q 值。 表中的行数等于环境中的状态数,而列数等于操作数。 由于状态数为16,而动作数为4,因此此环境的 Q 表由16行和4列组成。 它的代码在这里给出:

print("Number of actions : ",env.action_space.n)
print("Number of states : ",env.observation_space.n)

----------------------
Number of actions : 4 
Number of states : 16

Q 学习涉及的步骤如下:

  1. 用零初始化 Q 表(最终,更新将随着学习过程中所采取的每个操作收到的奖励而发生)。

  2. 更新一个状态-动作对的 Q 值,即Q(s, a)的方法是:

在此公式中:

  1. 通过按照步骤 2 中提到的公式更新 Q 值,该表收敛以获取给定状态下某个动作的准确值。

ε 贪婪方法

ε 贪婪是探索-利用困境的一种广泛使用的解决方案。 探索就是通过实验和研究来搜索和探索新的选择以产生新的值,而探索则是通过重复这些选择并提高其值来完善现有的选择。

ε 贪婪方法非常易于理解且易于实现:

epsilon() = 0.05 or 0.1 #any small value between 0 to 1
#epsilon() is the probability of exploration

p = random number between 0 and 1

if p  epsilon() :
    pull a random action
else:
    pull current best action

最终,经过几次迭代,我们发现了每个状态中所有状态中的最佳操作,因为它可以选择探索新的随机操作以及利用现有操作并对其进行优化。

让我们尝试实现一种基本的 Q 学习算法,以使智能体学习如何在从头到尾的 16 个网格的冰冻湖面中导航,而不会陷入困境:

# importing dependency libraries
from __future__ import print_function
import Gym
import numpy as np
import time

#Load the environment

env = Gym.make('FrozenLake-v0')

s = env.reset()
print("initial state : ",s)
print()

env.render()
print()

print(env.action_space) #number of actions
print(env.observation_space) #number of states
print()

print("Number of actions : ",env.action_space.n)
print("Number of states : ",env.observation_space.n)
print()

#Epsilon-Greedy approach for Exploration and Exploitation of the state-action spaces
def epsilon_greedy(Q,s,na):
    epsilon = 0.3
    p = np.random.uniform(low=0,high=1)
    #print(p)
    if p > epsilon:
        return np.argmax(Q[s,:])#say here,initial policy = for each state consider the action having highest Q-value
    else:
        return env.action_space.sample()

# Q-Learning Implementation

#Initializing Q-table with zeros
Q = np.zeros([env.observation_space.n,env.action_space.n])

#set hyperparameters
lr = 0.5 #learning rate
y = 0.9 #discount factor lambda
eps = 100000 #total episodes being 100000

for i in range(eps):
    s = env.reset()
    t = False
    while(True):
        a = epsilon_greedy(Q,s,env.action_space.n)
        s_,r,t,_ = env.step(a)
        if (r==0): 
            if t==True:
                r = -5 #to give negative rewards when holes turn up
                Q[s_] = np.ones(env.action_space.n)*r #in terminal state Q value equals the reward
            else:
                r = -1 #to give negative rewards to avoid long routes
        if (r==1):
                r = 100
                Q[s_] = np.ones(env.action_space.n)*r #in terminal state Q value equals the reward
        Q[s,a] = Q[s,a] + lr * (r + y*np.max(Q[s_,a]) - Q[s,a])
        s = s_ 
        if (t == True) :
            break

print("Q-table")
print(Q)
print()

print("Output after learning")
print()
#learning ends with the end of the above loop of several episodes above
#let's check how much our agent has learned
s = env.reset()
env.render()
while(True):
    a = np.argmax(Q[s])
    s_,r,t,_ = env.step(a)
    print("===============")
    env.render()
    s = s_
    if(t==True) :
        break
----------------------------------------------------------------------------------------------
<<OUTPUT>>

initial state : 0

SFFF
FHFH
FFFH
HFFG

Discrete(4)
Discrete(16)

Number of actions : 4
Number of states : 16

Q-table
[[  -9.85448046   -7.4657981    -9.59584501  -10\.        ]
 [  -9.53200011   -9.54250775   -9.10115662  -10\.        ]
 [  -9.65308982   -9.51359977   -7.52052469  -10\.        ]
 [  -9.69762313   -9.5540111    -9.56571455  -10\.        ]
 [  -9.82319854   -4.83823005   -9.56441915   -9.74234959]
 [  -5\.           -5\.           -5\.           -5\.        ]
 [  -9.6554905    -9.44717167   -7.35077759   -9.77885057]
 [  -5\.           -5\.           -5\.           -5\.        ]
 [  -9.66012445   -4.28223592   -9.48312882   -9.76812285]
 [  -9.59664264    9.60799515   -4.48137699   -9.61956668]
 [  -9.71057124   -5.6863911    -2.04563412   -9.75341962]
 [  -5\.           -5\.           -5\.           -5\.        ]
 [  -5\.           -5\.           -5\.           -5\.        ]
 [  -9.54737964   22.84803205   18.17841481   -9.45516929]
 [  -9.69494035   34.16859049   72.04055782   40.62254838]
 [ 100\.          100\.          100\.          100\.        ]]

Output after learning

SFFF
FHFH
FFFH
HFFG
===============
  (Down)
SFFF
FHFH
FFFH
HFFG
===============
  (Down)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG
===============
 (Right)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG
===============
  (Right)
SFFF
FHFH
FFFH
HFFG

将 Q 网络用于实际应用

维护少数状态的表是可能的,但在现实世界中,状态会变得无限。 因此,需要一种解决方案,其合并状态信息并输出动作的 Q 值而不使用 Q 表。 这是神经网络充当函数逼近器的地方,该函数逼近器针对不同状态信息的数据及其所有动作的相应 Q 值进行训练,从而使它们能够预测任何新状态信息输入的 Q 值。 用于预测 Q 值而不是使用 Q 表的神经网络称为 Q 网络。

在这里,对于FrozenLake-v0环境,让我们使用一个将状态信息作为输入的单个神经网络,其中状态信息表示为一个1 x 状态形状的单热编码向量(此处为1 x 16)并输出形状为1 x 动作数的向量(此处为1 x 4)。 输出是所有操作的 Q 值:

# considering there are 16 states numbered from state 0 to state 15, then state number 4 will be # represented in one hot encoded vector as
input_state = [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0]

通过添加更多隐藏层和不同激活函数的选择,Q 网络绝对比 Q 表具有许多优势。 与 Q 表不同,在 Q 网络中,通过最小化反向传播的损失来更新 Q 值。 损失函数由下式给出:

让我们尝试用 Python 来实现这一点,并学习如何实现基本的 Q 网络算法,以使智能体从头到尾在整个 16 个网格的冰冻湖面中导航,而不会陷入困境:

# importing dependency libraries
from __future__ import print_function
import Gym
import numpy as np
import tensorflow as tf
import random

# Load the Environment
env = Gym.make('FrozenLake-v0')

# Q - Network Implementation

## Creating Neural Network

tf.reset_default_graph()
# tensors for inputs, weights, biases, Qtarget
inputs = tf.placeholder(shape=[None,env.observation_space.n],dtype=tf.float32)
W = tf.get_variable(name="W",dtype=tf.float32,shape=[env.observation_space.n,env.action_space.n],initializer=tf.contrib.layers.xavier_initializer())
b = tf.Variable(tf.zeros(shape=[env.action_space.n]),dtype=tf.float32)

qpred = tf.add(tf.matmul(inputs,W),b)
apred = tf.argmax(qpred,1)

qtar = tf.placeholder(shape=[1,env.action_space.n],dtype=tf.float32)
loss = tf.reduce_sum(tf.square(qtar-qpred))

train = tf.train.AdamOptimizer(learning_rate=0.001)
minimizer = train.minimize(loss)

## Training the neural network

init = tf.global_variables_initializer() #initializing tensor variables
#initializing parameters
y = 0.5 #discount factor
e = 0.3 #epsilon value for epsilon-greedy task
episodes = 10000 #total number of episodes

with tf.Session() as sess:
    sess.run(init)
    for i in range(episodes):
        s = env.reset() #resetting the environment at the start of each episode
        r_total = 0 #to calculate the sum of rewards in the current episode
        while(True):
            #running the Q-network created above
            a_pred,q_pred = sess.run([apred,qpred],feed_dict={inputs:np.identity(env.observation_space.n)[s:s+1]})
            #a_pred is the action prediction by the neural network
 #q_pred contains q_values of the actions at current state 's'
            if np.random.uniform(low=0,high=1) < e: #performing epsilon-greedy here
                a_pred[0] = env.action_space.sample()
                #exploring different action by randomly assigning them as the next action
            s_,r,t,_ = env.step(a_pred[0]) #action taken and new state 's_' is encountered with a feedback reward 'r'
            if r==0: 
                if t==True:
                    r=-5 #if hole make the reward more negative
                else:
                    r=-1 #if block is fine/frozen then give slight negative reward to optimize the path
            if r==1:
                r=5 #good positive goat state reward

            q_pred_new = sess.run(qpred,feed_dict={inputs:np.identity(env.observation_space.n)[s_:s_+1]})
            #q_pred_new contains q_values of the actions at the new state 

            #update the Q-target value for action taken
            targetQ = q_pred
            max_qpredn = np.max(q_pred_new)
            targetQ[0,a_pred[0]] = r + y*max_qpredn
            #this gives our targetQ

 #train the neural network to minimize the loss
            _ = sess.run(minimizer,feed_dict={inputs:np.identity(env.observation_space.n)[s:s+1],qtar:targetQ})

            s=s_
            if t==True:
                break

    #learning ends with the end of the above loop of several episodes above
 #let's check how much our agent has learned
    print("Output after learning")
    print()
    s = env.reset()
    env.render()
    while(True):
        a = sess.run(apred,feed_dict={inputs:np.identity(env.observation_space.n)[s:s+1]})
        s_,r,t,_ = env.step(a[0])
        print("===============")
        env.render()
        s = s_
        if t==True:
            break
-----------------------------------------------------------------------------------------------
<<OUTPUT>>

Output after learning

SFFF
FHFH
FFFH
HFFG
===============
 (Down)
SFFF
FHFH
FFFH
HFFG
===============
 (Left)
SFFF
FHFH
FFFH
HFFG
===============
 (Up)
SFFF
FHFH
FFFH
HFFG
===============
 (Down)
SFFF
FHFH
FFFH
HFFG
===============
 (Right)
SFFF
FHFH
FFFH
HFFG
===============
 (Right)
SFFF
FHFH
FFFH
HFFG
===============
 (Up)
SFFF
FHFH
FFFH
HFFG

Q 学习和 Q 网络都需要付出一定的稳定性。 在某些情况下,如果给定的 Q 值超参数集未收敛,但具有相同的超参数,则有时会出现收敛。 这是由于这些学习方法的不稳定。 为了解决这个问题,如果状态空间较小,则应定义更好的初始策略(此处为给定状态的最大 Q 值)。 此外,超参数,尤其是学习率,折扣因子和ε值,起着重要的作用。 因此,必须正确初始化这些值。

由于增加了状态空间,因此与 Q 学习相比,Q 网络具有更大的灵活性。 Q 网络中的深度神经网络可能会导致更好的学习和表现。 就使用深度状态 Q 网络玩 Atari 而言,有许多调整,我们将在接下来的章节中进行讨论。

总结

在本章中,我们学习了 OpenAI Gym,包括安装各种重要功能以加载,渲染和理解环境状态操作空间。 我们了解了 ε 贪婪方法作为探索与利用难题的解决方案,并尝试实现基本的 Q 学习和 Q 网络算法,以训练增强学习智能体从 OpenAI Gym 导航环境。

在下一章中,我们将介绍强化学习中最基本的概念,包括马尔可夫决策过程MDP),贝尔曼方程和 Markov Chain Monte Carlo。

三、马尔可夫决策过程

马尔可夫决策过程(通常称为 MDP)是一种强化学习的方法,可用于在网格世界环境中进行决策。 Gridworld 环境由网格形式的状态组成,例如 OpenAI Gym 的 FrozenLake-v0 环境中的状态,我们在上一章中试图进行研究和解决。

MDP 试图通过将网格划分为状态,动作,模型/转换模型和奖励来捕获网格形式的世界。 MDP 的解决方案称为策略,目标是为该 MDP 任务找到最佳策略。

因此,任何遵循 Markov 属性的,由一组状态,动作和奖励组成的强化学习任务都将被视为 MDP。

在本章中,我们将深入研究 MDP,状态,动作,奖励,策略,以及如何使用贝尔曼方程求解它们。 此外,我们将介绍部分可观察的 MDP 的基础知识及其解决的复杂性。 我们还将介绍探索利用难题和著名的 E3(开发,探索或利用)算法。 然后我们将进入引人入胜的部分,在该部分中,我们将为智能体编程,以使用 MDP 原理学习和玩乒乓球。

我们将在本章介绍以下主题:

  • 马尔可夫决策过程
  • 部分可观察的马尔可夫决策过程
  • 使用 MDP 训练 FrozenLake-v0 环境

马尔可夫决策过程

如前所述,MDP 是网格世界环境中的强化学习方法,其中包含状态,动作和奖励集,遵循马尔可夫属性以获得最佳策略。 MDP 被定义为以下各项的集合:

  • 状态S
  • 动作A(s), A
  • 转移模型T(s, a, s') ~ P(s' | s, a)
  • 奖励R(s), R(s, a), R(s, a, s')
  • 策略π(s) -> a[π*]是最佳策略

对于 MDP,环境是完全可观察的,也就是说,智能体在任何时间点所做的任何观察都足以做出最佳决策。 在部分可观察的环境中,智能体程序需要一个内存来存储过去的观察结果,以便做出最佳决策。

让我们尝试将其分解为不同的乐高积木,以了解整个过程的含义。

马尔可夫属性

简而言之,根据马尔可夫属性,为了了解不久的将来的信息(例如,在时间t + 1),当前信息在时间t很重要。

给定序列[x[1], ..., x[t]],马尔可夫一阶表示P(x[t] | x[t-1], ..., x[1]) = P(x[t] | x[t-1]),即xₜ仅取决于x[t-1]。 因此,x[t+1]将仅取决于xₜ。 马尔可夫的二阶表示P(x[t] | x[t-1], ..., x[1]) = P(x[t] | x[t-1], x[t-2]),即xₜ仅取决于x[t-1]x[t-2]

在我们的上下文中,从现在开始,我们将遵循马尔科夫属性的一阶。 因此,如果新状态的概率x[t+1]仅取决于当前状态xₜ,则我们可以将任何过程转换为马尔科夫属性,以便当前状态捕获并记住过去的属性和知识 。 因此,根据马尔可夫属性,世界(即环境)被认为是固定的,也就是说,世界中的规则是固定的。

S状态集

S状态集是构成环境的一组不同状态,表示为s。 状态是从环境获得的数据的特征表示。 因此,来自智能体传感器的任何输入都可以在状态形成中发挥重要作用。 状态空间可以是离散的也可以是连续的。 从开始状态开始,必须以最优化的路径达到目标状态,而不会在不良状态下结束(例如下图所示的红色状态)。

考虑以下网格世界,它具有 12 个离散状态,其中绿色网格是目标状态,红色是要避免的状态,黑色是一面碰到墙壁就会反弹的墙壁:

状态可以表示为 1、2,.....,12 或由坐标(1, 1)(1, 2),.....(3, 4)表示。

动作

动作是智能体可以在特定状态下执行或执行的操作。 换句话说,动作是允许智能体在给定环境中执行的一组操作。 像状态一样,动作也可以是离散的或连续的。

考虑以下具有 12 个离散状态和 4 个离散动作(UPDOWNRIGHTLEFT)的 gridworld 示例:

前面的示例将动作空间显示为离散的设置空间,即a ∈ A,其中A = {UP, DOWN, LEFT, RIGHT}。 也可以将其视为状态的函数,即a = A(s),其中根据状态函数来确定可能采取的行动。

转移模型

转移模型T(s, a, s')是三个变量的函数,它们是当前状态(s),动作(a) 以及新状态(s'),并定义了在环境中玩游戏的规则。 它给出了P(s' | s, a)的概率,也就是说,假设智能体采取了行动a,在给定状态s下降落到新的s'状态的概率。

转移模型在随机世界中起着至关重要的作用,与确定性世界的情况不同,在确定性世界中,除了确定的着陆状态之外,任何着陆状态的概率都为零。

让我们考虑以下环境(世界),并考虑确定和随机的不同情况:

由于动作a ∈ A,其中A = {UP, DOWN, LEFT, RIGHT}

这两种情况的行为取决于某些因素:

  • 确定的环境:在确定的环境中,如果您采取某种行动,例如说UP,则您肯定会以概率 1 执行该行动。
  • 随机环境:在随机环境中,如果您执行相同的操作(例如说UP),则有一定的概率说 0.8 可以实际执行给定的操作,而有 0.1 的概率可以执行垂直于给定UP动作的动作(LEFTRIGHT)。 在此,对于s状态和UP动作转换模型,T(s', UP, s) = P(s' | s, UP) = 0.8

由于T(s, a, s') ~ P(s' | s, a),因此新状态的概率仅取决于当前状态和操作,而与过去状态无关。 因此,转移模型遵循一阶马尔可夫性质。

我们也可以说我们的宇宙也是一个随机环境,因为宇宙是由处于不同状态的原子组成的,这些原子由位置和速度定义。 每个原子执行的动作都会改变其状态,并导致宇宙发生变化。

奖励

状态的奖励量化了进入状态的有用性。 有三种不同的形式来表示奖励,即R(s)R(s, a)R(s, a, s'),但它们都是等效的。

对于特定环境,领域知识在不同状态的奖励分配中起着重要作用,因为奖励中的细微变化对于找到 MDP 问题的最佳解决方案确实很重要。

当采取某种行动时,我们会奖励智能体以两种方式。 他们是:

  • 信用分配问题:我们回顾过去,检查哪些活动导致了当前的奖励,即哪个活动获得了荣誉
  • 延迟奖励:相比之下,在当前状态下,我们检查要采取的行动会导致我们获得潜在的奖励

延迟的报酬形成了远见规划的想法。 因此,该概念被用于计算不同状态的预期奖励。 我们将在后面的部分中对此进行讨论。

策略

到现在为止,我们已经解决了造成 MDP 问题的块,即状态,动作,转移模型和奖励,现在是解决方案。 该策略是解决 MDP 问题的方法。

策略是将状态作为输入并输出要采取的措施的函数。 因此,该策略是智能体必须遵守的命令。

被称为最佳策略,它使预期收益最大化。 在采取的所有策略中,最优策略是一种优化的策略,用于最大化一生中已收到或预期收到的奖励金额。 对于 MDP,生命周期没有尽头,您必须确定结束时间。

因此,该策略不过是一个指南,它告诉您针对给定状态应采取的行动。 它不是计划,而是通过返回针对每个状态要采取的行动来揭示环境的基础计划。

奖励序列-假设

奖励序列在找到 MDP 问题的最佳策略中起着重要作用,但是有一些假设揭示了一系列奖励如何实现延迟奖励的概念。

无限的视野

第一个假设是无限的视野,即从起始状态到达目标状态的无限时间步长。 因此,

策略函数未考虑剩余时间。 如果是有限期的话,那么策略应该是

其中t是完成任务所需的时间。

因此,如果没有无限远景的假设,那么策略的概念就不会是固定不变的,即π(s) -> a,而是π(s, t) -> a

序列的效用

序列的效用是指当智能体经历状态序列时所获得的总报酬。 它表示为U(s[0], s[1], s[2], ...),其中s[0], s[1], s[2], ...表示状态序列。

第二个假设是,如果有两个效用U(s[0], s[1], s[2], ...)U(s[0], s'[1], s'[2], ...),则两个序列的开始状态都相同,并且

然后,

这意味着,如果序列U(s[0], s[1], s[2], ...)的效用大于另一个函数U(s[0], s'[1], s'[2], ...),只要两个序列的起始状态都相同,那么没有该起始状态的序列将具有相同的不等式,即U(s[1], s[2], ...)将大于U(s'[1], s'[2], ...)。 这种假设称为偏好的平稳性。

因此,以下等式满足了偏好的平稳性,

上式中的求和足以满足我们的假设,但它有两个缺点,如下所示:

  • 无限的时间将使求和无限
  • 求和的大小写或顺序无异,即U(a, b, c)U(a, c, b)的效用值相同,即R(a) + R(b) + R(c)

因此,我们采用折扣系数γ来实现未来奖励的概念,即延迟奖励。

其中0 <= γ < 1

让我们考虑所有R(s[t]),即在给定特定环境中来自不同状态的奖励,R_max是最大值,然后

怎么样? 让我们算出这个上限,

由于R(s[t]) <= R_max

因此,γᵗ R(s[t]) <= γᵗ R_max

因此,

让,

然后,

从而,

因此,

贝尔曼方程

由于最佳π*策略是使预期收益最大化的策略,因此,

其中E[...]表示从状态序列获得的报酬的期望值,智能体观察其是否遵循π策略。 因此,argmax[π]输出具有最高预期奖励的π策略。

同样,我们也可以计算状态为的策略效用,也就是说,如果我们处于s状态,则给定π策略,则, s状态的π策略,即U[π](s)将是从该状态开始的预期收益:

由于延迟奖励的概念,状态的立即奖励R(s)与状态的效用U(s)(即状态的最佳策略的效用U[π*](s))不同。 从现在开始,状态的效用U(s)将指该状态的最佳策略的效用(即U[π*](s))。

此外,最佳策略也可以被视为最大化预期效用的策略。 因此,

其中,T(s, a, s')是转移概率,即P(s' | s, a);在对s状态采取a动作后,U(s')是新着陆状态的效用。

Σ[s'] T(s, a, s')U(s')指的是针对特定行动采取的所有可能的新状态结果的总和,然后无论哪个行动给出了Σ[s'] T(s, a, s')U(s')的最大值,该最大值被认为是最优策略的一部分,因此, 状态由以下 贝尔曼方程给出,

其中,R(s)是即时奖励,max[a] Σ[s'] T(s, a, s')U(s')是来自未来的奖励,也就是说,如果采取行动a,智能体可以从给定的s状态到达的s'状态的贴现效用。

解决贝尔曼方程来找到策略

假设在给定的环境中我们有n个状态,如果我们看到贝尔曼方程,

我们发现给出了n个状态; 因此,我们将拥有n方程,而n未知,但是max[a]函数使其变为非线性。 因此,我们不能将它们作为线性方程式求解。

因此,为了解决:

  • 从任意效用开始

  • 根据邻域更新效用,直到收敛为止,也就是说,根据给定状态的着陆状态的效用,使用贝尔曼方程更新状态的效用

多次迭代以得出状态的真实值。 迭代以收敛到状态的真实值的过程称为值迭代

对于游戏结束的终端状态,那些终端状态的效用等于智能体在进入终端状态时所获得的立即奖励。

让我们尝试通过示例来理解这一点。

使用贝尔曼方程的值迭代的示例

请考虑以下环境和给定的信息:

给定信息:

  • ACX是某些状态的名称。

  • 绿色状态是目标状态G,奖励为 +1。

  • 红色状态为错误状态B,奖励为 -1,请尝试阻止您的智能体进入此状态

  • 因此,绿色和红色状态是终端状态,进入其中一个状态,游戏结束。 如果座席遇到绿色状态(即进球状态),则座席获胜;如果他们进入红色状态,则座席将输掉比赛。

  • γ = 1/2R(s) = -0.04(即,对除GB状态之外的所有状态的奖励是 -0.04),U[0](s) = 0(即,第一个时间步长的效用为 0,除GB状态外)。

  • 如果沿期望的方向前进,则过渡概率T(s, a, s')等于 0.8; 否则,如果垂直于所需方向,则各为 0.1。 例如,如果操作是UP,则概率为 0.8,智能体会UP,但概率为 0.1 时,它会RIGHT,而 0.1 则为LEFT

问题:

  1. 找到U[1](X),时间步骤 1 的X状态的效用,也就是说,智能体将进行一次迭代
  2. 同样,找到U[2](X)

解:

R(X) = -0.04

| 动作 | s' | | | |
| --- | --- | --- |
| RIGHT | G | 0.8 | +1 | 0.8 x 1 = 0.8 |
| RIGHT | C | 0.1 | 0 | 0.1 x 0 = 0 |
| RIGHT | X | 0.1 | 0 | 0.1 x 0 = 0 |

因此,对于动作a = RIGHT

| 动作 | s' | | | |
| --- | --- | --- |
| DOWN | C | 0.8 | 0 | 0.8 x 0 = 0 |
| DOWN | G | 0.1 | +1 | 0.1 x 1 = 0.1 |
| DOWN | A | 0.1 | 0 | 0.1 x 0 = 0 |

因此,对于动作a = DOWN

| 动作 | s' | | | |
| --- | --- | --- |
| UP | X | 0.8 | 0 | 0.8 x 0 = 0 |
| UP | G | 0.1 | +1 | 0.1 x 1 = 0.1 |
| UP | A | 0.1 | 0 | 0.1 x 0 = 0 |

因此,对于动作a = UP

| 动作 | s' | | | |
| --- | --- | --- |
| LEFT | A | 0.8 | 0 | 0.8 x 0 = 0 |
| LEFT | X | 0.1 | 0 | 0.1 x 0 = 0 |
| LEFT | C | 0.1 | 0 | 0.1 x 0 = 0 |

因此,对于动作a = LEFT

因此,在所有动作中

因此,U[1](X) = -0.04 + 0.5 * 0.8 = 0.36,其中R(X) = -0.04γ = 1/2 = 0.5

类似地,计算U[1](A)U[1](C),我们得到R(X) = -0.04γ = 1/2 = 0.5

由于U[1](X) = 0.36, U[1](A) = -0.04, U[1](C) = -0.04, U[1](G) = 1, U[1](B) = -1

R(X) = -0.04

动作 s'
RIGHT G 0.8 +1 0.8 x 1 = 0.8
RIGHT C 0.1 -0.04 0.1 x -0.04 = -0.004
RIGHT X 0.1 0.36 0.1 x 0.36 = 0.036

因此,对于动作a = RIGHT

动作 s'
DOWN C 0.8 -0.04 0.8 x -0.04 = -0.032
DOWN G 0.1 +1 0.1 x 1 = 0.1
DOWN A 0.1 -0.04 0.1 x -0.04 = -0.004

因此,对于动作a = DOWN

动作 s'
UP X 0.8 0.36 0.8 x 0.36 = 0.288
UP G 0.1 +1 0.1 x 1 = 0.1
UP 一种 0.1 -0.04 0.1 x -0.04 = -0.004

因此,对于动作a = UP

动作 s'
LEFT 一种 0.8 -0.04 0.8 x -0.04 = -0.032
LEFT X 0.1 0.36 0.1 x 0.36 = 0.036
LEFT C 0.1 -0.04 0.1 x -0.04 = -0.004

因此,对于动作a = LEFT

因此,在所有动作中

因此,U[2](X) = -0.04 + 0.5 * 0.832 = 0.376,其中R(X) = -0.04γ = 1/2 = 0.5

因此,上述问题的答案是:

  1. U[1](X) = 0.36
  2. U[2](X) = 0.376

策略迭代

通过迭代策略并更新策略本身(而不是值)直到策略收敛到最优值以获得最优效用的过程称为策略迭代。 策略迭代的过程如下:

  • 从随机策略π[0]开始

  • 对于迭代步骤t中给定的$1ₜ策略,请使用以下公式计算U[t] = U[t]^π

  • 根据以下公式改进π[t+1]

部分可观察的马尔可夫决策过程

在 MDP 中,可观察的数量是动作,设置A,状态,设置S,转移模型,T和奖励,设置R。 在部分可观察的 MDP(也称为 POMDP)的情况下,情况并非如此。 在 POMDP 中,内部存在一个 MDP,智能体无法直接观察到它,而是根据所做的任何观察来做出决定。

在 POMDP 中,有一个观测集Z,它包含不同的可观测状态和观测函数O,它采用s状态和z观察值作为输入,输出在s状态下看到z观察值的可能性。

POMDP 基本上是 MDP 的概括:

  • MDP{S, A, T, R}

  • POMDP{S, A, Z, T, R, O}

  • 其中,SATR相同。 因此,要使 POMDP 成为真正的 MDP,请满足以下条件:

,即完全遵守所有状态

POMDP 难以解决,无法实现最佳解决方案。

状态估计

如果我们扩展状态空间,这将有助于我们将 POMDP 转换为 MDP,其中Z包含完全可观察的状态空间。 这给出了信念状态b(s)的概念,这是决策者将在 POMDP 上下文中使用的状态。 置信状态,即b(s)给出了智能体处于s状态的可能性。 因此,置信状态b,是代表所有状态上概率分布的向量。 因此,一旦采取行动,信念状态就会更新。

假设存在一个信念状态b,该智能体采取行动a并收到了一些观察结果z。 这形成了一个新的信念状态。 因此,我们正在将 POMDP 转换为信念 MDP,其中它将由信念状态组成为 MDP 状态。

根据前述条件,给出的信息是置信状态b,动作a和观察值z。 因此,

b'(s')为在baz之后给出的处于s状态的概率 ,即P(s' | b, a, z)

其中p(z | b, a, s') = O(s', z)p(s' | s, b, a) = T(s, a, s')。 从而,

POMDP 中的值迭代

POMDP 中的值迭代基本上是从信念 MDP 获得的无限状态空间上的值迭代。

t = 0时,V[0](b) = 0

t > 0时,

其中b'b'(s') = p(s' | b, a, z),即(b, a, z)R(b, a)的状态估计是对信念状态的预期奖励,如下所示:

哪里,

p(s)s状态的概率

R(s, a)为该状态下的奖励

=对信念状态的预期奖励

使用 MDP 训练 FrozenLake-v0 环境

这是关于 OpenAI Gym 中名为 FrozenLake-v0 的网格世界环境,在第 2 章“使用 OpenAI Gym 训练强化学习智能体”中讨论。 我们实现了 Q 学习和 Q 网络(我们将在以后的章节中进行讨论)以了解 OpenAI Gym 的环境。

现在,让我们尝试使用以下代码实现值迭代,以获取 FrozenLake-v0 环境中每个状态的效用值:

# importing dependency libraries
from __future__ import print_function
import gym
import numpy as np
import time

#Load the environment
env = gym.make('FrozenLake-v0')

s = env.reset()
print(s)
print()

env.render()
print()

print(env.action_space) #number of actions
print(env.observation_space) #number of states
print()

print("Number of actions : ",env.action_space.n)
print("Number of states : ",env.observation_space.n)
print()

# Value Iteration Implementation

#Initializing Utilities of all states with zeros
U = np.zeros([env.observation_space.n])

#since terminal states have utility values equal to their reward
U[15] = 1 #goal state
U[[5,7,11,12]] = -1 #hole states
termS = [5,7,11,12,15] #terminal states
#set hyperparameters
y = 0.8 #discount factor lambda

eps = 1e-3 #threshold if the learning difference i.e. prev_u - U goes below this value break the learning

i=0
while(True):
    i+=1
    prev_u = np.copy(U)
    for s in range(env.observation_space.n):
        q_sa = [sum([p*(r + y*prev_u[s_]) for p, s_, r, _ in env.env.P[s][a]]) for a in range(env.action_space.n)]
        if s not in termS: 
            U[s] = max(q_sa)
    if (np.sum(np.fabs(prev_u - U)) <= eps):
        print ('Value-iteration converged at iteration# %d.' %(i+1))
        break

print("After learning completion printing the utilities for each states below from state ids 0-15")
print()
print(U[:4])
print(U[4:8])
print(U[8:12])
print(U[12:16])
------------------------------------------------------------------------------------------------
<<OUTPUT>>
[2018-04-16 20:59:03,661] Making new env: FrozenLake-v0
0

SFFF
FHFH
FFFH
HFFG

Discrete(4)
Discrete(16)

Number of actions : 4
Number of states : 16

Value-iteration converged at iteration# 25.
After learning completion printing the utilities for each states below from state ids 0-15

[ 0.023482 0.00999637 0.00437564 0.0023448 ]
[ 0.0415207 -1\. -0.19524141 -1\. ]
[ 0.09109598 0.20932556 0.26362693 -1\. ]
[-1\. 0.43048408 0.97468581 1\. ]

分析输出,

让状态表示如下:

0 1 2 3

4 5 6 7

8 9 10 11

12 13 14 15

我们智能体的起始状态为 0。让我们从s = 0开始,

U[s = 0] = 0.023482,现在动作可以是UPDOWNLEFTRIGHT

s = 0的情况下,如果:

  • 采取UP动作,s_new = o,因此,u[s_new] = 0.023482
  • 采取DOWN动作,s_new = 4,因此,u[s_new] = 0.0415207
  • 采取LEFT动作,s_new = o,因此,u[s_new] = 0.023482
  • 采取RIGHT动作,s_new = 1,因此,u[s_new] = 0.00999637

最大值为u[s_new = 4] = 0.0415207,因此,采取的动作为DOWNs_new = 4

现在在s = 4的情况下:

  • 采取UP动作,s_new = o,因此,u[s_new] = 0.023482
  • 采取DOWN动作,s_new = 8,因此,u[s_new] = 0.09109598
  • 采取LEFT动作,s_new = 4,因此,u[s_new] = 0.0415207
  • 采取RIGHT动作,s_new = 5,因此,u[s_new] = -1.0

最大值为u[s_new = 8] = 0.09109598,则采取的动作将为DOWNs_new = 8

现在,如果s = 8,则:

  • 采取UP动作,s_new = 4,因此,u[s_new] = 0.0415207
  • 采取DOWN动作,s_new = 12,因此,u[s_new] = -1.0
  • 采取LEFT动作,s_new = 8,因此,u[s_new] = 0.09109598
  • 采取RIGHT动作,s_new = 9,因此,u[s_new] = 0.20932556

最大值为u[s_new = 9] = 0.20932556,因此,采取的动作为RIGHTs_new = 9

现在,如果s = 9,则:

  • 采取UP动作,s_new = 5,因此,u[s_new] = -1.0
  • 采取DOWN动作,s_new = 13,因此,u[s_new] = 0.43048408
  • 采取LEFT动作,s_new = 8,因此,u[s_new] = 0.09109598
  • 采取RIGHT动作,s_new = 10,因此,u[s_new] = 0.26362693

最大值为u[s_new = 13] = 0.43048408,因此,采取的动作为DOWNs_new = 13

现在,如果s = 13,则:

  • 采取UP动作,s_new = 9,因此,u[s_new] = 0.20932556
  • 采取DOWN动作,则s_new = 13,因此,u[s_new] = 0.43048408
  • 采取LEFT动作,s_new = 12,因此,u[s_new] = -1.0
  • 采取RIGHT动作,s_new = 14,因此,u[s_new] = 0.97468581

最大值为u[s_new = 14] = 0.97468581,因此,采取的动作为RIGHTs_new = 14

现在,如果s = 14,则:

  • 采取UP动作,s_new = 10,因此,u[s_new] = 0.26362693
  • 采取DOWN动作,s_new = 14,因此,u[s_new] = 0.97468581
  • 采取LEFT动作,s_new = 13,因此,u[s_new] = 0.43048408
  • 采取RIGHT动作,s_new = 15(目标状态),因此,u[s_new] = 1.0

最大值为u [s_new = 15] = 1.0,因此,采取的动作为RIGHTs_new = 15

因此,我们的策略包含DOWNDOWNRIGHTDOWNRIGHTRIGHT通过避开空穴状态(5、7、11、12)从s = 0(开始状态)到达s = 15(目标状态)。

总结

在本章中,我们介绍了网格世界类型的环境的详细信息,并了解了马尔可夫决策过程的基础,即状态,动作,奖励,转移模型和策略。 此外,我们利用这些信息通过值迭代和策略迭代方法来计算效用和最优策略。

除此之外,我们对部分可观察的马尔可夫决策过程是什么样子以及解决它们的挑战有了基本的了解。 最后,我们从 OpenAI Gym 获取了我们最喜欢的 gridworld 环境,即 FrozenLake-v0,并实现了一种值迭代方法,以使我们的智能体学会在该环境中导航。

在下一章中,我们将从策略梯度开始,然后从 FrozenLake 过渡到其他一些引人入胜的复杂环境。

四、策略梯度

到目前为止,我们已经看到了如何使用基于值的方法从值函数中派生隐式策略。 在这里,智能体将尝试直接学习策略。 做法是相似的,任何有经验的智能体都会在目睹之后更改策略。

值迭代,策略迭代和 Q 学习属于通过动态编程解决的基于值的方法,而策略优化方法则涉及策略梯度和该知识与策略迭代的结合,从而产生了行动者批判算法。

根据动态编程方法,存在一组自洽方程,可以满足QV值。 策略优化是不同的,策略学习直接进行,而不是从值函数中得出:

因此,基于值的方法学习了值函数,我们得出了一个隐式策略,但是使用基于策略的方法,就不会学习任何值函数,而直接学习了该策略。 由于我们同时学习了值函数和策略,而行为者批评方法更为先进,而网络学习值函数则充当了作为参与者的策略网络的批评者。 在本章中,我们将深入研究基于策略的方法。

我们将在本章介绍以下主题:

  • 策略优化方法
  • 为什么要采用策略优化方法?
  • 策略目标函数
  • 时差规则
  • 策略梯度
  • 使用策略梯度的智能体学习 Pong

策略优化方法

策略优化方法的目标是找到随机策略π[θ],它是针对给定状态的操作分布,该状态使期望的奖励总和最大化。 它旨在直接找到该策略。 基本概述是创建一个神经网络(即策略网络),该网络处理一些状态信息并输出智能体可能采取的行动的分布。

策略优化的两个主要组成部分是:

  • 神经网络的权重参数由θ向量定义,这也是我们控制策略的参数。 因此,我们的目标是训练权重参数以获得最佳策略。 由于我们将保单视为给定保单的预期奖励总和。 在此,对于θ的不同参数值,策略将有所不同,因此,最佳策略将是具有最大总体奖励的策略。 因此,具有最大预期奖励的θ参数将是最佳策略。 以下是预期奖励金额的公式:

那就是最大化期望的奖励总和。

这里, H地平线的时间步长,因此,如果开始时间步长t = 0,则总时间步长为H + 1

  • 随机策略类消除了策略优化问题,为我们提供了一组可以选择最佳策略的策略。 在网格世界环境中采用确定性策略的情况下,由于动作变化而导致的变化并不平滑,但是如果每个状态都有动作分布,我们可以稍微改变分布,而这只会稍微改变预期的总和。 奖励。 这是使用随机策略的优势,其中π[θ](a | s)给出给定状态s的动作a的概率。 因此,π[θ]给出了给定状态下动作的概率分布。

因此,由于随机策略,我们有一个平滑的优化问题,可以应用梯度下降来获得良好的局部最优,从而导致最优策略。

为什么要采用策略优化方法?

在本节中,我们将介绍策略优化方法相对于基于值的方法的优缺点。 优点如下:

  • 它们提供了更好的融合。
  • 在高维/连续状态动作空间的情况下,它们非常有效。 如果动作空间很大,则基于值的方法中的max函数将在计算上昂贵。 因此,基于策略的方法通过更改参数来直接更改策略,而不是在每个步骤中求解max函数。
  • 学习随机策略的能力。

与基于策略的方法相关的缺点如下:

  • 收敛到局部而不是全局最优
  • 策略评估效率低下且差异很大

我们将在本章后面讨论解决这些缺点的方法。 现在,让我们集中讨论对随机策略的需求。

为什么采用随机策略?

让我们看两个例子,这些例子将解释基于值方法将随机策略与接近确定性策略相结合的重要性。

示例 1-石头,剪刀,布

石头,剪刀,布是两人游戏,包含以下规则:

  • 石头打剪刀
  • 剪刀打布
  • 布打石头

因此,不可能有确定的策略来取胜。 说,如果有确定性的策略,那摇滚总是赢家,但是如果对手有剪刀,情况就是这样。 但是,当对手拿到纸时,石头就被击败了。 因此,在这种环境下无法确定解决方案。 解决此问题的唯一方法是使用本质上是随机的统一随机策略。

示例 2-名为网格世界的状态

考虑以下别名为 grid-world 的状态:

在上图中,我们看到有八个状态,其中两个奖励为 -10 的状态是要避免的不良状态,并且有一个奖励为 10 的状态是良好状态,还有目标状态。 但是,我们主要担心的是灰色阴影状态,在该状态下,智能体无法区分这两个状态,因为它们具有相同的特征。

假设任何状态的特征都为φ(s, a),动作为北,东,西和南。

考虑到这些函数,让我们比较基于值的方法和基于策略的方法:

  • 基于值的强化学习将使用近似值函数Q(s, a) = f(φ(s, a), w)
  • 基于策略的强化学习将使用参数化策略π[θ](s, a) = g(φ(s, a), θ)

在此,w是值函数的参数,θ是策略的参数。 众所周知,灰色方块具有相同的特征,即在北部和南部都有墙。 因此,由于相同的特征,这导致状态混淆。 结果,基于值的强化学习方法学习了如下确定性策略:

  • 要么在两个灰色阴影状态下向西移动
  • 或在两个灰色阴影状态下向东移动

无论哪种方式,都极有可能被卡住或花费很长时间达到目​​标状态。

另一方面,在基于策略的方法的情况下,最优随机策略将随机选择处于灰色状态的东西方行为,因为这两种行为具有以下相同的概率:

  • (南北墙,行动=东)= 0.5
  • (南北墙,行动=西)= 0.5

结果,它将以更少的步骤达到目标状态,因为西方和东方都将具有相同的发生概率。 因此,与基于值的强化学习方法相比,不同的灰色阴影状态可能会随机发生不同的动作,从而导致目标状态更快。 因此,基于策略的强化学习可以学习最佳的随机策略。

因此,从前面的示例中,我们已经知道,每当发生状态别名时,随机策略都可以执行得更好。 因此,只要存在状态混叠的情况(即环境的表示),就会部分观察状态(例如,您处于部分可观察的马尔可夫决策过程中)或函数逼近器使用状态的特征,这会限制环境的整体视角,使用基于随机策略的基于策略的方法要比基于值的方法要好。

策略目标函数

现在让我们讨论如何优化策略。 在策略方法中,我们的主要目标是具有参数向量θ的给定策略J(θ)找到参数向量的最佳值。 为了测量哪个最好,我们针对参数向量θ的不同值测量J(θ)策略π[θ](s, a)的质量。

在讨论优化方法之前,让我们首先弄清楚度量策略π[θ](s, a)的质量的不同方法:

  • 如果是情景环境,则J(θ)可以是开始状态V[π[θ]](s[1])的值函数,也就是说,如果它从任何状态s₁开始,则其值函数将是该状态开始时的预期奖励总和 。 因此,

  • 如果是连续环境,则J(θ)可以是状态的平均值函数。 因此,如果环境持续不断,那么策略质量的衡量标准可以是处于任何状态s的概率之和,该概率是d[π[θ]](s)乘以该状态的值,也就是说,从该状态开始的预期奖励。 因此,

  • 对于连续环境,J(θ)可以是每个时间步长的平均奖励,它是处于任何状态s的概率的总和,即d[π[θ]](s)乘以对该状态的不同动作的期望奖励E[R[s]^a] = Σ[a] π[θ](s, a) R[s]^a的总和。 因此:

在此,R[s]^a是在状态s采取行动a的奖励。

到目前为止,我们知道基于策略的强化学习是一个优化问题,目标是找到使J(θ)最大化的θ。 同样,在这里,我们将使用基于梯度的方法进行优化。 使用基于梯度的优化的原因是要获得更高的效率,因为与无梯度方法相比,梯度指向了更高效率的方向。

让衡量策略质量的J(θ)成为我们的策略目标函数。 因此,策略梯度算法通过相对于参数θ提升策略的梯度,在J(θ)中寻找局部最大值。 这是因为我们的目标是使J(θ)相对于θ最大化,因此我们进行了梯度上升,其中
Δθ的参数的增量如下:

在这里,ᐁ[θ] J(θ)是策略梯度,α是学习率,也称为步长参数,步长参数决定该参数应在每个步长上偏移多少梯度。 策略梯度还可以用以下形式阐述:

策略梯度定理

假设给定策略π[θ](s, a)每当不为零时都是可微的,则给定策略相对于θ的梯度为ᐁ[θ] π[θ](s, a)。 因此,我们可以以似然比的形式进一步利用此梯度量,如下所示:

此处,ᐁ[θ] log π[θ](s, a)是得分函数,供将来参考。

现在,让我们考虑一个简单的一步式 MDP,即马尔可夫决策过程,其中:

  • 起始状态为s,发生的可能性为d[π[θ]](s)
  • 终止仅发生在获得奖励r = R[s]^a的一步之后

考虑到它是一个持续的环境,因此:

因此,策略梯度ᐁ[θ] J(θ)将如下所示:

在这里,我们证明了以下几点:

结果是:

因此,将该方法推广到多步马尔可夫决策过程将导致状态奖励 Q 值函数Q[π](s, a)代替瞬时奖励r。 这称为策略梯度定理。 该定理对前面讨论的其他类型的策略目标函数有效。 因此,对于任何这样的策略目标函数和任何可微分的π[θ](s, a),策略梯度如下:

时差规则

首先,时间差TD)是两个时间步之间的值估计值之差。 这与基于结果的蒙特卡洛方法不同,后者基于前瞻性的观点直到剧集结束才完成,以更新学习参数。 在时间差异学习的情况下,仅需完成一个步骤,而下一步的状态值估计将用于更新当前状态的值估计。 因此,学习参数会不断更新。 进行时差学习的不同规则是TD(1)TD(0)TD(λ)规则。 所有方法中的基本概念是,下一步的值估计用于更新当前状态的值估计。

TD(1)规则

TD(1)纳入了资格跟踪的概念。 让我们看一下该方法的伪代码,然后将详细讨论它:

Episode T
    For all s, At the start of the episode : e(s) = 0 and 
        After  : (at step t)

        For all s,

每个Episode T都以以下初始化开始:

  • 对于所有状态s,合格分数e(s) = 0
  • 对于所有状态s,给定Episode T中的状态值V[T](s)等于V[T-1](s)

在剧集的每个时间步,即当前步t,我们更新要离开的状态s[t-1]的资格,然后为所有状态更新以下内容:

  • 针对当前离开状态s[t-1](即r[t] + γ V[T-1](s[t]) + V[T-1](s[t-1]))和要更改其值的状态的合格分数e(s)使用时间差误差的状态值函数
  • 通过给定折扣系数进行折扣的资格分数

由于这些更新针对所有状态独立发生,因此可以针对所有状态并行执行这些操作。

在完成剧集的最后一步之后扩展每个状态的计算值估计值时,我们发现基于值的更新与基于结果的更新相同,例如在蒙特卡洛方法中,我们会进行全面的展望,直到剧集的结尾。 因此,我们需要一种更好的方法来更新我们的值函数估计值,而无需多做一步。 通过合并TD(0)规则,我们可以解决此问题。

TD(0)规则

如果无限重复重复有限数据,则TD(0)规则会找到值估计值,通常就是如果我们获取此有限数据并不断重复运行以下估计值更新规则。 然后,实际上我们正在平均每个转换。

因此,值函数由以下给出:

在基于结果的模型中,这是不正确的,在该模型中,我们不使用状态估计值V[T](s[t]),而是使用整个奖励序列,直到事件结束为止。 因此,在蒙特卡洛方法基于结果的模型的情况下,值函数由以下公式给出:

此外,在基于结果的方法中,我们只看到一个序列,重复该过程不会更改值函数的值。 但是,在TD(0)的情况下,每一步都会根据中间状态计算和完善值函数估计。

TD(0)TD(1)之间的区别是,在TD(1)情况下使用资格跟踪更新状态值函数,而在TD(0)情况下则不使用。

TD(0)规则的伪代码如下:

Episode T
    For all s, At the start of the episode : 
        After  : (at step t)
        For s = ,

因此,这里我们仅使用时间差误差r[t] + γ V[T-1](s[t]) + V[T-1](s[t-1])更新当前离开状态s[t-1]的值函数。

TD(λ)规则

TD(1)TD(0)规则产生一个通用规则,即TD(λ),因此对于λ ∈ [0, 1]并应满足以下条件:

  • 如果λ = 0,则TD(λ)趋于TD(0)
  • 如果λ = 1,则TD(λ)趋于TD(1)

TD(0)TD(1)都基于时间连续预测之间的差异进行更新。

因此,TD(λ)的伪代码如下:

Episode T
    For all s, At the start of the episode : e(s) = 0 and 
        After  : (at step t)

        For all s,

这满足前面两个条件,并且可以合并λ ∈ [0, 1]的任何值。

策略梯度

根据策略梯度定理,对于先前指定的策略目标函数和任何可微分策略π[θ](s, a),策略梯度如下:

下一节显示了使用基于蒙特卡洛策略梯度的方法更新参数的步骤。

蒙特卡洛策略梯度

蒙特卡洛策略梯度方法中,我们使用随机梯度上升方法更新参数,并按照策略梯度定理进行更新,并使用vₜ作为Q[π[θ]](s[t], a[t])的无偏样本。 在此,vₜ是从该时间步开始的累计奖励。

蒙特卡洛策略梯度法如下:

Initialize  arbitrarily
for each episode as per the current policy  do
    for step t=1 to T-1 do

    end for
end for

Output: final 

演员评论家算法

先前使用蒙特卡洛策略梯度方法进行的策略优化导致较大的差异。 为了解决此问题,我们使用评论家来估计状态作用值函数,如下所示:

这产生了著名的演员评论家算法。 顾名思义,演员评论家算法出于以下目的维护两个网络:

  • 一个网络充当评论者,它更新状态动作函数逼近器的权重w参数向量
  • 其他网络充当演员,它根据批评者给出的方向更新策略参数向量θ

下图代表了演员评论家算法:

因此,在执行者批评算法的情况下,实际策略梯度公式中的真实状态作用值函数Q[π[θ]](s, a)被替换为近似状态作用值函数Q[w](s, a)。 因此:

并且:

因此,为了估计状态作用值函数,评论者网络使用TD(0)(先前讨论)来更新权重参数w,并更新策略参数向量θ演员网络使用策略梯度。 演员评论家算法的一种简单方法如下所示:

Initialize s, 
for each episode
    Sample  as per the current policy     
    for each step do 
        Take action  and observe reward  and next state 
        Sample action  as per the current policy 

    end for
end for

Output : final 

因此,我们可以看到参与者评论家既具有基于值的优化又具有基于策略的优化。 因此,在采用蒙特卡洛策略梯度法的情况下,策略改进会贪婪地进行。 但是在演员批评家中,演员通过按照批评家的方向采取措施来更新策略参数,以便制定更好的策略。

使用基线减少方差

除了我们最初使用行为准则的方法来减少方差之外,我们还可以通过从策略梯度中减去基线函数 来减少方差。 这将减少方差而不影响期望值,如下所示:

有许多选择基线函数的选项,但是状态值函数被认为是很好的基线函数。 因此:

因此,我们可以通过减去基线函数来重写策略梯度公式,如下所示:

在这里,Q[π[θ]](s, a) - A[π[θ]](s)被称为优势函数A[π[θ]](s, a)。 因此,策略梯度公式变为:

因此,通过使用基线函数,期望值受到方差降低的控制,而方向没有任何变化。

原始策略梯度

在常规策略梯度方法中,目标是使用策略梯度估计和更好的基线估计来更新策略。

以下是实现原始策略梯度以找到最佳策略的伪代码:

Initialize: Policy parameter , and baseline b
for iteration = 1,2,......N   do
        Collect a set of trajectories using the current policy
        At each time step t in each trajectory, compute the following:
            returns ,and
            advantage estimate 
        Refit the baseline function 

end for

使用策略梯度的学习 Pong 的智能体

在本节中,我们将创建一个策略网络,该策略网络将使用来自 pong 环境的原始像素(来自 OpenAI Gym 的 pong-v0)作为输入。 策略网络是一个单独的隐藏层神经网络,它全连接到输入层上 pong 的原始像素,还全连接到包含单个节点的输出层,该单个节点返回了桨上升的可能性。 我要感谢 Andrej Karpathy 提出了一种使智能体使用策略梯度进行学习的解决方案。 我们将尝试实现类似的方法。

灰度大小为80 * 80的像素图像(我们将不使用 RGB,即80 * 80 * 3)。 因此,我们有一个80 * 80的二进制网格,它告诉我们桨和球的位置,并将其作为输入输入到神经网络。 因此,神经网络将包含以下内容:

  • 输入层(X:将80 * 80压缩为6400 * 1,即 6400 个节点
  • 隐藏层:200 个节点
  • 输出层:1 个节点

因此,总参数如下:

  • 连接输入层和隐藏层的权重和偏置6400 * 200(权重)+ 200(偏置)参数
  • 连接隐藏层和输出层的权重和偏置200 * 1(权重)+ 1(偏置)参数

因此,总参数将约为 130 万。

这是巨大的,因此训练需要几天的时间才能见证您的经纪人流畅地打乒乓球。

不能从静态帧播放 Pong,因此,需要捕获某种运动信息,可以通过连接两个这样的帧或新帧与前一帧之间的差异来完成。 因为我们没有使用卷积神经网络,所以除了 6400 个像素值在 0 和 1 之间翻转之外,没有可用的空间信息。 而不是桨和球的位置。

训练 130 万个参数的有效计算方法是使用策略梯度。 您可以将其与监督学习相关联,其中针对每个状态都提到了一个动作标签。 因此,数据和训练如下:

但是,实际上我们没有标签。 因此,我们将实现强化学习,在其中我们将尝试许多任务并记下观察结果。 然后,更频繁地执行表现更好的任务。

在输入 Python 代码之前,让我们放下步骤。 它们如下:

  1. 初始化随机策略。
  2. 对于给定的当前策略,我们将通过以下方式收集不同的样本轨迹(展示):
    1. 运行游戏的一个剧集并捕获该剧集的轨迹。
    2. 同样,收集一批轨迹,如下所示:
轨迹 游戏结果 轨迹好/坏
上,下,上,上,下,下,下,上
下,上,上,下,上,上
上,上,下,下,下,下,上
下,上,上,下,上,上

因此,我们能够创建示例数据,在这些示例中,我们认为赢得的案例是该操作的正确标签。 因此,我们将增加这些动作的对数概率,即log p(y[i], x[i]),并且每个动作失败的情况将被视为错误标签。 因此,在这些情况下,我们将减少这些操作的对数概率。

因此,在收集了一批轨迹之后,我们将最大化优势与对数概率的乘积,即Σ[i] A[i] x log p(y[i], x[i])

在此,Aᵢ是与状态操作对关联的优势。 优势是一个标量,它量化了操作最终的效果。 如果我们想在将来鼓励给定的行动,则Aᵢ会很高,而如果我们想阻止该行动,则Aᵢ会很低。 正优势使该状态的将来更有可能发生该行为,而负优势使该状态的将来不太可能发生该行为。

首先,我们将导入所需的重要依赖项,如下所示:

#import dependencies
import numpy as np #for matrix math
import cPickle as pickle #to save/load model
import gym
  • 超参数初始化:由于我们正在使用RMSProp优化器进行梯度下降,因此超参数(例如隐藏层节点的数量,批量大小,学习率,折扣系数gamma,衰减率)。 我们将使用以下代码进行初始化:
#hyperparameters
H = 200 #number of nodes in the hidden layer
batch_size = 10 
learning_rate = 1e-4 
gamma = 0.99 #discount factor
decay_rate = 0.99 #for RMSProp Optimizer for Gradient Descent
resume = False #to resume from previous checkpoint or not
  • 策略神经网络模型初始化:策略神经网络的权重参数的初始化。 在这里,我们使用一个隐藏层神经网络。 我们将使用以下代码进行初始化:
#initialize : init model
D = 80*80 #input dimension
if resume:
    model = pickle.load(open('model.v','rb'))
else:
    model = {}
    #xavier initialisation of weights
    model['W1'] = np.random.randn(H,D)*np.sqrt(2.0/D)
    model['W2'] = np.random.randn(H)*np.sqrt(2.0/H)
    grad_buffer = {k: np.zeros_like(v) for k,v in model.iteritems()} #to store our gradients which can be summed up over a batch
    rmsprop_cache = {k: np.zeros_like(v) for k,v in model.iteritems()} #to store the value of rms prop formula
  • 激活函数sigmoid(x)relu(x)分别指执行 Sigmoid 和 ReLU 激活计算的函数。 我们将使用以下代码定义函数:
#activation function
def sigmoid(x):
    return 1.0/(1.0+np.exp(-x)) #adding non linearing + squashing

def relu(x):
    x[x<0] = 0
    return x
  • 预处理函数preprocess(image)函数将图像像素作为参数,并通过裁剪,下采样,使其成为灰度,擦除背景并将图像展平为一维向量来对其进行预处理。 我们将使用以下代码定义函数:
#preprocessing function
def preprocess(image): #where image is the single frame of the game as the input
    """ take 210x160x3 frame and returns 6400 (80x80) 1D float vector """
    #the following values have been precomputed through trail and error by OpenAI team members
    image = image[35:195] #cropping the image frame to an extent where it contains on the paddles and ball and area between them
    immage = image[::2,::2,0] #downsample by the factor of 2 and take only the R of the RGB channel.Therefore, now 2D frame
    image[image==144] = 0 #erase background type 1
    image[image==109] = 0 #erase background type 2
    image[image!=0] = 1 #everything else(other than paddles and ball) set to 1
    return image.astype('float').ravel() #flattening to 1D
  • 折扣奖励discount_rewards(r)函数将与不同时间步长对应的奖励列表r作为参数,并返回与不同时间步长对应的折扣奖励列表,如以下代码所示 :
def discount_rewards(r):
    """ take 1D float array of rewards and compute discounted reward """
    discount_r = np.zeros_like(r)
    running_add = 0 #addition of rewards
    for t in reversed(xrange(0,r.size)):
        if r[t] != 0: #episode ends
            running_add = 0
        running_add = gamma*running_add+r[t]
        discount_r[t] = running_add
    return discount_r
  • 正向传播policy_forward(x)函数接收预处理的图像向量x,返回动作概率为UP,并且向量包含隐藏状态节点的值,例如以下代码:
def policy_forward(x):
    h = np.dot(model['W1'],x) 
    h = relu(h) 
    logit = np.dot(model['W2'],h)
    p = sigmoid(logit)
    return p,h #probability of action 2(that is UP) and hidden layer state that is hidden state
  • 反向传播policy_backward(arr_hidden_state, gradient_logp, observation_values)函数采用隐藏状态值,误差gradient_logp和观测值来针对不同权重参数计算导数,如以下代码所示:
def policy_backward(arr_hidden_state,gradient_logp,observation_values):
    """ backward pass """
    #arr_hidden_state is array of intermediate hidden states shape [200x1]
    #gradient_logp is the loss value [1x1]
    dW2 = np.dot(arr_hidden_state.T,gradient_logp).ravel() 
    # [200x1].[1x1] => [200x1] =>flatten=>[1x200]
    dh = np.outer(gradient_logp,model['W2']) # [1x1]outer[1x200] => [1x200]
    dh = relu(dh) #[1x200]
    dW1 = np.dot(dh.T,observation_values) #[200x1].[1x6400] => [200x6400]
    return {'W1':dW1,'W2':dW2}

创建环境并结合先前的函数以使智能体逐步学习多个剧集的最终任务如下:

#implementation details
env = gym.make('Pong-v0')
observation = env.reset()
prev_x = None 
#prev frame value in order to compute the difference between current and previous frame
#as discussed frames are static and the difference is used to capture the motion
#Intially None because there's no previous frame if the current frame is the 1st frame of the game
episode_hidden_layer_values, episode_observations, episode_gradient_log_ps, episode_rewards = [], [], [], []
running_reward = None
reward_sum = 0
episode_number = 0

#begin training
while True:
    env.render()
    #get the input and preprocess it
    cur_x = preprocess(observation)
    #get the frame difference which would be the input to the network
    if prev_x is None:
        prev_x = np.zeros(D)
    x = cur_x - prev_x
    prev_x = cur_x

    #forward propagation of the policy network
    #sample an action from the returned probability
    aprob, h = policy_forward(x)
    #stochastic part
    if np.random.uniform() < aprob:
        action = 2
    else:
        action = 3

    episode_observations.append(x) #record observation
    episode_hidden_layer_values.append(h) #record hidden state
    if action == 2:
        y = 1
    else:
        y = 0

    episode_gradient_log_ps.append(y-aprob) #record the gradient

    #new step in the environment
    observation,reward,done,info = env.step(action)
    reward_sum+=reward #for advantage purpose
    episode_rewards.append(reward) #record the reward

    if done: #if the episode is over
        episode_number+=1

        #stack inputs,hidden_states,actions,gradients_logp,rewards for the episode
        arr_hidden_state = np.vstack(episode_hidden_layer_values)
        gradient_logp = np.vstack(episode_gradient_log_ps)
        observation_values = np.vstack(episode_observations)
        reward_values = np.vstack(episode_rewards)

        #reset the memory arrays
        episode_hidden_layer_values, episode_observations, episode_gradient_log_ps, episode_rewards = [], [], [], []

        #discounted reward computation
        discounted_episoderewards = discount_rewards(reward_values)
        #normalize discounted_episoderewards
        discounted_episoderewards = (discounted_episoderewards - np.mean(discounted_episoderewards))/np.std(discounted_episoderewards) #advantage

        #modulate the gradient with the advantage
        gradient_logp *= discounted_episoderewards

        grad = policy_backward(arr_hidden_state,gradient_logp,observation_values)

        #summing the gradients over the batch size
        for layer in model:
            grad_buffer[layer]+=grad[layer]

        #perform RMSProp to update weights after every 10 episodes
        if episode_number % batch_size == 0:
            epsilon = 1e-5
            for weight in model.keys():
                g = grad_buffer[weight] #gradient
                rmsprop_cache[weight] = decay_rate*rmsprop_cache[weight]+(1-decay_rate)`g`2
                model[weight]+=learning_rate*g/(np.sqrt(rmsprop_cache[weight]) + epsilon)
                grad_buffer[weight] = np.zeros_like(model[weight])

        if running_reward is None:
            running_reward = reward_sum
        else:
            running_reward = running_reward*learning_rate+reward_sum*(1-learning_rate)

        print('Episode Reward : {}, Running Mean Award : {}'.format(reward_sum,running_reward))
        if episode_number % 100 == 0:
            pickle.dump(model,open('model.v','wb'))

        reward_sum = 0
        prev_x = None
        observation = env.reset() #resetting the environment since episode has ended

    if reward != 0: #if reward is either +1 or -1 that is an episode has ended
        print("Episode {} ended with reward {}".format(episode_number,reward))

智能体玩的游戏的屏幕截图:

如果您在笔记本电脑上运行先前的代码,则融合可能需要几天的时间。 尝试使用 GPU 驱动的云实例在大约 5-6 个小时内获得更好的结果。

总结

在本章中,我们介绍了强化学习中最著名的算法,策略梯度和参与者批评算法。 在制定策略梯度以强化学习中更好的基准测试方面,正在进行大量研究。 策略梯度的进一步研究包括信任区域策略优化TRPO),自然策略梯度深度依赖策略梯度DDPG),这些内容不在本书的讨论范围之内。

在下一章中,我们将研究 Q 学习的基础知识,应用深度神经网络以及更多技术。

五、Q 学习和深度 Q 网络

在第 3 章,“马尔可夫决策过程”中,我们讨论了遵循马尔可夫性质的环境转移模型以及延迟的奖励和值函数的概念(或工具)。 好,在本章中,我们将研究马尔可夫决策过程,了解 Q 学习,以及一种称为深度 Q 网络的改进方法,用于在不同环境中进行泛化。

我们将在本章介绍以下主题:

  • 人工智能的有监督和无监督学习
  • 基于模型的学习和无模型学习
  • Q 学习
  • 深度 Q 网络
  • 蒙特卡罗树搜索算法
  • SARSA 算法

为什么是强化学习?

2014 年,Google 以高达 5 亿美元的价格收购了伦敦一家名为 DeepMind 的创业公司。 在新闻中,我们了解到他们创建了一个 AI 智能体来击败任何 Atari 游戏,但是 Google 付出如此高的价格收购它的主要原因是因为这一突破向通用人工智能靠近了一步。 通用人工智能被称为 AI 智能体。 它能够完成各种任务并像人类一样泛化。 当它超过这一点时,该点称为人工超级智能。 目前,AI 社区所做的工作就是我们所说的人工智能,即人工智能,其中 AI 智能体能够执行多个任务,但不能概括各种任务。

DeepMind 在研究期刊 Nature 上发表了他们的论文《通过深度强化学习进行人类水平控制》,这表明,他们的深度强化学习算法可成功应用于 50 种不同的 Atari 游戏,并在其中 30 种游戏中达到高于人类水平的表现。 他们的 AI 智能体称为深度 Q 学习器。 在详细深入学习强化学习之前,让我们回顾一下强化学习的基础知识。

有监督和无监督的学习是 AI 应用社区众所周知的。 监督学习处理包含输入特征和目标标签(连续或离散)的标记数据集,并创建将这些输入特征映射到目标标签的模型。 另一方面,无监督学习处理仅包含输入特征但不包含目标标签的未标记数据集,其目的是发现基础模式,以将数据分类到不同集群中,并分别定义其效用。 不同集群中特定类型的数据。

因此,使用有监督和无监督的学习,我们可以创建数据分类器/回归器或数据生成器,通过一次学习就可以通过一批数据进行学习。 为了随着时间的推移增强学习,该批量需要合并越来越多的数据,从而导致有监督和无监督的学习变得缓慢且难以推广。 让我们考虑一种情况,您希望 AI 智能体为您玩特定的视频/虚拟游戏,但要注意的是,随着时间的流逝,该算法应该变得智能。

那么,如何解决这个问题呢?

假设我们拍摄了特定视频游戏中所有最佳玩家的视频,并以图像帧和目标标签的形式输入数据,作为可能采取的不同动作的集合。 由于我们具有输入特征和目标标签,因此形成了监督学习分类问题。 假设数据量巨大,并且我们可以使用具有最新 GPU 的高端机器,那么为该任务创建一个深度神经网络完全有意义。

但是这里有什么收获呢?

为了创建可解决此分类问题的深度神经网络,以使最终的 AI 智能体可以击败该游戏中任何级别的任何对手,我们的输入数据需要数千小时的视频数据分配到不同级别的游戏中, 不同的玩家,采用不同的方法赢得比赛,因此我们的神经网络可以以最佳方式概括映射。 获得更多数据的原因是为了避免欠拟合。 此外,过拟合中的大量数据也可能是一个问题,但是正则化是根据给定数据将模型推广到最佳状态的可能解决方案。 因此,我们看到,即使在获得了数千小时的专家播放器的视频数据(即非常高的数据量)之后,这种有监督的学习方法似乎也不是一个很好的解决方案。 这是因为,与其他应用的 AI 问题不同,此处的数据集是动态的而不是静态的。

此处的训练数据是连续的,新的框架在游戏世界中不断出现。 现在,问问自己我们人类如何学习这项任务,答案很简单,即我们通过与环境交互而不是看着其他人与环境交互来学习最好。 因此,AI 智能体可以尝试通过与环境交互来更好地学习,并通过一系列的反复试验来逐步发展其学习成果。

在现实世界和游戏世界中,环境通常是随机,其中可能发生许多事件。 由于所有事件都与某种发生概率相关联,因此可以对它们进行统计分析,但不能精确确定。 假设在给定的e环境中,我们只有三个动作来执行abc,但是每个动作都有一些与之相关的某种不确定性,即它们的出现机会是随机的,并且它们中的任何一个都可以发生,但是每个结果都不确定。 对于监督分类问题,我们认为环境是确定性的,其中确定了与特定动作相关的结果,并且结果是精确的预测,即特定类别(目标标签)。 在继续讨论该主题之前,让我们看一下两种环境之间的区别:

  • 确定性环境:由于没有不确定性,智能体的动作可以唯一地确定结果的环境。 例如,在国际象棋中,您将一块从一个正方形移到另一个正方形。 因此,确定结果,即结果平方。 没有随机性。
  • 随机环境:每个动作都与某种程度的随机性相关联的环境,因此,无论我们采取何种行动,都无法确定结果。 例如,将飞镖投掷到旋转的棋盘上或掷骰子。 在这两种情况下,结果均不确定。

因此,对于基于随机环境的问题,似乎最好的学习方法是尝试各种可能性。 因此,与其通过监督分类将其解决为模式识别问题,不如通过试错法更好,在这种方法中,结果标签将替换为量化特定操作对完成给定问题的最终目的的有用性的奖励。 声明。

这产生了环境-智能体交互方法,我们在第 1 章,“深度强化–架构和框架”中讨论了该方法,在该系统中,我们设计了一种使智能体与环境交互的系统。 首先,通过传感器感知状态,通过效应器对环境执行一些操作,然后接收反馈,即对所采取操作的奖励,如下图所示:

根据传感器在特定时间步长感测环境时接收到的信号,此处的状态基本上是智能体对环境的看法。

基于模型的学习和无模型学习

在第 3 章,“马尔可夫决策过程”中,我们使用状态,动作,奖励,转移模型和折扣因子来解决我们的马尔可夫决策过程,即 MDP 问题。 因此,如果 MDP 问题的所有这些元素均可用,我们可以轻松地使用规划算法为目标提出解决方案。 这种类型的学习称为基于模型的学习,其中 AI 智能体将与环境交互,并基于其交互,将尝试近似环境的模型,即状态转换模型。 给定模型,现在智能体可以尝试通过值迭代或策略迭代找到最佳策略。

但是,对于我们的 AI 智能体来说,学习环境的显式模型不是必需的。 它可以直接从与环境的交互中得出最佳策略,而无需构建模型。 这种学习称为无模型学习。 无模型学习涉及在没有具体环境模型的情况下预测某个策略的值函数。

可以使用两种方法完成无模型学习:

  • 蒙特卡洛学习
  • 时差学习

我们将在以下主题中讨论它们两者。

蒙特卡洛学习

蒙特卡洛(Monte Carlo)是用于模型免费学习的最简单方法,在该方法中,智能体会观察剧集中前进的所有步骤(即前瞻)的回报。 因此,在时间t时的总估计报酬为Rₜ

这里,γ是折扣因子,T是剧集结束的时间步长。 我们可以使用以下代码初始化蒙特卡洛学习技术:

Initialize:

     i.e. the policy to be evaluated
    V i.e. an arbitrary state-value function
    Returns(s) = empty list 
    #here Returns(s) refer to returns for a particular state i.e. the series of rewards the agent receives from that state onward

Repeat forever:

    Generate an episode using the current 
    For each state 's' appearing in the episode perform the following:
        R = returns following the first occurrence of 's'
        Append R to Returns(s)
        V(s) = Average(Returns(s))
    Update policy as per V

时差学习

与在蒙特卡洛学习中我们要全面展望未来不同,在时间差异学习中,我们只有一个展望,也就是说,我们只观察到剧集的下一步:

时间差异学习是一种用于学习值和策略迭代方法中的值函数以及 Q 学习中的 Q 函数的方法。

如果我们希望我们的 AI 智能体始终选择最大化折扣未来奖励的行动,那么我们需要某种时间差异学习。 为此,我们需要定义一个函数 Q,该函数表示当我们在状态s上执行动作a时最大的未来折扣。 因此,Q 函数表示给定状态下的动作质量。 使用它,我们可以通过仅了解当前状态和操作来估计最终得分,而在此之后无需进行任何操作。 因此,目标将是对具有最高 Q 值的状态采取该措施。 因此,我们必须通过称为 Q 学习的过程来学习此 Q 函数。

策略内和策略外学习

顾名思义,脱离策略的学习是独立于智能体行为的最优策略学习。 因此,您不需要一开始就使用特定的策略,并且即使通过随机动作开始,智能体也可以学习最佳策略,最终收敛到最佳策略。 Q 学习是非策略学习的一个例子。

另一方面,基于策略的学习通过执行当前策略并通过探索方法对其进行更新来学习最佳策略。 因此,基于策略的学习取决于开始时的策略。 SARSA 算法是基于策略学习的示例。

Q 学习

在强化学习中,我们希望 Q 函数Q(s, a)预测状态s的最佳动作,以便最大化未来的回报。 使用 Q 学习估计 Q 函数,该过程涉及使用贝尔曼方程通过一系列迭代更新 Q 函数的过程,如下所示:

这里:

Q(s, a)为当前状态s和动作a对的Q

=学习收敛速度

=未来奖励的折扣系数

Q(s', a')为在状态s下采取动作a之后,所得状态s'的状态动作对的Q

R表示即时奖励

=未来奖励

在状态空间和动作空间是离散的更简单的情况下,使用 Q 表实现 Q 学习,其中表代表状态,列代表动作。

Q 学习涉及的步骤如下:

  1. 随机初始化 Q 表
  2. 对于每个剧集,请执行以下步骤:
    1. 对于给定状态s,从 Q 表中选择动作a
    2. 执行动作a
    3. 奖励R和状态s'
    4. 通过以下方法更新当前状态操作对的 Q 值,即Q(s, a)

但是,这里并没有探索新路径,并且在大多数情况下,智能体正在利用已知路径。 因此,实现了一定程度的随机性,以使 AI 智能体有时通过采取随机动作而不是当前的最佳动作来随机探索新路径。 探索背后的原因是,它增加了获得比当前更好的路径(即新的最佳策略)的可能性:

Create Q-table where rows represent different states and columns represent different actions
Initialize Q(s,a) arbitrarily
For each episode:
    Start with the starting state i.e. Initialize s to start
    Repeat for each step in the episode:
        Choose action a for s using the policy derived from Q
        [e.g. -greedy, either for the given 's' which 'a' has the max Q-value or choose a random action]
        Take the chosen action a, observe reward R and new state s'
        Update 

    until s is the terminal state
end

探索利用困境

下表总结了探索与利用之间的困境:

探索 利用
除了当前的最佳动作之外,随机选择其他动作,并希望获得更好的回报。 选择当前的最佳操作而不尝试其他操作。

因此,难题是 AI 是仅根据当前最佳策略基于动作信任已获悉的 Q 值,还是应该随机尝试其他动作以希望获得更好的回报,从而改善 Q 值,因此, 得出更好的最佳策略。

OpenAI Gym 山地车问题的 Q 学习

山地车是强化学习领域的标准测试问题。 它由动力不足的汽车组成,必须将陡峭的山坡驱动到标志点,如下图所示:

这里的要点是重力要比汽车的引擎强,因此即使在全油门的情况下,汽车也无法在陡峭的斜坡上加速。 因此,汽车必须以相反的方向反向行驶来利用势能,然后再利用势能到达右上角的标志点。

在这里,状态空间是连续的,由两点定义:位置和速度。 对于给定的状态(即位置和速度),智能体可以采取三个离散的动作,即向前移动(向图中右上方),向相反方向(向图中左上方)或不使用引擎 ,即汽车处于空档。 智能体会收到负面奖励,直到达到目标状态。

Q 学习可以轻松地应用于具有离散状态空间和动作的环境,但是这个问题成为了强化学习算法的测试平台,因为它具有连续状态空间,并且需要离散化连续状态空间或函数逼近才能将其映射到离散类。

下面列出了山地车问题的技术细节,供您参考:

状态空间是二维且连续的。 它由位置和速度组成,具有以下值:

  • 位置(-1.2, 0.6)
  • 速度(-0.07, 0.07)

动作空间是离散的和一维的,具有三个选项:

  • (左,中,右)

每个时间步数都奖励 -1。

起始状态:

  • 位置:-0.5
  • 速度:0.0

终端状态条件:

  • 剧集在大于等于 0.6 的位置结束

正如我们现在看到的 Q 学习的参数一样,我们现在将研究解决山地车问题的 Q 学习的实现。

首先,我们将使用以下代码导入依赖项并检查山地车环境:

#importing the dependencies

import gym
import numpy as np

#exploring Mountain Car environment

env_name = 'MountainCar-v0'
env = gym.make(env_name)

print("Action Set size :",env.action_space)
print("Observation set shape :",env.observation_space) 
print("Highest state feature value :",env.observation_space.high) 
print("Lowest state feature value:",env.observation_space.low) 
print(env.observation_space.shape) 

先前的打印语句输出以下内容:

Making new env: MountainCar-v0
('Action Set size :', Discrete(3))
('Observation set shape :', Box(2,))
('Highest state feature value :', array([ 0.6 , 0.07]))
('Lowest state feature value:', array([-1.2 , -0.07]))
(2,)

因此,我们看到动作空间是一个离散集合,显示了三个可能的动作,状态空间是一个二维连续空间,其中一个维度满足位置,而另一个则满足汽车的速度。 接下来,我们将使用以下代码分配超参数,例如状态数,剧集数,学习率(初始和最小值),折扣因子伽玛,剧集中的最大步数以及 ε 贪婪的ε

n_states = 40  # number of states
episodes = 10 # number of episodes

initial_lr = 1.0 # initial learning rate
min_lr = 0.005 # minimum learning rate
gamma = 0.99 # discount factor
max_steps = 300
epsilon = 0.05

env = env.unwrapped
env.seed(0)         #setting environment seed to reproduce same result
np.random.seed(0)   #setting numpy random number generation seed to reproduce same random numbers

我们的下一个任务是创建一个函数来对连续状态空间进行离散化。 离散化是将连续状态空间观察转换为离散状态空间集:

def discretization(env, obs):

    env_low = env.observation_space.low
    env_high = env.observation_space.high

    env_den = (env_high - env_low) / n_states
    pos_den = env_den[0]
    vel_den = env_den[1]

    pos_high = env_high[0]
    pos_low = env_low[0]
    vel_high = env_high[1]
    vel_low = env_low[1]

    pos_scaled = int((obs[0] - pos_low)/pos_den)  #converts to an integer value
    vel_scaled = int((obs[1] - vel_low)/vel_den)  #converts to an integer value

    return pos_scaled,vel_scaled

现在,我们将通过初始化 Q 表并相应地更新 Q 值来开始实现 Q 学习算法。 在这里,我们将奖励值更新为当前位置与最低点(即起点)之间的绝对差值,以便它通过远离中心即最低点来最大化奖励。 这样做是为了实现更好的收敛:

#Q table
#rows are states but here state is 2-D pos,vel
#columns are actions
#therefore, Q- table would be 3-D

q_table = np.zeros((n_states,n_states,env.action_space.n))
total_steps = 0
for episode in range(episodes):
      obs = env.reset()
      total_reward = 0
      # decreasing learning rate alpha over time
      alpha = max(min_lr,initial_lr*(gamma**(episode//100)))
      steps = 0
      while True:
          env.render()
          pos,vel = discretization(env,obs)

          #action for the current state using epsilon greedy
          if np.random.uniform(low=0,high=1) < epsilon:
                a = np.random.choice(env.action_space.n)
          else:
                a = np.argmax(q_table[pos][vel])
          obs,reward,terminate,_ = env.step(a) 
          total_reward += abs(obs[0]+0.5)

          #q-table update
          pos_,vel_ = discretization(env,obs)
          q_table[pos][vel][a] = (1-alpha)*q_table[pos][vel][a] + alpha*(reward+gamma*np.max(q_table[pos_][vel_]))
          steps+=1
          if terminate:
                break
      print("Episode {} completed with total reward {} in {} steps".format(episode+1,total_reward,steps)) 

while True: #to hold the render at the last step when Car passes the flag
      env.render() 

根据学习情况,前面的 Q 学习器将以以下方式打印输出:

Episode 1 completed with total reward 8433.30289388 in 26839 steps
Episode 2 completed with total reward 3072.93369963 in 8811 steps
Episode 3 completed with total reward 1230.81734028 in 4395 steps
Episode 4 completed with total reward 2182.31111239 in 6629 steps
Episode 5 completed with total reward 2459.88770998 in 6834 steps
Episode 6 completed with total reward 720.943914405 in 2828 steps
Episode 7 completed with total reward 389.433014729 in 1591 steps
Episode 8 completed with total reward 424.846699654 in 2362 steps
Episode 9 completed with total reward 449.500988781 in 1413 steps
Episode 10 completed with total reward 222.356805259 in 843 steps

这还将渲染一个环境,显示汽车在行驶并采取最佳路径并达到目标状态,如以下屏幕截图所示:

山地赛车游戏的最终状态视图

因此,我们看到无模型学习可以从其与环境的交互中得出最佳策略,而无需创建环境模型。 因此,我们已经知道,Q 学习是一种无模型的时间差异学习,它通过估计 Q 函数来找到最佳状态动作选择策略。

深度 Q 网络

如果我们回想起第 2 章和“使用 OpenAI Gym 训练强化学习智能体”,我们曾尝试在其中实现基本的 Q 网络,之后我们针对一个实际问题研究了 Q 学习。 由于连续的状态和动作空间,使用 Q 表不是可行的解决方案。 而且,Q 表是特定于环境的,而不是通用的。 因此,我们需要一个模型,该模型可以将作为输入提供的状态信息映射到可能的一组动作的 Q 值。 在这里,神经网络开始发挥函数逼近器的作用,函数逼近器可以接受向量形式的状态信息输入,并学习将其映射为所有可能动作的 Q 值。

让我们讨论游戏环境中的 Q 学习问题以及深度 Q 网络的发展。 考虑将 Q 学习应用于游戏环境,该状态将由玩家,障碍物,对手等的位置来定义,但这将是特定于游戏的,即使在我们创建一个以某种方式表示该游戏所有可能状态的 Q 表,也不能在其他游戏环境中推广。

好吧,游戏环境有一个共同点,那就是全部由像素组成。 如果可以将像素输入可以映射到动作的模型中,则可以在所有游戏中将其推广。 DeepMind 的卷积神经网络实现具有游戏图像帧,其中输入和输出是该环境中每个可能动作的 Q 值。 卷积神经网络由三个卷积层和两个全连接层组成。 卷积神经网络CNN)的一个元素是池化层,在此已避免。 使用池化层的主要原因是在图像中进行对象检测的情况下,其中图像中对象的位置并不重要,而在此处,在游戏框架中对象的位置非常重要时,则不然。

因此,在游戏环境中,深度 Q 网络DQN)由连续的游戏帧组成,作为捕获动作的输入,并为游戏中所有可能的动作输出 Q 值。 游戏。 由于将深度神经网络用作 Q 函数的函数逼近器,因此此过程称为深度 Q 学习。

与 Q 网络相比,深度 Q 网络具有更强的泛化能力。 为了将 Q 网络转换为深度 Q 网络,我们需要进行以下改进:

  • 使用卷积神经网络代替单层神经网络
  • 使用经验回放
  • 分离目标网络来计算目标 Q 值

在以下主题中,我们将详细讨论每个参数:

使用卷积神经网络代替单层神经网络

我们的游戏环境是视频,而卷积神经网络在计算机视觉方面已经显示了最新的成果。 而且,游戏框架中物体检测的水平应该接近人类水平的能力,并且卷积神经网络从图像中学习表示,类似于人类原始视觉皮层的行为。

DeepMind 在其 DQN 网络中使用了三个卷积层和两个全连接层,从而在 Atari 游戏中实现了超人水平的表现,如以下流程图所示:

使用经验回放

添加到深度 Q 网络的另一个重要功能是经验回放。 该功能背后的想法是,智能体可以存储其过去的经验,并分批使用它们来训练深度神经网络。 通过存储经验,智能体可以随机抽取批量,并帮助网络从各种数据中学习,而不仅仅是对即时经验的决策正式化。 这些经历中的每一个都以包括状态,动作,奖励下一个状态的四维向量的形式存储。

为了避免存储问题,经验回放的缓冲区是固定的,并且随着新体验的存储,旧体验将被删除。 为了训练神经网络,从缓冲区中提取均匀批量的随机经验。

分离目标网络来计算目标 Q 值

生成目标 Q 值的单独网络是一项重要功能,它使深层 Q 网络具有独特性。 由此单独的目标网络生成的 Q 值用于计算智能体在训练过程中采取的每项操作之后的损失。 使用两个网络而不是一个网络的原因在于,由于每个步骤的权重变化,主要的 Q 网络值在每个步骤中都在不断变化,这使得从该网络生成的 Q 值不稳定。

为了获得稳定的 Q 值,使用了另一个神经网络,其权重与主要 Q 网络相比变化缓慢。 这样,训练过程更加稳定。 DeepMind 的文章也发表在这个页面中。 他们发现这种方法能够稳定训练过程。

改编自 Minh 等人(2015),以下是 DQN 的伪代码:

Input: the image(game frame) pixels 

Initialize replay memory D for experience replay
Initialize action-value function`Q`i.e. primary neural network with random weight   
Initialize target action-value function QT i.e. target neural network with weights 

for each episode do
    Initialize sequence  and preprocessed sequence 
    for t = 0 to max_step in an episode do
        Choose  using -greedy such that 

        Perform action 
        Observe reward  and image 
        Set  and preprocess 
        Store transition  in D

        // experience replay
        Sample random batch of transitions  from D
        Set 
        Compute the cost function = 
        Perform gradient descent on the cost function w.r.t. the primary network parameter θ

        // periodic update of target network
        After every C steps reset , i.e., set 

    until end of episode 
end

深度 Q 网络以及其他方面的进步

随着更多的研究和更多的时间,深度 Q 网络已经进行了许多改进,从而获得了更好的架构,从而提供了更高的表现和稳定性。 在本节中,我们将仅讨论两种著名的架构,即双重 DQN决斗 DQN

双 DQN

使用双重 DQN(DDQN)的原因是常规 DQN 高估了在给定状态下可能采取的措施的 Q 值。 在常规 DQN 中,所有动作之间的高估都不相等。 因此,问题仍然存在:否则,所有行动之间的均等估计就不会成为问题。 结果,某些次优的行为获得了更高的值,因此学习最佳策略的时间增加了。 这导致我们对常规 DQN 架构进行了少量修改,并导致了所谓的 DDQN,即双深度 Q 网络。

在 DDQN 中,我们不是在训练过程中计算目标 Q 值时取最大 Q 值,而是使用主要网络选择操作,并使用目标网络为该操作生成目标 Q 值。 这使动作脱钩。 从目标 Q 网络中进行选择,生成目标 Q 值,从而减少高估,并有助于更快地进行训练。 DDQN 中的目标 Q 值通过以下公式更新:

这里:

代表主网络的权重,并且

代表目标网络的权重。

决斗 DQN

决斗 DQN 的情况下,Q 值已被修改为状态的值函数和操作的优势函数的总和。 值函数V(s)量化处于状态s的有用性或优势,优势函数A(a)量化行为的优势代替其他可能的操作。 因此,

决斗 DQN 具有独立的网络来计算值和优势函数,然后将它们组合回以获取 Q 函数的值。 将值和优势的计算脱钩的原因在于,对于给定状态下的每个动作,智能体不必照顾不必要的值函数。 因此,将这些计算去耦会导致鲁棒的状态动作 Q 值。

用于 OpenAI Gym 山地车问题的深度 Q 网络

在针对山地车问题实现 Q 学习时,我们已经讨论了环境。 让我们直接深入实现一个深度 Q 网络来解决山地车问题。 首先,我们将使用以下代码导入所需的库:

#importing the dependencies

import numpy as np
import tensorflow as tf
import gym

让我们讨论一下 DQN 类,其中包含深度 Q 网络的架构:

  • __init__selflearning_rategamman_featuresn_actionsepsilonparameter_changing_pointermemory_size):默认构造器,用于分配超参数,例如:
    • learning_rate
    • gamma,即折扣因子
    • n_feature:状态中的特征数,即状态中的尺寸数
    • epsilon:ε 贪婪条件的阈值,以利用或探索动作
  • build_networks():使用 Tensorflow 创建主要和目标网络
  • target_params_replaced(self):用主要网络参数替换目标网络参数
  • store_experience(self,obs,a,r,obs_):存储经验,即(状态,动作,奖励,新状态)的元组
  • fit(self):训练我们的深度 Q 网络
  • epsilon_greedy(self,obs):对于给定的观察状态,要采取的操作,即根据现有策略利用操作或随机探索新操作

可以使用以下代码定义具有main函数的 DQN 类的架构:

class DQN:
    def __init__(self,learning_rate,gamma,n_features,
                 n_actions,epsilon,parameter_changing_pointer,memory_size):
    ....
    def build_networks(self):
    ....
    def target_params_replaced(self):
    ....
    def store_experience(self,obs,a,r,obs_):
    ....
    def fit(self):
    ....
    def epsilon_greedy(self,obs): 
    ....

if __name__ == "__main__":
    ....

__init__:在以下代码片段中解释了默认构造器以及注释:

def __init__(self,learning_rate,gamma,n_features,n_actions,epsilon,parameter_changing_pointer,memory_size):

        self.learning_rate = learning_rate
        self.gamma = gamma
        self.n_features = n_features
        self.n_actions = n_actions
        self.epsilon = epsilon
        self.batch_size = 100
        self.experience_counter = 0
        self.experience_limit = memory_size
        self.replace_target_pointer = parameter_changing_pointer
        self.learning_counter = 0
        self.memory = np.zeros([self.experience_limit,self.n_features*2+2]) #for experience replay

        self.build_networks()
        #to fetch parameters under the collection : 'primary_network_parameters'
        p_params = tf.get_collection('primary_network_parameters')

        #to fetch parameters under the collection : 'target_network_parameters'
        t_params = tf.get_collection('target_network_parameters')

        #replacing tensor replace the target network parameters with primary network parameters
        self.replacing_target_parameters = [tf.assign(t,p) for t,p in zip(t_params,p_params)]

        self.sess = tf.Session()
        self.sess.run(tf.global_variables_initializer())

现在让我们初始化build_networks(self)。 它是构建主要网络和目标网络的函数:

  • variable_scopeprimary_network下创建主要网络参数,并在primary_network_parameters集合中创建
  • variable_scopetarget_network下创建目标网络参数,并在target_network_parameters集合中创建目标网络参数
  • 这两个参数具有相同的结构,即:
    • w1:与输入层关联的权重矩阵
    • b1:与输入层关联的偏置向量
    • ReLU:信号从输入到隐藏层的激活函数
    • w2:与隐藏层关联的权重矩阵
    • b2:与隐藏层关联的偏置向量
  • 计算主网络输出的 Q 值与目标网络输出的 Q 值之间的损失
  • 使用 adam 优化器将损失降到最低

我们将使用以下代码定义build_networks(self)函数:

def build_networks(self):
        #primary network
        hidden_units = 10
        self.s = tf.placeholder(tf.float32,[None,self.n_features])
        self.qtarget = tf.placeholder(tf.float32,[None,self.n_actions])

        with tf.variable_scope('primary_network'):
                c = ['primary_network_parameters', tf.GraphKeys.GLOBAL_VARIABLES]
                # first layer
                with tf.variable_scope('layer1'):
                    w1 = tf.get_variable('w1',[self.n_features,hidden_units],initializer=tf.contrib.layers.xavier_initializer(),dtype=tf.float32,collections=c)
                    b1 = tf.get_variable('b1',[1,hidden_units],initializer=tf.contrib.layers.xavier_initializer(),dtype=tf.float32,collections=c)
                    l1 = tf.nn.relu(tf.matmul(self.s, w1) + b1)

                # second layer
                with tf.variable_scope('layer2'):
                    w2 = tf.get_variable('w2',[hidden_units,self.n_actions],initializer=tf.contrib.layers.xavier_initializer(),dtype=tf.float32,collections=c)
                    b2 = tf.get_variable('b2',[1,self.n_actions],initializer=tf.contrib.layers.xavier_initializer(),dtype=tf.float32,collections=c)
                    self.qeval = tf.matmul(l1, w2) + b2

        with tf.variable_scope('loss'):
                self.loss = tf.reduce_mean(tf.squared_difference(self.qtarget,self.qeval))

        with tf.variable_scope('optimizer'):
                self.train = tf.train.AdamOptimizer(self.learning_rate).minimize(self.loss)

        #target network
        self.st = tf.placeholder(tf.float32,[None,self.n_features])

        with tf.variable_scope('target_network'):
                c = ['target_network_parameters', tf.GraphKeys.GLOBAL_VARIABLES]
                # first layer
                with tf.variable_scope('layer1'):
                        w1 = tf.get_variable('w1', [self.n_features,hidden_units],initializer=tf.contrib.layers.xavier_initializer(),dtype=tf.float32,collections=c)
                        b1 = tf.get_variable('b1', [1,hidden_units],initializer=tf.contrib.layers.xavier_initializer(),dtype=tf.float32,collections=c)
                        l1 = tf.nn.relu(tf.matmul(self.st, w1) + b1)

                # second layer
                with tf.variable_scope('layer2'):
                        w2 = tf.get_variable('w2',[hidden_units,self.n_actions],initializer=tf.contrib.layers.xavier_initializer(),dtype=tf.float32,collections=c)
                        b2 = tf.get_variable('b2',[1,self.n_actions],initializer=tf.contrib.layers.xavier_initializer(),dtype=tf.float32,collections=c)
                        self.qt = tf.matmul(l1, w2) + b2

现在,我们将使用以下代码定义target_params_replaced(self)。 运行将主网络参数分配给目标网络参数的张量操作的函数:

def target_params_replaced(self):
        self.sess.run(self.replacing_target_parameters)

现在,我们将定义store_experience(self,obs,a,r,obs_),该函数用于将每种体验(即(状态,动作,奖励,新状态)的元组)存储在其体验缓冲区中,通过该数组可以训练主要目标,例如以下代码:

def store_experience(self,obs,a,r,obs_):
        index = self.experience_counter % self.experience_limit
        self.memory[index,:] = np.hstack((obs,[a,r],obs_))
        self.experience_counter+=1

在这里,我们将定义fit(self),该函数是通过从经验缓冲区中选择一批来训练网络,计算q_target的张量值,然后最小化qeval之间的损失(即输出)的函数。 来自主网络的数据)和q_target(即使用目标网络计算的 Q 值)。 我们将使用以下代码定义函数:

def fit(self):
        # sample batch memory from all memory
        if self.experience_counter < self.experience_limit:
               indices = np.random.choice(self.experience_counter, size=self.batch_size)
        else:
               indices = np.random.choice(self.experience_limit, size=self.batch_size)

        batch = self.memory[indices,:]
        qt,qeval = self.sess.run([self.qt,self.qeval],feed_dict={self.st:batch[:,-self.n_features:],self.s:batch[:,:self.n_features]})

        qtarget = qeval.copy() 
        batch_indices = np.arange(self.batch_size, dtype=np.int32)
        actions = self.memory[indices,self.n_features].astype(int)
        rewards = self.memory[indices,self.n_features+1]
        qtarget[batch_indices,actions] = rewards + self.gamma * np.max(qt,axis=1)

        self.sess.run(self.train,feed_dict = {self.s:batch[:,:self.n_features],self.qtarget:qtarget})

        #increasing epsilon 
        if self.epsilon < 0.9:
                self.epsilon += 0.0002

        #replacing target network parameters with primary network parameters 
        if self.learning_counter % self.replace_target_pointer == 0:
                self.target_params_replaced()
                print("target parameters changed")

        self.learning_counter += 1

我们已经讨论了探索与利用难题。 ε 贪婪方法是用于选择阈值ε并产生随机数的方法之一。 如果小于ε,我们将遵循相同的策略;如果大于ε,我们将随机探索行动,反之亦然。 在epsilon_greedy(self,obs)中,我们以动态方式实现了 ε 贪婪方法,其中在fit(self)函数中,我们在每个学习步骤中都增加了ε的值:

def epsilon_greedy(self,obs):
        #epsilon greedy implementation to choose action
        if np.random.uniform(low=0,high=1) < self.epsilon:
            return np.argmax(self.sess.run(self.qeval,feed_dict={self.s:obs[np.newaxis,:]}))
        else:
            return np.random.choice(self.n_actions)

以下是main函数,该函数创建上一个 DQN 类的对象,使用 Gym 来获取MountainCar-v0环境,并训练智能体程序来解决问题。 像在 Q 学习中一样,在这里我们还更新了奖励值,将其作为当前位置与最低点位置(即起点)之间的绝对差值,从而使其偏离中心而最大化了奖励:

if __name__ == "__main__":
      env = gym.make('MountainCar-v0')
      env = env.unwrapped
      dqn = DQN(learning_rate=0.001,gamma=0.9,n_features=env.observation_space.shape[0],n_actions=env.action_space.n,epsilon=0.0,parameter_changing_pointer=500,memory_size=5000)
      episodes = 10
      total_steps = 0

      for episode in range(episodes):
            steps = 0 
            obs = env.reset()
            episode_reward = 0
            while True:
                env.render()
                action = dqn.epsilon_greedy(obs)
                obs_,reward,terminate,_ = env.step(action)
                reward = abs(obs_[0]+0.5)
                dqn.store_experience(obs,action,reward,obs_)
                if total_steps > 1000:
                      dqn.fit()
                episode_reward+=reward
                if terminate:
                      break
                obs = obs_
                total_steps+=1
                steps+=1
            print("Episode {} with Reward : {} at epsilon {} in steps {}".format(episode+1,episode_reward,dqn.epsilon,steps))

      while True: #to hold the render at the last step when Car passes the flag
            env.render() 

前面的程序将打印以下内容:

target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
Episode 1 with Reward : 1399.25710453 at epsilon 0.5948 in steps 3974
target parameters changed
Episode 2 with Reward : 168.166352703 at epsilon 0.6762 in steps 406
target parameters changed
Episode 3 with Reward : 67.6246277944 at epsilon 0.7568 in steps 402
Episode 4 with Reward : 53.1292577484 at epsilon 0.7942 in steps 186
target parameters changed
Episode 5 with Reward : 38.90009005 at epsilon 0.818 in steps 118
Episode 6 with Reward : 60.9286778233 at epsilon 0.8738 in steps 278
target parameters changed
Episode 7 with Reward : 72.433268035 at epsilon 0.9002 in steps 257
Episode 8 with Reward : 80.7812592557 at epsilon 0.9002 in steps 251
target parameters changed
Episode 9 with Reward : 92.123978864 at epsilon 0.9002 in steps 234
Episode 10 with Reward : 38.7923903502 at epsilon 0.9002 in steps 126

在这里,它收敛很快,但是还取决于对动作的探索和利用以及参数和超参数的初始化。 这还将渲染一个环境,显示汽车在行驶并采取最佳路径并达到目标状态,如以下屏幕截图所示:

接下来,在以下主题中,我们尝试实现一个深度 Q 网络来解决 OpenAI Gym 中的 Cartpole 问题。

用于 OpenAI Gym Cartpole 问题的深度 Q 网络

Cartpole 是 MDP 环境中最简单的问题之一,如以下屏幕快照所示。 它由一个在水平轴上移动的推车组成,该推车的中心处固定有一根可旋转的杆。 目的是采取行动,使电杆保持接近垂直且不会向下旋转。

车杆环境中的状态是一个 4 维连续空间,其中每个维如下:

  • x:表示推车位置(最小值为 -2.4,最大值为 2.4)
  • x_dot:表示推车速度(最小值为-∞
  • theta:显示以弧度为单位的角度(最小值为 -0.73,最大值为 0.73)
  • theta_dot:显示角速度(最小值为-∞,最大值为

在给定状态下的每一步,都有两种可能的动作,即推车可以向左或向右移动,并且每一步收到的奖励为 1。这里,只要杆子靠近垂直,推车在边界内。 如果发生以下情况,则剧集被视为结束:

  • 极点下降超过某个角度,即超过 ±0.20944 弧度
  • 推车超出框架左侧或右侧太远,即超出 ±2.4

因此,该问题的目的是将杆保持在接近垂直的位置,而推车不会越过边界越长。

为了为 Cartpole 问题实现深层 Q 网络,我们将导入先前创建的 DQN 类。 请按照以下代码在 Cartpole 环境中实现深度 Q 网络。 如果连续 100 次试验的平均奖励大于或等于 195,则认为该问题已解决:

#Importing dependencies
import gym
import numpy as np

#Importing the DQN class created preceding
from Deep_Q_Network_Mountain_Car import DQN

现在,我们将使用以下代码探索 Cartpole 环境:

env = gym.make('CartPole-v0')
env = env.unwrapped

print(env.action_space)
print(env.observation_space)
print(env.observation_space.high)
print(env.observation_space.low)
print("Position extreme threshold value:",env.x_threshold)
print("Angle extreme threshold value:",env.theta_threshold_radians)

先前的打印语句输出以下内容:

Making new env: CartPole-v0
Discrete(2)
Box(4,)
[ 4.80000000e+00 3.40282347e+38 4.18879020e-01 3.40282347e+38]
[ -4.80000000e+00 -3.40282347e+38 -4.18879020e-01 -3.40282347e+38]
Position extreme threshold value: 2.4
Angle extreme threshold value: 0.20943951023931953

在此,观察空间的高/低值遵循以下顺序(位置,速度,角度,角速度)

下面的代码是我们创建 DQN 上一类的对象,使用 Gym 来获取 Cartpole-v0 环境以及训练智能体程序以解决问题的主要部分。 在这里,我们将奖励值更新为位置与极端位置之差和角度与极端极角之差的总和,因为远离极限位置,角度将变得更小,并且更接近推车的中央,因此奖励应该更高。 这样做是为了实现更好的主网络融合。 我们将使用此奖励进行学习,但是为了计算总体成功程度,我们将使用原始奖励:

dqn = DQN(learning_rate=0.01,gamma=0.9,n_features=env.observation_space.shape[0],n_actions=env.action_space.n,epsilon=0.0,parameter_changing_pointer=100,memory_size=2000)

episodes = 150
total_steps = 0
rew_ep = []

for episode in range(episodes):
    steps = 0
    obs = env.reset()
    episode_reward = 0
    while True:
        env.render()
        action = dqn.epsilon_greedy(obs)
        obs_,reward,terminate,_ = env.step(action)

        #smaller the theta angle and closer to center then better should be the reward
        x, vel, angle, ang_vel = obs_
        r1 = (env.x_threshold - abs(x))/env.x_threshold - 0.8
        r2 = (env.theta_threshold_radians - abs(angle))/env.theta_threshold_radians - 0.5
        reward = r1 + r2

        dqn.store_experience(obs,action,reward,obs_)
        if total_steps > 1000:
            dqn.fit()
        episode_reward+=reward
        if terminate:
            break
        obs = obs_
        total_steps+=1
        steps+=1
    print("Episode {} with Reward : {} at epsilon {} in steps {}".format(episode+1,episode_reward,dqn.epsilon,steps))
    rew_ep.append(episode_reward)

print("Mean over last 100 episodes are: ",np.mean(rew_ep[50:]))
while True: #to hold the render at the last step when Car passes the flag
    env.render()

前面的程序将打印输出,如下所示:

.................
.................
.................
Episode 145 with Reward : 512.0 at epsilon 0.9002 in steps 511
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
Episode 146 with Reward : 567.0 at epsilon 0.9002 in steps 566
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
Episode 147 with Reward : 1310.0 at epsilon 0.9002 in steps 1309
Episode 148 with Reward : 22.0 at epsilon 0.9002 in steps 21
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
Episode 149 with Reward : 1171.0 at epsilon 0.9002 in steps 1170
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
target parameters changed
Episode 150 with Reward : 1053.0 at epsilon 0.9002 in steps 1052
Mean over last 100 episodes are: 248.72999999999999

由于输出日志太长,因此在这里,我们的输出适合最近六个剧集以及最近 100 个剧集的每集平均奖励。

用于 OpenAI Gym Atari Breakout 的深度 Q 网络

Breakout 环境是 Atari 的 Nolan Bushnell,Steve Bristow 和 Steve Wozniak 团队开发的。与我们在山地车 Cartpole 中看到的状态相比,Atari Breakout 环境的状态要大得多。 或“冰湖”。 状态空间与我们在 Atari Pong 中看到的范围相似。 因此,学习收敛需要很长时间。 以下屏幕快照说明了 Atari Breakout 环境的初始图像帧:

Breakout-v0 环境的屏幕截图

观察空间是连续的,包含图像帧的像素值,并且动作空间是离散的,包括四个不同的动作。 每个图像帧的大小为210 * 160 * 3(高度为 210 像素,宽度为 160 像素,具有 3 个颜色通道,即 RGB)。 因此,我们可以拍摄灰度图像帧,因为不会丢失任何信息,并且尺寸将变为210 * 160。 仅拍摄状态的图像帧将不起作用,因为它无法捕获任何运动信息。 因此,我们将为每个状态堆叠四个连续的图像帧。 因此,状态大小将是4 * 210 * 160 = 134,440。 对于 Atari Breakout,在一定程度上降低采样率不会造成任何信息丢失。 此外,我们还可以裁剪图像框架以避免图像的不必要部分,并保留可能包含足够信息来玩游戏的重要部分。

首先,使用以下代码检查环境:

import gym

env = gym.make('Breakout-v0')
s = env.reset()
print("State space shape : ",env.observation_space)
print("Action space shape : ",env.action_space)
print("Type of actions : ",env.unwrapped.get_action_meanings())

这将输出以下语句:

State space shape : Box(210, 160, 3)
Action space shape : Discrete(4)
Type of actions : ['NOOP', 'FIRE', 'RIGHT', 'LEFT']

因此,我们得到了状态空间和动作空间的形状,以及球拍可以采取的四种不同类型的动作,即无动作(无操作的简称),开火(上方目标砖的球),向右走, 或向左移动以阻止球下降。

我们还检查示例裁剪并查看差异,如下图所示:

裁剪前(左)和裁剪后(右)

游戏以下列方式进行:

  • 底部的球拍将球击发,击中砖块以摧毁屏幕的顶层
  • 击中砖块后,球反弹回来
  • 球拍应向左或向右移动以击中球并阻止其掉落
  • 如果球落到下方,也就是说,从球拍下方的屏幕上移开,则游戏结束且玩家输
  • 如果球从球拍弹起,它将再次上升,从墙壁上弹起并击中更多砖块

因此,目标是通过摧毁所有积木而不让球进入球拍下来赢得比赛。

让我们开始实现一个深层的 Q 网络,以使我们的智能体学习 Atari Breakout 的游戏。 首先,我们将使用以下代码导入必要的库:

#Importing the dependencies

import numpy as np
import tensorflow as tf
import gym
from scipy.misc import imresize

具有以下main函数的class DQN的架构可以使用以下代码定义:

class DQN:

    def __init__(self,learning_rate,gamma,n_features,n_actions,epsilon,parameter_changing_pointer,memory_size,epsilon_incrementer):
    ....
    def add_layer(self,inputs,w_shape=None,b_shape=None,layer=None,ctivation_fn=None,c=None,isconv=False:
    ....
    def weight_variable(self,w_shape,layer,c):
    ....
    def bias_variable(self,b_shape,layer,c):
    ....
    def conv(self,inputs,w):
    ....
    def build_networks(self):
    ....
    def target_params_replaced(self):
    ....
    def store_experience(self,obs,a,r,obs_):
    ....
    def fit(self):
    ....
    def epsilon_greedy(self,obs): 
    ....

if __name__ == "__main__":
    ....

让我们讨论 DQN 类及其参数,它包含一个深度 Q 网络的架构:

  • __init__(self,learning_rate,gamma,n_features,n_actions,epsilon,parameter_changing_pointer,memory_size):分配超参数的默认构造器,例如:
    • learning_rate
    • gamma:即折扣系数
    • n_feature:状态下的特征数量,即状态下的尺寸数
    • epsilon:利用或探索行为的ε贪婪条件的阈值
    • parameter_changing_pointer:一个整数值(例如n),指定在每n次迭代之后,将主网络的参数复制到目标网络
    • memory_size:体验回复的最大长度
  • add_layer(self,inputs,w_shape=None,b_shape=None,layer=None,activation_fn=None,c=None,isconv=False):在神经网络中创建层的函数
  • weight_variable(self,w_shape,layer,c):创建权重参数的函数
  • bias_variable(self,b_shape,layer,c):创建偏置参数的函数
  • conv(self,inputs,w):对图像帧执行卷积运算的函数
  • build_networks():此函数用于使用 TensorFlow 创建主要网络和目标网络
  • target_params_replaced(self):用于将目标网络参数替换为主网络参数
  • store_experience(self,obs,a,r,obs_):帮助存储经验,即(状态,动作,奖励,新状态)的元组
  • fit(self):用于训练我们的深度 Q 网络
  • epsilon_greedy(self,obs):它可以帮助我们针对给定的观察状态选择正确的操作,即按照现有策略利用操作或随机探索新操作

现在,使用以下代码定义__init__ default构造器:

def __init__(self,learning_rate,gamma,n_features,n_actions,epsilon,parameter_changing_pointer,
             memory_size,epsilon_incrementer):

        tf.reset_default_graph()
        self.learning_rate = learning_rate
        self.gamma = gamma
        self.n_features = n_features
        self.n_actions = n_actions
        self.epsilon = epsilon
        self.batch_size = 32
        self.experience_counter = 0
        self.epsilon_incrementer = epsilon_incrementer
        self.experience_limit = memory_size
        self.replace_target_pointer = parameter_changing_pointer
        self.learning_counter = 0
        self.memory = [] #np.zeros([self.experience_limit,4]) #for experience replay

        self.build_networks()
        p_params = tf.get_collection('primary_network_parameters')
        t_params = tf.get_collection('target_network_parameters')
        self.replacing_target_parameters = [tf.assign(t,p) for t,p in zip(t_params,p_params)]

        self.sess = tf.Session()
        self.sess.run(tf.global_variables_initializer())

以下代码定义了add_layer函数,该函数通过提供isconv的布尔参数来帮助根据卷积的要求创建不同的层或全连接层,如果isconvtrue,则表示是卷积层:

def add_layer(self,inputs,w_shape=None,b_shape=None,layer=None,activation_fn=None,c=None,isconv=False):
        w = self.weight_variable(w_shape,layer,c)
        b = self.bias_variable(b_shape,layer,c)
        eps = tf.constant(value=0.000001, shape=b.shape)
        if isconv:
            if activation_fn is None:
                return self.conv(inputs,w)+b+eps
            else:
                h_conv = activation_fn(self.conv(inputs,w)+b+eps) 
                return h_conv
        if activation_fn is None:
            return tf.matmul(inputs,w)+b+eps
        outputs = activation_fn(tf.matmul(inputs,w)+b+eps)
        return outputs

接下来,我们具有weight_variablebias_variable函数。 以下代码用于定义权重参数:

def weight_variable(self,w_shape,layer,c):
        return tf.get_variable('w'+layer,w_shape,initializer=tf.contrib.layers.xavier_initializer(),
                                     dtype=tf.float32,collections=c)

定义偏置参数的代码:

def bias_variable(self,b_shape,layer,c):
        return tf.get_variable('b'+layer,b_shape,initializer=tf.contrib.layers.xavier_initializer(),
                                     dtype=tf.float32,collections=c)

现在让我们定义conv(self,inputs,w),该函数调用 TensorFlow 的tf.nn.conv2d函数并采用:

  • 输入为二维向量
  • 权重:形状[patch_size,patch_size,input_vector_depth,output_vector_depth]的权重
  • 跨步:以[1,x_movement,y_movement,1]形式出现的列表,其中:
    • x_movement:定义水平移动补丁的步数
    • y_movement:定义在垂直方向上移动的色块的步数
  • 填充SAMEVALID(我们在第 1 章,“深度学习–架构和框架”中讨论了此和有效的填充)

我们将使用以下代码定义函数:

def conv(self,inputs,w):
        #strides [1,x_movement,y_movement,1]
        #stride[0] = stride[3] = 1
        return tf.nn.conv2d(inputs,w,strides=[1,1,1,1],padding='SAME') 

现在,让我们定义build_networks(self)。 它是在以下情况下建立主要和目标网络的函数:

  • variable_scope下创建主要网络参数,即:primary_network和集合primary_network_parameters
  • variable_scope下创建目标网络参数,即:target_network 和集合target_network_parameters
  • 两者具有相同的结构,即:
    • 卷积层 1
    • 卷积层 2
    • 全连接层 1
    • 全连接层 2
    • 使用的激活函数:ReLU

该函数还有助于:

  • 计算主网络输出的 Q 值与目标网络输出的 Q 值之间的损失

我们可以使用亚当优化器将这种损失降到最低。

现在,我们已经了解了该函数,让我们对其进行定义:

def build_networks(self):
        #primary network
        shape = [None] + self.n_features
        self.s = tf.placeholder(tf.float32,shape)
        self.qtarget = tf.placeholder(tf.float32,[None,self.n_actions])

        with tf.variable_scope('primary_network'):
            c = ['primary_network_parameters', tf.GraphKeys.GLOBAL_VARIABLES]
            #first convolutional layer
            with tf.variable_scope('convlayer1'):
                l1 = self.add_layer(self.s,w_shape=[5,5,4,32],b_shape=[32],layer='convL1',activation_fn=tf.nn.relu,c=c,isconv=True)

            #first convolutional layer
            with tf.variable_scope('convlayer2'):
                l2 = self.add_layer(l1,w_shape=[5,5,32,64],b_shape=[64],layer='convL2',activation_fn=tf.nn.relu,c=c,isconv=True)

            #first fully-connected layer
            l2 = tf.reshape(l2,[-1,80*80*64])
            with tf.variable_scope('FClayer1'):
                l3 = self.add_layer(l2,w_shape=[80*80*64,128],b_shape=[128],layer='fclayer1',activation_fn=tf.nn.relu,c=c)

            #second fully-connected layer
            with tf.variable_scope('FClayer2'):
                self.qeval = self.add_layer(l3,w_shape=[128,self.n_actions],b_shape=[self.n_actions],layer='fclayer2',c=c)

        with tf.variable_scope('loss'):
                self.loss = tf.reduce_mean(tf.squared_difference(self.qtarget,self.qeval))

        with tf.variable_scope('optimizer'):
                self.train = tf.train.AdamOptimizer(self.learning_rate).minimize(self.loss)

        #target network
        self.st = tf.placeholder(tf.float32,shape)

        with tf.variable_scope('target_network'):
            c = ['target_network_parameters', tf.GraphKeys.GLOBAL_VARIABLES]
            #first convolutional layer
            with tf.variable_scope('convlayer1'):
                l1 = self.add_layer(self.st,w_shape=[5,5,4,32],b_shape=[32],layer='convL1',activation_fn=tf.nn.relu,c=c,isconv=True)

            #first convolutional layer
            with tf.variable_scope('convlayer2'):
                l2 = self.add_layer(l1,w_shape=[5,5,32,64],b_shape=[64],layer='convL2',activation_fn=tf.nn.relu,c=c,isconv=True)

            #first fully-connected layer
            l2 = tf.reshape(l2,[-1,80*80*64])
            with tf.variable_scope('FClayer1'):
                l3 = self.add_layer(l2,w_shape=[80*80*64,128],b_shape=[128],layer='fclayer1',activation_fn=tf.nn.relu,c=c)

            #second fully-connected layer
            with tf.variable_scope('FClayer2'):
                self.qt = self.add_layer(l3,w_shape=[128,self.n_actions],b_shape=[self.n_actions],layer='fclayer2',c=c)

现在,让我们定义target_params_replaced(self),它是运行将主网络参数分配给目标网络参数的张量操作的函数:

def target_params_replaced(self):
     self.sess.run(self.replacing_target_parameters)

现在,我们将定义store_experience(self,obs,a,r,obs_)函数,以将每种体验(即(状态,动作,奖励,新状态)的元组)存储在其体验缓冲区中,主要目标将在该缓冲区上进行训练:

def store_experience(self,obs,a,r,obs_):
    if len(obs.shape)<3 or len(obs_.shape)<3: 
          print("Wrong shape entered : ",obs.shape,obs_.shape,len(self.memory))
    else:
          index = self.experience_counter % self.experience_limit
          if self.experience_counter < self.experience_limit:
                self.memory.append([obs,a,r,obs_])
          else:
                self.memory[index] = [obs,a,r,obs_]
    self.experience_counter+=1

现在,我们将定义fit(self)函数,以通过从经验缓冲区中选择一个批量来训练网络,计算q_target的张量值,然后最小化qeval之间的损失(即主数据库的输出) 网络)和q_target(即使用目标网络计算的 Q 值):

def fit(self):
        # sample batch memory from all memory
        indices = np.random.choice(len(self.memory), size=self.batch_size)
        batch = [self.memory[i] for i in indices]
        obs_nlist = np.array([i[3] for i in batch])
        obs_list = np.array([i[0] for i in batch])
        qt,qeval = self.sess.run([self.qt,self.qeval],feed_dict={self.st:obs_nlist,self.s:obs_list})

        qtarget = qeval.copy() 
        batch_indices = np.arange(self.batch_size, dtype=np.int32)
        actions = np.array([int(i[1]) for i in batch])
        rewards = np.array([int(i[2]) for i in batch])
        qtarget[batch_indices,actions] = rewards + self.gamma * np.max(qt,axis=1)

        _ = self.sess.run(self.train,feed_dict = {self.s:obs_list,self.qtarget:qtarget})
  print(self.learning_counter+1," learning done")
        #increasing epsilon 
        if self.epsilon < 0.9:
                self.epsilon += self.epsilon_incrementer

        #replacing target network parameters with primary network parameters 
        if self.learning_counter % self.replace_target_pointer == 0:
            self.target_params_replaced()
            print("target parameters changed")

        self.learning_counter += 1

现在,我们将定义epsilon_greedy(self,obs),该函数类似于我们在 DQN 中为山地车和 Cartpole 实现的函数:

def epsilon_greedy(self,obs):
  new_shape = [1]+list(obs.shape)
  obs = obs.reshape(new_shape)
        #epsilon greedy implementation to choose action
        if np.random.uniform(low=0,high=1) < self.epsilon:
            return np.argmax(self.sess.run(self.qeval,feed_dict={self.s:obs})) #[np.newaxis,:]
        else:
            return np.random.choice(self.n_actions)

在类之外,我们有一个函数preprocessing_image,该函数用于预处理以下参数:

  • 裁剪图像
  • 将其转换为灰度
  • 对图像进行下采样
  • 归一化图像

我们将使用以下代码定义函数:

def preprocessing_image(s):
    s = s[31:195]  #cropping
    s = s.mean(axis=2)  #converting to greyscale
    s = imresize(s,size=(80,80),interp='nearest')  #downsampling
    s = s/255.0  #normalizing
    return s 

以下代码定义了main函数,该函数创建 DQN 的上一类的对象,使用gym来获取Breakout-v0环境,并训练智能体程序解决问题:

if __name__ == "__main__":
    env = gym.make('Breakout-v0')
    env = env.unwrapped
    epsilon_rate_change = 0.9/500000.0
    dqn = DQN(learning_rate=0.0001,
              gamma=0.9,
              n_features=[80,80,4],
              n_actions=env.action_space.n,
              epsilon=0.0,
              parameter_changing_pointer=100,
              memory_size=50000,
              epsilon_incrementer=epsilon_rate_change)

    episodes = 100000
    total_steps = 0

    for episode in range(episodes):
        steps = 0

        obs = preprocessing_image(env.reset())
        s_rec = np.stack([obs]*4,axis=0)
        s = np.stack([obs]*4,axis=0)
        s = s.transpose([1,2,0])
        episode_reward = 0
        while True:
            env.render()
            action = dqn.epsilon_greedy(s)
            obs_,reward,terminate,_ = env.step(action)
            obs_ = preprocessing_image(obs_)

            a = s_rec[1:]
            a = a.tolist()
            a.append(obs_)
            s_rec = np.array(a)

            s_ = s_rec.transpose([1,2,0])
            dqn.store_experience(s,action,reward,s_)
            if total_steps > 1999 and total_steps%500==0:
                dqn.fit()
            episode_reward+=reward
            if terminate:
                break
            s = s_
            total_steps+=1
            steps+=1
        print("Episode {} with Reward : {} at epsilon {} in steps {}".format(episode+1,episode_reward,dqn.epsilon,steps))

    while True: #to hold the render at the last step when Car passes the flag
        env.render()

由于权重参数很多,因此在普通计算机上进行收敛需要花费大量时间,而运行 GPU 的计算机运行成本很高。 但是,要见证在普通计算机上融合的可能性,请运行代码 5 到 6 个小时,以查看智能体情况如何好转。 我建议,如果价格合理,请在带有 GPU 的计算机上运行它。 无论如何,前面的main函数的示例输出将如下所示:

....
....
....
Episode 992 with Reward : 0.0 at epsilon 0.0008766 in steps 174
Episode 993 with Reward : 2.0 at epsilon 0.0008766 in steps 319
(488, ' learning done')
Episode 994 with Reward : 0.0 at epsilon 0.0008784 in steps 169
Episode 995 with Reward : 1.0 at epsilon 0.0008784 in steps 228
Episode 996 with Reward : 1.0 at epsilon 0.0008784 in steps 239
(489, ' learning done')
Episode 997 with Reward : 4.0 at epsilon 0.0008802 in steps 401
(490, ' learning done')
Episode 998 with Reward : 0.0 at epsilon 0.000882 in steps 171
Episode 999 with Reward : 4.0 at epsilon 0.000882 in steps 360
(491, ' learning done')
Episode 1000 with Reward : 0.0 at epsilon 0.0008838 in steps 171
Episode 1001 with Reward : 1.0 at epsilon 0.0008838 in steps 238
(492, ' learning done')
Episode 1002 with Reward : 1.0 at epsilon 0.0008856 in steps 249
Episode 1003 with Reward : 1.0 at epsilon 0.0008856 in steps 232
....
....
....

尝试使用不同的参数以更好地收敛。

蒙特卡罗树搜索算法

蒙特卡洛树搜索MCTS)是一种规划算法,是在出现人工窄智能问题时做出最佳决策的一种方法。 MCTS 致力于解决问题的预先规划方法。

在诸如 minimax游戏树之类的早期算法未能显示出具有复杂问题的结果之后,MCTS 算法变得越来越重要。 那么,是什么使 MCTS 与过去的决策算法(例如 minimax)不同并且更好呢?

让我们首先讨论什么是 minimax。

Minimax 和游戏树

Minimax 是 IBM Deep Blue 在 1996 年 2 月 10 日的国际象棋比赛中击败世界冠军 Gary Kasparov 的算法。 那时的胜利是一个非常重要的里程碑。 minimax 和游戏树都是有向图,其中每个节点代表游戏状态,即游戏位置,如下面的井字游戏图所示:

井字游戏树。 顶部节点代表游戏的开始位置。 沿着树走下去导致游戏的结果位置

因此,通过搜索游戏树,由于节点和树中存在的节点和路径的组合,AI 智能体可以选择最佳的移动方式。 这对于游戏复杂度处于可接受水平的问题很有用,因为随着复杂度的增加,游戏树的大小也会增加。 例如,国际象棋的游戏树具有比宇宙中原子更多的节点。 因此,在这种情况下,仅可能进行搜索。 因此,随着复杂度的增加,极大极小的可用性和游戏树减少。

另一个很好的例子是围棋的开放式中文游戏,其棋类复杂度为10^360,而棋类的复杂度为10^123。 由于具有如此高的复杂性,minimax 无法绘制评估函数,甚至无法创建如此大的游戏树。 因此,在《深蓝》取得成功的大约 20 年后,没有算法能够掌握围棋游戏。 原因很简单,当时的最新技术(例如 minimax)无法解决诸如围棋游戏之类具有很高复杂性的问题。 而且,解决围棋需要一种更人性化的学习方式,即基于交互。

因此,Google DeepMind 的 AlphaGo 被认为是最先进的 AI 智能体,它能够在 2016 年使用深度强化学习成功击败 Lee Sedol,该学习用于神经网络,强化学习和蒙特卡洛树搜索。 这是第一次以人类可以实现的方式完成 AI 任务,即通过不断的交互,并通过不断的反复试验过程来获取知识。

蒙特卡罗树搜索

那么,蒙特卡罗树搜索与 minimax 的方法有何不同?它如何在高度复杂的围棋游戏中进行提前计划,围棋有大量潜在的反制动作? MCTS 建立了一个看起来像游戏树的统计树,但是游戏树或 minimax 具有游戏位置,即有向图的节点中的游戏状态,在 MCTS 中,有向图的节点是该游戏的状态数量,告诉我们成功模拟的次数(即在游戏结束时导致获胜的动作)相对于游戏状态经过的模拟总数的数量。 因此,仿真次数越多,越多的节点有机会成为仿真的一部分,从而导致收敛。 因此,每个节点的值取决于仿真次数。

收敛后,此统计树将指导 AI 智能体在每个级别上寻找最佳可能节点,并继续进行直至达到目标。 最初,统计树用于扩展,以便通过多次仿真为可能的游戏状态添加更多节点。 收集足够数量的节点后,同时开始选择更好的节点,如果节点成功实现了问题目标,则每次仿真它们的值都会增加,从而提高了实用性。

在选择策略中,MCTS 还通过在现有的,有希望的节点与可能更有希望的未探索节点之间保持平衡来纳入探索与利用的权衡。 因此,仿真次数越多,统计树越大,则节点值收敛得越准确,最优决策就越好。

MCTS 是独立于域的,不需要复杂的手写试探法。 因此,它是解决各种开放式 AI 问题的强大算法。

SARSA 算法

状态-动作-奖励-状态-动作SARSA)算法是一种基于策略的学习问题。 就像 Q 学习一样,SARSA 也是一个时差学习问题,也就是说,它会预测剧集的下一步以估计未来的回报。 SARSA 和 Q 学习之间的主要区别在于,具有最大 Q 值的动作不用于更新当前状态动作对的 Q 值。 取而代之的是,选择作为当前策略结果的操作的 Q 值,或者由于采用诸如 ε 贪婪之类的探索步骤来更新当前状态操作对的 Q 值。 SARSA 之所以得名,是因为使用五元组Q(s, a, r, s', a')完成了 Q 值更新,其中:

  • sa:当前状态和操作
  • r:采取行动后观察到的奖励a
  • s':在采取操作a后到达下一个状态
  • a':要在状态s'下执行的动作

SARSA 算法涉及的步骤如下:

  1. 随机初始化 Q 表

  2. 对于每个剧集:

    1. 对于给定状态s,请从 Q 表中选择操作a

    2. 执行动作a

    3. 奖励R和新状态s'

    4. 对于新状态s',请从 Q 表中选择操作a'

    5. 通过以下操作更新当前状态操作的 Q 值,即Q(s, a)对:

SARSA 算法的伪代码如下:

Create Q-table where rows represent different states and columns represent different actions

Initialize Q(s,a) arbitrarily, e.g. 0 for all states
set action value for terminal states as 0

For each episode:
    Start with the starting state that is Initialize s to start
    Choose action a for s using the policy derived from Q [e.g. -greedy, either for the given 's' which 'a' has the max Q-value or choose a random action]
    Repeat for each step in the episode:
        Take the chosen action a, observe reward R and new state s'
        Choose action a' for s' using the policy derived from Q 
        [e.g. -greedy]
        Update 

    until s is the terminal state
end

用于 OpenAI Gym 山地车问题的 SARSA 算法

让我们尝试实现先前在山地车问题中解释过的 SARSA 算法。 该程序的初始部分与先前的 Q 学习器具有相似之处。

首先,我们将使用以下代码导入依赖项并检查山地车环境:

#importing the dependencies

import gym
import numpy as np

#exploring Mountain Car environment

env_name = 'MountainCar-v0'
env = gym.make(env_name)

print("Action Set size :",env.action_space)
print("Observation set shape :",env.observation_space) 
print("Highest state feature value :",env.observation_space.high) 
print("Lowest state feature value:",env.observation_space.low) 
print(env.observation_space.shape) 

前面的打印语句输出以下内容:

Making new env: MountainCar-v0
('Action Set size :', Discrete(3))
('Observation set shape :', Box(2,))
('Highest state feature value :', array([ 0.6 , 0.07]))
('Lowest state feature value:', array([-1.2 , -0.07]))
(2,)

接下来,我们将使用以下代码分配超参数,例如状态数,剧集数,学习率(初始和最小值),折扣因子伽玛,剧集中的最大步长以及 ε 贪婪的ε

n_states = 40  # number of states
episodes = 10 # number of episodes

initial_lr = 1.0 # initial learning rate
min_lr = 0.005 # minimum learning rate
gamma = 0.99 # discount factor
max_steps = 300
epsilon = 0.05

env = env.unwrapped
env.seed(0)         #setting environment seed to reproduce same result
np.random.seed(0)   #setting numpy random number generation seed to reproduce same random numbers

我们的下一个任务是创建一个函数,对连续状态空间进行离散化。 离散化是将连续状态空间观察转换为离散状态空间集。 我们将使用以下代码执行离散化:

def discretization(env, obs):

    env_low = env.observation_space.low
    env_high = env.observation_space.high

    env_den = (env_high - env_low) / n_states
    pos_den = env_den[0]
    vel_den = env_den[1]

    pos_high = env_high[0]
    pos_low = env_low[0]
    vel_high = env_high[1]
    vel_low = env_low[1]

    pos_scaled = int((obs[0] - pos_low)/pos_den)  #converts to an integer value
    vel_scaled = int((obs[1] - vel_low)/vel_den)  #converts to an integer value

    return pos_scaled,vel_scaled

到目前为止,每个任务都与我们在 Q 学习算法中所做的相似。 现在,SARSA 的实现从初始化 Q 表并相应地更新 Q 值开始,如以下代码所示。 同样,在这里,我们将奖励值更新为当前位置与最低点(即起点)之间的绝对差值,以便它通过远离中心即最低点来最大化奖励:

#Q table
#rows are states but here state is 2-D pos,vel
#columns are actions
#therefore, Q- table would be 3-D

q_table = np.zeros((n_states,n_states,env.action_space.n))
total_steps = 0
for episode in range(episodes):
   obs = env.reset()
   total_reward = 0
   # decreasing learning rate alpha over time
   alpha = max(min_lr,initial_lr*(gamma**(episode//100)))
   steps = 0

   #action for the initial state using epsilon greedy
   if np.random.uniform(low=0,high=1) < epsilon:
        a = np.random.choice(env.action_space.n)
   else:
        pos,vel = discretization(env,obs)
        a = np.argmax(q_table[pos][vel])

   while True:
      env.render()
      pos,vel = discretization(env,obs)

      obs,reward,terminate,_ = env.step(a) 
      total_reward += abs(obs[0]+0.5) 
      pos_,vel_ = discretization(env,obs)

      #action for the next state using epsilon greedy
      if np.random.uniform(low=0,high=1) < epsilon:
          a_ = np.random.choice(env.action_space.n)
      else:
          a_ = np.argmax(q_table[pos_][vel_])

      #q-table update
      q_table[pos][vel][a] = (1-alpha)*q_table[pos][vel][a] + alpha*(reward+gamma*q_table[pos_][vel_][a_])
      steps+=1
      if terminate:
          break
      a = a_
   print("Episode {} completed with total reward {} in {} steps".format(episode+1,total_reward,steps)) 
while True: #to hold the render at the last step when Car passes the flag
   env.render()  

前面的程序将以以下方式打印:

Episode 1 completed with total reward 11167.6296185 in 36605 steps
Episode 2 completed with total reward 830.204697241 in 2213 steps
Episode 3 completed with total reward 448.46977318 in 1899 steps
Episode 4 completed with total reward 930.154976751 in 3540 steps
Episode 5 completed with total reward 6864.96292351 in 20871 steps
Episode 6 completed with total reward 677.449030827 in 3995 steps
Episode 7 completed with total reward 2994.99152751 in 7401 steps
Episode 8 completed with total reward 724.212076546 in 3267 steps
Episode 9 completed with total reward 192.502071909 in 928 steps
Episode 10 completed with total reward 213.212231118 in 786 steps

因此,我们已经能够成功实现山地车问题的 SARSA 算法。

总结

我们知道强化学习可以优化环境中智能体的回报,马尔可夫决策过程MDP)是一种环境表示和数学框架,用于使用状态对决策进行建模 ,动作和奖励。 在本章中,我们了解到 Q 学习是一种无需任何转移模型即可为任何 MDP 找到最佳动作选择策略的方法。 另一方面,如果给出了转换模型,则值迭代会为任何 MDP 找到最佳的动作选择策略。

我们还学习了另一个重要的话题,称为深度 Q 网络,这是一种经过改进的 Q 学习方法,它采用深度神经网络作为函数逼近器来在不同环境中进行泛化,这与特定于环境的 Q 表不同。 此外,我们还学会了在 OpenAI Gym 环境中实现 Q 学习,深度 Q 网络和 SARSA 算法。 先前显示的大多数实现可能在具有更好的超参数值和更多训练集的情况下效果更好。

在下一章中,我们将详细介绍著名的异步优势参与者批评算法。

六、异步方法

到目前为止,我们已经涵盖了大多数重要主题,例如马尔可夫决策过程,值迭代,Q 学习,策略梯度,深度 Q 网络和参与者批评算法。 这些构成了强化学习算法的核心。 在本章中,我们将继续从演员评论家算法中停止的地方继续搜索,并深入研究用于深度强化学习的高级异步方法及其最著名的变体异步优势演员评论家算法,通常称为 A3C 算法

但是,在开始使用 A3C 算法之前,让我们修改第 4 章和“策略梯度”中涵盖的演员评论家算法的基础。 如果您还记得,演员评论算法有两个组成部分:

  • 演员
  • 评论家

参与者采取当前的环境状态并确定要采取的最佳行动,而评论家则通过采取环境状态和行动来扮演策略评估角色,并返回一个分数,以描述该状态对某项行动的良好程度。 如下图所示:

换句话说,演员的行为像孩子,而评论家的行为像父母,孩子探索多种行为,父母批评不良行为并补充良好行为。 因此,行动者批判算法既学习了策略函数,又学习了状态作用值函数。 像策略梯度一样,参与者评论算法也通过梯度上升来更新其参数。 在高维连续状态和动作空间的情况下,演员评论家方法非常有效。

因此,让我们从 Google DeepMind 发布的深度强化学习中的异步方法开始,该方法在表现和计算效率方面都超过了 DQN。

我们将在本章介绍以下主题:

  • 为什么使用异步方法?
  • 异步一步 Q 学习
  • 异步一步 SARSA
  • 异步 N 步 Q 学习
  • 异步优势演员评论家
  • OpenAI Gym 中用于 CartPole v0 的 A3C

为什么使用异步方法?

Google DeepMind 和 MILA 的联合团队于 2016 年 6 月发布了用于深度强化学习的同步方法。 它速度更快,并且能够在多核 CPU 上而不是使用 GPU 上显示出良好的效果。 异步方法也适用于连续动作空间和离散动作空间。

如果我们回想起深度 Q 网络的方法,我们会使用经验回放作为存储所有经验的存储,然后使用其中的随机样本来训练我们的深度神经网络,从而反过来预测最大 Q 值。 有利的行动。 但是,随着时间的流逝,它具有高内存使用和大量计算的缺点。 这背后的基本思想是克服这个问题。 因此,不是使用经验回放,而是创建了环境的多个实例,并且多个智能体以异步方式并行执行操作(如下图所示):

深度强化学习中异步方法的高级示意图

在异步方法中,为每个线程分配了一个进程,该进程包含一个学习器,该学习器表示与自己的环境副本进行交互的智能体网络。 因此,这些多个学习器并行运行以探索他们自己的环境版本。 这种并行方法允许智能体在任何给定的时间步长同时经历各种不同的状态,并涵盖了非策略学习和策略学习学习算法的基础。

如上所述,异步方法能够在多核 CPU(而不是 GPU)中显示出良好的效果。 因此,异步方法非常快,因此成为最新的强化学习算法,因为到目前为止,深度强化学习算法的实现依赖于 GPU 驱动的机器和分布式架构,以见证所实现算法的更快收敛。

这些并行运行的多个学习器使用不同的探索策略,从而最大限度地提高了多样性。 不同学习器的不同探索策略会更改参数,并且这些更新与时间相关的机会最少。 因此,不需要经验回放记忆,并且我们依靠使用不同探索策略的并行学习来执行先前在 DQN 中使用的经验回放的角色。

使用并行学习器的好处如下:

  • 减少训练时间。
  • 不使用经验回放。 因此,基于策略的强化学习方法也可以用于训练神经网络。

深度强化学习中异步方法的不同变体是:

  • 异步一步 Q 学习
  • 异步一步 SARSA
  • 异步 N 步 Q 学习
  • 异步优势演员评论家A3C

将变体 A3C 应用于各种 Atari 2600 游戏时,在多核 CPU 上获得了更好的基准测试结果,相对于早期的深度强化学习算法而言,其结果所需的时间要短得多,后者需要在 GPU 驱动的机器上运行。 因此,由于依赖于昂贵的硬件资源(如 GPU)以及不同的复杂分布式架构,因此解决了该问题。 由于所有这些优点,A3C 学习智能体是当前最先进的强化学习智能体。

异步单步 Q 学习

异步单步 Q 学习的架构与 DQN 非常相似。 DQN 中的智能体由一组主要网络和目标网络表示,其中一步损失的计算方法是主要网络预测的当前状态s的状态作用值与目标状态- 目标网络计算的当前状态的动作值。 相对于策略网络的参数来计算损失的梯度,然后使用梯度下降优化器将损失最小化,从而导致主网络的参数更新。

异步单步 Q 学习中的区别在于,有多个此类学习智能体,例如,学习器并行运行并计算此损失。 因此,梯度计算也并行发生在不同的线程中,其中每个学习智能体都与自己的环境副本进行交互。 这些梯度在多个时间步长上在不同线程中的累积用于在固定时间步长后或剧集结束后更新策略网络参数。 梯度的累积优于策略网络参数更新,因为这样可以避免覆盖每个学习器智能体执行的更改。

此外,将不同的探索策略添加到不同的线程可以使学习变得多样化且稳定。 由于更好的探索,因此提高了表现,因为不同线程中的每个学习智能体都受到不同的探索策略。 尽管有许多方法可以执行此操作,但一种简单的方法是在使用 ε 贪婪的同时为不同的线程使用不同的ε示例。

异步单步 Q 学习的伪代码如下所示。 这里,以下是全局参数:

  • :策略网络的参数(权重和偏差)
  • :目标网络的参数(权重和偏差)
  • T:整体时间步长计数器
// Globally shared parameters , and T 
//  is initialized arbitrarily
// T is initialized 0

pseudo-code for each learner running parallel in each of the threads:

Initialize thread level time step counter t=0
Initialize  = 
Initialize network gradients 
Start with the initial state s

repeat until  :
    Choose action a with -greedy policy such that:

    Perform action a
    Receive new state s' and reward r
    Compute target y : 
    Compute the loss, 
    Accumulate the gradient w.r.t. : 
    s = s'
    T = T + 1
    t = t + 1

    if T mod  : 
        Update the parameters of target network :  = 
        # After every  time steps the parameters of target network is updated

    if t mod  or s = terminal state:
        Asynchronous update of  using 
        Clear gradients : 
        #at every  time step in the thread or if s is the terminal state
        #update  using accumulated gradients 

异步单步 SARSA

异步单步 SARSA 的架构几乎与异步单步 Q 学习的架构相似,不同之处在于目标网络计算当前状态的目标状态作用值的方式。 SARSA 并未使用目标网络使用下一个状态s'的最大 Q 值,而是使用 ε 贪婪为下一个状态s'选择动作a'。 下一个状态动作对的 Q 值Q(s', a')Q(s', a', θ[t])用于计算当前状态的目标状态动作值。

异步单步 SARSA 的伪代码如下所示。 这里,以下是全局参数:

  • θ:策略网络的参数(权重和偏差)
  • $1ₜ:目标网络的参数(权重和偏差)
  • T:总时间步长计数器
// Globally shared parameters , and T 
//  is initialized arbitrarily
// T is initialized 0

pseudo-code for each learner running parallel in each of the threads:

Initialize thread level time step counter t=0
Initialize  = 
Initialize network gradients 
Start with the initial state s
Choose action a with -greedy policy such that:

repeat until  :
    Perform action a
    Receive new state s' and reward r
    Choose action a' with -greedy policy such that:

    Compute target y : 
    Compute the loss, 
    Accumulate the gradient w.r.t. : 
    s = s'
    T = T + 1
    t = t + 1
    a = a'

    if T mod  : 
         Update the parameters of target network :  = 
         # After every  time steps the parameters of target network is updated

    if t mod  or s = terminal state:
         Asynchronous update of  using 
         Clear gradients : 
         #at every  time step in the thread or if s is the terminal state
         #update  using accumulated gradients 

异步 N 步 Q 学习

异步 N 步 Q 学习的架构在某种程度上类似于异步单步 Q 学习的架构。 区别在于,使用探索策略最多选择t[max]步骤或直到达到终端状态,才能选择学习智能体动作,以便计算策略网络参数的单个更新。 此过程列出了自上次更新以来t[max]来自环境的奖励。 然后,对于每个时间步长,将损失计算为该时间步长的折扣未来奖励与估计 Q 值之间的差。 对于每个时间步长,此损失相对于特定于线程的网络参数的梯度将被计算和累积。 有多个这样的学习智能体并行运行和累积梯度。 这些累积的梯度用于执行策略网络参数的异步更新。

异步 N 步 Q 学习的伪代码如下所示。 这里,以下是全局参数:

  • θ:策略网络的参数(权重和偏差)
  • $1ₜ:目标网络的参数(权重和偏差)
  • T:总时间步长计数器
  • t:线程级时间步长计数器
  • T[max]:总时间步长的最大值
  • t[max]:线程中的最大时间步数
// Globally shared parameters , and T 
//  is initialized arbitrarily
// T is initialized 0

pseudo-code for each learner running parallel in each of the threads:

Initialize thread level time step counter t = 1
Initialize  = 
Initialize  = 
Initialize network gradients 

repeat until  :
     Clear gradient : 
     Synchronize thread-specific parameters: 

     Get state 
     r = [] //list of rewards
     a = [] //list of actions
     s = [] //list of actions
     repeat until  is a terminal state or :
             Choose action  with -greedy policy such that:

             Perform action 
             Receive new state  and reward 
             Accumulate rewards by appending  to r
             Accumulate actions by appending  to a
             Accumulate actions by appending  to s
             t = t + 1
             T = T + 1

     Compute returns, R : 
     for  :

            Compute loss, 
            Accumulate gradients w.r.t.  :

     Asynchronous update of  using 
     if T mod  : 
         Update the parameters of target network :  = 
         # After every  time steps the parameters of target network is updated

异步优势演员评论家

在异步优势参与者批评者的架构中,每个学习智能体都包含一个参与者批评者,该学习器结合了基于值和基于策略的方法的优点。 参与者网络将状态作为输入,并预测该状态的最佳动作,而评论家网络将状态和动作作为输入,并输出动作分数以量化该状态的动作效果。 参与者网络使用策略梯度更新其权重参数,而评论家网络使用TD(0)来更新其权重参数,换言之,两个时间步长之间的值估计之差,如第 4 章“策略梯度”中所述。

在第 4 章和“策略梯度”中,我们研究了如何通过从策略梯度的预期未来收益中减去基线函数来更新策略梯度,从而在不影响预期收益的情况下减少方差的情况。 梯度。 预期的未来奖励和基线函数之间的差称为优势函数; 它不仅告诉我们状态的好坏,而且还告诉我们该动作的预期好坏。

卷积神经网络既用于演员网络,又用于评论家网络。 在每个t[max]步骤之后或直到达到终端状态之前,将更新策略和操作值参数。 将与以下伪代码一起说明网络更新,熵和目标函数。 此外,将策略π的熵H添加到目标函数中,以通过避免过早收敛到次优策略来改善探索。

因此,有多个这样的学习智能体程序运行,每个学习智能体程序都包含参与者关键网络,其中策略网络参数(即参与者网络参数)使用策略梯度进行更新,其中优势函数用于计算那些策略梯度。

异步单步 SARSA 的伪代码如下所示。 这里,以下是全局参数:

  • θ:策略网络的参数(权重和偏差)
  • θ[v]:值函数逼近器的参数(权重和偏差)
  • T:总时间步长计数器

特定于线程的参数如下:

  • :策略网络的线程特定参数
  • :值函数近似器的线程特定参数
//Globally shared parameters  and T
//  is initialized arbitrarily
//  is initialized arbitrarily
// T is initialized 0

pseudo-code for each learner running parallel in each of the threads:

//Thread specific parameters  and 
Initialize thread level time step counter t = 1
repeat until  :
    reset gradients :  and 
    synchronize thread specific parameters :  and 

    Get state 
    r = [] //list of rewards
    a = [] //list of actions
    s = [] //list of actions
    repeat until  is a terminal state or :
        Perform  according to policy 
        Receive new state  and reward 
        Accumulate rewards by appending  to r
        Accumulate actions by appending  to a
        Accumulate actions by appending  to s
        t = t + 1
        T = T + 1

    Compute returns, that is expected future rewards R such that:

    for  :

            Accumulate gradients w.r.t.  :

            Accumulate gradients w.r.t.  :

    Asynchronous update of  using  and  using 

OpenAI Gym 中 Pong-v0 的 A3C

在第 4 章和“策略梯度”中,我们已经讨论过乒乓环境。 我们将使用以下代码在 OpenAI Gym 中为 Pong-v0 创建 A3C:

import multiprocessing
import threading
import tensorflow as tf
import numpy as np
import gym
import os
import shutil
import matplotlib.pyplot as plt

game_env = 'Pong-v0'
num_workers = multiprocessing.cpu_count()
max_global_episodes = 100000
global_network_scope = 'globalnet'
global_iteration_update = 20
gamma = 0.9
beta = 0.0001
lr_actor = 0.0001 # learning rate for actor
lr_critic = 0.0001 # learning rate for critic
global_running_rate = []
global_episode = 0

env = gym.make(game_env)

num_actions = env.action_space.n

tf.reset_default_graph()

输入状态图像预处理函数:

def preprocessing_image(obs): #where I is the single frame of the game as the input
    """ prepro 210x160x3 uint8 frame into 6400 (80x80) 1D float vector """
    #the values below have been precomputed through trail and error by OpenAI team members
    obs = obs[35:195] 
    #cropping the image frame to an extent where it contains on the paddles and ball and area between them
    obs = obs[::2,::2,0] 
    #downsample by the factor of 2 and take only the R of the RGB channel.Therefore, now 2D frame
    obs[obs==144] = 0 #erase background type 1
    obs[obs==109] = 0 #erase background type 2
    obs[obs!=0] = 1 #everything else(other than paddles and ball) set to 1
    return obs.astype('float').ravel() #flattening to 1D

以下代码显示了actor-critic类,其中包含actorcritic网络的架构:

class ActorCriticNetwork(object):
    def __init__(self, scope, globalAC=None):

        if scope == global_network_scope: # get global network
            with tf.variable_scope(scope):
                self.s = tf.placeholder(tf.float32, [None,6400], 'state')
                self.a_params, self.c_params = self._build_net(scope)[-2:]
        else: # local net, calculate losses
            with tf.variable_scope(scope):
                self.s = tf.placeholder(tf.float32, [None,6400], 'state')
                self.a_his = tf.placeholder(tf.int32, [None,], 'action')
                self.v_target = tf.placeholder(tf.float32, [None, 1], 'target_vector')

                self.a_prob, self.v, self.a_params, self.c_params = self._build_net(scope)

                td = tf.subtract(self.v_target, self.v, name='temporal_difference_error')
                with tf.name_scope('critic_loss'):
                    self.c_loss = tf.reduce_mean(tf.square(td))

                with tf.name_scope('actor_loss'):
                    log_prob = tf.reduce_sum(tf.log(self.a_prob) * tf.one_hot(self.a_his, num_actions, dtype=tf.float32), axis=1, keep_dims=True)
                    exp_v = log_prob * td
                    entropy = -tf.reduce_sum(self.a_prob * tf.log(self.a_prob + 1e-5),
                                             axis=1, keep_dims=True) #exploration
                    self.exp_v = beta * entropy + exp_v
                    self.a_loss = tf.reduce_mean(-self.exp_v)

                with tf.name_scope('local_grad'):
                    self.a_grads = tf.gradients(self.a_loss, self.a_params)
                    self.c_grads = tf.gradients(self.c_loss, self.c_params)

            with tf.name_scope('sync'):
                with tf.name_scope('pull'):
                    self.pull_a_params_op = [l_p.assign(g_p) for l_p, g_p in zip(self.a_params, globalAC.a_params)]
                    self.pull_c_params_op = [l_p.assign(g_p) for l_p, g_p in zip(self.c_params, globalAC.c_params)]
                with tf.name_scope('push'):
                    self.update_a_op = actor_train.apply_gradients(zip(self.a_grads, globalAC.a_params))
                    self.update_c_op = critic_train.apply_gradients(zip(self.c_grads, globalAC.c_params))

    def _build_net(self, scope):
        w_init = tf.random_normal_initializer(0., .1)
        with tf.variable_scope('actor_network'):
            l_a = tf.layers.dense(self.s, 300, tf.nn.relu6, kernel_initializer=w_init, name='actor_layer')
            a_prob = tf.layers.dense(l_a, num_actions, tf.nn.softmax, kernel_initializer=w_init, name='ap')
        with tf.variable_scope('critic_network'):
            l_c = tf.layers.dense(self.s, 100, tf.nn.relu6, kernel_initializer=w_init, name='critic_layer')
            v = tf.layers.dense(l_c, 1, kernel_initializer=w_init, name='v') # state value
        a_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope + '/actor')
        c_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope + '/critic')
        return a_prob, v, a_params, c_params

    def update_global(self, feed_dict): # run local
        session.run([self.update_a_op, self.update_c_op], feed_dict) # local gradient applied to global net

    def pull_global(self): # run local
        session.run([self.pull_a_params_op, self.pull_c_params_op])

    def choose_action(self, s): # run local
        s = np.reshape(s,[-1])
        prob_weights = session.run(self.a_prob, feed_dict={self.s: s[np.newaxis, :]})
        action = np.random.choice(range(prob_weights.shape[1]),
                                  p=prob_weights.ravel()) # select action w.r.t the actions prob
        return action

代表每个线程中的进程的Worker类如下所示:

class Worker(object):
    def __init__(self, name, globalAC):
        self.env = gym.make(game_env).unwrapped
        self.name = name
        self.AC = ActorCriticNetwork(name, globalAC)

    def work(self):
        global global_running_rate, global_episode
        total_step = 1
        buffer_s, buffer_a, buffer_r = [], [], []
        while not coordinator.should_stop() and global_episode < max_global_episodes:
            obs = self.env.reset()
            s = preprocessing_image(obs)
            ep_r = 0
            while True:
                if self.name == 'W_0':
                    self.env.render()
                a = self.AC.choose_action(s)

                #print(a.shape)

                obs_, r, done, info = self.env.step(a)
                s_ = preprocessing_image(obs_)
                if done and r<=0: 
                      r = -20
                ep_r += r
                buffer_s.append(np.reshape(s,[-1]))
                buffer_a.append(a)
                buffer_r.append(r)

                if total_step % global_iteration_update == 0 or done: # update global and assign to local net
                    if done:
                        v_s_ = 0 # terminal
                    else:
                        s_ = np.reshape(s_,[-1])
                        v_s_ = session.run(self.AC.v, {self.AC.s: s_[np.newaxis, :]})[0, 0]
                    buffer_v_target = []
                    for r in buffer_r[::-1]: # reverse buffer r
                        v_s_ = r + gamma * v_s_
                        buffer_v_target.append(v_s_)
                    buffer_v_target.reverse()

                    buffer_s, buffer_a, buffer_v_target = np.vstack(buffer_s), np.array(buffer_a), np.vstack(buffer_v_target)
                    feed_dict = {
                        self.AC.s: buffer_s,
                        self.AC.a_his: buffer_a,
                        self.AC.v_target: buffer_v_target,
                    }
                    self.AC.update_global(feed_dict)

                    buffer_s, buffer_a, buffer_r = [], [], []
                    self.AC.pull_global()

                s = s_
                total_step += 1
                if done:
                    if len(global_running_rate) == 0: # record running episode reward
                        global_running_rate.append(ep_r)
                    else:
                        global_running_rate.append(0.99 * global_running_rate[-1] + 0.01 * ep_r)
                    print(
                        self.name,
                        "Ep:", global_episode,
                        "| Ep_r: %i" % global_running_rate[-1],
                          )
                    global_episode += 1
                    break

以下代码显示了main函数,该函数创建线程池并将工作线程分配给不同的线程:

if __name__ == "__main__":
    session = tf.Session()

    with tf.device("/cpu:0"):
        actor_train = tf.train.RMSPropOptimizer(lr_actor, name='RMSPropOptimiserActor')
        critic_train = tf.train.RMSPropOptimizer(lr_critic, name='RMSPropOptimiserCritic')
        acn_global = ActorCriticNetwork(global_network_scope) # we only need its params
        workers = []
        # Create worker
        for i in range(num_workers):
            i_name = 'W_%i' % i # worker name
            workers.append(Worker(i_name, acn_global))

    coordinator = tf.train.Coordinator()
    session.run(tf.global_variables_initializer())

    worker_threads = []
    for worker in workers:
        job = lambda: worker.work()
        t = threading.Thread(target=job)
        t.start()
        worker_threads.append(t)
    coordinator.join(worker_threads)

    plt.plot(np.arange(len(global_running_rate)), global_running_rate)
    plt.xlabel('step')
    plt.ylabel('Total moving reward')
    plt.show()

根据学习的输出的屏幕截图(绿色桨是我们的学习智能体):

总结

我们看到,使用并行学习器更新共享模型可以大大改善学习过程。 我们了解了在深度学习中使用异步方法的原因及其不同的变体,包括异步单步 Q 学习,异步单步 SARSA,异步 N 步 Q 学习和异步优势参与者。 我们还学习了实现 A3C 算法的方法,在该方法中,我们使智能体学习了 Breakout 和 Doom 游戏。

在接下来的章节中,我们将重点介绍不同的领域,以及如何以及可以应用深度强化学习。

七、一切都是机器人-真正的战略游戏

近年来,视频游戏行业以惊人的速度增长。 根据 SuperData 的 2017 年度回顾报告,全球游戏行业创造了 1084 亿美元的收入。 全球游戏市场研究机构 Newzoo 预测,到 2020 年,视频游戏行业的收入将超过 1400 亿美元。

实时策略游戏构成策略视频游戏类型的子类别,并且相对于回合制策略游戏而言,实时策略游戏现在变得越来越重要。 在本章中,我们将讨论 AI 社区为何无法解决实时策略游戏,以及与其他算法相比,强化学习在学习和表现方面如何更好地解决该问题陈述。

我们将在本章介绍以下主题:

  • 实时策略游戏
  • 强化学习和其他方法
  • RTS 游戏中的强化学习

实时策略游戏

Brett Sperry 首先使用术语实时策略RTS)作为宣传其游戏 Dune II 的标语。 实时策略游戏涉及玩家使用实时策略来增加资产,保存资产并利用它们来摧毁对手的资产。 它与需要在非常短的时间内做出的许多复杂的战术决策相关。

这与基于回合的策略游戏不同,在回合制策略游戏中,每个对手都有时间分析和采取行动,而其他对手则无法执行任何动作。 在实时策略游戏中,动作和反应都实时发生,因为环境中的其他实体(即对手)也很活跃,并且会同时执行动作。 在真实的策略游戏环境中,实体的形式多种多样,包括玩家,结构及其多样化的高维特征。 因此,目标是采取最佳措施在游戏环境中生存,直到您取得胜利为止,而环境中的一个或多个实体正在对您不利。

实时策略游戏的特性使传统的规划方法效率低下,如下所示:

  • 高维连续动作空间
  • 高维连续状态空间
  • 环境是不确定的
  • 该环境是部分可观察的,玩家只能感知该环境的一部分(即游戏地图/世界)
  • 因此,由于游戏环境的状态不断变化,因此系统应该是实时的,可以实时决定并执行动作。

实时策略游戏已经发展了很多,现在具有包含许多实体的复杂虚拟环境,可以模拟各种现实问题。 因此,现实世界策略游戏已成为 AI 社区研究人员的良好测试平台,因为它们提供了复杂,多样,真实世界环境的仿真以测试其算法,从而创建更强大,更高效的算法。 因此,这些模拟环境实际上有助于创建更好的学习智能体,这些学习智能体可以在这些环境中生存和获胜,而无需在现实世界中进行测试,这在创建和维护方面非常昂贵。

近几十年来,计算能力的提高使得实现高级 AI 算法成为可能。 因此,它使他们成为解决实际策略游戏中国家行动复杂性和时间问题的最有效的候选人选择。 大多数技术(例如 minimax 和基于案例的在线计划)都可以用来解决此问题,但是它们在有限的条件下可以高效运行。

在可用的技术中,强化学习在学习和计划中表现更好。 我们已经知道,强化学习在涉及高维和连续状态动作空间时有许多成功的案例。

强化学习和其他方法

已经设计出许多方法来解决实时策略游戏的问题。 强化学习之前的主要方法之一是基于案例的在线规划。 基于案例的在线计划涉及基于案例的实时推理。 在基于案例的推理中,使用了一组方法来学习计划。 基于案例的在线计划在实现计划获取和执行的同时也实时地实现了此属性。

基于案例的在线规划

基于案例的推理包括四个步骤:

  • 检索

  • 重用

  • 修订

  • 保留

下图说明了这些步骤:

基于案例的推理

在检索步骤中,从案例库中选择与问题相关的案例子集。 在重用步骤中,将根据所选情况调整解决方案。 然后,在修订步骤中,通过在实际环境中进行测试来验证适应的解决方案,并观察到量化预测解决方案准确率的反馈。 保留步骤决定是否将此新解决的案例存储在案例库中。 因此,基于案例的推理和计划涉及重用以前的计划,并使它们适应新情况。

基于案例的推理主要应用于静态域,也就是说,智能体有时间决定要采取的操作,与此同时,环境的状态也不会改变。 但是现实世界中的问题是动态的,并且有时间限制。 因此,基于案例的推理不适合实际的策略游戏,这导致基于案例的在线规划,其中与基于案例的推理不同,实时进行计划和执行。 下图给出了基于案例的在线计划的架构:

基于案例的在线计划

如图所示,基于案例的在线计划具有两个额外的流程,相对于基于案例的推理,这些流程有很小的变化,以实时实现计划和执行。 这两个过程如下:

  • 扩展:此过程将当前适应的解决方案作为输入,并找到未解决的子问题,即子目标,如果有任何可检索和可解决的未解决子目标。 如果世界状态发生的变化足以使当前解决方案发生变化,它还会监视世界状态并将信号发送到适配模块。 这称为延迟自适应,在运行期间执行。 该流程模块使在线基于案例的计划在动态环境中工作。
  • 执行:这将执行当前解决方案并根据执行结果更新其状态。 如果子问题失败,导致当前解决方案在执行时失败,则此过程通过将当前信息发送到扩展模块以查找替代解决方案来更新当前解决方案,以缓解此问题。

实时策略游戏的缺点

所有先前方法效率低下的原因在于,决策是实时进行的,其中状态动作空间巨大且连续。 先前的方法在有限的条件下是有效的,因为它们不能满足以下所有条件:

  • 高维状态动作空间
  • 对抗环境
  • 部分可观察的环境
  • 随机环境
  • 即时

为了覆盖较大的状态操作空间,解决方案库中将需要大量规则。 此外,没有探索策略可以找到最佳解决方案。 因此,由于所有前面提到的与实时策略游戏相关的问题和复杂性,这些传统的 AI 方法很难实现。

为什么是强化学习?

强化学习相对于其他 AI 方法脱颖而出的原因如下:

  • 避免使用基于规则的手动编码方法。
  • 强化学习不需要存储游戏的特定规则。 强化学习智能体学习多种交互,并增强其每次与环境交互时在环境中起作用的理解。
  • 对于高维状态作用空间,可以将神经网络用作函数逼近器以得出最佳作用。
  • 始终探索不同的策略以找到最佳策略。
  • 强化学习已应用于需要状态行动计划的各个领域,例如机器人技术,自动驾驶汽车等。
  • 此外,强化学习是一个非常活跃且庞大的研究领域,因此可以肯定,还有许多更好的算法尚待发展。

RTS 游戏中的强化学习

在这里,我们将讨论如何实现强化学习算法来解决实时策略游戏问题。 让我们再次回顾强化学习的基本组成部分,它们如下:

  • 状态S
  • 动作A
  • 奖励R
  • 转移模型(如果基于策略,非策略学习不需要)

如果这些组件在接收来自给定游戏环境的信号时被学习智能体上的传感器感知和处理,则可以成功应用强化学习算法。 传感器感知到的信号可以进行处理,以形成当前的环境状态,根据状态信息预测动作,并接收反馈,即在所采取动作的好坏之间进行奖励。 这将更新状态-动作对值,即根据收到的反馈加强其学习。

此外,可以使用深度自编码器将较高维度的状态和操作空间编码为紧凑的较低维度。 这将状态和动作空间的特征尺寸减小为重要特征。

深度自编码器

深度自编码器是一种由两个对称神经网络组成的深度神经网络,如下图所示,它能够将输入数据转换为尺寸也较小的更紧凑的表示形式。 编码器网络首先将输入编码为紧凑的压缩表示形式,然后解码器网络将该表示形式解码回以输出原始输入。 如下图所示,中间层连接了两个神经网络(编码器和解码器),其中包含输入数据的紧凑压缩表示形式:

自编码器的架构

此处,X表示输入和输出层中的节点数,它等于输入数据的特征(维度)数,而N表示中间层中的节点数,它等于紧凑压缩表示形式所需的特征(尺寸)数。

例如,假设您输入的是游戏环境的28x28像素图像,即 784 像素。 因此,示例编码器网络架构可以按以下顺序拥有节点(不必遵循该顺序):

在前面的示例编码器网络中,我们采用了维度 784 的输入,然后将其扩展为 1024 维度,然后通过网络的连续层分别减小为 512、256、128、64,最后是 32 维度。 在这里,X为 784,N为 32。这里,我们的紧凑压缩表示形式仅相对于 784 维的输入数据由 32 维表示。

同样,我们的解码器网络架构与此相反,如下所示:

训练深度的自编码器后,无需解码器网络。 因此,我们的目标是训练网络,使解码器网络的输出与编码器网络的输入之间的损失最小。 结果,中间层学会了创建更好的输入表示形式。 因此,我们可以为输入特征向量检索特征向量的更好,紧凑和低维的表示形式。

强化学习如何更好?

以前,通过基于案例的在线计划,专家提供的人的踪迹是学习过程中最重要的组成部分。 这些由专家提供,以创建解决方案列表。 这样就创建了案例库并消耗了大量空间。 而且,它还带有一个缺点,即它们没有捕获所有可能的痕迹,也就是说,特别是在连续的状态动作空间的情况下,状态和动作的组合。

但是,通过强化学习,不需要存储这些迹线,而且,高维和连续状态动作空间可以处理深度神经网络,该网络将其作为输入并输出最佳动作。 此外,如果状态作用空间很大,并且需要减小尺寸以进一步减少计算时间,那么使用如前所示的深层自编码器会将输入数据转换为紧凑的低维向量。

强化学习中的奖励函数必须与每个状态相关联,以使从开始状态开始的动作通过一系列中间状态导致达到目标状态,从而使预期的奖励总和最大化,从而产生最佳路径。

基本的强化学习算法,例如 Q 学习和 SARSA 算法(在第 5 章,“Q 学习和深度 Q 网络”中进行了解释),与早期的在线案例学习相比,在收敛时间和比率方面表现更好 。

此外,在深度强化学习领域中正在进行大量研究,该研究集中于使用图像进行智能体感知以在更复杂的领域中更好地工作。 以前的自编码器方法有助于将非常复杂的域转换为更简单的域。 此外,学习奖励函数和自编码器的其他变体,尤其是去噪堆叠式自编码器,将进一步改善结果。

此外,使用异步或分布式多主体强化学习方法(在第 6 章,“异步方法”中讨论),其中学习智能体与自己的环境副本并行工作,这将进一步减少收敛时间,并产生更好的结果。

总结

在本章中,我们讨论了真正的战略游戏以及 AI 社区的研究人员为何试图解决它们。 我们还介绍了实际策略游戏的复杂性和属性以及不同的传统 AI 方法,例如基于案例的推理和基于在线案例的计划以解决它们及其缺点。 我们讨论了强化学习成为该问题的最佳人选的原因,以及强化学习如何成功解决与早期传统 AI 方法失败有关的实时战略游戏相关的复杂性和问题。 我们还了解了深层自编码器,以及如何使用它们来减少输入数据的维数并获得更好的输入表示。

在下一章中,我们将介绍使深度强化学习成为众人关注的最著名的话题,并使之成为 AI 算法的旗手,即 AlphaGo。

八、AlphaGo –最好的强化学习

游戏为许多人工智能AI)算法提供了最佳的测试环境。 这些模拟环境具有成本效益,并且可以安全方式测试算法。 人工智能的主要目标是解决世界上最大的问题。 人工智能的主要全球目标是:

  • 消除贫困
  • 消除饥饿
  • 所有人的主要个性化医疗保健
  • 素质教育
  • 清洁能源
  • 良好的基础设施
  • 创新与创造力
  • 减少不平等
  • 保护地球
  • 应对气候变化
  • 和平与正义
  • 好的工作
  • 经济增长
  • 解决水危机

研究技术和工业界正在努力实现更多的全球目标。 现在,借助 AI 算法和更好的计算能力,随着时间的推移,向这些目标迈进的步伐越来越长。 尽管这是一条很长的路要走,但随着最近的进步和发现,我们至少可以说我们走在正确的道路上,并且比十年前处于更好的位置。

如前所述,游戏是测试这些 AI 算法的最佳测试平台。 除了具有成本效益之外,没有两个游戏是相同的,因此能够使用从一个游戏中学到的知识并将其应用于另一个游戏,这是一般智慧的标志。 单个算法可以应用的游戏越多,它变得越通用。

我们第一次看到向人工智能AGI)迈出了巨大的一步,当时 DeepMind 证明了他们的 AI 可以击败许多 Atari 游戏,使其成为现存最通用的 AI 系统 。 DeepMind 在研究期刊 Nature 上发表了他们的论文《通过深度强化学习进行人类级别控制》,由 Silver 等展示了他们的 AI 智能体深度 Q 学习器,使用了深度强化学习算法,已成功应用于 50 种不同的 Atari 游戏,并在以下截图中显示了其中的 30 种,其表现均达到人类水平。 通用人工智能的发展方向是 Google 购买 DeepMind 的原因:

比较 50 种不同的 Atari 游戏的表现:DQN 的表现根据专业人类玩家测试员规范化,《通过深度强化学习的人类水平控制》

2016 年 3 月 9 日,我们见证了 Google DeepMind 的 AlphaGo 在古代中国游戏围棋中击败 18 届世界冠军 Lee Sedol 的历史。 对于整个 AI 社区来说,这是一个伟大的里程碑。 这是因为人们投入了毕生精力来掌握围棋游戏。 由于其复杂性,围棋游戏具有很高的挑战性。 根据 1997 年《纽约时报》的文章,科学家说,围棋是智力水平最高的游戏,要在围棋上击败人类至少要花一个世纪的时间。 但是,由于有了 Google DeepMind,我们得以在不到二十年的时间内实现了这一壮举。 以下是本章将涉及的主题:

  • 什么是围棋?
  • AlphaGo-精通围棋
  • AlphaGo Zero

什么是围棋?

围棋游戏起源于中国大约 3000 年前。 游戏规则很简单,如下所示:

  • 围棋是一款两人游戏
  • 默认棋盘尺寸为19x19
  • 一个玩家放置一块黑色的石头,而另一玩家放置一块白色的石头
  • 目标是包围对手的石头,并覆盖棋盘上的大部分空白区域

以下是默认的板尺寸,为19x19行:

19x19围棋板

即使有这些简单的规则,围棋的游戏还是非常复杂的。 在19x19围棋中,大约有2.08 x 10^170,而在宇宙中有10^80个原子,而在象棋中有10^120个可能的移动。 因此,玩围棋游戏所需的智力深度已经吸引了人类多年的想象力。

围棋

1997 年,IBM 的 DeepBlue 在国际象棋比赛中击败了当时的世界冠军加里·卡斯帕罗夫。 大约二十年后,Google DeepMind 的 AI 程序 AlphaGo 击败了 9 段围棋选手和前世界冠军 Lee Sedol。 为了了解通过 AlphaGo 进行的 Google DeepMind 的巨大飞跃和成就,让我们首先了解这两个游戏之间的区别,然后再了解 DeepBlue 和 AlphaGo 的 AI 背后使用的架构。

国际象棋和围棋都需要两名球员。 在国际象棋中,每个玩家都有十六种不同类型的十六种棋子,根据游戏规则它们具有不同的优势。 目的是夺取对手的国王。 另一方面,围棋从一个空白的棋盘开始,每个棋手依次一个人放置一块石头,并且所有石头都具有相同的强度,遵循相同的规则。 此处的目标是在板上捕获尽可能多的区域。

因此,我们发现围棋的游戏规则比国际象棋简单,但我们没有看到的是复杂性,相对于国际象棋,围棋的复杂性很高。 在每个游戏状态下,围棋玩家必须从 250 个可能的选择中选择一个棋步,而国际象棋则需要选择 35 个选择。 围棋比赛持续约 150 步,而象棋比赛持续约 80 步。

正如我们之前研究的,在19x19围棋中大约有2.08 x 10^170个可能的移动,而宇宙中有10^80个原子和在国际象棋中有10^120个可能的移动。

DeepBlue 如何击败 Gary Kasparov?

在第 5 章, “Q 学习和深度 Q 网络”中,我们研究了游戏树和 minimax 算法。 让我们回想一下那些了解 IBM DeepBlue AI 程序背后的架构的方法。

游戏树表示游戏的完整端到端表示,其中树中的每个节点表示特定的游戏状态(位置),链接节点的边表示在先前游戏状态下所采取的动作(动作),产生新游戏状态。 根节点代表游戏的开始,下一级别的节点代表在游戏的开始状态下采取了所有不同的可能动作之后生成的可能状态,并且类似地生成了其他层中的节点。

对于井字游戏这样的简单游戏,由于复杂度较低,因此很容易创建游戏树。 一旦游戏复杂性增加,就不可能创建游戏树。 对于国际象棋,将需要10^120个不同的节点来创建游戏树。 如此巨大的游戏树无法存储。

按照传统方法,了解游戏的游戏树对于创建玩 AI 的游戏非常重要,因为它有助于在任何给定状态下选择最佳动作。 使用最小最大算法选择了最佳的移动方式,在每个回合中,它试图找出哪个移动方式可以最大程度地减少最坏的情况(这还包括输掉比赛)。

为此,它首先找出代表当前游戏状态的节点,然后以使遭受的损失最小化的方式采取行动。 为此,需要遍历整个游戏树到叶子节点(最终游戏状态)以评估损失。 因此,minimax 算法要求遍历游戏树以评估每一步的损失(最坏的情况),然后选择损失最小的那一步。

DeepBlue 搜索国际象棋的游戏树到最低深度(因为不可能创建整个国际象棋的游戏树)。 然后,它使用评估函数来计算值,该值将替换下面的子树。 此评估函数用于将下面的子树汇总为单个值。 然后,它使用 minimax 算法引导最小的最坏情况,直到达到最大可能深度。

评估函数依赖于一些试探法。 在 DeepBlue 中,评估函数分为 8000 个部分,专门针对某些特定位置进行设计。 因此,为了更深入地了解游戏树,计算能力应该更高,甚至在此之后,还要根据监督下的不同游戏位置来设计游戏特定评估函数。 因此,由于没有学习,它不能在其他领域(或游戏)上推广。

简而言之,为了解决国际象棋的复杂性,DeepBlue 对设计良好的评估函数的游戏树使用了蛮力方法。

为什么游戏树方法对围棋不利?

不能以游戏树方式接近。 原因是所使用的更大的复杂性和蛮力方法无法进行任何学习。 它执行的唯一任务是将游戏状态映射到游戏树中的节点。 而且,DeepBlue 中使用的蛮力方法没有通用的评估函数,而是针对不同的游戏位置手工制作的。 因此,先前的方法过于特定于游戏,因此此类方法无法扩大规模以玩围棋。

AlphaGo –精通围棋

在围棋的情况下,基于搜索树覆盖所有可能位置的传统 AI 方法会失败。 原因是由于2.08 x 10^170 可能的移动以及因此而难以评估每个可能的棋盘位置的强度,因此搜索空间极其巨大。 因此,传统的蛮力方法在围棋的巨大搜索空间中失败了。

因此,高级树搜索(例如具有深度神经网络的蒙特卡罗树搜索)被认为是捕捉人类用来玩围棋游戏的直觉的新颖方法。 这些神经网络是卷积神经网络CNN),并为棋盘拍摄图像,即棋盘的描述,并根据游戏的给定状态,通过一系列层激活它来找到最佳的动作。

AlphaGo 的架构中使用了两个神经网络,分别是:

  • 策略网络:此神经网络决定要采取的下一步行动/行动
  • 值网络:此神经网络从当前位置预测游戏的获胜者

AlphaGo 使用策略和值网络的方式是将搜索树的巨大复杂性降低到较小的可管理搜索空间。 因此,它没有考虑每个步骤的数百个不同动作,而是考虑了策略网络建议的一些最佳可能动作。

此外,值网络减少了搜索的深度。 在每个位置,值网络都试图预测哪个玩家将获胜,而不是遍历搜索树进行评估。 因此,它能够返回一个值,该值量化可能的网络建议的移动量。

人类在游戏寿命方面存在弱点,也就是说,他们在长时间比赛中会感到疲倦,从而导致失误,而这并不是计算机的问题。 而且,人类的时间有限。 他们一生可以玩大约数千场围棋游戏,而 AlphaGo 一天可以玩一百万场游戏。 因此,经过足够的处理,足够的训练,足够的搜索和足够的计算能力,AlphaGo 击败了世界上最好的专业围棋选手。

因此,应对给定的围棋极大复杂性也可以为在医学中使用这种方法铺平道路,通过深度强化学习来帮助患者接受个性化治疗,从而可以根据患者的病史和生物学史来产生最佳结果。

蒙特卡罗树搜索

在第 5 章, “Q 学习和深度 Q 网络”中,我们研究了蒙特卡洛树搜索。 在这里,让我们再次对其进行修改,看看 AlphaGo 如何使用它来获得更好的结果。

蒙特卡洛树搜索是游戏树搜索的另一种方法。 在这种方法中,我们对游戏进行了许多模拟,其中每个模拟都以当前游戏状态开始,以两个玩家之一作为获胜者结束。 开始时,模拟是随机的,即为两个玩家随机选择动作。 在每个模拟中,对于该模拟的每个游戏状态,都会存储相应的值。 游戏状态(节点)的该值表示该节点的出现频率以及其中几次出现导致获胜的频率。 这些值可为以后的模拟选择动作提供指导。 运行的模拟次数越多,这些值在选择获胜举动时就会越优化。

蒙特卡洛树搜索(Monte Carlo Tree Search)更加侧重于一旦赢得胜利并趋向该方向的获胜行为,因此导致对已探索的现有行为的利用。 为了探索新动作,在执行下一个动作时添加随机性很重要。 这有助于增加对搜索中新动作的探索。

最大的优势之一是,蒙特卡洛树搜索不需要任何领域知识。 它唯一需要做的就是对游戏进行大量模拟,并在遇到相应的情况时更新不同游戏状态的值。 而且,它不需要整个游戏树就可以了解每个可能的游戏状态。 存储象棋和围棋之类的游戏树是不可能的。 相反,蒙特卡洛树搜索(Monte Carlo Tree Search)只是运行越来越多的模拟来优化节点(游戏状态)值,从而获得更好的结果。

AlphaGo 之前的围棋 AI 程序完全依赖于蒙特卡洛树搜索。 这些是 Fuego,Pachi,Zen 和 Crazy Stone。 其中,Pachi 是最强的,直到 AlphaGo 仅使用策略网络而不使用任何搜索方法将其击败。 前面提到的围棋 AI 程序还依赖于一些领域知识,以便在蒙特卡洛模拟期间选择更好的结果并达到强大的业余水平。 纯粹的蒙特卡洛树搜索(Monte Carlo Carlo Tree Search)不会通过经验模拟来学习,它只是优化位置(游戏状态/节点)。

AlphaGo 的架构和属性

所有方法都依赖于结合某些领域知识和人工干预的树搜索。 AlphaGo 使用树搜索和两种 CNN(策略和值网络)来指导树搜索。 这些 CNN 类似于 DeepBlue 中使用的评估函数,但有一个区别,即 CNN 在手工制作 DeepBlue 中使用的评估函数时学习评估函数。

较早使用的树搜索是一种蛮力方法,而 CNN 是一种基于学习的方法,它提供了一种基于直觉的游戏方式。 因此,第一个任务是减少搜索空间(围棋的搜索空间大约为10^170)。 这可以通过两种方法来完成:

  • 减少动作候选,即广度减少(避免在游戏树中探索它们时避免出现不必要的动作)
  • 在时间之前减少评估函数,即深度减少(避免遍历整个游戏树来评估所采取的移动并根据当前游戏状态预测获胜状态)

策略网络并入当前游戏状态,并输出给定​​状态下每个可能动作的概率。 具有较高概率的动作有较高的获胜机会。 首先,使用专家玩家玩游戏的数据集,通过监督学习来训练策略网络。 输入数据包含游戏板的图像,输出将采取的措施。 来自 160000 个专家游戏的大约 3000 万个棋盘位置的训练数据集最初用于训练 AlphaGo 的策略网络。 在专家数据集上进行训练后,通过自我扮演改进了预测可能学习到的动作的模型,在自我扮演的过程中,它与自身无数次比赛,以使用策略梯度从过去的错误中学习。 因此,策略网络通过提供可能采取行动的可能性来帮助减少候选行动。

值网络提供当前状态的估计值,该值是黑人玩家在当前状态下赢得比赛的概率。 策略和值网络的输入与当前游戏状态(具有当前石头位置的棋盘游戏的图像)相同。 策略网络的输出是获胜的概率。 因此,值网络的作用类似于评估函数,该函数是通过 3000 万个棋盘位置的监督学习集获得的。

因此,值网络输出直觉(赢和输的机会),而策略网络输出反思(训练游戏知识)。 因此,AlphaGo 中直觉和反射的混合使其比任何基于搜索的方法都强大。 但是在 AlphaGo 中,这些网络可根据所开发的直觉和学习的反射来帮助更快,优化树搜索。

下图是神经网络训练管道和架构:

AlphaGo 的神经网络训练流水线和架构,摘录自 Google DeepMind 的 Silver 等人在 Nature 上发表的文章《AlphaGo》

让我们讨论前面详细显示的 AlphaGo 的神经网络架构图:

  • a:快速部署策略ρ[π]和监督学习策略网络ρ[σ]在包含 3000 万个棋盘位置的数据集上接受专家训练,以像人类专家一样学习预测动作。 通过学习的监督学习策略网络的权重初始化强化学习策略网络,并通过使用策略梯度来最大化策略质量,从而改进其策略ρ[ρ]策略网络的早期版本。 通过使用此更新的策略网络进行自我播放,将生成一个新的数据集。 数据集包含棋盘位置的图像及其相应的最终结果,即获胜或失败。 最后,使用该自玩数据集通过回归训练值网络ν[θ],以输出获胜的概率。

  • b:该流程的架构流程,其中策略网络将棋盘位置(游戏状态)的图像表示作为输入,并通过参数σ的卷积层传播(如果它是一个有监督的学习策略网络)或ρ(如果它是强化学习策略网络),并针对所有可能的动作a返回概率分布p[σ](a | s)p[ρ](a | s)输出。 值网络还使用参数θ的许多卷积层,返回标量值v[θ](s'),该标量值表示在给定位置s'中获胜或失败的结果(最终结果)的概率:

Silver 等人

让我们讨论前面详细显示的在 AlphaGo 中使用的蒙特卡罗树搜索MCTS):

  • a:在每次仿真过程中,遍历树时选择了该边,该边具有作用值Q和值u(P)之和的最大值。 u(P)是该边存储的先验概率P的函数。
  • b:扩展叶节点,即在策略网络p[σ]之后处理新节点,并将每个操作的输出概率存储为先验概率P
  • c:在仿真结束时,以两种方式对叶节点进行评估:
    • 使用值网络v[θ]
    • 使用学习到的快速推广策略p[π]进行推广,直到游戏结束,并使用函数r计算获胜者
  • d:更新动作值Q,以跟踪该动作下方子树中所有评估值r(·)v[θ](·)的平均值。

如前所述,对一个策略网络进行了 3000 万个游戏职位的训练。 在不使用树搜索的情况下,AlphaGo 赢得了与 Pachi(最强的围棋 AI 程序)对战的 85% 的比赛,其中 Pachi 依靠基于蒙特卡洛搜索树的 100,000 次模拟。 值网络接受了 3000 万个游戏位置的训练,并学习了预测获胜概率的模型。 策略网络输出充当树搜索的指南。 对于给定的游戏状态,策略网络为每个可能的移动提供了概率。 这有助于减少树搜索期间的候选动作。

能耗分析– Lee Sedol 与 AlphaGo

下表是能耗分析(Lee Sedol 与 AlphaGo):

Lee Sedol(9 段围棋棋手) Google DeepMind 的 AlphaGo
每人每天的卡路里 ~ 2,500 kCal(平均 BMR) 假设:CPU ~ 100W,GPU ~ 300W,使用了 1,202 个 CPU 和 176 个 GPU
假设 Lee Sedol 在一场比赛中消耗了所有精力, 因此为2,500 kCal * 4184 J/kCal ≈ 10 MJ [1,202 * 100 + 176 * 300] W = [1,202 * 100 + 176 * 300] J/s = 173,000 J/s,考虑到它是至少四小时的游戏,因此,173,000 J/s * 3 * 3,600 s ≈ 2,500 MJ

AlphaGo Zero

第一代 AlphaGo 能够击败专业的围棋玩家。 2017 年 10 月,Google DeepMind 在 Nature 上发表了有关《AlphaGo Zero》的论文。 AlphaGo Zero 是 AlphaGo 的最新版本。 早期版本的 AlphaGo 在接受过数以千计的从业余到专业游戏的人类游戏训练后,学会了玩游戏。 但是 AlphaGo 的最终版本(即 AlphaGo Zero)从零开始学到了一切,这是从第一个基本原理开始的,既没有使用任何人工数据也没有任何人工干预,并且能够实现最高水平的表现。 因此,AlphaGo Zero 通过与自己对战来学习玩围棋。 最大的壮举之一是,AlphaGo Zero 在 19 小时内就能够学习更高级的围棋策略的基础知识,包括生与死,影响力和领土。 在短短的三天内,AlphaGo Zero 击败了所有先前的 AlphaGo 版本,并在 40 天内超过了人类对围棋的一千年了解。

AlphaGo Zero 背后最重要的想法是,它完全从空白状态(即清晰的围棋棋盘)中学习,并通过自己的玩法自行弄清楚,而无需任何人类知识,没有任何人类游戏示例和数据,甚至没有任何人为干预。 它从最初的基本原理中发现并发展了学习围棋游戏的直觉。 这种从头开始的学习称为表格学习白板学习

Tabula rasa 学习对于任何 AI 智能体都是非常重要的,因为如果有一个智能体已实现 Tabula rasa 学习,则可以将其从围棋游戏移植到其他域环境(可能是其他任何游戏)。 Tabula rasa 学习将智能体与其所在领域的具体情况脱钩,并尝试开发一种算法,该算法足够通用,可以学习以实现与该环境相关的目标,并且可以在任何地方应用。

AlphaGo 项目背后的目标不是击败最佳的人类围棋选手,而是发现学习和做科学的意义以及对于计算机程序学习知识和直觉本质的意义。 AlphaGo Zero 不仅重新发现了人类倾向于玩的常见模式和空缺,还通过自行弄清它们来学习它们,并且还抛弃了许多已知的人类移动,而是优先选择了在数百万游戏中在数天之内发现的更好的移动。 这些更好的举动甚至是人类所不知道的。

在短时间内,AlphaGo Zero 可以理解人类在数千年的游戏过程中积累的所有围棋知识。 AlphaGo Zero 本身发现了大部分知识,并发现了人类围棋玩家尚未发现的大多数举动。 因此,除了比人类更快地适应知识之外,它还开发了新的知识,即知识创造,因此这种成就在许多方面被认为是新颖的。

因此,AlphaGo Zero 是第一个在围棋复杂而具有挑战性的领域中实现了非常高性能的计算机程序,已经开始了新的旅程,在该旅程中,我们可以开始解决一些具有挑战性的问题,这些问题要紧跟着一个顺序,而这些问题很少或更少。 同样复杂的游戏,例如围棋,会对人类产生不利影响。

Google DeepMind 已经开始使用 AlphaGo Zero 来了解蛋白质折叠,因为错误折叠的蛋白质会导致许多疾病,例如阿尔茨海默氏病,帕金森氏病,II 型糖尿病和囊性纤维化。 因此,使用基于 Tabras Rasa 的深度强化学习方法,可以了解蛋白质折叠,减少能量消耗,发现新元素或新材料以及更多其他内容。

AlphaGo Zero 的架构和属性

与先前版本的 AlphaGo 相比有五处变化。 它们如下:

  • 完全从自我游戏中训练,这不是人类专家的游戏数据,而是从头开始学习一切。 较早的版本监督学习策略网络,该网络经过专家游戏训练。
  • 没有手工制作的特征。
  • 用残差卷积架构替换了普通卷积架构。
  • AlphaGo Zero 并没有将其单独的策略和值网络,而是将它们两者合并为一个大型网络。
  • 简化了蒙特卡洛树搜索,该搜索使用此大型神经网络进行仿真。

网络输入包括:

  • 19 x 19矩阵平面,代表棋盘
  • 一个用于白色宝石的特征映射(在具有白色宝石的位置具有 1,在其他位置具有 0 的二进制矩阵)
  • 一个用于黑宝石的特征映射(在具有黑宝石的位置具有 1,在其他位置具有 0 的二进制矩阵)
  • 七个使用白色石头的玩家过去的特征映射(代表历史,因为它捕获了过去的七个动作)
  • 七个使用黑石头的玩家过去特征映射(代表历史,因为它捕获了过去七个动作)
  • 一个用于转弯指示的特征映射(转弯可以用 1 位表示,但此处已在整个特征映射上重复出现)

因此,网络输入由19 x 19 x (1 + 1 + 7 + 7 + 1) = 19 x 19 x 17张量表示。 使用过去七个动作的特征映射的原因在于,这段历史就像一个注意力机制。

为什么我们使用残差架构而不是普通卷积架构? 其背后的原因是残留的架构允许梯度信号直接穿过层。 此外,即使在卷积层没有做任何有用的学习的早期阶段,重要的学习信号也会进入卷积层并直接进入其他层。 详细解释残留架构超出了本书的范围。

因此,我们采用板的19 x 19 x 17张量表示形式的输入,并将其通过残差卷积网络,从而生成特征向量。 该特征向量通过全连接层传递,以进行最终的特征提取,其中包含两件事:

  • 值表示形式:AlphaGo 的可能性在当前棋盘位置赢得零的游戏。
  • 策略向量:AlphaGo 可以在当前位置播放的所有可能动作的概率分布。

因此,目标将是获得较高的良好举动概率和较低的不良举动概率。 在强化学习中,通过自玩这种较高复杂性的游戏来训练网络经常导致网络高度不稳定。 在这里,简化的蒙特卡洛树搜索执行稳定网络权重的任务。

AlphaGo Zero 中的训练过程

接收板表示的输入,它是19 x 19 x 17张量。 它经过残差卷积网络,然后全连接层最终输出策略向量和值表示。 最初,策略向量将包含随机值,因为网络最初以随机权重开始。 在获得给定状态下所有可能动作的策略向量后,假设具有高概率的动作也可能是强力动作,它会选择一组概率很高的可能动作:

AlphaGo Zero 的自玩增强学习架构,摘录自 Google DeepMind 的 Silver 等人在 Nature 上发表的文章《AlphaGo Zero》

基于这些选定的移动集,接收不同的游戏状态,每个状态对应于它们的移动。 由于您模拟了在先前状态下的移动,因此会产生许多不同的状态。 现在,对于这些下一组状态,通过输入这些游戏状态的表示张量来重复前面的过程,并获得其策略向量。

因此,对于当前的棋盘位置,这种重复过程将爆发成一棵大树。 运行更多的模拟,并且树将随着扩展呈指数扩展。 因此,该想法是将该搜索树爆炸到一定深度,因为由于有限的计算能力,进一步的搜索将是不可能的。

AlphaGo 团队决定为每个单板位置评估进行大约 1600 次仿真。 因此,对于每个单板状态,将运行蒙特卡洛树搜索,直到获得 1600 个模拟为止。 之后,值网络决定哪个结果棋盘位置是最好的,即获胜的可能性最高。 然后将所有这些值备份到树的顶部,直到当前的游戏状态(即正在评估的当前棋盘位置),并获得对真正有力的,但不是强势的动作的非常强的估计:

AlphaGo Zero 进行的蒙特卡罗树搜索,摘录自 Google DeepMind 的 Silver 等人在 Nature 上发表的文章《AlphaGo Zero》

总结

在本章中,我们研究了目前最好的强化学习架构,即 AlphaGo。 我们了解了选择围棋的原因及其相对于象棋的复杂性。 我们还了解了 DeepBlue AI 架构的工作原理,以及围棋需要一种不同的更好的架构和训练过程。 我们研究了 AlphaGo 和 AlphaGo Zero 使用的架构和训练过程,还了解了版本之间的差异以及 AlphaGo Zero 如何超越其早期版本。

在下一章中,我们将研究如何在自动驾驶和自动驾驶汽车中使用和实现强化学习。

九、自动驾驶中的强化学习

在本章中,我们将介绍研究人员正在致力于使端到端自动驾驶成为可能的不同方法。 我们已经看到许多公司,例如 Google,特斯拉,Uber,梅赛德斯·奔驰,奥迪,沃尔沃,博世,还有更多公司进入自动驾驶汽车领域。 对于 AI 社区而言,端到端自动驾驶将是通往人工智能AGI)的下一个里程碑。

纵观汽车行业的当前趋势,我们看到以下几点:

  • 环境和气候友好型电动汽车正在增加
  • 通过出租车聚合服务和拼车(即拼车)获利
  • 利用 AI 和云技术进行无人驾驶汽车的颠覆性研究

乐高自动驾驶的主要功能如下:

  • 传感器融合(传感器可以是相机,LIDAR,RADAR,GPS 等)
  • 对象检测与分类
  • 车辆路径规划-采取哪种操作,例如向左或向右转向,加速或制动,以及更多取决于:
    • 操作的不同类型
    • 操作的复杂性

自动驾驶中的机器学习

首先,为了开发端到端的无人驾驶汽车,在深入研究整个过程中使用强化学习之前,我们必须从高水平了解开发过程。 下图描述了开发过程:

如上图所示,该过程的第一步是传感器数据的收集。 传感器包括摄像头,LIDAR,IMU,RADAR,GPS,CAN 和更多其他设备,这些设备可以以最佳方式捕获车辆状态以及周围环境。 收到这些感官信号后,将对它们进行预处理,汇总,然后准备发送到下一个过程,包括机器学习ML)和数据中心分析。 在准备好的感觉信号上执行 ML 的这一步骤是关键部分,它涉及从输入数据进行状态估计,从而对其进行建模,预测可能的未来动作,最后根据预测的输出进行计划,即执行哪个动作从而使整体奖励最大化。

涉及自动驾驶时,ML 可以用于不同的任务。 它们主要是以下内容:

  • 传感器融合:聚类,模式识别和隔离
  • 环境理解:图像处理,对象检测,对象分类和运动检测
  • 轨迹规划:运动规划和控制
  • 控制策略:强化和监督学习
  • 驱动模型:图像处理和模式识别

此外,使用强化学习背后的最大原因是,由于以下几种不同的类型,它是处理多种车辆操纵的最佳人选:

  • 换道时超车
  • 交通拥堵
  • 高速公路合并
  • 高速公路分叉
  • 车道缩小
  • 在红色交通信号灯处停车
  • 在停车标志处停在
  • 放慢速度限制标志
  • 在建筑或事故现场附近行驶时改变路线或安全驾驶
  • 道路交叉口
  • 合并为环岛的道路(环形路)

某些先前提到的车辆操作如下所示:

变道(左)和合并高速公路(右)时超车

分叉的高速公路(左)和道路交叉点(右)

合并为环岛的道路(环形路)

自动驾驶中的强化学习

由于与环境的强大交互作用以及环境中的多个障碍和操作(如前所述),无法通过全面的有监督的学习方法来解决自动驾驶所带来的挑战。 强化学习的奖励机制必须非常有效,这样智能体才能对内部个体的安全以及外部所有障碍(无论是人类,动物还是任何正在进行的构造)保持谨慎。

奖励的方法之一可能是:

  • 智能体车辆与前方车辆相撞:高负面奖励
  • 智能体车辆与前端和后端之间的距离都更安全:积极的回报
  • 智能体车辆保持不安全的距离:中等的负面奖励
  • 智能体车辆正在接近距离:负面奖励
  • 智能体车辆加速:随着速度增加,正奖励减少,超过速度限制则负奖励

整合循环神经网络RNN)来整合时间序列信息将使汽车能够处理部分可观察的场景。 此外,使用注意力模型来关注相关信息还可以降低计算复杂度。 如前所述,AI 的下一个,当然是最大的里程碑之一是创建端到端自动驾驶汽车。

创建自动驾驶智能体

驾驶车辆需要良好的技能,专注力和经验。 因此,作为一项高技能的任务,创建自动驾驶智能体所涉及的过程可以大致分为三类,如下图所示:

  • 识别周围环境的组成部分,其中包括人行道,人,交通信号灯,任何建筑,道路边界,其他车辆等。 对于 AI,由于使用卷积神经网络CNN)和生成对抗网络GAN)。 CNN 和 GAN 的成功可用于自动驾驶环境组件的识别过程。

  • 预测环境的未来状态。 识别当前环境状态的环境的当前组成部分很重要,但是将其用作输入并预测未来环境状态对于计划下一步行动也很有必要。 解决此问题的基本方法之一是创建环境图。 此外,我们可以合并深度神经网络,例如循环神经网络的变体,例如长短期记忆网络LSTM)或门控循环单元GRU),以整合和整合过去时间步长以及当前时间步长和预测未来中的数据。 正如我们在第 1 章,“深度学习–架构和框架”中讨论的那样,由于长期依赖以及 LSTM 单元如何解决该问题,围绕梯度消失的问题仍然存在 RNN 的情况。 RNN 是集成时间序列数据的最新技术,它在 DeepTracking中显示了对象跟踪方面的改进。

  • 规划是整个过程中最难的部分。 该任务包括将识别和预测的结果集成在一起,以计划将来的动作序列以及下一个驾驶动作集(向左或向右转向,加速等等),以使导航安全且成功。 这是一项艰巨的任务,因为整合和规划需要处理不可避免的情况才能安全到达目的地。 强化学习最适合此类控制计划任务。 我们已经了解了如何成功地部署强化学习来控制 50 场 Atari 游戏中的计划任务,以及 Google DeepMind 提供的最先进的 AlphaGo Zero。 在这些情况下,我们目睹了深度学习在进行表示学习的同时进行强化学习的规划。

由于使用了多种类型的传感器,所有这些信息的集成对于自动驾驶至关重要。 由于数据维数的差异,很难整合来自不同来源的感官输入。 例如,摄像机输入为高维,而 LIDAR 输入为低维。 提取相关信息并忽略不相关信息无疑会提高性能和准确率。 它降低了计算和存储能力的利用率。 因此,为了获取相关信息,注意模型适用于此目的,因为使用注意力机制的循环神经网络强化学习已成功应用于图像,从而仅关注相关部分。

为什么要强化学习?

我们已经讨论的一个重要原因是车辆操纵的可变性,无法以有监督的方式学习。 在本节中,我们将详细介绍为什么强化学习是自动驾驶的最佳选择。

就 ML 而言,驾驶是一个多主体交互问题。 考虑人类驾驶员在没有其他汽车在附近的车道上行驶。 与交通繁忙时更改车道相比,这更容易。 第二种情况之所以如此困难,是因为它还包括其他驾驶员的不确定行为和未知行为。 因此,与您的车辆进行交互的车辆数量,车辆类型(大小)以及其相应驾驶员的行为都是巨大且高度可变的信息。 由于这种高可变性,因此在此类数据上设计监督学习模型将无法涵盖所有​​不同类型的场景。 在监督学习中,训练数据越多越好,但是可变性和数量很重要。 因此,如果我们进行监督学习,则不可能涵盖所有情况。

当我们开车时,我们可以了解附近其他驾驶员的行为,这取决于他们的车辆在道路上行驶的方式。 假设,如果车辆行驶非常快并经过其他车辆,那么您会认为其他车辆的驾驶员具有进取心和经验。 因此,人脑执行此在线学习,从而了解环境及其组成部分。

需要这种类型的不断学习和计划,才能了解各种情况,从您无车行驶时到交通繁忙时的换道。 因此,在这些情况下,人们可以通过经验学习,但是在某些情况下,人们也会感到困难? 因此,潜在的挑战包括目前人类尚难解决的情况。 这些情况包括在灾难性情况下驾驶,例如洪水,建筑坍塌或在没有 GPS 连接的情况下在新环境中导航等等。

因此,所有这些显式场景都不能被纳入学习模型,而需要诸如强化学习之类的方法来覆盖这些场景并通过从执行的不同动作中获得的奖励来增强其学习能力。

我们已经讨论了创建端到端自动驾驶车辆涉及的不同类别的任务。 当前,将这些任务分离并分别处理,然后使用后处理层进行合并。 一个基本且非常重要的缺点是这些孤立的任务可能无法正确组合。

因此,强化学习由于其行动奖励机制,可以根据所采取的驾驶行为和所获得的相应奖励进行建模,然后计划采取哪种行动。 测试自动驾驶的奖励机制对于真实汽车来说是非常危险且昂贵的,因为奖励值应基于良好的驾驶和意外情况而保持稳定。 因此,最好在 TORCS 或 Unity 等模拟环境中进行测试。

提出的自动驾驶框架

在本节中,我们将讨论 El Sallab 等人(2017)给出的提出的用于自动驾驶的深度强化学习框架

以下是端到端深度神经网络的架构:

El Sallab 等人(2017)的《对自动驾驶深度神经网络进行端到端训练》

让我们详细讨论前面的架构。 在这种情况下,输入是多个时间步长上环境状态的汇总。

空间聚合

该架构的第一个单元是空间聚合网络。 它由两个网络组成,每个网络都用于以下子过程:

  • 传感器融合
  • 空间特征

总体状态包括车辆的状态以及周围环境的状态。 车辆的状态包括位置,几何方向,速度,加速度,当前剩余燃料,当前转向方向等等。 环境状态包括其组成部分,即对象,生物,障碍及其特征,即它们的位置,几何定向(无论是否运动)以及更多。 周围物体的状态通过摄像机,激光雷达等来感知。 因此,对于识别,预测和计划任务,需要将多个感官输入组合在一起。

传感器融合

此步骤包括融合来自不同传感器和过程的输入,并准备将其输入到深度神经网络。 每个传感器信息以原始向量的形式捕获环境状态。 完成所有这些原始向量的分组,并将其馈入深度神经网络。 每个感官输入将形成一个单独的特征向量。 因此,作为学习的结果,即成本最小化,发生了与那些传感器特征中的每一个相关联的权重的优化。 这些学习的权重量化了相应传感器特征的相关性。 就深度神经网络而言,CNN 是完成任务的最佳选择。

空间特征

卷积神经网络用于查找隐藏的表示,然后应用注意力机制。 注意力机制指导网络的卷积层专注于数据的相关部分。 使用注意力模型的优势在于,它减少了数据集的维数。 结果,还减少了对原始数据的大量计算,包括卷积等。

运用注意力模型的最佳方法是使用动作和瞥见网络(说明超出了本书的范围,但有关动作和瞥见网络的更多详细信息,请转到此研究出版物《视频中的帧错误的动作检测的端到端学习》,并避免使用注意过滤器,因为注意过滤器不会降低计算的维数 ,并将卷积应用于整个数据。 但是对于包含神经网络的动作和瞥见网络却不是这种情况,该网络学习学习数据的相关部分,从而引导卷积层专注于数据的这些相关部分。

周期性时间聚合

周期性时间聚合涉及跨不同时间步长聚集环境状态。 让我们详细讨论其背后的原因。 首先,获取环境状态并非易事,传感器读数可提供环境的最佳状态表示。 因此,当前时间步的状态信息不足以获取环境的完整信息。 因此,在多个时间步长上整合状态信息可捕获运动行为,这在环境状态在几秒钟内发生变化的自动驾驶中非常重要。

因此,通过增加重复性,可以处理 POMDP(部分可观察的马尔可夫决策过程)场景,这在驾驶中非常常见,因为无法完全观察到整个环境状态。 传统的算法(如贝叶斯过滤器)用于处理这种情况,方法是随着时间的推移集成信息,但它们是从 MDP 框架(环境状态完全可见)中派生的。

因此,通过创建时间序列格式,我们可以使用 RNN 来使用过去状态信息和当前状态数据对长期依赖关系进行建模。 众所周知,LSTM 具有足够的能力来处理长期依赖性,而不会遇到梯度消失的任何问题。 这是因为 LSTM 具有单元状态和隐藏状态,在该状态下,对于每个新的时间步,LSTM 都会根据来自先前的隐藏状态和当前时间步的新传入数据的相关信息来更新其新的隐藏状态。 此外,单元状态跨不同的时间步长存储相关数据,并且在单元状态中从存储的信息中忘记无关数据。 因此,LSTM 完全控制要在其单元格和隐藏状态中包含哪些信息。

规划

先前的网络构成深度 Q 网络DQN)的一部分,该网络将状态信息作为输入并将体验存储在体验缓冲区中。 来自该经验缓冲区的样本数据用于训练 DQN 中使用的深度神经网络,该神经网络进而预测状态动作值。 状态操作值有助于得出最佳策略,即为给定状态规划最佳操作。

基于 DQN 的方法适用于连续状态空间,但它要求动作空间是离散的。 因此,在连续动作空间的情况下,首选参与者批评算法。 回顾第 4 章,“策略梯度”的参与者评论算法,以下是参与者评论算法的示意图:

演员评论算法包括:

  • 充当评论者的网络更新状态动作的函数逼近器的权重参数向量
  • 另一个充当参与者的网络按照评论者给出的方向更新策略参数向量

DeepTraffic –用于自动驾驶的 MIT 模拟器

DeepTraffic 是为课程《MIT 6.S094:用于自动驾驶汽车的深度学习》创建的,由 Lex Fridman 教授 。 课程内容和作业是公开的。 DeepTraffic 由于其排行榜而获得了很多欢迎。 迄今为止,DeepTraffic 拥有 13,000 多个提交文件,竞争非常激烈。 用户必须在convnet.js(由 Andrej Karpathy 创建的框架)中使用本节开头提到的链接中存在的编码依据来编写其神经网络。 平均速度最高的座席在排行榜上居首。

诸如 DeepTraffic 之类的模拟可帮助训练不同的方法,以使汽车智能体迅速适应模拟环境。 此外,它的竞争性元素随着时间的推移增加了更好的提交,超过了过去的最高得分。 比赛很有趣,但在现实世界中,学生无法测试他们的深度强化学习脚本。 因此,DeepTraffic 为下一代 AI 开发人员提供了使用不同方法的最佳测试平台,这肯定会导致未来的 AI 开发人员在现实世界中创造出自动驾驶汽车,而这要得益于这些模拟的学习。

众所周知,在现实世界中,自动驾驶汽车应该规划最安全的道路。 因此,将需要大量修剪和更好的神经网络架构来实现该目标。 DeepTraffic 是朝着这个方向迈出的第一步,因此 AI 社区中感兴趣的人们可以玩耍并创建更好的学习架构和方法:

DeepTraffic 环境的四个视角:模拟,占用网格,防撞系统以及代表增强学习状态的占用网格的一部分,策略网络可基于此学习估计期望的奖励,通过采取五种可用操作中的每一项。(DeepTraffic:Fridman 等人在这个页面上进行的具有深度强化学习的密集交通快速驾驶)。

DeepTraffic 由一条高速公路带组成,该高速公路带显示了同时行驶的七个车道和二十辆汽车(请参见上图的第一列),其时速限制为 80 mph(不允许任何车子超过该限制)。 DeepTraffic 是现实公路场景的简化模拟表示。 此模拟的重点只是学习交通繁忙时的有效运动方式。 所有汽车均可从以下五种动作中进行选择:

  • 车道向左转
  • 车道向右转
  • 加速
  • 减速
  • 没做什么

对于其他汽车,将按照现实的模式随机选择动作,例如,由于随机选择动作,不会太频繁地改变车道。 以红色(深灰色)显示的汽车由深度强化学习智能体控制。 竞争对手获得以 DQN 实现的预定义神经网络。 任务是配置不同的超参数并获得最佳表现,即最高平均速度。

总结

在本章中,我们谈到了与最大的 AI 问题之一即自动驾驶相关的主要概念和挑战。 我们了解了问题所带来的挑战,还了解了用于使自动驾驶成功的当前方法。 此外,我们从接收感官输入到计划开始,对过程的各个子任务进行了概述。 我们还介绍了著名的 DeepTraffic 仿真,您可以在其中测试神经网络,以了解繁忙交通中的有效运动方式。 自动驾驶本身就是一个不断发展的广泛研究主题,而涵盖所有这些内容超出了本书的范围。

在下一章中,我们将研究另一个发展中的研究热点,即在金融中使用人工智能,我们将学习强化如何帮助金融投资组合管理。

十、金融投资组合管理

金融投资组合是将资金分配到不同金融产品中的过程。 在项目组合管理中实现深度学习一直是人工智能界的一个研究部门。 随着强化学习的进步,在创建免费的无财务模型的强化学习框架以产生端到端的财务组合管理智能体方面,人们进行了积极的研究。

投资组合管理是一个连续的决策过程,将资金重新分配到众多不同的金融产品中,以期获得最大的回报。

传统的最新在线投资组合管理方法包括:

方法 重要算法
基准测试 买入并持有
最佳股票
恒定的平衡投资组合
关注获胜者 通用投资组合
指数梯度
跟随领导者
跟随正则领导者
聚合类型算法
跟随失败者 反相关
被动正向平均回归
置信加权平均回归
在线移动平均回归
稳健中值回归
模式匹配 非参数直方图对数最优策略
基于非参数核的对数最优策略
非参数最近邻对数最优策略
相关驱动的非参数学习策略
基于非参数核的半对数最优策略
基于非参数核的 Markowitz 类型策略
基于非参数核的 GV 类型策略
元学习 聚合算法
快速通用算法
在线梯度更新
在线牛顿更新
遵循领先的历史

跟随获胜者和跟随失败者是基于先前构建的财务模型,该模型可能会或可能不会在上表中提及的相应算法中使用机器学习技术。 这些方法在不同金融市场中的有效性可以判断其效果。

模式匹配模型将历史数据样本作为输入,根据样本分布优化投资组合,并预测下一个时期的市场分布。 元学习聚合了不同类别的多种策略,以实现稳定的表现。

当前,存在用于金融市场交易的深度学习方法,这些方法可以预测价格走势和趋势,但不能在不同的金融产品之间执行自动的资金分配和重新分配。 由于我们拥有所有资产的历史价格,因此我们可以将包含它们的输入数据准备到循环神经网络中,该网络将预测下一时期的资产价格作为输出。 这是机器学习中的监督回归问题。

这些模型的表现完全取决于未来资产价格的预测准确率,而不仅是在下一个时期。 但是,未来的市场价格极难预测,因为它们不仅取决于历史价格,而且只能反映波动和流动,不包括也会驱动金融市场的情感因素。

需要注意的另一个重要点是,预测市场价格并不意味着预测市场行为。 因此,需要领域知识和逻辑将预测价格转换为行动。 结合深度强化学习,可根据最大化回报的目标使此逻辑转换自动化。

已经提出了许多成功的针对金融模型免费和完全基于机器学习的方法的尝试,用于算法交易。 其中使用强化学习的主要问题是它们无法预测未来价格,并且仅适用于单一资产交易。 因此,它们不能应用于投资组合管理,其中包括同时管理多个资产。

而且,投资组合管理是一个连续的动作空间问题,而不是一个离散的动作空间。 大多数已建立的最先进的深度强化学习算法都可以很好地与离散的动作空间配合使用。 但是,尽管我们已经为投资组合管理问题开发了连续操作空间离散化的过程,但是如果我们采用离散化过程,那么我们将失去许多可能的重要市场行为。 这导致更大的信息丢失和不可用的风险。

投资组合管理,甚至任何设计的交易算法所需的算法,都应可在不同市场上扩展。 传统算法曾经失败,因为无法在不同的市场上扩展,因为市场受资产类型和资产总数等因素支配,这些因素因市场而异。 这是因为资产的模式和行为因市场而异,并且传统算法没有得到概括。 此处的机器学习具有跨不同垂直方向(即不同金融市场)进行泛化的优势。

此外,如前所述,强化学习在金融投资组合管理中的应用在人工智能界的研究人员中很重要。 在本章中,我们将讨论一个关于《针对金融投资组合管理问题的深度强化学习框架》的最新论文,该论文由西交利物浦大学的研究者发布。我们将介绍他们采取的方法及其相对于当前在线投资组合管理方法的表现,如下所示:

  • 介绍
  • 问题定义
  • 数据准备
  • 强化学习
  • 进一步的改进

介绍

所提出的强化学习框架的核心是相同独立评估器EIIE)拓扑。 在这里,EIIE 是一个神经网络,它将资产历史记录作为输入并评估未来资产的潜在增长。 每个资产的评估得分用于计算下一个交易期的投资组合权重。

投资组合权重(我们将在后面讨论)实际上是由强化学习驱动的投资组合管理智能体的市场行为。 将购买目标权重增加的资产,而目标权重减小的资产将被出售。 因此,最后交易期间的投资组合权重也作为 EIIE 的输入。 因此,每个期间的投资组合权重存储在投资组合向量存储器PVM)中。

EIIE 通过在线随机批量学习OSBL)进行训练,其中强化学习框架的奖励函数是该时期的平均对数回报。 由于奖励函数是动态的,因此,随着训练是通过梯度上升进行的,EIIE 也在不断发展。 如前所述,EIIE 由一个神经网络组成,因此,对于当前框架,使用不同类型的神经网络测试了三种不同类型的 EIIE,即卷积神经网络CNN),循环神经网络RNN)和长短期记忆网络LSTM),这是 RNN 单元。 这种类型的框架可以轻松扩展到不同的市场,而不仅限于一个。

该提议框架的测试平台是一个名为 Poloniex 的加密货币交易市场。 实验之前,通过在一定时间间隔内的交易量排名来选择硬币。 实验在 30 分钟的交易时间内进行,并将 EIIE 的表现与前面提到的在线投资组合选择方法进行了比较。 EIIE 能够击败所有这些方法。

由于该框架不是在现实世界的金融市场中而是在加密货币市场中进行测试的,因此我们必须知道加密货币与传统金融资产之间的差异,以及为什么加密货币市场事先是算法投资组合管理实验的更好测试平台。 它们如下:

  • 加密货币的去中心化(不是控制协议的中央机构)
  • 加密货币市场的开放性(更易进入的市场)
  • 加密货币中的小批量货币丰富
  • 加密货币市场一直都是开放的,因此,对于学习智能体来说,随着时间的流逝学习非常有用,这与受时间限制的现实世界不同。

问题定义

众所周知,投资组合管理是指跨多种金融产品(资产)对资金进行持续重新分配。 在这项工作中,时间分为相等长度的时间段,其中每个时间段T = 30分钟。 在每个时期的开始,交易智能体将资金重新分配到不同的资产上。 资产的价格在一段时间内会波动,但要考虑四个重要的价格指标,它们足以表示该期间资产的价格变动。 这些价格指标如下:

  • 开盘价
  • 最高价
  • 最低价
  • 收盘价

对于连续市场(例如我们的测试用例),资产在t期间的开盘价是其在前一时期t-1的收盘价。 投资组合由m个资产组成。 在时间段t中,所有m资产的收盘价都创建了价格向量vₜ。 因此,vₜ的第i个元素即v[i, t]是该t时间段内第i个资产的收盘价。

同样,我们有向量v[t]^(hi)v[t]^(lo),其中:

  • :包含时间段t中所有m资产的最高价格的向量
  • :包含时间段t中所有m资产的最低价格的向量

投资组合中的第一个资产是特殊资产,从现在开始将被称为现金。 之所以认为与众不同,是因为所有资产的价格均以现金面额报价。 由于第一个资产定义了基础货币,因此vₜv[t]^(hi)v[t]^(lo)的第一个元素将始终为 1,即:

在这里,比特币被认为是现金。 因此,所有资产定价都将按照比特币进行。 正如我们已经讨论过的,这是一个连续的市场,t + 1期的开盘价将等于t期的收盘价。 周期t价格相对向量表示为yₜ,它是vₜv[t - 1]的按元素划分,如下所示:

这是时间段t中资产的收盘价和时间段t-1中资产收盘价的按元素划分,换句话说, 时间段t中资产的收盘价和开盘价的百分比。 因此,yₜ的元素是时间段t中单个资产的收盘价和开盘价之比。 价格相对向量用于计算一个时期内投资组合总价值的变化。

令时间段t开头的投资组合值为pₜ。 因此,忽略交易成本:

在这里,w[t-1]投资组合权重向量,也称为投资组合向量在时间段t的开始时,其第i元素是:w[i, t-1]是资产i在当前投资组合中的比例。 因为wₜ是权重(比例)的向量,所以从定义上讲wₜ的元素总和将总和为 1,即Σ[i] w[t, i] = 1, ∀t

时间段t回报率由下式给出:

对数回报率由下式给出:

初始投资组合权重向量w₀表示进入市场之前,该金额是以交易货币(称为现金,此处现金为比特币)表示,因为初始投资金额以交易货币计算。 由于金额是以交易货币为单位的,因此投资组合向量的第一个资产是指交易货币资产,因此:

因此,如果没有交易成本,则最终投资组合价值将由下式给出:

在此,p₀是初始投资金额。 因此,投资组合经理的目标是在给定的时间范围内最大化p[f]。 实验中有两个假设:

  • 零滞后:每笔定单在下单时均以最后价格执行,没有滞后,立即进行交易

  • 零市场影响:交易智能体在市场上的投资金额微不足道,不会影响市场

数据准备

交易实验在名为 Poloniex 的加密货币交易所中进行了测试。 为了测试当前方法,预先选择了m = 11具有最高交易量的非现金资产作为投资组合。 由于第一基础资产是现金,即比特币,因此投资组合的大小为m + 1 = 12。 如果我们在交易量较大的市场(例如外汇市场)中进行了测试,则m将与市场中资产的总数一样大。

资产的历史数据被馈送到神经网络,该神经网络输出投资组合权重向量。 在周期t结束时输入到神经网络的是张量Xₜ,其阶数为 3(fnm),其中:

  • m是预选的非现金资产的数量
  • nt之前的输入周期数(此处n = 50
  • f = 3是特征数量

由于n = 50,即输入周期数为 50,每个周期为 30 分钟,因此总时间= 30 * 50 min = 1500 min = 25 h。 时间段t上资产i的特征是其在时间段t中的收盘价,最高价和最低价。 价格矩阵不直接输入到神经网络。 价格变化决定了投资组合管理的表现。 输入张量中的所有价格将由最新收盘价标准化,如下所示:

这里:

  • VₜV[t]^(hi)V[t]^(lo)是归一化价格矩阵
  • 1 = [1, 1, ..., 1]ᐪΦ是逐元素除法运算符

因此,Xₜ是三个归一化价格矩阵的栈:

投资组合管理智能体使用输入张量Xₜ和上一个时间段的(即t-1),投资组合权重向量w[t-1]输出时间段t的投资组合权重向量wₜ。 根据策略π

因此:

并且由于(如前面的“问题定义”部分中所示):

因此,通过对前面的陈述进行强化学习的框架化,我们可以说先前的权重向量w[t-1]是在时间段t-1的动作,收到了立即奖励rₜ

强化学习

在算法投资组合管理的实验中,投资组合管理智能体在强化学习的支持下在金融市场环境中执行交易操作。 环境包括给定市场的所有可用资产。 由于环境庞大而复杂,因此智能体程序无法完全观察状态,即获取状态的所有信息。 而且,由于市场的全部订购历史太大而无法处理,因此从订购历史数据中进行子采样可以简化环境状态表示的处理。 这些子采样方法包括:

  • 周期性特征提取:将时间离散化为多个时段,然后提取每个时段的开盘价,最高价,最低价和收盘价
  • 数据切片:仅考虑最近时间段的数据,并避免使用较旧的历史数据,以便进行环境的当前状态表示

智能体根据时段输出的投资组合权重向量wₜ,在时段t结束时,即在时段t + 1的开始进行了一些买卖交易。 神经网络。 因此,主体在时间t的动作仅由投资组合权重向量wₜ表示。 因此,在当前框架中,w[t-1]被视为环境的一部分,并作为输入输入到智能体中,以输出下一个时间段即wₜ的智能体的操作策略。 因此,在时期t,即sₜ的状态由价格张量Xₜ和前一时期w[t-1]的投资组合权重向量表示:

和,

如前所述,投资组合管理智能体的目标是使最终投资组合价值最大化,即p[f],其中:

因此,在t[f]时间段内的总收益为p[f] / p[0]。 因此,总回报对数的平均值为:

因此,最大化最终投资组合价值可以转换为最大化总收益的对数平均值,其公式为:

创建了三个具有深度神经网络的三个不同变体的策略网络,分别是 CNN,RNN 和 LSTM。 前一个时间段的输出是当前时间段内网络的输入。 因此,使用策略梯度和深层 Q 网络中的经验回放的想法,创建了一个 PVM,用于存储网络输出,也就是说,它将包含每个时间步骤的投资组合权重向量。

PVM 是按时间步长顺序(即时间顺序)收集投资组合向量的集合。 在训练周期的每个时间步t,策略网络从t-1的存储位置取最后时间段的投资组合权重向量w[t-1],并进行覆盖t处的内存与输出投资组合权重向量wₜ的关系。 由于策略网络参数的收敛,PVM 中的值随着训练时期的增加而收敛。

单个内存栈(例如 PVM)还有助于使用小批量提高训练过程的并行性,从而提高训练过程的效率。

对于有监督的学习,数据的排序以小批量为单位,但是在这里,数据需要按照训练过程中每批传递的时间步长进行排序。 现在,由于数据是按时间序列格式的,因此从不同时间段开始的小批量是更可取的,因为它们涵盖了训练过程的独特数据。 金融市场的持续性导致不断向智能体网络输入新数据,从而导致训练数据中的数据爆炸。

因此,提出了 OSBL,其中在时段t结束时,时段的价格变动将添加到训练集中。 在完成时间段t + 1的订单后,使用从该组中随机选择的小批量对策略网络进行训练。 有关 OSBL 的完整详细研究超出了本书的范围,但是为了进一步探索,请阅读《金融组合管理问题的深层强化学习框架》中的 5.3 节 。

使用所有三个不同的策略网络(即 CNN,RNN 和 LSTM)在加密货币交易所 Poloniex 上对该框架进行了测试。 用于检查框架表现的投资组合的财务指标为:

  • 投资组合价值:最终投资组合的价值
  • 最大跌幅:在达到新峰值之前,从一个峰值(最高点)到波谷(最低点)的最大损失
  • 夏普比率:风险收益率(可变性)比率

在前面提到的指标的基础上,将提出的框架的表现与现有的在线投资组合管理方法进行了比较,它能够成功击败现有的在线投资组合管理方法。 因此,提出的强化学习框架能够解决一般的金融投资组合管理问题。

拟议框架的主要特点是:

  • 多渠道,多市场输入

  • 策略网络直接提供投资组合权重向量形式的市场行为

  • 在此,仅使用了深度神经网络的三个变体,但也可以应用其他变体

  • 随着投资组合规模的增加可线性扩展

  • PVM 在使用小批量的训练中增加了并行性功能

  • OSBL 帮助在线使用实时输入数据

进一步的改进

可以对以前的框架进行进一步的改进,也可以使用深度强化学习来创建端到端金融投资组合管理智能体的更好方法。 它们如下:

  • 当前框架假设为零滑点和零市场影响。 因此,考虑市场影响和滑点将提供真实的交易样本,这将改善训练数据集。
  • 使用行为者-批评类型的框架将有助于长期的市场反应。
  • 在基本 RNN 上优于 LSTM 和 GRU 可以解决梯度消失的问题。

总结

在本章中,我们研究了最近发布的在金融组合管理中使用深度强化学习的方法之一。 我们查看了金融投资组合管理中的问题陈述,投资组合经理的目标,并将问题陈述映射到强化学习任务。 我们还了解了用于基准化表现的不同财务指标以及不同的现有在线投资组合管理方法。 使用深度强化学习使财务组合自动化的研究主题是 AI 社区中要解决的最具挑战性的任务之一。 因此,除了本章介绍的方法外,还要尝试研究算法交易中的其他传统机器学习方法。

在下一章中,我们将研究强化学习在机器人技术中的使用,当前的挑战及其提出的解决方案。

十一、机器人技术中的强化学习

到目前为止,我们已经看到了强化学习在 AlphaGo,自动驾驶,项目组合管理等方面的进步。 研究表明,强化学习可以提供认知特征,例如动物行为。

与认知科学的紧密比较将是动态机器人系统和自动驾驶中强化学习的许多成功实现。 他们证明了将强化学习算法用于物理系统实时控制的理论。

在深度 Q 网络和策略梯度中使用神经网络可消除对人工设计的策略和状态表示的使用。 在深度强化学习中直接使用 CNN 并使用图像像素代替手工设计的特征作为状态已成为广泛接受的实践。 小型批量训练以及单独的主要网络和目标网络的概念为深度强化学习算法带来了成功。 在以像素为输入的 50 场 Atari 2600 游戏中,DeepMind 和深度强化学习的成功实现了超人的表现水平,这是强化学习研究的转折点。

研究人员试图在机器人技术中实现深层 Q 网络,但并未取得重大成功。 其背后的主要原因是机器人领域中的高维连续动作空间。 为了在连续的动作空间中实现 DQN,必须离散化它们,但是这种离散化会导致信息丢失,这对于诸如机器人之类的领域可能是非常危险的。

离散动作空间DAS)算法下,将处理离散动作空间域的算法归为一组。 诸如策略梯度之类的其他方法通过将状态空间作为输入来直接将状态空间与动作空间连接,并返回最佳策略作为输出,即采取的可行动作。 与基于值的方法(例如 Q 学习)相比,基于策略的方法的优势在于,它们解决了连续操作空间的处理问题,因为对于给定的状态输入,输出策略是跨不同可能操作的随机分布。

诸如处理连续动作空间域的策略梯度之类的算法归为连续动作空间CAS)算法。 因此,在行动空间上提供随机表示的基于策略的方法解决了该问题,而不是 DAS 算法中的离散化。 CAS 算法最初是开发并用于低维状态空间,后来使用基于 CNN 的架构扩展到高维状态空间。 CAS 算法分为两个子类别:随机连续动作空间SCAS)和确定性连续动作空间DCAS)算法。 它们之间的主要区别在于复杂性,因为 SCAS 算法提供了更好的覆盖范围,因此需要大量的训练样本来学习更好的策略。 在现实世界的机器人应用中获取大量训练样本是非常不可行的,因此,仿真必须以尽可能最佳的方式表示现实世界,否则生成现实世界的数据将非常昂贵。

确定性策略梯度的发现超过了随机策略算法,如 Silver 等人所述,该技术已包含在附录 A 中, “强化学习”中的其他主题。 在本章中,我们将介绍机器人强化学习背后的挑战以及当前如何实现机器人强化学习。

本章将讨论的主题包括:

  • 机器人技术中的强化学习
  • 机器人强化学习中的挑战
  • 未解决的问题和实际挑战
  • 要点

机器人技术中的强化学习

机器人技术与行为的高度复杂性相关联,这使手工工程师既难以进行操作,也没有足够详尽的方法来使用监督学习来完成任务。 因此,强化学习提供了一种捕获此类复杂行为的框架。

与机器人技术有关的任何任务都由高维,连续状态和动作空间表示。 环境状态不是完全可观察到的。 仅在模拟中学习不足以说强化学习智能体已经为现实世界做好了准备。 在使用机器人技术的情况下,强化学习智能体应该在现实世界中遇到不确定性,但是获取和复制起来既困难又昂贵。

鲁棒性是机器人技术的重中之重。 在常规分析或传统机器学习问题中,数据,预处理或算法中的细微错误会导致行为发生重大变化,尤其是对于动态任务。 因此,需要能够捕获实际细节的健壮算法。 机器人强化学习的下一个挑战是奖励函数。 由于奖励函数在优化学习中起着最重要的作用,因此需要生成特定领域的奖励函数,以帮助学习智能体尽快更好地适应现实世界。 因此,领域知识是设计好的奖励函数的关键,而这又是机器人机器学习中的艰巨任务。

在这里,将讨论通过我们在本书中研究的强化学习算法可以实现的机器人领域中的任务类型,并尝试将它们连接在一起以构建一种有前途的方法。

强化学习的演变

在本书中,我们涵盖了从基础到高级的强化学习领域中的大多数算法。 因此,这些章节是理解机器人领域中不同算法所面临的应用和挑战的前提。 早期强化学习算法通过首先获取状态动作值,然后从中得出策略来处理获取最佳策略的问题。 然后,策略迭代方法出现了,直接用于输出优化的策略。 探索利用技术有助于完善现有策略,探索新措施并更新现有策略。 强化学习方法,例如 MDP(在第 3 章,“马尔可夫决策过程”中),其中需要采用转移模型的值迭代方法称为基于模型的学习器。 另一方面,诸如 Q 学习(在第 5 章,“Q 学习和深度 Q 网络”中)的算法不需要这种转移模型,因此也不需要任何预定义的策略。 他们被称为无模型的脱离策略学习器

在深度强化学习领域,行动值函数逼近器和策略函数逼近器在制定最先进的学习算法集方面发挥着关键作用。 策略搜索算法(例如策略梯度)旨在通过最大化期望的奖励总和来找到最佳策略,而使用行动值函数近似器(例如深度 Q 网络)的算法旨在通过最大化期望的总和,来找到给定状态和行动值的奖励。 但是,在处理由高维和连续状态动作空间构成的环境时,表现上的差异在于,这最能描述机器人在其中运行的真实环境。 在这种情况下,策略搜索算法的表现会更好,因为它们在连续状态操作空间域中可以更好地工作:

上图显示了不同的深度强化学习算法的类别。 通过在深度 Q 网络中使用神经网络和策略梯度方法解决了映射连续和高维状态空间的问题。 各种 DAS 和 CAS 算法都使用神经网络有效地执行连续状态空间映射的任务。 但是主要的问题是将输入状态空间映射到高维连续动作空间。 为了在映射到连续动作空间的任务中获得更好的结果,派生了 CAS 算法。

机器人强化学习中的挑战

强化学习在机器人技术中的应用包括:

  • 运动
  • 操纵
  • 自主机器控制

如前所述,为了使增强型学习智能体在现实世界中的任务中表现更好,它应该具有定义明确,特定领域的奖励函数,这很难实现。 通过使用学徒制学习等技术可以解决此问题。 解决奖励不确定性的另一种方法是根据状态不断更新奖励函数,以便生成最优化的策略。 这种方法称为逆强化学习。

由于许多挑战,机器人强化学习是一个很难解决的问题。 第一个是连续的状态动作空间。 根据问题陈述,决定是采用 DAS 算法还是 CAS 算法。 这意味着机器人控制应处于何种粒度级别。 一大挑战是现实系统的复杂性,这导致执行时间,手动干预和维护的增加。 因此,需要一种可以实时运行并应对现实世界复杂性的算法。

因此,该算法必须处理现实世界系统的复杂性,并且必须实时运行,其目的是通过设计一个良好的,特定于领域的,知识衍生的奖励函数来最大化期望的奖励总和。 因此,在以下各节中讨论并在下图中显示的机器人强化学习面临许多挑战:

高维问题

随着维数的增加,数据也随之增加。 结果,有更多的计算覆盖了完整的状态动作空间。

让我们举个例子:

  • 对于每个维度,状态空间都离散为 10 个不同的状态
  • 因此,三维状态空间将具有10x10x10 = 1000个状态
  • 因此,随着维数的增加,状态将增加 10 倍

因此,随着尺寸的增加,评估变得困难。 函数近似器(例如神经网络)可以有效地解决此问题。 机器人系统的问题是由于拟人(类人)机器人导致的高维状态和动作。 经典的强化学习方法考虑具有离散状态动作空间的网格世界环境。 在网格世界环境中,导航任务将涉及许多离散的动作,包括移动,加速,加速,下降,启动,停止以及更多高精度方向。

使用离散化来减少维数会导致信息丢失,尤其是在机器人领域。 由于连续的动作空间,这会阻碍动态能力。 将动作空间减小为离散值可掩盖许多重要动作。 在处理到连续动作空间的映射时,函数逼近是一种明智的方法。

现实世界中的挑战

机器人与现实世界互动。 因此,机器人强化学习的真正问题是应对这些现实问题。 这是因为在现实世界中机器人组件的定期磨损非常昂贵。 连续的维护和修理在劳力和维护和修理的时间损失方面付出了巨大的代价。 因此,安全探索是机器人强化学习过程中的关键问题。

Perkins 和 Barto(2002)提出了一种基于 Lyapunov 函数构造强化学习主体的方法(附录 A,“强化学习中的其他主题”)。 现实世界带来的挑战包括环境因素的变化,即气候,温度,光线等。 结果,由于温度和气候的极端影响,机器人的动力学将受到影响,并且将避免学习过程的收敛。 现实环境是不确定的。 结果,由于气候,温度,光线等外部因素,无法产生过去的学习时间。 因此,状态是不确定的,因此很难模拟真实的真实场景。 因此,大多数模拟器都没有考虑气候,温度和光的元素。 因此,这对要解决的算法提出了严峻的挑战。 除此之外,传感器噪声测量的不确定性导致无法直接用传感器观察所有状态。

现实世界中的大多数机器人学习任务都需要人工监督,而获取现实世界中的样本在时间,劳动力和金钱方面都非常昂贵。 在机器人强化学习中,无法使用诸如模拟器之类的情景设置,因为它们在时间,维修和金钱上都花费很多。 机器人需要在严格的约束下与现实世界互动,以免造成重大破坏。

此外,由于这些强化学习算法是在计算机中实现的,因此无法避免时间离散化,从而导致在现实情况下无法复制连续时间系统。 由于以下过程,现实世界的状态表示与现实世界状态相比可能会滞后:

  • 信号通信延迟
  • 信号信息处理
  • 实时创建学习模型以输出要采取的最佳措施
  • 延迟接收动作信号和致动导致机器人中的机器运动

由于这些延迟,动作无法立即实现,从而导致延迟效果。 在诸如马尔科夫决策过程MDP)之类的强化学习算法中,假定动作会瞬间影响环境,而忽略了与现实世界相关的延迟。 可以通过汇总一些最近的操作并将其提供给状态来解决此问题,但这也将导致尺寸的增加(在上一节中讨论的机器人强化学习中的挑战)。 解决该问题的另一种方法是增加时间步长,但这有两个缺点,一个缺点是妨碍了机器人的控制,第二个缺点是由于持续时间的变化而对系统的动态产生不利影响。

因此,我们总结了如下讨论的实际挑战:

  • 现实世界中的磨损
  • 昂贵的硬件
  • 环境因素,例如气候,温度,光线,噪音等
  • 接收环境信号与执行操作之间的延迟
  • 包括大量的时间,人工和维护费用方面的投资

模型不确定性导致的问题

为了避免与实际交互相关的成本,使用了模拟器。 问题在于,仿真模型应接近实际情况。 对于理想的设置,方法是在模拟中执行学习任务,并将知识模型转移到机器人。 为机器人创建良好的精确学习模型以及现实场景的模拟环境模型非常具有挑战性,因为它需要大量的现实世界数据样本。

从少量数据中学到的小模型会导致建模不足,从而使机器人很容易与实际系统脱节。 模拟器的问题在于它们无法复制与物理交互(如摩擦和触摸)相关联的真实世界的复杂性,因此它们被忽略了。 结果,在现实世界中,由于与物理交互有关的挑战,机器人的能量和对它的控制也丢失了。 因此,忽略这些特征使机器人强化学习模型难以根据实际情况进行准确训练。 因此,在现实世界中学习有助于捕获环境的这些固有特征。

因此,由于现实世界的不完整状态表示而导致的模型不确定性是机器人强化学习要克服的巨大挑战。

机器人要实现的最终目标是什么?

奖励函数对于在机器人强化学习中指定学习智能体的目标至关重要。 如我们所知,对于强化学习算法,最终目标是使从开始状态到达到目标状态的预期奖励总和最大化。

在现实世界中,设计好的奖励函数是一个巨大的挑战。 因此,代表或指定目标是现实世界中的挑战。 现实世界中充满不确定性,因此,奖励函数应能够捕获与此类不确定性相关的积极状态。

一些领域在任务完成后获得奖励,不确定性较小,但在某些情况下,导致更好的最终结果的每个动作都具有不同的奖励。 这是由于每个状态的重要性,因为每个状态都像在现实情况中那样采取了行动。 因此,任务完成奖励机制不能在现实世界中实现,因为它不会捕获不确定性,也不会导致学习趋同,从而导致表现下降。

在我们遇到的大多数现有模拟中,我们看到了一种二元奖励机制,该机制仅捕获了学习智能体的成功和失败。 将中间奖励包含为奖励函数的一部分,将比二元奖励方法更好,从而导致更好的解决方案。 包括中间奖励在内,将捕获现实系统中从状态到状态转换的不确定性。

因此,奖励函数通常表示为状态动作对的函数。 如前所述,由于先前讨论的现实世界的挑战,该模拟不能准确地表示现实世界的状态。 但是,除了环境因素和时间滞后之外,由于具有良好的奖励函数,机器人加固智能体还可以学习优化时间和管理风险,并避免了实际系统设置和维护的成本。

最近,已经进行了进一步的研究开发,以在简单模型的基础上构建复杂策略,以通过使用更好的参数化奖励函数来探索那些复杂策略来实现此目标。 在他们的研究中,Sorg 等人(2010 年)以及 Zucker 和 Bagnell(2012 年)通过调整奖励函数,通过策略搜索技术实现简单的最优控制,得出了复杂的策略。

未解决的问题和实际挑战

根据强化学习算法的不同挑战,与监督学习相比,它们无法直接应用于机器人技术,后者在研究和更好的部署方面已经取得了重大的进步。

在风险不是很高的机器人技术中,可以为各种物理系统和控制任务引入强化学习。 其背后的原因是在现实世界系统中强化学习模型的稳定性问题。 所有学习过程都需要已实现的领域知识,以便更好地表示状态并设计准确的奖励函数。 这需要进一步的研究和开发。

让我们讨论一些关于强化学习算法的开放性问题,这些问题在机器人强化学习领域中正在进行的和未来的研究中需要更多的关注。

开放问题

以下列出了一些开放的,并非详尽无遗的问题,需要特别注意以提供更好的机器人技术强化学习模型:

  • 我们如何使状态动作空间表示过程自动化?

    • 机器人技术中的状态作用空间是连续的并且是多维的。 状态和动作空间的高维性和连续性使表示选择过程难以实现自动化。
    • 状态逼近也是一个未解决的问题,目前正在深入研究中。
  • 我们如何根据收到的数据生成奖励函数?

    • 强化学习算法的成功很大程度上取决于奖励函数的质量,其对不同状态表示的覆盖范围以及与之相关的不确定性
  • 先验领域知识的重要性是什么?

    • 先验知识对于强化学习智能体的准确率更好。
    • 在尽可能少的剧集中更好地学习所需的先验知识量尚不确定,并且尚待解决。 因此,重复大量的迭代以确保更好的学习。
    • 在某些情况下,由于与环境相关的大量不确定性,先验知识可能无济于事。
  • 我们如何根据感知数据仔细学习?

    • 繁重的预处理和约束条件使感知到的大多数关键信息抽象化
    • 这种抽象是由于与处理不完整,模棱两可和嘈杂的传感器数据相关的限制
    • 当接收到数据信号时,在旅途中同时学习是一个活跃的研究领域
  • 我们如何处理与模型相关的误差和不确定性?

    • 为了减少所需的实际交互,请使用基于模型的方法
    • 仅在模拟中学习的策略不应直接传递给机器人
    • 由于与实际系统相关的不确定性,这个问题似乎是不可避免的
    • 创建足够强大的算法来处理与现实世界系统相关的不确定性的算法是一个活跃的研究领域

机器人强化学习的实际挑战

除了前面讨论的基本挑战之外,机器人强化学习中还存在更大的问题和实际挑战。 这是因为要克服实际挑战很重要,要使机器人以最小的错误率有效地工作。 为了避免实际挑战,必须执行以下任务:

  • 更好地利用数据集:
    • 人类能够在已经学到的知识和新的交互作用之上增强自己的学习。
    • 例如,一个孩子触摸火锅并迅速学会远离火锅。 同样,在步行或执行任何任务时,人类的表现也会得到改善,从而增强了学习能力。
    • 转移先前学到的知识并通过机器人在旅途中增强它是非常具有挑战性的。
    • 对于简单的任务,可以在学习中实现收敛,但是对于复杂的任务,由于缺少足够的数据来增强学习,因此学习可能永远不会收敛。
    • 更好地利用数据可以更好地处理噪声。
    • 创建处理环境变化的数据集以更好地表示状态是机器人强化学习中一个活跃的研究领域。
  • 执行更好的实验并不断评估它们以进一步改进。
    • 在机器人强化学习中执行大规模,真实世界的实验是一项艰巨的任务
    • AI 社区的研究人员正在为机器人强化学习进行实验的标准设置

要点

在本章中,我们经历了机器人技术领域强化学习算法所面临的主要挑战。 因此,下图显示了想要进入这一强大的机器人强化学习研究领域的学生的主要收获:

总结

在本章中,我们介绍了强化学习算法的现状以及机器人技术方面的挑战。 我们还尝试详细了解每个挑战。 我们还了解了实际挑战及其建议的解决方案。 破解端到端机器人技术的解决方案将是 AI 社区最大的里程碑。 当前,算法和数据处理单元的不断改进面临挑战。 但是,我们看到机器人执行一般人工任务的日子已经过去了。 如果您想跟进机器人强化学习中的一些研究,那么您可以从以下选项开始:

在下一章中,我们将尝试涵盖另一个有趣的领域,即广告技术以及如何使用深度强化学习来破坏它。

十二、广告技术中的深度强化学习

到目前为止,在讨论强化学习应用研究领域的单元中,我们看到了强化学习如何破坏机器人技术,自动驾驶,金融投资组合管理以及解决诸如围棋之类的极其复杂的游戏领域。 强化学习可能会破坏的另一个重要领域是广告技术。

在深入了解问题陈述及其基于强化学习的解决方案之前,让我们了解所涉及的挑战,业务模型和投标策略,这将成为理解我们将尝试使用强化学习框架解决问题的基本前提。 我们将在本章中介绍的主题如下:

  • 计算广告挑战和出价策略

  • 展示广告中使用强化学习的实时出价

计算广告挑战和出价策略

广告是一种传达信息的方式。 计算广告的核心任务是在给定上下文中的给定用户和广告之间找到最佳匹配,其中适用以下因素:

  • 上下文/出价人:用户访问过且被认为适合广告的平台,例如:
    • 使用搜索引擎的用户。 因此,在这种情况下赞助广告是一个很好的计划。
    • 用户阅读网页。 因此,展示广告适合这种情况。
    • 观看任何视频(电影,剪辑,短视频等)的用户。 因此,短视频广告是好的。
  • 约束条件:对广告客户而言,最大的约束条件是预算有限和时间段有限。

在实现上述目标方面面临的核心挑战如下:

  • 设计市场和交易平台,以便利所有用户,广告商和发行人的所有参与利益相关者的工作,并使其价值最大化。
  • 为此完整的端到端过程构建基础结构:

这些元素之间的关系如下所示:

广告中使用的商业模式

广告平台的业务模型由不同的模型组成,这些模型控制广告商必须使用广告平台支付的应付金额度量。 计算广告领域中有不同的指标,如下所示:

  • CPM:每千次展示费用
    • 在这种类型的模型中,广告商为每千次展示支付固定金额,其中的展示次数可以是点击次数,观看次数等
  • CPC:每次点击费用,每次点击付费PPC
    • 在这种类型的在线广告模型中,广告商向用户支付平台所有者对用户在广告链接上进行的每次点击操作的费用
  • CPA:每次操作费用/每次获取费用/每次获取费用PPA)/每次转化费用
    • 在这种类型的模型中,平台所有者(例如,运行广告的发布者)承担所有风险,而广告客户仅为已获得全部用户(换句话说,他们已经完成了所需操作,注册订阅或购买交易)。

赞助搜索广告

赞助搜索在在线广告中起着重要作用,尤其是在诸如 Google,Yahoo,Bing 等搜索引擎中。 由于每天都有大量的受众访问这些搜索平台,因此它们是最大的广告平台。

搜索广告管理

广告客户对某些搜索查询的每次点击率进行出价,这些查询由搜索引擎接收。 然后,将广告显示为那些搜索查询结果的一部分,并且,如果用户单击广告,则广告商必须支付投标金额。

Adwords

在所有广告客户将其每次点击费用的出价针对某些搜索查询进行出价后,平台会接收到数据,该数据包括不同广告客户的出价集以及每个广告客户的总预算,以及每个搜索查询的点击率CTR)的历史数据。

主要目的是响应每个查询选择一组广告,以使搜索引擎(即出价商)获得的收益最大化。 就像出价师的收入最大化一样,广告商的利润最大化也很重要,并且包括各种出价策略。

广告商的竞标策略

广告客户的出价策略主要包括在出价时针对不同关键字的预算优化。 重点讨论如下:

  • 广告客户可以更好地将预算分配给不同的关键字
  • 实现利润最大化的更好的出价策略

此外,在这个在线广告世界中,竞标是实时发生的。 您如何实现更好的实时出价策略以实现利润最大化?

  • 自主竞标智能体

    • 这些智能体将使用历史市场数据并直接与市场参与者进行交互,并根据此数据对自己的行为进行建模,从而帮助制定不同的决策策略
  • 使用强化学习的机器学习方法

    • 在第 3 章“Markov 决策过程”中可以看到马尔可夫决策过程MDP)的框架,在该框架中,我们,最大化了每个状态的预期效用,并通过最大化预期奖励总和,优化了每个状态到目标状态的路径。

展示广告中使用强化学习的实时出价

在线展示主要通过实时出价来提供,其中,展示广告的每次展示都是在通过用户访问产生的同时实时出价的。 自动实时地出价对于广告商最大限度地提高利润至关重要。 因此,需要设计一种学习算法,该算法可以基于历史数据实时设计出最佳的学习策略,以便根据即时和未来的回报跨不同的印象进行预算的动态分配。 在这里,我们将讨论由 Cai 等人在《使用强化学习的展示广告中的实时出价》中发布​​的强化学习框架来制定出价决策过程。

在蔡等人的这项研究中。 此外,我们考虑了在展示广告的情况下进行机器竞标,因为实时竞标是一项极富挑战性的任务,因为在在线展示广告的情况下,只要它由用户访问生成,广告印象的竞标就会立即开始。 在考虑了剩余预算,未来相关广告展示的可用性,出价结果和收到的反馈之后,为每次广告出价计算最佳出价,这些都可以帮助广告客户优化出价策略,从而更好地进行分配。

在这里,研究人员试图获得最佳出价函数,该函数可以最大化广告活动的关键表现指标,这些指标主要是总点击次数或总收入。 但是,这种方法主要在静态出价的情况下起作用,在这种情况下,出价发生在广告商为每个展示支付固定的平均费率的情况下。 在实时出价的情况下,它在展示级别是动态的,这意味着在一个平台中,根据生成的展示的需求,出价值会有所不同。

本研究试图通过使用强化学习框架来解决实时竞标挑战,并将其作为顺序决策来解决,其中:

  • 智能体将从广告商的角度学习
  • 整个广告市场和所有互联网用户形成环境
  • 状态空间包含出价信息和实时活动参数
  • 动作是要设定的买入价

因此,在每个步骤中,代表广告商出价者的智能体都会观察到由当前广告系列参数(例如预算和剩余时间)以及针对该特定广告印象的出价请求组成的状态。 然后,它发布一个动作; 例如,确定出价,中奖结果和用户反馈将一起作为对所采取措施的奖励,并将用于加强模型。 由于在现实世界中出价量很大,因此 MDP 框架已与基于 Q 网络的方法一起使用,该方法使用神经网络作为状态作用值函数逼近器。 竞标的基本强化学习框架如下所示:

最初,预算b是​​提供给智能体的,此处的目标是在随后的出价t中获得尽可能多的点击。 以下是智能体考虑的重要信息:

  • 其余出价,即剩余出价编号t ∈ {0, ···, T}
  • 初始分配预算中剩余的剩余金额,即未用预算b ∈ {0, ..., B}
  • 特征向量x,代表出价请求

在每个剧集中,每次出价都会按顺序发送给智能体,智能体针对每个智能体根据当前信息tbx。 因此,智能体基于出价的剩余时间,初始分配预算中剩余的剩余量以及提出的投标请求的所有关键信息来决定适当的动作。

如上图所示,智能体维护剩余的出价t和剩余的预算b。 在每个时间步,智能体都收到一个竞标请求以及出价x ∈ X(特征向量空间),并且它必须确定竞标价格a

给定特征向量x的市场价格概率分布函数为m(δ, x),其中δ是市场价格, m是其概率。 因此,如果智能体以a ≥ δ的价格出价,则它将赢得竞标并支付δ,剩余预算将变为b-δ。 万一失败,智能体从竞标中得不到任何东西。 在此,如果将赢得出价视为预期奖励,则将预测 CTRpCTR)表示为θ(x)。 在每次出价之后,剩余的出价数量减少 1。当t = 0时,也就是说,没有剩余的出价,则剧集结束。 随着当前剧集的结束,剩余的出价编号和预算都将分别重置为TB

以下是前面的增强型学习框架要投标的实现的伪代码:

(In this part of the process: approximation of the optimal value function V(t, b) is done)

Inputs: probability distribution function of market price that is m(),
        average click through rate (CTR) , 
        episode length that is number of auctions in an episode T,
        budget B

Output: value function V(t, b)

Steps:
initialize V(0, b) = 0
for t = 1, 2, · · · , T − 1 do
    for b = 0, 1, · · · , B do
        enumerate  from 0 to min(, b) and set V (t, b) as per the following equation:     
    end for
end for
(In this part of the process: as per the converged optimal value function V(t, b) obtained from the above part, using that value function the action to bid price is performed)

Input: CTR estimator θ(x), 
value function V(t, b), 
current state()

Output: optimal bid price  in current state

Steps:
calculate the pCTR for the current bid request: 
for δ = 0, 1, · · · , min(, ) do
     if θc + V ( − 1,  − δ) − V ( − 1, ) ≥ 0 then
          ← δ
     end if
end for

总结

在本章中,我们了解了广告技术领域的基本概念和挑战。 我们还了解了相关的业务模型,例如 CPC,CPM 和 CPA,以及实时策略出价,以及为什么需要一个独立的智能体来使流程自动化。 此外,我们讨论了一种将在线广告中实时出价的问题状态转换为强化学习框架的基本方法。 这是用于强化学习的全新领域。 利用强化学习技术进行广告技术开发的更多探索性作品及其结果尚未发布。

在下一章中,我们将研究在计算机视觉领域,尤其是在对象检测中,如何使用强化学习。

十三、图像处理中的强化学习

在本章中,我们将介绍人工智能AI)社区(计算机视觉)中最著名的应用领域之一。 将 AI 应用于图像和视频已经持续了二十多年。 具有更好的计算能力,诸如卷积神经网络CNN)及其变体的算法在对象检测任务中表现良好。 在自动图像字幕,糖尿病性视网膜病变,视频对象检测,字幕等方面,已经采取了高级措施。

由于其令人鼓舞的结果和更通用的方法,将强化学习应用于计算机视觉成功地构成了研究人员的艰巨任务。 我们已经看到了 AlphaGo 和 AlphaGo Zero 如何胜过专业的人类围棋玩家,在每个步骤中,将深度强化学习方法应用于游戏板的图像。

因此,在本章中,我们将介绍计算机视觉中最著名的领域,对象检测以及强化学习如何尝试做到这一点。

深度强化学习中的分层对象检测

在本节中,我们将尝试理解如何根据 Bellver 等人(2016)在《使用深度强化学习的分层对象检测》中建议的框架,将深度增强学习应用于分层对象检测。 该实验展示了一种使用深度强化学习在图像中执行分层对象检测的方法,该方法主要侧重于承载更丰富信息的图像重要部分。 此处的目的是训练一个深度增强学习智能体,为其提供一个图像窗口,并将图像进一步分为五个较小的窗口,并且该智能体成功地将注意力集中在较小的窗口之一上。

现在,让我们考虑一下人类如何看待图像。 我们总是以顺序的方式提取信息以了解图像的内容:

  • 首先,我们专注于图像的最重要部分
  • 最重要部分提供的信息将引导我们进入图像的下一部分,重点关注
  • 只要图像的不同部分提供一些相关信息,上述步骤便会继续

在计算机视觉中,图像是在局部范围内进行分析的,我们使用一个像素大小的小窗口,然后滑动窗口以扫描整个图像。 传统上,这就是我们处理图像处理和分析任务的方式。 使用这种窗口滑动方法,可以独立地分析图像的不同部分,而不会相互关联。 可以通过图像的分层表示来实现不同图像部分的关联。

为了获得图像的分层表示,首先,像以前一样,顺序进行图像的自顶向下扫描,以聚焦于包含相关信息的图像的不同局部部分。 使用强化学习,可以使智能体具有足够的能力来检测图像中的对象。 智能体首先分析整个图像,然后决定要聚焦的部分,并且智能体在找到图像中的对象后最终停止。 在此实验中,图像窗口分为五个预定义的较小部分,其中四个部分代表四个象限,一个部分代表中心区域。

之所以使用强化学习,是因为智能体可以按不同的顺序探索层次结构表示,并且仍然可以达到目标。 这是因为其目标是在目标状态为找到包含对象的图像部分的情况下,最大化预期的总和回报。

相关作品

物体检测中的大多数传统解决方案包括窗口大小选择,然后将窗口滑动到图像上,聚焦于不同区域。 区域之间的关系从未捕获,所有区域都用于计算。 在这里,我们将简要讨论在对象检测领域进行的其他一些研究。 本节中对以下研究的详细说明超出了本书的范围,但这将为您提供对象检测领域中取得的进展的基本知识。

基于区域的卷积神经网络

在较早的对象分类模型中,CNN 非常慢且计算量很大。 此外,作为分类问题的成功完全取决于准确率。 通过在每层的所有区域上滑动窗口来完成 CNN 中的运行卷积。 因此,更多的边界框(通过滑动窗口分析的不同区域的总数)意味着更高的计算成本。

基于区域的卷积神经网络R-CNN)是首次采用选择性搜索方法来减少输入分类器的边界框的数量。 此外,选择性搜索使用纹理,强度,颜色等特征来创建对象的可能盒子位置。 现在,这些盒子可以送入 CNN 模型。

因此,R-CNN 的关键组件包括:

  • 生成包含对象的可能的盒子区域(创建感兴趣的区域)
  • 将这些生成的框区域输入到 CNN
  • 然后,将 CNN 的表示输出馈送到 SVM 层,以预测每个框区域的类别
  • 通过边界框回归来分别优化这些框区域,以实现更好的定位

空间金字塔池网络

通过消除对图像不必要区域的关注,R-CNN 的速度比普通 CNN 快,但 R-CNN 实际上仍然非常慢,因为 R-CNN 所关注的区域数量足够高,因此总体计算仍然很昂贵 。

空间池金字塔网络SPP-net)是解决此问题的首次尝试。 在 SSP-net 中,整个图像的 CNN 表示仅计算一次,然后进一步用于计算通过选择性搜索方法生成的每个盒子区域的 CNN 表示。 这是通过在卷积表示的对应于框区域的那部分上进行合并来完成的。 通过考虑中间层的下采样,通过将盒区域投影到卷积层上来计算对应于盒区域的卷积表示部分。

与传统 CNN 方法中的最大池化不同,空间池化是在 SPP-net 中的最后一个卷积层之后进行的。 该空间池化层将任意大小的盒子区域划分为固定数量的容器,并在每个容器上进行最大池化。

SPP 网络的一大缺点是,只能微调网络的全连接层,而不能进行不会发生反向传播的空间池化层。

Fast R-CNN

首先,是 Fast R-CNN(由 Microsoft Research 的 Ross Girshick 于 2015 年提出)提出了在图像的不同区域之间共享卷积输出的想法:

Ross Girshick 的 Fast R-CNN

在 Fast R-CNN 中,将输入图像和多个兴趣区域作为 CNN 的输入。 完成 RoI 的合并以获得固定大小的特征映射,然后通过全连接层FC)发送以获得特征向量。 R-CNN 每个兴趣区域具有两个输出向量,如下所示:

  • Softmax 概率
  • 每类边界框回归偏移

Fast R-CNN 解决了与 SPP 网络相关的关键问题; 由于空间池化层未进行微调,因此,Fast R-CNN 提供了端到端的学习网络。 Fast R-CNN 使用类似于最大池梯度计算的简单反向传播,但池区域重叠。

此外,与 R-CNN 不同,Fast R-CNN 结合了边界框回归和神经网络训练,而 R-CNN 则使用边界框回归单独进行此区域优化,这有助于更好地定位。 因此,在 Fast R-CNN 中,分类和定位不需要单独的网络。 结果,相对于之前开发的任何其他对象检测模型,总的训练时间显着减少,并且由于端到端学习,与 SPP 网络相比,其准确率更高。

Faster R-CNN

Faster R-CNN 以其名字命名。 它比以前的 Fast R-CNN 更快。 这是通过用称为区域提议网络的非常小的卷积网络替换 Fast R-CNN 的最慢部分(感兴趣的生成框区域)的选择性搜索来执行相同的任务来生成的, 极有可能包含对象(感兴趣的区域)。

Faster R-CNN 实现了锚框的概念,以处理宽高比和对象比例的变化。 对于每个区域,都有三个用于缩放比例和三个纵横比的锚点框。 因此,对于每个位置,我们有九个框被馈送到区域提议网络RPN),以预测该区域是背景还是前景的可能性。 边界框回归用于改善每个此类区域的锚框。 因此,RPN 输出可变大小的边界框及其类概率。

因此,RPN 给出了各种大小的边界框,每个边界的概率与每个类的对应概率相同,其余网络类似于 Fast-RCNN。 Faster-RCNN 的速度是 Fast-RCNN 的 10 倍,具有相似的精度,从而使其成为可用的最精确的对象检测模型之一。 下表显示了 R-CNN 不同变体的速度分析:

类型 每张图像的测试时间(以秒为单位) 加速
神经网络 50 1 倍
Fast R-CNN 2 25 倍
Faster R-CNN 0.2 250 倍

YOLO(你只看一次)

YOLO 通过执行回归学习类概率和边界框的大小,从而对输入图像执行对象检测。 YOLO 将图像划分为SxS网格,每个网格预测N边界框和置信度。 该置信度值量化边界框的准确率和对象在边界框中的出现。

YOLO 还可以为每个盒子预测训练中所有类的类得分。 因此,图像中所有框上的类别得分的总和也有助于计算整个图像的类别概率,从而有助于预测对象。 由于将图像划分为SxS网格,并且针对每个输出N个边界框,因此,正在预测SxSxN框。 但是,由于我们具有盒子的置信度得分并使用显着的阈值,因此可以删除所有低置信度(不包含对象)的盒子。

而且,YOLO 一次扫描整个图像,而无需执行先生成兴趣区域,然后以较早的方法将这些区域馈入 CNN 的步骤。 因此,在 YOLO 中运行,图像需要一次经过 CNN,并且实时生成结果。

单发探测器

单发检测器SSD)以其在速度和准确率之间的平衡而著称。 就像 YOLO 一样,SSD 仅在输入图像上运行一次 CNN 即可学习表示形式。 在此表示形式上运行一个小的3x3卷积核,以预测边界框和类概率。 为了处理比例,SSD 会在多个卷积层之后预测边界框。 由于每个卷积层以不同的比例运行,因此它能够检测各种比例的对象。

下图显示了 Fast R-CNN,Faster R-CNN,YOLO 和 SSD 的表现指标:

分层对象检测模型

在这里,我们将尝试通过强化学习框架来实现对象检测问题,在强化学习框架中,强化学习智能体将与环境图像进行交互,并且每步,智能体将决定关注哪个区域,以实现目标。 以最少的时间步长找到对象。 问题陈述以马尔可夫决策过程MDP)框架表示,其不同参数讨论如下:

状态

智能体状态的第一部分由使用两个模型提取的视觉特征定义,它们是:

  • 图像缩放模型
  • Pool45-作物模型

在下面的“模型和训练”部分中说明了这两种变化。

智能体状态的第二部分是存储向量,它捕获了智能体为了搜索对象而采取的过去四个时间步骤的动作。 在每个时间步长,都有六种可能的操作(在下面的部分中进行介绍)。 因此,存储向量的尺寸为4 * 6 = 24。 已经发现该存储向量对于稳定搜索轨迹很有用。

动作

有两类可能的操作,如下所示:

  • 运动动作暗示着当前观察区域的变化
  • 终端操作,指示已检测到对象并且搜索已结束

每个移动动作只能从预定义的层次结构在区域之间自上而下转移注意力。 图像被进一步分为五个较小的子区域进行聚焦。 因此,在创建为的五个子区域(下图中)中构建了层次结构:

  • 四个区域
  • 一个中央重叠区域

因此,存在五个运动动作,每个运动动作与子区域相关联,并且具有一个终端动作,其被选择以指示成功检测到对象的搜索的结束。

奖励

运动动作的奖励函数由以下公式表示:

下式表示的终端动作的奖励函数:

此处,g是基本事实,b是当前步骤中的区域,b'是下一步中的新区域,而 IoU 是事实真相之间的交并比。

交并比IoU)是对象检测中的一个指标,其中有两个重叠的边界框。 首先,计算盒子的交点,即重叠的面积。 其次,计算重叠框的并集,将整个框的面积之和减去重叠面积。 然后将相交除以并集得到 IoU。

对于移动动作,对于特定状态s,朝着区域b'移动的动作将获得更好的回报,该区域的地面实况g大于 IoU g与上一步中考虑的区域b的关系。 否则,行动将受到负面奖励。

对于终端动作,如果具有基本事实的当前区域b的 IoU 大于某个阈值τ,则奖励为正,否则为负。

模型与训练

在这里,训练了一个深度 Q 网络,针对该网络使用两个模型来创建智能体状态表示的一部分。 这两种模型如下:

  • ImageZooms 模型
  • Pool45-作物模型

对于 Image-Zooms 模型,每个区域的大小调整为224x224,并通过 Pool5 层馈入 VGG-16,以获得特征映射。 对于 Pool45-Crops 模型,全分辨率的图像通过 Pool5 层输入到 VGG-16。 合并从整个图像中提取的所有兴趣区域ROI)的特征映射。

这两个用于特征提取的模型输出7x7的特征映射,该图被馈送到公共块中(如以下架构所示)。 这些特征映射和存储向量(前面讨论过)被馈入由两个全连接层组成的深层 Q 网络,每个层各有 1024 个神经元。 每个全连接层都具有 ReLU 激活函数,并经过丢弃训练:

分层对象检测模型(架构)来自《具有深度强化学习的分层对象检测》,Bellver 等,2016 年

训练细节

通过 ε 贪婪方法学习了一个深层 Q 网络,该网络以ε = 1(完全 100% 探索)开始,并以 0.1 的步长直到 0.1(仅 10% 探索,90% 开发)减少。 在探索过程中,选择随机动作是因为通过更好的探索,可以避免局部最小值,并且还可以揭示通往目标状态的未知优化路径。 而且,为了帮助智能体学习终端动作,每当当前区域具有IoU > τ时,智能体便被迫采取该动作,这反过来又加速了学习过程。

我们在训练时发现的一个事实是,我们不应强加要首先看图像的哪个对象。 在每个时间步长,智能体都将专注于当前区域中与真实情况性重叠程度最高的对象。 这样,目标对象有可能在自顶向下的探索过程中发生变化。

从正态分布和 Adam 优化器初始化深度 Q 网络的权重和偏差参数,以使损失最小化。 高伽玛(折扣系数)用于平衡当前和未来的回报。

使用深度强化学习进行对象检测的这种方法显示了一种由学习智能体自上而下探索区域层次结构的方法。 因此,通过适当的层次结构,可以在更少的时间步长内正确检测对象,如下图共享的结果所示:

总结

在本章中,我们介绍了对象检测中的各种最新技术,例如 R-CNN,Fast R-CNN,Faster R-CNN,YOLO,SSD 等。 此外,我们探索了 Bellver 等人(2016)在《使用深度强化学习的分层对象检测》中所提供的方法。按照这种方法,我们学习了如何创建 MDP 框架以进行对象检测,并以最短的时间步长以自上而下的探索方法分层检测对象。 图像中的对象检测是计算机视觉中的一种应用。 还有其他领域,例如视频中的对象检测,视频标记等等,在这些领域中,强化学习可以创建最先进的学习智能体。

在下一章中,我们将学习如何在 NLP(自然语言处理)领域应用强化学习。

十四、NLP 中的深度强化学习

大约一年前,在自然语言处理NLP)中进行强化学习成为人工智能界研究的热点。 2017 年下半年发布了大多数适合在 NLP 中使用强化学习的研究出版物。

在任何领域中使用强化学习框架的最大原因在于,以状态的形式表示环境,详尽列出了环境中所有可能的动作,以及特定领域的奖励函数,通过该函数来实现目标。 最优化的行动路径。 因此,如果系统具有许多可能的动作,但是未给出正确的动作集,并且目标高度依赖于系统的不同选项(动作),则强化学习框架可以比现有的监督或非监督模型更好地对系统进行建模。

为什么在 NLP 中使用强化学习?

  • 面向 NLP 的系统(例如文本摘要,对话框生成,问题解答,机器翻译等)确实具有典型的强化学习场景。 例如,对话系统具有增强型学习智能体,该学习智能体根据接收到的查询生成响应,其中接收到的查询可以是代表当前状态的信号,并且可以采取某种行动来生成响应,智能体可以以奖励的形式对此进行反馈。
  • 有很多隐藏变量,它们以隐藏状态的形式存在,还有更多。 决定要包括哪个潜在变量也可以表示为与某些奖励相关的动作。
  • 当前,对于序列到序列模型,我们有一个 BLEU 分数(请参见附录 A,“强化学习中的其他主题”),该分数用于评估生成的语言和实际输出之间的错误分数,但 BLEU 分数只能在生成输入的整个预测语言之后进行评估。 它无法评估代持续进行的时间; 因此,它无法改善旅途中的流程。

根据迄今为止进行的积极研究,强化学习为破坏和增强 NLP 下列领域的成果提供了机会:

  • 文字摘要
  • 问题回答
  • 对话生成
  • 对话系统
  • 基于知识的质量检查
  • 机器翻译
  • 文字生成

在这里,我们将介绍在文本摘要和问题解答中使用强化学习的方法,这将使您对研究人员如何在这些领域中收获强化学习的好处有一个基本的了解。

文字摘要

文本摘要是通过保留文档的重要信息自动生成作为输入输入的文档测试的摘要文本的过程。 文本摘要以简洁的方式压缩了大量信息; 因此,摘要在与新闻/文章,文本搜索和报告生成相关的应用中起着重要作用。

有两种类型的汇总算法:

  • 提取式摘要:通过复制输入文本中的部分文本来创建摘要
  • 抽象式摘要:通过改写文本或使用输入文本中未包含的新词来生成新文本

为机器翻译创建的基于注意力的编码器解码器模型(Bahdanau 等,2014)是一个序列到序列模型,能够通过获得良好的 ROUGE 得分来生成具有良好表现的抽象摘要(请参见附录 A,“强化学习中的其他主题”)。 在短输入序列上的表现很好,并且随着输入文本序列长度的增加而降低。

在 CNN /每日邮件数据集的更大输入序列和输出摘要数据集上(Hermann 等,2015),Nallapati 等人(2016)提出了抽象摘要模型的应用,其中输入序列最多为 800 个标记,而摘要最多为 100 个标记。 对本实验的分析表明,与较大输入序列的基于注意力的编码器-解码器模型相关的问题是,它们通常会生成异常摘要,这些摘要通常由重复的短语组成。 这是因为仅通过监督学习方法进行训练的编码器解码器模型通常会遭受曝光偏差,即在训练过程中的每个时间步骤都提供了真实情况(实际文本)的假设。

在这里,我们将讨论 Paulus 等人(2017 年 11 月)的研究出版物《抽象摘要的深度强化模型》。 它向我们介绍了一种抽象摘要的新模型,该模型在 CNN /每日邮件数据集以及纽约时报NYT)数据集上都获得了强大的结果(Sandhaus,2008 年)。

所提出的模型通过使用神经内部注意模型混合学习目标来解决上述重复短语的问题,从而获得了这些最新结果:

  • 神经内部注意模型:它由编码器中的时间内部注意组成,以记录每个输入标记的注意权重和顺序解码器中的内部注意模型来记录解码器已经生成的单词。
  • 混合学习目标:这是最大似然交叉熵损失(通常在有监督的深度学习框架中使用)和从策略梯度强化学习中获得的奖励的组合,以减少暴露偏见。 因此,当使用监督学习的标准单词预测与强化学习的全局序列预测训练相结合时,所得的摘要变得更具可读性,而不是重复短语。

该提议的方法在 CNN /每日邮件数据集上进行了测试,并获得 41.16 的 ROUGE-1 评分,相对于以前的抽象摘要方法而言,这是一个显着的改进。 此外,人工评估还表明,与早期方法相比,所得到的摘要更具可读性。

在下一节中,我们将简要介绍该方法,以了解如何使用强化学习来创建最新的抽象摘要模型。

用于抽象摘要的深度强化模型

如前所述,此方法包含两个重要方法:

  • 神经内部注意模型
  • 混合学习目标

神经内部注意模型

本节说明了编码器-解码器网络上的神经内部注意模型。 此处,x = [x[1], x[2], ..., x[n]]代表输入(文章)标记的序列,y = [y[1], y[2], ..., y[m]]代表输出(摘要)标记的序列。 网络的编码器部分由双向 LSTM 组成(请参见附录 A,“强化学习”中的其他主题)。 因此,使用双向 LSTM 读取输入序列x,该 LSTM 从xᵢ的嵌入向量计算隐藏状态h[i]^e = [h[i]^e_fwd || h[i]^e_bwd],其中||表示向量的连接。

在框架的解码器部分,使用单个 LSTM,该 LSTM 从yₜ的嵌入向量计算隐藏状态h[t]^d。 在时间步零处的初始隐藏状态(即h[0]^d)使用编码器的最后一个隐藏状态(即h[n]^e)进行初始化。 因此,h[0]^d = h[n]^e

解码时的输入序列上的时间内部注意

解码时,在每个时间步t时,时空内部注意力函数用于伴随编码器输入序列的重要部分以及解码器的隐藏状态和先前生成的单词(在早期的解码过程中)t之前的时间步长)。 这种注意方法用于防止在不同时间步长的解码过程中出现输入序列的相同部分。

e[ti]给出在解码时间步长t处的隐藏输入状态h[i]^e的关注分数。 因此,e[ti] = f(h[t]^d, h[i]^e),其中f是返回e[ti]标量值的任何函数。

注意权重进一步标准化(如下所示),以惩罚在先前的解码步骤中已收到较高注意值的那些输入标记。 这为我们提供了新的时间注意力得分e'[ti]

最后,在输入中计算归一化注意力分数α[ti]^e,然后将其用于计算输入上下文向量c[t]^e

解码器内部注意

即使是时间内部注意函数,也可以确保在每个解码步骤中,都参与了编码输入的不同部分,但解码器仍可以在长序列中生成重复的短语。 为了防止这种情况,来自先前解码的序列的信息也可以被馈送到解码器中。 来自先前解码步骤的信息将帮助模型避免重复相同的信息并导致结构化的预测。

为了实现这种方法以合并来自先前解码步骤的信息,应用了解码器内部注意。 当前的编码器-解码器模型中未使用此方法进行抽象总结。 对于解码时的每个时间步t,都会计算新的解码器上下文向量c[t]^d。 由于在解码时为第一时间步生成的序列为空,因此,将用于时间步 1 的初始解码器上下文向量(即c[1]^d)设置为零向量。

对于t > 1,按以下方式计算时间关注分数e[tt']^d,归一化关注分数α[tt']^d和解码器上下文向量c[t]^d

下图显示了两个上下文向量C的使用(绿色为上下文编码器向量,蓝色为上下文解码器向量),以及该向量的当前隐藏状态H。 解码器生成输出序列的新单词:

Paulus 等人(2017)在《用于抽象摘要的深度强化模型》中发表的时间内部注意和解码器内部注意

标记生成和指针

在确定输出序列标记时,解码器决定使用 softmax 层生成标记,或者使用指针机制指向输入中的稀有重要标记,并将其复制为输出序列标记。 在每个解码步骤,使用切换函数来决定是使用标记生成还是使用点来复制输入标记。 uₜ定义为二进制值,如果使用指针机制,则等于 1,否则等于 0。因此,yₜ作为输出标记的概率由以下公式给出:

在这里,标记生成层创建以下概率分布:

这里,W_outb_out是连接到输出节点的解码器网络的权重和偏差参数,并且指针机制生成以下概率分布来复制输入标记xᵢ

使用指针机制(即p(u[t] = 1))的概率由以下公式给出:

在此,σ是 Sigmoid 激活函数。

混合学习目标

在本节中,使用监督学习和强化学习的组合来训练编码器解码器网络上先前提出的神经内部注意模型的框架。

带有教师强迫的监督学习

教师强迫算法(由 Williams 等,1989)是训练解码器 RNN 用于序列生成的最广泛使用的方法。 在解码过程中的每个时间步,教师强制算法都将最大似然损失降至最低。 定义为给定输入序列x的地面真值输出序列。 然后,使用教师强迫算法进行监督学习的最大似然目标将是最小化损失函数,如下所示:

但是,将L_ml最小化的目标并不总是产生最佳结果。 此问题背后的两个主要原因如下:

  • 暴露偏差:在训练过程中,神经网络知道直到下一个标记的真实情况序列,但在测试时并非如此。
  • 多个输出候选(即多个可能有效的摘要):有更多方式可以安排标记以生成多个摘要。 最大可能性目标没有考虑这种可能性。

策略学习

这里的思想是学习一种最大化度量标准而不是最小化从最大似然目标获得的损失的策略。 为此,使用了强化学习方法,其中将自关键策略梯度算法用于训练。 对于此训练,每次训练迭代都会生成两个单独的输出序列:

  • 通过在每个解码时间步长处从p(y[t]^s | y[1]^s, ..., y[t - 1]^s, x)的概率分布中采样来获取y^s
  • y_hat是通过最大化每个时间步的输出概率分布而获得的基线输出

因此,奖励函数r可以是我们选择的任何评估指标,目的是最大程度地减少以下损失:

最小化L_rl等同于最小化采样序列y^sL_ml。 因此,为了使L_rlr(y^s)最小化,需要增加输出序列的奖励,使其变得高于基线y^s的奖励,从而增加了预期的奖励。

因此,强化学习框架用于学习最大化特定离散量度的策略。 强化学习框架总结如下:

  • 操作u[t] ∈ generate(0), copy(1)和单词y[t]^s
  • 状态:编码器和先前输出的隐藏状态
  • 奖励:ROUGE 得分或任何其他评估指标

混合训练目标函数

由于最大似然目标基于先前生成的标记计算了下一个标记的概率,而诸如 ROUGE 之类的奖励指标有助于通过困惑度来衡量人类的可读性,因此这两种方法都可用于得出混合学习目标函数,如下所示:

此处,γ是缩放系数,用于平衡L_rlL_ml的大小差异。

文字问答

问题回答是提供文档上下文以及在给定文档上下文中存在其答案的问题的任务。 现有的问题回答模型用于优化交叉熵损失,该模型用于鼓励准确答案并惩罚与准确答案同等准确的其他可能答案。 这些现有的问题回答模型(Xiong 等人,2017 年的最新动态动态求职网络)经过训练,可以从文档上下文中输出所问问题的准确答案范围。 实际真实情况答案的开始和结束位置将用作此监督学习方法的目标。 因此,该监督模型在两个位置上都使用了交叉熵损失,目的是使两个位置上的总损失最小化。

如我们所见,优化是通过使用位置来完成的,评估是通过使用答案的文本内容来完成的。 因此,优化和评估方法之间存在脱节。 由于这种脱节,许多文本上相似的答案由于其在其他位置的存在而受到惩罚,就好像它们是不正确的答案一样,这与真实情况答案的位置不同。

为了解决这个问题,熊等人发表了他们的研究《DCN+:问答的混合目标和深度残差协作》,*提出了使用混合目标函数的方法,该函数是交叉熵损失和自我批判策略学习的组合。 这个混合目标使用从单词重叠中获得的奖励来解决现有模型中评估与优化之间的脱节问题。

提出的新框架对于需要捕获长期依存关系的长问题表现更好,能够获得 75.1% 的精确匹配准确率和 83.1% 的 F1 分数的强大结果,而集成模型获得 78.9% 的精确匹配准确率和 86.0% F1 分数。

因此,混合目标的方法提供了两个好处:

  • 强化学习目标还鼓励在文字上相似的答案
  • 交叉熵通过鼓励更正确的部署轨迹来帮助策略学习

除了混合训练目标之外,还通过使用深度残差共同注意编码器建立输入的更好表示,对现有的动态共同注意注意网络进行了改进(Xiong 等人,2017 年)。

来自 Stanford 问答数据集SQuAD)(Rajpurkar 等人)的一些示例如下:

Context/Passage 1:
Nikola Tesla (Serbian Cyrillic: Никола Тесла; 10 July 1856 – 7 January 1943) was a Serbian American inventor, electrical engineer, mechanical engineer, physicist, and futurist best known for his contributions to the design of the modern alternating current (AC) electricity supply system.
Questions and Answers:
In what year was Nikola Tesla born?
Ground Truth Answer: 1856

What was Nikola Tesla's ethnicity?
Ground Truth Answer: Serbian

What does AC stand for?
Ground Truth Answer: alternating current

Context/Passage 2:
Tesla went on to pursue his ideas of wireless lighting and electricity distribution in his high-voltage, high-frequency power experiments in New York and Colorado Springs, and made early (1893) pronouncements on the possibility of wireless communication with his devices. He tried to put these ideas to practical use in an ill-fated attempt at intercontinental wireless transmission, his unfinished Wardenclyffe Tower project. In his lab he also conducted a range of experiments with mechanical oscillators/generators, electrical discharge tubes, and early X-ray imaging. He also built a wireless controlled boat, one of the first ever exhibited.
Questions and Answers: What were some of Tesla's experiments?
Ground Truth Answer: mechanical oscillators/generators, electrical discharge tubes, and early X-ray imaging

Other than New York where did Tesla conduct experiments?
Ground Truth Answer: Colorado Springs 

现有的最新动态共同注意网络DCN)将上下文/段落和问题视为两个不同的输入序列,并输出输入上下文中的答案范围的开始和结束位置。 下图简要概述了 DCN:

动态共同注意网络(由 Xiong 等人撰写,2017 年)

在下一部分中,我们将简要介绍该方法,以了解如何使用强化学习来创建最新的问题回答模型。

用于问答的混合目标和和深度残差共同注意

本研究中提出的框架基于 DCN 模型(请参见上图),该模型由共同注意编码器和动态解码器指针组成。 编码器分别对问题和文档上下文进行编码,然后通过覆盖范围形成二者的协作表示,然后解码器根据覆盖范围输出开始和结束位置估计。

在 DCN+ 的新框架中,原始 DCN 框架引入了两个新更改。 它们如下:

  • 添加深度残差共同注意编码器
  • 混合训练目标函数,是最大似然交叉熵损失函数和强化学习的奖励函数的组合

深度残差共同注意编码器

由于原始的 DCN 仅具有一个单层涂布编码器,因此形成输入序列的复杂表示的能力也受到限制。 因此,对共同注意保持编码器进行了两种修改。 它们如下:

  • 通过堆叠许多共同注意增强层来修改共同注意增强编码器,以便网络能够创建更好的复杂表示形式
  • 合并每一层的所有共同注意输出,以减少信号路径长度:

深度残差共同注意编码器,由 Xiong 等人发表在《DCN+:问答的混合目标和深度残差共同注意》

使用自我批评性策略学习的混合目标

DCN 在答案的开始位置创建概率分布,并在答案的结束位置创建单独的概率分布。 在每个解码时间步长,模型会汇总每个位置的交叉熵损失。 问答任务包括两个评估指标。 它们如下:

  • 完全匹配:一个二进制值,指示模型输出的答案范围与真实情况答案范围具有精确的字符串匹配
  • F1 分数:该值用于量化模型在预测答案范围和真实情况答案范围之间的单词重叠程度

根据原始的 DCN 框架,目标函数和评估指标是不连贯的,因此,对确切的匹配给予了极大的鼓励。 举例来说,有两个答案范围AB,但它们都不与真实情况答案范围匹配,但是A具有完全匹配的字符串,而B没有字符串匹配。 然后,在这种情况下,尽管根据先前的完全匹配指标,A是正确的输出,但仅交叉熵损失的旧客观方法将同等地惩罚AB和 F1 得分。

如果我们检查 F1 分数,则A的量度显示单词在跨度A中重叠且具有真实答案范围,但答案B则不是这种情况。 因此,F1 分数与自关键策略梯度算法一起用作训练的奖励函数。

总结

在本章中,我们学习了强化学习如何破坏 NLP 的领域。 我们研究了在 NLP 中使用强化学习的原因。 我们涵盖了 NLP 中的两个主要应用领域,即文本摘要和问题回答,并了解了在现有模型中如何实现强化学习框架以获得最新结果的基础。 NLP 中还有其他实现了强化学习的应用领域,例如对话生成和机器翻译(讨论它们不在本书的范围之内)。

这使我们结束了深度强化学习的惊人旅程。 我们通过了解概念开始了基础知识,然后使用 TensorFlow 和 OpenAI Gym 实现了这些概念,然后遍历了很酷的研究领域,在这些领域中正在实现核心强化学习。 我希望旅途很有趣,我们能够建立最好的基础。

十五、强化学习的其他主题

在本附录中,我们将介绍一些超出本书范围的主题。 但是,我们将简要提及它们,并以外部链接结尾这些主题,以供您进一步探索。 本书已经涵盖了深度强化学习理论以及活跃研究领域的大多数高级主题。

连续动作空间算法

深度强化学习拓扑中有许多连续的动作空间算法。 我们在第 4 章,“策略梯度”中较早介绍的其中一些主要是随机策略梯度和随机演员评论家算法。 随机策略梯度与许多问题相关,例如由于观察值和奖励分配的连续变化而导致的非平稳数据导致难以选择步长,其中差的步长会对策略网络参数的学习产生不利影响。 因此,需要一种在训练策略网络参数时可以限制此策略搜索空间并避免不良步骤的方法。

在这里,我们将尝试介绍一些高级连续动作空间算法:

  • 信任区域策略优化
  • 确定性策略梯度

信任区域策略优化

信任区域策略优化TRPO)是一种用于优化策略的迭代方法。 TRPO 优化了大型非线性策略。 TRPO 通过对输出策略分布施加约束来限制策略搜索空间。 为此,对策略网络参数使用 KL 散度损失函数(D_max[KL](θ_old, θ))来惩罚这些参数。 新策略和旧策略之间的 KL 差异约束称为信任区域约束。 由于此约束,策略分布中不会发生大规模更改,从而导致策略网络尽早收敛。

TRPO 由 Schulman 等(2017)发布在名为《信任区域策略优化》的研究出版物中。 在这里,他们提到了一些实验,这些实验证明了 TRPO 在不同任务上的强大表现,例如学习模拟机器人游泳,玩 Atari 游戏等等。 为了详细研究 TRPO,请访问出版物的 arXiv 链接

确定性策略梯度

确定性策略梯度由 Silver 等人提出在名为《确定性策略梯度算法》的出版物中。 在连续行动空间中,用贪婪方法改进策略变得困难,并且需要全局优化。 因此,最好按以下方向在Q函数的梯度方向上更新策略网络参数:

其中,μ[θ](s)是确定性策略,α是学习率,θ表示策略网络参数。 通过应用链式规则,策略改进可以显示如下:

可以将先前的更新规则合并到策略网络中,在该策略网络中使用随机梯度上升来更新参数。 这可以通过确定性的行为者批判方法来实现,其中批评者估计动作值函数,而行为者从批评者获得其梯度以更新其参数。 如 Silver 等人在《确定性策略梯度算法》中所述。 在实验之后,他们能够成功得出结论,确定性的策略梯度比随机的梯度更有效率。 此外,确定性演员评论家的表现优于随机行动者。 有关此主题的详细说明超出了本书的范围。 因此,请转到前面提到的研究出版物链接。

NLP 序列模型中的评分机制

两种评分机制用于评估第 14 章“NLP 中的深度强化学习”中提到的方法,如下所示:

BLUE

在机器翻译,文本摘要,图像字幕等中使用的 NLP 顺序模型中的最大挑战之一是评估的适当度量。

假设您的用例是机器翻译; 您有一个德语短语,并且有多个英语翻译。 他们看起来都不错。 因此,如果有多个同样好的答案,您如何评估机器翻译系统? 这不同于图像识别,在图像识别中,目标只有一个正确答案,而没有多个同样好的正确答案。

例如:

  • 德语句子Die Katze ist auf der Matte

先前德语句子的多参考人为翻译如下:

The cat is on the mat
There is a cat on the mat

如果目标只是一个正确的答案,那么准确率的测量很容易,但是如果存在多个同样正确的可能性,那么在这种情况下如何测量准确率? 在本节中,我们将研究 BLEU 分数,BLEU 分数是一种评估指标,用于在出现多个同等正确答案的情况下,测量准确率。

什么是 BLEU 分数,它的作用是什么?

BLEU 分数由 Papineni 等(2002)发表在他们的研究出版物《BLEU:一种自动评估机器翻译的方法》中。 BLEU 代表双语评估计划。 对于给定的机器生成的输出(例如,机器翻译为翻译或文本摘要为摘要),分数可衡量输出的优劣,即,机器生成的输出与任何一个可能的人工生成参考有多接近(可能的实际输出)。 因此,输出文本离任何人工生成的参考越近,BLEU 得分就越高。

BLEU 分数背后的动机是设计一种度量标准,该度量标准可以像人类评估者一样相对于人类产生的引用来评估机器产生的文本。 BLEU 评分背后的直觉是,它考虑了机器生成的输出,并探讨了这些单词是否存在于多个人工生成的引用中的至少一种。

让我们考虑以下示例:

  • 输入德语文本Der Hund ist unter der Decke

假设我们有两个人为产生的参考,如下所示:

  • 参考 1The dog is under the blanket
  • 参考 2There is a dog under the blanket

并说我们的机器翻译生成了可怕的输出,即the the the the the the

因此,精度由以下公式给出:

因此,以下情况适用:

由于the在输出中出现了六次,而the的每个出现在至少一篇参考中,因此精度为 1.0。 出现此问题的原因是精度的基本定义,即定义为实际输出(参考)中出现的预测输出的分数。 因此,在预测输出中出现的the是唯一的文本,由于它出现在参考中,因此精度为 1.0。

因此,对精度的定义进行了修改,以得到修改后的公式,在该公式中放置了片段计数。 此处,片段计数是单词在任何参考中出现的最大次数。 因此,修改的精度定义为单词在任何参考中出现的最大次数除以该单词在机器生成的输出中出现的总数。

对于前面的示例,修改后的精度为:

到现在为止,我们已经以孤立的形式(即,字母组合形式)考虑了每个单词。 在 BLEU 分数中,您还希望成对看待单词,而不仅仅是孤立地看。 让我们尝试使用二元语法方法来计算 BLEU 分数,其中二元语法表示一对单词彼此相邻出现。

让我们考虑以下示例:

  • 输入德语文本Der Hund ist unter der Decke

假设我们有两个人工生成的引用,如下所示:

  • 参考 1The dog is under the blanket
  • 参考 2There is a dog under the blanket

机器生成的输出The dog the dog the dog under the blanket

机器生成的输出中的二元组 计数 片段计数(任何参考中的二元组的最大数量)
the dog 3 1
dog the 2 0
dog under 1 0
under the 1 1
the blanket 1 1

因此,修改后的二元语法精度将为二元语法的片段计数与二元语法计数的总和之比,即:

因此,我们可以为单字组,二元组和 N 元组创建以下精度公式,如下所示:

  • p₁为精确度,表示:

  • p₂为二元语法的精度,其中:

  • pₙ为 N 元组的精度,其中:

以单字,双字或什至任何 N 元组计算的改进精度,使您可以测量机器生成的输出文本与人工生成的引用相似的程度。 如果机器生成的文本与人工生成的引用中的任何一个完全相似,则:

让我们将所有的i分数放在一起,以计算机器生成的输出的最终 BLEU 分数。 由于pₙ仅是 N 元组的 BLEU 分数(即,改进的 N 元组精度),因此组合的 BLEU 分数为n[max] = N由以下公式给出:

BP 称为简短惩罚。 如果机器生成的输出非常短,那么这个代价就会出现。 这是因为,在输出序列短的情况下,其中出现的大多数单词很有可能出现在人工生成的参考中。 因此,简洁性惩罚是一种调整因素,当该机器生成的文本短于该输入的最短人类生成的输出参考时,它便会对其进行惩罚。

简短惩罚BP)由以下公式给出:

哪里:

len(MO)为机器生成的输出的长度

s[len](REF)为最短的人工生成参考输出的长度

有关更多详细信息,请检查 Papineni 等人(2002)关于 BLEU 分数的出版物

ROUGE

ROUGE 代表针对召回评估的面向召回的本科。 它也是评估 NLP 中的顺序模型(特别是自动文本摘要和机器翻译)的度量。 CY Lin(2004)在研究出版物《ROUGE:摘要自动评估包》中提出了 ROUG。

ROUGE 还可以通过将机器生成的输出(自动摘要或翻译)与一组人工生成的参考进行比较来工作。

让我们考虑以下示例:

  • 机器生成的输出the dog was found under the bed
  • 人为产生的参考物the dog was under the bed

因此,在 ROUGE 上下文中的精度和召回率如下所示:

因此,召回率= 6/6 = 1.0

如果召回率为 1.0,则意味着人工生成的参考中的所有单词均由机器生成的输出捕获。 可能会出现机器生成的输出过长的情况。 因此,在计算召回率时,较长的机器生成的输出很可能覆盖大多数人工生成的参考词。 结果,精度得以提高,其计算方法如下所示:

因此,精度(对于前面的示例)= 6/7 = 0.86

现在,如果机器生成的输出为the big black dog was found under the big round bed,那么,

这表明机器生成的输出不合适,因为它包含大量不必要的单词。 因此,我们可以很容易地发现仅召回是不够的,因此召回率和精度应同时用于评估。 因此,在以下情况下,作为召回率和精度的谐波均值计算的 F1 分数是一种很好的评估指标:

  • ROUGE-1 表示机器生成的输出和人工生成的引用之间的字母组合的重叠
  • ROUGE-2 表示机器生成的输出和人工生成的引用之间的二元语法重叠

通过以下示例,让我们更多地了解 ROUGE-2:

  • 机器生成的输出the dog was found under the bed
  • 人为产生的参考物the dog was under the bed

机器生成的输出the dog was found under the bed的二元组为:

"the cat"

"cat was"

"was found"

"found under"

"under the"

"the bed"

人类产生的参考the dog was under the bed:的二元组为:

"the dog"

"dog was"

"was under"

"under the"

"the bed"

因此:

因此,ROUGE-2_procision显示该机器生成的二元语法的 67% 与人类生成的参考重叠。

本附录涵盖了 NLP 中顺序模型中 ROUGE 评分的基本概述。 有关 ROUGE-N,ROUGE-L 和 ROUGE-S 的更多详细信息,请浏览《ROUGE:自动摘要评估包》,作者为 CY Lin。

总结

作为附录的一部分,我们涵盖了深度强化学习拓扑的连续动作空间算法的基本概述,其中简要介绍了信任区域策略优化和确定性策略梯度。 我们还了解到 BLEU 和 ROUGE 分数被积极用于基于 NLP 的顺序模型中的评估。

最后,我想说的是,随着将开发出更多的算法,深度强化学习仍然是一个新主题。 但是,最有助于您理解和探索那些尚未发现的未来算法的最重要的事情,将是牢固掌握本书所涵盖的基础知识。

posted @ 2026-03-25 10:36  布客飞龙II  阅读(0)  评论(0)    收藏  举报