TowardsDataScience-博客中文翻译-2019-五十五-
TowardsDataScience 博客中文翻译 2019(五十五)
推荐系统系列之三:将改变游戏的深度推荐系统的 6 个研究方向
RecSys 系列
推荐社区的研究方向
更新: 本文是我探索学术界和工业界推荐系统系列文章的一部分。查看完整系列: 第一部分 , 第二部分 , 第三部分 , 第四部分 , 第五部分 和
简介
在过去的几年里,我们已经看到推荐领域发生了巨大的变化,从传统的矩阵分解算法(2009 年 c.f. Netflix 奖)转向了最先进的基于深度学习的方法。目前,我正在一家做视频推荐的初创公司实习,我可以清楚地看到这种运动背后的主要原因:
- 来自用户的信号(例如视图)不是独立分布的观察,而是可以表示为动作序列。使用递归神经网络(RNN)有效地理解和建模这些序列是提高视频推荐系统准确性的关键。
- 视频通常由特征(视频的类别、描述标签)来表征,这些特征可用于导出视频之间的相似性。此外,手表的背景(设备、国家……)对于定制推荐至关重要。在深度学习模型中使用它们作为特征实现了更快的收敛,而且在给定视频没有用户信号可用的冷启动机制中也有帮助。
- 反馈(观看)只能在给定的视频上观察到,当视频已经显示给用户时(强盗反馈)。因此,我不知道如果我为某个用户选择了其他视频会发生什么(反事实推理)。在这种类型的环境中学习需要特殊的范例,例如偏离策略学习或反事实学习,这在强化学习中已经被大量使用。最近,一些作品一直在研究这些环境中基于“深度学习”的模型。
在这篇文章和接下来的文章中,我将介绍推荐系统的创建和训练,因为我目前正在做这个主题的硕士论文。在第 1 部分中,我提供了推荐系统的高层次概述,它们是如何构建的,以及它们如何被用来改善跨行业的业务。在第 2 部分中,我提供了一个关于这些模型的优势和应用场景的正在进行的研究计划的很好的回顾。第 3 部分将通过提出几个可能与推荐系统学者社区相关的研究方向来解决使用基于深度学习的推荐模型的局限性。
弊端
使用深度神经网络进行推荐有哪些弊端?
根据我的研究,有 3 个主要问题:
(1)深度学习的一个常见异议是隐藏的权重和激活难以解释。众所周知,深度学习的行为像黑盒一样,提供可解释的预测似乎是一项非常具有挑战性的任务。
(2)深度学习还需要大量数据来完全支持其丰富的参数化。与视觉和语言等其他领域相比,在推荐系统研究的背景下很容易收集大量数据。
(3)深度学习需要大范围的超参数调优,其中是一般机器学习的通病。
为了解决这些问题,最近出现了各种各样的研究计划,在这篇文章中,我将介绍其中的 6 个。
1 —评估方法
在阅读了 RecSys 会议上最近发表的大量文献后,我注意到基线模型和评估数据集的选择相当随意,取决于作者。这方面的一个大问题是分数报告中明显的不一致性,这使得新模型的相对基准极具挑战性。
为什么没有 MNIST 或者 ImageNet 等同于推荐系统?最常用的数据集好像是movie lens;然而,即使在这种情况下,训练和测试分离也是任意的。此外,无法控制推荐系统结果中测试样本的难度(随机、按时间顺序等)。)如果没有设计测试集的适当标准,估计和测量该领域的进展将是一个挑战。
2 —大规模设置的可扩展性
可扩展性对于推荐系统在行业环境中的有用性至关重要。为此,通过探索以下问题,推荐模型肯定会更有效:
- 针对非静态和流式数据(大量传入用户和项目)的增量学习
- 高维张量和多媒体数据源的计算效率
- 随着模型参数呈指数增长,平衡复杂性和可伸缩性
一个有前途的研究领域是使用压缩技术来压缩高维输入数据的嵌入空间,这样可以减少模型学习过程中的计算时间。另一个有前途的方法是提取知识来学习推荐系统中用于推理的紧凑模型。关键的概念是训练一个小的学生模型,从一个大的教师模型中吸收知识。
3 —多任务学习
多任务学习是一种同时解决多个学习任务,同时利用不同任务之间的共性和差异的方法。它已经成功地用于许多计算机视觉和自然语言处理任务。最近的一些作品也将这种技术应用于推荐系统:
- 询问 GRU:深度文本推荐的多任务学习提出了一种利用深度递归神经网络将文本序列编码为潜在向量的方法,该潜在向量是在协同过滤任务上端到端训练的特定门控递归单元(GRUs)。对于科学论文推荐的任务,这产生了具有显著更高准确度的模型。
- 神经生存推荐器提出了一个基于长短期记忆的模型,以估计用户何时会返回网站,以及他们未来的收听行为。这样做的目的是解决及时推荐的问题,即在正确的时间推荐正确的项目。它使用生存分析中的工具进行返回时间预测,并使用指数族进行未来活动分析。
- 为推荐生成抽象提示的神经评分回归提出了一个基于深度学习的框架,名为 NRT,它可以同时预测精确评分并生成具有良好语言质量的抽象提示,模拟用户对电子商务网站的体验和感受。对于抽象提示生成,使用门控递归神经网络将用户和项目的潜在表示“翻译”成简洁的句子。
- 扩展的自动编码器推荐框架及其在电影推荐中的应用采用堆叠式自动编码器提取输入的特征,然后重构输入进行推荐。然后在框架中融合项目和用户的边信息,并使用基于 Huber 函数的正则化来提高推荐性能。
使用基于多任务学习的深度神经网络有许多优点。它有助于通过概括共享的隐藏表示来防止过度拟合。它为解释建议提供了可解释的输出。它隐式地增加了数据,从而缓解了稀疏性问题。最后,我们可以部署跨领域推荐的多任务学习,每个特定的任务为每个领域生成推荐(见下一节)。
4 —域适配
单领域推荐系统只关注一个领域,忽略了用户在其他领域的兴趣,大大加剧了稀疏性和冷启动问题。这些问题的一个切实可行的解决方案是应用领域适应技术,其中模型由从源领域学到的知识来辅助。在这种情况下,一个非常受欢迎和研究充分的主题是迁移学习,它可以通过使用从其他领域转移的知识来改进一个领域的学习任务。一些现有的工作表明了深度学习在捕捉不同领域的共性和差异以及在跨领域平台上生成更好的建议方面的功效。
- 在“推荐系统中跨域用户建模的多视图深度学习方法中,微软研究人员提出了一种基于内容的推荐系统,以解决推荐质量和系统可扩展性两方面的问题。他们使用深度学习方法将用户和项目映射到潜在空间,在该空间中,用户和他们偏好的项目之间的相似性最大化,根据他们的 web 浏览历史和搜索查询,使用丰富的功能集来表示用户。他们还展示了如何通过减少输入的维度和训练数据的数量来使这种基于丰富特征的用户表示可扩展。将不同领域组合到单个学习模型中有助于提高所有领域的推荐质量,以及具有更紧凑和语义更丰富的用户潜在特征向量。
- 在“一个用于跨领域推荐系统的内容增强的协同过滤神经网络”中,微软研究人员提出了一个名为 CCCFNet 的跨领域推荐系统,它可以在一个统一的框架中结合协同过滤和基于内容的过滤,从而克服数据稀疏性问题。
在我看来,这是一个很有前途的研究方向,但对于推荐系统的研究来说,仍然没有得到充分的开发。
5 —可解释性和可解释性
反对深度学习的一个常见论点是,神经网络高度不可解释。因此,基于深度神经网络做出可解释的推荐似乎非常具有挑战性。可解释的深度学习的重要性主要体现在两个方面。
- 第一是向用户做出可解释的预测,让他们理解网络推荐背后的因素。用于评论评级预测的具有双重局部和全局注意力的可解释卷积神经网络提出使用具有双重局部和全局注意力的卷积神经网络(CNN)对用户偏好和项目属性进行建模,这是由 CNN 在提取复杂特征方面的优势所激发的。通过使用来自用户的聚合评论文本和项目的聚合评论文本,他们的模型可以学习每个用户和每个项目的独特特征(嵌入)。这些特征然后被用于预测评级。
- 第二是通过探查权重和激活来了解更多关于模型的信息。潜在关系度量学习通过基于记忆的注意力进行协作排序提出了一种称为潜在关系度量学习的模型,该模型可以学习描述每个用户-项目交互的潜在关系。这有助于减轻现有度量学习方法的潜在几何不灵活性。这不仅实现了更好的性能,还实现了更大程度的建模能力,允许他们的模型扩展到更大数量的交互。
最近,注意力模型在缓解神经模型的不可解释性方面做出了很大贡献。例如,注意力因子分解机器通过神经注意力网络从数据中学习每个特征交互的重要性。注意力权重不仅给出了关于模型内部工作的见解,还能够向用户提供可解释的结果。一般来说,注意力模型既可以提高性能,又可以提供简洁的解释,这进一步推动了它在基于深度学习的推荐系统中的使用。
值得注意的是,模型的可解释性和可解释性强烈依赖于应用领域和内容信息的使用。因此,一个有前途的研究方向将是设计更好的注意机制,例如——会话或生成解释。
6 —联合学习框架
做出准确的推荐,需要对物品特性以及用户的实际需求和喜好有深刻的理解。例如,上下文信息可以根据用户的环境和周围环境定制服务和产品,这有助于缓解冷启动问题。隐式反馈可以表明用户的隐式意图,并补充显式反馈(这是一项资源要求很高的任务)。这种隐式反馈可以从社交媒体和物理世界中收集,深度学习可以处理这些数据源,同时带来更多机会来推荐具有非结构化数据(如文本、视觉、音频和视频特征)的多样化项目。
此外,深度学习可以极大地帮助自动化特征工程,这目前需要在推荐研究社区中进行人工干预。还有一个额外的优势是,在野外从自由文本、图像或数据中学习表示,而不必设计复杂的特征工程管道。
最近一个叫做联合表示学习的框架能够学习用户和物品的多模态表示。在该框架中,采用每种类型的信息源(评论文本、产品图像、数字评级等)来基于可用的(深度)表示学习架构学习相应的用户和项目表示。来自不同来源的表示与一个额外的层集成,以获得用户和项目的联合表示。最后,使用成对学习将每个源和联合表示作为一个整体来训练,以对前 N 个推荐进行排序。通过将用户和项目表示为离线嵌入,并使用简单的向量乘法进行在线排名得分计算,与学习复杂预测网络进行在线计算的推荐的其他深度学习方法相比,JRL 还具有快速在线预测的优势。因此,另一个有前途的研究方向是在端到端的管道中设计更好的归纳偏差,这可以对不同模态的数据进行推理,以获得更好的推荐性能。
结论
深度学习在计算机科学的所有子领域都变得越来越流行,例如自然语言处理、图像和视频处理、计算机视觉和数据挖掘,这是一个值得注意的现象,因为以前没有这样一种通用的方法用于解决不同类型的计算问题。通过深度学习技术的这一方面,它们不仅能够在许多领域中修复复杂的问题,而且还形成了这些研究领域的共享词汇和共同基础。深度学习方法甚至有助于这些子领域相互合作,而在过去,由于所用技术的多样性和复杂性,这有点成问题。
尽管深度学习在推荐系统领域的应用有望取得重大和令人鼓舞的成果,但可解释性和可扩展性等挑战仍有待改进,并保证未来的工作。就个人而言,我对用于推荐商品的领域适应技术非常感兴趣,并希望看到 RecSys 的 ImageNet 时刻。请继续关注本系列未来的博客文章,深入了解这些模型如何工作的本质细节。
现在继续上 推荐系统第四部 !
如果你想关注我在推荐系统、深度学习和数据科学新闻方面的工作,你可以查看我的Medium和GitHub,以及 https://jameskle.com/**的其他项目。也可以在 推特 , 直接发邮件给我 ,或者 在 LinkedIn 上找我。 注册我的简讯 就在你的收件箱里接收我关于数据科学、机器学习和人工智能的最新想法吧!**
具有强化学习的推荐系统
哈佛数据科学顶点项目,2019 年秋季
团队成员:赵小菲,,钱丰
对于 Spotify 等服务提供商来说,推荐系统可能是一项至关重要的竞争优势,因为 Spotify 主要通过用户订阅来发展业务。准确的推荐有助于改善用户体验,增强客户忠诚度。
传统的推荐方法包括使用监督学习对用户-项目交互进行建模,如分类、基于记忆的用户历史内容过滤等等。这些想法忽略了连续时间步的依赖性。受强化学习在其他领域(如玩 Atari 游戏)的进展的启发,我们应用了一种最先进的模型,即深度确定性梯度策略(DDPG),将音乐推荐建模为一个顺序决策过程。在这个设置中,DDPG 学习者的动作是从一个巨大的库中选择的一首歌曲。通过使用一组连续特征来表示每首歌曲,并随后将动作空间从离散扩展到连续,我们的代理成功地扩大了它可以容纳的候选歌曲的数量,同时保持了令人满意的推荐准确性和多样性。
数据
我们使用“音乐流会话数据集”(MSSD) ,最初是由 Spotify 为一项比赛发布的。数据集包含收听会话数据和歌曲特征的查找表。
数据结构
上面是我们现有数据的结构图。我们有两个数据文件:一个文件包含多行会话,另一个文件包含多行轨迹要素。曲目是歌曲,会话是单个用户收听的一系列曲目。Spotify 将会话的最大长度限制为 20。
在会话内部,记录轨迹之间和轨迹内部的动作。曲目之间的动作包括:skip_very_briefly、skip_briefly、mostly _ played _ before _ skip、no_skip,指示用户从一个曲目转移到下一个曲目的模式。一首歌内的动作主要有 move_forward、move_backward、no_move,表示用户在听一首曲目时的行为;以及指示用户暂停行为的 no_pause_before_play、short_pause_before_play、long_pause_before_play。上述响应可以被解释为每个音轨上的用户偏好。
我们也有每个曲目的特征数据,这些特征由 Spotify 通过手动或自动方式给出。这些特征包括声音、节拍、舞蹈性等。并且在[0,1]之间变化。我们可以将这些特性整合到我们的模型中。
数据采样
MSSD 是一个巨大的数据集,有超过 2000 万首歌曲和 1700 万个会话,包括大约 600 GB 的数据。为了使我们的模型适应这个数据集,我们选取了歌曲和会话的子集,如下所述。
要选择 MSSD 的一个子集,我们需要执行以下操作:首先,我们对会话数据进行采样,然后,我们对会话跟踪数据进行采样。在原始数据中,我们决定从数据中抽取 10 万个会话作为样本。由于数据被分成 10 个大小相似的 zip 文件,我们需要从每个 zip 文件中抽取 1 万个会话作为样本。每个 zip 文件由 N 个数据文件组成,因此我们需要从每个数据文件中抽取 10k/N 千个会话。由于每个数据文件包含不同数量的会话,我们需要以不同的概率从每个数据文件中进行采样。例如,如果数据文件$ f1 \(中有\)M$个会话,我们以 10k/NM 的概率随机接受文件 f1 中的每个会话。
在对所有会话进行采样后,我们需要找出出现在采样数据中的所有轨迹。如果数据的大小很小,这可能很容易:我们可以使用一组数据结构来找到一组轨道 id。然而,由于数据的大小太大,无法存储在内存中,我们决定使用数据库(Macbook Air 2014 上的 Mysql)来让数据库为我们维护树结构。使用数据库,我们可以很容易地找到我们需要的曲目。
我们从 300 多个数据文件中统一采样,并将数据减少到 106,375 个会话(376MB)和 281,185 个磁道(167MB)。
模型概述
强化学习模型有以下组成部分:主体、环境、状态、奖励函数、价值函数和政策。为了简化问题,我们假设一个假想的用户,他的经验来自所有实际用户。我们的推荐器模型将成为系统的代理,为这个假设的用户处理歌曲,跳过/不跳过推荐。用户表现为系统的环境,根据系统的状态响应系统的建议。用户反馈决定了我们的奖励,即只有用户不跳过才得一分。行动的代理人是宋推荐的。我们的状态被定义为过去 5 个步骤的歌曲特征和相应的用户反应,不包括当前步骤。所以,反馈和行动一起给了我们下一个状态。代理的目标是学习一个策略,在 15 个步骤中最大化累积奖励。我们将预测的长度设置为 15,以避免冷启动,也就是说,在没有足够的历史记录时进行预测,假设我们的原始会话长度为 20,历史记录长度为 5。
更正式地说,数学定义如下:
Model Pipeline
自动编码器
概观
我们的数据首先通过一个由两部分组成的自动编码器:一个数字压缩器和一个时间压缩器。每个数据点最初是 5×21,对应于 5 首歌曲的 20 个歌曲特征和观察到的用户动作(跳过/不跳过)。我们用前馈自动编码器压缩 20 首歌曲特征,该编码器将输入转换成 5×8。我们在最后将用户响应连接起来,得到这个 5 x 9。然后,我们将该潜在表示输入到 LSTM 自动编码器,该编码器沿着时间维度压缩成 1×9 维度的单个向量。
履行
在训练过程中,我们首先构建一个自动编码器,并在歌曲特征数据集上对其进行训练。
然后我们固定编码层和解码层,并用 LSTM 时间压缩器连接它们。编码层负责预处理数字特征,解码层负责将时间解码器的输出扩展到最大长度。
时间压缩器尝试将 5 x 9 输入压缩为 1 x 9,然后解码为 5 x 9。为了适应混合型数据,我们使用两个时间解码器,一个使用 MSE 损失来恢复数值,另一个使用交叉熵损失来恢复二进制用户跳过行为。最终损失是这两个损失的线性组合,分配的权重影响这两个任务中的模型性能。尽管使用了两个解码器,它们共享一个长度为 9 的潜在表示作为输入。在预测过程中,增加了一个步骤,即数值解码器获取时间解码器的输出,并恢复数值特征的原始维数。
可能的延期
以前的“数字压缩器”不是只压缩数字特征,而是压缩歌曲特征和二进制用户响应,为了与“数字压缩器”相区别,我们称之为“组合压缩器”。通过从我们的时间压缩器中释放压缩分类响应的负担,可以进一步改进这种结构。在这个项目中,我们必须将组合压缩器与时间压缩器连接起来。
结果
Table 1: Results of the autoencoders
我们的数字特征被标准化为在 0 到 1 之间。从 1×9 潜在值重构 5×20 的 MSE 是 0.0111,大约是特征范围的 1%。重构二元用户行为的准确率为 88.89%。训练数值压缩器的 MSE 是 0.0016。所有统计数据都是在测试集上计算的。最后两行是实验组合压缩机的性能统计。实验性组合压缩器具有在测试集上检索二进制用户跳过行为一次的准确度,以及在 0.0064 处略微增加的数值重构 MSE。
强化学习
结构
- 状态:时间压缩器的潜在向量。长度为 9 的状态包含前五首歌曲的信息和相应的用户响应。
- 动作:数值压缩器的潜在向量。动作是推荐歌曲。为了降低维数,我们使用长度为 8 的歌曲特征的潜在表示。
- 奖励:不跳概率和推荐多样性之和。
- 代理:策略功能和 Q 功能。
环境
当给定一对状态和动作时,环境理应回报。然而,在这个问题中,我们无法观察到实时的用户响应。我们要做的是使用现有的数据来估计跳过/不跳过行为。
深度确定性政策梯度
DDPG(Deep Deterministic Policy Gradient)是深度确定性政策梯度(Deep Deterministic Policy Gradient)的缩写,是一种无模型的政策外行动者批评算法,结合了 DPG 和 DQN。最初的 DQN 在离散空间中工作,DDPG 在学习确定性政策的同时,用演员-评论家框架将其扩展到连续行动空间。
该算法中有四个神经网络:演员、评论家、演员目标和评论家目标。行动者网络学习策略函数,而批评家网络近似 Q 函数。
结果
由于我们的模型需要前五首歌曲的信息,代理将为每个会话提供 15 个推荐。因此我们每集跑 15 步。
推荐系统可以从我们截断的音乐会话中累积的最高分数是 15。不跳过行为占据了整个数据的 34%,相当于基准分数 5 左右。正如我们从左图中看到的,在仅仅几百集的训练中,我们的代理达到了大约 11 的分数,展示了比基准好得多的性能。右边是多样性得分。如果当前动作和前一个动作之间的距离超过某个阈值(0.4 倍标准差),我们得到的多样性得分为 1,否则为 0。这是为每一步计算的,因此最高分也是 15。从剧情可以看出,一开始我们的经纪人倾向于推荐类似的歌曲。但在大约 300 集之后,它学会了考虑推荐的多样性。
结论
在这个项目中,我们成功地使用强化学习来捕捉用户-歌曲交互以及当前和过去决策之间的时间依赖性。未来的研究可以通过放宽许多简化的假设来扩展我们的发现:首先,不是假设一个单一的假设用户,而是进行客户分层,并将这一变量纳入模型。第二,我们可以考虑自会话开始以来的完整用户历史,而不是在五点截断历史。此外,我们可以通过将实验组合压缩器连接到时间压缩器和下游 DDPG 代理来测试它是否优于当前模型。
在训练方面,由于计算资源和时间的限制,我们正在分别训练不同的模型组件。这将是一个好主意,训练模型端到端,使潜在的可能更适合强化学习任务。最后,在我们研究的基础上,可能最重要的改进是为强化学习代理提供一个真实的环境。我们当前的数据集高度偏向于跳过行为(未跳过率为 34%),可能无法反映真实的客户行为。因此,与使用数据集(600G)模拟环境不同,让模型投入生产的更好方法是招募一些参与者来测试他们对建议的反应。这样代理可以充分挖掘推荐空间,做出更可信的推荐。
承认
我们要向 Javier Zazo 致以最诚挚的谢意,他是我们的导师,强化学习方面的专家,也是我们的好朋友,他总是给我们提出宝贵的建议,鼓励我们继续前进。297R 研究项目的负责人 Pavlos Protopapas,使这一难忘的研究之旅成为可能的导师,以及 Spotify 高级研究员兼数据科学家 Aparna Kumar,一位出色的支持经理。
该研究项目隶属于 IACS 297R 研究项目。
原载于https://sophieyanzhao . github . io。
大规模推荐系统——让 Grab 的日常应用变得超级棒
这篇文章最初发表在这里作为 Grab 的工程博客的一部分。来看看我们更多的精彩作品吧。
Grab 是东南亚领先的 superapp ,提供高使用率的日常服务,如打车、送餐、支付等等。我们的目标是让人们更好地获得对他们来说重要的服务,提供更多价值和便利,因此我们一直在扩展我们的生态系统,以包括账单支付、酒店预订、旅行规划和视频,未来还会有更多。我们希望为我们的客户提供更好的服务——不仅仅是通过将 Grab 应用程序与有用的功能和服务打包,而是通过为他们每个人提供独一无二的个性化体验。
为了实现我们的超级应用雄心,我们与合作伙伴合作,他们和我们一样,希望帮助推动东南亚向前发展。
我们与合作伙伴的许多协作工作都可以在 Grab Feed 中看到。在这里,我们以聚合的方式传播关于 Grab 和我们合作伙伴的各种类型的内容,为整体用户体验增加价值。这是提要的样子:
Waiting for the next promo? Check the Feed.
Looking for news and entertainment? Check the Feed.
Want to know if it’s a good time to book a car? CHECK. THE. FEED.
随着我们继续向 Grab Feed 添加更多的卡片、服务和大量内容,我们的用户可能会发现更难找到与他们相关的信息。因此,我们努力确保我们的平台能够根据最适合用户的资料来区分和显示信息。这又回到了我们一直以来关注的焦点——客户,这也是我们如此重视为每个客户提供个性化的 Grab 体验的原因。
为了在像东南亚这样高度多样化的市场中脱颖而出,我们利用我们数据的深度来了解用户想要看到什么样的信息以及他们应该在什么时候看到这些信息。在本文中,我们将讨论 Grab Feed 的推荐逻辑和策略,以及它的未来路线图。
启动你的引擎
We offer a lot of great services.
我们在这里试图解决的问题被称为建议问题。简单来说,这个问题是关于推断消费者向其推荐内容和服务的偏好。在 Grab Feed 中,我们有不同类型的内容,我们希望向不同类型的消费者展示,我们的挑战是确保每个人都能获得高质量的内容。
为了解决这个问题,我们建立了一个推荐引擎,这是一个建议用户应该考虑消费的内容类型的系统。为了提出建议,我们需要了解三个因素:
- 用户。根据用户如何使用 Grab 应用,我们可以推断出很多关于用户的信息,例如他们乘坐的次数,他们喜欢点的食物类型,他们购买的电影优惠券,他们玩过的游戏,等等。这些信息让我们有机会更好地了解用户的偏好,使我们能够将他们的个人资料与相关和合适的内容相匹配。
- 物品。这些都是内容的特点。我们考虑内容的类型(例如视频、游戏、奖励)和可消费性(例如购买、观看、兑换)。我们还考虑其他元数据,如商家的营业时间、奖励积分和兴趣点的 GPS 坐标。
- 语境。这与用户消费我们内容的环境有关。它可以是一天中的时间、用户的位置或者当前的提要类别。
使用来自所有这些因素的信号,我们建立一个模型,向用户返回一组排序的卡片。在接下来的几节中会有更多的介绍。
了解我们的用户
从上述信号中解读用户偏好本身就是一个挑战。这里需要注意的是,我们一直处于实验状态。缓慢但肯定的是,我们正在继续微调如何测量内容偏好。也就是说,我们关注两个领域:
- 动作。我们坚信,并非所有的互动都是平等的。喜欢一张牌其实就代表你喜欢吗?你喜欢事物的速度和你的朋友一样吗?交易呢,那些更受青睐?提要为用户向平台提供反馈引入了许多方法。这些事件包括喜欢、点击、滑动、浏览、交易和行动号召。
根据不同的型号,我们可以采取稍微不同的方法。我们可以了解每个事件的重要性,并将它们聚合起来以获得预期的评级,或者我们可以预测每个事件的概率并据此进行排名。 - 新近度。旧的交互可能没有新的有用。提要是一个不断发展的产品,我们用户的偏好也是如此。未能衰减旧交互的权重会给我们提供对用户不再有意义的推荐。
优化体验
An overview of our recommendation strategy architecture
构建一个可行的推荐引擎需要几个阶段。通过迭代工作,我们能够创建一些核心推荐策略来产生最终模型,以确定内容与用户的相关性。我们将在这一部分讨论每个策略。
- 人气。这种策略被称为趋势推荐。我们在一个滚动的时间窗口内捕获在线点击流事件,并汇总这些事件,向用户展示在那个时间点每个人都喜欢什么。倾听群众通常是一种有效的策略,但是这种特殊的策略还可以通过为新的 feed 用户提供建议来帮助我们解决冷启动问题。
- 用户最爱。我们知道我们的用户有不同的品味,用户会比其他用户有更多的内容。在这个策略中,我们捕捉到了个人参与度和用户不断变化的偏好。
- 协同过滤。构建我们的日常超级应用的一个关键目标是让用户体验不同的服务。为了实现可发现性,我们研究相似的用户,以发现他们可能拥有的一组相似的偏好,然后我们可以使用这些偏好来指导我们向其他用户展示什么。
- 习惯性行为。有时用户只想做一件特定的事情,我们不希望他们只是为了做这件事而一直向下滚动。我们已经建立了习惯性的建议来解决这个问题。因此,如果用户总是在午餐时使用 feed 滚动食物选择,或者在周日早上瞥一眼乘车高峰(双关语),我们仍然会覆盖他们。
- 深度推荐。我们已经向您展示了我们如何使用订阅源数据来推动整个平台的使用。但是如何利用平台数据来驱动用户反馈行为呢?通过嵌入我们多个业务部门的用户活动,我们还能够利用这些数据和点击流来确定每个用户的内容偏好。
我们应用所有这些策略,通过选择或聚合来找出服务于用户的最佳推荐。这些决定是通过对用户的定期实验和研究来决定的。
总是在学习
我们不断学习和重新学习我们的用户。有很多方法可以理解行为,也有很多不同的方法可以整合不同的策略,因此我们一直在迭代这些方法,以在应用程序上提供最个性化的体验。
为了识别用户的偏好和最佳策略展示,我们利用我们的实验平台向不同的用户展示我们的推荐引擎的不同配置。为了监控我们的推荐质量,我们使用互动、点击率和参与率等在线指标和 Recall@Kand 归一化折扣累积收益(NDCG)等离线指标来衡量影响。
未来的工作
通过我们建立这个推荐平台的经验,我们意识到这个空间足够大,并且有很多可以持续建立的部分。为了不断改进,我们已经在以下项目上开展工作:
- 业务和技术指标的多目标优化
- 为超参数优化构建自动化管道
- 结合在线学习进行实时模型更新
- 面向用户个性化推荐策略的多臂土匪
- 替换系统,让利益相关者更好地理解系统
结论
Grab 是东南亚发展最快的公司之一。随着其业务、合作伙伴关系和产品的不断增长,超级应用的房地产问题只会越来越大。在本帖中,我们将讨论如何通过构建一个理解用户并为每个用户提供个性化体验的推荐系统来解决这个问题。这个系统(包括美国)继续从我们用户的反馈中学习和迭代,为他们提供最好的版本。
如果你有任何反馈、建议或其他好主意,请随时拨打justin.bolilia@grab.com联系我。有兴趣自己研究这些技术吗?查看我们的职业页面。
现实世界中的推荐系统
设计和构建推荐系统管道的过程概述。
选择太少不好,但选择太多会导致瘫痪
你听说过著名的 果酱实验 吗?2000 年,来自哥伦比亚和斯坦福大学的心理学家希娜·艾扬格和马克·莱珀根据他们的实地实验进行了一项研究。在平常的一天,消费者在当地食品市场的一家高档杂货店购物时,会看到一个展示 24 种果酱的试吃摊位。另一天,同一个摊位只展示了 6 种果酱。进行这个实验是为了判断哪个摊位会获得更多的销售,人们认为更多种类的果酱会吸引更多的人来到柜台,从而获得更多的生意。然而,观察到一个奇怪的现象。虽然有 24 个果酱的柜台产生了更多的兴趣,但与 6 个果酱的柜台相比,它们的销售转化率相当低(大约低 10 倍)。
Image Source: [The Paradox of Choice](http://The Paradox of Choice)
刚刚发生了什么?嗯,看起来很多选择看起来确实很吸引人,但是这种选择过多有时可能会给顾客带来困惑和阻碍。因此,即使在线商店可以获得数百万件商品,如果没有良好的推荐系统,这些选择可能弊大于利。
在我上一篇关于推荐系统的文章中,我们对推荐系统的非凡世界有一个概述。现在让我们更深入地了解一下它的体系结构和与推荐系统相关的各种术语。
推荐系统概述以及它们如何提供一种有效的定向营销形式。
towardsdatascience.com](/the-remarkable-world-of-recommender-systems-bff4b9cbe6a7)
术语和架构
让我们来看一些与推荐系统相关的重要术语。
项目/文件
这些是系统推荐的实体,如网飞上的电影、Youtube 上的视频和 Spotify 上的歌曲。
查询/上下文
系统利用一些信息来推荐上述项目,并且这些信息构成了查询。查询还可以是以下内容的组合:
- 用户信息,可能包括用户 id 或用户之前交互过的项目。
- 一些额外的环境,如用户的设备、用户的位置等。
嵌入
嵌入是将分类特征表示为连续值特征的一种方式。换句话说,嵌入是高维向量到称为嵌入空间的低维空间的平移。在这种情况下,要推荐的查询或项目必须映射到嵌入空间。许多推荐系统依赖于学习适当的 嵌入 查询和项目的表示。
这里有一个关于推荐系统的很好的资源,值得一读。我在上面总结了一下,但是你可以详细研究一下,它给出了一个整体的建议,尤其是从谷歌的角度。
机器学习中的推荐系统介绍
developers.google.com](https://developers.google.com/machine-learning/recommendation/)
架构概述
推荐系统的常见架构包括以下三个基本组件:
1.候选生成
这是推荐系统的第一阶段,从用户过去的活动中获取事件作为输入,并从大型语料库中检索一小部分(数百个)视频。主要有两种常见的候选生成方法:
- 基于内容的过滤
基于内容的过滤包括根据项目本身的属性推荐项目。系统推荐与用户过去喜欢的项目相似的项目。
- 协同过滤
协同过滤依赖于用户-项目交互,并且依赖于相似用户喜欢相似事物的概念,例如购买了这个项目的顾客也购买了这个项目。
2.得分
这构成了第二阶段,其中另一个模型进一步对候选人进行排名和评分,通常以 10 为标度。例如,在 Youtube 的情况下,排名网络通过使用描述视频和用户的丰富特征集根据期望的目标函数给每个视频分配分数来完成这项任务。得分最高的视频被呈现给用户,按照他们的得分排序。
3.重新排名
在第三阶段,系统考虑额外的约束,以确保多样性、新鲜度和公平性。例如,系统移除用户先前明确不喜欢的内容,并且还考虑网站上的任何新项目。
The overall structure of a typical recommendation system
相似性度量
如何识别一个项目与另一个项目是否相似?事实证明,基于内容的过滤技术和协作过滤技术都采用了某种相似性度量。让我们来看两个这样的指标。
考虑两部电影——电影 1 和电影 2 属于两种不同的类型。让我们在 2D 图上画出电影,如果电影不属于某个类型,则赋值 0,如果电影属于该类型,则赋值 1。
这里,电影 1(1,1)属于类型 1 和类型 2,而电影 2 只属于类型 2(1,0)。这些位置可以被认为是向量,这些向量之间的角度告诉我们很多关于它们的相似性。
余弦相似性
它是两个向量夹角的余弦值,similarity(movie1,movie2) = cos(movie1,movie2) = cos 45
约为 0.7。余弦相似度 1 表示最高相似度,而余弦相似度值 0 表示没有相似度。
点积
两个向量的点积是角度的余弦乘以范数的乘积,即similarity(movie1,movie2) = ||movie1|| ||movie 2|| cos(movie1,movie2).
推荐管道
典型的推荐系统管道包括以下五个阶段:
A typical recommender system pipeline
假设我们正在构建一个电影推荐系统。该系统没有用户或电影的先验知识,而只有用户通过他们给出的评级与电影的交互。这是一个由电影 ID、用户 ID 和电影分级组成的数据帧。
Movie rating Dataframe
因为我们只有收视率,没有其他的,我们将使用协同过滤推荐系统。
1.预处理
- 效用矩阵转换
我们需要首先将电影分级数据帧转换成用户项目矩阵,也称为效用矩阵。
矩阵的每个单元都由用户对电影给出的评级填充。这个矩阵通常被表示为一个稀疏矩阵,因为由于缺少对该特定电影的任何分级,许多单元是空的。如果数据稀疏,协同过滤就不能很好地工作,所以我们需要计算矩阵的稀疏度。
如果稀疏值大约为 0.5 或更大,那么协同过滤可能不是最好的解决方案。这里需要注意的另一个要点是,空单元格实际上代表新用户和新电影。因此,如果有高比例的新用户,那么我们可能会考虑使用一些其他的推荐方法,如基于内容的过滤或混合过滤。
- 正常化
总会有一些用户过于积极(总是给出 4 或 5 分)或过于消极(把所有事情都评为 1 或 2 分)。因此,我们需要将评分标准化,以考虑用户和项目的偏见。这可以通过取平均值归一化来实现。
Source: Normalisation the Ratings
2.模特培训
数据经过预处理后,我们需要开始模型构建过程。矩阵分解是协同过滤中常用的技术,尽管还有其他方法,如邻域法。以下是涉及的步骤:
- 对用户-项目矩阵进行因子分解,得到 2 个潜在因子矩阵——用户因子矩阵和项目因子矩阵。
用户评级是由人类生成的电影的特征。这些特征是我们认为重要的可以直接观察到的东西。然而,也有一些不能直接观察到的特征,但在评级预测中也很重要。这些隐藏特征被称为潜在特征。
A simplified illustration of the latent factor approach
潜在特征可以被认为是用户和项目之间交互的基础特征。本质上,我们不清楚每个潜在特征代表什么,但是可以假设一个特征可能代表用户喜欢喜剧电影,而另一个潜在特征可能代表用户喜欢动画电影等等。
- 从这两个潜在矩阵的内积预测缺失评分。
潜在因素这里由 K 表示。这个重构的矩阵填充原始用户-项目矩阵中的空单元,因此未知的评级现在是已知的。
但是我们如何实现上面显示的矩阵分解呢?事实证明,有很多方法可以做到这一点,使用下面的方法之一:
- 交替最小二乘法
- 随机梯度下降(SGD)
- 奇异值分解
3.超参数优化
在调整参数之前,我们需要选择一个评估指标。对于推荐者来说,一个流行的评估标准是 K 处的精度,其中查看前 K 个推荐,并计算这些推荐中有多大比例与用户实际相关。
因此,我们的目标是找到在 K 处给出最佳精度的参数,或者任何其他想要优化的评估指标。一旦找到参数,我们可以重新训练我们的模型,以获得我们的预测评级,我们可以使用这些结果来生成我们的建议。
4.后加工
然后,我们可以对所有预测的评级进行排序,并为用户获得前 N 名推荐。我们还想排除或过滤掉用户之前已经交互过的项目。就电影而言,推荐一部用户以前看过或以前不喜欢的电影是没有意义的。
5.估价
我们之前已经讨论过这一点,但是让我们在这里更详细地讨论一下。评估任何推荐系统的最佳方式是在野外测试它。像 A/B 测试这样的技术是最好的,因为人们可以从真实的用户那里得到真实的反馈。然而,如果这是不可能的,那么我们不得不求助于一些离线评估。
在传统的机器学习中,我们分割原始数据集来创建训练集和验证集。然而,这并不适用于推荐模型,因为如果我们在单独的用户群上训练我们的所有数据,并在另一个用户群上验证它,那么该模型将不起作用。所以对于推荐者,我们实际上随机屏蔽了矩阵中的一些已知评分。然后,我们通过机器学习预测这些屏蔽的评级,然后将预测的评级与实际评级进行比较。
Evaluating recommenders Offline
前面我们谈到了精度作为一种评估指标。以下是一些可以使用的其他方法。
Python 库
有许多专门为推荐目的而创建的 Python 库。以下是最受欢迎的:
- 惊喜:Pythonscikit构建和分析推荐系统。
- 隐式 :隐式数据集的快速 Python 协同过滤。
- light FM:Python 实现了许多流行的隐式和显式反馈推荐算法。
- pyspark.mlib .推荐 : Apache Spark 的机器学习 API。
结论
在本文中,我们以缩小选择范围的方式讨论了推荐的重要性。我们还介绍了设计和构建推荐系统管道的过程。Python 实际上让这个过程变得更简单,因为它为此提供了对许多专门库的访问。尝试使用一个来构建您自己的个性化推荐引擎。
参考
使用紫外线分解的推荐系统
快速浏览 Jure Leskovec、Anand Rajaraman 和 Jeffrey Ullman 的大规模数据集挖掘第 9 章
如今,几乎每个行业都在使用无数推荐系统的例子。大多数人在高层次上理解推荐系统试图达到的目的。然而,没有多少人了解它们在更深层次上是如何工作的。这就是 Leskovec、Rajaraman 和 Ullman 在他们的书的第 9 章【大规模数据集的挖掘】中深入探讨的内容。
今天使用的推荐系统的一个很好的例子是网飞。只要你登录网飞,就会看到各种各样的板块,比如“现在趋势”或“新发布”,但还有一个板块的标题是“你的最佳选择”。这一部分使用了一个复杂的公式来估算你最喜欢哪部电影。这个公式考虑了你以前欣赏过的电影,以及其他像你一样的人也欣赏过的电影。
这暗示了推荐系统的两个主要领域:基于内容的系统和协作系统。我们将在本文中更深入地探讨这些领域,但是,我想对每个领域做一个快速总结。基于内容的系统使用项目间的相似性。在网飞的例子中,一个基于内容的系统将关注电影之间的相似性,例如类型、导演、演员等。协作系统关注不同用户之间的相似性。再次以我们的网飞为例,假设有两个用户,他们彼此看过所有相同的电影,并且对每部电影的评价完全相同。如果他们中的一个人看了一部新电影,并将它评为 4 级,那么可以想象另一个人也会将这部电影评为 4 级。这两种技术是理解现代推荐系统如何工作的基础。
在互联网时代之前,一切都是在实体店买卖的。这些商店不可能为每一个进门的人量身定做商品。他们只能吸引大众。换句话说,他们的策略是非个人的,完全由畅销书或最受欢迎的商品驱动。想象一下 20 世纪 60 年代的唱片店。由于空间的限制,他们一次只能储存有限数量的专辑。为了最大化销售,他们会储存最有可能吸引最多人的专辑。然而,会有许多对音乐有独特品味的人不会被“迎合大众”的策略所服务。
将这家 20 世纪 60 年代的唱片店与 2019 年的 Spotify 相比较。Spotify 有一个 1960 年的唱片店没有的问题。Spotify 不可能向用户展示其曲库中所有可用的歌曲。Spotify 被迫开发一种方法来估计个人最有可能喜欢哪些歌曲。这是每个在线零售商都有的问题。无论在线零售商销售什么类型的产品,他们都需要开发一种方法,向每个客户成功推荐他们的大量选择。在竞争激烈的在线零售世界中,一家未能建立准确推荐系统的在线公司将处于巨大的劣势。
效用矩阵
Figure 1 (Mining of Massive Datasets — pg 308)
理解推荐系统的第一步是理解什么是效用矩阵以及它是如何构成的。效用矩阵是每个 用户的 对他们看过和/或评价过的每个 项目 的享受程度的集合。在我们的网飞例子中,我们可以想象这将会是什么样子。假设我们有来自四个网飞用户的评论:A、B、C 和 D,分别针对五部不同的电影:哈利波特 1、2 和 3、暮光之城和星球大战 1、2 和 3(见图 1)。我们的四个用户都没有看过每部电影,所以我们的表中有许多空白。这些空白单元格是我们作为一家公司想要预测的,以便知道我们应该向我们的每个用户推荐哪些电影。实际上,这个矩阵将是巨大的,包含数千列(电影)和数百万行(用户)。该矩阵也将非常稀疏,因为大多数用户不会看到网飞上数以千计的电影中的大多数。
基于内容的推荐
Figure 2 (Mining of Massive Datasets — pg 308)
正如我们前面简要提到的,基于内容的推荐关注项目之间的相似性。物品的相似性可以是任何东西。在我们的网飞例子中,它可以是流派、运行时间、提名/奖项、演员、导演、父母评级等。让我们选择一个简单的例子,我们只关注一个相似之处:电影系列。在我们的例子中,我们有两个不同的电影系列:哈利波特和星球大战,每个系列都有三部不同的电影。
在基于内容的推荐中,该示例中的用户 A 对于剩余的两部哈利波特电影将被给予预期评级 4,而对于剩余的两部星球大战电影将被给予预期评级 1。然而,我们可以想象,如果我们添加更多的项目相似性,而不仅仅是电影系列,这将变得更加复杂。让我们快速看一下用户 b。我们的电影系列基于内容的推荐会告诉我们所有星球大战电影的预期评级是什么?不是很多,对吧?也许如果我们有除了电影系列之外的额外功能,在《星球大战》电影和用户 B 看过的其他电影之间可能会有一些其他的相似之处。
协作推荐
同样,正如我们上面简要提到的,协作推荐系统关注用户之间的相似性。看看我们在网飞的四个用户的例子,假设不同的用户会以不同的尺度给每部电影打分是现实的。例如,某人可能只给电影打 3 到 5 分,而另一个人可能主要打 1 到 3 分。为了说明这种用户差异,我们希望在进行协作推荐时标准化效用矩阵。这种常态化会把每个人的评分系统放在同一个标尺上。
Figure 3 (Mining of Massive Datasets — pg 324)
为了标准化数据,我们首先找到每个用户的平均电影评级。然后我们创建一个新的矩阵,对于每个用户,我们从每个提供的电影评分中减去用户的平均评分。具有负分的电影是对于该特定用户具有低于平均分数的电影,而正分表示用户对该电影的评价高于他们的平均分数。上图显示了我们四个用户的标准化评分。用户 A 的平均得分为 3.33 (4、5 和 1)。当我们从提供的三个分数中去掉 3.33,我们得到 0.67 (2/3),1.67 (5/3)和-2.33 (-7/3)。
我想强调一下我们在这里所做的。在原始矩阵中,用户 A 和 C 都将电影评为 4 级。用户 A 将 HP 1 评级为 4,而用户 C 将 SW1 评级为 4。然而,在我们的归一化矩阵中,我们可以看到这些值不再相同。用户 A 在 2/3 处拥有 HP1,而用户 C 在 1/3 处拥有 SW 1。这是因为用户 C 与用户 A 相比具有更高的平均分,这意味着来自用户 C 的低分与来自用户 A 的低分相比具有更大的权重
既然每个人的评分都在同一等级上,我们就可以准确地比较用户之间的相似性。我们这样做的方法是通过计算任意两个用户的余弦值。大余弦意味着我们测量的角度小,反之亦然。因为角度表示用户之间的相似性,所以大余弦(小角度)意味着被测量的两个用户之间存在小差异。
Figure 4 — A and C — (Mining of Massive Datasets — pg 324)
让我们来看一下计算余弦的公式。首先,我们选择两个用户进行比较。作为一个例子,我们将比较用户 A 和 c。接下来,我们找到两个用户都提交了评级的所有电影。从我们的矩阵中可以看到,这恰好是两部电影:TW 和 SW1。然后,我们将每个用户的电影评分相乘,并将乘积相加,得到我们的分子。分母获取用户 A 的每个评分,对评分求平方,然后在求平方根之前将用户 A 的所有评分相加。它对用户 C 再次这样做,然后将两个结果相乘得到分母。我们可以看到用户 A 和 C 的余弦值为-0.559,这意味着他们对电影的品味相反。
Figure 5 — A and B — (Mining of Massive Datasets — pg 323)
让我们看看用户 A 是否更类似于用户 B 或用户 c。我们知道用户 A 和 c 之间的余弦。所以我们只是重复上面的步骤,但这次是在 A 和 B 之间。只有一部电影用户 A 和 B 都评级(HP 1)。因此,我们的分子只有一次乘法。我们看到用户 A 和 B 之间的余弦值为 0.092。记住,余弦值越高,用户越相似。基于此,我们可以有把握地得出这样的结论:用户 A 与用户 B 的相似度高于用户 c。如果我们将用户 A 与新用户 X 进行比较,得到余弦值为 0.099,则用户 A 与用户 X 的相似度甚至高于用户 B。
紫外线分解
最广泛接受的估计用户评级的形式之一是 UV 分解方法。为了展示这种方法是如何工作的,让我们看看下面图 6 中的效用矩阵。我们仍然可以假设行是各种用户,列是各种电影,但是这一次只缺少两个评级值。
Figure 6 (Mining of Massive Datasets — pg 328)
UV 分解的第一步是确定可以对我们的用户和电影进行类似分类的维度数量。在我们的例子中,我们将把我们的维数设置为 2,但这可以更大。然后,我们利用上面的矩阵,创建两个新矩阵:用户矩阵(U)和项目矩阵(V)。U 矩阵将是 5 乘 2(对于 5 个用户和 2 个维度),而 V 矩阵将是 2 乘 5(对于 2 个维度和 5 部电影)。这两个新矩阵(U 和 V)用随机数填充(现在我们用 1 填充),然后将它们相乘以创建另一个矩阵,其大小与原始效用矩阵相同(5x 5)。我们的目标是逐步改变 U 和 V 矩阵中的数字,使新矩阵尽可能接近原始效用矩阵。
Figure 7 (Mining of Massive Datasets — pg 329)
为了测量 U 和 V 的每次增量调整的成功,我们计算两个矩阵之间的 RMSE(均方根误差)。RMSE 越小,两个矩阵越接近(或越相似)。因此,我们希望找到插入 U 和 V 的最佳值,这将导致两个 5x 5 矩阵之间的最低 RMSE。参见下面的附录部分,详细了解 RMSE 的计算以及矩阵乘法的工作原理。
一旦我们找到了使 RMSE 最小化的 U 和 V 矩阵的值的组合,我们就可以找到原始效用矩阵中缺失评级的估计值。
摘要
Leskovec、Rajaraman 和 Ullman 涵盖的内容比上面讨论的更多,但是我想涵盖推荐系统的三个主要主题。基于内容的推荐系统只关注项目间的相似性,而协同推荐系统主要关注用户间的相似性。UV 分解是一种很好的方法,它使用 U 和 V 矩阵来寻找矩阵中缺失值的最佳估计值。
附录
矩阵乘法
在进行 RMSE 计算之前,让我们先来看看矩阵乘法是如何工作的。当我们将 U (5 x 2)乘以 V (2 x 5)时,实际上发生了什么?我们如何得到填充了 2 的 5×5 矩阵呢?
首先,矩阵乘法的顺序很重要。第一矩阵中列的数量必须等于第二矩阵中行的数量。在我们的例子中,U 有 2 列,V 有 2 行,所以我们很好。下一个技巧是,输出矩阵将具有与第一个矩阵相同数量的行,以及与第二个矩阵相同数量的列。在我们的例子中,U 有 5 行,V 有 5 列,所以得到的矩阵是 5 乘 5。
现在,我们如何填充 5x 5 矩阵?让我们举一个不同的例子,这将使解释矩阵乘法更容易,这里是我们的 U 和 V 矩阵:
Figure 8
为了计算 5 乘 5 矩阵的左上值,我们取 U (3)的左上值,并将其乘以 V (5)的左上值。然后我们取 U (4)的右上值,再乘以 V (7)的左下值。所以公式看起来是:(3 x 5) + (4 x 7) = 43 。这是我们的矩阵:
Figure 9
为了填充 5 乘 5 矩阵的第一行,我们继续使用 U 矩阵的第一行,但是对于 V 矩阵,我们每次移动一列。所以 43 右边的数字将是:(3 x 8) + (4 x 4) = 40 ,以此类推。这又是我们的矩阵:
Figure 10
为了填充行,我们重复上面的过程,但是我们向下移动 U 行。所以 43 以下的值会是:(2 x 5) + (8 x 7) = 66 。40 以下的值将是(2 x 8) + (8 x 4) = 48 ,以此类推。这是我们 5x 5 矩阵的最终结果:
Figure 11
RMSE 计算
简单回顾一下,RMSE 用于 UV 分解,以比较原始矩阵(具有实际用户评级)和新计算的矩阵(通过计算 U x V)之间的差异大小。下面是初始设置的样子:
Figure 12 (Mining of Massive Datasets — pg 328–329)
问题是,我们如何衡量这些矩阵有多相似?我们用 RMSE 做这个。如果我们想计算上述两个矩阵之间的 RMSE,第一步是从原始矩阵中减去计算矩阵的每个值。结果看起来像这样:
Figure 13
我们在这里所做的只是从我们的原始矩阵中减去我们计算出的矩阵(2s 的矩阵)中的值。所以左上角的 3 是 5 减 2 得来的。下一步是对这个新矩阵中的每个值求平方,得到以下结果:
Figure 14
一旦我们对矩阵中的每个值进行平方,我们就将每一行加在一起(例如,我们将对 9 + 0 + 4 + 4 + 1 求和得到 18,依此类推。结果如下所示:
Figure 15
步骤的最终组合是:1)对这个 5 乘 1 矩阵中的所有值求和,2)除以从我们的原始效用矩阵提供的评级总数(在我们的情况下,这将是 5×5-2,即 23,因为我们的原始效用矩阵中有两个空白),3)取这个结果的平方根,该值就是 RMSE。因此,这是我们示例的最后 3 个步骤的视觉效果:
Figure 16 (23 = 5 x 5 - 2)
3.26 的平方根是 1.81,所以我们原来的效用矩阵和 2s 的矩阵之间的 RMSE 是 1.81 。
引用的作品
Jure Leskovec,Anand Rajaraman,Jeffrey D. Ullman。海量数据集的挖掘。2014.【http://infolab.stanford.edu/~ullman/mmds/book.pdf
推荐系统
推荐系统是指能够预测用户对一组项目的未来偏好并推荐最佳项目的系统。现代社会需要推荐系统的一个重要原因是,由于互联网的普及,人们有太多的选择。过去,人们习惯在实体店购物,实体店的商品有限。例如,可以放在大片商店的电影数量取决于商店的大小。相比之下,如今,互联网允许人们在线访问丰富的资源。例如,网飞收藏了大量的电影。虽然可获得的信息量增加了,但新的问题出现了,因为人们很难选择他们真正想看的项目。这就是推荐系统的用武之地。本文将简要介绍构建推荐系统的两种典型方法,协同过滤和奇异值分解。
构建推荐系统的方法:
有两种方法可以构建推荐系统:
1。基于内容的推荐:推荐系统的目标是预测用户未评级项目的得分。内容过滤背后的基本思想是每个项目都有一些特征 x。例如,电影“爱情在最后”是一部爱情电影,其特征𝑥₁得分高,但特征𝑥₂.得分低
Movie Ratings Data
每个人都有一个参数θ,表示他们有多喜欢爱情电影,有多喜欢动作片。如果θ是[1,0.1],说明这个人爱看言情片,不爱看动作片。那么对于每个人,我们可以用线性回归找到最优的θ。
(Notation)
r(i,j): 1 if user j has rated movie i (0 otherwise)
y(i,j): rating by user j on movie i (if defined)
θ(j): parameter vector for user
x(i): feature vector for movie i
predicted rating [user j, movie i]: (θ(j))ᵀx(i)
m(j): # of movies rated by user j
nᵤ: # of users
n: # of features of a movie
给定上面的符号,用户 j 的优化目标可以写成如下:
Optimization Objective for user j
因为我们想为所有用户找到最佳参数,所以我们有很多这样的参数。
Optimization Objectives for All Users
我们希望对这些目标有一个单一的表述。注意 m(j)只是一个不影响优化的常数。因此,忽略 m(j)个因素,我们可以将所有目标相加,得到一个单一的表达式。
Optimization Objective
因此,梯度下降可以用下面的表达式来执行:
Cost Updating Function
2。协作过滤:内容过滤的缺点是它需要每个项目的辅助信息。比如言情、动作之类的体裁就是电影的边信息。让某人观看电影并为每部电影和未来的每部电影添加补充信息是非常昂贵的。此外,一个人怎么可能列出一部电影的所有特征?如果想增加一个新功能,该怎么办?我们要给所有的电影增加新的功能吗?协同过滤解决了这个问题。首先,让我们考虑内容过滤的相反方法。也就是说,我们能根据用户偏好参数预测电影的特征吗?
Predict the features of movies
我们将再次使用线性回归来预测特征。
Optimization Objective for movie i
请注意,这一次我们将最小化特征 x 的成本,而不是参数θ。我们想预测所有电影的特征。
Optimization Objectives for All Movies
与我们之前所做的类似,我们希望用一个表达式来表达这些目标。
Optimization Objective
现在,我们有两个优化表达式,一个用于查找最佳参数θ,另一个用于查找最佳特征 x。
Two Optimization Objectives
我们可以同时找到最优参数θ和最优特征 x。我们可以将两个优化目标合二为一。请注意,两次双重求和都是遍历 r(i,j)=1 的所有数据。因此,我们可以将两种优化相加。
Collaborative Filtering Optimization Objective
我们用 1/2 代替 1,因为这样做在数学上更方便。这里要注意一个很有意思的事情,就是我们不需要把截距项 1 加到 x 上,为什么呢?因为如果算法需要截距项 1,它可以通过将 x 的第一项设置为 1 来实现。(现实中,我们不知道 x1,x2,…代表什么。所以我们设置了任意数量的特征。第一个特征可以代表偏差。)因此,成本更新函数如下所示:
Cost Updating Functions
交替最小二乘法:
我们之前讨论过协同过滤不需要任何关于用户或项目的信息。那么,有没有另一种方法可以让我们弄清楚用户和商品之间的关系呢?
事实证明,如果我们应用矩阵分解,我们就能做到。通常,矩阵分解应用于降维领域,我们试图在保持相关信息的同时减少特征的数量。主成分分析(PCA)和非常相似的奇异值分解(SVD)就是这种情况。
从本质上讲,我们是否可以获得一个用户/物品交互的大矩阵,并在一个更小的用户特征和物品特征矩阵中找出将它们相互关联的潜在(或隐藏)特征?这正是 ALS 试图通过矩阵分解实现的。
如下图所示,假设我们有一个大小为 MxNMxN 的原始评分矩阵 RR,其中 MM 是用户数量,NN 是项目数量。这个矩阵非常稀疏,因为大多数用户每个人只与几个项目交互。我们可以将该矩阵分解成两个独立的更小的矩阵:一个具有维度 MxKMxK,这将是我们对于每个用户(U)(U)的潜在用户特征向量,而第二个具有维度 KxNKxN,这将具有我们对于每个项目(V)(V)的潜在项目特征向量。将这两个特征矩阵相乘接近原始矩阵,但是现在我们有两个密集的矩阵,包括我们的每个项目和用户的许多潜在特征 KK。
为了求解 UU 和 VV,我们可以利用 SVD(这将需要对可能非常大的矩阵求逆,并且计算量很大)来更精确地求解因式分解,或者应用 ALS 来近似它。在 ALS 的情况下,我们一次只需要求解一个特征向量,这意味着它可以并行运行!(这一巨大优势可能是它成为 Spark 首选方法的原因)。为此,我们可以随机初始化 UU 并求解 VV。然后我们可以回过头来,用我们的 VV 解来求解 UU。像这样反复迭代,直到我们得到一个尽可能接近 RR 的收敛点。
随机梯度下降优化;
随机梯度下降(SGD)优化是一种并行算法,可以解决推荐系统的相同问题。该算法以随机顺序遍历训练数据中的所有评级,对于每个已知评级 r ,它做出预测 r* (基于向量 x 和 y 的点积)并计算预测误差 e 。然后,我们通过在梯度的相反方向上移动它们来修改 x 和 y ,为 x 和 y 的每个特征产生某些更新公式。
推荐系统应用开发
余弦相似度、等级阈值和其他定制技术
在本文中,我们将使用余弦相似度(CS)和 Python 编程语言的其他自定义公式开发一个推荐系统(RS)。这个应用程序将是我在硕士论文期间从事的项目的一部分。
有许多方法可以建立一个 RS。在这里,我们将开发特别解决 RSs 冷启动问题的方法。冷启动问题是在没有关于用户(新注册用户)的大量信息的情况下为用户做出推荐的困难。在这个项目中,我们将研究仅使用少量用户信息进行推荐的方法(允许用户选择他们感兴趣的类别)。
要求:
- Python 3
- numpy
- 熊猫
- nltk
我假设您在这些文章的整个开发过程中都了解 Python。我不会把重点放在也不会详细描述 Python 代码,因为这些文章的主要目的是讲授如何使用 CS 和其他技术来构建 RS。同样值得一提的是,我可能会写一些更好的代码,因为我不是 Python 大师。如果你意识到了这样的部分,请在评论中告诉我,这样我可以在以后重构它:)
我们将开发 4 个不同的版本来研究不同的方法来改进我们的系统。首先,我们将从具有余弦相似度的推荐系统开始。
我们将要建立的 RS 将根据所选的类别推荐 5 个不同的旅游城市。当然,这些技术和方法以后可以应用于不同环境的应用程序。
请在此下载我们的 RS 将基于的数据集。
该数据集的一些要素(列)是我之前从猫途鹰网站获得的真实信息,而其中一些只是我添加的随机要素,以便稍后实现和显示不同的技术。我们的数据集由 25 个城市组成,具有以下特征:城市,受欢迎程度,描述,图像,评级,评级计数,正面评论,负面评论。您可以在下面看到前 5 个城市的数据集预览。
City dataset preview
我从猫途鹰身上获得的特征是:城市、知名度、描述和形象。除此之外的功能都是我随机制作的。我们不会在 RS 的第一个版本中使用这些特性,但是它们会在这个系列的其他部分中用于不同的技术。
让我们回顾一下每项功能的含义:
- 城市:城市名称
- 受欢迎程度:为城市保存评论计数。
- 描述:关于城市的博客帖子
- 图像:城市的背景图像
- 评分:城市的平均评分值(0-10)
- rating_count:从用户处收到的评级数量
- 正面评论:正面评论的数量。
- 负面评论:负面评论的数量。
现在我们已经下载了数据集并了解了特性,我们可以开始开发了。如前所述,在第一个版本中,我们将只使用城市和描述特性。
版本 1
RS 的第一个版本将根据我们数据集中城市的描述特征给出建议。RS 将使用余弦相似度计算城市描述和与用户可能选择的旅行类别相关的关键字之间的相似度,然后返回具有最高相似度得分的前 5 个城市。
余弦相似性
余弦相似性是两个向量之间的相似性的度量,通过计算投影到多维空间中的两个向量之间的角度的余弦。它可以应用于数据集上可用的项目,以通过关键字或其他指标计算彼此的相似性。两个向量(A 和 B)之间的相似性通过取两个向量的点积并除以幅度值来计算,如下式所示。我们可以简单地说,两个向量的 CS 分数随着它们之间的角度减小而增加。
Cosine Similarity Calculation for vectors A and B
Similarity between vectors A and B on 3-dimensional space
预处理
首先,我们需要对我们的数据集做一些预处理,使其可以用于我们的 CS 计算方法。让我们在包含数据集的文件夹中创建一个名为 pre_processing.py 的 python 文件。
我们将只清除数据集的描述要素。我们需要从描述中删除停用词。停用词是没有任何上下文意义的词,例如;the,for,an,a,or,what 等。移除这些单词的动机是确保相似性分数不会因为非上下文单词而降低。这将对分数产生负面影响,因为每个单词在空间中创建了不同的维度,并且这些维度的对应值将总是零,因为我们的关键字中没有一个将包括非上下文相关的单词。
import numpy as np
import pandas as pd
from nltk.corpus import stopwordsdef clear(city):
city = city.lower()
city = city.split()
city_keywords = [word for word in city if word not in stopwords.words('english')] merged_city = " ".join(city_keywords)
return merged_city
我们将使用上面的清除(城市)方法来清除城市描述。它的工作原理如下:
- 它接受一个名为 city 的字符串参数
- 降低字符串中的每个字符。lower()方法。
- 用创建单词列表。split()方法。
- 通过删除英语的停用词来初始化 city _ keywords(nltk 框架)
- 从清除的单词中合并一个字符串并返回它
现在,让我们将此方法应用于数据集中的每个条目,如下所示:
for index, row in df.iterrows():
clear_desc = clear(row['description'])
df.at[index, 'description'] = clear_descupdated_dataset = df.to_csv('city_data_cleared.csv')
该代码块将清除我们数据集中所有城市的所有描述,然后将更新后的描述保存为 city_data_cleared.csv 文件。从现在开始,我们将使用这个清除的数据集。
pre_processing.py 要点:
用余弦相似度计算相似度得分
现在我们已经清除了城市描述,我们可以开始实现负责计算相似性得分的类了。让我们创建一个名为余弦相似性. py. 的 python 文件
正如我前面提到的,该方法将根据两个字符串包含的单词来计算它们的相似度。首先,这两个字符串将被转换成向量,然后向量中的每个单词将在单词空间上创建一个维度。如果一个向量中存在的任何单词在另一个向量中不存在,则另一个向量的相应维度的值将为零。
不是:余弦相似度是尺度不变的,意义;一个单词在给定的字符串中出现的次数对它没有太大的影响。不管怎样,我们使用余弦相似度,因为我们只关心一个单词是否在两个字符串中都存在,我们不关心一个单词出现了多少次。但是,如果你对这种计数差异感兴趣,并希望你的推荐者考虑到这一点(这意味着分数将受到单词出现次数的极大影响),那么我会建议你去看看皮尔森相关性。
即使只有一种计算方法,让我们在一个类下创建它,以提高以后的可用性。
import re, math
from collections import Counterclass CosineSimilarity:
def __init__(self):
print("Cosine Similarity initialized")
[@staticmethod](http://twitter.com/staticmethod)
def cosine_similarity_of(text1, text2):
first = re.compile(r"[\w']+").findall(text1)
second = re.compile(r"[\w']+").findall(text2)
vector1 = Counter(first)
vector2 = Counter(second) common = set(vector1.keys()).intersection(set(vector2.keys())) dot_product = 0.0 for i in common:
dot_product += vector1[i] * vector2[i] squared_sum_vector1 = 0.0
squared_sum_vector2 = 0.0 for i in vector1.keys():
squared_sum_vector1 += vector1[i]**2 for i in vector2.keys():
squared_sum_vector2 += vector2[i]**2 magnitude = math.sqrt(squared_sum_vector1) * math.sqrt(squared_sum_vector2) if not magnitude:
return 0.0
else:
return float(dot_product) / magnitude
余弦相似度方法的工作原理如下:
- 接受两个字符串参数
- 借助正则表达式获取两个字符串的单词
- 用 Counter (words,word count)初始化字典,其中键对应于一个单词,值对应于该特定单词的计数。
- 获取在两个向量中都存在的常用单词
- 按照余弦相似性一节中介绍的公式计算余弦相似性,并返回值。
cosine_similarity.py 要点:
cosine_similarity.py
推荐引擎
接下来,我们将编写负责推荐的引擎。
engine 类将会很小,因为在版本 1 中,我们将只通过比较关键字和城市描述来提供建议,但是我们将把它作为一个单独的类,因为在本系列的下一部分中,我们将在其他版本中对它进行迭代和开发。
recommender_engine.py:
recommender_engine.py for Version-1
get_recommendations(keywords)方法的工作方式如下:
- 接受字符串参数来计算城市描述的余弦相似性
- 用给定的参数计算每个城市的 CS,并将其作为字典保存为
- 创建一个包含城市、受欢迎程度、描述和分数要素的空数据框。
- 将得分最高的 5 个城市添加到此数据框中
- 将数据帧转换为 JSON 并返回。
请求代码
现在我们将测试我们的引擎(以及 CS 计算功能)。让我们创建一个 request.py python 文件。
我们将在三个不同的类别下测试我们的推荐引擎:
- 文化、艺术和历史
- 沙滩和阳光
- 夜生活和派对
我调查了数据集中所有城市的描述,并手动确定了每个类别的关键字,如下所示:
- [历史历史艺术建筑城市文化]
- 【沙滩沙滩公园自然度假海海边沙滩阳光阳光明媚】
- [夜总会夜总会夜生活酒吧酒吧酒吧酒馆派对啤酒]
让我们添加以下代码,该代码将发送一个请求,以获取给定关键字的前 5 个相似城市,以及预定义的关键字:
from recommender_engine import RecommenderEngineculture_keywords = "history historical art architecture city culture"
beach_n_sun_keywords = "beach beaches park nature holiday sea seaside sand sunshine sun sunny"
nightlife_keywords = "nightclub nightclubs nightlife bar bars pub pubs party beer"def get_recommendations(keywords):
result = RecommenderEngine.get_recommendations(keywords)
return result
然后让我们编写一个 helper 方法来从 JSON 中获取城市名称和分数,如下所示:
def get_top_5_city_names_out_of_json(json_string):
list = json.loads(json_string)
result = []
max = len(list)
i = 0
while i < max:
result.append(list[i]['city'])
i += 1 return result
现在,我们将针对 3 个类别向推荐者发出 3 个请求,然后打印前 5 个城市及其每个类别的相似性得分:
top_5_cultural_cities = get_recommendations(culture_keywords)
city_names_for_cultural = get_top_5_city_names_out_of_json(top_5_cultural_cities)
print(city_names_for_cultural)
print("#################")top_5_summer_cities = get_recommendations(beach_n_sun_keywords)
city_names_for_summer = get_top_5_city_names_out_of_json(top_5_summer_cities)
print(city_names_for_summer)
print("#################")top_5_party_cities = get_recommendations(nightlife_keywords)
city_names_for_party = get_top_5_city_names_out_of_json(top_5_party_cities)
print(city_names_for_party)
print("#################")
当我们运行代码时,我们将获得所有 3 个类别的建议,但让我们只调查文化、艺术和历史类别的结果:
[('Athens', 0.21629522817435007),
('St. Petersburg', 0.16666666666666666),
('Stockholm', 0.14962640041614492),
('Milan', 0.140028008402801),
('Rome', 0.12171612389003691)]
如上所示,雅典的相似性得分为 21.6%,而罗马为 12.17%。分数可能比你预期的要低。得分较低是因为,每个城市的描述自然比我们提供的用于比较的关键词有更多的词。不同的词在空间上创建不同的维度,并且由于我们的关键词没有这些词,这些维度的相应值将为零,这导致较低的相似性得分。如果你从关键词中增加或减少单词,你会发现结果也会改变。
request.py 要点:
request.py
版本 1 的结论
在这个版本中,我们开发了一个推荐应用程序,通过计算城市描述与给定类别关键字的余弦相似性,为三个不同类别的旅行提供城市推荐。
即使相似性得分很低,当您调查每个类别返回的前 5 个城市时;你可以看到我们的推荐系统,推荐有意义和合适的城市。不妨看看城市描述验证一下:)
我们已经到了第一版的末尾。你可以从这里访问所有为第一版写的代码。
在下面的下一个版本中,我们将实现一个不同的方法来计算分数,包括余弦相似性和城市的评级信息。
版本 2(评级贡献)
在这个版本中,我们将利用数据集的评级功能,并改进我们的推荐应用程序,使其更加动态,并提供更好的推荐。我们不想建立一个推荐低评级内容的系统,对吗?至少大多数情况下不会:)
使用 CS 和评级贡献生成最终得分
首先,我们将省略评级数量。我们仍然会计算余弦相似度,但现在除此之外,我们还会对最终得分进行评分。我们将创建一个新的方法来确定评分对最终得分的贡献。我们将有两个参数,Q 和 r。其中 r 代表评级,Q 代表重要性(最终分数计算的评级权重)。通过使用 Q 参数,我们将能够增加或减少评分值对最终得分生成的影响。
新函数将根据与给定 Q 参数成比例的评分是大于还是小于 5 来增加或减少余弦相似性的输出(假设平均评分小于 5 的城市不喜欢并且应该被劝阻,大于 5 的城市喜欢并且应该被鼓励推荐)。如前一章所述,评级范围在 0-10 之间,评级贡献输出范围在-Q 和+Q 之间。
例如:如果 Q 给定为 10,则最大评分值可以通过将 CS 分数的 10%加到 CS 分数上来产生最终推荐分数,对于最小评分,最终分数可以通过从 CS 分数中减去 CS 分数的 10%来产生。
我们将在方法中使用的公式将找出给定评级的准确输出(找到蓝线上的准确点)。对于 Q = 10,这种评级贡献生成器方法的直观表示如下图所示:
Rating Contribution computer function for Q = 10
让我们创建一个名为 rating_extractor.py 的新文件,并添加以下代码
from math import eclass RatingExtractor:
def __init__(self):
print("initialized")#Returns value between -q and q. for rating input between 0 and 10.
#Parameters:
#rating: indicates the rating for the destination
#q: indicates the percentage of rating for general score. (default is 10.)
[@staticmethod](http://twitter.com/staticmethod)
def get_rating_weight(rating, q=10):
if rating > 10 or rating < 0:
return None
else:
m = (2*q) / 10 #10 because rating varies between 0 and 10
b = -q
return (m*rating) + b
get_rating_weight()方法进行一些计算,以确定给定等级和 Q 参数的贡献输出,然后返回值。如前所述,也如上图所示,这种方法可以产生负值和正值。意义;这种方法将对最终分数的计算产生积极或消极的影响。(请注意 Q 参数的默认值设置为 10)。
一种新方法在推荐引擎中的实现
现在,我们将添加一个新的方法来推荐一个使用余弦相似性分数和评级贡献来计算最终分数的工程类。在 RecommenderEngine 类中添加下面的方法。(我已经在 init 后面添加了)。
def calculate_final_score(cs, r):
amount = (cs / 100) * r return cs + amount
方法的工作方式如下:
- 接受 CS 分数和评级贡献 r 参数。
- 计算金额变量中 CS 分数的+-r 百分比
- 将金额加到 CS 分数上并返回。
由于金额可以是正数,也可以是负数,最终得分将根据贡献值增加或减少。
值得一提的是,这种方法对 CS 分数有很大的偏见。因为它的操作是取 CS 的 r 个百分比,并将其加回原始 CS 值。CS 值较高的城市将受到这一新的最终得分计算的极大影响,特别是如果为 get_rating_weight() 方法提供较高的 Q 值。
现在让我们添加另一个方法到 RecommenderEngine 来使用这个新方法进行评分计算(我们将保留旧的推荐方法)。
New method for recommender_engine in Version-2
get _ re commendations _ include _ rating(keywords)方法的工作方式与第一章中实现的 get_recommendations(keywords)方法类似。但现在它将使用 CS 得分和评分贡献值计算最终得分,让我们来看看该方法是如何工作的:
- 接受 keywords 参数,并对数据集中的每个城市执行以下操作
- 计算 cs 分数
- 计算 Q=10 的评分贡献分数
- 通过使用 calculate_final_score 方法中的两个分数来计算最终分数
- 获得最终得分最高的前 5 个城市,并以 JSON 的形式返回
请求
现在我们有了方法,我们可以请求获得推荐。首先,让我们打开 request.py 文件,并添加一个从 RecommenderEngine 类中检索建议的方法:
def get_recommendations_include_rating(keywords):
return RecommenderEngine.get_recommendations_include_rating(keywords)
现在让我们添加新的请求,用新的方法获得 3 个类别的推荐。
# Version 2 requests are below:top_5_cultural_with_rating = get_recommendations_include_rating(culture_keywords)
city_names_for_cultural_rating = get_top_5_city_names_out_of_json(top_5_cultural_with_rating)
print(city_names_for_cultural_rating)
print("#################")
top_5_summer_with_rating = get_recommendations_include_rating(beach_n_sun_keywords)
city_names_for_summer_rating = get_top_5_city_names_out_of_json(top_5_summer_with_rating)
print(city_names_for_summer_rating)
print("#################")
top_5_party_with_rating = get_recommendations_include_rating(nightlife_keywords)
city_names_for_party_rating = get_top_5_city_names_out_of_json(top_5_party_with_rating)
print(city_names_for_party_rating)
print("#################")
上面的代码将获取带有最终分数的推荐,您可以运行它并查看您得到的结果。
在本文中,我们将只从文化、艺术和历史这两个不同的角度来考察结果。首先,我们将比较在第一个版本中实现的唯一 CS 评分方法和我们刚刚实现的新方法得到的结果。
get_recommendations 和 get _ re commendations _ include _ rating 方法的比较:
下面的代码是出于实验目的,所以它们不再包含在 request.py 中,因为这两个请求已经存在。
top_5_cultural_cities = get_recommendations(culture_keywords)
city_names_for_cultural = get_top_5_city_names_out_of_json(top_5_cultural_cities)
print(city_names_for_cultural)
print("#################")top_5_cultural_with_rating = get_recommendations_include_rating(culture_keywords)
city_names_for_cultural_rating = get_top_5_city_names_out_of_json(top_5_cultural_with_rating)
print(city_names_for_cultural_rating)
print("#################")
这里我们观察两种不同方法的输出:
[('Athens', 0.21629522817435007),
('St. Petersburg', 0.16666666666666666),
('Stockholm', 0.14962640041614492),
('Milan', 0.140028008402801),
('Rome', 0.12171612389003691)]#################[('Athens', 0.22927294186481106),
('Stockholm', 0.1556114564327907),
('St. Petersburg', 0.15333333333333332),
('Milan', 0.15123024907502508),
('Rome', 0.13145341380123987)]
在这里,我们有两种方法的不同得分,你可以看到,当评级考虑在内时,斯德哥尔摩上升到第二位,而圣彼得堡下降到第三位。让我们看看为什么:
正如您在我们的数据集中看到的,斯德哥尔摩的评分为 7,而圣彼得堡为 1。然后,如前所述,我们的算法降低了圣彼得堡的最终得分,并提高了斯德哥尔摩的最终得分,这导致斯德哥尔摩升至第二名。在这里,我们可以看到,使用实现的方法和公式,我们的推荐系统鼓励具有良好评级的内容,同时阻止具有不良评级的内容。您还可以观察其他城市排名的数据集,以了解为什么它们的最终得分与仅余弦相似性得分相比有所增加。
Q = 10 和 Q = 100 时 get _ recommendations _ include _ rating 方法的比较:
现在我们将使用不同的 Q 参数来比较我们的新方法。较低的 Q 表示对最终分数的评分贡献较小,而较高的 Q 表示贡献较大。正如我们之前打印出来的,以下是我们在 Q = 10 时得到的文化、艺术和历史类别的建议:
[('Athens', 0.22927294186481106),
('Stockholm', 0.1556114564327907),
('St. Petersburg', 0.15333333333333332),
('Milan', 0.15123024907502508),
('Rome', 0.13145341380123987)]
您可以转到 recommender_engine.py,将 10 替换为 100,以增加 get _ recommendations _ include _ rating 方法中的 Q 参数:
rating_contribution = RatingExtractor.get_rating_weight(rating,100)
现在让我们看看结果是如何变化的:
[('Athens', 0.3460723650789601),
('Milan', 0.2520504151250418),
('Rome', 0.21908902300206645),
('Stockholm', 0.2094769605826029),
('Venice', 0.17777777777777776)]
我们可以观察到我们现在的结果非常不同。
- 圣彼得堡已经不在前 5 名了,因为它的评分是 1,Q 值越高,这个城市就越不值得推荐
- 米兰和罗马分别升至第二和第三位,而斯德哥尔摩则跌至第四位,因为米兰和罗马的排名高于斯德哥尔摩。
Rating comparison for Stockholm, Rome and Milan
我建议你检查其他类别的结果,以及它们如何随着不同的 Q 值而变化。
版本 2 的结论
在版本 2 中,我们实现了一种方法,通过基于描述特征的余弦相似性得分和基于评级特征的评级贡献得分计算最终得分来推荐城市。因为在推荐系统中,我们经常想要向用户推荐好的内容,所以利用诸如评级之类的信息是很重要的。
你可以在这里访问所有为第二版编写的代码。
在下面的下一个版本中,我们将实现另一种方法,通过使用数据集中的评级计数功能来改进我们的推荐应用程序。
版本 3(评级阈值)
一个内容有好的评级,不代表评级就可靠。假设我们有两个内容 A 和 B,A 在 500,000 个用户中的平均评分为 4.7,而 B 仅在 10 个用户中的平均评分为 5。你想向你的朋友推荐哪一个?只有 10 个用户提供评级,你认为 B 有多可靠?在 rating_count 特性的帮助下,我们将提出一个阈值参数,这样我们的推荐系统将能够处理评级计数低的内容(在我们的例子中是城市),因为评级贡献并不太重要。
具有评级和计数功能的评级权重生成
在这个版本中,我们将开发几个新的方法来改进我们的推荐系统,以便它将有一个用于评级贡献计算的阈值。现在给大家介绍一个我写论文时想出来的公式:
Multiplier formula
该公式得出 M,它是一个乘数值,将与我们得到的评分贡献值相乘,然后用于最终推荐分数计算。这里 T 代表阈值,c 代表评级计数。该公式以具有以下属性的方式构建:
- 输出的范围在 0.0 和 1.0 之间
- 如果 T 和 c 参数相等,则公式始终得出 0.5
这个公式中的数字 e 没有什么特别的,它可以是任何数字(那么 0,68 也必须改变)。我只是用 e 让它看起来很酷:P
因此,该方法的主要重要性在于,当 T = c 时,它产生 0.50,这就是阈值处理的工作方式。我们将为评级计数设置一个阈值 T,这样,如果评级计数小于阈值,输出将在 0.0–0.50 的范围内(取决于有多低。)并且如果评级计数大于阈值,则输出将在 0.50 和 1.0 之间,但是永远不会超过 1.0。
如前所述,该乘数将仅应用于评级贡献值,因此我们不会太在意没有提供大量评级的评级,并且输出将降低评级贡献。因此,推荐将主要落入 CS 分数。但是,如果一个地方有更多的评级,那么评级贡献值也将会很高,最终的总体推荐分数也会更高。
现在让我们转到 rating_extractor.py 文件并创建一个新方法。我们只是将评分贡献值乘以乘数,但让我们创建一个新的方法,这样您仍可以有其他方法并按原样使用它。
首先我们需要从 math 中导入 e:
from math import e
然后在 RatingExtractor 类中,添加新方法:
[@staticmethod](http://twitter.com/staticmethod)
def get_rating_weight_with_quantity(rating, c, T, q=10):
if rating > 10 or rating < 0:
return None
else:
m = (2*q) / 10 #10 because rating varies between 0 and 10
b = -q
val = (m*rating) + b M = e**((-T*0.68)/c) return val * M
方法的工作原理如下:
- 它需要 rating、c (rating_count)、T (threshold)和 q 参数。
- 从上一章我们已经知道了评级和 q 参数。
- c 指用户提供评级的数量
- t 指的是上面介绍的阈值
- 计算评分贡献值
- 计算乘数 M 值
- 通过将贡献值乘以 M 返回评级权重
一种新方法在推荐引擎中的实现
让我们打开 recommender_engine.py,为 RecommenderEngine 类添加一个新方法(我们将保留我们在以前版本中实现的方法),它实际上与我们在前一章中添加到 RecommenderEngine 的方法几乎完全相同,但这次我们将传递评级计数和阈值以及城市描述和评级功能:
get_recommendations_include_rating_threshold method
该方法的工作原理如下:
- 接受 keywords 参数,并对数据集中的每个城市执行以下操作
- 计算 CS 分数
- 通过将城市评级、评级计数、阈值作为 100 万(数据集中的城市的评级计数在 100k 到 5M 之间,我最初选择了 100 万,但我们将对此进行调整)和 Q=10 来获取评级贡献权重
- 通过使用 CS 分数和评级权重,使用 calculate_final_score 方法(在上一章中实施)计算最终分数。
- 获得最终得分最高的前 5 个城市,并以 JSON 的形式返回
请求
我们将向 request.py 文件中添加新的请求,以便使用新方法获得 3 个类别的建议
首先,让我们添加一个方法来从 RecommenderEngine 类中检索具有新实现的建议:
def get_recommendations_include_rating_count_threshold(keywords):
return RecommenderEngine.get_recommendations_include_rating_count_threshold(keywords)
现在让我们添加新的请求,用新的方法获得 3 个类别的推荐。
# Version 3 requests are below:top_5_cultural_with_rating_count_threshold = get_recommendations_include_rating_count_threshold(culture_keywords)
city_names_for_cultural_rating_count_threshold = get_top_5_city_names_out_of_json(top_5_cultural_with_rating_count_threshold)
print(city_names_for_cultural_rating_count_threshold)
print("#################")top_5_summer_with_rating_count_threshold = get_recommendations_include_rating_count_threshold(beach_n_sun_keywords)
city_names_for_summer_rating_count_threshold = get_top_5_city_names_out_of_json(top_5_summer_with_rating_count_threshold)
print(city_names_for_summer_rating_count_threshold)
print("#################")top_5_party_with_rating_count_threshold = get_recommendations_include_rating_count_threshold(nightlife_keywords)
city_names_for_party_rating_count_threshold = get_top_5_city_names_out_of_json(top_5_party_with_rating_count_threshold)
print(city_names_for_party_rating_count_threshold)
print("#################")
上面的代码将获取推荐以及它们的最终分数,你可以运行它并查看你得到的所有类别的结果。但我们将只调查文化、艺术和历史类别的结果。
不同阈值的结果比较
让我们对文化、艺术和历史类别提出不同阈值(T)的实验请求。您可以在 RecommenderEngine 类的 get _ recommendations _ include _ rating _ count _ threshold 方法中更改 threshold。同样,这次我们将 Q 参数(前一章中介绍的评级贡献重要性参数)更改为 100,这样我们可以更好地看到阈值效果。
阈值= 100.000 的结果:
[('Athens', 0.33318171469723395),
('Milan', 0.24587898720843948),
('Rome', 0.21192640793273687),
('Stockholm', 0.18358642633975064),
('Venice', 0.17262307588744202)]
阈值= 1.000.000 的结果:
[('Athens', 0.26188415260156817),
('Milan', 0.2035910531885378),
('Rome', 0.16707033294390228),
('Stockholm', 0.14983344608755947),
('Barcelona', 0.14757848986361075)]
阈值= 2.500.000 的结果:
[('Athens', 0.2257870828894539),
('Milan', 0.16719580286435054),
('St. Petersburg', 0.158824470447676),
('Stockholm', 0.14962644254339),
('Rome', 0.13613352041126298)]
如你所见,阈值为 100K 和 1M;第 5 名就不一样了,门槛值低一点的时候我们有威尼斯在第 5 名,值高一点的时候我们有巴塞罗那。让我们看看为什么:
Rating and Rating count for Barcelona and Venice
他们都有 8 分,但巴塞罗那有 120 万分,而威尼斯有 845.000 分,威尼斯的 CS 分数也比巴塞罗那高。因此,当阈值为 100.000 时,两个城市都可以提供良好的评级贡献,因为威尼斯的 CS 得分较高,所以我们看到它位于第 5 位。
但是当阈值为 1.000.000 时,贡献分数如下(Q=100):
- 巴塞罗那:34
- 威尼斯:26.8
由于巴塞罗那现在具有更高的输出,并且由于 Q 也很高,巴塞罗那的最终得分计算将大于威尼斯,因此巴塞罗那位于第 5 位。
当阈值为 2.500.000 时,您可以看到圣彼得堡排名第三,而当阈值更低时,我们甚至没有排名第四或第五的圣彼得堡。我会把调查工作交给你。查看圣彼得堡的数据集,了解我们的实现是如何工作的,看看您是否能理解为什么我们让圣彼得堡拥有更高的阈值。如果你对评论有任何问题,请告诉我:)
此外,我鼓励你尝试所有这些参数,检查数据集的特征(应该没问题,因为我们只有 25 个城市),并尝试理解这些方法如何对推荐系统有效。
版本 3 的结论
在第 3 版中,我们实现了一种推荐城市的方法,首先计算余弦相似性得分,然后使用评级和评级计数功能计算评级权重输出,最后使用两种结果计算最终得分。使用可靠的信息是很重要的,因此通过这些实现,我们已经看到了如何改进我们的推荐系统,以便它可以更多地依赖于具有更高(高度取决于应用的上下文)反馈的内容。
你可以在这里访问所有为第三版编写的代码。
在下面的下一个版本中,我们将通过研究如何利用不同形式的反馈来进一步改进我们的推荐系统。
版本 4
在这个版本中,我们将通过使用数据集的正面 _ 评论和负面 _ 评论特征来进一步改进我们的系统。
这一章将比前几章更多地关注该方法的理论和实验结果(这里不是动手执行,而是在结果表上),所以如果你只是对代码实现感兴趣,你可以直接进入 实现 部分。
有时,我们可能会有不同类型的内容反馈。例如评论和评级。正如您所猜测的,它们并不是完全相同的反馈类型,评级反馈是以给定的尺度提供的(对于我们的情况是 0-10),而评估通常以文本格式给出。假设我们已经将评论分为正面和负面反馈(也许我们可以调查另一篇文章的评论分类),那么评论反馈可以被分析为二元反馈(0 或 1);意义,负面或正面评论。
我们的数据集中已经有两个可用的特征正面 _ 评论和负面 _ 评论。这些特征代表了一个城市收到的正面和负面评论的数量。
推荐系统的挑战之一是以不同的形式整合反馈。有许多不同的方法可以做到这一点,在这一章中,我们将尝试使用两种反馈形式,通过一种定制的方法将评论转换为评分形式。
将评论转换为评级标准
这样做的基本方法是为负面和正面反馈选择两个评分值,然后将每个评审反馈视为一个评分,并重新计算项目的平均评分。但是这种方法并不理想。例如,如果对于负面和正面评论,评级被选择为 0 和 10,则评论的效果将大于实际评级数据,尤其是当项目的评级接近 0 或 10 时。可以选择不同的评级值来减轻评论对评级的影响。例如,如果评级被选择为 2.5 和 7.5,那么将会出现另一个问题,其中对于平均评级大于 7.5 的项目的正面反馈仍然会有助于降低评级,而对于平均评级小于 2.5 的项目的负面反馈将有助于提高评级。因此,需要另一种方法来更好地结合这两种形式。
对于正面和负面的评价,我们的方法将相应地表现如下:
- 对于任何正面评价,通过计算项目的平均评分和最大评分值之间的距离(在我们的例子中为 10),然后将计算的距离的一半添加到平均评分,以确定评价值,从而将新的评分值添加到评分中。
- 对于任何负面评价,通过计算项目的平均评分和最低评分值(在我们的例子中为 0)之间的距离,然后从平均评分中减去计算的距离的一半来确定评价值,从而将新的评分值添加到评分中。
下面给出了将正面和负面评论分别转换为平均评级为 r 的给定项目的评级值 Rp 和 Rn 的公式:
Rating value conversion for a positive review
Rating value conversion for a negative review
例如,对于平均评分为 6(范围 0-10)的项目,对于每个负面评价,值为 3 的新评分将被添加到评分中,而对于每个正面评价,值为 8 的新评分将被添加到评分中。然后,在反馈到评分功能之前,使用新评级再次计算平均评级。对于不同的评级、评级计数和审核计数,审核反馈转换为评级反馈的结果如下表所示。
Rating calculation results with average rating and reviews
最终评级结果表明,在当前实施情况下,当评级值接近最大值或最小值时,计算出的评级倾向于支持相反的评级值。例如,对于评级为 7.2 且正面和负面评论计数相等的情况,结果为 6.65,因为它从原始值越来越接近最低评级。这是因为,0 和 7,2 之间的距离大于 7,2 和 10 之间的距离,当原始评级为 2,8 且正负评级值相等时,也观察到类似的行为。此外,评论的影响是最小的,因为测试案例比商业推荐系统通常情况下的评论包括更多的评级值。可以通过引入一个额外的参数来改变评论的重要性,以使这种方法更有效(例如,对于每个评论,我们可以用计算的值生成 10 个评级值),从而增加效果。
履行
现在我们已经研究了它的工作方式和它可以生成的结果,让我们继续在 RatingExtractor 类中实现一个新方法:
[@staticmethod](http://twitter.com/staticmethod)
def get_rating_with_count_and_reviews(r, rc, pf, bf):
if r > 10 or r < 0:
return None
else:
positive_diff = (10 - r) / 2
positive_rating = r + positive_diff negative_diff = r / 2
negative_rating = r - negative_diff updated_rating = ((r * rc) + (pf * positive_rating) + (bf * negative_rating)) / (rc + pf + bf)return RatingExtractor.get_rating_weight_with_quantity(updated_rating,rc,1000000,10)
方法的工作方式如下:
- 采用 r(评分)、rc(评分计数)、pf(正面评论计数)和 bf(负面评论计数)参数
- 计算正面评价的换算评分值
- 计算负面评价的换算评分值
- 然后用每个正面和负面反馈的旧平均评分和新评分值计算更新后的平均评分
- 然后使用更新的平均评级、评级计数、T = 1.000.000(阈值)和 Q=100(评级重要性参数)调用在先前版本中实现的方法,并将结果作为评级贡献返回
一种新方法在推荐引擎中的实现
让我们打开 recommender_engine.py,添加一个新方法来推荐 engine 类。这将与我们在前面章节中实施的方法类似,但这次我们将通过正面评价和负面评价计数以及描述、评级、评级计数、阈值:
get_recommendations_include_rating_count_threshold_positive_negative_reviews method
该方法的工作原理如下:
- 接受 keywords 参数,并对数据集中的每个城市执行以下操作
- 计算 CS 分数
- 通过传递城市评分、评分计数、正面评价计数和负面评价计数来获取评分贡献权重。这次(T 和 Q 参数直接从 RatingExtractor 类中的 new 方法传递。
- 通过使用 CS 分数和评级权重,使用 calculate_final_score 方法(在前面章节中实现)计算最终分数。
- 获得最终得分最高的前 5 个城市,并以 JSON 的形式返回
请求
我们将向 request.py 文件中添加新的请求,以便使用新方法获得 3 个类别的建议
首先,让我们添加一个方法来从 RecommenderEngine 类中检索具有新实现的建议:
def get_recommendations_include_rating_count_threshold_positive_negative_reviews(keywords):
return RecommenderEngine.get_recommendations_include_rating_count_threshold_positive_negative_reviews(keywords)
现在让我们添加新的请求,用新的方法获得 3 个类别的推荐。
# Version 4 requests are below:top_5_cultural_with_rating_count_threshold_reviews = get_recommendations_include_rating_count_threshold_positive_negative_reviews(culture_keywords)
city_names_for_cultural_rating_count_threshold_reviews = get_top_5_city_names_out_of_json(top_5_cultural_with_rating_count_threshold_reviews)
print(city_names_for_cultural_rating_count_threshold_reviews)
print("#################")top_5_summer_with_rating_count_threshold_reviews = get_recommendations_include_rating_count_threshold_positive_negative_reviews(beach_n_sun_keywords)
city_names_for_summer_rating_count_threshold_reviews = get_top_5_city_names_out_of_json(top_5_summer_with_rating_count_threshold_reviews)
print(city_names_for_summer_rating_count_threshold_reviews)
print("#################")top_5_party_with_rating_count_threshold_reviews = get_recommendations_include_rating_count_threshold_positive_negative_reviews(nightlife_keywords)
city_names_for_party_rating_count_threshold_reviews = get_top_5_city_names_out_of_json(top_5_party_with_rating_count_threshold_reviews)
print(city_names_for_party_rating_count_threshold_reviews)
print("#################")
上面的代码将获取推荐以及它们的最终分数,你可以运行它并查看你得到的所有类别的结果。我将省略最后一章的结果调查,因为这些实现的影响在本文开始时已经讨论过了。我会把文化、艺术和历史的结果留给你们:
[('Athens', 0.2622560540924768),
('Milan', 0.2040068651858985),
('Rome', 0.16752794267650856),
('Stockholm', 0.14984473241175314),
('Barcelona', 0.14831614523091158)]
但我强烈建议您调查所有类别的结果,转到第 3 章并在这里比较结果,有什么不同,为什么?检查数据集以找到答案,如果您有任何问题,请告诉我:)
结论
在这个版本中,我们实现了一种方法,将不同形式的反馈整合到推荐系统中。我们的方法是用一些定制的技术将评审反馈转换成评级反馈。
通过这一章,我们已经结束了推荐系统的实现。总的来说,我们已经实现了一个系统,在我们对用户几乎一无所知的情况下提出建议,只让他们选择一个类别(冷启动问题),并在每章的基础上采用迭代方法。我希望你喜欢这篇文章,如果你有任何问题,请告诉我。此外,由于所有这些实现都是我自己的想法(自定义函数,公式和技术),它们当然不是完美的,正如我们所看到的,有一些权衡。因此,如果您能在评论中告诉我如何改进,我会很高兴:)
你可以在这里下载项目的最终版本。
干杯!
额外的
您可能想知道为什么数据集中没有使用某些要素。正如我前面提到的,这些实现来自我的 MSc 项目,当我通过 Flutter 为移动设备开发 UI 时,我使用了其中的一些特性。您可以在下面看到应用程序的截图:
Images from the application
请让我知道你是否有兴趣通过 Flutter 为这里实现的推荐系统建立一个 UI。也许我也可以发布构建应用程序的帖子:)
保重!
Python 中的推荐系统第一部分(准备和分析)
就像我几天前做的 Kickstart 活动分析项目一样,今天我将分析电影评级。如果你错过了上一篇文章,这里有它的链接:
让我们探讨一下 Kickstarter 活动的一些注意事项
towardsdatascience.com](/analyzing-380k-kickstarter-campaigns-10649bbf4e91)
推荐系统是大多数较大的(和较小的)网上商店、像【网飞】这样的电影/电视节目网站以及许多其他网站的核心。根据维基百科,这是“官方”的定义:
推荐系统是信息过滤系统的一个子类,它试图预测用户对一个项目的“评分”或“偏好”。它们主要用于商业应用。[1]
存在两种主要类型的推荐系统:
- 协作过滤(Collaborative Filtering)——基于这样的假设:过去同意的人将来也会同意,并且他们会像过去一样喜欢相似种类的项目
- 基于内容的 —基于项目的描述和用户偏好的配置文件。他们将推荐视为特定于用户的分类问题,并根据产品特征学习用户喜欢和不喜欢的分类器。
当然,这两者之间存在一些派生,但目前这已经足够了。让我们把重点放在这篇文章要讲的内容上。
为什么要看这篇文章?
有两个主要好处:
- 你将深入到推荐系统的世界中——有很多有趣的事情要做,也是添加到简历中的一件好事
- 您将经历另一个探索性的数据分析过程,进一步提高您在该领域的技能
听起来像是对你有益的事情? 好,我们开始吧。
这篇文章的结构是怎样的?
这是我将要写的关于推荐系统的两篇文章中的第一篇。它涵盖了数据收集、探索性数据分析和数据可视化的过程。虽然这篇文章不会完全涵盖创建推荐系统的过程,但是每个数据科学项目都必须首先熟悉数据本身。
如果你想知道,本系列的第二篇文章将介绍如何用 Python 从头开始构建推荐系统,所以那篇文章将是本系列的核心,而这篇文章将会让你感到温暖。
帖子内容如下:
- 数据收集和导入
- 基础数据准备
- 探索电影发行年份
- 评级探索
- 电影类型探索
- 按流派计算评分
- 可视化评级数量
- 结论
是的,我知道你在想什么,我也知道有很多事情要谈。但我会尽量简短,尽可能切题。
数据收集和导入
数据集可以在官方 GroupLens 网站上找到。所以去那里选一个你喜欢的吧。它们分为几种尺寸:
由于较大的内存问题,我下载了第一个。如果你的电脑比我的更强(I5–8300h,8GB 内存),请随意下载任何更大的。但是话说回来,如果你不想等待计算完成太久,下载 100K 数据集,结果一般不会有太大变化。
好了,数据集下载了吗? 我们用 Python 导入吧。这里是您需要的所有库,以及 CSV 读取和合并过程:
Imports — https://gist.github.com/dradecic/61ceda3fcf0c2619f2b62774f88439e7
完成后,数据集将如下所示:
基础数据准备
我必须向你承认,我在整个数据清理过程中撒了谎。这个数据集不会有,因为它已经尽可能干净了:
一个价值都没有丢失,这种情况很少见。上帝保佑教育数据集!
从数据集标题可以推断,有 100K 个条目。但是电影有多少?
在 10K 周围。很好,实际上,我认为这将足以对电影市场得出一些一般性的结论。
探索电影发行年份
这一步需要做一些准备。我们的目标是分析电影发行年份的分布,但是这些信息还没有以预期的形式出现。
出版年份在标题栏中,在标题的末尾用括号括起来。然而,对于一些电影来说,情况并非如此,这使得提取过程有点困难。所以,逻辑如下:
- 如果存在出版年份,请删除括号并保留年份的整数表示
- 否则,将 9999 作为年份,这是缺少年份的明显标志
该代码块实现了所描述的逻辑:
Years — https://gist.github.com/dradecic/d3224dfd866d8444fd03cc3cfd4cb526
事实证明,只有 30 个实例没有年份信息,这并不可怕(因为我们有 100K 行)。现在让我们绘制一个这些年(不包括 9999 年)的柱状图。代码如下:
Histogram — https://gist.github.com/dradecic/f6c28a9cb3f0f04b74c2bccf35b811a5
一旦这个单元的代码被执行,下面是结果图表:
看起来,大多数电影都是在 1995 年到 2005 年之间上映的。
评级探索
此处可以使用来自 make_histogram 函数的逻辑,无需任何其他准备或数据操作,即可绘制电影评级的直方图。只要确保将 评级 作为属性传递,而不是 电影年份 。
看起来平均评分会在 3.5 左右,而且看起来用户更倾向于给满分而不是 0.5。
电影类型探索
与出版年份一样,需要做一些准备。看看流派栏是什么样子的:
没有办法像现在这样分析它。我想完成以下任务:
- 拆分竖线(|)字符上的字符串
- 为每个流派创建一个新条目
所以,1 行冒险|动画|儿童|喜剧|奇幻应该变成 5 行,其他信息保持不变。熊猫提供了一个很好的方式来实现这一点:
Genres — https://gist.github.com/dradecic/179d68a33510f8f25291e27c0b86eca1
这样就创建了一个新的数据帧,前几行如下所示:
这 5 行现在代表原始数据集中的 1 行,所以,是的,这就是我的笔记本电脑在大型数据集上失败的地方— 它无法在内存中容纳 1 亿行。
类似地,我现在可以声明一个绘制条形图的函数:
Bar Chart — https://gist.github.com/dradecic/1f1d1519e55e3875942c927136161603
我知道为一张图表做了很多准备,但这是值得的:
大多数电影都属于 剧情类 或 喜剧类 类别——这里没什么稀奇的。
按流派计算评分
获得这些信息可能是这篇文章中最困难的任务。这主要是因为它涉及到一些准备工作,背后的逻辑可能不像前面那样直观。您需要:
- 计算每部电影在单个流派级别上的评级(流派字符串由| 分割)
- 将每种类型的分级列表添加到词典中
- 计算平均评分,作为字典中列表的平均值
听起来让人迷惑?
Rating by Genre — https://gist.github.com/dradecic/7a65cac23c59c8206417ec26a6411641
在这里,您可以轻松地按流派划分等级:
似乎黑色电影做得最好,但是,这种类型的电影数量最少。 恐怖 电影做得更糟,这是有道理的,有一吨只是可怕的恐怖。纪录片和战争电影往往比大多数电影都要好,这也是有道理的——每个人都喜欢一部好的二战电影,如果它以纪录片的形式呈现,我会给它打五星!
可视化评级数量
你已经完成了最后一部分,干得好!现在让我们深入了解一下评级可视化的数量。它也将涉及一些准备工作,但没有什么要求。您必须:
- 创建一个数据帧,将 movieId 列分组,并对实例进行计数
- 将其与原始数据集合并
- 重命名合并时出错的列
Num Ratings — https://gist.github.com/dradecic/ef33ad4c942c2d013def6ed0c4945bc8
在进入可视化之前,我们先来看看根据收视率排名的前 10 部电影:
Top 10 — https://gist.github.com/dradecic/a5a6a669de0d6b380cad745d57a231f0
我对结果相当满意。这些顶级的都是经典之作,值得拥有。
为什么按收视率数量而不是纯收视率排序?
啊,问得好。原因是,我想避免被评为 5 星的电影,但只有一个或几个用户。如果这些电影足够受欢迎,会有更多的用户对它们进行评级,那么它们就是不相关的。
你现在可以绘制一个直方图的 列和 列:
这是意料之中的。大多数电影没有很好的预算,总的来说,这导致了一部不太受欢迎的电影。如果电影不流行,大多数人不会看,因此,不会评价它。爱它或恨它,这就是它的工作方式。
最后,让我们用一个很好的评分与评分数量散点图来结束这一部分。代码如下:
Scatter Plot — https://gist.github.com/dradecic/874c6f56bc1d92d3de45f6c170a5837f
下面是我的图表的样子:
你可以在这里看到一个趋势——随着电影获得更多的评级,其平均评级往往会增加。如果你仔细想想,这也很有道理。如果越来越多的人在看一部特定的电影,它可能有很好的预算和很好的营销,这将意味着它是某种类型的大片,他们通常评价很高。
结论
这是一个很长的帖子,我知道。然而,它涵盖了探索性数据分析的每一个重要部分。现在你对数据本身更熟悉了,这意味着你在进一步的分析中不太可能犯一些愚蠢的错误。
下一篇文章将在几天后发布,在这篇文章中,你将创建你的第一个(可能是)推荐系统。它将被链接到这里,所以请把这篇文章放在你身边(这听起来很奇怪)。
[## Python 中的推荐系统——第二部分(基于内容的系统)
深入推荐系统的神奇世界,并自己构建一个(第 2 部分)
towardsdatascience.com](/recommender-system-in-python-part-2-content-based-system-693a0e4bb306)
你有什么想法?你的分析中还包括了其他内容吗?如果有,请在评论区分享。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
资源
[1]https://en.wikipedia.org/wiki/Recommender_system
Python 中的推荐系统——第二部分(基于内容的系统)
欢迎来到 2 部分系列的第二部分。这篇文章将着重于从以前探索过的电影数据集中开发一个简单的、基于内容的推荐系统。整个数据探索和分析已在第一部分完成,如果您错过了,请点击以下链接:
深入推荐系统的神奇世界,自己构建一个(第 1 部分)
towardsdatascience.com](/recommender-system-in-python-part-1-preparation-and-analysis-d6bb7939091e)
我不得不说,今天的帖子会比上一篇短得多。最主要的原因是,没有太多的推荐系统(在这个基础层面至少有)。话虽如此,今天的帖子将向您解释一个简单的基于内容的推荐系统背后的直觉和逻辑(如果您不知道什么是基于内容的系统,请参见第 1 部分),您将看到这里没有实际的机器学习,只有高级的(类似于)过滤。
你为什么要读这篇文章?
与前一篇文章一样,它有两个主要好处:
- 您将深入推荐系统的世界,并构建您的第一个(可能是)
- 你会发现它们比看起来要简单
这篇文章是如何组织的?
前面我说了,这一部分会比上一部分短很多,上一部分涵盖了数据收集、准备和探索的过程。阅读那篇文章是的先决条件,因为如果你不阅读它(或者至少复制其中的代码,你的数据将不会与我的数据格式相同,因此你将无法继续。
帖子内容如下:
- 矩阵创建
- 创建获取推荐的函数
- 获取和验证结果
在开始之前,数据集应该是这样的:
弄成这个形状?你可以继续了。
矩阵创建
对于矩阵,我的意思是您应该以某种方式创建具有以下内容的表:
- 每个用户 ID 作为一行
- 每个电影标题作为一个专栏
- 将每个用户对每部电影的评价定为行和列的交集
这很容易通过熊猫pivot _ table()函数获得:
Movie Matrix — https://gist.github.com/dradecic/339da863583482ef8fc67770e1a40bd7
这个矩阵本质上是一个熊猫 DataFrame 对象,通过知道你知道你可以调用 。头()在上面:
是啊,很多 男 ,我都知道。花一分钟思考为什么这么多的值丢失了,然后继续阅读。
你拿到了吗?
原因是,并不是每个人都看过每部电影并对其进行评级。这个表里面有 9700 多部电影,你自己想想吧。你看了多少部电影?在你看过的人中,你公开评价了多少?没那么多吧?
现在你有了矩阵,你可以进行下一步了。
创建获取推荐的函数
这是邮报的主要内容。如果这是你的第一个推荐系统,你会惊讶地发现做一个是多么容易,至少在初级水平上是这样。
下面是你必须实现的逻辑:
- 计算所需电影与其他电影的相关性(使用 )。corrwith()法)
- 将具有相关性的电影标题存储在单独的数据帧
- 将数据帧与原数据帧合并,删除重复数据,保留 标题 、 相关 系数、编号列
- 按相关性降序排序(从最大相关性到最小相关性
- 过滤掉收视率低的电影(那些电影是不相关的,因为它们只被少数人看过
- 返回 top n 相关电影
听起来工作量很大,但实际上只有 10 行代码。
The Function — https://gist.github.com/dradecic/322359d1bf36de305c55a8fc539fec75
如您所见,我已经设置了作为默认函数参数返回的过滤器数量和电影推荐数量,因此它们更容易调整。
简而言之,这就是你需要实现的全部逻辑。
容易吧?
获取和验证结果
获得推荐的过程现在就像函数调用一样简单。你需要传入的唯一参数是电影标题,并且它必须与数据集中存在的那个相同,每个小小的拼写错误都会破坏一切。请随意使用这个函数来解决这个问题。
如果我现在拿到低俗小说电影的推荐:
第一个显而易见,低俗小说与低俗小说完美关联,但看看之后的几个。
看看 IMDB 给了这部电影什么推荐。很酷,对吧?
Obtained from IMDB on 29th September 2019 — https://www.imdb.com/title/tt0110912/?ref_=tt_sims_tt
我现在可以对电影玩具总动员做同样的事情:
很明显这些建议是有效的,但是让我们确认一下以防万一:
Obtained from IMDB on 29th September 2019 — https://www.imdb.com/title/tt0114709/?ref_=nv_sr_3?ref_=nv_sr_3
《怪兽电力公司》和《海底总动员》是 IMDB 上的前 6 个推荐,而《超人总动员》在下一页。
结论
推荐系统做起来很有趣,也很容易验证(至少在这种情况下)。我希望在读完这篇文章后,你不会把它们看作是黑盒,因为它们基本上可以归结为用 Python ( 或你选择的语言)进行一些数据操作。
你考了哪些电影?你对结果满意吗?请让我知道。
使用贝叶斯个性化排序的推荐系统
用矩阵分解直观理解贝叶斯个性化排序优化准则
在这篇文章中,我将讨论贝叶斯个性化排序(BPR),这是推荐系统中使用的著名的学习排序算法之一。在深入 BPR 算法的细节之前,我将概述一下推荐系统是如何工作的,以及我的音乐推荐系统项目。这将有助于一些第一次阅读推荐系统的人,并作为其他人的复习资料。
内容:
- 概观
- 学习推荐系统
- 使用交替最小二乘法的矩阵分解
- 使用贝叶斯个性化排序的矩阵分解
1。概述
在网飞奖诞生的早期,大多数推荐系统都是基于显式数据(评分数据)的,用户明确地给出评分来表达他们的观点。从那以后,很多事情都变了。随着数据收集技术的增强和在客户中给出明确评级的趋势的减少,隐式反馈数据在学术界和工业界都变得更加流行,以构建健壮的推荐系统。
隐含数据
隐式数据就是我们从客户那里收集的反馈,包括点击量、购买量、浏览量等。隐式数据的主要特征是
- 无负面反馈:在显性数据中,客户明确表达了他们的正面和负面反馈。其余没有值的数据点被视为缺失值。但在隐性数据中,我们只有正面反馈,如点击、购买等,没有办法判断缺失的数据是因为客户不喜欢该商品还是没有意识到这一点
- 固有噪声:尽管隐式数据固有噪声,但其庞大的数据量弥补了这一缺陷,有助于构建健壮的推荐系统。
- 偏好与信心:在显性数据中,评级专指客户的偏好,用数值表示偏好的大小。在隐含数据的情况下,数值通常指的是频率,它不一定反映客户偏好的大小。因此,需要推导出显示客户信心的信心度量
潜在因素模型
对于隐式数据,潜在因素模型提供了邻居模型(基于相似性度量的模型)的替代方法,有助于揭示用户和项目的潜在特征。这种模型的例子是矩阵分解、潜在语义模型、潜在狄利克雷分配等。其中,矩阵分解由于其吸引人的准确性和可扩展性而变得更加流行。
虽然一个简单的奇异值分解为此目的工作,但它遭受过拟合,这将我们带到下一组涉及正则化的模型。
2。学习推荐系统
学习推荐系统就是这样一种方法,其中矩阵分解可以转化为一个带有损失函数和约束的优化问题。在这种方法中,我们在优化过程中从一系列推荐器中选择最佳推荐器。这种方法的最终结果是一个潜在因素模型,它帮助我们使用参数估计方法来揭示用户和项目的潜在特征。
为了详细说明这一点,让我们看看学习推荐系统的结构
Figure 1
如上图所示,学习推荐系统有 3 个组成部分:
1。型号:
模型可以是矩阵分解模型或线性回归模型。它有一些参数,如矩阵分解中的矩阵,我们将在此过程中进行优化。在我们的例子中,模型和参数一起构成了推荐系统
2。效用函数或损失函数:
这就像我们在机器学习算法中的任何其他损失函数一样,将被最小化以达到最优解
Equation 1
θ:推荐模型的参数,如矩阵分解中的用户矩阵和项目矩阵。
g(θ):我们试图最小化的损失函数
3。优化算法:
我们可以选择任何符合我们目的的优化算法。对于隐式数据,最好的优化算法之一是交替最小二乘法
3.使用交替最小二乘法的矩阵分解
这些推荐系统的性能通常取决于所使用的优化算法。
你猜对了。下一部分是关于优化算法,我们越来越接近贝叶斯个性化排名。
交替最小二乘法
交替最小二乘法(ALS)就是这样一种算法,由胡一帆、耶胡达·科伦和克里斯·沃林斯基在针对隐式反馈的协作过滤中提出。如果你不知道这个算法,我强烈建议你阅读这篇由 Victor 撰写的文章,以详细了解 ALS。然而,为了保持贝叶斯个性化排序方法的逻辑连续性,我将简要概述 ALS 模型。
ALS 是一种算法,通过在特定迭代期间保持一个向量不变来迭代地优化用户和项目潜在向量。
在他们的论文中,胡一帆和其他人提出了这样一个概念:在执行一个动作时,把自信归因于用户的选择。他们制定了一个新的平方损失函数,其中包括偏好和信心指标,反过来将使用 ALS 方法进行优化。
损失函数:
Equation 2
徐和易分别是用户潜在向量和项目潜在向量。
崔:置信度度量
pui : 偏好指标
实施 ALS 创建音乐推荐系统
为了更好地理解使用 ALS 的推荐系统,我实现了这些概念来创建一个使用开源音乐数据集(lastfm 数据集)的音乐推荐系统。在构建这个音乐推荐系统时,我从 Ben Frederickson 和 Jesse Steinweg-Woods 的作品中获得了灵感和一些代码帮助。
您可以在我的 github 资源库中找到该项目的代码。
[## akhilesh-Reddy/基于隐含数据的推荐系统
基于用户所听歌曲的数量和类型的音乐推荐系统|实现了约 90%的 AUC
github.com](https://github.com/akhilesh-reddy/Implicit-data-based-recommendation-system)
结果
我使用 AUC 度量作为这个推荐系统的评估标准。值得注意的是,这个数据集非常稀疏,当我对 40000 名用户和 100000 名艺术家进行采样时,稀疏度为 99.9%。尽管数据集中有很大的稀疏性,推荐系统给出了大约 90%的 AUC 值。
尽管该算法在查找相似艺术家方面表现更好,但在向特定用户推荐艺术家方面,我并没有获得令人满意的结果。这就把我带到了这篇文章的最后一部分。
为什么要贝叶斯个性化排名?
尽管胡一帆的 ALS 方法使用置信度和偏好度量减少了缺失数据的影响,但它并不直接优化其用于排名的模型参数。相反,它优化预测一个项目是否被用户选中。贝叶斯个性化排名优化标准涉及成对的项目(两个项目的用户特定顺序),以便为每个用户提供更个性化的排名。
首先,很明显这种优化是在实例级(一项)而不是像 BPR 那样在对级(两项)。除此之外,它们的优化是最小二乘法,已知对应于正态分布随机变量的最大似然估计。然而,项目预测的任务实际上不是回归(定量),而是分类(定性),因此逻辑优化更合适。—
Steffen Rendle,Christoph Freudenthaler,Zeno Gantner 和 Lars Schmidt-Thieme 在 BPR:根据隐式反馈进行贝叶斯个性化排序
使用贝叶斯个性化排序的矩阵分解
个性化排序的主要任务是向用户提供排序后的项目列表。在下一节中,我总结了这种方法,尽量减少数学方程的数量,以方便第一次阅读的读者。关于数学的详细理解可以参考原文。
数据准备:
设 U 是所有用户的集合,I 是所有项目的集合。下图显示了在一般项目推荐者的情况下,隐式数据是如何处理的。
Figure 2
通常的方法是预测项目的个性化得分 xui,该得分反映了用户对该项目的偏好。之后,项目将根据该分数进行排名。如上图所示,用户和项目之间的所有现有交互被标记为正类(1),其余交互被标记为负类(0)。
这意味着,如果我们的模型与训练数据完全吻合,它将以同样的方式对待训练数据中不存在的所有相互作用,因为它们都被标记为 0。这种方法在将来的推荐中不一定考虑排名。
在 BPR 方法中,项目对将被视为训练数据,而不是取一个项目。将基于这些用户-项目对的排名来执行优化,而不是仅仅根据用户-项目交互来评分。将被考虑的数据集被公式化如下
Equation 3
(u,I,j) ∈ DS 的语义是假设用户 u 更喜欢 I 而不是 j。
Figure 3
这里,为训练数据生成的三元组是一对项目之间的用户特定的成对偏好。
在上图中,用户 u1 已经查看了项目 i2,但没有查看项目 i1,因此该算法假设该用户更喜欢项目 i2 而不是 i1( i2 > i1 ),并给出一个正号。无法推断用户对既已看到又显示为的项目的偏好。马克。对于用户还没有看到的两个项目也是如此(例如,用户 u1 的项目 i1 和 i4)。相反,您可以观察到(i1,j2)的负号,因为用户更喜欢 item2 而不是 item1。
业务流程重组选项
像在任何贝叶斯方法,我们有一个似然函数,先验概率和后验概率。
为所有项目 i ∈ I 找到正确的个性化排序的贝叶斯公式是最大化以下后验概率,其中θ表示任意模型类的参数向量(例如,矩阵分解)。
似然函数
Equation 4
这里,> u 是用户 u 的期望但潜在的偏好结构。同样重要的是要注意,p( >u | θ)是用户特定的似然函数。
假设用户将独立行动,并且特定用户的每对项目(I,j)的排序独立于每对其他项目的排序,我们可以将用户更喜欢项目 I 而不是项目 j 的个体概率公式化如下:
Equation 5
上述等式中的 x^uij(θ)是表示用户 u、项目 I 和项目 j 之间的关系的实值函数,并且通常通过使用矩阵分解模型来计算。换句话说,捕捉用户 u、项目 I 和项目 j 之间的关系的分数将使用三元组训练数据和矩阵分解来计算,并且被包装在 sigmoid 函数中。该 sigmoid 函数给出了在该过程中将被优化的个体概率。
先验概率
p(θ)是先验概率,它是具有零均值和方差-协方差矩阵的正态分布
Equation 6
BPR 标准
以下等式是最终的 BPR-OPT 标准,必须进行优化
Equation 7
其中λθ是模型特定的正则化参数
为什么要记录可能性?
现在我们有了概率函数,评估它的一个常用方法是对数似然函数。
使用对数函数的原因是数值稳定性。事实证明,对于非常大的数据集,我们有可能获得非常低的概率,而系统很难记录这些概率。通过取概率的对数,我们得到一个总和,而不是每个点的概率的乘积,这将有效地存储在计算机存储器中。
类比 AUC 优化
对于不了解 AUC 的人来说,它是 ROC 曲线下的面积,该曲线以真阳性率作为 y 轴,假阳性率作为 x 轴,用于所考虑的模型的各种阈值。换句话说,对于一组项目推荐,我们可以通过计算每个阈值的好项目推荐百分比和坏项目推荐百分比来绘制 ROC 曲线。
有趣的是,AUC 指标是一个基于排名的指标,也可以被视为正确排名点的百分比。
从数学上来说,分类器的 AUC 等于该分类器将随机选择的正例排序高于随机选择的负例的概率。
为我们的用例实现 AUC 定义为我们提供了以下等式:
Equation 8
s(I;u)> S(j;u)是我们之前讨论过的 x^uij 分数。
函数 1{foo}是一个不可微的 Heaviside 函数。优化 AUC(基于秩的度量)的一般做法是用类似 sigmoid 函数的可微分函数代替 Heaviside 函数。在我们的例子中,我们选择了对数(sigmoid)。这个概念总结在下面的 论文 。
Heaviside function
Figure 4
AUC 与 BPR-OPT 的比较
Equation 10
针对 BPR-OPT 标准的优化将类似于针对 AUC 的优化,AUC 是一种基于排名的指标,我们可以从上面的等式中看出。
使用自举的梯度下降
在这种情况下,当标准是可微的时,明显的选择是在优化标准上使用梯度下降。但在这种情况下,模型遍历训练对的顺序至关重要。遵循一般的随机梯度方法将导致较差的收敛性,因为在相同的用户-项目对上有如此多的连续更新,即对于一个用户-项目对(u,I),有许多具有(u,I,j) ∈ DS 的 j。
为了解决这个问题,在该算法中采用了自举方法。不是以连续的顺序获取数据点,即对于特定用户的所有项目(I)和项目(j ),而是随机获取数据点导致更快的收敛。BPR 方法的作者已经从经验上证实了这一点。
通过使用梯度下降优化 BPR-OPT 标准计算 xuij
这篇文章的最后一步是了解矩阵分解模型如何计算 x^uij 分数。矩阵分解通常试图模拟用户对某个项目的隐藏偏好。它是每个用户项目对(u,I)的实数 x^ui。
由于我们的数据中有三个一组,估计量 x^uij 将分解如下:
Equation 11
我们可以使用任何标准的协同过滤模型代替矩阵分解来预测 x^ui 和 x^uj.BPR-OPT 标准是对任务进行排序的最佳标准,因为我们正在对两个预测的差异进行分类(x^ui -x^uj).
Ben Frederickson 的隐式打包有一个用于 BPR 的模块,对于任何数据集都很容易实现。您可能想看看如何用 python 为您的推荐系统实现这种方法。
这是所有的乡亲。我希望你现在对贝叶斯个性化排序方法有了很好的理解。我将把这作为我的音乐推荐系统的下一步来实现,并检查它在我的推荐排名方面的表现。
请继续关注未来几周关于数据科学和数据可视化统计的更多帖子!
参考
[1]http://citeseerx.ist.psu.edu/viewdoc/download?doi = 10 . 1 . 1 . 2 . 3727&rep = rep 1&type = pdf
[2]https://www . ka ggle . com/otmanesakhi/the-rank-statistic-differentiable-AUC-estimate
3http://www.benfrederickson.com/matrix-factorization/
[4]http://www . benfrederickson . com/fast-implicit-matrix-factorization/
[5]https://medium . com/radon-dev/als-implicit-collaborative-filtering-5ed 653 ba 39 Fe
https://arxiv.org/ftp/arxiv/papers/1205/1205.2618.pdf
推荐系统和超参数调整
机器学习中(经常)被遗忘的孩子
每一个有互联网连接的人都受到推荐系统(RS)的影响。
Spotify suggestions to
几乎所有的媒体服务都有一个特定的部分,系统会在那里向你推荐一些东西,比如网飞的一部电影、亚马逊的一件商品、Spotify 的一个播放列表、脸书的一个喜欢的页面等等。在我们日常使用的几乎所有服务中,我们都至少看过一次“你可能喜欢这个”部分;背后的算法是一个推荐系统。
有些人可能会认为简历是一个试图比你自己更了解你并给你所需要的东西的系统。如果你这么说的话,听起来有点(也许很多)令人毛骨悚然,但它的目标是通过了解你的喜欢和不喜欢,让你的体验变得尽可能好。
像机器学习(ML)的所有应用一样,RS 的前景是从大量数据中学习,然后对新的输入数据进行预测,其中 RS 中的预测可以被视为用户是否喜欢推荐项目的分类问题。尽管从数据存储方式(稀疏矩阵)到仅适用于 RS 的方法和模型都有明显的差异,但所有 ML 应用程序遵循的步骤都是相同的:
- 数据可视化
- 数据预处理
- 选择模型
- 培养
- 估价
- 超参数调谐 (HPT)
虽然前 5 步都很好,但我在论文中遇到的最后一步是:超参数调整。在 RS 中进行 HPT 的可能方法缺乏材料和实际的例子,通常什么是最好的等等,这是非常突出的,这是写这篇文章的灵感来源。
温柔推荐系统介绍
RS 算法的设置与任何其他 ML 应用程序相同,但有两个关键要素除外:
- 数据存储:在 RS 中,数据存储在稀疏矩阵中,更准确地说是存储在两个矩阵中, URM (用户评级矩阵)和 ICM (项目内容矩阵)。一个 URM,一个 UserxItem 矩阵,包含关于用户偏好的所有信息,也就是说,在一行中,我们有用户对服务提供的项目所做的评级(显式或隐式)。相反,ICM 是一个保存所有项目元数据的矩阵,其中每一行都包含一个项目的所有信息。
- 方法:可分为三种类型。
- 基于内容的:我们利用项目的特征(元数据)来寻找其他与之相似的项目,然后向用户推荐与用户已经感兴趣的项目相似的项目。用更实际的话来说:对于一个喜欢/看过/评价电影《大美人》的用户来说,你推荐像《青春》这样的电影,是因为他们有一些共同点,比如导演(保罗·索伦蒂诺)、相同的流派(戏剧、喜剧)、关键词等等。
- 协同过滤:利用了这样一个事实,即尽管人们可能不同,但在偏好方面存在模式,因此两个具有相似偏好的用户,我们向其中一个推荐其他人喜欢但该用户不知道的项目。
- 混血儿:前两者通过旧方式组合而成
一旦你准备好了数据,也就是矩阵,并选择了使用的方法,这就是矩阵乘法的问题了。
超参数调谐
我们在模型调整中所做的是塑造我们的模型,目标是在看不见的数据(测试集)中获得尽可能好的分数。在跳到 HPT 可以做的方式之前,首先我们需要知道什么是超参数(HP)。
在 ML 中,超参数是模型不会自己学习的参数,但我们必须在模型开始学习之前提供给模型,例如神经网络中隐藏单元的数量、随机森林中的树的数量、KNN 最近邻居的 K 个数量等。
关键是 HP 本身需要被学习:我们事先不知道一个神经网络中的 10 个隐藏单元是否是我们问题的最佳选择,或者 1000 个是否更好,随机森林中的 50 棵树是否会比 100 棵树产生更好的性能,等等。因此需要做 HPT。
HP 不要与参数混淆:虽然 HP 是由我们提供给模型的,但参数是在模型通常的黑盒中自动学习的。
通过快速搜索,您会发现 HPT 最基本、最常用的方法是:
- 手动:我们可以回到用两块石头生火的时候
- 网格搜索(GS) :稍微好一点了
- 随机搜索:你开始看到光明了
- 贝叶斯优化(BO) :现在我们来谈谈
对 HPT 方法的这种考虑背后的主要原因仅仅是由于一个事实:时间。为您的问题找到最佳惠普所花费的时间至关重要,尤其是在必须实时提供建议,并根据您在线插入的信息进行更新的领域。
为了证明所有这一切背后的争论,我举了一个相当简单的例子来证明这一点,面对其中的两种方法:
- GS :一个简单的强力方法
- BO :一种自动化的方法,已经被证明在许多问题上优于其他最先进的优化算法。
为了不进入太多的细节,该算法用于后的范围是不是,基本事实是这些:
数据集 : MovieLens 数据集,有 1000 万次交互
RS 方法 : KNN,一种基于内容的方法,对于每部电影,我们找到与其相似的 K 部电影(最近的邻居),其中相似度是余弦相似度
训练-测试:80%-20%的分割,训练集中约有 800 万次交互,测试集中约有 200 万次交互
验证集:为了使 HPT 成为可能,我们还需要一个验证集,我通过将训练集以 80-20%的比例进一步分为训练集和验证集来生成它,所以现在我们在训练集中有大约 740 万个交互,在验证集中有 1.6 个交互
Metric:MAP @ 5(Mean Average Precision)将推荐视为一项排名任务,目标是首先向用户推荐最有可能让用户喜欢的项目。5 代表评估推荐的前 5 个项目。MAP 的值从 0 到 1。贴图值越高越好。
调整的超参数:NN(最近邻)和收缩系数
网格搜索
GS 背后的想法是用你的超参数的可能值创建一个网格,然后开始测试这些可能值的组合。
Hyper-parameters’ set of values
在我们的例子中,可能的组合是 81,这意味着用每个参数组合训练和评估我们的算法 81 次。想象一下有两个以上的参数需要调整,想象一下组合的数量会增加,因此时间也会增加。是啊,这需要更多的时间。
NN variation impact on performance (on Validation set)
Shrinkage variation impact on performance (on Validation set)
好的:通过将一个参数固定在 GS 找到的最佳值,我们改变另一个参数,以可视化性能的变化。模型对超参数的敏感性显而易见,表明了这一步骤在创建 rs 过程中的重要性。
Running time of GS
不太好:这是尝试所有组合所花的时间!
不用说,我疯狂地寻找另一种方法来完成我的模型训练的最后一步,我的研究将我引向 BO。
贝叶斯优化方法
关于 GS,手动和随机搜索,下一组要评估的超参数是在不知情的情况下产生的。这就是业务对象方法的突出之处:它使用过去做出的选择,以便为要测试的下一组值做出明智的选择,从而以搜索下一个要以更智能的方式测试的参数为代价来减少评估的数量。
随着优化的进行,在 BO 中,我们的目标是找到有界集合 X 上的函数 f (x) 的最大值(或最小值),这转化为这个特定问题意味着所考虑的函数是这样一个函数,在综合中给定来自X(HP 的所有可能值的集合)的输入 X(HP 的配置),它返回用这样的 HP 生成的模型的性能。对于业务对象流程,函数 f 是未知的,它所做的是在它之前关联 a。先验的目的是表达关于被优化的函数的假设,并且随着评估的进行,形成后验分布。然后,后验分布本身被用于驱动下一个输入(HP)的获取函数以进行评估。这是一个连续的策略,因此随着迭代次数的增加,后验的质量也增加,这反过来意味着下一个要探索的区域的质量的确定性更高。
至于其他许多关于 ds 世界的方法,你可以把它作为一个黑盒来达到你的目标,或者你可以试着做一些解包,试着理解这样的优化是如何完成的。这种方法的完整解释可以在这里阅读,这是本文所用 BO 实现的基础。如果你想读些轻松的东西,这篇文章对我很有帮助。
本例中使用的 BO 的实现是这个 Python 库。
在实践中,为了给 HPT 做业务对象,您需要定义三个基本要素:
-
参数值的范围,所以函数的定义域:
-
要优化的函数,其中您可以适应您想要的任何指标,因此该方法很方便:
-
调用函数
BO 唯一棘手的方面是,它选择连续值进行试验,如果超参数是整数,您需要进行调整;没有什么简单的铸造不能解决的。定义这三个要素,你的工作就完成了。
达到相同结果的时间差你可能会想:
BO running time
使用 GS 找到的最佳参数组合:
使用 BO 找到的最佳参数组合:
NN | Shrinkage
这些参数略有变化,但不用担心。一个简单的测试可以消除任何疑问。
Performance with parameters found by BO
Performance with parameters found by GS
时间性能上的差异是显而易见的,几乎少了 10 倍,但这两种方法都达到了目标。这绝不是一个简单的例子,可以用来证明贝叶斯优化是解决所有推荐系统问题的方法,但有趣的是,RS 在使用 BO 时也不例外。毕竟,如果数据科学中有确定性的话,那就是没有确定性的方法会在你的数据集中起作用。
实践中的推荐系统
公司如何推荐产品
by @rocinante_11
亚马逊、网飞、Linkedin 和 Pandora 等公司利用推荐系统帮助用户发现新的相关项目(产品、视频、工作、音乐),创造令人愉快的用户体验,同时推动收入增长。
在这里,我们提供了一个实用的推荐系统概述。首先,回顾了三个主要的系统:基于内容的、协同过滤的和混合的,随后讨论了冷启动、可扩展性、可解释性和开发/探索。
基于内容的推荐
在潘多拉,一个音乐团队给每首音乐贴上了 400 多种属性的标签。然后当用户选择一个音乐电台时,匹配该电台属性的歌曲将被添加到播放列表中(音乐基因组计划|Pandora,Howe|Pandora)。
这是基于内容的推荐。用户或项目具有描述其特征的简档,并且如果两个简档匹配,系统将向用户推荐项目。Stitch Fix 的时尚盒子是另一个基于内容推荐的例子。收集用户的属性(身高、体重等。)和搭配的时尚产品放在一个盒子里交付给用户(Stitch Fix|2013)。
对于潘多拉来说,创造音乐属性需要人工的努力/成本,但也有很多情况下没有这样的需求。Stitch Fix 的客户提供他们自己的偏好,Linkedin 用户提供他们自己的工作经验和技能,亚马逊上的商家提供他们的产品信息,所有这些都可以免费用于基于内容的推荐。
匹配用户和项目的一种简单方法是关键字匹配。例如,对于工作推荐,可以将工作描述与求职者的简历进行匹配。术语频率-逆文档频率通常用于为对项目或用户唯一的关键字赋予更大的权重。
一种更系统的方法是建立一个监督模型,估计用户喜欢看不见的物品的倾向。在该模型中,特征是来自用户和项目的属性(例如,工作和求职者是否在同一行业的指示变量),响应变量是用户是否喜欢该项目(例如,求职者是否会申请该工作)。
基于内容的方法计算速度快且可解释。它们可以很容易地适应新的项目或新的用户。然而,项目/用户的一些特征可能不容易捕捉或明确描述。Stitch Fix 通过让机器学习处理结构化数据,让人类处理非结构化数据(例如,用户的 Pinterest board)来解决这一问题。
协同过滤
协同过滤系统基于历史用户对项目的偏好(点击、观看、购买、喜欢、评级等)来做出推荐。).偏好可以被呈现为用户项目矩阵。下面是一个描述 4 个用户对 5 个项目的偏好的矩阵示例,其中 p_{12}是用户 1 对项目 2 的偏好。
虽然条目可以是数字的,例如网飞的电影分级预测挑战(分级范围从 1 到 5),但是在大多数应用中,它们是二进制的(例如,点击、观看、购买)。
在现实中,用户-项目矩阵可能超过数百万*数百万(例如,亚马逊、Youtube),并且大多数条目是缺失的——推荐系统的目标是填充那些缺失的条目。
在这里,我们描述了三种协同过滤相关的方法,最近邻法,以及两种创建新的潜在空间的方法:矩阵分解和深度学习。
最近邻
基于最近邻的方法基于成对的项目或用户之间的相似性。余弦相似性常用于度量距离。
偏好矩阵可以表示为项目向量
项目 I1 和项目 I2 的相似度计算为 cos(I1,I2) 。该矩阵也可以表示为用户向量
U1 和 U2 的相似度计算为 cos(U1,U2) 。注意,偏好矩阵中缺失的值通常用零填充。
对于 user_i,我们可以推荐 user_i 最相似用户喜欢的物品(user-to-user)或者 user_i 最相似物品的物品(item-to-item)。
亚马逊(Amazon|2003)、Youtube (Youtube|2010)、Linkedin (Linkedin|2014)等在实践中普遍采用了项目对项目的方法。当客户喜欢一个项目时,项目到项目系统可以快速显示与之相似的项目(每个项目的相似项目都是预先计算好的,并保存在键值数据存储中)。此外,项目对项目的推荐比用户对用户的推荐更容易解释,例如,系统可以解释为什么推荐一个项目,因为“你喜欢 X ”。
有可能与一个项目相似的项目的数量太小(在对相似性分数应用阈值之后)。人们可以通过包括相似物品的相似物品来扩展相似物品列表(Youtube|2010)。
在获得最相似的项目后,后处理步骤会很有用。(Youtube|2010)根据视频质量(例如,通过评级来测量)、多样性(例如,限制来自一个频道的推荐)和用户特异性(例如,与用户观看更多的视频相似的视频应该对用户排名更高)来对相似的项目进行排名。这三个要素与一个线性模型相结合,提供了一个最终排名。
潜在因素法
潜在因素方法创建了原始用户或项目向量的新的且通常减少的特征空间,导致实时的减少的噪声和更快的计算。
下面,我们介绍两种潜在因素方法——矩阵分解和深度学习。
矩阵分解
矩阵分解在网飞推荐挑战赛中被广泛使用,特别是奇异值分解和推荐系统的一个更实用的版本。
奇异值分解 ( SVD)将偏好矩阵分解为
U 和 V 是酉矩阵。对于 4 个用户和 5 个项目,它看起来像
其中西格玛 _1 >西格玛 _2 >西格玛 _3 >西格玛 _4 。
第一用户对第一项目的偏好可以写成
这可以用向量来表示
在 sigma 向量和第一个用户向量之间应用 entrywise 乘积,然后与第一个项目向量应用点积。可以看出 u 和 v 具有相同的长度,即它们在相同的潜在特征空间中。西格玛向量代表每个特征的重要性。
现在,让我们根据 sigmas 选择前两个特征
其可以表示为项目和用户向量,每个向量的长度为 2。
西蒙·芬克的奇异值分解
偏好矩阵中的许多条目可能会丢失,常规 SVD 存在以下问题:( 1)丢失值的估算方式可能会对结果产生不良影响。(2)考虑到所有条目,训练的计算复杂度可能很高。
在网飞挑战赛中,西蒙·芬克提出了一个可行的解决方案
在公式中,仅考虑非缺失条目 p_{ij} 。来自 i^{th} 用户的 j^{th} 项目的预计得分为
注意,用户和项目向量没有 SVD 中的单位长度,但这无关紧要,因为误差的平方和被最小化了。芬克的方法在网飞挑战赛中取得了巨大的成功,这个想法由网飞实施(网飞|2012)。
深度学习嵌入
深度学习在将各种因素纳入建模和创建嵌入方面更灵活(比矩阵分解更灵活)。例如,深度学习通过利用 skip-gram 模型来对序列信息进行建模,该模型最初用于计算单词相似度。(Airbnb|2018,Zillow|2018)
比如说,一个用户的项目序列是 item1 -> item2 -> item 3 -> item4 ->直觉是用序列中的每一个项目来预测它的相邻项目,公式化为一个分类问题,其中每一个项目都是一个类。训练数据包括每个项目的相邻 K 个项目(左 K 和右 K 个项目)。下图说明了 K = 1 的项目对。
此外,每个项目被表示为一个独热向量,其长度等于项目的数量。类神经网络将项目 one-hot 向量作为输入,并输出其相似项目之一的向量,如下图所示,使用(Item2,Item1)作为训练示例。
隐藏层是新的特征空间(或潜在空间),可以使用输入层和隐藏层之间的权重将每个项目转移到新的特征空间(本质上是原始特征的线性组合)。
在现实中,可能有数百万个项目,数十亿个示例用于训练网络。为了简化计算,可以应用负采样的思想。其思想是只更新输出项(项 1)和少量随机抽样的其他项的权重。在下面,我们突出显示需要更新的项目和权重。这使得计算速度更快。
一旦在新的特征空间中表示了每个项目,就可以计算项目之间的相似性,并且可以基于相似性分数来进行推荐。
在一些情况下,用户在转换之前访问一系列项目,例如,亚马逊用户在一系列页面浏览之后进行购买;Airbnb 用户在查看了几个房源后预订了一个房源。可以通过将购买的物品添加到每个物品的训练对(Airbnb|2018)来包含这些信息,如下图所示。以这种方式推荐的项目可以提高转化率。
混合方法
混合方法使用来自用户-项目交互和用户/项目特征的信息。
Linkedin 的“你可能想关注的公司”功能使用了内容和协作过滤信息(Linkedin|2014)。为了确定用户是否想要关注某个公司,逻辑回归分类器建立在一组特征上。协同过滤信息被包括在指示该公司是否与用户已经关注的公司相似的特征中。内容信息包括是否行业、地点等。用户和公司之间的匹配。
深度学习模型在结合协作过滤和基于内容的信息方面可以是强大的。Youtube 推荐系统(Youtube|2016)建立了深度学习模型,根据用户以前的活动(搜索查询和观看的视频)和静态信息(性别、位置等)来预测用户的观看。).观看的视频和查询被表示为嵌入。由于神经网络通常采用固定长度的输入,用户观看的视频或查询向量被平均,并与其他静态特征连接。建议将多个类别的特征嵌入到一个小得多的空间中(大致与唯一值个数的对数成正比),连续特征在 0 到 1 之间归一化(Youtube|2016)。
当用户/项目没有或很少活动时,混合方法可以依赖于基于内容的推荐,并且随着更多数据可用而变得更加准确。
冷启动、可扩展性、可解释性和开发探索
对于没有信息或信息很少的新用户/项目,无法做出准确的推荐。这被称为冷启动问题。这是依赖于用户-项目交互的协同过滤系统的典型问题。可以使用一些试探法。对于新用户,可以推荐用户区域中最受欢迎的项目。对于新项目,可以定义一些基于规则的相似性标准。例如,Airbnb 使用相同类型和价格范围的 3 个地理上最接近的房源的平均值来近似一个新房源(Airbnb|2018)。
在决定使用哪种类型的推荐系统时,可扩展性是一个关键因素。更复杂的系统需要更多的人,可能更难雇用,以更高的硬件成本来构建/维护。这可能是一个长期的承诺,因此企业应该了解增加的业务收益与增加的成本。也就是说,这里有一些构建可伸缩系统的关键要素。
离线批量计算和在线上菜。有了大量的用户和项目,人们必须离线批量计算容易获取的推荐。例如,Linkedin 使用 Hadoop 来批量处理用户项目事件数据,然后将建议加载到键值存储中进行低延迟实时查询。(领英|2014)
采样。当处理数百万用户和项目时,可以考虑抽样,随机抽样项目或用户,或者在没有显著用户参与的情况下删除项目。
利用稀疏度。在推荐系统中,用户项目偏好矩阵通常非常稀疏,大多数条目都丢失了。利用稀疏性可以显著降低计算复杂度(Amazon|2003)。
多阶段建模。Youtube 推荐系统将建模过程分为两步。在第一阶段,仅使用用户项目活动数据从数百万个候选项中选择数百个。在第二阶段,使用关于候选视频的更多信息用于进一步的选择和排序是可行的。(Youtube|2016)
规模化深度人脉。虽然在输出层中使用 softmax 或其他函数进行训练,但是在实时服务时间期间,不必计算概率,并且可以对来自最后一个隐藏层的输出使用最近邻方法。也可以考虑前面提到的负采样,以便对于每个训练示例,只更新少量的类的权重。
可解释性。从客户的角度来看,陈述为什么提出建议是有帮助的。在向用户推荐视频时,Youtube 添加了用户观看的视频的链接,并触发了推荐(Youtube|2010)。
从建模的角度来看,可解释性有助于开发人员理解和调试系统。基于内容的方法很容易理解,而协作过滤模型很难理解,尤其是在潜在空间。可以基于项目或用户的原始特征空间或潜在空间(矩阵分解和深度学习)对其进行聚类,并检查来自同一聚类的对象是否共享相似的特征。
此外,t-SNE 算法(Maaten|2018)可用于将高维空间投影到二维空间进行可视化(Zillow|2018)。拥有一个工具也是有用的,这样人们可以快速查看建议作为健全检查,例如 Airbnb 开发了一个内部探索工具来验证建议(Airbnb|2018)。
开采——勘探。推荐系统不应该过度拟合历史用户项目偏好数据(利用),以避免陷入局部最优。
首先,应该避免训练数据完全受到先前建议的影响。Youtube 包括嵌入在其他网站中用于培训的视频。在 Youtube 站点外观看的视频并非来自推荐系统,可以有效地浮出新内容(Youtube|2016)。还可以考虑将随机性注入系统中(例如,进行随机推荐)。
可以将简单的规则添加到系统中,以增加推荐的多样性。例如,在 Youtube 推荐(Youtube|2010)中,删除了彼此过于相似的视频,并且限制了来自同一频道的视频数量。
也可以应用来自多武装匪徒的方法。优步 eats 应用了置信上限,以增加推荐餐厅/菜肴的多样性(优步|2018)。置信上限的思想是使用估计成功率的上限(例如,订单率、点击率、观看率)。当一个新项目到达时没有任何信息,置信区间很宽,因此上限很高。因此,新项目将有很高的机会被推荐。随着项目获得更多的印象,估计会更准确,上限会更接近其实际价值。
关闭
本文讨论了构建推荐系统的方法和关键观点。在实践中,公司应根据准确性、复杂性和业务影响等多种因素,在现实的资源限制(例如,工程师和软件/硬件成本)下做出选择。
参考文献
【1】音乐基因组计划。潘多拉|维基百科
【2】潘多拉的音乐推荐器。迈克尔·豪|潘多拉
3Amazon.com 推荐:单品对单品协同过滤,格雷格、史密斯和约克|亚马逊| 2003
[4]YouTube 视频推荐系统。Davidson,Liebald,Liu,Nandy,Vleet,Gargi,Gupta 等人。
[5]浏览器地图:LinkedIn 的协同过滤。吴,山姆,肖恩,米图,波塞| Linkedin | 2014
6推荐:超越 5 星。网飞科技博客| 2012
【7】网飞更新:在家试试这个。Simon Funk | 2006
[8]列出搜索排名中的嵌入。mihajlo Grbovic | Airbnb | 2018
【9】YouTube 推荐的深度神经网络。Paul Covington,Jay Adams 和 Emre Sargin | Youtube | 2016
【10】类似住宅推荐的住宅嵌入。桑迪林|Zillow|2018
[11]使用 t-SNE 可视化数据。Maaten,Laurens van der,和 Geoffrey Hinton|2008
[12]用 Uber Eats 发现食物:向市场推荐。Yuyan Wang,Ning,Isaac Liu,和 Xian |优步|2018
[13]在推荐系统中使用人机处理。埃里克·科尔森|缝合修复|2013
用知识图表协调您的数据和世界
对知识图表迷人世界的全面介绍。
Featured image credits: The GDELT Project
知识是任何成功计划的核心。在数据时代,人们会认为整合知识的任务会比以往任何时候都容易。
然而,数据量、数据速度和数据准确性这三个因素使得这项任务一点也不容易。实现这一目标的有效方法是什么?
输入知识图表。
知识的图形化表示已经存在了几十年,可以追溯到 20 世纪 60 年代。
在我们的上一篇文章中,我们谈到了图形技术(数据库、处理和可视化)。我们还探讨了它如何解决阻碍数据驱动计划高效运行的多个棘手问题。
图形技术崛起的一个关键点是谷歌早在 2012 年就发布了其知识图 (KG)。
Google’s KG acquires and connects data from multiple sources so that you can see this box. Photo courtesy: Google
一些最大的技术公司的核心是知识图表。2018 年,Gartner 将 kg 纳入了技术炒作周期。
Knowledge graphs were included under the ‘Digitalized Ecosystems’ trend in the 2018 hype cycle.
Photo courtesy: Gartner
什么是知识图(KG)?
尽管有突出的学术和行业例子,围绕术语知识图有许多混乱。2016 年的论文“走向知识图的定义”探讨了这一困境,并试图提供一个定义。
你也可以在网上找到其他合理的定义。在这些定义的基础上,我尝试给出一个定义:
知识图由图形数据存储和知识工具包组成。它使用遵循本体的图模型将领域的数据存储为实体和关系。
知识工具包支持持续集成来自多个来源的数据,允许最终用户有效地查询图表,并从现有信息中进行推断。
Sample Panama papers data schema. Photo courtesy: Neo4j
Here’s how a portion of a KG may look like. Photo courtesy: Neo4j
可以把本体看作是图形数据的一种模式。这并不完全准确,但这是一个有用的开始方式。一个领域的本体以一种类似于真实世界的方式定义了它的成员(实体、关系)和它们的属性。点击阅读更多相关信息。
此外,上面提到的工具包可以提供许多高级功能,如语义搜索和机器学习(ML)能力。我的定义只涵盖了最低限度。
为什么要关心知识图(kg)?
当谷歌引入 KGs 时,他们写了一个博客,提到 KGs 如何允许用户通过“事物,而不是字符串”进行搜索。图表更接近我们的心理模型,使我们可以很容易地将数据描述为现实世界的对象。
一公斤的重量伴随着图形技术公司通常的 T4 优势。这意味着摆脱昂贵的连接操作、白板友好的数据模型、稀疏数据的有效处理,以及使用诸如 PageRank 之类的便捷算法。图表也可以帮助改善 ML 的现状。特别是,图形神经网络最近出现在新闻中。
现在,添加一个强大的知识工具包,您将获得:
- 从结构化(RDBMS)到非结构化(文本和图像)的多种来源和不同格式的数据的持续集成。
- 逻辑推理和推断能力。例如,从“A 在化学系工作”、“B 管理化学系”等关系中,系统应该推断出“B 是 A 的经理”。
- 实体解析和提取功能,用于处理杂乱的数据和事实的多个版本。下图显示了一个示例,其中一个人有两个与其姓名相关联的不同记录,这种情况必须得到解决。
first name | last name | address | phone | ------------------------------------------------------
Sal | khan | 10 m nagar | 91-0123 |
Salman | Khan | 10 Malviya Nagar | |
此外,KG 还充当了多个团队甚至整个组织的共享资源和公共接口。例如,使用来自多个部门的数据的 ML 模型需要查询 KG 的实体和关系,而不是来自多个筒仓(仓库、湖泊和 RDBMSes)的数据。
语义网和它有什么关系?
你可能经常会发现知识图和语义网在同一个语境中被提及。有一段时间,语义网技术和标准是 KGs 的同义词。现在不是这样的。
注意上面的定义并没有提到具体的标准。
使用语义 web 标准构建图表有很多好处,包括容易与使用相同标准发布的许多公共知识库集成。然而,相关的复杂性和陡峭的学习曲线可能会使其更加困难和无用。
那么,我该如何使用它呢?
以下任一方法都可以提供对 KG 的访问:
- 可视化层:可视化浏览器和直观的界面可以用来为最终用户提供图形浏览体验。这对于不熟悉编程或查询语言的领域经验丰富的用户特别有用。
- 查询层:可以使用 Sparql 、 Gremlin 和 Cypher 等语言查询存储 KG 的数据库。
An example of a query on Gremlin.
Query courtesy: Apache Tinkerpop
- API 层:能够通过 REST 或编程语言访问 KG 在开发应用程序时很有用。
野外知识图表
工业界、学术界和公共领域都有成功的例子。
- 一些最大的互联网公司,包括谷歌、微软(Bing,LinkedIn)、脸书、阿里巴巴和优步,使用 KGs 为他们的内部和外部服务提供动力。
- 像美国国家航空航天局(研究)和汤森路透(金融)这样的组织也接受了 KGs。
- CMU 的 NELL (永无止境的语言学习)是一个学术项目,试图创建一个学习阅读网页并使用 KG 存储信息的计算机系统。
GDelt 项目是一个实时的全球开放数据图。它不断从世界各地的新闻媒体中提取信息。
知识图表的挑战
知识图被用于不同的行业,它们的用例在功能上可能有所不同。但是他们在实现一个有用的知识工具包时面临的核心挑战是一样的。
- 实体歧义消除和解决:不同的源可能不同地指代相同的实体。其他时候,不同的实体可能共享属性,如名称。我们需要为图中的实体分配唯一的规范化身份。
- 知识提取和整合:尽管最近在 ML 和自然语言处理 (NLP)方面取得了进展,但从异构源(文本、RDBMS 和 pdf)中提取信息仍然是一个挑战。整合它们也不是一项简单的任务。
- 管理变化:加上身份挑战,捕捉知识随时间的演变会变得很困难。KG 可能需要存储时间偏移和历史。例如,如果一家公司被收购,如何管理其新旧身份?
- 轻松访问:用户界面可以是查询编辑器、可视化资源管理器或编程接口,如软件库或 API。
- 安全和隐私:如果要广泛部署 kg,它们必须在提供价值的同时考虑隐私和安全问题。
- 规模化经营:当规模化的挑战到来时,上述所有问题都变得更加难以解决。
在 Atlan,我们一直致力于为世界各地的数据团队解决数据民主化问题。我们每天都在应对激动人心的挑战,包括上面列出的挑战。请继续收听我们的经历。
最后的话
互联数据比以往任何时候都更加重要。能够有效地整合孤岛对于从数据中提取价值至关重要。知识图表提供了一个很好的方法来做同样的事情。它可以增强从业务用户(改进的数据发现)到数据科学家(更好的 ML 模型)的利益相关者的能力。
着手构建和操作知识图表确实会带来挑战。但是一个有效的工具包可以帮助你应对挑战。
如果你想了解 KGs 是否适合你的用例或者有疑问,请留下评论。🙂
以下是一些参考资料,它们在我为这篇文章做研究时对我有所帮助:
原载于https://humansofdata.atlan.com2019 年 8 月 22 日
谢谢你的阅读。关注我 中 了解更多内容。非常感谢您的反馈。你可以通过推特 @AkashTandon 联系到我。
重建谷歌趋势长期每日数据
比较方法以超越每日趋势数据的 9 个月查询限制。
iPhone search trends, AAPL stock price and Apple key events
- 我们可以在任何持续时间内以每日分辨率获取搜索趋势数据。
- 用每周趋势来衡量每日数据可能会产生一些假象。
- 只要在重叠期间有足够的搜索活动,使用重叠期间进行缩放会更好。
- 代码可以在这里找到。
随着谷歌获得了互联网搜索的垄断地位,随着时间的推移,我们搜索的任何内容都成为了另一种公众兴趣的衡量标准。谷歌新闻实验室已经很好地解释了这一点,一些文章展示了基于谷歌趋势的数据分析,如结束与某人关系的循环模式、预测美国总统竞选等。
局限性
为了充分利用搜索趋势数据库,可以使用 python 模块 pytrends 或 R 包 gtrendsR 。然而,google 目前基于查询的时间框架限制了时间分辨率。例如,过去 7 天的查询将具有每小时的搜索趋势(所谓的实时数据),每天的数据仅提供给短于 9 个月且在您搜索之前最多 36 个小时的查询期(如 Google Trends FAQ 所述),每周的数据提供给 9 个月到 5 年之间的查询,任何长于 5 年的查询将仅返回每月的数据。
我研究这个课题的动机最初是受到 Kaggle 的 Rossmann 竞赛的启发,在该竞赛中,谷歌搜索趋势被用来预测销售数字。我发现获取每日搜索趋势并不那么明显,人们使用每周趋势作为替代。但是,对于任何需要每日精度和实时应用的预测模型来说,它并不理想(因为每周数据只在本周结束时可用)。
比较重建每日趋势的方法
虽然人们已经想出了规避的方法(比如:这里的,这里的)。我很好奇这些方法是如何相互比较的,如何与原始的每日趋势数据最匹配。因此,我使用“iPhone”作为关键词,通过以下三种方法重建 35 个月的每日趋势数据:
- 从多个 1 个月的查询中串联的每日数据,并通过相应的每周趋势数据进行标准化。(pytrends 中实现的 dailydata 函数)。
- 查询具有大量重叠时段的多个 9 个月时段,并使用重叠时段来获得一致的缩放比例(类似于此处的目的)。
- 每日数据只是从每周数据中插入的。(供参考)
Comparing daily trend data obtained using the overlapping method(blue), dailydata method from pytrends(orange), interpolation from weekly data(green), and the overlapped period used for scaling (red)
乍一看,我们可以注意到他们给出了完全不同的结果。pytrends 的 dailydata 函数与周数据匹配得相当好,其基线值(重要峰值之间的周期)高于通过重叠方法获得的值。目前,很难说哪个更好,尽管如此,每日数据(绿线)在主要峰值附近有一些明显的下降,例如 2017 年 9 月左右的最低值。
为了验证哪些重建的每日趋势与原始数据匹配得更好,直接提取较短时期(< 9 个月)的每日数据进行比较。
Comparing daily trends data normalized differently with the original daily trends (pink)
现在很清楚,重叠方法(蓝线)与原始日数据(粉线)最匹配,橙色线的下降是由周数据缩放产生的伪影。
英国退出欧盟、谷歌趋势和英镑
为了进一步展示长期每日搜索数据的潜在优势和应用,我们使用“英国退出欧盟”作为 2018 年 10 月至 2019 年 11 月期间的搜索词。重建的每日数据与默认的每周数据(因为查询期长于 9 个月)一起绘制,以便进行比较。
Compare the daily trend reconstructed by the overlapping method (blue) with the original weekly trend (red).
有了重建的每日趋势,我们可以精确地将搜索趋势的激增与这 14 个月期间的每个重大事件相匹配。它还使我们能够比较每个不同事件日期的相对搜索量,而每周趋势失去了分辨率,相邻事件的相对搜索量被平均(或汇集在一起)。
出于好奇,我试图将英镑汇率叠加在每日趋势图上。当“英国退出欧盟”搜索达到顶峰时,英镑经常在同一天暴跌,这并不奇怪。
GBP/USD exchange rate and ‘Brexit’ search trends
也许谷歌会取消这样的限制,并在未来提供一个更方便的 API,但在此之前,缝合和缩放重叠查询可能是最好的方式,以获得长期的每日搜索趋势。
*重构每日走势和生成本文剧情的代码可以在 github 上找到。
RecoTour II:神经推荐算法
这是 python 推荐算法系列文章的第二篇。在我很久以前写的系列文章的第一篇中,我快速浏览了我使用 Kaggle 的 Ponpare 数据集实现并尝试的一些算法。你可以在回购中找到所有相关代码。在这篇文章中,我将使用亚马逊评论数据集 [1] [2],特别是 5 核电影和电视评论,来说明两种基于 DL 的推荐算法的使用:神经协同过滤 3和最近的神经图协同过滤 [4]。
在我继续之前,让我强调以下几点。我在这里所做的是,在阅读了作者的论文后,使用 Pytorch 实现了他们的原始解决方案(分别在 Keras 和 Tensorflow 中)。与 RecoTour repo 中的所有其他算法一样,我用大量细节编写了许多笔记本,从如何准备数据到如何训练和验证结果。我还加入了一些额外的功能,并根据我的喜好修改了代码。然而,当然,所有的荣誉都归于作者,感谢他们出色的论文和代码的发布,这总是令人感激的。一旦清楚了这一点,不再赘言,让我们继续讨论算法
1.神经协同过滤(NCF)
让我首先澄清一下,作者将 NCF 作为一个通用框架,在他们论文的第 3 节中,它被表述为由一系列接收用户和项目嵌入的所谓 NCF 层组成。
1.1 算法
他们最终在该通用框架的上下文中实现的特定算法被称为神经矩阵分解(NeuMF)。这个算法比较简单,所以我不打算在这里花太多时间。网上有很多帖子,你或许可以在那里找到更多信息,一如既往,我强烈建议你阅读报纸,在那里你可以找到所有的细节。此外,在前几节中,你会发现引导作者实现算法的基本原理(你知道…科学论证)。
NeuMF 由两部分组成,一部分被作者称为通用矩阵分解(GMF),另一部分是多层感知器(MLP)。GMF 实际上是用户和项目嵌入之间的元素产品。我猜是如此简单,作者甚至没有考虑包括一个数字只是 GMF。尽管如此,我还是做了一个,这就是:
Fig 1. GMF model
相应的向前传球很简单:
GMF forward pass
哪里out=nn.Linear(in_features=n_emb, out_features=1)
。
MLP 其实并不复杂。他们论文中的图 2 显示了 NCF 的一般框架:
Fig 2. MLP model. (Figure 2 in their paper)
如果我们认为神经 CF 层是一些激活的线性层,我们就有了 MLP 模型。相应的向前传球:
MLP forward pass
其中mlp
只是线性图层的Sequential
堆栈,而out
与 GMF 的相同,具有相应数量的输入要素。
一旦我们有了所有的构建模块,NeuMF 就是两者的结合。如图 3 所示:
Fig 3. NeuMF model (Figure 3 in their paper.)
形式上,NeuMF 可以定义为:
Equation(s) 1. NeuMF, all the math you need
其中φ-GMF 是 MF 嵌入之间的元素乘积。φ-MLP 是所谓的 MLP 嵌入通过一系列具有一些激活的线性层的结果,而 y_hat 只是φ-GMF 和φ-MLP 的串联的结果,通过具有 sigmoid 激活(σ)的线性层。
在代码中(即正向传递):
NeuMF forward pass
至于 NeuMF 算法本身,就是这样,真的。
1.2 培训/验证策略和结果
在我们进入下一个算法之前,请允许我简单地评论一下作者的训练/验证策略,以及我使用该策略在 Amazon Revies 数据集上获得的结果。
对于给定的用户,作者分割数据集,使得除了一个之外,该用户的所有评价项目都用于训练,而剩余的评价项目用于测试。然后,在训练期间,负面隐式反馈通过每个正面项目包括 N 个负面项目(从未评定)来表示。例如,如果用户评价了 10 部电影,并且 N =4,则在训练期间将为该用户使用 50 次观察(10 次肯定+ 40 次否定)。注意, N 负样本是每个历元随机采样的,这样算法就对用户不喜欢的物品类型有了更全面的看法(参见这里的中的 repo)。在训练期间,预测得分是对输出层应用 sigmoid 函数的结果,损失是二进制交叉熵(BCE)损失。
在测试期间,每个用户使用一组 100 个项目。其中一项是训练时没有用到的正面项目,其余九十九项是随机选取的负面项目。然后,我们预测这 100 个项目的得分,并计算排名指标。在 NeuMF 的情况下,这些是命中率(HR)和在 k 推荐值(在本例中 k=10)下的归一化贴现累积收益(NDCG)。
NeuMF 可以在有或没有 GMF 或 MLP 预训练权重的情况下运行,具有不同数量的嵌入、MLP 层等。我已经运行了许多实验(可以在 repo 的脚本run_experiments.sh
中找到),包括使用循环学习率【5】,对结果的讨论可以在本笔记本中找到。让我在这里简单总结一下。
Fig 4. Ranking metrics vs Embedding dimension for the GMF and MLP models
图 4 显示了根据嵌入数量(8、16、32 和 64)绘制的 GMF 和 MLP 模型获得的排名度量。有趣的是,使用最简单的模型(即 GMF 和低嵌入数)可以获得更好的排名指标。这表明,对于这个特定的数据集,可以通过简单的算法获得好的推荐,一般来说,这并不是不寻常的结果。尽管如此,值得一提的是,使用预训练权重的 NeuMF 算法获得了最好的结果,但是改进是微不足道的。当然,在“真实世界”中,人们可能想知道增加的复杂性是否补偿了排名指标的边际增加。
Fig 5. Ranking metrics vs BCE Loss for the GMF and MLP models
图 5 中显示了另一个有趣的发现,其中测试期间的排名度量相对于训练期间获得的 BCE 损失进行了绘制。这里可以看到 BCE 损失和排序度量是相关的,而先验地,人们可能期望相反的行为(即,反相关,BCE 损失越低,排序度量越高)。这种情况并不罕见,或许应该引起更多的关注。一旦我描述了神经图协同过滤及其相应的结果,我将在文章的结尾回到这个结果。
2.神经图协同过滤
这个算法比前一个稍微复杂一点,所以我将更详细地描述它。尽管如此,为了保持这篇文章的可读性,我将把内容限制在我认为理解算法所必需的最小限度。请一如既往地阅读这篇论文,在这种情况下,请阅读其中的参考文献。特别是用图卷积网络的半监督分类【6】和图卷积矩阵完成【7】。托马斯·基普夫和合著者为他们的论文发布的代码非常棒。让我们继续讨论算法:NGCF。
2.1。算法
Fig 6. Illustration of the user-item interaction up to order 3 (Figure 1 in their paper)
图 6 的左侧是用户-项目交互图的图示,作者称之为高阶连接。节点/用户 u ₁是为其提供建议的目标用户。我们可以看到,在第一阶( l -hop,其中 l =1),将捕获用户与项目 1、2 和 3 交互的信息。在第二阶(2-hop ),人们将捕获u₁←I₂←u2 和u₁←I₃←u₃,等等。
右边是模型方案。用作者的话说:“我们设计了一种神经网络方法,在图上递归传播嵌入。这是受图形神经网络的最近发展的启发[…],它可以被视为在嵌入空间中构造信息流。具体来说,我们设计了一个嵌入传播层,它通过聚合交互项目(或用户)的嵌入来细化用户(或项目)的嵌入。通过堆叠多个嵌入传播层,我们可以加强嵌入,以捕捉高阶连接中的协作信号。”**
让我们试着通过一些数学和代码来增加前一段的清晰度。当然,我们需要的第一个构建模块是表示图,即构建拉普拉斯矩阵,定义为:
Eq 2. Laplacian Matrix
其中 D 是对角度矩阵, A 是邻接矩阵, R 是评级矩阵,在这种情况下是具有 1/0 的二进制矩阵,指示用户是否对电影进行了评级。构建拉普拉斯矩阵发生在utis
模块内的[load_data.py](https://github.com/jrzaurin/RecoTour/blob/master/Amazon/neural_graph_cf/utils/load_data.py)
中。你会看到,按照作者最初的实现,我构建了许多不同的邻接矩阵来探索不同的场景(例如,在某些情况下,我们考虑自连接,或者在连接的节点之间使用不同的衰减因子)。一旦拉普拉斯矩阵建立,让我们移动到模型。
示意性地,上面引用的模型可以绘制成这样:
Fig 7. Illustration of NGCF model architecture (Figure 2 in their paper).
嵌入传播层(图 7 中的灰色方块)中的第一个数学运算是“嵌入聚合”(即聚合每个用户/项目的所有交互项目/用户的嵌入)。然后,聚合的结果通过一系列带有 LeakyRelu 激活的线性层传递,并与初始嵌入连接。最后,我们直接计算损失(在这种情况下,BPR 损失,见下文)。也就是说,在该特定实现中,正向传递的输出将直接是损耗值。一旦我们研究了数学和代码,所有这些都会变得更加清晰。
形式上,该模型由两部分组成:消息构造和消息聚合。
消息结构定义为:
Eq 3. NCGF message construction.
其中⊙表示逐元素乘法。1/√(|nᵤ||nᵢ|)是图的拉普拉斯范数。 Nᵤ 和 Nᵢ 是用户 u 和项目 i 的第一跳邻居。如果你看一下load_data.py
中的代码,你会发现这个因子(两个相连节点之间的衰减因子)已经通过构造在我们的拉普拉斯矩阵中被考虑了。这意味着,一旦我们在 Pytorch 实现中达到了正向传递,我们就可以只关注等式 3 中括号内的两项。
还值得提醒的是,这里 eᵢ或 eᵤ不是初始嵌入,而是聚合嵌入,即对于用户 1,eᵢ将是该用户与之交互的所有项目的聚合嵌入。从程序上来说,这可以简单地通过将初始嵌入乘以拉普拉斯矩阵来实现。我们将在后面的前传中看到。
消息聚合定义为:
Eq4. NGCF message aggregation
这只是应用于所有构造的消息的总和的结果的 LeakyRelu 激活。
一旦构建和聚合了消息,我们会根据您的需要多次重复该过程(即分层)。如果您想了解更多关于消息构造和聚合公式背后的推理,请参阅本文。易于阅读和理解。对于这个职位我需要的 Eq 2,3 和 4 就足够了。
现在让我们关注训练期间使用的损失函数,即所谓的 贝叶斯个性化排序 损失【8】。在 NGCF 的论文中被定义为:
Eq 5. BPR Loss
其中 O = {( u,I,j )| ( u,i ) ∈ ℝ⁺,( u,j ) ∈ ℝ⁻}是训练元组的集合,其中ℝ⁺和ℝ⁻分别对应于观察到的和未观察到的交互(也称为正交互和负交互)。σ是 sigmoid 函数,θ都是训练参数。
总之,我们已经看到了如何构建拉普拉斯矩阵,如何构造和聚合消息,以及如何在训练期间评估算法的性能。我们现在可以转到代码:
NGCF Forward Pass
这个片段中的代码类似于带有 repo 的代码,只是去掉了一些额外的组件。让我们对这段代码稍加注释,看看它与前面显示的数学表达式有什么关系:
- 第 2 行:初始嵌入的简单串联。这将产生一个维度矩阵(# 用户 +# 项目,# 嵌入)。作者称这种串联的结果为
ego_embeddings
。这是因为在形式上,如果我们仅使用这些嵌入,我们将仅考虑从给定节点(又名焦点节点)传递到与其直接连接的节点(即自我网络)的信息。 - 第 9–10 行:对于每一跳(层或连接顺序),我们首先将拉普拉斯矩阵乘以前面描述的连接结果。该矩阵乘法的结果将是之前提到的聚合嵌入,并且在等式 3 中被称为 eᵤ 和 eᵢ 。因为拉普拉斯矩阵…很大,我们不能一下子做到这一点,所以我们把它分成“折叠”(按行划分)并依次相乘。
- 第 13 行:等式 3 括号内的第一项就是第 13 行。
- 第 15–16 行:这是等式 3 括号内的第二项。
从那里开始是相当简单的。在计算 BPR 损失之前,我们归一化嵌入并连接它们。
注意,我们还应用了作者所谓的“消息丢失”,这是通常直接应用于嵌入的nn.Dropout
。它们区分了消息丢失和节点丢失。作者通过在拉普拉斯矩阵上使用tf.sparse_retain
(见这里的)来实现后者,该矩阵保留位置。就我个人而言,我称之为边缘丢失,因为节点丢失,以我的理解,是将拉普拉斯矩阵中的一整行归零。尽管如此,无论是边缘还是节点丢失,这些在计算上都是非常昂贵的。因此,即使我已经实现了它们,并且包含在我的 repo 中的代码中,我也没有在运行实验时探究它们的效果。
在这个阶段,我想暂停一下,把注意力放在上面片段中的 NGCF 向前传球上。正如我们所看到的,直到第 24 行,批量的大小并不重要。到那一行,我们必须为所有的用户和条目构建和执行整个图。在这种情况下,静态(即声明性)框架,如 Tensorflow,更适合。当使用静态框架时,图被构建一次,然后当数据流经图时被端到端地执行(例如,我们称之为loss
函数)。另一方面,当使用动态框架(也称为命令式框架)时,图是在每次向前传递时构建和执行的。因此,虽然第二种方法比第一种方法更灵活,但在类似这里描述的问题中,它们的执行速度明显较慢。例如,Pytorch 在运行 NGCF 时保持"竞争力"的唯一方法是使用大批量,因此可以将每个时期的向前传递次数降至最低。尽管如此,作者最初的TF 实现更快。
2.2 培训/验证策略和结果
在 NGCF 的案例中,培训遵循的是使用 BPR 损失时的标准策略。每个批次由类似(用户、正项目、负项目)的三元组组成,即 256 的批次大小将包含 256 个这样的三元组,正向传递的输出直接是我们需要最小化的 BPR 损失。
然后,在测试过程中,我们对每个用户从未评价过的所有项目进行排名。在这种情况下,排名分数只是用户和项目嵌入之间的点积。请注意,由于在这种情况下,我们对每个用户的大量项目(用户在训练期间没有与之交互的所有项目)进行评级,因此此处获得的排名指标明显小于为 NeuMF 获得的排名指标,后者是在每个用户 100 个项目的组内计算的。
以 NCGF 为例,我只进行了 15 次实验。因此,这绝不是对参数空间的详尽探索。我尝试过使用 RAdam 优化器[9],这是为了在一些问题中找到 SOTA 解。事实是,在使用 RAdam 时,我在最少的历元数内获得了最佳的 BPR 损失。然而,正如我将在下面讨论的,在这些类型的问题(推荐算法)中,最佳损失值并不总是意味着最佳排名度量。尽管如此,我发现这个结果真的很有希望和鼓舞人心,我期待着在其他项目中尝试 RAdam。
总的来说,在这个笔记本里可以找到结果的总结和简短的讨论。让我在这里包括下图。
Fig8. Ranking metrics vs BPR Loss
图 8 显示了排名指标随着 BPR 损失的减少而提高的趋势,正如人们所预料的那样。然而,这并不是一个平稳的趋势。事实上,就排名指标而言,第二好的结果是第六好的 BPR 损失值(参见笔记本)。这与我之前关于“损失与排名指标”评估的评论有关,或许值得专门写一两段。
一般来说,在构建推荐算法时,您通常可以将其作为分类/回归问题或排名问题来评估其性能。后者与信息检索效率更相关,通常是我的偏好。首先,因为我认为这是衡量推荐算法表现的一个更可靠的方法,其次,因为有时评分可能有点、。例如,他们可能会受到用户当天情绪的影响,或者因为电影期间发生了一些事情(互联网故障,或者网站故障)。
此外,你不希望得到“太好”的预测评级。一般来说,你希望你的算法具有良好的覆盖率(即尽可能多地覆盖商品空间)和多样性(即推荐用户可能喜欢的尽可能多样化的商品)。这也涉及到新颖性(即推荐用户没有意识到的项目)和偶然性(向用户推荐意想不到的项目)的概念。如果你的建议完全依赖于在预测明确评级时实现最佳损失,那么你最终将减少所有覆盖面、多样性、新奇性和意外收获,并最终减少参与度。
如果你想了解更多关于如何评估推荐算法的细节,请确保阅读这本神奇的书【10】的第 7 章。
暂时就这样了。在 NCF 和 NGCF 这两个案例中,我都包含了一个名为get_embeddings.py
的脚本,其中我使用了学习嵌入和 KNN 来展示这些学习嵌入“有意义”。也就是说,给定某部电影,嵌入空间中最接近的电影将是明智的推荐。
3.未来的工作
当我有时间的时候,我打算使用最新发布的XL learn库,查看与分解机【11】和现场感知分解机【12】相关的笔记本。我相信他们已经解决了我在使用该软件包时所面临的许多问题,而且当时它已经是一个非常有前途的软件包了。因此,我认为值得再试一次。就添加更多算法而言,下一步是多 VAE【13】。正如法拉利·达克雷马等人【14】的优秀作品中所描述的,Mult-VAE 似乎是唯一一种基于深度学习的推荐算法,实际上比更简单的非 DL 技术表现得更好。
一如既往,任何想法或意见,请发邮件给我:jrzaurin@gmail.com
参考资料:
[1] J .麦考利,c .塔吉特,j .施,a .范登亨格尔。基于图像的风格和替代品建议。2015 年,SIGIR
[2]何,麦考利。用一类协同过滤对流行趋势的视觉演变建模。WWW,2016
3何湘南,廖,汉王张,聂,,蔡达生.神经协同过滤。arXiv:1708.05031v2. 2016
[4],何湘南,,冯福利,蔡达生.神经图协同过滤。SIGIR 2019。arXiv:1905.08108
[5]莱斯利·史密斯。训练神经网络的循环学习率。WACV 2017。arXiv:1506.01186
6 Thomas N. Kipf 和 Max Welling:使用
图卷积网络的半监督分类。ICLR 2017。arXiv:1609.02907
7里安娜·范登贝格,托马斯·n·基普夫,马克斯·韦林。KDD 2018。arXiv:1706.02263
[8] Steffen Rendle、Christoph Freudenthaler、Zeno Gantner 和 Lars Schmidt-Thieme。2009.BPR:基于隐式反馈的贝叶斯个性化排序。在 UAI。452– 461.
[9],,江,何鹏程,,陈,,高剑锋,韩家伟.适应性学习率的方差及其超越。arXiv:1908.03265
[10]推荐系统:教科书。查鲁·阿加尔瓦尔。斯普林格 2016
[11]斯蒂芬·伦德尔。因式分解机。2010 年 IEEE 数据挖掘国际会议 ICDM 会议录
[12]·潘、·阿丰索··鲁伊斯、·赵、·潘、·孙玉、展示广告点击率预测的场加权因子分解机。WWW 2018。arXiv:1806.03514
[13] Dawen Liang,Rahul G. Krishnan,Matthew D. Hoffman,Tony Jebara:用于协同过滤的可变自动编码器。WWW 2018。arXiv:1802.05814
[14]毛里齐奥·费拉里·达克雷马、保罗·克雷莫内西、迪特马尔·扬纳克:我们真的取得了很大进步吗?最近神经推荐方法的令人担忧的分析。第 13 届 ACM 推荐系统会议录(RecSys 2019)。arXiv:1907.06902
使用 Plotly Express 用 2 行 Python 重新创建 Gapminder 动画
免责声明:使用了一个新模块
plotly_express
,Gapminder 动画没有使用 2 行代码从头开始编码
这是数据可视化的标志性时刻之一,当时汉斯·罗斯林在他的 ted 演讲中展示了著名的 Gapminder 动画,这是有史以来观看次数最多的 TED 演讲之一。从那时起,它就像是任何进行可视化的人复制它以显示他们的数据可视化能力的基准——就像复制爱德华·塔夫特或内特·西尔弗的可视化作品一样。
最近 Plotly (以 R 和 Python 的交互式可视化 DSL 而闻名)推出了一个新的工具/模块/库,名为 Plotly Express 。顾名思义,plotly express
的主要目标是成为一个非常简单、快速和易于使用的高级 API 来构建交互式可视化。
更像这样,
plotly Express:plotly . py::Seaborn:Matplotlib
受 R 的ggplot2
和 Python 的seaborn
的启发,以简单为核心的plotly express
试图在one-liners
中做事。在这篇文章中,我们将看到如何仅仅使用plotly express
来重现(如果不完全重现,至少类似于)标志性的 Gapminder 动画。
装置
pip3 install plotly_express
使用别名导入库:
import plotly_express as px
气泡图动画又名 Gapminder 动画
px.scatter(px.data.gapminder(), x="gdpPercap", y="lifeExp", animation_frame="year", animation_group="country",
size="pop", color="country", hover_name="country",
log_x = True,
size_max=45, range_x=[100,100000], range_y=[25,90])
这是一个非常简单的函数(我曾经见过这样的 Gapminder 动画)。函数px.scatter()
从px.data.gapminder()
获取数据,然后通常定义x
和y
轴以及每年递增的animation_frame
。随着更多关于外观改进的讨论,动画泡泡图已经准备好了!
Plotly Express 教程视频构建 Gapminder 动画:
鳍
这篇文章的目的是传播关于plotly_express
的信息,这是一个创造美丽的交互式可视化的惊人之举(也类似于 R 中的highcharter
)。如果你想从总体上了解《T2》的剧情,可以去看看《数据营》。
资源
从 WhatsApp 聊天中重塑自我
探索我能在聊天机器人中复制我的人格的程度
Image by Gerd Altmann from Pixabay
我一直在想,我们是否有一天可以在互联网上上传一份我们自己的副本。今天,虽然我们无法制造高分辨率的意识复制品,但我相信我至少可以用现有的技术捕捉到我的人格快照。本能地,人工智能的用法浮现在脑海中——特别是聊天机器人。
有许多现有的训练聊天机器人的模型。对我个人来说,我关注了使用 Python 和 TensorFlow 的send ex 的 Youtube 教程系列。我用了 nmt-chatbot (Github 资源库这里)作为基础,写了几个工具帮我做我的 WhatsApp 聊天数据的预处理(我的 Github 工具资源库这里)。我采取了很多步骤,也从这次经历中学到了很多。
第一部分:预处理
下载 WhatsApp 聊天作为训练数据
众所周知,WhatsApp 会自动将你的聊天记录备份到 Google Drive 中。现有的解决方案允许你直接读取加密文件,但我选择直接从 WhatsApp 下载聊天记录。要做到这一点,你必须点击下拉菜单内你的聊天对话的人,点击“更多”,然后其次是“导出聊天”。
然后会提示您选择包括或不包括介质。对我来说,我选择不这样做,因为我无法通过自动化手段处理除文本之外的任何东西。希望在未来,我可以这样做,以便给整个对话提供更多的上下文,并提高聊天机器人的准确性。
清理 WhatsApp 聊天
下载聊天内容后,用您选择的任何文本编辑器打开它。您将看到这样的内容(出于隐私考虑,我删除了这些名字):
My conversation with my friend in WhatsApp opened in Sublime Text
如你所见,时间戳和人名并不是训练聊天机器人所必需的。数据需要清理,所以我写了一个 Python 脚本来去掉多余的数据段。
我首先删除了聊天的时间戳,这样名字将定义每一行的开始。我写了一个脚本叫 chatparser.py,可以在聊天处理文件夹下找到。
正如您在下面的源代码中看到的,您可以将文件名添加到数组中,这样您就可以一次处理多个文本文件。使用终端更改目录后,我执行了以下命令:
$ python chatparser.py
执行该命令后,会生成一个新文件“WhatsApp 与人聊天 Bout.txt”。
Chat with timestamp removed.
接下来,我把我和其他人的聊天记录分成两个文本文件。我运行了自己编写的另一个脚本 chatseparator.py:
$ python chatseparator.py
这导致生成的文件“WhatsApp 与人聊天 Bsep.txt”和“WhatsApp 与人聊天 BCW.txt”(也就是我),如下所示:
The responses of the person I am talking to.
The things I texted to the other party.
“|”字符用作分隔符,表示当一个人回答或发起对话时,对话在哪里分开。后来证明这是非常有用的。
分组对话
发短信时,我们倾向于把句子分成几个部分,而不是把它们聚在一起作为一条信息发送。我对一对问题/回答进行分类的方法只是通过检测发短信的人何时改变。对于一个人输入的每一个连续的文本链,它相当于句子本身。我不得不承认,这是一个极其简化的模型,但它适用于我的大多数聊天。
现在,我执行我编写的下两个 python 脚本— otherstagdelete.py 和 mytagdelete.py —来删除对话前面的名字。
$ python otherstagdelete.py$ python mytagdelete.py
然后,我运行我的 combine.py 脚本来合并分散在多个聊天消息中的句子。
$ python combine.py
删除包含媒体的响应对
因为我们选择导入没有媒体的聊天,所以有几行显示
第二部分:训练聊天机器人
将您发起的所有聊天复制到一个文档中,将其他人发起的所有聊天复制到一个单独的文档中。到目前为止,每个问题/回答对都应该对齐到同一行,所以应该没有问题。
如果你有超过一百万个问题/回答对,你的训练结果会更准确。参考 nmt-chatbot 的 Github 库,只需将你创建的各自的训练数据放入 train.from 和 train.to 即可。
第三部分:结果
在部署我的模型时,我用一些问题测试了它,很明显聊天机器人已经采用了我的说话风格。以下是一些快照:
当然,这并不都是美好的事情,因为聊天机器人仍然在很大程度上胡说八道。这是因为我的训练集太小,没有效果。然而,作为概念验证,我发现它非常有前途。
第四部分:吸取的教训和改进
通过这个项目,我想我有一些很棒的收获,我想分享一下。
首先,可以实现自然语言处理算法来确定对话的上下文何时改变。这进一步增强了问题/响应对的准确性,并允许更好的聊天机器人。
第二,也可以采用图像识别,使得包括照片的聊天也可以用作训练数据。通过给图片加上特定的标签,它也给对话提供了背景,这很好。
AI 和机器学习真的是一个潜力无限的神奇领域。即使你和我一样是初学者,我也觉得大有可为。我鼓励每个人都真正尝试一下学习人工智能。我希望你发现这个项目是有用的,也许在某种程度上是鼓舞人心的!
重现梵高遗失的画作
在寻找杰作的过程中使用生成模型
1889 年夏天,文森特·梵高开始创作一系列风景画。每一幅画他都寄给他在巴黎的兄弟西奥。
From Museum of Fine Arts, Boston
可以看到,其中一幅画缺少了对应的画。这幅画叫做“野生植被”,大概是一片开满鲜花的田野,背景是一座山。
人们注意到丢失的画,许多人想知道它可能在哪里。
118 年后的 2007 年,当波士顿美术博物馆的一位名叫 Meta Chavannes 的管理员用 X 射线对这幅名为“峡谷”的画进行检查时,这个谜有了一个结论,并在下面发现了野生植物的遗骸。
众所周知,梵高一生都缺乏材料,当绘画的欲望变得势不可挡时,他甚至用毛巾作为画布。考虑到这一点,他干脆重用野生植被画布也就不足为奇了。遗憾的是,很难从 x 光片上看出这幅画的样子,所以这幅画似乎已经失传了。
也就是说,直到现在。借助生成机器学习的力量,我开始尝试重建这幅画。
神经类型转移
我最初的想法是,神经类型转移可能会解决这个问题。神经类型转移是一种利用深度学习内部工作的有趣事实的技术。
Image from https://blog.datarobot.com/a-primer-on-deep-learning
深度学习的一大优势是它能够自动选择特征。事实证明,当训练一个深度神经网络时,例如在人脸上,每一层都学习识别越来越高抽象的特征,因此第一层寻找直线和边缘,随后的层寻找眼睛和耳朵,而进一步的层寻找整张脸。
如果我们看两幅图像,如果它们具有相同的“内容”,即都包含一辆汽车或一张脸,我们会期望它们在更深的层中具有相似的特征。这与汽车或面部的确切外观无关。
相比之下,如果图像都包含类似的“风格”,如颜色、边缘或圆形,则早期的层将具有类似的特征。然而,事情比这要复杂一些,因为我们所说的风格通常是几个特征的组合。例如,一幅草坪的图像可能包含“尖”和“绿”的特征,而一幅森林中的刺猬的图像包含相同的特征。如果我们使用第一张图片作为样式输入,大概我们实际上想要的是“草”的样式,它是绿色和尖尖的特征在同一个地方的组合。为了实现这一点,我们使用了 gram 矩阵,它告诉我们某些特征在图像中的什么位置出现在一起。在绿草如茵的图像中,绿色和尖刺出现在同一个地方,与刺猬图像形成对比,在刺猬图像中,尖刺与棕色相关。因此,为了实现相似的风格,我们试图最大化 gram 矩阵的相似性。上面的例子摘自生成式深度学习。
然后我们进行反向传播算法,但不是像我们通常在训练时那样改变网络的权重,而是保持它们固定不变,而是改变图像。
使用库神经风格转移,我在野生植物和油画“罂粟田”上做了这个,结果如下:
结果远不能令人满意,因为模型似乎有一个辨别什么是地面和什么是天空的问题,因此在某些地方使地面变成蓝色。这种把天空的颜色放在地面上的方式当然是梵高自己在精彩的作品《播种者》中所做的,他颠倒了地面和天空的颜色顺序,但我觉得这在上面的作品中可能不合适,至少在这里不合适。
我当然应该猜到会是这样,为什么神经类型转移会知道什么是天空,什么是地面?
CycleGAN
我的下一个想法是使用 CycleGAN。GAN 是两个相互竞争的神经网络的名称。第一个网络(生成器)试图绘制图像,第二个网络(鉴别器)试图猜测第一个网络是否绘制了图像,或者它是否取自训练数据。第一种训练的目标是愚弄第二种,第二种训练的目标是不被愚弄。
Image from https://developers.google.com/machine-learning/gan/gan_structure
我喜欢和你的对手一起通过竞争变得更好,不断挑战彼此的极限。有点像猎豹如何在试图跟上羚羊的同时变得如此完美地设计速度,而羚羊在与猎豹竞争时变得更快。
普通类型的 GANs 只能产生类似于大量训练数据的图像,但是没有办法指导它。然而,CycleGAN 是一种条件 GAN,它将图像作为条件,并使用该条件来创建新图像。
它由两个 gan 和两个数据集组成。一个 GAN 生成与第一个数据集相似的图像,另一个生成与另一个数据集相似的图像。我们还将附加的“重构标准”应用于 GAN。这意味着,如果第一个 GAN 获取图像并生成另一个图像,第二个 GAN 应该能够获取新图像并生成与原始起始图像非常相似的图像。
Generator Gx->y transform image from domain x into y. Discriminator Dy tries do determine if it belongs to domain Y. Image from GAN Lecture 2 (2017): CycleGAN
在我的慢速 GTX 670 上使用库GDL _ 代码一个晚上后,结果如下:
这个好多了。天空是蓝色的,地面是绿色的,开满了花。不过分辨率太低了,所以我用更高的设置再试了一次。
不幸的是,这里的结果实际上更糟。我认为一个问题是异常小的天空。在具有较大天空的图像上进行训练,网络很难知道它在哪里。
一路上帮助机器
由于不完全满意,我决定使用混合方法。由于网络似乎很难知道图像的不同部分应该是什么,也许人机合作将有利于解决这个问题。我作为一个人,告诉机器什么是天空,什么是花朵,机器做它最擅长的事情,并以正确的风格描绘一幅画。
好吧,那没用。梵高和其他后印象派画家仍然从现实中绘画,尽管他们对现实有自己特殊的解释。我需要的不是由大块彩色区域组成的图像,而是更像照片的东西。如果我能重现梵高看到的场景,那么风格转换就可能成功。
GauGAN 和 Pix2Pix
Nvidia 创造了他们自己风格的 Pix2Pix 算法,并将其称为 GauGAN (另一位后印象派画家高更的双关语)。在这里,GAN 在两个图像上训练,在 GauGAN 的情况下,一个是照片,另一个是照片的示意图,描绘了它的不同部分,如草,水,天空。通过这种方式,GauGAN 学会了在草图和照片之间进行转换。我从上面给了它我的草图。
这看起来像是梵高可能真的见过的场景。这让我想起了阿尔卑斯山,那里有鲜花和香草,背景是那座山。
通过风格转换运行重建的图片产生:
最后,我们有可能通过野生植物的重建。
结论
我们正处于一个有趣的时间点,在这个时间点上,无论是机器还是人类,都不是在所有方面都更优越。这开启了一些有趣的合作,每一方都可以做出贡献,做出一些他们自己无法做到的事情。
生物和人工神经网络中的递归
相似性、差异及其重要性
递归是神经网络上下文中的一个过载术语,在机器学习和神经科学社区中具有完全不同的口语含义。然而,这种差异正在缩小,因为用于实际应用的人工神经网络(ann)越来越复杂,在某些方面更像生物神经网络(BNNs)(但在整体上仍有很大不同)。
在本帖中,我们将讨论这两个社区中使用术语复发的历史差异,强调一些最近向神经科学发展的深度学习人工神经网络模型,指出一些揭示复发功能的神经科学研究,并推测未来的发展。
太长;没看
- 深度学习社区所说的循环 连接类似于神经科学社区所说的横向连接。即局部区域内相互连接的神经元。
- 在神经科学社区中,递归网络是一个连通性丰富的网络,包括前馈、 和反馈 连接。
- 反馈连接适应了动物的能力和行为,这些能力和行为在缺乏这种连接的深度学习模型中可能无法复制。
深度学习人工神经网络中的递归
正如许多读者所知,深度学习网络是人工神经网络的子类型,其中神经元(或节点)被排列成层。在这样一个网络中,许多层的存在给了它一个主观的深度,这就是它的名字,与早期研究的这种类型的网络相比,只有一个或两个这样的层。在一个典型的全连接前馈深度学习网络中,给定层中的所有神经元都将它们的输出发送给紧随其后的层中的所有神经元(计算的方向流通常被示意为从下到上或从左到右在层之间进行)。
人们也可以设计这样的网络,其中给定层中的神经元将它们的输出发送到它的上一层,从而在层间引入反馈连接。我们稍后将回到这一点。
最后,一层神经元可以以完全连接(或其他)的方式将其输出发送回自身。存储在层中的信息在下一个时间/处理步骤中作为输入再次出现。这是深度学习实践者讨论时几乎总是指的那种递归类型——局限于一个层的递归。(注意,可能有多个递归层,但层间连接只是前馈。)
Unlike the feed-forward network on the right, the network on the left has a recurrent layer (the larger light blue circles) that “feeds back” onto itself. In deep learning parlance, the network is termed a recurrent network rather than a feed-back network because the feed-back does not project to a preceding layer. Note that although the recurrent neurons in the figure are depicted as connecting back to themselves individually, the typical arrangement is for all neurons in the recurrent layer to connect to all other neurons in that same layer.
这种循环连接的作用是在循环神经网络(RNN)中赋予记忆。网络的输出不再仅仅依赖于对齐的时间步长上的输入。相反,网络在任何给定的时间都有一个“状态”,它与下一个输入相结合,提供一个新的输出,并更新网络的状态。
这使得 rnn 能够识别或产生时间结构不同的模式,如语音[1]。例如,话语
文本的语言翻译是另一个非常成功的领域。递归的使用允许信息在编码阶段被累积,并在解码阶段被分发(跨时间输出),由此直接的单词到单词或短语到短语的对齐是不必要的[2]。例如,允许一种语言中单词前面的修饰语跟随在另一种语言中的单词后面,例如当将 red hat 翻译为 sombrero rojo 时。
The use of LSTMs, a type of RNN, allows for language translation networks with network memory that can accumulate information. Words (as vector representations) are incrementally input to the network, and the network distributes output words in a different language, with some delay. This is successful even when ordering of parts of speech (nouns, adjectives, etc.) is different between the two languages. [Image taken from The Keras Blog.]
我们不能不提到上面描述的“香草”RNN 架构在实践中很少使用。高级应用通常依赖于人类设计的适应门控机制的修改。在某种意义上,当接收到某个输入或传递某个输出时,这允许循环层的状态存储器被“转储”。打个比方,当你完成一个句子,以及相关的想法时,你可能希望把那个想法扔掉,这样它就不会和你的下一个想法混淆了。值得注意的是,最常见和最有效的门控层之一,长短期记忆 (LSTM)层最初创建于 1997 年3,远远早于 RNN 应用的最新进展。参见 Christopher Olah 的博客文章中关于 LSTMs 的精彩教程。
生物神经网络中的递归
在神经科学家中,递归有一个更宽泛的定义——部分基于生物神经网络(BNNs)中神经元之间近乎各向同性的连接模式。神经元在向其他神经元的轴突投射中是多产的,向前和向后,短距离和长距离地发送它们。虽然有强有力的证据表明在结构和功能上存在粗糙的层次排列[4],但大脑皮层显然没有排列成神经元的有限层(组)。大脑作为一个整体具有不同的区域,具有不同类型的神经元和神经递质,但不像作为深度学习人工神经网络的定义特征的划分连接。尽管如此,深度学习实践者所谓的循环连接更有可能被神经科学家称为横向连接。
计算神经科学家已经深入研究的递归网络的一个方面是所谓的吸引子网络的模式完成属性。想一想,在我们自己的头脑中,可能只需要短暂的一瞥、短暂的一阵声音或一点点气味就能带来强烈的、充满活力的记忆。或者当我们试图回忆一个男演员或女演员的名字时,我们会想象他们的脸,想到他们合作过的其他演员的名字,电影名称等等。直到他们的名字突然神奇地出现在我们的脑海中。在循环吸引子网络(一种人工神经网络,但没有深度学习结构,并且通常具有抑制性和兴奋性人工神经元,旨在成为 BNNs 的更现实的模型)的模拟中观察到了这种现象的类比。例如,由一张脸的图像驱动的神经活动模式也可能由同一张脸的模糊或嘈杂的图像驱动,尽管在后一种情况下,网络的动态需要更长时间才能进化到稳定状态。
The energy landscape of a Hopfield attractor network. Sensory information may briefly position the network activity in an unstable, partial-information state, from which it dynamically moves (adjusts neuron firing rates) to a stable state that represents a fully-remembered object, sensation, abstract idea, etc. In this case, “memory” is really the strength and pattern of the synaptic connections between neurons, and recall of that memory is the neuronal firing pattern that ensues when external or internal stimuli push the network beyond the edge of the memory’s attractor basin (like a drop of rain that eventually flows to one of many possible lakes or oceans). See Jack Terwilliger’s blog post for more detail.
比深度学习 ann 的受限递归(层内)与 bnn 的广泛递归之间的区别更重要的是,大多数深度学习模型中缺乏反馈连通性。在神经科学界,术语“复发”几乎是反馈和前馈连接的同义词,最近的研究为反馈的作用提供了新的证据。
生物网络中循环和反馈连接的可能功能:
- 迭代感觉处理:循环处理,其中自下而上和自上而下的信息流相互作用以确定一个稳定的结果。关于这个主题的更深入的讨论,请参见下一节。
- 长期记忆:不完整的信息可以在吸引子网络中从长期存储中启动对记忆的回忆(如上所述)。
- 短期记忆:短期记忆,即需要记住一小段数字序列或几个句子内容的那种记忆,可能由神经元维持,这些神经元共同产生一个稳定的(但可能是动态的)放电模式,有点像吸引子,只是维持一个新的短期记忆,而不是回忆一个存储的长期记忆。该功能与上述序列到序列深度学习 RNNs 的功能相关(例如,允许语音识别和语言翻译)。
- 自上而下的目标驱动注意力:基于一个有机体手头的任务和相关的目标,并不是所有的感官信息都同样有价值。一只寻找它最喜欢的红色浆果的动物可能有反馈连接,可以增强对红光做出反应的低级神经元的活动,同时降低对其他颜色做出反应的神经元的活动。这个过程的神经模型利用了深度学习社区的工作[5]。
- 可塑性:递归也是生物大脑学习机制的重要组成部分。例如,皮质下基底核中的多巴胺释放神经元是由皮质和皮质下区域组成的复杂网络的一部分,最终可以增强皮质区域的可塑性,以响应导致奖励的行为(食物、交配等)。),从而强化了那种行为。这种类型的神经元和网络复杂性在最先进的深度学习中几乎完全不存在。
- 门控:推测上,反馈也可能作为门控机制,控制信息从较低级神经元向较高级神经元的流动。注意力可能会选择这样的门控,但这里我们指的是不由有机体的意识感知和目标驱动的门控。例如,众所周知,关于物体身份的视觉信息沿着从枕叶皮层到下颞叶皮层的路径被提取和提炼。相反,对象位置信息是沿着从枕叶皮层到顶叶皮层的路径提取和提炼的。(注意这是一个过于简单化的描述。)门控可以帮助指导这种信息路由,并且可以是支持在该列表顶部讨论的迭代感觉处理的机制。
迭代感觉处理
我们将简要强调 BNNs 中递归/反馈连接的迭代感觉处理作用,并将其与深度学习 ann 中主导图像分类任务的前馈卷积神经网络(CNN)进行对比。
深度学习对象(图像)识别模型在该领域取得了巨大成功,自第一个赢得 ImageNet 大规模视觉识别挑战赛(ILSVRC)的 CNN 模型“Alex net”6发表以来,该领域发展迅速。想要一个好的教程,请看这篇博文,或者许多其他的。因为视觉皮层是哺乳动物皮层中研究得最充分的区域,所以在深度学习 CNN 和哺乳动物视觉之间进行了许多主观和定量的比较。
早期的视觉神经科学模型,基于 Hubel 和 Weisel 等人对单个神经元的记录7,与标准的 CNN 相似,它们具有卷积、汇集和专门的前馈连接[8,9]。完全前馈的功能模型的部分动机是视觉感知发生迅速,大约 100 毫秒。这一估计是基于大脑“较高”区域的神经放电时间,相对于向实验室动物展示图像的时刻。基于解剖学,视觉皮层通常被建模为具有大量反馈连接的 4-6 级松散层级。尽管存在反馈连接,但更高级别的神经反应的快速性表明反馈连接并不完全必要(对于简单的物体识别任务)。如果不是这样,在这些区域形成稳定的反应将会更慢,因为反馈回路的贡献传播需要更多的时间。
然而,在具有挑战性的 ILSVRC 测试集上,CNN 需要几十层(如果不是几百层)才能实现良好的图像分类性能,这与仅由几个前馈层组成的视觉皮层模型相反。此外,在一些计算研究中,相对较浅的 rnn 的性能与非常深的 CNN 相当[10,11]。
Liao and Poggio [10] built a 4-level recurrent network meant to model the visual cortex. In this coarse model, visual input from the eye (via retina and thalamus) enters the primary visual cortex, V1. The network contains feed-forward connection (left-to-right), feed-back connections (right-to-left) and lateral connections (looping back to same area; synonymous with recurrent connections in deep learning terminology). Outputs from the inferotemporal area, IT, are used for object classification. They demonstrate that a shallow RNN is equivalent to a very deep ResNet model (a type of deep learning ANN) with weight sharing among the ResNet layers.
最近,世界一流实验室的两项神经科学研究,以及对生物循环连接的时间延迟的更细致入微的理解,表明需要循环来捕捉人类视觉皮层的动态计算[12],并且循环对视觉皮层执行物体识别行为至关重要[13]。简而言之,证据表明,如果不通过递归网络进行多次迭代,更具“挑战性”的物体图像实例就无法被识别。换句话说,需要额外的非线性变换来成功地识别挑战案例中的对象。
最后的话
如上所述,虽然递归深度学习 ANN 模型具有层内递归(神经科学术语中的“横向”连接),但很少具有神经科学家通常研究的反馈连接类型——即从较高层到较低层的连接。值得注意的例外包括模拟注意力的人工神经网络和一些图像分类模型。
具有反馈连接性的深度学习模型几乎不存在的一个原因是训练这种模型的难度。我们可能需要新的学习规则(除反向传播之外的方法)来实现反馈在 BNNs 中提供的功能类型。
与之相关的是,生物神经元并行工作,因此大规模循环网络中的计算可以快速进行。事实上,神经元状态的同时计算更新可能是成功的关键。对于在现代硬件上运行的大型、高重现性(神经科学术语)人工神经网络来说,这种程度的并行性可能很难或不可能实现。
我们推测,将重反馈递归引入深度学习模型,并开发这种模型的训练方法,将带来强大的 now AI 能力。然而,这些进展的速度很难预测。
参考
- 格雷夫斯(2012)。"神经网络的序列转换."https://arxiv.org/abs/1211.3711
- Sutskever、Vinyals 和 Le (2014 年)。"用神经网络进行序列对序列学习." NIPS 2014 。【https://arxiv.org/abs/1409.3215
- Hochreiter 和 Schmidhuber (1997 年)。“长短期记忆。”神经计算。https://www . mitpressjournals . org/doi/ABS/10.1162/neco . 1997 . 9 . 8 . 1735
- 克拉维茨等人。(2013)."腹侧视觉通路:处理物体质量的扩展神经框架."趋势认知科学。https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3532569/
- 亚明斯和迪卡洛(2016)。“使用目标驱动的深度学习模型来理解感觉皮层。”自然神经科学。https://www.nature.com/articles/nn.4244
- Krizhevky、Sustskever 和 Hinton (2012 年)。“使用深度卷积神经网络的 ImageNet 分类” NIPS 2012。http://papers . nips . cc/paper/4824-imagenet-class ification-with-deep-convolutionary-neural-networking
- 胡贝尔和威塞尔(1959)。"猫纹状皮层中单个神经元的感受野."生理学博士。https://phys oc . online library . Wiley . com/doi/pdf/10.1113/jphysiol . 1959 . sp 006308
- 福岛(1980 年)。“Neocognitron。不受位置变化影响的模式识别机制的自组织神经网络模型生物控制论。https://www.rctn.org/bruno/public/papers/Fukushima1980.pdf
- Riesenhuber 和 Poggio (1999 年)。"大脑皮层中物体识别的层次模型."性质。https://www.nature.com/articles/nn1199_1019
- 廖和波焦(2016)。"弥合剩余学习、循环神经网络和视觉皮层之间的差距."CBMM 备忘录 047 。https://arxiv.org/abs/1604.03640
- 扎米尔等人。(2016).“反馈网络。”IEEE 计算机视觉和模式识别会议(CVPR)。https://arxiv.org/pdf/1612.09508.pdf
- Kietzmann,等人。(2019)."捕捉人类腹部视觉流的动态计算所需的递归."https://arxiv.org/abs/1903.05946
- 卡尔等人 (2019)。"证明循环回路对腹侧流执行核心物体识别行为至关重要."自然神经科学。https://www.nature.com/articles/s41593-019-0392-5
递归神经网络-从头到脚
神经元是人脑的组成部分。它可以在微秒内分析复杂的信号,并向神经系统发送信号来执行任务。每个神经元的结构都是相同的,这意味着神经元之间的结构层不会改变。让这些层连续,它可以很容易地复制我们的大脑。这些连续的“层”帮助我们进行日常活动、复杂的决策和语言处理。
但是,如何在这些层面上概括我们的问题呢?概括起来需要什么样的模型?
答案以参数共享的形式出现在研究人员面前。它有助于将模型扩展和应用到不同形式的数据。这是通过将输出的成员共享为输出的先前成员的函数来实现的。输出的成员由相同的更新规则产生。理解这种计算结构的更简单的方法是使用‘展开计算图’。图形的展开导致共享结构中参数的深层网络。
考虑动力系统的经典形式:
展开这个动力系统的结构,我们得到:
如你所见,这个等式不再涉及递归。
递归神经网络可以以不同的方式建立,其中一些也可以有隐藏单元。当训练递归神经网络基于过去的输入来执行时,摘要是有损耗的,因为我们将任意长度的序列映射到向量【h(t)。根据手头的任务,我们也可以选择哪些过去的输入,我们可以有选择地保留过去序列的某些方面。
Unfolded graph: A recurrent network with no outputs, it processes the information from the input x by incorporating it into the state h that is passed forward through time.
我们可以用函数 g(t) 来表示 t 步之后展开的递归。
The function of past sequence takes g(t) as input.
展开过程具有一些主要优势,并导致使模型 f 无处不在成为可能的因素,这进一步允许一般化。
a)不管输入序列的长度如何,模型具有相同的输入大小。
b)有可能在每个时间步使用具有相同参数的相同转移函数 f,因为它是从一个状态到另一个状态指定的。
展开图通过显示信息流动的路径,说明了明确描述和信息在时间上向前和向后流动的思想。
这些想法对于构建递归神经网络非常重要,因为 RNN 在每个时间步都产生输出,并且隐藏单元之间的连接可以通过读取整个序列产生输出,然后产生单个输出。这导致了一个结论,即任何可以被图灵机 计算的函数都可以被有限大小的递归神经网络计算。正是这种利用过去的输出和隐藏层连接的性质,使得 RNN 取得了今天的成就。
递归神经网络
有了图形展开和参数共享的知识,我们现在开发 RNN。我们假设双曲正切激活函数。考虑输出的一个自然方法是给出非标准化的对数概率,我们将 softmax 作为后处理步骤。
Computation Graph to compute training loss of recurrent neural network.The sequence of output values o is compared to the training targets y, this leads to the computation of the loss function. We assume o is the unnormalised log probabilities. The loss function L internally computes y^ = softmax(o) and compares this to target y.The RNN has input to hidden connections parameterised by a weight matrix U, parameterised by a weight matrix W, and hidden to output connection parameterised by a weight matrix V.
RNN 的计算可以分解为三个参数块:
1.从输入到隐藏状态
2.从以前的隐藏状态到现在的隐藏状态
3.从隐藏状态到输出
这些块中的每一个都与单独的权重矩阵相关联。当网络展开时,这些块中的每一个都对应于浅层变换(影响单个层的变换)。
The above equations specify forward propagation of this model,forward propagation begins with a specification of initial state h(0) for each time step from t = 1 to t= T
这是 RNN 的图像,它将输入序列映射到相同长度的输出序列。总损失是一段时间内损失的总和。 L(t) 是 y(t)的负对数似然。
梯度计算包括从左到右的前向传播,随后是从右到左的反向传播。在前向传播中计算的状态必须在反向传播中使用,因此需要存储它们。通过输出 o(t) 应用的反向传播算法被称为‘通过时间的反向传播’。通过递归神经网络计算梯度非常简单。人们简单地应用广义反向传播算法来展开计算图。通过反向传播获得的梯度然后可以用于训练 RNN。
让我们在 Pytorch 中制作 RNN 模型。我们在这里生成伪代码,我将在我的 GitHub 链接中贴出完整的引文:链接
Pytorch MNIST 培训
首先,我们导入类和 MNIST 数据集。
导入 torch
导入 torchvision
导入 torch.nn 作为 nn
导入 torchvision.transforms 作为转换
导入 torchvision.datasets 作为数据集
从 matplotlib 导入 numpy 作为 np
导入 pyplot 作为 pltn _ epochs = 3
batch _ size _ train = 64
batch _ size _ test = 1000
learning _ rate = 0.01
momentum = 0.5
log _ interval = 10random _ seed = 1
torch . backends . cud nn . enabled = False
torch . manual _ seed(random _ seed)train _ loader = torch . utils . data . data loader(dsets。MNIST('/Users/akhileshrai/Downloads ',train=True,download=True,
transform = torch vision . transforms . compose([
torch vision . transforms . totensor(),
torch vision . transforms . normalize(
(0.1307),(0.3081),)
)),
batch_size=batch_size_train,shuffle=True)test _ loader = torch . utils . data . data loader(
dsets)。MNIST('/Users/akhileshrai/Downloads ',train=False,download=True,
transform = torch vision . transforms . compose([
torch vision . transforms . totensor(),
torch vision . transforms . normalize(
(0.1307),(0.3081),)
)),
batch_size=batch_size_test,shuffle=True)examples = enumerate(test _ loader)
batch _ idx,(example_data,example_targets) = next(示例)将 matplotlib.pyplot 作为 plt 导入
fig = plt.figure()
对于范围(6)中的 I:
PLT . subplot(2,3,I+1)
PLT . tight _ layout()
PLT . im show(example _ data[I][0],cmap='gray ',interpolation = ' none ')
PLT . title(" Number:{ } "。格式(example _ targets[I])
PLT . x ticks([])
PLT . y ticks([])
打印(图)
**数据加载器加载 MNIST 数据集。数据集被下载到上述文件夹中。这些变换首先用于将数据转换为张量,然后将数据归一化。
让我们通过打印测试数据集的样本来看看同样的情况。
Samples of the MNIST Dataset
让我们根据上面所示的架构来准备我们的神经网络:
*RNNModel 类(nn。模块):
def init(self,input_dim,hidden_dim,layer_dim,output _ dim):
super(rnn model,self)。init()隐藏维度
self.hidden_dim = hidden_dim*
#隐藏层数
self.layer_dim = layer_dim*#构建您的 RNN
batch_first=True 导致输入/输出张量的形状为
(batch_dim,seq_dim,input_dim)
batch_dim =每批的样本数
self.rnn = nn。RNN(input_dim,hidden_dim,layer_dim,batch_first=True,非线性='tanh ')*
#读出层
self.fc = nn。线性(隐藏尺寸,输出尺寸)*def forward(self,x):
用零初始化隐藏状态
(layer_dim,batch_size,hidden _ dim)
h0 = torch . zeros(self . layer _ dim,x.size(0),self.hidden_dim)。requires_grad_()*
*#我们需要分离隐藏状态以防止爆炸/消失梯度
这是通过时间截断反向传播的一部分(BPTT)
out,hn = self.rnn(x,h0.detach())*
*#索引上一时间步的隐藏状态
out.size() → 100,28,10
out[:,-1,:] → 100,10 →只想要上一时间步的隐藏状态!
out = self.fc(out[:,-1,😃
out.size() → 100,10
返回 out*
输入 _ 尺寸= 28
隐藏 _ 尺寸= 100
图层 _ 尺寸= 3
输出 _ 尺寸= 10model = RNNModel(输入尺寸,隐藏尺寸,图层尺寸,输出尺寸)
print(model)
print(len(list(model . parameters())))
for I in range(len(list(model . parameters()))):
print(list(model . parameters())【I】。size())
我们的模型有 3 个隐藏层,每层 100 个隐藏神经元,接受 28 维的输入数据,同时输出 10 维的数据。我们假设的激活函数是双曲线* ' tanh' 。随机梯度下降用于在每次迭代中寻找单个例子的成本函数的梯度,而不是所有例子的成本函数的梯度之和。*
然后,该模型经过 5000 次迭代训练,一种称为早期停止的方法用于防止模型“过度拟合”。
提前停止 是通过计算验证损失完成的优化技术。如果验证损失在指定的迭代次数内没有减少,则模型停止其训练。
learning _ rate = 0.01
min _ val _ loss = NP。INF
epochs _ no _ improve = 0
n _ epoch _ stop = 2
early _ stop = False*optimizer = torch . optim . SGD(model . parameters()、lr=learning_rate)
展开步骤数
criteria = nn。交叉入口型()*
*#展开的步骤数
seq_dim = 28
early _ stop = False
ITER = 0
for epoch in range(num _ epochs):val _ loss = 0
for I,(images,labels)in enumerate(train _ loader):将图像加载为具有梯度累积能力的 torch 张量
images = images.view(-1,seq _ dim,input_dim)。requires_grad_()*
#清除梯度 w.r.t .参数
optimizer.zero_grad()*#向前传递以获取输出/logits
outputs . size()→100,10
输出=模型(图像)*
#计算损失:softmax →交叉熵损失
损失=标准(输出,标签)#获取梯度 w.r.t .参数
loss.backward()*#更新参数
optimizer . step()val _ loss+= loss
val _ loss = val _ loss/len(train _ loader)如果验证损失最小
如果 val _ loss<min _ val _ loss:
保存模型
torch . Save(model)
epochs _ no _ improve = 0
min _ val _ loss = val _ loss否则*
*如果 iter % 500 == 0:
计算精度
正确= 0
总计= 0迭代测试数据集
检查提前停止条件
如果 epochs _ no _ improve = = n _ epochs _ stop:
打印('提前停止!')
early _ stop = True
break
else:
continue
break
if early _ stop:
print(" Stopped ")
break对于图像,test_loader 中的标签:
Resize images
images = images . view(-1,seq_dim,input_dim)*
#仅向前传递以获取逻辑/输出
输出=模型(图像)#从最大值得到预测值
_,predicted = torch . max(outputs . data,1)#标签总数
total += labels.size(0)#正确预测总数
正确+=(预测==标签)。总和()*准确度= 100 正确/总计
# Print Loss
print('迭代:{}。损失:{}。准确性:{} '。format(iter,loss.item(),accuracy))
Description: Training the RNN using early Early Stopping.
模型调查及结论:
该模型很好地检测了与先前数字无关的手写数字。如果这些数字是跨序列相关的(长期和短期相关),该模型不会做得很好。
通过时间的反向传播算法是昂贵的,因为在正向传递中计算的状态将被存储,直到它们在反向传递中被重用,所以存储器成本也是 O(T)。
RNNs 可能面临的另一个问题是“悬崖”。非线性函数会出现这种情况,因为它们的导数的大小可能非常大,也可能非常小。 【裁剪渐变】 是一种技术,用于使渐变下降更合理,并限制步长。
我希望这能让你了解 rnn 是如何形成的,它们的直觉是如何塑造深度学习世界的。
一些让你入门的好的研究论文和书籍:
- Alex Graves: [用递归神经网络生成序列](http://Generating Sequences With Recurrent Neural Networks) 。
- 深度学习:伊恩·古德菲勒
- 用于模式识别的神经网络。
- Y .本吉奥;P. SimardP. Frasconi: 学习具有梯度下降的长期依赖关系是困难的
一如既往地欢迎评论。
LSTM 预测股票价格—时间序列数据
金融时间序列预测
基于神经网络的多变量建模方法
金融序列的预测一直是一项复杂的任务,吸引了学术界、投资公司、银行等的极大关注。价格预测通常基于统计标准进行评估,例如 平均误差、平均绝对误差(MAE)或均方根误差(RMSE) 。我们已经 看到了 多个时间序列之间的关系 ( 黄金价格、白银价格、原油价格、股票指数、利率和美元汇率) 以及它们如何相互影响 。
让我们使用相同的数据集,并尝试使用【RNN】算法来解决我们的预测问题。众所周知,神经网络在多输入变量的情况下效率很高。
先把已经处理好的数据载入;如果有任何数据错误,希望我们的模型将学会忽略。
**
单输出前馈网络:
先来了解一下前馈网络的数学直觉。
其中, x1,x2…xk 是输入序列, ŷ 是输出序列,中间是一串隐藏层。然而,这里的问题是-
- 信息不考虑时间顺序
- 输入是独立处理的
- 没有保存过去信息的机制
前馈网络结构没有内置存储器。此外,出现了一种情况,其中深层多层前馈网络不能将有用的梯度信息从模型的输出端传播回模型输入端附近的层”
为了克服这些困难, RNN 被引入,它带有一个网络架构,可以-
- 保留过去的信息
- 跟踪世界的状态
- 随着网络速度的加快,更新世界的状态
“RNN 通过具有递归隐藏状态来处理可变长度序列,该隐藏状态的每次激活都依赖于前一次的激活”
下面的图表和等式清楚地说明了 RNN 是如何工作的
其中,𝑥𝑡表示输入,ℎ𝑡表示从输入到输出的隐含层, yt 为输出。最重要的是,它有一个循环回路,循环回到过去,以表示输出不仅是新输入的函数,而且是过去隐含层的函数,这样网络就能保持增长。然而,它有一个问题爆炸和消失梯度。递归神经网络(LSTM)* 解决了这个问题。它们是带有环路的网络,允许信息持续存在。对于 LSTM 来说,最重要的概念是单元的状态,这些信息通过嵌入在单元顶部的 yt 数据在单元之间相互传输。*
在上图中,神经网络 A 的一个块查看某个输入 xt 并输出一个值 ht。环路允许信息从网络的一个步骤传递到下一个步骤。这些循环使得递归神经网络成为一种神秘的物体。然而,它们与普通的神经网络并没有什么不同。一个递归神经网络是同一个网络的多个副本,每个副本向后继者传递一个信息。细胞状态就像一条传送带,通过整个链条传送。细胞可以对这些信息进行微小的改变。牢房里有门。这些门包含一个 sigmoid 功能,并根据输出值打开和关闭 sigmoid 功能。然后门输出值和 yt 值相乘。sigmoid 函数输出可以取 0 到 1 之间的值,而零值将关闭信息转换,并在整个信息中移动一个值。如果循环展开,如下图所示-
这种链状性质揭示了递归神经网络与序列和列表密切相关。它们是用于此类数据的神经网络的自然架构。让我们考虑在时间步 t 的隐藏状态 ht 。LSTM 单元需要决定的第一件事是报告单元状态。这个决定是由忘栅层做出的。遗忘门层通过查看ht1和𝑥𝑡.,为每个yt1生成一个在 0 和 1 之间的值 1 表示数据被存储,0 表示数据将被遗忘。由忘记栅极层执行的过程的数学表达式:
下一步是关于是否在单元状态中记录新信息。输入门层决定更新哪个值。输入栅极层和输入栅极层的输出可以表示为:
非线性函数层 (tanh) ,其生成新的候选值的向量, ŷt ,其可以被添加到状态。
**
然后更新旧的单元状态,并确定代表新的单元状态的 y𝑡值。可以写出下面的等式来获得新的 y𝑡值。
最后,为确保输出值介于-1 和 1 之间并对输出进行滤波,输出函数可指定为:
LSTM 也有渐变消失的问题,但没有基本的 RNN 那么严重。区别在于对于基本 RNN,梯度随 wσ′(⋅衰减,而对于 LSTM,梯度随σ(⋅).衰减对于 LSTM,有一组可以学习的权重,例如σ(⋅)≈1.假设对于某个权重 w 和输入 x,vt + k = wx,那么神经网络可以学习一个大的 w 来防止梯度消失。对于基本的 RNN ,没有一套可以学习的砝码:
在 Keras 中的 LSTM 模型假设数据分为输入(x)和输出(y)分量。这可以通过在时间序列中使用来自上一时间步(t-1)的观测值作为输入和当前时间步(t)的观测值作为输出来实现。
让我们添加一个“pred”列作为我们的输出,并移动它。
标准化数据:
缩放和标准化是形成神经网络架构的重要活动。
如果我们检查数据,它有一个很宽的值范围 (1.336,13592.79) 而神经网络在这种范围内表现不好。
我们定义了一个函数来指定回看间隔(60 个时间步长)和预测列,如下所示。
拆分数据并将其转换为正确的形状:
在这里,我将数据按 80/20 的比例进行了拆分。此外,我们需要将数据整形为 3D 数组,以供读取和训练模型。**
我们可以看到,训练集包含 4103 个数据点,测试集包含 966 个数据点。
LSTM 网络架构:
现在,我们添加 LSTM 层和几个脱落层,以防止过度拟合。我在网络中增加了 3 层。对于网络架构,需要考虑以下因素:
- 50 个单位,这是输出空间的维度,
- return_sequences = True,决定是返回输出序列中的最后一个输出,还是整个序列,
- input_shape 作为训练集的形状,
- 指定为 0.2 的丢弃层,即将丢弃 20%的层,
- 此后,我添加了指定 1 个单位输出的密集层,
接下来,该模型适合在 100 个时期上运行,并且的批量大小为 32 。代替在完整的观察序列上训练【RNN】,我们使用了从训练数据中随机选取的一批较短的子序列(32)。
**model_lstm = tf.keras.Sequential()
model_lstm.add(tf.keras.layers.LSTM(75, return_sequence = True, input_shape = (xtrain.shape[1], xtrain.shape[2])))
model_lstm.add(tf.keras.layers.LSTM(units=30, return_sequence=True))
model_lstm.add(tf.keras.layers.LSTM(units=30))
model_lstm.add(tf.keras.layers.Dense(units=1))
model_lstm.Compile(loss = 'mae', optimizer = 'adam')
model_lstm.summary()history_lstm = model_lstm.fit(xtrain, ytrain, epochs = 15, batch_size=32, validation_data = (xtest, ytest), shuffle=False)**
创建了训练集和测试集的模型准确度的线图,显示了所有 15 个训练时期的性能变化。下面的测试数据(蓝色)与预测值(橙色)的线图提供了模型技能的背景。
用于预测的拟合 LSTM 模型:
模型符合训练数据;因此,它可以用来做预测。现在,使用训练好的模型来预测测试数据集中的【pred】值。我在这里使用固定的方法进行预测。
固定方法:我们可以决定对所有训练数据拟合一次模型,然后从测试数据中一次一个地预测每个新的时间步长
动态方法:当从测试数据中获得新的观察结果时,我们可以在测试数据的每个时间步重新拟合模型或更新模型。
我们必须反转预测的标度,将数值返回到原始标度,以便可以解释结果并计算出可比的误差分数。
****
现在我们可以看到,我们还没有完全实现。结果并不令人印象深刻。我们可以检查这两者之间的差异,并以各种方式比较结果&在建立交易策略之前优化模型。
让我们看看是否可以通过移动 10 个时间步长和做一些超参数调整来提高模型性能。
在训练集和测试集上,这里的线图看起来比前两个更好。该模型似乎能够快速学习问题,在大约 20 个时期内收敛到一个解决方案。损耗指标,如 RMSE、平均损耗,可以通过前面所示的类似方法获得。
虽然有一些改进,但在预测方面,我们仍有改进的余地。这里的一个重要因素是,我们在这个模型中使用了每日价格,因此数据点实际上很少,对于神经网络架构,只有 5129 个数据点。我建议使用超过 100,000 个数据点,使用分钟或分笔成交点数据来训练模型,同时建立 ANN 或任何其他深度学习模型,以便最有效。
总结:
为了公平地测量网络的性能,使用了六个不同的时间序列。利用格兰杰因果关系,我们发现这些序列互为因果。得到的估算结果与图表进行了比较。 RMSE 和 R 值作为预测成功的标准进行检查。然而,通过更多的数据点和改变 LSTM 网络的超参数,有可能获得更成功的结果。
我可以到达 这里 。
递归神经网络和自然语言处理。
递归神经网络(RNNs)是机器学习算法的一种形式,对于诸如文本、时间序列、金融数据、语音、音频、视频等序列数据是理想的。
Image source: Unsplash
rnn 是解决序列比单个项目本身更重要的问题的理想方法。
RNNs 本质上是一个完全连接的神经网络,它包含将其某些层重构为一个循环。该循环通常是对两个输入、矩阵乘法和非线性函数的相加或级联的迭代。
在文本用法中,rnn 擅长执行以下任务:
- 序列标记
- 自然语言处理(NLP)文本分类
- 自然语言处理文本生成
rnn 有效解决的其他任务是时间序列预测或其他不是基于图像或表格的序列预测。
关于文本生成的进步,尤其是 OpenAI 的 GPT-2 算法,媒体上有一些突出和有争议的报道。在许多情况下,生成的文本通常与人类书写的文本难以区分。
我发现学习 rnn 如何工作以及如何构造它们和它们的变体是我必须学习的最困难的课题之一。我要感谢 Fastai 团队和杰瑞米·霍华德,他们的课程以一种更容易理解的顺序解释了这些概念,我在这篇文章的解释中也遵循了这一顺序。
rnn 实际上有一个内部存储器,允许以前的输入影响随后的预测。如果你知道前面的单词是什么,那么预测句子中的下一个单词就容易得多。
通常对于非常适合 RNNs 的任务,项目的顺序与序列中的前一个项目一样重要或者更重要。
当我在我的智能手机上输入这篇文章的草稿时,我手机键盘上的下一个单词将会被 RNN 预测出来。例如,swift key 键盘软件使用 RNNs 来预测您正在键入的内容。
自然语言处理
自然语言处理(NLP)是计算机科学和人工智能的一个子领域,处理和生成自然语言数据。虽然仍然有机器学习之外的研究,但现在大多数 NLP 都是基于机器学习产生的语言模型。
NLP 是 RNNs 的一个很好的用例,并在本文中用来解释如何构建 RNNs。
语言模型
语言模型的目标是最小化模型看到给定文本序列时的混乱程度。
每个域只需要训练一个语言模型,因为语言模型编码器可以用于不同的目的,例如文本生成和该域内的多个不同的分类器。
由于训练的最长部分通常是创建语言模型编码器,重用编码器可以节省大量的训练时间。
将 RNN 与完全连接的神经网络进行比较
如果我们用一个由三个单词组成的文本序列和一个预测第四个单词的网络。
该网络具有三个隐藏层,每一层都是仿射函数(例如矩阵点积乘法),后面是非线性函数,然后最后一个隐藏层后面是来自最后一层激活函数的输出。
代表序列中每个单词的输入向量是在单词嵌入矩阵中的查找,基于代表词汇表中单词的一个热编码向量。注意,所有输入的单词都使用相同的单词嵌入。在这个上下文中,单词实际上是一个可以表示单词或标点符号的记号。
输出将是表示序列中预测的第四个字的一个热编码矢量。
第一隐藏层将表示序列中第一个单词的向量作为输入,输出激活作为第二隐藏层的输入之一。
第二隐藏层从第一隐藏层的激活中获取输入,并且还获取表示为向量的第二单词的输入。这两个输入可以相加或连接在一起。
第三隐藏层遵循与第二隐藏层相同的结构,从第二隐藏层结合表示序列中第三个单词的向量来获取激活。同样,这些输入被相加或连接在一起。
来自最后一个隐藏层的输出经过一个激活函数,该函数产生一个输出,该输出将词汇表中的一个单词表示为一个热编码向量。
第二个和第三个隐藏层可以使用相同的权重矩阵,这为将其重构为循环提供了机会。
A fully connected network for text generation/prediction. Source: Fastai deep learning course V3 by Jeremy Howard.
词汇
词汇表是一个数字向量,称为标记,其中每个标记代表我们语料库中的一个独特的单词或标点符号。
通常,在组成语料库的文本中不出现至少两次的单词通常不会被包括在内,否则词汇量会太大。我想知道这是否可以用作检测生成文本的一个因素,寻找在给定领域中不常见的单词的存在。
单词嵌入
单词嵌入是一个权重矩阵,词汇表中的每个单词/单词对应一行
与一个热编码向量的矩阵点积乘法输出表示来自该单词的激活的矩阵行。它本质上是矩阵中的行查找,并且在计算上更有效,这被称为嵌入查找。
使用来自单词嵌入的向量有助于防止产生的激活非常稀疏。如果输入是一个热编码向量,除了一个元素之外都是零,则大多数激活也将是零。这将很难训练。
用一个循环重构,一个 RNN
对于循环网络,需要在网络模型中考虑一个环路。对每个单词输入使用相同的嵌入权重矩阵是有意义的。这意味着我们可以在一个循环中用迭代替换第二层和第三层。
循环的每一次迭代都接受一个向量的输入,该向量表示序列中的下一个单词,输出来自上一次迭代的激活。这些输入被相加或连接在一起。
最后一次迭代的输出是句子中下一个单词的表示,该单词通过最后一层激活函数,该函数将其转换成表示词汇表中单词的一个热编码矢量。
A basic RNN. Source: Fastai deep learning course V3 by Jeremy Howard.
这使得网络可以预测任意长度序列末尾的单词。
通过环路保持输出,改善 RNN
一旦在单词序列的末尾,下一个单词的预测输出可以被存储,附加到一个数组,在下一次迭代中用作附加信息。然后,每次迭代都可以访问以前的预测。
对于给定数量的输入,会产生相同数量的输出。
An improved RNN retaining its output. Source: Fastai deep learning course V3 by Jeremy Howard.
理论上,预测文本序列的长度可以是无限的,预测单词跟随循环中最后一个预测单词。
留住历史,更好的 RNN
对于每个新批,前一批序列的历史(状态)通常会丢失。假设句子是相关的,这可能会失去重要的洞察力。
为了帮助我们在开始每一批时进行预测,了解最后一批的历史记录比重置它更有帮助。这保留了状态,因此保留了上下文,这导致对单词的理解是更好的近似。
请注意,对于一些数据集,例如十亿个单词,每个句子都与前一个句子不相关,在这种情况下,这可能没有帮助,因为句子之间没有上下文。
穿越时间的反向传播
时间反向传播(BPTT)是训练期间使用的序列长度。如果我们试图训练 50 个单词的序列,BPTT 就是 50。
通常文件被分成 64 个相等的部分。在这种情况下,BPTT 是以单词为单位的文档长度除以 64。如果文档的字数是 3200,那么除以 64 得到的 BPTT 是 50。
稍微随机化每个序列的 BPTT 值有助于改进模型。
分层 RNNs
为了让更多层的计算能够解决或近似更复杂的任务,RNN 的输出可以被输入到另一个 RNN,或任何层数的 rnn。下一节将解释如何做到这一点。
扩展 RNNs 以避免消失梯度
由于 rnn 的层数增加了损耗,并且变得不可能训练,这就是消失梯度问题。为了解决这个问题,可以使用门控循环单元(GRU)或长期短期记忆(LSTM)网络。
LSTMs 和 GRUs 获取当前输入和前一个隐藏状态,然后计算下一个隐藏状态。
作为计算的一部分,sigmoid 函数将这些向量的值压缩在 0 和 1 之间,通过将它们与另一个向量相乘,您可以定义想要“通过”该向量的多少
长期短期记忆(LSTM)
RNN 人有短期记忆。当与长短期记忆(LSTM)门结合使用时,网络可以具有长期记忆。
LTSM 不是 RNN 的循环部分,而是由四个神经网络层组成的小型神经网络。这些是来自 RNN 的循环层,三个网络充当入口。
除了隐藏状态,LSTM 还有一个单元格状态。这种细胞状态就是长期记忆。不是在每次迭代中只返回隐藏状态,而是返回由单元状态和隐藏状态组成的隐藏状态元组。
长短期记忆(LSTM)有三个门。
- 一个输入门,它控制每个时间步的信息输入。
- 一个输出门,它控制输出到下一个单元或上一层的信息量
- 这是一个遗忘门,控制着在每个时间步丢失多少数据。
门控循环单元(GRU)
门控循环单元有时被称为门控循环网络。
在每次迭代的输出处,有一个具有三个实现的神经网络层的小神经网络,包括来自 RNN 的递归层、复位门和更新门。更新门充当遗忘和输入门。这两个门的耦合执行与 LSTM 中的三个门遗忘、输入和输出类似的功能。
与 LSTM 相比,GRU 具有合并的单元状态和隐藏状态,而在 LSTM 中这些是分开的。
复位门
重置门从最后一层获取输入激活,这些激活被乘以介于 0 和 1 之间的重置因子。重置因子由没有隐藏层的神经网络计算(如逻辑回归),这在权重矩阵和先前隐藏状态与我们的新输入的相加/串联之间执行点积矩阵乘法。然后,这一切都通过 e^x / (1 + e^x).)的 sigmoid 函数
这可以学会在不同的情况下做不同的事情,例如,如果有一个句号标记,就忘记更多的信息。
更新门
更新门控制接受多少新输入和接受多少隐藏状态。这是一个线性插值。这是 1-Z 乘以先前的隐藏状态加上 Z 乘以新的隐藏状态。这控制了我们在多大程度上保留以前状态的信息,以及在多大程度上使用新状态的信息。
更新门在图中通常表示为一个开关,尽管该门可以在任何位置创建两个隐藏状态之间的线性插值。
A RNN with a GRU. Source: Fastai deep learning course V3 by Jeremy Howard.
GRU 和 LSTM 哪个更好
这完全取决于所讨论的任务,通常两者都值得一试,看看哪一个执行得更好。
文本分类
在文本分类中,网络的预测是对文本属于哪个或哪些组进行分类。一个常见的用途是分类一段文本的情感是积极的还是消极的。
如果像本文前面 RNN 解释的那样,训练一个 RNN 从给定领域的语料库中预测文本,那么它被重新用于该领域的文本分类是接近理想的。网络的代“头”被移除,留下网络的“骨干”。脊柱内的重量可以被冻结。然后,可以将新的分类头连接到主干上,并对其进行训练以预测所需的分类。
逐渐解冻层内的权重是一种非常有效的加速训练的方法。从最后两层的权重开始,然后是最后三层的权重,最后全部解冻所有层的权重。
迁移学习和 Wikitext 103 数据集
wikitext 103 数据集包含超过 1.03 亿个来自维基百科的好的或有特色的标记。
在 wikitext 103 数据集上训练的预训练模型是可用的,这可以用于几乎任何语言处理任务的迁移学习。它比任何随机初始化都更接近于任何书面文本。这是没有免费午餐理论的矛盾之一。大多数时候,在你开始训练之前,算法就已经接近解决方案了。
Fastai 课程
我要感谢 Fastai 团队,他们的课程帮助巩固了我的深度学习和 RNN 知识,为进一步的学习和理解提供了良好的基础。
递归神经网络
记住什么是重要的
递归神经网络(RNNs)为基本神经网络增加了一个有趣的转折。标准神经网络采用固定大小的向量作为输入,这限制了它在涉及没有预定大小的“系列”类型输入的情况下的使用。
Figure 1: A vanilla network representation, with an input of size 3 and one hidden layer and one output layer of size 1.
rnn 被设计成接受一系列输入,没有预先确定的大小限制。有人可能会问这有什么大不了的,我也可以反复调用一个常规 NN?
Figure 2: Can I simply not call a vanilla network repeatedly for a ‘series’ input?
当然可以,但是输入的“系列”部分意味着什么。系列中的单个输入项与其他项相关,并可能对其相邻项产生影响。否则它只是“许多”输入,而不是“一系列”输入(咄!).
因此,我们需要有意义地捕捉这种跨输入关系的东西。
递归神经网络
递归神经网络记住过去,并且它的决策受到它从过去所学到的东西的影响。注意:基本的前馈网络也能“记住”东西,但它们记住的是在训练中所学的东西。例如,图像分类器在训练中学习“1”的样子,然后使用该知识对生产中的事物进行分类。
此外,虽然 rnn 在训练时学习类似,但是它们在生成输出时记住从先前输入中学到的东西。这是网络的一部分。RNNs 可以采用一个或多个输入向量,并产生一个或多个输出向量,并且输出不仅受应用于输入的权重的影响,如常规 NN,还受表示基于先前输入/输出的上下文的“隐藏”状态向量的影响。因此,相同的输入可能会产生不同的输出,这取决于序列中先前的输入。
Figure 3: A Recurrent Neural Network, with a hidden state that is meant to carry pertinent information from one input item in the series to others.
总之,在普通的神经网络中,固定大小的输入向量被转换成固定大小的输出向量。当你对一系列给定的输入反复应用变换并产生一系列输出向量时,这样的网络就变成了“循环的”。对向量的大小没有预设限制。此外,除了生成作为输入和隐藏状态的函数的输出,我们还基于输入更新隐藏状态本身,并在处理下一个输入时使用它。
参数共享
您可能已经注意到了图 1 和图 3 之间的另一个关键区别。在早期,多个不同的权重被应用于输入项的不同部分,生成隐藏层神经元,该隐藏层神经元又使用进一步的权重进行转换,以产生输出。这里似乎有很多砝码在起作用。而在图 3 中,我们似乎一遍又一遍地对输入序列中的不同项目应用相同的权重。
我相信你会很快指出我们在这里比较苹果和橘子。第一张图处理“一个”单个输入,而第二张图表示来自一系列的多个输入。但是尽管如此,从直觉上讲,随着输入数量的增加,游戏中的权重数量不也应该增加吗?我们是否在图 3 中失去了一些通用性和深度?
也许我们是。我们在图 3 中共享输入参数。如果我们不在输入之间共享参数,那么它就像一个普通的神经网络,每个输入节点都需要自己的权重。这引入了输入长度必须固定的约束,并且使得不可能利用长度不同并且不总是已知的串行类型输入。
Figure 4: Parameter sharing helps get rid of size limitations
但是,我们在这里看似失去的价值,通过引入将一个输入链接到下一个输入的“隐藏状态”又回来了。隐藏状态捕获串行输入中邻居之间可能存在的关系,并且它在每一步中都保持变化,因此实际上每个输入都经历不同的转换!
图像分类 CNN 已经变得如此成功,因为 2D 卷积是参数共享的有效形式,其中每个卷积滤波器基本上提取图像中特征的存在或不存在,该特征不仅是一个像素的函数,而且是其周围相邻像素的函数。
换句话说,CNN 和 RNNs 的成功可以归功于“参数共享”的概念,与普通神经网络相比,这是一种以更内在的方式利用一个输入项与其周围邻居之间关系的基本有效方式。
深层 RNNs
虽然隐藏状态的引入使我们能够有效地识别输入之间的关系,这是一件好事,但我们有没有办法使 RNN“深入”,并获得我们通过典型神经网络中的“深度”获得的多级抽象和表示?
Figure 4: We can increase depth in three possible places in a typical RNN. This paper by Pascanu et al., explores this in detail.
这里有四种增加深度的方法。(1)也许最明显的是增加隐藏状态,一个在另一个之上,把一个的输出提供给下一个。(2)我们还可以在输入到隐藏状态之间添加额外的非线性隐藏层(3)我们可以增加隐藏到隐藏过渡的深度(4)我们可以增加隐藏到输出过渡的深度。Pascanu 等人的论文对此进行了详细的探讨,并且总体上确定了深 rnn 比浅 rnn 的性能更好。
双向 RNNs
有时候,这不仅仅是从过去学习来预测未来,我们还需要展望未来来修复过去。在语音识别和手写识别任务中,如果只给出输入的一部分,可能会有相当大的歧义,我们通常需要知道接下来会发生什么,以便更好地理解上下文并检测当前情况。
Figure 5: Bidirectional RNNs
这确实带来了一个显而易见的挑战,那就是我们需要对未来进行多大程度的研究,因为如果我们不得不等待看到所有的投入,那么整个运营将变得非常昂贵。在像语音识别这样的情况下,等待整个句子被说出可能会导致不太引人注目的用例。而对于 NLP 任务,输入往往是可用的,我们可能会一次考虑整个句子。此外,根据应用,如果对最近和更近的邻居的敏感度高于对更远的输入的敏感度,则可以对仅查看有限的未来/过去的变量进行建模。
递归神经网络
递归神经网络以连续的方式分析输入。递归神经网络在某种程度上类似于将转换重复应用于输入,但不一定是按顺序的方式。递归神经网络是递归神经网络的更一般形式。它可以在任何层次树结构上操作。通过输入节点进行解析,将子节点组合成父节点,并将它们与其他子/父节点组合以创建树状结构。递归神经网络做同样的事情,但是那里的结构是严格线性的。即权重被应用于第一个输入节点,然后是第二个、第三个等等。
Figure 6: Recursive Neural Net
但是这提出了关于结构的问题。我们如何决定?如果结构像在递归神经网络中一样是固定的,那么训练、反向传播等过程是有意义的,因为它们类似于常规的神经网络。但是如果结构不固定,那也是学来的吗?本文和Socher 等人的本文探索了一些解析和定义结构的方法,但是考虑到计算上的复杂性,甚至更重要的是,在获得必要的训练数据方面,递归神经网络似乎不如它们的递归表亲流行。
编码器解码器序列到序列 rnn
编码器、解码器或序列到序列 rnn 在翻译服务中大量使用。基本思想是有两个 rnn,一个是不断更新其隐藏状态并产生最终单一“上下文”输出的编码器。然后,这被馈送到解码器,解码器将该上下文翻译成输出序列。这种安排的另一个关键区别是输入序列的长度和输出序列的长度不必相同。
Figure 6: Encoder Decoder or Sequence to Sequence RNNs
LSTMs
我们不能关闭任何试图在不提及 LSTMs 的情况下查看 rnn 和相关架构的帖子。这不是 RNN 架构的不同变体,而是它引入了我们如何使用输入计算输出和隐藏状态的变化。
这篇文章很好地介绍了 LSTMS。在普通的 RNN 中,输入和隐藏状态只是通过一个 tanh 层传递。LSTM(长短期记忆)网络对这种简单的转换进行了改进,并引入了额外的门和单元状态,从而从根本上解决了跨句子保持或重置上下文的问题,并且与这种上下文重置之间的距离无关。存在包括 gru 的 LSTMs 的变体,其以不同的方式利用门来解决长期依赖性的问题。
到目前为止,我们在这里看到的只是普通的架构和一些众所周知的变体。但是了解了 rnn 和相关的变体之后,我们更加清楚地知道,设计一个好的架构的诀窍是了解不同的架构变体,理解每种变化带来的好处,并适当地将这些知识应用于手头的问题。
递归神经网络:NLP 的深度学习
这篇文章涵盖了不同类型的 RNN,包括 LSTM 和 CRF 网络
每当你问 Alexa 一道菜的配方或一位艺术家的新歌时,一个复杂的代码就会在后台运行,为你提供相关的答案。这只是在最近几年才成为可能。到目前为止,从非结构化文本数据中理解和提取信息只能通过手工操作,更不用说自动确认用户请求了。
Image by Author
将文本数据暴露给各种数学和统计技术的革命性想法背后的基本概念是自然语言处理(NLP)。顾名思义,目标是理解人类所说的自然语言,并在此基础上做出响应和/或采取行动,就像人类一样。不久,改变生活的决定将仅仅通过与机器人交谈来做出。
在本文中,我将尝试提供对神经网络的一些基本理解,这对 NLP 的目的特别有用。我们不会深入研究每种算法的数学原理,但是,我们会尝试理解其背后的直觉,这将使我们处于一个舒适的位置,开始将每种算法应用于现实世界的数据。
我们开始吧。
递归神经网络(RNN)
RNN 是广泛用于自然语言处理的神经网络结构。在建立语言模型和语音识别任务中,它被证明是相对准确和有效的。
如果预测必须在单词级别,例如命名实体识别(NER)或词性(POS)标注,rnn 特别有用。因为它存储了当前特征以及用于预测的相邻特征的信息。RNN 维护基于历史信息的记忆,这使得模型能够预测基于长距离特征的当前输出。下面是 NER 使用 RNN 的一个例子。
Recurrent Neural Network (RNN) — Image by Author
长短期记忆细胞(LSTM)
尽管 RNN 可以学习依赖性,但是它只能学习最近的信息。LSTM 可以帮助解决这个问题,因为它可以理解上下文以及最近的依赖性。因此,LSTM 是一种特殊的 RNN,在这种情况下,理解背景会有所帮助。
LSTM 网络类似于 rnn,一个主要区别是隐藏层更新由存储单元代替。这使他们更善于发现和揭示数据中的长期依赖关系,这对句子结构是必不可少的。下图显示了 LSTM 序列标签模型的表示,该模型用 LSTM 记忆单元代替了隐藏层。
LSTM network — Image by Author
双向 LSTM 网络
顾名思义,这些网络是双向的,也就是说,在给定时间内,它可以访问过去和未来的输入要素。这在序列标记中尤其重要。
Bidirectional LSTM — Image by Author
CRF 网络
条件随机场(CRF)在进行预测时会考虑上下文。BiLSTM 和 CRF 的区别在于前者使用两个方向的输入特征,而后者使用标签生成。这里,输入和输出是直接相连的,而不是 LSTMs 网络。此外,如下所示,连接的是输出标签信息,而不是输入要素。
CRF network — Image by Author
LSTM-CRF 网络
该网络是 LSTM 和 CRF 网络的结合,利用了两者的优点。该网络可以通过 LSTM 层有效地使用过去的输入特征,并通过 CRF 层有效地使用句子级标签信息。
LSTM-CRF model — Image by Author
双 LSTM-CRF 网络
该网络与之前的网络相似,唯一的区别是 LSTM 网络被双 LSTM 网络所取代,从而实现了更高的性能。正如我们已经知道的,双 LSTM 使用过去和未来的输入特征,这有助于提高标记的准确性。
BiLSTM-CRF model — Image by Author
这提供了可以应用于文本数据的深度学习网络的基本思想。下一个合理的步骤是获取一些文本数据并开始实现这些算法,以查看真实的结果并进行比较,这是我将在下一篇文章中讨论的内容。敬请关注。
用于衰退预测的递归神经网络
语境
人们普遍认为,美国经济将在未来几年面临另一场衰退。问题是什么时候以及如何发生。我们目睹了十年的经济扩张,但这不会永远持续下去。在这篇文章中,我将尝试一个基本的递归神经网络(RNN)模型来预测美国经济将如何增长,或者在不久的将来可能萎缩。
方法
你可能知道,在过去的几十年里,我们没有经历过多少次衰退,最近的一次是在 2008 年全球金融危机之后。这可能是任何机器/深度学习分类器模型的一个障碍。衰退的定义之一是“连续两个季度经济负增长”,因此估计 GDP 增长的回归模型应该足以满足目的。此外,由于潜在国内生产总值相当稳定,国内生产总值增长中的周期性因素,即产出缺口,将是回归模型的一个良好目标。
这是一种时间序列分析,由于其自回归性质,RNN 是最合适的工具之一。我使用了美联储经济数据中的主要宏观经济和金融变量,这些数据是由圣路易斯美联储银行的研究部门提供的,自 20 世纪 70 年代以来,并将它们重新采样到每周频率中。RNN 模型的输入包括 30 个顶级主成分,52 个时间步长为一周,即一年。这里的目标是提前 6 个月的产出缺口。
模型-LSTM 层
我从一个简单的模型开始,这个模型有两个长短期记忆(LSTM)层。
regressor = Sequential()
regressor.add(LSTM(units=50,
return_sequences=True,
input_shape=(X_train_rnn.shape[1],
X_train_rnn.shape[2])))
regressor.add(Dropout(drop_out))
regressor.add(LSTM(units=50))
regressor.add(Dropout(drop_out))regressor.add(Dense(units=1))regressor.compile(optimizer='adam',
loss='mean_squared_error')
下图描述了十次试验的模型预测。很明显,预测波动太大,不能说这个模型是可靠的。
Source: FRED, author’s calculation
可能的情况是,模型没有学习到足够的知识,更深的模型可以稳定预测,而增加层往往会导致更多的过度拟合。
Source: FRED, author’s calculation
如你所见,在增加几个 LSTM 层后,预测的波动下降到-2.5%~2.5%的合理范围。比较具有不同数量 LSTM 图层的模型的均方根误差,您会发现具有六个或更多 LSTM 图层有助于控制误差的级别和方差。
Source: FRED, author’s calculation
模特-辍学
尽管添加更多的 LSTM 图层可以降低预测的方差,但模型仍然存在过度拟合的问题。较大的辍学率可能会有所帮助,不同的辍学率进行了审查。下面的图表代表了不同退出率的模型的十次试验。
Source: FRED, author’s calculation
目前还不清楚退出在多大程度上缓解了过度拟合,而过高的退出率会增加误差。看看均方根误差的分布,我们会说辍学率应该不高于 0.6。
Source: FRED, author’s calculation
观察
预测未来的经济状况并不容易,即使是从现在开始的六个月。上述模型都无法预测 2008-2009 年的急剧下滑。一个主要问题是数据可用性有限;我们只有 2200 个数据点来训练和测试模型。还应该看到,经济结构一直在不断变化。每次衰退的背景都不一样。因此,模型很难以一种概括的方式充分学习。
后续步骤
然而,这些模型似乎还有改进的空间。为了解决过拟合问题,我们可以考虑正则化,或者潜在地使用从输入变量中提取的循环因子(例如带通滤波器)。门控循环单位(GRU)代替 LSTM 可以减轻过度拟合。
递归神经网络(RNN)解释 ELI5 方式
ELI5 项目机器学习
Photo by Michael Fruehmann on Unsplash
序列建模是预测下一个单词/字母的任务。序列模型计算一定数量的单词在特定序列中出现的概率。与 FNN 和 CNN 不同,在序列建模中,当前输出不仅依赖于当前输入,还依赖于先前输入。在序列模型中,输入的长度是不固定的。
引用注: 本文的内容和结构是基于我对四分之一实验室深度学习讲座——pad hai的理解。
递归神经网络
递归神经网络(RNN) 是一种神经网络,前一步的输出作为当前步骤的输入。
RNN 主要用于,
- 序列分类 —情感分类&视频分类
- 序列标注 —词性标注&命名实体识别
- 序列生成 —机器翻译&音译
序列分类
在这一节中,我们将讨论如何使用 RNN 来完成序列分类的任务。在序列分类中,我们将得到一个句子的语料库和相应的标签,即…句子的情感,无论是肯定的还是否定的。
在这种情况下,我们不需要在输入的每个单词后输出,而是我们只需要在阅读整个句子后理解情绪,即…积极或消极。
从上图可以看出,输入的句子长度不等。在将数据输入 RNN 之前,我们需要预处理数据,以使输入序列长度相等(输入矩阵的维数固定为 mxn)。输入的单词应该被转换成一个独热码表示向量。
预处理数据
在处理过程中,我们定义了一些特殊字符,如序列的开始,序列的结束。
所有输入序列都附加有“””
我们应用填充的方式是,
- 找出所有序列的最大输入长度(比如 10)
- 将特殊字 <填充> 添加到所有较短的序列中,使它们具有相同的长度(本例中为 10)。
一旦我们做了预处理(添加特殊字符),我们必须将这些包含特殊字符的单词转换成一个热点向量表示,并将它们输入网络。
关于填充需要注意的要点是:
- 填充只是为了确保输入序列大小一致。
- RNN 中的计算仅执行到“ 序列结束 ”特殊字符,即…填充不被认为是网络的输入。
序列标记
词性标注是对序列中每个单词的词性标签进行标注(预测)的任务。同样,在这个问题中,当前时间步长的输出不仅取决于当前输入(当前字),还取决于先前的输入。例如,如果我们知道前面的单词是形容词,那么将单词“movie”标记为名词的概率会更高。
与序列分类问题不同,在序列标记中,我们必须预测序列中出现的每个单词在每个时间步的输出。正如我们从图像中看到的,由于我们在第一个序列中有 6 个单词,我们将根据句子的结构得到 6 个词性预测。
因为我们的输入序列长度可变,所以我们必须预处理数据,使输入序列长度相等。请记住,RNN 只有在遇到“
模型
在前面的部分中,我们讨论了在将数据输入模型之前,可以使用 RNN 的一些任务以及要执行的预处理步骤。在这一节中,我们将讨论如何模拟(近似函数)输入和输出之间的真实关系。
序列分类
我们已经知道,在序列分类中,输出依赖于整个序列。通过分析评论来预测这部电影的发展趋势。
该功能的输入以橙色表示,并表示为一个 xᵢ 。使用向量 U 来表示与输入相关联的权重,并且将单词的隐藏表示( sᵢ) 计算为先前时间步长的输出和当前输入以及偏差的函数。隐藏的表示将被计算直到序列的长度(sₜ).
来自网络的最终输出(y_hat)是隐藏表示和与其相关联的权重以及偏差的 softmax 函数。
序列标记
在序列标记中,我们必须预测每个时间步的输出,这不同于序列分类中最后的预测。
数学公式与序列分类略有不同,在这种方法中,我们将预测每个时间步后的输出。
一旦我们计算了隐藏表示,来自网络的特定时间步长的输出( yᵢ )是隐藏表示和与其相关联的权重以及偏差的 softmax 函数。类似地,我们将计算序列中每个时间步的隐藏表示状态和预测输出。
损失函数
损失函数的目的是告诉模型在学习过程中需要进行一些校正。
在序列分类问题的背景下,为了比较两种概率分布(真实分布和预测分布),我们将使用交叉熵损失函数。损失函数等于真实概率和预测概率的对数之和。
对于“m”个训练样本,总损失将等于总损失的平均值(其中 c 表示正确类别或真实类别)。
在序列标记问题中,在每个时间步,我们必须做出预测,这意味着在每个时间步,我们都有真实分布和预测分布。
由于我们在每个时间步长预测标签,因此在每个时间步长都有可能出错。所以我们必须检查每个时间步的真实概率分布和预测概率分布,以计算模型的损失。
实际上,对于所有训练示例(m-训练示例)和所有时间步长(T ),我们试图最小化真实类的预测分布之间的交叉熵损失。
学习算法
学习算法的目标是确定参数的最佳可能值,使得模型的总损失(平方误差损失)尽可能最小。学习算法是这样的:
我们随机初始化 w,u,v 和 b 。然后,我们对数据中的所有观察值进行迭代,使用 RNN 方程找到每个观察值的预测结果,并计算总损失。基于损失值,我们将更新权重,使得模型在新参数下的总损失将比模型的当前损失小。
我们将继续进行更新操作,直到我们满意为止。直到满意可能意味着以下任何一种情况:
- 模型的总损失变为零。
- 模型的总损失变成接近于零的非常小的值。
- 基于计算能力迭代固定次数。
推荐阅读
了解卷积运算和 CNN 的
towardsdatascience.com](/understanding-convolution-neural-networks-the-eli5-way-785330cd1fb7) [## 利用 Pytorch 神经网络模块构建前馈神经网络
Pytoch 神经网络模块初学者指南
medium.com](https://medium.com/@niranjankumarc/building-a-feedforward-neural-network-using-pytorch-nn-module-52b1d7ea5c3e)
从这里去哪里?
如果你想用 Keras & Tensorflow 2.0 (Python 或者 R)学习更多关于人工神经网络的知识。看看来自 Starttechacademy 的 Abhishek 和 Pukhraj 的人工神经网络。他们以一种简单化的方式解释了深度学习的基础。
结论
在这篇文章中,我们讨论了 RNN 如何用于不同的任务,如序列标记和序列分类。然后,我们研究了在输入模型之前用于处理数据的预处理技术。之后,我们研究了如何解决序列标记和序列分类问题的数学模型。最后,我们讨论了 RNN 的损失函数和学习算法。
在我的下一篇文章中,我们将深入讨论 LSTM 和 GRU。所以,请务必在 Medium 上跟随我,以便在它下跌时得到通知。
直到那时,和平:)
NK。
作者简介
Niranjan Kumar 是好事达印度公司的高级数据科学顾问。他对深度学习和人工智能充满热情。除了在媒体上写作,他还作为自由数据科学作家为 Marktechpost.com 写作。点击查看他的文章。
你可以在 LinkedIn 上与他联系,或者在 Twitter 上关注他,了解关于深度学习和机器学习的最新文章。
免责声明 —这篇文章中可能有一些相关资源的附属链接。你可以以尽可能低的价格购买捆绑包。如果你购买这门课程,我会收到一小笔佣金。*
递归神经网络
用 Python 从头开始实现 RNN。
这篇文章的主要目的是从头实现一个 RNN,并提供一个简单的解释,使它对读者有用。从头开始实现任何神经网络至少一次是一项有价值的练习。它帮助你了解神经网络是如何工作的,这里我们实现了一个 RNN,它有自己的复杂性,因此为我们提供了一个磨练技能的好机会。
有各种教程提供了非常详细的 RNN 内部信息。你可以在这篇文章的末尾找到一些非常有用的参考资料。我可以很快理解 RNN 的工作原理,但最困扰我的是 BPTT 的计算和实现。我不得不花了一些时间去理解,并最终把它放在一起。为了不再浪费时间,让我们先快速浏览一下 RNN 的基本知识。
什么是 RNN?
递归神经网络是一种专门用于处理数据序列**x(t)= x(1), . . . , x(τ)**
的神经网络,其时间步长索引***t***
的范围为**1 to τ**
。对于涉及顺序输入的任务,如语音和语言,使用 RNNs 通常更好。在 NLP 问题中,如果你想预测句子中的下一个单词,知道它前面的单词是很重要的。rnn 被称为循环,因为它们对序列的每个元素执行相同的任务,输出取决于之前的计算。考虑 rnn 的另一种方式是,它们有一个“存储器”,可以捕获到目前为止已经计算过的信息。
架构:让我们简单看一下基本的 RNN 网络。
上图的左侧显示了一个 RNN 的符号,右侧显示了一个 RNN 被展开成一个完整的网络。展开意味着我们写出了完整序列的网络。例如,如果我们关心的序列是一个由 3 个单词组成的句子,那么这个网络将展开成一个 3 层的神经网络,每个单词一层。
输入: x(t) 在时间步长 t 取为网络的输入。例如, x1,可以是对应于一个句子的一个单词的一键向量。
隐藏状态 : h(t) 代表 t 时刻的隐藏状态,充当网络的“记忆”。 h(t) 基于当前输入和前一时间步的隐藏状态计算:**h(t)** = *f*(*U* **x(t)** + *W* **h(t**−**1)**).
函数*f*
取为非线性变换,如 tanh , ReLU。
权重:RNN 具有由权重矩阵 U 参数化的隐藏连接的输入,由权重矩阵 W 参数化的隐藏到隐藏的递归连接,以及由权重矩阵 V 参数化的隐藏到输出的连接,并且所有这些权重( U 、 V 、 W) 【T21)在时间上被共享。
输出 : o(t) 说明了网络的输出。在图中,我只是在 o(t) 后放了一个箭头,这也经常受到非线性的影响,尤其是当网络包含更多的下游层时。
向前传球
该图未指定隐藏单元激活功能的选择。在我们继续之前,我们做一些假设:1)我们假设隐藏层的双曲正切激活函数。2)我们假设输出是离散的,就像 RNN 用于预测单词或字符一样。表示离散变量的一种自然方式是将输出**o**
视为给出离散变量每个可能值的非归一化对数概率。然后,我们可以应用 softmax 操作作为后处理步骤,以获得输出的归一化概率向量***ŷ***
。
因此,RNN 向前传球可以由下面的一组等式来表示。
这是一个递归网络的例子,它将输入序列映射到相同长度的输出序列。一个给定的**x**
值序列与一个**y**
值序列的总损失就是所有时间步长的损失之和。我们假设输出***o(t)***
被用作 softmax 函数的参数,以获得输出概率的向量***ŷ***
。我们还假设损失**L**
是给定目前输入的真实目标***y(t)***
的负对数似然。
偶数道次
梯度计算包括执行从左到右穿过上述图形的前向传播过程,随后是从右到左穿过该图形的后向传播过程。运行时间为 O(τ),不能通过并行化来减少,因为正向传播图本质上是顺序的;每个时间步长只能在前一个时间步长之后计算。前向传递中计算的状态必须被存储,直到它们在后向传递中被重用,因此内存开销也是 O(τ)。应用于成本为 O(τ)的展开图的反向传播算法被称为时间反向传播(BPTT)。由于网络中的所有时间步长共享这些参数,因此每个输出的梯度不仅取决于当前时间步长的计算,还取决于之前时间步长的计算。
计算梯度
给定我们的损失函数 L ,我们需要计算三个权重矩阵 U、V、W 和偏差项 b、c 的梯度,并用学习率***α***
更新它们。类似于正常的反向传播,梯度给我们一种损失如何相对于每个权重参数变化的感觉。我们用下面的等式更新权重 W 以最小化损失:
对于其他重量 U、V、b、c 也要进行同样的操作。
现在让我们计算上面 RNN 方程的 BPTT 梯度。我们的计算图的节点包括参数 U、V、W、b 和 c 以及由 t 索引的 x (t)、h(t)、o(t)和 L(t)的节点序列。对于每个节点**n**
,我们需要递归地计算梯度**∇nL**
,基于在图中跟随它的节点处计算的梯度。
计算相对于输出 o(t) 的梯度,假设 o(t)用作 softmax 函数的自变量,以获得输出概率的向量***ŷ***
。我们还假设损失是真实目标 y(t)的负对数似然。
请参考这里的推导出上述优雅的解决方案。
现在让我们理解梯度是如何流过隐藏态 h(t)的。从下图中我们可以清楚地看到,在时间 t,隐藏状态 h(t)具有从当前输出和下一个隐藏状态流出的梯度。
Red arrow shows gradient flow
我们从序列的末尾开始,反向工作。在最后的时间步长τ,h(τ)只有 o(τ)作为后代,因此其梯度很简单:
然后,我们可以在时间上向后迭代,以通过时间反向传播梯度,从 t =τ1 向下到 t = 1,注意 h(t )(对于 t < τ ) has as descendants both o(t) and h(t+1). Its gradient is thus given by:
Once the gradients on the internal nodes of the computational graph are obtained, we can obtain the gradients on the parameter nodes. The gradient calculations using the chain rule for all parameters is:
We are not interested to derive these equations here, rather implementing these. There are very good posts 此处和此处)提供这些等式的详细推导。
履行
我们将使用 Python 从头开始实现一个完整的递归神经网络。我们将尝试使用 RNN 构建一个文本生成模型。我们训练我们的模型来预测给定前面字符的字符的概率。这是一个生成模型。给定一个现有的字符序列,我们从预测的概率中抽取下一个字符,并重复这个过程,直到我们得到一个完整的句子。这个实现来自 Andrej karpathy的伟大帖子构建人物级 RNN。这里我们将逐步讨论实现细节。
要遵循的一般步骤:
- 从随机分布初始化权重矩阵 U,V,W 并用零偏置 b,c
- 向前传播以计算预测
- 计算损失
- 计算梯度的反向传播
- 基于梯度更新权重
- 重复步骤 2–5
第一步:初始化
从基本 RNN 单元的实现开始,我们首先定义各种参数 U、V、W、b、c 的维数
维度:假设我们选择一个词汇大小**vocab_size= 8000**
和一个隐藏层大小**hidden_size=100**
。然后我们有:
词汇大小可以是基于字符的模型的唯一字符数或基于单词的模型的唯一单词数。
有了我们的几个超参数和其他模型参数,让我们开始定义我们的 RNN 细胞。
权重的正确初始化似乎对训练结果有影响,在这方面已经有很多研究。事实证明,最佳初始化取决于激活函数(在我们的例子中为 tanh ),一种推荐的方法是在来自**[ -1/sqrt(n), 1/sqrt(n)]**
的间隔内随机初始化权重,其中**n**
是来自前一层的传入连接数。
第二步:向前传球
简单明了根据我们的每个时间戳 t 的等式,我们计算隐藏状态 hs[t]并输出 os[t],应用 softmax 来获得下一个字符的概率。
计算 softmax 和数值稳定性:
Softmax 函数获取一个 N 维实数向量,并将其转换为一个范围为(0,1)的实数向量,其总和为 1。使用下面的公式完成映射。
softmax 的实现是:
虽然它看起来很好,但是当我们用一个更大的数字调用这个 softmax 时,它给出了“nan”值
Numpy 使用的浮点数的数值范围是有限的。对于 float64,最大的可表示数是 10 ⁰⁸.的数量级 softmax 函数中的乘幂运算可以轻松超过该数值,即使对于中等大小的输入也是如此。避免这个问题的一个好方法是将输入标准化为不太大也不太小。这里有一个小的数学技巧,详情请参考这里的。所以我们的 softmax 看起来像:
第三步:计算损失
因为我们正在实现一个文本生成模型,所以下一个字符可以是我们词汇表中的任何独特字符。所以我们的损失将是交叉熵损失。在多类别分类中,我们取观测值中每个类别预测的测井损失值的总和。
- M —可能的类别标签数量(我们的 vocab 中的唯一字符)
- y —类标签
***C***
是否是观察***O***
的正确分类的二进制指示符(0 或 1) - p —模型预测的观察概率
第四步:向后传球
如果我们参考 BPTT 方程,实现是按照方程。添加了足够的注释来理解代码。
问题
虽然原则上 RNN 是一个简单而强大的模型,但在实践中,很难进行适当的训练。这个模型如此笨拙的主要原因是消失渐变和爆炸渐变的问题。当使用 BPTT 进行训练时,梯度必须从最后一个单元一直行进到第一个单元。这些梯度的乘积可以变为零或呈指数增长。爆炸梯度问题指的是在训练期间梯度范数的大幅度增加。消失梯度问题指的是相反的行为,当长期分量以指数速度达到范数 0 时,模型不可能学习时间上遥远的事件之间的相关性。
虽然可以使用渐变裁剪技术来修复爆炸渐变,如示例代码中所使用的,但是消失渐变问题仍然是 RNN 的主要问题。
这种消失梯度限制被各种网络克服,例如长短期记忆(LSTM)、门控循环单元(GRUs)和残差网络(ResNets),其中前两种是 NLP 应用中最常用的 RNN 变体。
步骤 5:更新权重
使用 BPTT,我们计算了模型每个参数的梯度。现在是更新权重的时候了。
在 Andrej Karparthy 最初的实现中,Adagrad 用于梯度更新。阿达格拉德的表现比 SGD 好得多。请检查并比较两者。
步骤 6:重复步骤 2-5
为了让我们的模型从数据中学习并生成文本,我们需要训练它一段时间,并在每次迭代后检查损失。如果损失在一段时间内减少,这意味着我们的模型正在学习对它的期望。
生成文本
我们训练了一段时间,如果一切顺利,我们应该准备好我们的模型来预测一些文本。让我们看看它是如何为我们工作的。
我们将实现一个预测方法来预测几个单词,如下所示:
让我们看看我们的 RNN 在几个时代的训练后是如何学习的。
输出看起来更像带有单词边界和一些语法的真实文本。所以我们的小 RNN 已经开始学习语言,并且能够预测接下来的几个单词。
这里给出的实现只是为了易于理解和掌握概念。如果你想玩模型超参数,笔记本是这里。
奖励:想形象化训练 RNN 时实际发生的事情,看这里的。
希望对你有用。谢谢你的阅读。
参考资料:
[1]http://www.deeplearningbook.org/contents/rnn.html
https://gist.github.com/karpathy/d4dee566867f8291f086
[3]http://www . wild ml . com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/
[4]https://medium . com/forward-artificial-intelligence/wireless-tour-of-rnns-a 11 effb 7808 f
我支持 OpenAI 新 GPT 协议的一个原因是:REDDIT
TLDR: 他们通过红迪网播种他们的网络搜索,红迪网是所有想法的宝库。因此,如果他们发布更大的型号,至少会是一场公关灾难。较小的 117 米是讨厌的,因为没有微妙的!
目录
简介:
我推荐我的实习生阅读的一篇论文是不带偏见地看数据集偏见 ,其中有一些很棒的介绍性文字:
Torralba, Antonio, and Alexei A. Efros. “Unbiased look at dataset bias.” (2011): 1521–1528.
如果我可以补充的话,没有非常仔细地整理这些数据也是一个致命的错误。考虑到这些天来(正当的)对数据集产生的偏见和有害特质问题的关注,你会认为大型组织在开始像最近这篇引起轰动的论文中那样雄心勃勃的冒险之前,应该对数据集收集程序的细节进行广泛的讨论。正如猜测的那样,架构建模中没有引入突破性的想法(作者也没有声称有),因此pieèce de réstate实际上是数据集的庞大、模型的庞大和训练模型的计算能力的庞大这三者的结合。
但事实证明,情况并非如此,这导致了一个模型,呈现了一种非常特殊的潜在的邪恶威胁,我们都可以没有它。为进一步澄清,标题应为:
OpenAI 建立了一个文本生成器,s̶o̶ ̶g̶o̶o̶d̶在一个数据集上进行训练,这个数据集是如此不小心有毒和有效,以至于它被认为太危险而不能发布。
(那里!修好了!)
就其本身的学术价值而言,这篇论文充满了一些优秀的观点和见解,无论你是否专门研究 NLP,都值得从头到尾读一遍。除了被介绍到这个令人敬畏的提取工具之外,由于我个人对字节级 LMs 的不满(这个问题可能会在另一篇博文中探讨),当我通读关于输入表示的第 2.2 节时,我有一种个人的痛苦救赎感。不过,我必须承认,看到基于字节对编码(BPE)的方法在十亿字基准测试中惨败也令人失望,尤其是在阅读了第 2 部分之后:当前的字节级 LMs 在大规模数据集(如十亿字基准测试)上无法与字级 LMs 竞争
GPT-S’s waterloo: One Billion Word Benchmark
核心问题:数据集监管
对我来说,论文的全部内容都在第二部分,它回答了我的两个主要问题。
a)他们如何管理数据集?
b)他们对此数据集使用了什么模型?——答案有点令人失望,对这篇博文没有意义。
我收集到的 a)的答案至少让我感到有点不安,最终促使我同意 OpenAI 的立场,但原因完全不同。
作者根据 R-E-D-D-I-T. 创建了他们的数据集' WebText'
用他们自己的话说:
手动过滤一个完整的网络抓取会非常昂贵,因此作为一个起点,我们从社交媒体平台 Reddit 抓取了所有出站链接,该平台收到了至少 3 个 karma。这可以被认为是一个启发性的指标,表明其他用户是否觉得这个链接有趣、有教育意义或者仅仅是有趣。结果数据集 WebText 包含了这 4500 万个链接的文本子集。
这可能是因为我自己对 Reddit 又爱又恨的关系,但这听起来像是一部写得很差的拉姆齐兄弟电影的开始。你把一个拥有强大计算能力的庞大模型扔进了一个有毒的数据宝库,这个数据宝库是从 REDDIT 上收集的?
请参考下面这些同行评审的关于该平台毒性的研究论文:
Source: https://journals.sagepub.com/doi/abs/10.1177/1461444815608807 , https://www.researchgate.net/profile/Thalia_Field2/publication/316940579_Domain_Adaptation_for_Detecting_Mild_Cognitive_Impairment/links/5a45372c458515f6b05477c2/Domain-Adaptation-for-Detecting-Mild-Cognitive-Impairment.pdf#page=65
reddit 的事业和最终被投票通过的东西构成了一个坏主意的主矿脉和坏主意的链接。这种数据集构建努力充满了令人不快的上下文生成的高风险,尤其是如果我试图从 LM 中生成无条件样本的话。
哦等等!
Source: https://github.com/openai/gpt-2
出于好奇,如果这种恐惧真的会转化为文字(这是一个糟糕的双关语),我下载并玩了他们通过 github 页面在这里适时分享的较小(117M 参数)版本的 GPT-2。
无条件样本生成:不适合内心脆弱的人
令我懊恼的是,这个小模型生成的许多样本与研究人员对 Reddit 的担心非常接近。
在这个问题上,自由主义者也在试图切断他们自己意识形态学术的刺痛。考虑公开转基因玉米,因为它有隐藏的但有价值的价值(减少个体的机会和工作机会)。在非经济学家看来(许多登山者在可能的情况下会求助于无偿的外交服务基金),啤酒和华夫饼在一段时间内供应给所有性别的军事化男性倡导者。支持堕胎权利的保守告密者、藏人和被强奸的平民很可能包括在这些伪激进分子的诽谤活动中,那么这引发了什么政治问题呢?许多年来,我们对左派的信念感到不安,他们认为奴隶制度结束后,人类对男人的第一个嗜好是高潮或金钱。我们试图忘记地球上的男人是如何变得不依赖于绿帽子或江湖骗子,只是。
还有这个!
男性杰特——所以他们中的许多人住在乐购,包括木炭烧烤店的程序员和员工,以及手无寸铁的社交瘾君子凯西·布里格斯(Kathy Briggs ),他们有 1000 份工作,来自 DW 车站、海洛因注射、漂亮的发型和酒吧学习日。
稍微用谷歌搜索一下,就会发现“瘾君子”+“凯西·布里格斯”唯一同时出现的是这个令人揪心的故事,讲的是费尔法克斯的某个凯西·布里格斯与她 21 岁的儿子因吸食海洛因过量而死亡的事情。
以下是其他一些热门话题:
“对孕妇来说,最大的障碍之一是耻辱感。他们是不明智的人无法跳出的中心,”斯奈德周三在 8 月份援引的州议会网站上说,此前全国各地收容机构的有毒堕胎导致州立医院比去年多 10 人死亡。(至少那些人指责诊所大量解剖患病女性的尸体,造成了数千人的死亡
..而且,
2014 年,同性恋权利活动人士向民主党人提出了同样的论点,呼吁帕利特卡支持该法案,而不是推动它。“罗马尼亚需要一个坚实的南部国会侧翼,以沿着同样的路线‘建立反对和争取时间’,更不用说小心了,”社会正义基金(Social Justice Fund)LGBT 倡议主任阿德里亚诺·罗梅罗(Adriano Romero)告诉波兰人 RT . DGA(RT . Roberto),嗯,这是指特别是猴子和猿;她还提到了支持 longs 的 Janus Djiman 的快速投票。“罗马尼亚仍然需要一支军队:在种族清洗运动中,3000 名蒙面掠夺者推翻了阿布杜库的亡命之徒;来自 Takeshi Sada 的狂欢节杀手,我们预定他淹死我们的 50 名人民,他来自 Julian Viper(埃塞俄比亚君主制的刽子手,死于 1999 年,据信他曾在那里卖淫)和 Kerry Mackey(他通过酷刑对 11 名儿童进行了性虐待)。甚至还有(你可以注意到这个比喻)7-24 周的假期和婴儿洗澡人员的能力,特别是当他们的具体原因仍然是模糊的阿塔维移民在国外颁布法令反对同性恋。“这是一个关键问题,”她说,为沙龙写作。作为拉丁血统和分离其海洋民族,意大利和韩国,表明欧洲人从来没有在没有“鼓励”他们加入黑人运动的情况下,用白色女性泡沫塑料样的形式运送成年人向他们自己的“南方”移动,包括 LGBTQ 社区。"
这至少构成了一个很好的理由,为什么我现在非常赞同作者不发布更大的模型/代码的决定。
如果附录中精选的例子是可靠的(例如,见下面的例子),我认为作者没有发布 1.5B 模型确实是合理的。一个危险的有毒来源及其所有的政治含义和微妙之处与大模型和大计算的肌肉力量相结合,是一个等待释放的武器。
如果作者也能在训练模型之前阐明他们使用的“启发式清理”程序,那将是非常有用的。
我想用一个相当简单的问题来结束这篇博客/长篇大论:当有人提出这个问题时,难道没有经过深思熟虑吗..因此,作为一个起点,我们从社交媒体平台 Reddit 上抓取了所有的外部链接,这至少收到了 3 个因果报应。这可以被认为是一个启发性的指标,其他用户是否觉得这个链接有趣,有教育意义,或者仅仅是有趣?
在开始这项显然是巨大而昂贵的工作之前,难道没有考虑过这种数据集播种的危险吗*在此插入 interrobang
PS:链接到我的笔记本,上面引用了示例文本:
编辑描述
colab.research.google.com](https://colab.research.google.com/drive/1WtSGPDduf7hffoN6vp4LFaXc6PqAqoJB)
发布脚本:
我想把另一个小问题解决掉。
像 OpenAI 这样资金充足的行业实验室,表面上有一群聪明人进行内部审查,兜售有拼写错误和滥用符号的论文,这种想法实在是令人作呕。还有,耶稣基督,你怎么能把一个语言模型的等式第一号弄错呢?
First of ‘maNy’
Source: https://arxiv.org/pdf/1404.3377.pdf
下标中那个可怜的小 i 从来没有看到它的到来。也许是确认偏差,但这是一种趋势吗?不久前,这个小小的 i 的希腊表亲(\(\theta\))在 OpenAI 的另一篇论文中也遭到了猛烈抨击(尽管这是一篇非常好的论文)。读一下吧!).
Source: The trolling of theta — Source: https://arxiv.org/pdf/1807.03039.pdf
我在我办公桌的乱七八糟的地方翻出了打印稿,以下是我的确切反应:
Must be a real scary space for subscripts this place
我明白了。这些都是造成小伤害的小错误,但即使是一个铁杆粉丝也必须承认,当这些与投入公关努力的所有精力并列时,确实使它至少有点值得一看。没有吗?
Reddit 帖子分类
在我沉浸于数据科学的过程中,我必须完成的第三个项目是 Reddit 帖子分类。我们刚刚完成了数据抓取和自然语言处理,所以这个项目有两个部分:从 Reddit 的 API 中抓取尽可能多的帖子&然后使用分类模型来预测帖子的来源。
我不久前完成了这个项目,但我决定用更多的经验重新审视这个项目:从那时起,我了解了两个新的分类模型(支持向量分类器和 XGBoost 分类器)。
数据采集、清理和预处理
从 Reddit 的 API 中抓取数据的过程相当简单:这只是一个基本的请求设置,因为它们不需要访问 API 的密钥。对我来说幸运的是,我仍然有我第一次完成这个项目时的第一组帖子:我总共有大约 4000 个帖子。
在某些方面,清理文本比清理数字数据要容易得多:我只需要删除空值,过滤掉重复的&粘贴的帖子,过滤掉交叉帖子,非字母字符和 URL。我在帖子中有两个文本来源:标题和自我文本(帖子中的实际文本)。我决定将这两个源合并到一个文档中,这样建模会容易一点。在这一点上,我决定查看每个子编辑中最常用的单词。
The 15 most frequent words before being lemmatized
一旦我知道最常用的单词是什么,我就能把它们添加到我使用的停用词列表中。
我采取的最后一个预处理步骤是对文本进行词汇化。我选择词汇化而不是词干化,因为词汇化是一个更温和的过程,它寻求返回单词的字典形式,而不是将单词简化为词干,后者可能返回非单词。
建模
import nltk
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import RegexpTokenizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_extraction.text import TfidfVectorizerfrom
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
from sklearn.metrics import roc_auc_score
from sklearn.metrics import accuracy_score, f1_score
from sklearn.metrics import balanced_accuracy_score
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
from skearnn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from xgboost import XGBClassifier
我用 4 个模型来解决这个问题:逻辑回归、支持向量分类器(SVC)和 XGBoost 分类器。每个模型运行两次:一次使用计数矢量器,一次使用 TFIDF(术语频率-逆文档频率)矢量器。
- 计数矢量器从数据的每一行中取出每个单词,为它创建一列,并计算这个单词出现的次数。
- TFIDF 矢量器也做同样的事情,但是它不是返回计数,而是返回频率的百分比,该百分比根据它在所有文档中出现的频率进行缩放。
我必须在每个模型上使用 gridsearch,因为我要调优 2 组超参数(算法无法确定的参数):一组用于矢量器,一组用于实际模型。
谈到评估,我使用了三组指标:指标评估(准确性、敏感性、特异性。)、混淆矩阵和 ROC(接收机工作特性)曲线和分数。为了简单起见,我将只显示最佳模型的评估,否则会有太多的图像。
我从一个逻辑回归模型开始,因为它很简单:如果那个模型表现不好,我将不得不转移到一个不同的模型类型。逻辑回归的性能是可变的:使用 TFIDF 矢量器时,它的性能要好得多,并且是过度拟合的。
我尝试的下一个模型是 SVC 模型。我认为,因为支持向量算法使用核技巧将数据移动到更高维度,它会在分类方面做得更好。然而,它并没有胜过真正让我吃惊的逻辑回归。使用两种矢量器的 SVC 的结果实际上没有过度拟合,这也是令人惊讶的。
接下来,我继续使用随机森林分类器。由于矢量器可以生成数百个特征,我认为随机森林算法中内置的随机特征选择将比以前的模型更好地解决方差问题。随机森林比 SVC 表现更好,但仍然比逻辑回归差。
最后我求助了 XGBoost。XGBoost 分类器是一个基于树的分类器,它实现了增强(将模型拟合到以前的误差上)和梯度下降。我确信这将是我最好的模型,但它不是:它仍然胜过 SVC 和随机森林
最佳模特
我最好的模型是带有 TFIDF 矢量化的逻辑回归。尽管它是最好的模型,但它远不是一个好模型。
我选择这些度量是因为它们以不同的方式代表了模型的准确性。
- 准确性是总体上有多少预测是正确的
- 特异性是多少负面预测是正确的
- 敏感度是有多少正面预测是正确的(r/Cooking)
- ROC AUC 得分本质上衡量阳性和阴性类别的不同程度。
- Matthews Corr. Coef。是实际值和预测值相关程度的度量。
这个模型在准确率上跑赢了基线(41.89%),但得分还是不大。我对敏感度进行了优化,这意味着我想预测来自 r/Cooking 的帖子,但这个模型有一个可怕的敏感度:它更擅长预测负面类(r/ask cunning ),因为它的实例更多。MCC 较低,但仍为正值,这是一件好事。
ROC 曲线描绘了逻辑回归区分两个类别的能力,即 r/Cooking & r/AskCulinary。曲线本身显示了灵敏度和假阳性之间的关系。然而,更重要的是 AUC(曲线下面积),因为它显示了两类之间的区别。可能的最低分数是 0.5,我的最佳模型的分数是 0.67,这根本不是一个好分数:模型很难区分这两个类别。
结论
对于我正在处理的帖子,我无法令人满意地对来源的子编辑进行分类。
这个模特的表演还有很多不足之处。其他模型有特异性分数,但其他模型表现更差。此外,模型过度拟合,即使我尝试了可以帮助处理过度拟合的算法。
向量化的方法提高了性能,但幅度不大;这是一个我想继续尝试的领域。
最后,我想尝试运行神经网络,因为它们非常擅长分类问题。
我无法得到我想要的结果,但这没关系:在现实世界中,并不是所有事情都如你所愿。
这个项目的仓库可以在这里找到。
在 LinkedIn 上也可以找到我。
使用 R 和 Tableau 对美国阿片类药物过量死亡率进行综合分析和可视化
重新设计一个糟糕的图表——从意大利面条到微型地图
作者:Chaithanya Pramodh Kasula 和 Aishwarya Varala
简介
当前报告的主要焦点是重新设计一个描述美国不同州每 100,000 人阿片类药物过量死亡率(经年龄调整)的图表。它还讨论了用于从数据中获得有意义的见解的详细方法和技术。注释了坏图和重新设计的图的优点和缺点。此外,还进行了数据分析,以揭示隐藏的知识,并通过有效的互动图形将这些信息可视化。
坏图:
图形来源: https://datausa.io/visualize?enlarged=c-lineplot-Zpn26u&groups = 0-zpn 26 u&measure = 2 sucf 4
讨论中的坏图来自'美国数据公司',该公司提供共享的美国政府数据供公众使用。
描述:
Fig. 1
上图量化了 1999 年至 2016 年美国 51 个州记录的每 100,000 人的阿片类药物过量死亡率(经年龄调整)。将特定年龄死亡率应用于 2000 年美国标准人口年龄分布,以计算年龄调整死亡率。图中的每条线代表一个州。悬停时的图形显示一张卡片,详细说明了悬停点处的 X 轴和 Y 轴的值,如图 2 所示。该图旨在显示美国 51 个州每 100,000 人中阿片类药物过量死亡率的时间序列变化(经年龄调整)
优势:
精确数据表示:原始数据包含编码为 NSD(数据不足)和 NR(未报告)的缺失字段。该图没有绘制任何值,也没有试图用任何其他值来替代不可用的数据。此外,悬停时会显示精确的数值。
在选择时突出显示线条:在选择时,很容易聚焦代表状态的线条。
Fig. 2
弱点:
数据重叠:由于数据集很大,图中的线条重叠,不可读。举例来说,由于存在大量彼此接近的线,所以无法理解不同状态的 X 和 Y 值之间的关系。
难以区分的状态:很难将一个状态与其他状态区分开来。例如,如果一个读者想要找到一个州,他需要在混乱的情节中通过将鼠标悬停在线上来搜索它。这可能是一个令人困惑、耗时和令人疲惫的过程。
艰难地跟随趋势线:很难跟随一个国家多年来的路线,随着它盘旋和移动。而且,当线条过于接近,相互重叠时,执行这个过程是非常费力的。
不必要的曲线平滑:观察到曲线平滑,难以识别和读取线图的峰值。
难以理解的分析一览:图表不能帮助快速分析单一视图中的数据。例如,查看图表,无法快速推断出类阿片过量死亡率的最高、最低或中间值等简单统计信息。
不支持并发分析:不能同时分析多个状态。这是因为悬停一次只能突出显示单个状态的线条。此外,随着大量州的出现,很难同时比较/分析不同州的死亡率。
只能与用户交互工作:图表的细节严重依赖于用户交互。例如,图表打印在纸上没有任何意义。此外,对于不熟悉交互式图形的人来说,这是非常困难和耗时的。
建议:
可以利用地理环境,因为数据与美国各州相关。
可以为图形中的线条提供空间分离。
可以构建数据的逻辑子组,而不是将其视为一个整体。
颜色可以用来区分不同的状态。
数据来源:
数据来自凯泽家庭基金会(KFF),这是一个关注美国健康问题的非营利组织。它被收录在“州健康事实”栏目下的“精神健康和物质使用”集合中。正如他们网站上所说,KFF 从“疾病控制和预防中心”,国家卫生统计中心获得了这些数据。可以通过向 CDC WONDER 数据库提出“1999-2017 年多种死因”(https://wonder.cdc.gov/controller/datarequest/D77)的数据请求来访问这些数据。
数据收集:
阿片类药物过量死亡率的数据可通过点击趋势图并在屏幕左侧显示的“时间范围”部分选择 1999 年至 2017 年获得。下载的文件由 20 列原始数据组成,其中第一列是“位置”(州),其他 19 列表示 1999 年至 2017 年。每行代表一个州及其在上述时间段内的阿片类药物过量死亡率。此外,据观察,收集了 1999 年至 2017 年有关“每 100,000 人口中所有药物过量死亡率(年龄调整后)”、“与上一年相比阿片类药物过量死亡率的百分比变化”和“与上一年相比所有药物过量死亡率的百分比变化”的其他信息,并将其作为 an R 计划数据集的一部分。此外,该数据集用于获得通过表格显示的洞察力。此后,文件中可能不会明确提及“每 100,000 人中”的“阿片类药物过量死亡率”。所有提及的“阿片类药物过量死亡率”均可视为“每 100,000 人的阿片类药物过量死亡率(经年龄调整)”。
数据探索:
完整的数据集包括 77 列和 53 行(包括标题)。每行代表美国的一个州。它可以理解为 4 个指标(“阿片类药物过量死亡率(年龄调整后)”、“所有药物过量死亡率(年龄调整后)”、“与上一年相比阿片类药物过量死亡率的百分比变化”和“与上一年相比所有药物过量死亡率的百分比变化”)x 19 年(1999-2017 年)x 51 个州(美国)。
下载的数据由表示为 NSD 和 NR 的缺失值或单元组成。NSD 代表“数据不充分”。资料来源中还提到,为了保密,NSD 的数据被隐瞒了。NR 代表“未报告/不可靠”。在总数据集中,NR 为 32 的细胞数和 NSD 为 187。在 1999 年至 2017 年的阿片类药物过量死亡率中,NR 细胞的数量为 24,NSD 细胞的数量为 22。对于阿拉斯加、北达科他、南达科他和怀俄明等州,包含 NSD 和 NR 的像元数量很大。因此,对这种状态的分析是不准确的。
数据预处理:
作为数据清理的一部分,具有 NSD 和 NR 的像元被替换为数字零。这被认为是比用均值、中值、众数或任何其他数字来代替更好的选择,因为像死亡这样的变量在时间序列中更有影响力。例如,平均值倾向于向更高的值移动,它可能无法准确反映包含 NSD 或 NR 的单元格在特定年份的死亡人数。因此,替换这些量会使数据变得不可靠。此外,由于没有 1998 年以前的数据可供计算,诸如“1999 年阿片类药物过量死亡率与前一年相比的百分比变化”等栏包含了所有 NSD 值。因此,一个安全的选择是用零替换所有包含 NSD 和 NR 的单元格。
此外,包含 USA 的第一行已被删除,因为它对整体理解数据没有任何显著影响。由于可用的数据分布在不同的文件中,的 R 代码被写入将不同的数据帧合并成一个数据集。对于数据清洗,使用了看门人 (Wickham,2017)tidy verse(Firke,2019)。
发现虚假陈述:
在数据探索过程中,发现与“与上一年相比阿片类药物过量死亡率的百分比变化”和“与上一年相比所有药物过量死亡率的百分比变化”相关的列中的值仅代表与上一年相比的“增长率”,而非百分比变化。例如,阿拉巴马州的“2000 年阿片类药物过量死亡率与前一年相比的变化百分比”表示为 0.25,而不是 25%,但列名为“变化百分比”。
特征工程:
为了从数据中提取隐藏的知识,通过 R 代码创建了如下某些列:
avg _ opoid _ death _ growth _ rate:这是通过计算 19 年来(1999 年至 2017 年)每个州的阿片类药物过量死亡率的所有增长率的平均值计算出来的。
avg _ deaths _ due _ to _ 阿片类:通过计算各州在一段时间内(1999-2017 年)阿片类药物过量死亡率的平均值获得。
avg _ deaths _ due _ to _ All _ drugs:通过取每个州在该时间段(1999 年至 2017 年)内所有药物过量死亡率的平均值计算得出
avg _ opoid _ death _ rate _ 2009 _ 2013:通过计算各州 2009-2013 年期间阿片类药物过量死亡率的平均值计算得出。
avg _ opoid _ death _ rate _ 2013 _ 2017:通过计算每个州在时间段(2013-2017)内的阿片类药物过量死亡率的平均值来计算。
重新设计的图形:
图 1 所示的线图不适用于给定的数据。由于数据很大,必须容纳所有 51 个州,所以使用链接的微地图来重新设计现有的 bad 图。如(Carr 等人,1998 年)所述,微地图能够创建小感知组,以简化视觉外观,同时指向与统计估计相关的地理位置。微型地图也可以显示补充信息。一种分类机制使得 Micromaps 更具可读性。在这种情况下,地图由中间等高线分隔。重新设计的曲线图如图 3 所示。
可以观察到,所使用的分类机制是所有州 2017 年最新的阿片类药物过量死亡率。累积微地图已被用于绘制 51 个州的时间序列数据。排序面板的中间值出现在犹他州。移动到图的底部,可以注意到前面提到的状态用黑色标出,用黄色标出。组中的当前状态由颜色表示,并显示在其旁边的图例中。
Micromap 的第三列包含代表 1999 年至 2017 年的 x 轴。y 轴表示每个州的阿片类药物过量死亡率。总共 51 个状态被分成小的感知组,每组包含由五种不同颜色表示的 5 个状态。用于分组的标准是 2017 年发生的最新阿片类药物过量死亡按降序排列的排序机制。微缩图的第四列也是如此。x 轴代表“每 100,000 人的死亡率”。散点图中的每个点根据州的颜色进行着色。
时间序列微地图的构建:
重新设计的图表是在名为micro mast的 R 包的帮助下构建的(Carr 等人,2010)。使用“read.table”函数将所需数据读入数据框。构建了一个时间序列对象,使得第一维表示美国的 51 个州。第二维表示时间序列的时间段,即从 1999 年到 2017 年。第三个方面包括阿片类药物过量死亡率。第三维的 x 和 y 值,即 TSdata[,,2]被分配给一个名为“temprates”的变量。“panelDesc”数据帧是通过使用“type”、“lab1”、“lab2”、“lab3”、“lab4”、“col1”和“panelData”构建的。标题被赋给了一个变量(“ExTitle”)。必须存储 Micromap 的 pdf 文件名作为 pdf 函数的输入提供。最后,temprates、panelDesc、sortVar、ascend、title 被提供给 micromapST 函数来构造新的图。“sortVar”确定用于对状态进行排序的阿片类药物过量死亡率的列指数(年)。“升序”确定排序的顺序(递增或递减)。
Fig. 3
强项:
避免数据过度绘制:美国所有 51 个州及其阿片类药物过量死亡率已被分组到逻辑感知子组中,消除了在单个图形中过度绘制的问题。
状态的清晰区分:通过在空间环境中可视化数据,实现了状态之间的清晰区分。此外,在重新设计的图表的第三列中,已经为每个状态分配了特定的颜色。因此,读者可以很容易地区分趋势线和与之相关的状态。
易于跟踪趋势线:由于在一个子组中只有 5 个状态,每个状态用不同的颜色表示,所以沿时间序列跟踪趋势线相对容易。
通过排序和链接促进快速数据分析:通过查看微图,读者将能够快速理解数据及其模式。这是通过中值、累积微地图的使用和排序机制实现的。
促进并发分析:51 个州的所有趋势线都在单一视图中一起绘制。因此,可以毫不费力地执行并发分析。
支持绘制附加信息:除了 bad 图中显示的趋势线,还明确显示了最新阿片类药物死亡率的补充表示。微型地图有助于这种额外的数据呈现。
最小的记忆负担:定位不同的状态并不是一件费力的事情。在累积显微地图的帮助下,在任何给定的时刻,很容易识别前面提到的状态。
弱点:
有微小差异的趋势线:阿片类药物过量死亡率有微小差异的州有明显的区别,但仍比它们在 bad 图中的表现要好。
缺乏用户交互:重新设计的图形不便于用户交互。因此,无法执行点击、悬停等操作。
不支持自定义颜色分配: Micromaps 不提供将用户定义的颜色分配给状态或趋势线的功能。因此,颜色符合某些标准,如色盲友好,打印友好等。无法分配。
结论:
考虑到上述两个图(图 1 和图 3)的优点和缺点,可以得出结论,Micromaps 是一种通过提供地理空间背景和其他补充信息来表示讨论中的数据的更合适的技术。然而,交互式微型地图的应用可以增强当前的技术并提供更好的可视化。
用 Tableau 从数据中提取隐藏知识
简单计算辅助的可视化可以帮助从数据中提取大量信息。下图展示了数据可视化在知识提取中的强大功能。
热图:
Fig. 4
图 4 中所示的热图是通过使用“avg _ 阿片样物质 _ 死亡 _ 增长率”列(在特征工程部分中指定)绘制的。可以看出‘新泽西’阿片类药物过量死亡率增长率最高,其次是‘西弗吉尼亚’。此外,借助热图,很明显阿片类药物过量死亡率的平均增长率从西向东增加。
Fig. 5.1
图 5.1 示出了一个标有行的图,表示 100,000 人口中阿片类药物死亡率占所有药物死亡率的百分比。可以推断,百分比最高的前五个州分别是西弗吉尼亚州、新罕布什尔州、马里兰州、马萨诸塞州和罗德岛州。
Fig. 5.2
图 5.2 显示了图 5.1 中确定的前 3 个州(不包括西弗吉尼亚州)的时间序列图。与 1999 年到 2013 年相比,2013 年到 2017 年观察到一个突然的峰值。进一步的调查解释了这种死亡率的特殊上升,揭示了从 2013 年开始合成药物在市场上的危险引入。证实这一点的新闻文章和研究论文(Gladden 等人,2016 年),(Scholl 等人,2018 年),(Stephens,2019 年)已经发表。信息的快照如下所示。
Fig. 5.3
出于好奇,绘制了图 5.3,该图通过使用特征提取期间生成的“avg _ 阿片类 _death_rate_2009_2013”和“avg _ 阿片类 _death_rate_2013_2017”列,描绘了 2009–2013 年和 2013–2017 年之间平均死亡人数的百分比变化。这导致发现“华盛顿特区”的百分比变化最大,其次是康涅狄格州、新罕布什尔州、新泽西州和缅因州。此外,还发现蒙大拿州、俄克拉荷马州、内华达州、俄勒冈州和夏威夷在所述年份之间的百分比增幅最低。这在图 5.3 和 5.4 中描述(前 3 种状态)。
Fig. 5.4
参考文献
哈德利·威克姆(2017)。tidyverse:轻松安装和加载“Tidyverse”。r 包版本 1.2.1。https://CRAN.R-project.org/package=tidyverse
山姆·菲尔克(2019)。看门人:检查和清理脏数据的简单工具。r 包版本 1.2.0。【https://CRAN.R-project.org/package=janitor
卡尔·d . b .、奥尔森·a . r .、库尔博伊斯、J.P .、皮尔森·S . M .和卡尔·d . a .(1998 年)。链接的微地图图:命名和描述,统计计算和统计图形通讯 9(1):24–32。
Daniel B. Carr 和 Linda Williams Pickle (2010),用 Micromaps 可视化数据模式。
格拉德登,R. M .,马丁内斯,p .,,塞斯,P. (2016)。2013-2014 年 27 个州的芬太尼执法提交和合成阿片类药物相关用药过量死亡的增加。MMWR。发病率和死亡率周报,65(33),837–843。doi: 10.15585/mmwr.mm6533a2
Scholl,l .,Seth,p .,Kariisa,m .,Wilson,n .,& Baldwin,G. (2018)。2013 年至 2017 年美国与药物和阿片类药物相关的用药过量死亡。MMWR。发病率和死亡率周报,67(5152)。doi: 10.15585/mmwr.mm6751521e1
史蒂芬斯,E. (2019,10 月 2 日)。阿片毒性。从 https://emedicine.medscape.com/article/815784-overview取回
药物过量死亡。(未注明)。从 https://www.cdc.gov/drugoverdose/data/statedeaths.html取回
如何用 Python 在地图上绘制地理数据
用 Python 可视化地理数据的实用教程
Figure 1
背景
在本系列的第 1 部分 中,我们通过将今天的贷款申请与旧的标记的邮政编码进行交叉关联,调查了标记的地图与今天的信贷格局之间的相关性。我们在 P2P 贷款市场使用的数据中发现了一些不公平算法或历史偏见的迹象。特别是,我们惊讶于 80 年前的贷款申请拒绝率和今天的拒绝率之间的正线性趋势,在那些被划分为危险或明确下降的标记区域。
美国 20 世纪 30 年代的红线为近一个世纪的房地产实践制定了规则,种族不平等如此深刻地塑造了城市,以至于我们今天仍能感受到它们的遗产。
早在 20 世纪 30 年代,房主贷款公司(Home Owners' Loan Corporation)或“HOLC”创建了地图,使用以下等级对近 250 个美国城市的社区级别的信用价值和风险进行颜色编码:
- 最好的
- b——仍然可取
- c——肯定下降
- D —危险
在本帖第一部分的中,我们从测绘不等式网站下载了相应的红线形状文件,并计算了 HOLC 各路基的面分布(比例)。
df_redlines.head()
我们还使用了 LendingClub 网站上的 2400 万份贷款申请,这是最大的 P2P 贷款市场,目的是估计每个邮政编码每个季度的平均贷款申请拒绝率。
df_loan_reject_ratio.head()
在 LendingClub,每笔贷款都有相应的利率,从 A 到 G 不等。我们计算了等级在邮政编码上的分布。
df_loan_grades.head()
在我们故事的第二部分,我们希望在美国的地理地图上可视化红线区域贷款拒绝率和贷款利率分布。
基线地图
我们的可视化是作为一个多层地图建立的,用一个美国等高线地图塑造背景。相应的地图边界形状文件从人口普查局获得。
df_map_us = gpd.read_file('data/states.shp')
df_map_us.head()
因为我们希望将最终地图限制在美国大陆,而不是夏威夷群岛和太平洋或加勒比海的美国岛屿领土,所以我们过滤掉了这些州。
dfu = df_map_us[~df_map_us.STATE_ABBR.isin(['AK','HI', 'AA', 'AE','AP','PR','RI','VI'])]
红色热点地图
我们地图的下一层应该显示 20 世纪 30 年代红线的热点
因为我们在第 1 部分中总结了每个邮政编码的红线数据,我们将需要一个美国邮政编码的地图边界形状文件。该文件从人口普查局网站下载。
df_zipcodes = gpd.read_file('data/cb_2017_us_zcta510_500k.shp')
df_zipcodes.rename(columns={'ZCTA5CE10':'zipcode'}, inplace=True)
df_redlines.zipcode = df_redlines.zipcode.astype('str')
df_redlines.zipcode = df_redlines.zipcode.str.pad(5, 'left', '0')
为了能够将美国邮政编码多边形与标记的汇总数据连接起来,我们创建了一个包含 123xx 邮政编码模式的新列。
df_zipcodes['zip_code'] = df_zipcodes['zipcode'].astype('str')
df_zipcodes['zip_code'] = df_zipcodes['zip_code'].str.pad(5, 'left', '0')
df_zipcodes['zip_code'] = df_zipcodes['zip_code'].str.slice(0,3)
df_zipcodes['zip_code'] = df_zipcodes['zip_code'].str.pad(5, 'right', 'x')
我们使用免费的 Python 库 uszipcode 添加州和县信息。
search = SearchEngine(simple_zipcode=True)
df_zipcodes['state'] = df_zipcodes.apply(lambda row: search.by_zipcode(row.zipcode).state, axis=1)
df_zipcodes['county'] = df_zipcodes.apply(lambda row: search.by_zipcode(row.zipcode).county, axis=1)
df_zipcodes.head()
Figure 1
接下来,我们将标记的数据与邮政编码多边形合并。
df_redlines_maps = df_zipcodes.merge(df_redlines, on='zipcode', how='left')
我们把多边形限制在美国大陆。
df_redlines_maps = df_redlines_maps[~df_redlines_maps.state.isin(['AK','HI', 'AA', 'AE','AP','PR','RI','VI'])]
我们通过在没有 HOLC 标记区域的邮政编码中填充零来处理缺失数据。
df_redlines_maps.fillna(0, inplace=True)
df_redlines_maps.head()
Figure 2
现在我们已经准备好用 Geopandas 创建我们的第一张地图。下图显示了包含两个图层的地图:
- 浅蓝色美国基线地图,
- 红色的标记区域。
dfm = df_redlines_maps[df_redlines_maps.zip_area>0]
fig, ax = plt.subplots(1, figsize=(50, 50))
dfm.plot(facecolor='red', linewidth=0.8, ax=ax, edgecolor='0.8', alpha=0.8)
dfu.plot(ax=ax, alpha=.1)
ax.axis('off')
ax.set_title('HOLC Redlining Zones', fontdict={'fontsize': '20', 'fontweight' : '3'});
Figure 2
为了更好地观察红线区域和区分危险等级,我们将使用每个区域的质心而不是完整的多边形在地图上添加另一个图层。
dfmc = dfm.copy()
dfmc.rename(columns={'geometry': 'borders'}).set_geometry('borders')
dfmc['centroid_column'] = dfmc.centroid
dfmc = dfmc.set_geometry('centroid_column')
这允许我们现在在标记区域绘制圆圈。圆圈越多,区域就变得越暗,形成一个热图。
fig, ax = plt.subplots(1, figsize=(50, 50))
dfm.plot(facecolor='red', linewidth=0.8, ax=ax, edgecolor='0.8', alpha=0.8)
dfmc.plot(marker='o', facecolors='none', edgecolors='r', linewidth=0.8, markersize=2000, alpha=.2, ax=ax)
dfu.plot(ax=ax, alpha=.1)
ax.axis('off')
ax.set_title('HOLC Redlining Zones', fontdict={'fontsize': '20', 'fontweight' : '3'});
Figure 3
上图看起来像是映射不等式(来源)生成的地图的精细再现,如下图。
Figure 4
贷款与红线图
我们现在将在地图顶部添加一个新图层,以显示 LendingClub 拒绝率较高的区域。我们选择阈值 90%,这比 20 世纪 30 年代的 HOLC 废品率略高。
dfr = df_loan_reject_ratio[df_loan_reject_ratio.lc_reject_ratio>.9]
类似地,我们添加一个新图层来突出显示 LendingClub 为一半以上的贷款分配高利率的区域。
dfg = df_loan_grades.fillna(0)
dfg = dfg[dfg.LC_A_ratio+dfg.LC_B_ratio+dfg.LC_C_ratio<.5]
我们的目标是可视化 2007 年至 2018 年间与红线相关的 P2P 贷款的地理格局。我们可以通过为每个季度生成一个地图来实现这一点,如下所示。
dfz = df_zipcodes[~df_zipcodes.state.isin(['AK','HI', 'AA', 'AE','AP','PR','RI','VI'])]
quarters = df_loan_reject_ratio.issue_q.unique()
for q in quarters:
fig, ax = plt.subplots(1, figsize=(50, 50))
dfm.plot(facecolor='red', linewidth=0.8, ax=ax, edgecolor='0.8', alpha=0.8)
dfmc.plot(marker='o', facecolors='none', edgecolors='r', linewidth=0.2, markersize=100, alpha=.2, ax=ax)
ax.axis('off')
dfz.merge(dfr[dfr.issue_q==q], on='zip_code', how='inner').plot(facecolor='green', ax=ax, alpha=.5)
dfz.merge(dfg[dfg.issue_q==q], on='zip_code', how='inner').plot(facecolor='magenta', ax=ax, alpha=.3)
f = dfu.plot(ax=ax, alpha=.1)
f.get_figure().savefig(q+"_loans_reject_ratio.png", dpi=300)
下面我们可以看到为 2007 年第二季度制作的地图。在记录了大量贷款申请被拒的地区和前 HOLC 标记区之间似乎存在关联。
Figure 5
- 地图层 0 :美国基线州地图— 浅蓝色形状显示美国各州,
- 地图图层 1 : HOLC 红线图— 红圈显示 20 世纪 30 年代红线最多的地方,
- 地图图层 2 : LendingClub 拒绝率— 绿色形状显示 LendingClub 拒绝超过 90%申请人的地方,
- 地图图层 3 : LendingClub 利率— 洋红色形状显示 LendingClub 平均分配最高利率的地点。
地图上的颜色可以解释如下:
- 绿色表示 LendingClub 的废品率非常高(> 90%)。
- 深紫色是 HOLC 红线和 LendingClub 拒绝之间强相关的指示器。当红色形状(来自 HOLC)被绿色形状(来自 LendingClub)覆盖时,就获得了紫色。
- 深红是 HOLC 红线与 LendingClub 高利率之间强相关的指标。
一年后,也就是 2008 年,废品在 HOLC 区之外蔓延开来。但是 HOLC 地区仍然是利率最高的地区。
Figure 6
在 2012 年第一季度之后,我们再也看不到 HOLC 和 LendingClub 之间有任何明显的联系。然而,我们可以像 2012 年之前一样记录更多的贷款申请被拒,但是这些被拒出现在几乎所有的州,而不仅仅是在划红线的地区。
Figure 7
随着 LendingClub 在 2012 年后获得更多市场份额,我们可以看到其活动在美国各地平均分布,如 2016 年第三季度地图所示。
Figure 8
当查看 2018 年第二季度的地图时,HOLC 的红线似乎被遗忘了,并且没有影响任何 LendingClub 的统计数据。
Figure 9
地图动画
使用 plot.ly、Dash 或类似工具的多层地图动画是一项具有挑战性的任务。我们发现通过使用每个季度生成的 45 个地图构建 GIF 来模拟 choropleth 地图动画更容易。这是通过手动裁剪 Geopandas 生成的每个地图图像周围的空白区域实现的。下一步是使用免费软件 IrFanView 的批量转换功能将图像的分辨率降低到 500x500px。使用同样的工具,我们在每张图片上添加一个显示年份和季度的叠加文本。最后我们使用免费的图像编辑软件 Gimp 创建了一个 GIF 动画。
Figure 10: red — main Redlining cities in the 1930s | green — Lending Club’s highest loan application rejects in 2007–2018| magenta — Lending Club’s highest interest rates in 2007–2018
结论
这项工作中出现的几个问题可能是进一步研究的主题:
- LendingClub 使用的数据是否包含某种与 HOLC 红线共线的偏差,例如 FICO 分数、工作时长、种族?
- 邮政编码、性别、种族会在多大程度上影响 LendingClub 的决策?
- 考虑到 HOLC 红线,风险评估算法中哪些调整是必要的,这显然不属于过去?
我们在这个项目中演示了探索性数据分析。使用 Geopandas 构建多层地图作为空间时间序列可视化的展示。我们引入了额外的数据科学概念:算法公平性、web 爬行、数据清理、特征工程和相关性分析。
希望这篇文章能提高人们对数据科学中伦理问题的认识,尤其是在人类相关数据上使用机器学习的时候。
从命令行红移
我最近发现自己在 AWS Redshift 控制台中编写和引用保存的查询,并知道一定有更简单的方法来跟踪我的常用 sql 语句(我主要用于定制复制作业或检查日志,因为我们对所有 BI 使用模式)。
原来有一种更简单的方法,叫做 psql (Postgres 的基于终端的交互工具)!开始使用 psql 非常容易,您会对 AWS 控制台点击它的次数感到高兴。
步骤 1:安装
$ brew install postgres
步骤 2:建立红移连接
接下来,连接到你的红移星团。
由于您将一直使用 psql,我建议在您的~/.bash_profile
中创建一个别名,这样您就可以轻松地用一个单词建立数据库连接。我用redshift
作为我的别名。您可以使用您在中定义的凭据。bash_profile:
alias redshift='psql "host=$REDSHIFT_HOST user=$REDSHIFT_USER dbname=$REDSHIFT_DB port=$REDSHIFT_PORT sslmode=verify-ca sslrootcert=<path to your postgres root .crt file> password=$REDSHIFT_PASSWORD"'
步骤 3:添加您的开发 IP 地址
您需要确保您的集群安全组被设置为接收来自您将在开发中使用的任何 IP 地址的入站流量。如果您的集群在自定义 VPC 中,您可以从命令行使用 CLI 的authorize-security-group-ingress
来完成此操作。否则,如果您使用默认 VPC,您可以在控制台中手动将您的 IP 地址添加到安全组的入站规则中
第四步:探索你的仓库
现在您已经连接好了,在命令行上键入redshift
,并尝试这些方便的命令:
\dt — 查看您的表
\df — 查看您的函数
\dg — 列出数据库角色
\dn — 列出模式
\dy — 列出事件触发器
\dp — 显示表、视图和序列的访问权限
步骤 5:进行一次查询
$ SELECT * FROM your_schema.your_table LIMIT 10;
步骤 6:运行一个简单的事务
打开您最喜欢的文本编辑器,编写一个简单的事务(一系列 sql 语句,作为一个整体运行,如果其中任何一个失败,什么也不做),例如:
BEGIN;
INSERT INTO your_table VALUES (1), (2), (3), (4);
INSERT INTO your_table VALUES (5), (6), (7), (8);
INSERT INTO your_table VALUES (9), (10), (11), (12);
COMMIT;
保存这个事务,并使用\i
命令在 psql repl 中运行:
dev=# \i your_transaction.sql
玩得开心,让我知道你发现了什么!
Siobhán 是在着陆的数据工程负责人。Landed 的使命是帮助重要的专业人士在他们服务的社区附近建立金融安全,当他们准备在昂贵的市场购买房屋时,我们会与教育工作者一起投资。听起来很棒?加入我们!
减少单个单元格的尺寸
生命科学的数理统计和机器学习
比较单细胞基因组学的降维
From Becht et al., Nature Biotechnology 2019, image source
这是专栏 生命科学的数理统计和机器学习 中的第八篇文章,我试图涵盖生物信息学、生物医学、遗传学、进化科学等领域常用的分析技术。今天我们要讲的是降维技术应用于 单细胞基因组学 数据。其中,我们将比较线性和非线性降维技术,以便理解为什么和 UMAP 成为单细胞生物学的金标准。
单细胞数据的非线性结构
单细胞基因组学是一个高维数据,大约有 20 000 维的 T21 对应着蛋白质编码基因。通常并不是所有的基因对细胞功能都同样重要,也就是说,有个冗余的** 个基因可以从分析中剔除,以简化数据复杂性并克服维数灾难。剔除冗余基因,将数据投射到一个潜在空间中,在那里数据的隐藏结构变得透明,这就是降维的目标。**
Path from raw expression matrix to latent features: from Wang et al., Nature Methods 14, p. 414–416 (2017)
主成分分析(PCA) 是一种基本的线性降维技术,由于单细胞数据的高度非线性结构,该技术已被广泛认为不适用于单细胞数据。直观上,由于 丢失 效应,非线性来自表达式矩阵中随机零点的大部分。通常,单个单元格数据在表达式矩阵中有60–80%个零元素。这样,单细胞数据类似于图像数据,其中例如对于手写数字 MNIST 数据集的图像,我们有 86%的像素具有零强度。
tSNE non-linear dimensionality reduction for MNIST hand-written digits data set, image source
表达矩阵中这种大比例的随机零使得数据的行为类似于非线性 亥维赛阶梯函数 ,即无论“非零”多少,基因表达要么为零,要么非零。让我们演示应用于癌症相关成纤维细胞(CAFs) 单细胞数据集的基本线性和非线性降维技术。
线性降维技术
我们将从线性降维技术开始。在这里,我们读取并对数转换单细胞 CAFs 表达数据,后者可以被视为一种标准化数据的方法。通常,列是基因,行是细胞,最后一列对应于先前在 CAFs 数据集中发现的 4 个群体(集群)的 id。
现在,我们将使用 scikit-learn 流形学习库来应用最流行的线性降维技术。查看我的 github 以获得完整的脚本,这里为了简单起见,我只展示了线性判别分析(LDA)的代码:
Linear dimensionality reduction techniques applied to the CAFs single cell data set
我们可以立即得出的结论是,线性降维技术不能完全解决单细胞数据中的异质性。例如,小的黄色细胞群似乎与其他 3 个细胞群没有明显区别。唯一的例外是 LDA 图,然而这不是一个真正的无监督学习方法,因为与其他方法相反,它使用细胞标签来构建潜在特征,其中类是彼此最可分离的。因此,线性降维技术擅长保持数据的全局结构(所有数据点之间的连接),而对于单个单元数据,保持数据的局部结构(相邻点之间的连接)似乎更重要。
MDS tries to preserve global stricture while LLE preserves local structure of the data, image source
观察数据如何转换为潜在的低维表示真的很有趣,每种降维技术都值得有自己的文章。思考为什么基本上每种技术都适用于一个特定的研究领域,而在其他领域并不常见是很有趣的。例如,信号处理中使用独立成分分析(ICA),文本挖掘中流行非负矩阵分解(NMF),宏基因组学分析中非常常见的非度量多维标度(NMDS)等。,但很少见到例如 NMF 用于 RNA 测序数据分析。
非线性降维技术
我们转向非线性降维技术,并检查它们是否能够解析单个单元格数据中的所有隐藏结构。同样,完整的代码可以在 github 上找到,这里为了简单起见,我只显示了 tSNE 算法的代码,已知该算法难以处理真正的高维数据,因此通常在 20–50预缩减的维上运行,例如 PCA。
Non-linear dimensionality reduction techniques applied to the CAFs single cell data set
在这里,我们看到大多数非线性降维技术已经通过保留数据的局部结构(相邻点之间的连接)成功地解决了小的黄色聚类。例如,局部线性嵌入(LLE)通过局部线性平面表面的集合来近似非线性流形,这对于重建稀有细胞群(如小黄团)来说是至关重要的。T4 最好的视觉效果来自多伦多和 UMAP。前者捕获局部结构以及 LLE,并且似乎在这种特定情况下对原始表达数据起作用,然而,使用 PCA 的预降维通常提供更浓缩和不同的聚类。相比之下,UMAP 保留了局部和全局数据结构,并且基于拓扑数据分析,其中流形被表示为基本 单形 单元的集合,这确保了数据点之间的距离在高维度流形中看起来并不完全相等,但是存在类似于 2D 空间的距离分布。换句话说,UMAP 是一个战胜维度诅咒的优雅尝试,我将为 UMAP 背后的数学专门写一篇文章。****
摘要
在这篇文章中,我们了解到单细胞基因组数据有一个非线性结构,它来自于由于遗漏效应而在表达矩阵中占很大比例的随机零点。线性流形学习技术保留了数据的全局结构,但不能够完全解析所有存在的细胞群体。相比之下,保持** 数据点(LLE,tSNE,UMAP) 之间的局部连通性是单细胞基因组数据成功降维的关键因素。**
请在下面的评论中告诉我,生命科学中的哪些分析对你来说似乎是 T2 特别神秘的,我会在这个专栏中尝试回答这些问题。在我的 github 上查看帖子中的代码。在 Medium 关注我,在 Twitter @NikolayOskolkov 关注我,在 Linkedin 关注我。下次我们将讨论无监督组学整合,敬请关注。
减少数据的内存,生活会更美好
Wing Tsun Practitioners Silhouette
上面的剪影是两个咏春练习者在做技术练习。请注意它们是如何相互靠近的。咏春是一种武术风格,从最小的动作中获得相同的冲击力。这种风格真正体现了“少即是多”的说法。
酷,但这和数据有什么关系?
它与数据的内存使用情况有关。在小数据集,这可能不是一个问题。但是如果你的数据集在内存中太大,你的计算机的性能将会降低。这意味着您的可视化将需要更长的时间来加载,特征工程需要更长的时间来生成,您的机器学习应用程序将需要更长的时间来处理。
减少你数据的内存,你所有有数据的应用都会更流畅。
You don’t want to drag your data around. Image by Lloyd Morgan on Flickr
那么,我们如何减少数据的内存使用呢?
有两种方法可以让你在熊猫身上做到这一点:
1.删除任何不相关的列。
2.更改列的数据类型。
我会用我收集的纽约州几何试题的数据给你看一个例子。
对于那些感兴趣的人来说,这些数据是从公开提供的 pdf 中收集的。数据然后被转移到 Excel,然后转移到 Postgresql。在那里,我使用 Python 的 Sqlalchemy 库从 Postgresql 中提取数据,并将其放入数据框中。
我假设你熟悉熊猫的信息方法。应用这个,我们得到以下结果:
df.info()
RangeIndex: 358 entries, 0 to 357
Data columns (total 7 columns):
id 358 non-null int64
ClusterTitle 358 non-null object
Cluster 358 non-null object
Regents Date 358 non-null object
Type 358 non-null object
DateFixed 358 non-null object
Qnumber 358 non-null object
dtypes: int64(1), object(6)
memory usage: 19.7+ KB
比这更准确。如果您应用参数memory_usage='deep'
,Pandas 将告诉您数据帧使用了多少内存。毕竟,当我们能得到精确的值时,它们比估计值要好。这样做显示了相同的信息,但是内存使用行是不同的。
df.info(memory_usage='deep') RangeIndex: 358 entries, 0 to 357
Data columns (total 7 columns):
id 358 non-null int64
ClusterTitle 358 non-null object
Cluster 358 non-null object
Regents Date 358 non-null object
Type 358 non-null object
DateFixed 358 non-null object
Qnumber 358 non-null object
dtypes: int64(1), object(6)
memory usage: 139.9 KB
所以我们的数据帧专门用了 139.9 KB 的内存。
我们需要的另一个方法是带有参数deep=True
的memory_usage
方法,以查看每一列使用了多少字节的内存。让我们将它应用到我们的数据集,看看使用了多少内存。
df.memory_usage(deep=True)Index 80
id 2864
ClusterTitle 38222
Cluster 22713
Regents Date 14320
Type 21122
DateFixed 22554
Qnumber 21392
dtype: int64
删除列
我们将删除 id 列,因为它是 Postgresql 表使用的列。您不需要它来进行分析。为此,我们将使用来自熊猫的drop
方法,使用axis='columns'
和inplace=True
。我们的axis
参数确保只删除该列。inplace
参数保留原始数据帧,不包含我们删除的列。
df.drop(['id'],axis='columns',inplace=True)
现在让我们看看内存减少了多少。
df.info(memory_usage='deep')
RangeIndex: 358 entries, 0 to 357
Data columns (total 6 columns):
ClusterTitle 358 non-null object
Cluster 358 non-null object
Regents Date 358 non-null object
Type 358 non-null object
DateFixed 358 non-null object
Qnumber 358 non-null object
dtypes: object(6)
memory usage: 137.1 KB
因此少了 2.8 KB 是一个很小的改进。但是当然,我们想做得更好。现在让我们看看我们可以对每一列的数据类型做些什么。
改变列数据类型
回想一下,我们使用了memory_usage
方法来查看每一列使用的内存量(以字节为单位)。我们还从info
方法中看到了每个列的类型。其中大部分是物品。在这些列中,有些是可以被视为标签的字符串数据列。我们可以减少标签数据(比如集群列)内存的一种方法是将它改为一种category
数据类型。
让我们使用astype
方法将集群列更改为category
数据类型。(对于上下文:聚类列显示问题的总体主题的代码)
df['Cluster']=df['Cluster'].astype('category')
现在来看看该列的内存使用量是如何变化的。
df.memory_usage(deep=True)
Index 80
ClusterTitle 38222
Cluster 1885
Regents Date 14320
Type 21122
DateFixed 22554
Qnumber 21392
dtype: int64
哇!1885 字节比 22713 字节好多了!这意味着内存使用减少了 91.7%。现在我们将把 Type 和 Qnumber(问题编号范围从 1 到 36)列转换成相同的数据类型。如果你在看之前需要练习,你可以自己试试。
df['Type']=df['Type'].astype('category')
df['Qnumber']=df['Qnumber'].astype('category')
现在让我们看看这对单个列的内存使用有什么影响。
df.memory_usage(deep=True)
Index 80
ClusterTitle 38222
Cluster 1885
Regents Date 14320
Type 556
DateFixed 22554
Qnumber 3789
dtype: int64
太神奇了!Qnumber 数据类型内存使用减少了 82.8%。Type 列的内存使用大幅减少了 97.3%。现在,查看整个数据帧的整体内存使用量减少情况。请记住,我们的数据帧使用了 137.1 KB 的内存。
df.info(memory_usage='deep')
RangeIndex: 358 entries, 0 to 357
Data columns (total 6 columns):
ClusterTitle 358 non-null object
Cluster 358 non-null category
Regents Date 358 non-null object
Type 358 non-null category
DateFixed 358 non-null object
Qnumber 358 non-null category
dtypes: category(3), object(3)
memory usage: 79.5 KB
总体而言,我们的数据帧的内存使用减少了 42%。我们将内存使用量减少了将近一半!不错!
最终想法和额外资源
内存使用更多的是一个计算机科学的概念,但是请记住,在您进行分析的时候,您仍然在编写代码。减少内存使用将全面提高计算机生成可视化的性能,在进行特征工程时提高新列的生成,并提高机器学习应用程序的处理能力。同样,您可以通过删除不必要的列并更改列的数据类型来减少数据的内存使用。
Image from Floriana on Flickr.
这更多的是为了减少数据的内存使用。如果你觉得这有帮助(或没有),你有进一步的问题,然后留下评论,让我知道。
关于减少内存使用的更深入的解释,请看 Josh Delvin 的博客文章。
感谢阅读!
直到下一次,
约翰·德杰苏斯
通过兴趣点归一化减少数据不一致性
By Franki Chamaki
数据规范化是一种减少数据不一致性的优雅技术。尤其是当我们处理一个巨大的数据集时。通过这篇文章,我将带你了解我在最近的一个项目中所做的一些选择。
首先让我介绍一下问题,描述一下预期的结果,然后说明我达到目标的步骤。
请在这里找到我们将在本文中使用的虚拟数据。
问题:
假设我们希望通过重塑值的分布来规范化点列表(名称,值)。
预期目标将是:
1-限制最小常数值(标注为“Min ”)和最大常数值(标注为“Max ”)之间的值。
2-从“最小”值到“最大”值,点的密度应显著降低。
这意味着我们应该让大多数点接近“最小值”,只有少数几个点接近“最大值”极限。
我们将使用 Python 脚本从文件中读取点值,并根据上述标准对它们进行规范化。
我的策略:
首先,我从启动我的 Python 库和读取数据开始
import pandas as pd
import matplotlib.pyplot as plt
from scipy import special
import numpy as np
# Read the data
data = pd.read_csv('raw_scores.txt',sep=' ', header=None)
x = data[1]
在那之后,我执行一些标准的数据分析操作,检查数据形状,检查重复的线和检查异常值(超出最小、最大范围)。
为简单起见,我们将设置 Min=0,Max=10
# Check data description and shape
print (data.describe())
# check if any duplicate lines
duplicateID = data[data.duplicated(subset=0)]
print("Duplicated lines count is :",duplicateID.shape[0])
## check if any outliers (outside range(0,10))
outl=data[data[1] >= 10]
print("Outliers count (POI greater than 10) = ", outl.shape[0])
outl=data[data[1] <= 0]
print("Outliers count (POI less than 0) = ", outl.shape[0])
然后,我绘制了实际的分布图,看看它看起来如何,离要求的结果有多远。
# Drawing barPlot by [k,k+1] range to see data
data[1].value_counts(bins=[Min,Min+1,Min+2,....,Max]).plot.bar(figsize=(10,5))
plt.xlabel('range of POI')
plt.ylabel('Occurences')
plt.tight_layout()
plt.show()
接下来,考虑到以下需求,我开始了一些标准化实验:
要求 1: 将数值限制在标注为“Min”的最小常数值和标注为“Max”的最大常数值之间。
要求 2 :从“最小”值到“最大”值,点的密度应显著降低。
在我们的实验中,我们定义:dif = minimum ([ k-1,k]和[k,k=1]之间的差)应该大于 0(如果> 5,我们提出宾果)
要求 3 :很少的值应该以接近最大值的分数结束。
为了做这个实验,我创建了一些有用的函数:
countBin() : 计算每个[k,k+1]中有多少个点
def countBin(l,i):
if len(l.value_counts(bins=[i, i+1]).tolist()) == 0:
return 0
else:
return l.value_counts(bins=[i, i+1]).tolist()[0]
check_requirements() :检查结果是否符合上述要求的函数。
def check_requirements(l):
t1=countBin(l,0)
print("range [ 0 - 1 ]",t1)
t2=countBin(l,9)
dif = 10
for i in range(0,9):
print("range [",i,"-",i+1,"]", countBin(l,i))
t1 = t1 + countBin(l,i)
if dif > (countBin(l,i-1) - countBin(l,i)):
dif = countBin(l,i-1) - countBin(l,i)
print("total=" ,t1, "dif=", dif, "t2=", t2)
if (t1 == 91897) and (dif>=5) and (t2 in range(5,250)):
print("==========================================")
print("============== BINGO =====================")
print("==========================================")
Experiment_dis(): 对不同的分布模型进行实验,试图找到符合要求的最佳模型参数。
def Experiment_dis(distribution,l,n,m,step):
for i in np.arange(n, m, step):
if distribution == "zipfian":
y = (l + 1) ** (-i) / special.zetac(i)
if distribution == "pareto":
y = i / l ** (i + 1)
if distribution == "binomial":
y = (1 / i) ** (0.4 * l)
if distribution == "lomax":
y = 1 / (i + l) ** (4)
if distribution == "weibull":
y = (5 / i) * (l / i) ** (5 - 1) * np.exp(-(l / i) ** 5)
y = 1 / y # to preserve order (Requirement4) since all distribution involved will inverse the order.
y = 10 * (y - min(y)) / (max(y) - min(y)) # Normalisation to [0,10]
print("i=", i)
check_requirements(y)
print("-----")
data[2] = y
print(data.head())
我们在这里实验的模型有:
二项式分布、洛马克斯分布、威布尔分布、齐夫安分布。
我们为什么选择这些模型分布?
因为从它们的图形表示来看,它们似乎非常符合要求,请参见下文:
所以我们进行实验:
Experiment_dis("zipfian",x,1,5,0.1)
#best score obtained is dif=10 t2=7 for i=2.6
Experiment_dis("pareto",x,1,5,0.1)
#best score obtained is dif=9 t2=7 for i=1.2
Experiment_dis("binomial",x,1,5,0.1)
#best score obtained is dif=10 t2=6 for i=1.8
Experiment_dis("lomax",x,1,10,0.1)
#best score obtained is dif=9 t2=7 for i=7.7
Experiment_dis("weibull",x,1,2,0.1)
# Did not give good result, hence not adapted
我们选择形状参数为2.6的 Zipfian,因为它代表了需求方面的最佳得分。
Experiment_dis("zipfian ",x,2.5,2.6,0.1)
以下是我们的 POI 标准化后的样子:
## Drawing Plot to see new distribution after normalisation using zipfian
data[2].value_counts(bins=[0,1,2,3,4,5,6,7,8,9]).plot.bar(figsize=(10,5))
plt.xlabel('range of POI')
plt.ylabel('Occurences')
plt.tight_layout()
plt.show()
## Saving the output into CSV
data.to_csv(r'submission1.csv')
我也在一个公开的要点中分享了代码。
本文简单介绍了标准化如何组织我们的数据,并在不丢失信息的情况下使其更准确地符合现实。一般来说,规范化是许多机器学习算法的要求。如果您不确定哪种类型的标准化适合您的数据,请参阅这些资源的更多详细信息功能缩放。
一如既往,我希望你学到了一些新东西:)
萨拉姆。
减少不确定性:知道的越少,学到的越多
你不需要大数据在你的分析中变得“重要”
在一个数据变得如此普遍的时代,我们已经太习惯于解决我们认为拥有“足够数据”的问题,而忽视我们认为缺乏数据的问题。更糟糕的是,大数据的嗡嗡声已经改变了我们的预期,让小数据变得无用、无信息、非常无聊。但这就是为什么我们有数据科学家,对不对?
其实数据科学家这个头衔有点多余;另一类科学家到底是什么?不是每个科学家都是数据科学家吗?根据 sciencecouncil.org 的说法,科学家是这样的人:
系统地收集和使用研究和证据,提出假设并进行检验,以获得和分享理解和知识。
本质上,科学更多的是关于收集数据,而不是拥有数据。相反,我们应该将自己视为商业或可能的决策科学家:观察和 收集数据 以便为我们的决策提供信息。
我将用 3 个例子来说明收集数据的行为是如何值得的,尤其是在数据很少或没有数据的情况下。
#1 估计受污染鱼类的百分比
假设有谣言说附近的一个湖爆发了某种水传播疾病,这种疾病可能会感染鱼。你绝对不知道鱼的哪一部分(如果有的话)被感染了。如果你想 100% 确定百分之多少的鱼被感染,你需要对每条鱼进行取样(这是一项不合理且昂贵的任务)。相反,你决定随机抽取几条鱼的样本,观察它们是否被污染?当然,我们知道样本越多,我们的估计就越准确。尽管如此,随着我们采集越来越多的鱼样本,我们估计的确定性的净增加是增加还是减少?换句话说,我们从第一条鱼中获得的确定性的增加等于、小于还是大于我们从第 1000 条鱼中获得的确定性的增加?在继续之前,让我们先确定一些事情:
最高密度区间 (HDI): 该度量表示分布中最可信的一组点。例如,95% HDI 区域意味着 HDI 内部的每个值都比 HDI 外部的任何值具有更高的概率密度。
不确定性:在我们的例子中,不确定性将被定义为 95% HDI 的范围。例如,如果我们给定分布的 95% HDI 是[.04 到. 66],那么我们的不确定性将是. 62 (.66-.04)。范围越小,我们越有把握。
贝塔分布:贝塔分布是一个纯粹的连续分布,我们将用它来表示我们的鱼被污染的概率。
现在是时候对鱼进行随机取样,检测是否被污染了。我们可以在每个样本后更新贝塔分布,从而量化新的不确定性。请注意,在对任何鱼进行采样之前,我们的分布在 0 和 1 之间是均匀的,在 0 和 1 之间的任何值都是同样可能的。为了这个例子的目的,让我们假设我们采样了 15 条鱼,没有一条被感染。下面的图表显示了每个样本后我们更新的分布。
The order of charts is top-down starting from left; Uncertainty shown in red region
注意我们的不确定性(红色区域)在每个样本后是如何减少的。没有任何鱼样本(左上),我们的 HDI 范围是 95%。到我们对第 15 条鱼取样时,我们的 HDI 下降到了 17%(减少了 80%以上)。假设 15 条鱼样本中没有一条被感染,那么真实的污染率有 95%的可能在 0%到 17%之间。
然而,最令人印象深刻的是不确定性的最大减少实际上来自第一个样本。在我们的第一个样本之后,我们的人类发展指数范围下降了 17%,从 95%下降到 78%。
Reduction in Uncertainty after 15 samples
左边的图表反映了每个后续样本后我们的 HDI 中的 减少 。注意不确定性的减少。对第 10 条鱼取样只减少了我们 2%的不确定性。
最后,我们的第一个样本比第十个样本减少了 8.5 倍的不确定性!
#2 根据未知分布估计中值
假设我们只从未知大小的未知分布(参数或非参数)中抽取 3 个值。
未知分布的真实中值落在最高和最低采样值之间的几率有多大?
我们可以通过计算相反的问题来解析地解决这个问题——真实中值落在我们的最高或最低值之间的概率。根据定义,一个随机样本有 50%的几率低于中值,因此所有 3 个样本都低于中值的几率为 0 . 5。然而,我们也可以让所有 3 个样本以相等的几率高于中位数。因此,1 减去组合概率将计算出真实平均值落在两者之间的概率。
下面反映了前 9 个样品的结果。
请注意,只有 2 个样本时,其概率是 50–50。抽取第三个样本将使我们的机会增加 0.25%到 75%!到我们的第 5 个样本,我们的机会已经提高到 93.75%!
只需 5 个样本,我们就可以了解未知分布的很多信息!
瓮中的 3 个球
假设有一个骨灰盒,里面有一万个红蓝球。你不知道一个球有百分之多少是蓝色或红色的(它可以在 0 到 100%之间变化)。你猜对骨灰盒中主要颜色的几率是 1–1(50%的几率)。
假设你从骨灰盒中取出 1 个且只有 1 个球。你现在猜对大多数颜色的几率有多大?
假设你总是猜你采样的颜色,猜对大多数颜色的几率从 50%上升到 75%,只要采样一个球就增加 25%!
结论
- 在许多情况下,当你对某件事知之甚少时,数据的价值,也就是信息的价值,是最大的。
- 有机会证明在做决定之前收集更多数据的价值,特别是当我们知道的很少的时候。实际上,你可以使用贝叶斯统计框架将价值货币化。这些概念与信息分析的值密切相关,可用于计算收集更多数据以减少不确定性的 ROI。
反思 4 个月的数据科学博客
Photo by Designecologist from Pexels
回顾过去的 4 个月,并为未来的 4 个月设定一些目标…加上我终于达到了 1K 粉丝!谢谢大家!
我在今年(2019)五月中旬左右开始认真写博客。我正在参加一个数据科学训练营,想要一个论坛来展示我的工作。我的导师建议我在 Medium 或 GitHub 上写博客。感谢星星,我选择了中等(我永远无法让我的 GitHub 博客工作)。
完全披露——这篇博客有点沾沾自喜。当我最终达到 1000 名追随者的里程碑时,我告诉自己我会写一篇“回顾我来的地方”的帖子,我终于在几天前达到了这个里程碑(感谢所有人的支持和阅读我的材料)。
我将谈一谈我是如何走到这一步的,但老实说,我没有太多的智慧可以分享。我的博客能够获得关注的原因之一是运气。如果我从头开始,我不确定我是否能够复制所发生的事情(你会在下面看到为什么我会有这种感觉)。
一些统计数据
以下是我博客的一些数据:
- 1018 名粉丝(1000 是我的长期目标,所以请原谅我的吹嘘)。
- 25 篇文章发表 (自五月中旬起,不包括此篇)
- 我目前的收入大约是每周 160 美元。还没有租金,但也不是花生。
我当然为能走到这一步而自豪。当我开始写关于数据科学的博客时,我希望将我的写作与职业联系结合起来,最终 帮助我 找到一份工作,就是这样。我当时并不知道写作会成为我的一项新爱好和额外的收入来源——我现在把我的博客视为我自己的一个小公司,我打算在可预见的未来继续完善和努力。
我在上面提到了运气。让我告诉你我的意思。
瓶中闪电
在我写这篇文章的时候,我的博客有 225,346 次的浏览量。这些观点中,82058 个(占总数的 36%)来自一个帖子, 了解随机森林。 它成功的主要原因是,当你谷歌“随机森林”(就在维基百科下面找)时,它是顶级搜索结果之一——顺便说一下,我不知道谷歌为什么把它排在这么高的位置。
有趣的是,我从未打算单独发表那篇文章。它原本是为了补充另一篇文章(我的新兵训练营项目,在那里我使用机器学习来选择 Lending Club 贷款进行投资)。随机森林算法在我的结果中占有显著地位,所以我写了一份关于它如何工作的描述。然而,我不是一个简洁的作家,因此描述结束时真的很长。考虑到没有人愿意阅读一篇关于我的数据科学项目的 25 分钟的博客文章,我决定将关于 random forest 的部分作为自己的文章发表。幸运的我,看看结果的不同:
- 了解随机森林——82056浏览量和 432 粉丝。
- 把 Lending Club 最差的贷款变成投资金—1136观点和 39 粉丝。
即使现在 3 个月过去了,它仍然是我浏览次数最多的博客,我几乎没有发表它。如果我没有发表它,我就不会有今天。
在波动中坚持
从那以后,我试图重现那道闪电,但收效甚微。我取得了一些合理的成功(我应该说是一些火花),但没有闪电。定期发布好内容真的很辛苦。我非常钦佩我的媒体同行们,他们每天都出版高质量和受欢迎的内容。
通过努力工作,让我们诚实一些运气,这些人磨练了他们的写作风格和主题专业知识,以这样一种方式,它与媒体读者感兴趣的事情有很大的重叠。借用创业界的术语,这些超级作家享受着巨大的产品市场契合度(见下面的文氏图):
The Type of Writer We All Aspire to Be (The In My Dreams Venn Diagram)
然而,对于我们这些普通人来说,现实更有可能是我们并不像我们认为的那样知道很多。普通读者对我们有见解的主题不感兴趣:
The Type of Writer I Actually Am (Realistic Venn Diagram)
当你花了几天时间制作和研究的作品失败了,这绝对令人沮丧。例如,我真的为这篇关于如何更有效地提高人们的技能并帮助他们转行的文章感到骄傲。然而,这是迄今为止我最少阅读的故事之一。
但没关系——有些波动是意料之中的,就像上面现实的文氏图一样,人们不会总是对我认为值得注意的事情感兴趣。对我来说,关键是写作,直到我找到自己的定位,然后继续磨练那个专业领域,如果我的定位更小、更窄也没关系。
此外,除了观点和阅读之外,我还写了许多其他原因:
- 为了学习 —我的很多数据科学帖子都是为了让我更好地理解一门技术学科。试图教某人某样东西是如何工作的,尤其是在像 Medium 这样公开的论坛上,迫使我再三检查我认为我对这个主题的了解。此外,用简单的英语解释主题迫使我完全理解基本原理,这样我就可以想出清晰和相关的例子。
- 好奇心——这个世界上有如此多有趣的数据被收集,也有如此多有趣的问题需要解决。我可能无法像在真正的研究项目中那样深入研究,但这个博客将继续作为我定量探索的日记。
- 结识志同道合的人——这是博客的一个方面,我肯定需要更加努力。我喜欢媒体上几乎没有巨魔或火焰(根据我个人的经验),但我也不介意更经常地与我的读者交流。在不久的将来,我希望与读者和其他作家建立真正的、持久的联系。
- 副业收入 —我不会撒谎。我的写作能得到报酬,这当然很好,也很令人惊讶。与其他平台相比,我还喜欢 Medium 上的努力和收入之间有更多的相关性。
最后也是最重要的一点,我写作是为了遵守纪律。我坚信良好的行为会增加——这意味着随着时间的推移,良好决策的累积收益会呈指数增长:
What Positive Compounding Looks Like
我计划继续每周至少发布一篇文章,风雨无阻。就像耐心地培育和维护一个花园最终会带来一个又一个的丰收一样,我希望在一两年后回头看时会说,“哇,看看我的博客取得了多大的进步,我从每周坚持写博客中学到了多少。”
最后,因为我经历了训练营和职业转变,我对教育即服务行业(训练营、MOOCs、职业发展平台等)产生了兴趣。).对于转行者来说,找工作可能是相当残酷无情的(我个人经历过这种情况,也在我的密友身上看到过)。我觉得肯定有更好的方法——不幸的是,我目前在这方面没有任何改变游戏规则的见解,但它肯定会是我未来关注的领域。
结束语
我为这篇文章的漫无边际道歉。我真的很兴奋能够为你们所有人写作,并感谢你们的支持。
如果有任何数据科学、教育或金融作家想要合作或只是聊天/头脑风暴,请在 Medium 或通过 Twitter 在给我留言。干杯,我期待着你的来信!
更多数据科教相关岗位由我:
运用数据科学实现财务自由的思考
在我写这篇文章的时候,由于是长周末,今天是一个休闲星期五,所以我想写一篇很好的反思文章,谈谈我将数据科学应用于财务自由的想法。抱歉,我的正常 peeps 想要一些编码样本。今天的文章会让人感觉像是在酒吧的壁炉前放松的谈话。所以,让我们打开流畅的爵士乐,开始吧。
只是一个侧栏,所有这些主题将特别集中在金融市场领域。利用数据科学赚钱的方式有很多,但金融市场是我自己赚钱的方式。另外,当我说系统时,我指的是一个投资策略或策略组合,它可以变成一个自动化的模型。
为什么找到盈利系统很难?
对于任何搜索过盈利系统的人来说,你通常会得到一大堆 X 保证,Y 系统会像这样工作:
一旦运行它,返回结果如下:
从数据科学的角度来看,我们会说系统是过度适应的。这意味着该模型只采用历史上看起来不错的交易,而没有捕捉到任何潜在的模式,可以为未来的使用而获利。
在我们的案例中,寻找有利可图的系统是很困难的,因为你必须发现一个没有多少人发现的低效率。如果每个人都找到了,那它就不会在那里了。但是我说的低效率是什么意思呢?
研究旧理论的价值
大多数熟悉金融领域的人都知道有效市场假说。但是回顾一下,有效市场假说认为资产的市场价格是完全定价的,所有市场参与者都知道所有信息。研究像有效市场假说这样的理论的价值在于了解为什么它们是错的。这样做,你会发现通向盈利系统的道路。在行为金融学开始占据主导地位之前,有效市场假说在过去是一个相当占主导地位的理论。我想,回想起来,这是有道理的。我的意思是交易市场很难,所以它一定是有效的。
失败是成功的前兆
市场在某种程度上是很难的,但我认为,就像生活中的所有事情一样,取决于你如何看待它。难只是基于你目前的技能水平对一项任务的主观评估。一旦你提高了技能,事情就会变得简单。我相信我们都有过比我们更高质量更快完成任务的同事。那来自专业知识,可以通过专注和时间获得。
对于那些更关注心态方面的人,这里有一篇关于我如何处理逆境的更深入的文章:https://towards data science . com/starting-out-data-science-never-coded-b 79 ed 985 e 661
记住,失败也没关系。我们都会犯错。这是挑战你极限的唯一方法。一旦你发现它们,你就克服它们并重复。对我来说,就是试图找到一个成功的投资系统,做我想做的事情。
成功是短暂的,但却是甜蜜的
在寻找一个成功的投资系统的过程中,我确实找到了一些。它们包括技术分析、10-K 和新闻报道的基础知识,以及更先进的机器学习技术。令我惊讶的是,一旦你知道如何研究,实际上有很多成功的系统。
请记住,这些系统中的大多数不会永远存在。例如,2015 年,我在研究欧元兑美元(一种外币资产)的技术分析系统。这是一个半公开论坛上的公开合作。该系统在几个月内运行良好,大约每月 10%。然后论坛稍微火了一点,系统就死了。这可能是太多人利用低效率的结果,或者是事件的根本原因因为另一个原因而被删除了。这是关于技术分析的事情,你几乎只是相信图表所做的一切,而没有任何潜在的经济原因。
至于基本系统,当它们是正确的时候,那是非常有趣的。有一天,你可以走进办公室,看到你所有的位置。你认为你是个天才。又一天,你发现你所有的仓位都下跌了,你觉得自己像个白痴。从积极的一面来看,你会有一个潜在的经济/金融原因来解释你的系统工作。
至于机器学习方面,这是我目前在私人投资组合中使用的东西。自动化最酷的地方是你可以做其他事情。假设你不是那种会强调你的投资状况的人,这是相当放松的。对于那些和交易者心理斗争的人,我推荐范萨普的书。
结论
对于那些想知道你是否还能利用数据科学在金融市场中赚取收入的人,答案是肯定的。但这需要你做大量的研究。大多数人不分享他们成功的交易系统的原因是大多数不会持续那么长时间,而且一些策略不会随着更大的资金而扩大。Scaling 用另一种方式解释说,如果太多人在同一个系统上操作,那么利润就会下降。如果我要从头再来一遍,我会开始:
- 学习数据科学/软件工程——通过系统决策和未来研究改进战略的客观审查
- 学习金融/经济学——理解为什么会发生变化
- 学会交易——帮助执行策略
从以上三点来看,我根据相对于行业内的难度对它们进行了分类。例如,与金融博士相比,大多数投资公司更倾向于统计学博士。只是实际的编码部分需要更多的时间来开发,而财务方面被认为是可以在过程中教授的东西。
总的来说,我建议那些对金融市场充满热情并喜欢独立研究的人成为一名定量/金融数据科学家。一旦你达到了财务独立的临界点,仅仅因为想在某个地方工作而不是必须在那里工作是很好的。唉,寻找更多策略的探索永无止境,因为市场总是在变化。为了保持领先,你必须随之改变。
另外,对于那些刚刚接触定量领域的人,我发现了一篇来自 Ross Ledhrman 的 Quora 帖子,这篇帖子可以给你一个好的方向:https://www . Quora . com/How-do-I-be-a-good-quant-What-technical-skills-I-should-I-learn-and-improve-if-I % E2 % 80% 99m-a-new-graduate
你最喜欢的投资风格有哪些?欢迎在下面留下任何问题或评论,我会在你身边!
免责声明:本文陈述的所有内容均为我个人观点,不代表任何雇主。投资有很大的风险,所有投资决定都要咨询你的投资顾问。
关于 NeurIPs 2019 的思考
机器学习何去何从?
我最喜欢的主题,个人想法,和新的研究领域。研究人员是否展现了与大型科技公司不同的一面?
Vancouver as a conference venue left me blown away. Has been perfect for me, let’s hope others agree.
我完全理解为什么这些天人们都涌向神经信息处理会议。当然,在 12 分钟内销售一空是个问题,但这里的展示展示了机器学习影响的巨大前景。我袖手旁观机器学习是我们可以用来超越许多全球问题的创新工具之一(我认为认为我们可以超越气候变化的想法有点天真)。
NeurIPs Society. Let’s hope they keep providing great events!
会议的亮点都在充满活力的推特社区上被追踪,呼吁最好的结果,并询问可疑时刻的问题。还有一个关于机器学习在技术和人文意义上的走向的实质性讨论。考虑到机器学习往往会在主流媒体上引起负面报道,这一事件真正传递给了一个试图为社会尽最大努力并检查他人的社区(如果更多的这种情况能够应用于同行评审系统,让许多人在这里)。
主题:研究人员真的同意海报呼吁更多的结果的可解释性
这里的研究人员强烈要求问责。我在深度强化学习研讨会上展示了一张关于“基于模型的强化学习中的目标不匹配”的海报,人们非常容易接受这样的观点,即我们对强化学习如何工作的一些潜在假设可能是有缺陷的。
Here’s my poster. Always happy to answer research questions, but don’t want to dive too far in on this post!
我还碰巧在谷歌的一位研究员旁边展示了我的海报,这位研究员正在推动 RL 算法中更多的可靠性指标。这意味着:当性能论文声称跨环境和随机种子的新“最先进”时,它们提出的一致性如何。这种现实的鲁棒性可能是让这些算法在实际应用中更有用的关键(例如机器人,我将一直把它作为 RL 的一个伟大的可解释平台)。
我们两张海报之间的重点评论来自 Oriol Vinyals (该领域非常著名的研究员),关于如果我们将当前的 RL 基线与解决任务的人类进行比较会发生什么?我们猜测人类会更快、更可靠地解决合理的任务——所以作为一个行业,我们还有大量的工作要做!
RL 可靠性度量标准库提供了一组度量标准来衡量强化学习的可靠性
github.com](https://github.com/google-research/rl-reliability-metrics)
此外,有很多研究人员质疑人们为什么会谈论敏感话题的例子。对抗我们领域危险趋势的地面力量是大公司注意到这一点的唯一方式。
Had the pleasure of exploring the skyline on a jog. Thanks to some great friends that eagerly entertained me wanting to chat on the phone while jogging. Peep the paddle boarder.
疯狂的新想法:用于健康应用的 RL
强化学习已经被证明是学习如何在结构化环境中行动的有效工具,那么我们如何利用它来改善健康呢?我和我的新朋友斯蒂芬妮·陈(来自神经科学领域的谷歌人工智能常驻人员)想出了将 RL 应用于实验室小鼠的想法,以检查不同的饮食、药物和活动模式。许多医学实验室使用老鼠作为人体实验的先驱,所以这是合乎逻辑的起点。我在考虑给伯克利的生物学学生发几封电子邮件,他们可能会疯狂到让我尝试一下。我加入是因为它将融合我对 RL 的专业兴趣和我对长寿和健康的个人热情。有什么想法吗?
当 RL 找到优化小鼠生物标记子集的最佳方法时,这个问题基本上就形成了。环境会有一系列的行为组合(饮食、活动和药物),回报要么是寿命(稀疏回报),要么是生物标记(更难分析的持续回报)。这能有多难?
A hideaway in Stanley Park — Beaver Lake is a drop into nature from city center, and the mayhem of a busy conference.
新领域:医疗保健联合学习
联合学习正在设计云中的系统,这些系统可以在中央服务器上合并私有数据(例如患者数据),以改善学习指标和结果(例如医学图像检测)。该领域的研究正应用于一个与网络安全和医疗系统密切相关的领域,这两个领域有时已经很难合作。
Friedman, Charles P., Adam K. Wong, and David Blumenthal. “Achieving a nationwide learning health system.” Science translational medicine 2.57 (2010): 57cm29–57cm29.
也就是说,联合学习成为标准将是巨大的。截至目前,由于隐私协议,大多数医院共享的数据少得惊人。谁不想让自己的扫描匿名地与计算机的全国数据库进行比较呢?它为医疗系统的人性化方面增加了安全、定量的分析。
我还要补充一点,创建一个通用的结构,让我们的数据能够 1)被用来帮助一个更大的系统,同时 2)不被我们的身份所束缚,这才是数据使用的正确方向。大多数公司一直在买卖我们的数据,因此能够在使用数据的同时维护隐私是一个巨大的胜利。
这是 Nvidia 今年早些时候关于联合学习的总结。
在任何领域,成为医学专家的关键是经验。知道如何解释症状,这…
blogs.nvidia.com](https://blogs.nvidia.com/blog/2019/10/13/what-is-federated-learning/)
联合学习在我看来是学习社区中一个非常有前途的方向。学习正在改变世界,因为它能够在数据集中建立联系,而联合学习是一个结构化的系统,可以将学习应用于大型社会规模的问题,这些问题以前由于缺乏基础设施而无法解决。
Views from the morning email desk. NeurIPs kept me appreciating the little things.
咖啡和自然。我非常喜欢在这里短暂的停留,我会回来的。
NuerIPs 2020?希望如此。
更多?订阅我关于机器人、人工智能和社会的时事通讯!
一个关于机器人和人工智能的博客,让它们对每个人都有益,以及即将到来的自动化浪潮…
robotic.substack.com](https://robotic.substack.com/)
对人工智能现状的思考:2018
人工智能领域关键发展的概述,重点关注关键参与者、应用、机遇和挑战
每天,讨论各种“与人工智能有关”的事情的多个新闻项目堆积在我们的邮箱中,每周都有几十篇(如果不是数百篇的话)文章、观点和综述在标题中包含“人工智能”一词。然而,并非所有声称与人工智能相关的东西实际上都是有意义的或相关的,相反,它们往往与该领域毫无关系。
为了使机器学习、神经网络和人工智能的其他领域的知识民主化,我们决定通过创建一系列专注的文章来展开我们的努力,这些文章将涵盖该领域的最新进展,看看关键人物,并提供一些对最有前途的技术的见解,以及该行业今天面临的机遇和困境。
在第一篇文章中,我们按照主要贡献者、应用和挑战对 2018 年的主要发展进行了简要概述。
今天,随着数百家公司深入人工智能领域,甚至更多的公司正在努力找出与该领域相关的战略,可能有点难以确定哪些特定公司最有可能在未来引领潮流。然而,如果我们看一下列出关键参与者的众多名单中的任何一个(例如,见这里的和这里的和和,5 家公司——谷歌、脸书、亚马逊、微软&IBM——不可避免地出现在所有名单上(其他几乎同样经常被提及的公司是苹果、腾讯&百度)。在本文中,我们将重点关注谷歌&微软,因为在 2018 年,这两家公司在人工智能领域的新闻中出现得最多;尽管如此,其余的科技巨头并没有少产,我们计划在下一篇关注技术最新进展的文章中更详细地介绍其中一些。
谷歌
Google Pixel: Night Sight capabilities demo from Google blog
对于谷歌在人工智能领域的努力来说,这是富有成效的一年,该公司推出的新产品数量以及对现有服务的一些关键改进都证明了这一点。
数量最多的公告来自谷歌 I/O,该公司在 5 月举行的年度开发者大会。除此之外,谷歌为 Gmail 推出了 Smart Compose,对谷歌地图进行了一些令人印象深刻的更新,或许最重要的是,宣布了其新的人工智能虚拟助手,称为谷歌双工(参见 2018 年谷歌 I/O 上介绍的所有新产品和功能的良好总结这里)。
用公司自己的话说:
【谷歌双工是】一种通过电话进行自然对话以完成“现实世界”任务的新技术。该技术旨在完成特定的任务,例如安排某些类型的约会。对于这样的任务,该系统使对话体验尽可能自然,允许人们正常说话,就像他们对另一个人说话一样,而不必适应机器。”
Duplex 给一家发廊打电话的录音令人印象深刻,甚至导致一些人质疑 Google Duplex 是否通过了图灵测试(提示:没有;至少,做出判断的人必须意识到她可能在和一台机器说话)。它还引发了一场激烈的讨论,即以这种方式使用技术,而不让接收端的人们意识到他们不是在与一个真实的人互动,而是在与一个机器人交谈,这是否合适。虽然可能很难明确回答这些问题,但我们可能很快就会看到更多这样的讨论,因为谷歌在 12 月开始在一些智能手机上推出 Duplex。
谷歌的另一个有趣的更新是智能手机 Pixel 系列的最新更新(Pixel 3 & 3 XL),它带有一些通过使用人工智能实现的真正令人印象深刻的新相机功能(我们将在本文后面专门讨论计算摄影进步的部分再次触及)。
最后,Alphabet Inc .全资拥有的 DeepMind Technologies 通过其 AlphaZero 程序的最新版本成功实现了一个重要的里程碑。
在 2015 & 2016 的围棋比赛中,我们已经看到了 AlphaGo 和 AlphaGo Zero 令人印象深刻的成就,当时它在与两位最强的围棋冠军比赛时轻松赢得了大多数比赛;然而,在 2018 年,DeepMind 的团队成功实现了更有趣的事情——最新的 AlphaZero 引擎展示了它在国际象棋、shogi 和 Go 中所有现有最强引擎中的明显优势。
AlphaZero 特别有趣的是,它在无需研究人类所玩游戏的任何日志的情况下,成功实现了这一壮举;相反,该程序自学了如何玩所有三个游戏,只提供了基本的规则。事实证明,通过摆脱从以前玩过的游戏中学习的限制,AlphaZero 采用了“一种突破性的、高度动态的和“非传统的”游戏风格”,这种风格与以往任何时候都不同。反过来,这使得引擎对社区更有用,社区可以通过观察机器开发的策略来学习新的策略。鉴于 AlphaZero 能够成功地从零开始学习并解决完美的信息问题,这也为这项技术在未来的现实应用创造了前景。
DeepMind 也在努力创建可以处理不完美信息问题的系统,正如它最近通过展示的 AlphaStar 在《星际争霸 2》中击败了一些职业玩家(而在过去,由于游戏的复杂性,人工智能一直难以成功地玩《星际争霸》)。
微软
Julia White, Corporate Vice President, Microsoft Azure Marketing, speaks at the Conversations on AI event in San Francisco. Photo by John Brecher for Microsoft
与谷歌类似,微软在 2018 年推出了新的人工智能相关产品和服务,并改进了一些底层技术。这项工作的一个重要部分是以社区为中心的,专注于为开发者提供更好的工具和功能,以在微软的云平台上构建人工智能解决方案。
有趣的是,微软名为“ Build 的重要开发者大会也将在 5 月举行,就像谷歌的一样。2018 年,对微软来说是一个拥挤的事件,该公司发布了大量新公告,特别是宣布项目脑波整合到 Azure 机器学习。
脑波项目(最初被称为弹射器)是 Bing 在 2010 年开始的数年研究的结果。脑波是 2017 年 8 月在顶级半导体会议之一的 Hot Chips 上向社区宣布的。简而言之,脑电波是一个 FPGA 芯片上的硬件平台,旨在加速实时人工智能计算,这是搜索引擎等服务的一个关键领域(这也解释了为什么这个项目从 Bing 中发展出来)。现在,随着脑波融入 Azure 的机器学习,微软声称 Azure 是 AI 最高效的云平台。
在去年 9 月在奥兰多举行的另一场大型会议 Ignite 上,微软发布了面向企业的 Cortana 技能工具包,这代表了一次在办公空间测试基于人工智能的助手的令人兴奋的尝试——想象一下你可以对机器人进行编程,使其能够为办公室安排清洁服务,或者在你简短的语音命令的指导下自动向服务台提交票证。
几天后,微软还宣布将实时翻译功能集成到 SwiftKey 中,这是微软在 2016 年收购的一款安卓键盘应用。最后,在 9 月底,继谷歌 Duplex 之后,微软发布了其语音服务工具,引入了改进的文本到语音合成功能。
11 月晚些时候,又有一系列有趣的公告,比如认知服务容器。认知服务允许开发人员在他们的应用程序中利用人工智能,而不需要他们成为数据科学专家,或者拥有广泛的人工智能相关知识。反过来,容器的故事集中在边缘计算的案例上——这个概念不需要将数据发送到云来执行计算,而是在本地处理,从而减少延迟,在许多情况下优化成本。有了容器中的认知服务,微软的客户现在可以构建在边缘位置运行人工智能的应用程序。
投资
Top 100 startups in AI, from CB Insights
人工智能领域的投资最近一直在蓬勃发展,尽管 Crunchbase 合理地呼吁,但很难估计有多少。CB Insights 已经建立了一个很好的人工智能空间的信息图表,并在这篇文章中按类别对顶级初创公司进行了分类。我们在这里看到两个主要的收获——首先,2018 年人工智能行业最大的几轮融资是由中国公司筹集的,如商汤科技和 Face++等(分别为 16 亿美元和 6 亿美元)。第二,在目前 11 家估值超过 200 亿美元的独角兽中,5 家公司来自中国,贡献了总估值的 50%,商汤科技以惊人的 45 亿美元估值领先。这强调了一个关键点:与其他国家相比,中国似乎正以更快的速度前进。此外,随着足迹越来越大,中国现在正成为人工智能领域的强国。(要了解更多细节,请查看这篇概述了当今世界各国正在推行的各种国家人工智能战略的摘要)。
道德、法规和教育
深刻的假货争议
AI-generated fake clips of President Obama’s speeches, from The Verge
2017 年 12 月,Motherboard 发表了一个故事,讲述了一个名为“deepfakes”的 Reddit 用户发布了一些硬核色情视频,这些视频将名人的脸映射到色情明星的身体上。虽然不完美,但这些视频相当可信,尤其是考虑到这些视频是由一个人制作的。尽管 Reddit 很快禁止了这些视频,但关于这项技术的合法性和潜在滥用的讨论从那时起就一直在升温。
通过交换演员的面部来制作假视频的技术已经存在了一段时间,但创作的容易程度和质量在 2018 年肯定达到了一个新的水平(见另一个例子,一个懂技术的用户可以实现什么这里)。制作虚假的色情视频虽然令人不安,但可能仍然相对无害,但正如我们最近看到的那样,同样的技术可以用来制造假新闻或制作虚假的宣传材料(或让巴拉克·奥巴马总统说他永远不会说的话,至少不会在公共场合说),这可能会对我们的社会产生严重的影响。对此能做些什么吗?这还有待观察,但事实是,深度赝品会一直存在,而且很可能只会变得更难与真品区分开来。
人工智能偏见
Photo from Microsoft’s blog post “Facial recognition: It’s time for action”
在过去几年中,监督和非监督学习方法都产生了一些令人兴奋的结果(DeepMind 的 AlphaZero 就是通过非监督学习实现的一个例子)。尽管如此,大量现实世界的应用程序需要基于标记数据的训练模型(顺便提一下,这是经常阻碍进一步发展的关键问题之一)。
然而,拥有一个由大量标记数据组成的数据集来训练模型并不等同于拥有一个好的数据集。你看,依赖监督学习的神经网络只和它们最初被训练的数据一样好,所以如果底层数据集有任何缺陷(例如以牺牲其他特征为代价专注于一个特征),神经网络有可能会拾取这些偏差并进一步放大它们。这在理论上听起来可能不太糟糕,但只有当我们考虑到现实世界应用中可能由此产生的问题时——正如我们在 2018 年看到的那样,这些问题可能会非常深远。
例如,在麻省理工学院媒体实验室的研究员 Joy Buolamwini 所做的研究中,她证明了微软、IBM 和旷视科技的领先人脸识别系统只错分了 1%的白人男性的性别,却错分了高达 35%的深色皮肤女性。原因?这些模型是在一个有偏见的数据集上训练的,该数据集包含更大比例的白人男性照片,因此在正确识别他们的性别方面越来越好。考虑到人脸识别技术现在越来越多地被执法部门使用,以及非裔美国人被挑选出来的可能性最大,因为他们在面部照片数据库中的比例失调,这种表现上的差异可能会产生非常重大的负面影响。
2018 年公开的同一问题的另一个著名例子是与亚马逊内部人工智能招聘工具相关的案件。亚马逊打算利用机器学习能力来实现更高效的招聘流程,并有可能完全自动化一些步骤。不幸的是,事实证明,上述工具是根据以前申请过该公司的人的简历进行培训的,其中大多数是男性。因此,该模型获得了这些偏见,并反过来训练自己降低女性候选人的等级,优先考虑“男性语言”等内容,以促进男性的申请。亚马逊最终放弃了这个工具,但还有很多其他公司试图利用人工智能来帮助招聘过程,他们的模型可能有类似的缺陷。
今天,越来越多的人(和公司)呼吁当局制定监管框架来管理人脸识别的使用。它会很快发生吗?这仍有待观察,但至少某种程度的监管可能即将到来。
优步的自动驾驶汽车在亚利桑那州撞死行人
Uber Volvo XC90 autonomous vehicle, image from MIT Technology Review article
不幸的是,在复杂、不确定的环境中运行时,即使是最伟大的技术也难免会偶尔出错。因此,2018 年 3 月 18 日,最终注定要发生的事情发生了,当时一辆属于优步的自动驾驶汽车在亚利桑那州坦佩市撞死了一名行人。这起事故迫使该公司暂停其无人驾驶汽车的所有测试,并重新检查其流程和技术;这也引发了关于自动驾驶汽车背后的技术现状的热烈讨论,以及如果自动驾驶汽车要在短期内获得公众的广泛接受,需要解决的道德和监管挑战。
九个月后,优步被允许在匹兹堡恢复其自动驾驶汽车测试,随后于 12 月在旧金山和多伦多进行测试,尽管在这些情况下,优步的自动驾驶汽车仍然被限制在“手动模式”(这意味着该公司将专注于将汽车软件暴露在新环境中,而不是进行主动测试)。为了再次赢得当局的好感,优步不得不同意对允许其自动驾驶汽车行驶的道路类型和条件进行额外限制。此外,优步不得不转向为司机提供更严格培训的系统(这是一个关键环节,因为对三月份发生的致命事故的调查表明,司机心不在焉,因此没有像他应该的那样注意路况),现在被称为“任务专家”。最后,该公司推出了第三方司机监控系统,并对其技术进行了额外的改进。
尽管如此,当谈到自动驾驶汽车时,我们似乎不太可能看到关于公共安全和必要监管的讨论结束;相反,优步的不幸事故只是助长了正在进行的辩论。我们会看到 2019 年将带给我们什么;然而,我们可以确定的一件事是,未来 2-3 年可能会被证明是塑造无人驾驶汽车主题公众舆论的关键。
对于那些对自动驾驶汽车的历史和现状感到好奇的人,我们建议查看《连线》杂志的这篇关于自动驾驶汽车的深度指南。
麻省理工学院投资 10 亿美元新建人工智能学院
Photo: MIT Dome, by Christopher Harting
2018 年 10 月 15 日,麻省理工学院宣布成立一所新学院,以黑石联合创始人兼首席执行官斯蒂芬·a·施瓦茨曼计算学院命名,他捐赠了 3.5 亿美元的基础捐款。新学院将专注于应对人工智能崛起带来的全球机遇和挑战。
麻省理工学院已经在该领域享有很高的声誉(更不用说它在人工智能领域的努力可以追溯到 20 世纪 50 年代末该领域的最初阶段)。然而,很难高估这一最新发展的重要性——例如,施瓦茨曼的礼物将允许创建额外的 50 个致力于人工智能研究的教师职位,有效地将麻省理工学院专注于计算和人工智能的研究人员数量增加一倍。
对跨学科合作的强调,以及对相关政策和道德的研究,以确保负责任地实施人工智能,在这里也值得一提——虽然我们已经看到了过去几年中建立的许多专注于这些主题的智库和研究倡议,但很高兴看到麻省理工学院的承诺,因为在这个问题上还有很多工作要做。
人工智能应用:计算摄影
Image generated by Prisma app, from Business Insider
从最广泛的意义上来说,计算摄影是人工智能在过去几年里带来了或许是最引人注目的进步的领域,至少从消费者的角度来看是如此。尽管如此,尽管过去几年在这一领域取得了很多进展(例如谷歌照片在 2015 年学会了如何自动标记和分类照片,或者 iPhone 7 在 2016 年获得了自动模糊人像模式下拍摄的照片背景的功能),但在 2018 年,我们已经看到了许多令人印象深刻的技术壮举,它们正在成为大规模产品。
像谷歌像素的夜视模式,或者 iPhone XS 和 XS Max 上的 T2 智能 HDR 功能,仅仅是通过使用机器智能而成为可能的一些例子。也许更有趣的是,这些新功能现在已经清楚地展示了人工智能的能力,使改进超越了摄像机的物理限制,从而使整个领域走上了一条新的令人兴奋的道路。因此,今天的计算摄影已经向那些熟悉人工智能领域其他进展的人和远离该领域的用户证明了它的价值。
计算摄影应用的另一个方面是当神经网络被用于使用算法完全重新制作图像,以调整输出,使其看起来像著名艺术家的作品,如梵高或莫奈(例如,参见 Prisma 应用)。类似的概念也用于机器视觉和福利的各个领域,例如无人驾驶汽车。
我们将在 Evolution One 的下一篇名为“机器智能的关键近期发展”的文章中涵盖更多具体技术,如大规模 GANs 和视频到视频合成,这些技术最近取得了重大进展,这是对当今一些最热门的人工智能领域的深入探讨,如自然语言处理和计算机视觉。
额外阅读:
一些不错的 AI 相关总结:
最初发表于evolution one . ai。
重新聚焦:使失焦的显微图像重新聚焦
Image source: https://www.thebisforboss.com/blog/2017/10/16/the-power-of-refocusing-resetting
显微图像广泛用于诊断各种疾病,例如感染和癌症。此外,它们促进了基础生物医学研究,这些研究不断产生对人类疾病原因的新见解。因此,显微图像对改善我们的健康非常重要。然而,获得高质量的聚焦显微镜图像是显微镜领域最大的挑战之一。例如,某些组织(如肺和肠)是不均匀的,会导致图像失焦。在这篇文章中,我们将通过使用深度学习来重新聚焦失焦的显微镜图像来解决这个问题。换句话说,我们将使用深度学习将失焦的显微镜图像变成对焦的图像(见下图)。
Left: out of focus. Right: in focus (Image source: https://data.broadinstitute.org/bbbc/BBBC006/)
数据
我们将使用Broad bio image Benchmark Collection 006(bbbc 006)图像集,该图像集是从一个 384 孔微孔板中获取的,该微孔板包含细胞核被 Hoechst 染色剂标记的人类细胞。为 768 个视场(384 个孔,每个孔 2 个视场)中的每一个拍摄 32 个图像的 z 叠置体(最佳焦平面处 z = 16,焦平面上方 15 个图像,下方 16 个图像)。
方法
总体策略是建立一个卷积神经网络,将离焦图像作为输入,生成聚焦图像作为输出。我们将把我们的神经网络建立在 U-net 架构上。此外,我们将使用特征损失(最初由 Johnson 等人称为感知损失)作为损失函数,以量化神经网络的输出与其在 z = 16 处的相应最佳焦平面图像或目标之间的差异。
优信网
U-net 最初是 Ronneberge 等人针对生物医学图像分割问题开发的。U-net 本质上由三个组件组成:减小图像尺寸的下采样路径、增大图像尺寸的后续上采样路径、以及将激活从下采样路径的所选部分转移到上采样路径中的相应部分的交叉连接。交叉连接用来自下采样路径的信息补充上采样路径,并且是使 U-net 表现如此好的主要发明。我们将使用在 ImageNet 上预训练的 ResNet -34 作为下采样路径,它利用了被称为迁移学习的技术。
U-net-based architecture (adapted from https://arxiv.org/pdf/1505.04597.pdf)
特征损失
特征损失有助于重建图像中的精细细节,非常适合于风格转移和超分辨率成像应用。如下图所示,特征损失的基本思想是将输出和目标放入同一个 ImageNet 模型中(在我们的例子中是 VGG -16),然后在选定的中间层而不是最终层比较它们的激活。
Feature Loss (adapted from https://arxiv.org/pdf/1603.08155.pdf)
使用 fastai 实现
我们的基于 U-net 的神经网络的实现只是使用如下所示的 fastai 库的一行代码。我们只需要提供数据、下采样架构(ResNet-34)、损失函数(特征损失)和一些附加参数。
U-net-based model in fastai
我们将使用杰瑞米·霍华德的特征损失的实现,如下所示:
Feature loss implementation by Jeremy Howard
培训和测试
我们将使用 z = 16 作为基本事实(y ),用在 z = 1(最差)、5(中间)和 10(接近焦点)的焦平面上方的失焦图像来训练我们的神经网络。我们将留出这些图像的一小部分作为验证集,并使用它们来指导和评估训练过程。训练后,我们将进一步评估模型在 z = 32 的焦平面下方的失焦图像上的性能。虽然两者都没有对焦,但焦平面上方或下方的图像看起来不同,因为它们到镜头的距离不同。因此,我们的策略将允许我们测试训练模型的可推广性。
结果
我们首先评估我们的模型在不同失焦水平的验证集上的性能。如下所示,该模型在区分模糊细胞方面做得很好,如果我们像预期的那样使用较少模糊的图像,性能会得到提高。
Model performance on the validation sets
接下来,我们在 z = 32 的测试集上检查了模型的性能。如下所示,模型生成的图像非常类似于 z = 16 时的最佳焦平面图像。因此,我们用焦平面上方的图像训练的模型在焦平面下方的图像上也表现良好。
Model performance on the test set at z = 32
总结和未来方向
总之,我们成功地建立了一个神经网络,可以重新聚焦模糊的失焦显微图像。这项工作提高了显微图像的质量,并将促进人类疾病的研究。由于计算能力有限,我只能处理非常小的图像(128*128)。理想情况下,神经网络应该能够处理整个幻灯片图像,可能是通过将它们分成小块。此外,神经网络应该能够处理具有不同染色的不同种类的显微图像。最后,我们可以将神经网络集成到采集平台中,以实时重新聚焦失焦图像,并消除采集后固定的需要。
感谢
我要感谢拉荷亚免疫学研究所(LJI)影像中心的 Paola Marcovecchio、Sara McArdle 和 Zbigniew Mikulski 博士的有益讨论。
利息集中区域
使物体检测更快更可行的技术。
从图像分类到目标检测的主要障碍是对网络的固定大小输入要求,因为存在完全连接的层。在对象检测中,每个提议将具有不同的形状。因此,需要将所有建议转换为完全连接的层所需的固定形状。投资回报池就是这样做的。
感兴趣区域(ROI)池用于将单一特征图用于 RPN 一次生成的所有提案。ROI pooling 解决了目标检测网络对图像大小要求固定的问题。
The entire image feeds a CNN model to detect RoI on the feature maps. Each region is separated using a RoI pooling layer and it feeds fully-connected layers. This vector is used by a softmax classifier to detect the object and by a linear regressor to modify the coordinates of the bounding box. Source: J. Xu’s Blog
ROI 合并通过对输入进行最大化合并,从非均匀输入中产生固定大小的特征图。输出通道的数量等于该层的输入通道的数量。ROI 池层接受两个输入:
- 从卷积神经网络经过多次卷积和汇集层后获得的特征图。
- n '来自区域提案网络的提案或感兴趣的区域。每个建议有五个值,第一个值表示索引,其余四个值是建议坐标。一般代表提案的左上角和右下角。
ROI pooling 从输入中提取每个 ROI,并提取对应于该 ROI 的输入特征图的一部分,并将该特征图部分转换为固定维度的图。每个 ROI 的 ROI 池的输出固定维度既不取决于输入特征图,也不取决于建议大小,它仅取决于层参数。
**Layer Parameters: pooled_width, pooled_height, spatial scale.**
Pooled_width 和 pooled_height 是超参数,可以根据手头的问题来决定。这些指示对应于建议的特征地图应划分成的格网数量。这将是该层的输出尺寸。让我们假设 W,H 是建议的宽度和高度,P_w,P_h 是宽度和高度的总和。然后,ROI 将被分成 P_w*P_h 个块,每个块的维数为(W/P_w,H/P_h)。
**bin_size_h = roi_height/pooled_height;
bin_size_w = roi_width/pooled_width;**
空间比例是用于根据特征地图尺寸调整提议大小的比例参数。假设在我们的网络中,图像大小为 1056x640,由于许多卷积和池化操作,特征图大小缩小到 66x40,由 ROI 池使用。现在,建议是基于输入图像大小生成的,因此我们需要将建议重新调整为要素地图大小。在这种情况下,我们可以将提案的所有维度除以 16 (1056/66=16 或 640/40=16)。因此,在我们的示例中,空间比例为 1/16。
**int roi_start_w = round(bottom_rois[1] * spatial_scale_);
int roi_start_h = round(bottom_rois[2] * spatial_scale_);
int roi_end_w = round(bottom_rois[3] * spatial_scale_);
int roi_end_h = round(bottom_rois[4] * spatial_scale_);**
现在我们对每个参数都有了清楚的了解,让我们看看 ROI pooling 是如何工作的。对于输入建议中的每个建议,我们取相应的特征地图部分,并将该部分分成由层参数定义的 WH 块。之后,取每个块的最大元素并复制到输出中。因此,对于每个 ROI 提议,输出大小为 P_wP_h,对于所有 N 个提议,输出大小为 NP_wP_h,这是一个固定维度的特征图,与输入提议的各种大小无关。
**Scaled_Proposals = Proposals * spatial_scale
for every ROI in Scaled_Proposals:
fmap_subset = feature_map[ROI] (Feature_map for that ROI)
Divide fmap_subset into P_wxP_h blocks (ex: 6*6 blocks)
Take the maximum element of each block and copy to output block**
下图说明了投资回报池层的向前传递。
credits: https://deepsense.ai/region-of-interest-pooling-explained/
ROI 汇集的主要优势在于,我们可以对所有提案使用相同的特征图,这使我们能够将整个图像传递给 CNN,而不是单独传递所有提案。
希望这有所帮助!谢谢大家!
参考文献:
- 吉斯克,罗斯。"快速 r-cnn "IEEE 计算机视觉国际会议论文集。2015.
- 《精确物体检测和语义分割的丰富特征层次》IEEE 计算机视觉和模式识别会议录。2014.
订阅 FOCUS——我的每周简讯,获取人工智能的最新更新和最新进展,以及来自机器学习媒体的精选故事。
区域提案网络—详细视图
什么是主播?RPN 如何从特征地图中学习生成盒子?它如何覆盖所有形状的盒子?
如果您知道用于对象检测的 R-CNN 家族,您可能听说过术语“RPN”,这是一个区域提议网络。如果你不知道 R-CNN 系列探测器,我建议你在深入研究 RPN 之前先浏览一下这篇文章。
我们都有一个模糊的想法,区域建议网络是用来产生建议的对象检测在更快的 rcnn。我们还听说,它通过从基础网络(VGG16、ResNet 等)获得的特征图进行学习来做到这一点。,).许多人都有这种模糊的想法,但很少有人彻底了解它是如何工作的。我以前有很多疑惑。RPN 如何从特征地图中学习生成盒子?它是如何用不同空间层次的特征图生成图像层次的盒子的?什么是主播?它如何覆盖所有形状的盒子?我的物件不会有遗失的盒子吗?它的召回率有多少?我的盒子很小怎么办?这是我曾经有过的一些疑问。浏览论文和许多博客已经澄清了一些疑问,然后我想通过代码实现来获得一个更清晰的想法,这很有帮助!让我们开始吧。
目标检测方法:我们生成候选框(可能有我们要检测的目标)并将这些框分类为像猫/狗/人等目标之一..那就是分类。同时,这些框形状调整学习正确地适合实际对象。这就是包围盒回归。
现在,第一步,即候选框的生成,是由 RPN 完成的。在早期版本的对象检测器中,这种提议生成是通过传统的计算机视觉技术离线进行的。一种这样的方法是选择性搜索。这些方法的缺点是计算成本和离线计算。
RPN 在很短的时间内就解决了这个问题,而且它可以合并到任何对象检测网络中,这使得它对于端到端的训练非常有用。就像我们的 CNN 如何从特征图中学习分类一样,它也从特征图中学习建议。让我记下 RPN 中的步骤:
- 生成锚定框。
- 对每个锚定框进行分类,无论它是前景还是背景。
- 了解锚定框的形状偏移,以使它们适合对象。
锚点:骨干网生成的特征图中的每一个点都是锚点。我们需要为每个锚点生成锚点框。我们使用两个参数生成候选框——比例和纵横比。方框需要在图像尺寸,而特征图根据主干缩小。例如,在 vgg16 的情况下,到主干的末端,图像被缩小 16 倍。那么我们如何在图像维度上生成盒子呢?我们使用这个 16 作为在图像级生成锚定框的步距。(例如:如果锚点比例为[8,16,32],比率为[0.5,1,2],跨距为 16,那么我们使用这些比例和比率的组合为每个锚点生成 9 个锚点框,然后在图像上跨距为 16,以获取下一个锚点框。)
Anchor boxes generation (Source)
These correspond to anchor points at image level. 16 and 8 are strides used depending on backbone. (Source)
现在我们已经生成了锚盒,但是这些是不同于实际感兴趣对象的虚拟盒。此外,可能有许多盒子里面没有任何对象。因此,我们需要了解给定的框是前景还是背景,同时我们需要了解前景框的偏移,以调整适应对象。这两个任务是通过从主干网获得的特征图上的两个卷积层来实现的。这些层是 rpn_cls_score 和 rpn_bbox_pred,架构如下所示。
For 9 anchors at every anchor point, 2 scores (fg and bg) and 4 offsets for coordinates. (Image by Author)
我们学习 x,y,w,h 值的偏移量,其中(x,y)是盒子的中心,w 和 h 是宽度和高度。我们知道这些补偿是回归。为了学习这些分数和偏移量,我们需要有目标。这些目标是通过将锚盒与地面真实盒进行比较而生成的。这个过程就是锚定目标生成。在锚目标生成中,我们使用锚框计算 GT 框的 IOU 以检查它是否是 fg/bg,然后计算坐标中的差作为回归器要学习的目标。然后这些目标被用作交叉熵损失和平滑 l1 损失的输入。
一旦使用卷积层学习了这些 fg/bg 分数和偏移,就根据置信度分数来考虑 fg 和 bg 框的一些部分。将偏移应用于这些框,以获得要进一步处理的实际 ROI。这种使用偏移的锚盒的后处理被称为建议生成。这些最终提案通过 ROI 池层和 fc 层向前传播。可以参考我之前的帖子了解一下 ROI pooling 和 NMS(非最大压制)。
这就是这篇文章的全部内容,希望你能很好地理解盒子是如何从 RPN 生成的。可以参考这个代码库来理解代码。让我们稍后在另一篇文章中见面吧。
参考
- https://www.mdpi.com/2072-4292/11/3/286
- https://www . research gate . net/publication/325385109 _ Yield _ Estimation _ using _ faster _ R-CNN
- https://arxiv.org/abs/1506.01497
回归:回归度量的解释和可能出错的地方
对 R 为什么为负感到困惑?阅读以下内容,了解更多信息。
(source)
机器学习正在不断发展,据说会影响所有领域,并给人类的运作方式带来根本性的变化。一些进步已经开始对社会产生影响,如欺诈检测系统、在线贷款审批系统、无人驾驶汽车、肿瘤检测等。机器学习算法已经成为我们日常生活的一部分,从早上的新闻推荐到晚上网飞的优化电影推荐,我们使用的一切都直接或间接受到或即将受到机器学习的影响。
机器学习基本上有两种类型,即监督学习和非监督学习。监督学习可以简单地理解为在老师的帮助下学习。这意味着我们有数据点以及每个数据点的标签。另一方面,无监督学习可以被认为是没有老师的学习。在这种情况下,我们只得到没有任何标签的原始数据,算法应该找到数据中的模式,并相应地对其进行分组。机器学习的大部分进展是在有监督的学习世界中实现的,而无监督的世界仍然是神秘的,没有被完全探索。
监督机器学习可以执行两个任务,即分类和回归。在非常高级的术语中,分类是将标签分配给属于不同类别的数据样本的任务,例如,对于训练,区分猫和狗的神经网络是一个分类问题,其中猫和狗是两个类别。
另一方面,回归是通过从各种独立特征中学习来预测连续值的任务。例如,基于像卧室数量、位置等特征来预测房子的价格。
基本分类或回归管道的工作方式如下:
- 我们从模型的一些初始配置开始,并基于一些输入来预测输出。
- 然后将预测值与目标值进行比较,并测量我们的模型性能。
- 然后,迭代地调整模型的各种参数,以便达到性能度量的最佳值。
对于不同的任务,恒定性能标准是不同的,并且努力达到标准的最佳值。在分类任务的情况下,性能标准可能是准确的,这意味着关于我们的模型看到的总案例,有多少案例被我们的模型正确分类。其他性能度量包括灵敏度(召回率)、特异性、精确度、f1 分数、AUC、均方误差、平均绝对误差、R、调整 R 等,并且根据任务和用于该任务的数据来使用。
在本文中,我们将讨论回归任务中使用的度量标准,以及 R 变为负值的原因。
回归任务是在其他相关独立变量的帮助下,预测某一特定时间点的结果变量的状态。与分类任务不同,回归任务输出给定范围内的连续值。
用于评估预测结果的各种指标包括:
- 均方误差
- 均方根误差(RMSE)。
- 平均绝对误差。
- r 或决定系数。
- 调整后 R
均方误差: MSE 或均方误差是回归任务最首选的指标之一。它只是目标值和回归模型预测值之间的平方差的平均值。当它计算差异的平方时,它惩罚了一个很小的错误,这个错误会导致高估模型的糟糕程度。它比其他指标更受青睐,因为它是可微分的,因此可以更好地优化。
Figure 1. Mean Squared Error Formula
均方根误差: RMSE 是回归任务中使用最广泛的指标,是目标值和模型预测值之间的平均平方差的平方根。在某些情况下,这种方法更为可取,因为在求平均值之前,首先对误差进行平方,这对于较大的误差来说是一种很高的惩罚。这意味着当不希望出现大误差时,RMSE 是有用的。
Figure 2. The formula of Root Mean Squared Error
平均绝对误差: MAE 是目标值与模型预测值的绝对差值。MAE 对异常值更稳健,并且不会像 mse 那样极端地惩罚误差。MAE 是一个线性分数,这意味着所有个体差异的权重相等。它不适合您希望更多关注异常值的应用程序。
Figure 3. The Formula of Mean Absolute Error
R 误差:决定系数或 R 是用于评估回归模型性能的另一个度量。该指标帮助我们将当前模型与恒定基线进行比较,并告诉我们我们的模型有多好。通过取数据的平均值并在平均值处画一条线来选择恒定基线。R 是一个无标度分数,这意味着值太大或太小都没有关系,R 将始终小于或等于 1。
Figure 4. The Formula for R²
调整后的 R : 调整后的 R 描绘了与 R 相同的含义,但却是它的改进。r 遇到的问题是,即使模型没有改进,分数也会随着术语的增加而提高,这可能会误导研究者。调整后的 R 总是低于 R,因为它对增加的预测因子进行了调整,并且只有在有真正的改善时才显示出改善
Figure 5. The Formula of Adjusted R²
R 为什么是负数?
在给你简单概述了各种回归度量之后,让我们最后来谈谈为什么 R 是负的。
人们有一种误解,认为 R 值的范围是从 0 到 1,但实际上,它的范围是从-∞到 1。由于这种误解,他们有时会害怕为什么 R 是负的,这在他们看来是不可能的。
R 为负的主要原因如下:
- R 为负的一个主要原因是所选择的模型没有遵循数据的趋势,导致 R 为负。这导致所选模型(分子)的 mse 大于恒定基线(分母)的 mse,从而导致负 R。
Figure 6.
2.也许数据中存在大量异常值,导致模型的 mse 大于基线的 mse,从而导致 R 为负(即分子大于分母)。
3.有时,在编写回归算法时,研究人员可能会忘记将截距添加到回归变量中,这也将导致 R 为负。这是因为,在没有截距的情况下,回归在跟踪因变量方面可能比样本均值(基线)更差(即分子可能大于分母)。然而,大多数标准的机器学习库,如 scikit-learn,默认情况下都包含截距,但如果您使用 stats-model 库,则必须手动添加截距。
个人经历:
最近,我在研究一个回归问题,我的模型是根据一个数据训练的,这个数据的因变量范围在 17-35 之间,但是这个范围在中间是不相交的。为了澄清,数据的值从 17-22,然后是一个断点,然后又从 29-33。如果我绘制数据,它会是下图所示的样子。
该模型在验证集上的 r2 _ 得分为 0.95。在模型被训练之后,我被要求在 17–22 和 29–33 之间的数据子集上测试模型的性能。该模型在每个子集上的表现都有一个负的 r2_score,我非常困惑,不知道自己哪里出错了。我在组合数据集上检查了模型的性能,它类似于验证集的性能,但是当我将测试数据分成子集并进行测试时,看到了负的 r2_score。然后在思考了很久,手工实现 r2_score 函数,并在计算的每个阶段打印输出之后,我才意识到问题的所在。
因此,让我们考虑一下 17–22 的情况,并找出 r2_score 为负的原因。如上所述,r2_score 表明了与均值估计量相比的模型的性能,即,采用因变量的均值并对所有条目进行预测的模型。在正常情况下,均值估计是一个糟糕的模型,是失败的。但是当我们把数据分成更小的子集时,均值估计实际上是一个很好的估计。例如,如果我们认为因变量的平均值是 17–22 子集的 19。现在,如果我们考虑我们的模型是根据整个范围的数据训练的,而不仅仅是 17-22,那么平均误差为 1,如果我们考虑 17-33 的整个范围,这是非常好的,但是如果我们将数据分成 17-22 的子集,平均误差为 1 可能比均值估计值更差,从而导致负 r2_score。当数据是 19–33 子集的一个子集时,也会观察到类似的情况。
结论:
在这篇文章中,我们发现了回归分析中使用的各种指标,并试图回答这个问题为什么 R 是负的?
我希望你喜欢这篇文章,并且学到了新的东西。如果您有任何疑问或想讨论,请随时通过 Linkedin 、 Twitter 或下面的回复部分联系我。
激励人心的名言:
"尽可能以最散漫、最不敬和最原始的方式努力学习你最感兴趣的东西."理查德·费曼
延伸阅读:
分析构建模块:预测
一款模块化笔记本电脑,可在控制面板中使用最少的编码来调整和比较 11 种预测算法
本文总结并解释了我的回归模块的关键模块(我正在开发的用于执行常见分析任务的简单模块化笔记本之一)。该笔记本旨在帮助对回归模型和 Python 编程有一定了解的用户更快地进行实验。GitHub 到笔记本的链接在文章底部!
介绍
在从事我最喜欢的一个项目时,我意识到有时测试不同的模型形式以确定最合适的模型更好,这种模型根据手头的问题提供了准确性、复杂性和执行效率的良好平衡。RapidMiner 等一些软件提供此功能。然而,出于这个目的使用软件产品会导致在调整模型和探索一些复杂性方面的黑盒方法。因此,我决定创建一个简单的 python 脚本,它具有足够的模块化和参数化,能够测试和调整许多广泛使用的预测算法,只需对代码进行最小的更改。
本笔记本摘要如下:
目标:
在 Python 中以最少的人工干预测试、调整和比较各种回归模型。
本模块包含的车型有:
*线性回归
*岭回归
*拉索回归
- K 近邻
*贝叶斯岭
*决策树回归
*随机森林
*装袋(默认使用决策树)
*梯度提升 - XGBoost
*支持向量机
用户熟练程度:
用户应该对每种算法的工作原理有一个直观的了解,并且很好地理解改变一个特定的超参数会如何影响结果。需要对 python 有基本的了解,以便能够有效地利用代码,并根据需求进一步定制代码。
关键可修改输入:
以下是关键输入(行内注释中为每个输入提供了更多详细信息)。这些部分在代码中以注释'突出显示,在此处进行修改':
*用于回归分析的输入数据集:在本例中,我使用了来自 pandas 默认数据集的“糖尿病”数据集
*测试数据比例:在 0 到 1 之间,默认为 0.3(或 30%)
*归一化:0 —无归一化,1 —最小-最大缩放, 2 — Z-score scaling
*要测试的模型对象列表
*网格搜索的折叠数(超参数调整)
*确定最佳模型的评分标准(例如均方误差)—代码注释中提供了更多详细信息
- Flag 用于查看模型拟合期间终端上的详细程度:0 —无输出,1 —所有详细信息,2 —进度条
*超参数库:代码中的全局字典,为要调整的每个模型表单提供一组超参数
一般执行步骤:
获取这些输入后,对考虑中的每个模型形式的执行以下操作:
*正向特征选择
*标准化
*网格搜索超参数调整
*最佳模型的度量计算
输出:
创建 pandas 数据框架“结果”,为您测试的每个模型提供以下指标
*具有最佳超参数的模型细节
*训练和测试均方根误差
*训练和测试平均绝对百分比误差
该表有助于在各种模型形式之间进行比较,而训练和测试度量可以是发现过度拟合的良好指标。
重要提示:
该模块不以任何方式处理特征工程,仅基于输入数据执行特征选择。为了改善任何模型的结果,执行有效的特征工程是非常重要的。用户可能会观察到一种模型形式比另一种给出更好的结果,但是任何模型的整体性能都可以随着预测变量的改进而显著提高。
剧本:
各种任务的模块
第一个函数根据用户在控制面板中指定的条件,为标准化和网格搜索创建管道。
def create_pipeline(norm, model):
if norm == 1:
scale = StandardScaler()
pipe = Pipeline([('norm', scale), ('reg', model)])
elif norm == 2:
scale = MinMaxScaler()
pipe = Pipeline([('norm', scale), ('reg', model)])
else:
pipe = Pipeline([('reg', model)])
return pipe
第二个函数执行正向特征选择,并返回最佳特征的索引。
def select_features(model, X_train, Y_train, selection,
score_criteria, see_details, norm=0):
pipe = create_pipeline(norm, model)
sfs = SequentialFeatureSelector(pipe,
forward=selection,
k_features='best',
scoring=score_criteria,
verbose=see_details)
sfs = sfs.fit(X_train, Y_train)
return list(sfs.k_feature_idx_)
此函数对提供的参数网格执行网格搜索,并返回最佳模型对象。
def run_model(model, param_grid, X_train, Y_train,
X, Y, score_criteria, folds,
see_details, norm=0):
pipe = create_pipeline(norm, model)
model_grid = GridSearchCV(pipe,
param_grid,
cv=folds,
scoring=score_criteria,
verbose=see_details)
model_grid.fit(X_train, Y_train)return model_grid.best_estimator_
最后一个函数计算最佳超参数组合的所有相关指标,并返回这些指标的 pandas 系列。
def get_model_eval(model, X_train, Y_train, X_test, Y_test):
return pd.Series([model, mean_squared_error(Y_train, model.predict(X_train)),
mean_squared_error(Y_test, model.predict(X_test)),
(abs(model.predict(X_train) - Y_train) / Y_train).mean(),
(abs(model.predict(X_test) - Y_test) / Y_test).mean()])
全局超参数字典(在此修改)
这是该模块中所有模型的各种模型参数的全局字典。基于糖尿病数据集的典型范围的代码中已经填充了一些缺省值集。该词典包含每个模型的一些关键超参数,但并不详尽。鼓励用户访问 scikit-learn 文档以获得所有参数的列表,并根据他们的要求添加到下面的字典中。
PARAM_DICT = {
LinearRegression: {'reg__copy_X': [True, False],
'reg__fit_intercept': [True, False],
'reg__n_jobs': [10, 20]},
Ridge: {'reg__alpha': [0.1, 1, 100],
'reg__copy_X': [True, False],
'reg__fit_intercept': [True, False],
'reg__tol': [0.1, 1],
'reg__solver': ['auto', 'svd', 'cholesky', 'lsqr',
'sparse_cg', 'sag', 'saga']},
Lasso: {'reg__alpha': [0.1, 1, 100],
'reg__copy_X': [True, False],
'reg__fit_intercept': [True, False],
'reg__tol': [0.1, 1]},KNeighborsRegressor: {'reg__n_neighbors': [5, 30, 100]},
BayesianRidge: {'reg__alpha_1': [10**-6, 10**-3],
'reg__alpha_2': [10**-6, 10**-3],
'reg__copy_X': [True, False],
'reg__fit_intercept': [True, False],
'reg__lambda_1': [10**-6, 10**-3],
'reg__lambda_2': [10**-6, 10**-3],
'reg__n_iter': [300, 500, 1000],
'reg__tol': [0.001, 0.01, 0.1]},DecisionTreeRegressor: {'reg__max_depth': [5, 10, 20],
'reg__max_features': [0.3, 0.7, 1.0],
'reg__max_leaf_nodes': [10, 50, 100],
'reg__splitter': ['best', 'random']},BaggingRegressor: {
'reg__bootstrap': [True, False],
'reg__bootstrap_features': [True, False],
'reg__max_features': [0.3, 0.7, 1.0],
'reg__max_samples': [0.3, 0.7, 1.0],
'reg__n_estimators': [10, 50, 100]},
RandomForestRegressor: {'reg__bootstrap': [True, False],
'reg__max_depth': [5, 10, 20],
'reg__max_features': [0.3, 0.7, 1.0],
'reg__max_leaf_nodes': [10, 50, 100],
'reg__min_impurity_decrease': [0, 0.1, 0.2],
'reg__n_estimators': [10, 50, 100]},SVR: {'reg__C': [10**-3, 1, 1000],
'reg__kernel': ['linear', 'poly', 'rbf'],
'reg__shrinking': [True, False]},GradientBoostingRegressor: {'reg__learning_rate': [0.1, 0.2, 0.5],
'reg__loss': ['ls', 'lad', 'huber', 'quantile'],
'reg__max_depth': [10, 20, 50],
'reg__max_features': [0.5, 0.8, 1.0],
'reg__max_leaf_nodes': [10, 50, 100],
'reg__min_impurity_decrease': [0, 0.1, 0.2],
'reg__min_samples_leaf': [5, 10, 20],
'reg__min_samples_split': [5, 10, 20],
'reg__n_estimators': [10, 50, 100]},
XGBRegressor: {'reg__booster': ['gbtree', 'gblinear', 'dart'],
'reg__learning_rate': [0.2, 0.5, 0.8],
'reg__max_depth': [5, 10, 20],
'reg__n_estimators': [10, 50, 100],
'reg__reg_alpha': [0.1, 1, 10],
'reg__reg_lambda': [0.1, 1, 10],
'reg__subsample': [0.3, 0.5, 0.8]},}
按键输入的用户控制面板(在此进行修改)
可以在此处更改模块的输入。这是这个脚本的控制面板,介绍中提到的所有变量都可以在这里修改,以测试各种场景。请参考评论了解变量。
# --------------------------------------------------------------------------
# USER CONTROL PANEL, CHANGE THE VARIABLES, MODEL FORMS ETC. HERE# Read data here, define X (features) and Y (Target variable)
data = datasets.load_diabetes()
X = pd.DataFrame(data['data'])
X.columns = data['feature_names']
Y = data['target']# Specify size of test data (%)
size = 0.3# Set random seed for sampling consistency
random.seed(100)# Set type of normalization you want to perform
# 0 - No Normalization, 1 - Min-max scaling, 2 - Zscore scaling
norm = 0# Mention all model forms you want to run - Model Objects
to_run = [LinearRegression,
Ridge,
Lasso,
KNeighborsRegressor,
DecisionTreeRegressor,
BaggingRegressor,
SVR,
XGBRegressor]# Specify number of crossvalidation folds
folds = 5# Specify model selection criteria
# Possible values are:
# ‘explained_variance’
# ‘neg_mean_absolute_error’
# ‘neg_mean_squared_error’
# ‘neg_mean_squared_log_error’
# ‘neg_median_absolute_error’
# ‘r2’
score_criteria = 'neg_mean_absolute_error'# Specify details of terminal output you'd like to see
# 0 - No output, 1 - All details, 2 - Progress bar
# Outputs might vary based on individual functions
see_details = 1# --------------------------------------------------------------------------
模型执行
该部分迭代地为用户指定的每个模型找到最佳的超参数集,计算度量并填充结果表,用于进一步的分析/实验。
# Model execution part, resuts will be stored in the dataframe 'results'
# Best model can be selected based on these criteriaresults = pd.DataFrame(columns=['ModelForm', 'TrainRMSE', 'TestRMSE',
'TrainMAPE', 'TestMAPE'])X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=size)for model in to_run:
with warnings.catch_warnings():
warnings.simplefilter('ignore')
best_feat = select_features(model(), X_train, Y_train, True,
score_criteria, see_details, norm)
model = run_model(model(), PARAM_DICT[model],
X_train.iloc[:, best_feat],
Y_train,
X.iloc[:, best_feat], Y,
score_criteria, folds, see_details, norm)
stats = get_model_eval(model, X_train.iloc[:, best_feat], Y_train,
X_test.iloc[:, best_feat], Y_test)
stats.index = results.columns
results = results.append(stats, ignore_index=True)print(results)
结论
Results data frame
从结果表中可以看出,在该场景中测试的所有模型形式中,最基本的线性回归模型提供了最佳且一致的性能。这也强调了特征工程的重要性,因为我们期望集合模型总体上表现出更好的性能。另一方面,基于训练和测试指标,XGB 回归器显示出过度拟合的迹象。所有其他型号都提供类似的性能。这表明还需要测试不同范围的超参数。我希望这个模块能够加快实验速度,并提供一个机会,根据您的需求在它的基础上进行进一步的定制!
点击此处查看完整的笔记本:
在 GitHub 上创建一个帐户,为 himan Shu 0394/AnalyticsBuildingBlocks 开发做贡献。
github.com](https://github.com/himanshu0394/AnalyticsBuildingBlocks/blob/master/Prediction Block.ipynb)
请随时提供任何建议和反馈!
回归——用简单的术语解释!!
在这篇文章中,我希望用尽可能简单的术语来阐述回归,这样你就不会把它当成一个统计概念,而是一个更相关的经验。
回归——听起来很奇怪,但可以认为是任何两个事物之间的“关系”。例如,想象你呆在地面上,温度是华氏 70 度。你开始爬山,当你爬的时候,你意识到你感觉更冷,温度在下降。当你到达海拔 500 米的山顶时,你测量的温度是华氏 60 度。我们可以得出结论,海拔高度影响温度。因此,高度和温度之间是有关系的。这在统计学上被称为“回归”。温度取决于高度,因此是“因变量”,而高度是“自变量”。可能有各种因素影响温度,如湿度、压力,甚至空气污染水平等。所有这些因素都与温度有关,可以用数学方法写成一个方程。
回归的形式定义
任何方程,即因变量和一组权重的函数,称为回归函数。
y ~ f(x;w)其中“y”是因变量(在上述示例中为温度),“x”是自变量(湿度、压力等),“w”是方程的权重(x 项的系数)。
例如,等式可以是
y = 0.5 x1 + 2.15 x2 + 0.76 x3
其中 0.5、2.15 和 0.76 是等式的权重。这些权重将通过研究因变量和自变量之间的关系来学习。
回归方程怎么确定?
现在的问题是要弄清楚如何学习方程的权重。我们为什么要这么做?是的,我们这样做是为了预测未来。一旦我们知道了因变量和自变量之间的关系,我们就可以预先预测因变量。为了学习回归方程,我们需要从现场收集一些真实数据。我们人类从真实世界的经历中学习。类似地,回归函数只能通过初始真实数据(称为“训练”数据)来学习。
在所考虑的例子中,我们需要记录不同高度的温度、气压水平、湿度以及所有我们知道的影响因变量的因素。下面是一个数据集示例。
Example data for regression
和上表一样,我们需要收集尽可能多的真实数据。让我将“温度”表示为“y”,其余的特征(高度、压力、湿度)表示为“x”。我们将误差函数定义为(y-x*w)的和。即每个数据点的误差平方和。我们需要找出使上述函数最小化的“w”向量(逻辑上,不引起错误)。什么时候函数是数学上的最小值?这是方程斜率为 0 的地方。因此,我们可以通过将下面函数的斜率等于 0 来找到“w”向量,并求解“w”。
The objective function equation
“w” vector upon solving the equation
这篇文章并不打算在数学上做太多,然而,权重向量是由上面的等式得到的。使用我们收集的所有数据,我们通过上面的等式得到“w”向量。
我希望这篇文章对你有帮助。如果您有任何疑问,请在下面留下。
回归还是分类?线性还是逻辑?
理解不同之处和各自的不同模型
回归与分类
为了决定是使用回归模型还是分类模型,您应该问自己的第一个问题是:
你的目标变量是一个数量,一个二元范畴的概率,还是一个标签?
如果是前一种选择,那么你应该使用一个回归模型。这意味着,如果您试图预测身高、收入、价格或分数等数量,您应该使用将输出连续数字的模型。或者,如果目标是观察值成为二进制标签的概率(例如是好的而不是坏的概率),那么你也应该选择一个回归模型,只是你用的模型会略有不同。这些模型通过均方误差(MSE 或变异)和均方根误差(RMSE 或标准偏差)进行评估,以量化模型中的误差量。
如果是后一种选择,您希望使用一个分类模型。这种方法对于预测观察的标签(例如差、一般、好)。棘手的部分是有时意识到目标是否是一个标签。例如,如果目标是一个顺序变量,比如从 1 到 5 的离散排名,那么这些就是标签,但它们仍然具有数学意义。这意味着数据的平均值和变化仍然是有洞察力的,但是为了预测,你最好使用分类。这些模型是通过 F 分数或模型的准确性而不是变异和标准差来评估的。该分数给出了对有多少观察结果被正确标记的理解,并且可以用混淆矩阵来可视化,该混淆矩阵将观察结果分成真阳性/阴性和假阴性/阳性。
在开始运行模型和形成预测之前,理解目标变量的特征是很重要的。如果您在应该使用分类的时候使用回归,您将得到连续的预测而不是离散的标注,从而导致较低(如果不是零)的 F 值,因为大多数(如果不是全部)预测将不是您想要预测的 1 或 0。如果你使用的是给你概率的逻辑模型,一个解决方法是创建一个截止点。例如,也许你决定大于 0.9 的都是 1,小于 0 的都是 0。这样做,你仍然可以找到一个 F 值,并看到混淆矩阵。然而,这个额外的步骤通常可以通过使用适当的模型来避免。
一旦确定了使用哪种方法,下一步就是选择用于生成预测的模型。
Regression vs Classification visual
回归模型
在回归模型中,最流行的两个是线性和逻辑模型。
一个基本的线性模型遵循著名的公式 y=mx+b,但通常格式略有不同:
y=β₀+β₁x₁+…+βᵢxᵢ
其中,β₀是 y 轴截距,即所有解释变量都设置为零时的 y 值。β₁到βᵢ是变量 x₁到 xᵢ的系数,假设所有其他变量保持不变,变量 y 增加或减少一个单位。例如,如果等式是 y=1+2x₁+3x₂,那么如果 x₁从 0 增加到 1,而 x₂保持在 0,y 将从 1 增加到 3。
一个逻辑模型遵循一个稍微改变的等式:
y= 1 / (1+e^-(β₀+β₁x₁+…+βᵢxᵢ))
这将它限制为 0 到 1 之间的值。因此,它主要用于二进制目标变量,其中可能的值为 0 或 1,或者目标是二进制变量的概率。如前所述,该方程可以防止概率低于 0 或高于 1 的预测不合逻辑。
您可以改变这两种标准模型,以便更好地适应您的数据。做到这一点的主要方法是包括惩罚。对于线性和逻辑模型,创建的方程将包括你输入的每一个变量的,这是一个使你的模型过度拟合的简单方法。过度拟合模型会降低模型在训练样本之外生成预测的有用性。为了避免这种情况,您可以执行一个特征选择过程来挑选出重要的特征,或者您可以在您的模型中包含惩罚。
Underfitting and Overfitting visual
添加 L2 惩罚将进行岭回归,这将缩小不重要变量的系数以限制它们的重要性,但仍将包括所有输入的变量。如果您希望包含每个变量,而不管它有多重要,这是很有用的,但是在大多数情况下,您希望模型尽可能简单。相反,添加 L1 惩罚将进行套索回归(最小绝对收缩和选择算子),这将做与岭相同的事情,但如果不重要,将收缩系数到零,有效地移除它们。LASSO 的缺点是,如果你的变量(k)比观测值(n)多,它最多只会包含 n 个变量。此外,套索斗争与相关变量,并会随机选择其中一个保留。要克服这些障碍,您可以使用弹性网回归,它结合了两种损失,可以更好地处理高维数据和多重共线性。这通常会给出一个与 LASSO 同样准确或更准确的模型,但这取决于选择作为弹性网超参数之一的 L1 比率。
最后,目标变量可能不是解释变量的严格线性函数。这里,我们有两个主要选项:高阶回归或随机森林回归。
比方说,在进行初始数据探索时,您发现在预测收入时,年龄与收入的关系更多的是二次关系,而不是线性关系。在这种情况下,您希望在一次线性方程中包含一个二阶变量。然后它将看起来像 y=β₀+β₁x+β₂x,你将再次运行该模型。您仍然可以在高阶模型上运行线性回归。一个常见的误解是,线性回归方法只能创建线性函数。线性回归中的“线性”是指系数之间的关系,而不是变量本身,因此,如果高阶或交互作用有助于更好地解释这种关系,则在模型中包括高阶或交互作用是有利的。然而,如果你包括一个高阶变量或交互作用,你必须在你的最终方程中保留低阶变量和主要效应变量,无论它们是否显著。你不能拥有 y=β₀+β₂x 或 y=β₀+β₁x₁*x₂.
我们也可以使用一个随机森林回归器,它在下面被可视化了,但是稍后将会解释它的替代物,随机森林分类器,这是更常用的。回归器的使用类似于逻辑模型,其输出是二进制标签的概率。简而言之,随机森林回归器创建了数百个决策树,所有决策树都预测一个结果,最终输出要么是最常见的预测,要么是平均值。
Random Forest Classifier for Titanic Survival
现在你可能会想,难道这些模型都不能用于概率目标吗?如果训练集的 y 值为 0 到 1,模型将只预测从 0 到 1 的 y 值,对吗?嗯,是也不是。模型最有可能总是预测 0 到 1 之间的值,但如果模型是线性的,则超过 0 或 1 的值在概率的情况下是不合逻辑的。你可以在你的模型构建中付出 110%的努力,但是一个观察不可能有某个类别 110%的可能性。此外,线性模型意味着接受诊断的概率分别为 0.10 和 0.15 的人与接受诊断的概率分别为 0.95 和 1.0 的人之间存在相同的差异。显然,如果一个人 100%患有疾病,那么很可能还有其他原因没有在线性模型中得到解释,因为对于低于 0.50 的概率来说,这是一个无关紧要的特征。
分类模型
如果您的分析的目标是创建一个模型来预测一个观察的标签,那么您想要使用一个分类模型。最简单的模型还是一个逻辑模型。然而,通过创建目标虚拟变量并在每个变量上运行单独的逻辑模型,可以在非二进制目标变量上训练逻辑模型。您还可以将 L1 和 L2 惩罚添加到此逻辑模型中,以便进行套索和山脊逻辑模型。
然而,更有用的是随机森林分类器,它像随机森林回归器一样,可以包括可能只在特定点有意义的特征。重申一下,这种方法采用了决策树的概念,创建了一个随机森林,随机选择要包含的变量,然后基于森林输出预测。在用于运行该模型的代码中,您可以指定许多超参数,例如生成的树的数量、每片叶子的最小观察数量、最大分裂、树的最大深度等。所有这些超参数都有助于创建更精确的模型,但随机森林仍然可能会过拟合。如果你的树太大了,它们很可能太具体而不能应用于测试集。
Random Forest Classifier visual
最后,可以创建一个神经网络来预测一个观察的标签。这是最复杂的方法,但相对于前面的方法有一定的优势。主要是,它有机会进行无监督学习。这意味着,该算法可以根据它检测到的相似性对组进行聚类,而无需事先标记训练数据。尽管创建起来很复杂,但它们可以更准确地预测标签,这对于高风险预测(如疾病诊断或欺诈检测)非常重要。本质上,该算法接受一组输入,在其中找到模式和趋势,并输出预测(监督)或聚类组(非监督)。随着更多的迭代和更大的训练集,神经网络可以变得非常准确,但要小心,通过在网络中创建太多的层,使其过度适应您的训练集。
摘要
在选择用于预测的模型时,要考虑的最重要的事情是目标变量的特征。是连续的还是离散的?是数量还是标签?是一个范畴的概率吗?与所有解释变量线性相关吗?我希望所有这些变量都包含在它的预测中吗?这些问题的答案可以引导你为你的预测选择最好的模型。
资源
回归均值——苦涩的事实
My attempt to illustrate regression to the mean
想象一下这个场景:你是一家连锁百货商店的商业分析师。所有的商店在规模和商品选择上都是相似的,但是由于位置、竞争和随机因素,它们的销售额是不同的。您将获得 2018 年的结果,并被要求预测 2019 年的销售额。你被指示接受经济学家的总体预测,即销售额将总体增长 10%。你将如何完成下列数据?
商店— 2018 年销售额— 2019 年销售额
1—100 万美元—
2—1000 万美元—
3—200 万美元—
4—1500 万美元—
5—2000 万美元—2200 万美元
如果你的分析是基于每个商店的销售额增加 10%,你很可能是错的,但是…为什么?继续读下去。
上面的例子改编自马克斯·巴泽曼的《管理决策中的判断》一文,出现在丹尼尔·卡内曼的《思考快慢》一书第 17 章的最后一页。在这一章中,卡尼曼清楚地解释了什么是回归均值。
回归到均值是什么?
回归均值,简单来说就是极值分数回归均值分数的自然趋势。
在上面的例子中,预测每家商店的销售额为 10%是一个判断错误,因为您的预测需要是回归的(即,将 10%以上的销售额加到低绩效的分店,将更少的销售额加到(甚至减去)高绩效的分店)。这是因为由于所有商店的规模和商品选择都相似,但它们的销售额因位置、竞争和随机因素而有所不同,那些在 2018 年表现非常好的商店很可能在 2019 年的销售额增长低于其他商店,而那些表现非常差的商店很可能在 2019 年的销售额增长高于其他商店。
理解回归均值
引用卡尼曼的例子,想象一群患有抑郁症的儿童已经接受了八周的能量饮料治疗。一旦他们完成治疗,临床结果显示他们的抑郁状态有显著改善。
看了上面的案例,我们大多数人都倾向于在脑子里做出(无意识地)下面这个等式:
能量饮料→抑郁的孩子=改善
现在想象同样的例子,但是这次不是能量饮料,那些抑郁的孩子被治疗了八周,每天倒立 20 分钟。我敢肯定这一次(自觉你没有在你的头上做如下等式:
20 '倒立→抑郁的孩子=改善
痛苦的事实是,抑郁的孩子是一个极端的群体,就像商店里极端的销售数字一样,他们会自然地倾向于回归到他们的平均情绪状态。无论他们是喝酒还是倒立,这种情况都很有可能发生。
这些回归效应无处不在。尤其是在体育运动中,非常普遍。例如在足球比赛中,当那些倾向于赢得大部分比赛的球队经历三场连胜时,媒体开始声称他们正面临一场重大危机。然而,在几场比赛后,他们很可能会回到他们的平均连胜纪录。
The sports headline by the daily newspaper The Telegraph on 26 December 2018
为什么我们没有意识到回归均值以及这样做的巨大风险
我们经常在识别均值回归时遇到困难,因为我们的思维强烈倾向于因果解释。我们人类渴望相信我们检测到的一切背后都有因果关系(或想要检测到 t),比如:
能量饮料→抑郁儿童=改善
令人痛苦的事实是,我们太愿意相信这些影响大部分是随机的结果。如果没有,问问自己是否会买一份标题如下的体育报纸:
尽管该队遭遇了三场连胜,但他们很可能会回到平均胜率,因为他们经历了不幸的比赛,这是一个随机的问题。
我们中的大多数人不会买上面的标题,因为我们不想阅读,也不相信我们团队失败的后果=纯粹的随机性。相反,我们会找到一个因果解释,比如教练不合适,球员在如此多的胜利后变得懒惰。
此外,这些影响的后果超出了个人意识范围,就组织而言,例如,如果一家公司决定实施一项培训计划,通过花费大量的工资来培训其员工,目的是提高其不寻常的年的客户满意度,并且实际结果显示客户满意度有了显著的提高,经理们可能倾向于相信:
培训计划→员工绩效=客户满意度提高
痛苦的事实是,如果在培训计划中不包括对照组(即接受培训的员工和未接受培训的员工),对良好结果的因果解释可能是一个严重的缺陷,是回归均值的一个似是而非的结果。
如何更加意识到回归均值
这里有一些提示,以防读完这篇文章后你问自己,我如何才能更好地意识到我每天发现的关于回归均值的效应的随机性?
- 相关性不是因果关系
尽管两个变量可能存在某种关系,但这并不意味着一个是另一个的原因。
例如…
能量饮料 → 感觉沮丧=感觉更好
培训主动性 → 参加培训的员工= KPI 的提高
幸运袜 → 考试=通过 - 原始得分越极端,你越应该期待回归
极差销售 → 较好改善预期
一般销售 → 正常改善预期 - 接受随机性听起来很容易,但并不容易,试着意识到生活充满了随机性、运气和偶然性。学会处理。
参考
卡尼曼博士,思考快与慢。麦克米伦(2011)。
在 KC 住房数据集上使用 sklearn 进行回归
动机
为了预测 King County 的房价,我选择了来自 Kaggle 的房价数据集。该数据集包含 King 县(包括西雅图)的房屋销售价格。它包括 2014 年 5 月至 2015 年 5 月期间出售的房屋。它有很多学习的特点,数据集可以从这里下载。
介绍
回归的总体思路是考察两件事:(1)一组预测变量在预测一个结果(因变量)时是否做得很好?(2)哪些变量是结果变量的重要预测因子,它们是如何影响结果变量的——由β估计值的大小和符号表示?这些回归估计用于解释一个因变量和一个或多个自变量之间的关系。
执行的回归
简单线性回归
- 卧室与价格
- “等级”与“价格”
多元回归
- 卧室','等级','居住面积','以上面积'
- '卧室','浴室',' sqft_living ',' sqft_lot ','楼层','海滨','景观','等级',' sqft_above ',' sqft _ baseball ',' lat ',' sqft_living15 '
多项式回归
- 度数=2
- 度数=3
描述
在该数据集中,显示了西雅图金县房屋的销售价格。它包括 2014 年 5 月至 2015 年 5 月期间出售的房屋。在做任何事情之前,我们应该首先了解数据集,它包含什么,它的特征是什么,以及数据的结构是什么。
通过观察数据,我们可以知道价格取决于各种功能,如卧室(最依赖的功能)、浴室、sqft_living(第二重要的功能)、sqft_lot、地板等。价格也取决于房子所在的位置。像滨水景观这样的其他特色对价格的依赖性较小。在所有记录中,没有缺失值,这有助于我们创建更好的模型。
数据预处理
导入所需的库。
*#importing numpy and pandas, seaborn*
import numpy as np *#linear algebra*
import pandas as pd *#datapreprocessing, CSV file I/O*
import seaborn as sns *#for plotting graphs*
import matplotlib.pyplot as plt
阅读 CSV 文件。
df = pd.read_csv("../input/housesalesprediction/kc_house_data.csv")
pandasdata frame . info()函数用于获取数据帧的简明摘要。在对数据进行探索性分析时,这非常方便。为了快速浏览数据集,我们使用了data frame . info()函数。
df.info()
Pandas head ()方法用于返回一个数据帧或系列的前 n(默认为 5)行。
df.head()
熊猫形状函数用于返回大小、形状以及数据帧和系列的尺寸。
*#finding no of rows and columns*
df.shape
调用 isnull()返回的 DataFrame 的 sum()将给出一个包含每列中 NaN 计数的数据的序列。
df.isnull().sum()
找出卧室的数量。
df['bedrooms'].value_counts()
寻找海滨的伯爵。
寻找分数。
df['grade'].value_counts()
寻找条件计数。
df['condition'].value_counts()
为卧室绘制了一个计数图。
sns.countplot(df.bedrooms,order=df['bedrooms'].value_counts().index)
sqft living 和价格之间绘制了一个柱状图,以了解价格随 sqft 的变化情况。
在上面的平方英尺和价格之间绘制一个柱状图,以观察价格如何随着上面的平方英尺而变化。
fig,axes=plt.subplots(nrows=1,ncols=1,figsize=(15,10))
plt.title("house prices by sqft_above")
plt.xlabel('sqft_above')
plt.ylabel('house prices')
plt.legend()
sns.barplot(x='sqft_above',y='price',data=df)
绘制了生活平方英尺的直方图。
plt.hist('sqft_living',data=df,bins=5)
为 sqft living 绘制了 distplot,以查看数据是否有偏差
fig,axes=plt.subplots(nrows=1,ncols=1,figsize=(15,10))
sns.distplot(df['sqft_living'],hist=True,kde=True,rug=False,label='sqft_living',norm_hist=True)
为上面的 sqft 绘制了 distplot,以查看数据是否有偏差
fig,axes=plt.subplots(nrows=1,ncols=1,figsize=(15,10))
sns.distplot(df['sqft_above'],hist=True,kde=True,rug=False,label='sqft_above',norm_hist=True)
寻找平方英尺生活的均值、众数和中位数。
print('Mean',round(df['sqft_living'].mean(),2))
print('Median',df['sqft_living'].median())
print('Mode',df['sqft_living'].mode()[0])
通过图表我们观察到 sqft living=1300 有更多的值。
len(df[df['sqft_living']==1300])
为了确保我们涵盖了所有的关系,我们使用热图绘制了所有特征之间的关联。
热图是数据的二维图形表示,矩阵中包含的各个值用颜色表示。
def correlation_heatmap(df1):
_,ax=plt.subplots(figsize=(15,10))
colormap=sns.diverging_palette(220,10,as_cmap=True)
sns.heatmap(df.corr(),annot=True,cmap=colormap)
correlation_heatmap(df)
既然我们已经获得了足够的数据信息,我们就开始线性回归。
简单线性回归
对于线性回归,我们使用来自 sklearn 函数的 linear_model。
Scikit-learn 通过 Python 中的一致接口提供了一系列监督和非监督学习算法。该库建立在 SciPy(科学 Python)之上,在使用 scikit-learn 之前必须安装该库。用于 SciPy care 的扩展或模块通常称为 SciKits 。因此,该模块提供了学习算法,并被命名为 scikit-learn。
我们导入train _ test _ split。这将数据分割成所需的比率(例如:80–20),其中一个比率用于训练数据,其余比率用于测试数据。训练数据以预测一条线,然后使用测试数据来查看这条线是否完全符合。
多项式特征 生成一个新的特征矩阵,由次数小于或等于指定次数的特征的所有多项式组合组成。
引入 度量 是因为度量模块实现了针对特定目的评估预测误差的功能。
在KNeighborsRegressor中,通过对训练集中最近邻相关的目标进行局部插值来预测目标。
from sklearn.model_selection import train_test_split
from sklearn import linear_model
from sklearn.neighbors import KNeighborsRegressor
from sklearn.preprocessing import PolynomialFeatures
from sklearn import metrics
from mpl_toolkits.mplot3d import Axes3D
%matplotlib inline
在这里,我们将数据分成 80:20 的比例,其中 train_size 为 80%,test_size 为 20%。 train_test_split 将数组或矩阵分割成随机训练和测试子集。这意味着每次在没有指定 random_state 的情况下运行它,都会得到不同的结果,这是意料之中的行为。为了得到相同的训练和测试子集,我们声明一个随机状态。这里的 x 是‘sqft _ living’,y 是‘price’。我们正在重塑 x_train 和 y_train,数据是拟合的。x 检验和 y 检验用于预测模型的准确性。这里我们首先计算 y_test 的均方误差。找出训练和测试的均方误差。找到直线的截距和系数。
train_data,test_data=train_test_split(df,train_size=0.8,random_state=3)
reg=linear_model.LinearRegression()
x_train=np.array(train_data['sqft_living']).reshape(-1,1)
y_train=np.array(train_data['price']).reshape(-1,1)
reg.fit(x_train,y_train)
x_test=np.array(test_data['sqft_living']).reshape(-1,1)
y_test=np.array(test_data['price']).reshape(-1,1)
pred=reg.predict(x_test)
print('linear model')
mean_squared_error=metrics.mean_squared_error(y_test,pred)
print('Sqaured mean error', round(np.sqrt(mean_squared_error),2))
print('R squared training',round(reg.score(x_train,y_train),3))
print('R sqaured testing',round(reg.score(x_test,y_test),3) )
print('intercept',reg.intercept_)
print('coefficient',reg.coef_)
R 平方检验:0.496
为 x_test,y_test 绘制了散点图。数据分布在图表上。现在绘制从上面获得的线,看看它如何适合数据。
_, ax = plt.subplots(figsize= (12, 10))
plt.scatter(x_test, y_test, color= 'darkgreen', label = 'data')
plt.plot(x_test, reg.predict(x_test), color='red', label= ' Predicted Regression line')
plt.xlabel('Living Space (sqft)')
plt.ylabel('price')
plt.legend()
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
这里我们以 80:20 的比例分割数据,其中 train_size 为 80%,test_size 为 20%。这里 x 是‘等级’,y 是‘价格’。我们正在重塑 x_train 和 y_train,数据是拟合的。x 检验和 y 检验用于预测模型的准确性。这里我们首先计算 y_test 的均方误差。找出训练和测试的均方误差。找到直线的截距和系数。
train_data,test_data=train_test_split(df,train_size=0.8,random_state=3)
reg=linear_model.LinearRegression()
x_train=np.array(train_data['grade']).reshape(-1,1)
y_train=np.array(train_data['price']).reshape(-1,1)
reg.fit(x_train,y_train)
x_test=np.array(test_data['grade']).reshape(-1,1)
y_test=np.array(test_data['price']).reshape(-1,1)
pred=reg.predict(x_test)
print('linear model')
mean_squared_error=metrics.mean_squared_error(y_test,pred)
print('squared mean error',round(np.sqrt(mean_squared_error),2))
print('R squared training',round(reg.score(x_train,y_train),3))
print('R squared testing',round(reg.score(x_test,y_test),3))
print('intercept',reg.intercept_)
print('coeeficient',reg.coef_)
R 平方检验:0.46
多元线性回归
箱线图是根据“价格”绘制的“等级”、“卧室”和“浴室”。
fig,ax=plt.subplots(2,1,figsize=(15,10))
sns.boxplot(x=train_data['grade'],y=train_data['price'],ax=ax[0])
sns.boxplot(x=train_data['bedrooms'],y=train_data['price'],ax=ax[1])
_ , axes = plt.subplots(1, 1, figsize=(15,10))
sns.boxplot(x=train_data['bathrooms'],y=train_data['price'])
我们正在考虑的功能是'卧室','品位','平方英尺 _ 生活'和'平方英尺 _ 以上'。这些被认为是一个特征,即特征 1 。现在数据被拟合到模型中,并且特征 1 的测试数据被用于预测。计算 y_test 的均方误差。均方误差四舍五入到小数点后两位。计算训练和测试的 r 平方误差。计算直线的截距和单个特征的系数。
features1=['bedrooms','grade','sqft_living','sqft_above']
reg=linear_model.LinearRegression()
reg.fit(train_data[features1],train_data['price'])
pred=reg.predict(test_data[features1])
print('complex_model 1')
mean_squared_error=metrics.mean_squared_error(y_test,pred)
print('mean squared error(MSE)', round(np.sqrt(mean_squared_error),2))
print('R squared training',round(reg.score(train_data[features1],train_data['price']),3))
print('R squared training', round(reg.score(test_data[features1],test_data['price']),3))
print('Intercept: ', reg.intercept_)
print('Coefficient:', reg.coef_)
R 平方检验:0.555
我们正在考虑的功能是'卧室','浴室',' sqft_living ',' sqft_lot ','楼层','海滨',' view ',' grade ',' sqft_above ',' sqft _ baseball ',' lat ',' sqft_living15 '。这些被认为是一个特征,即特征 2 。现在数据被拟合到模型中,并且特征 2 的测试数据被用于预测。计算 y_test 的均方误差。均方误差四舍五入到小数点后两位。计算训练和测试的 r 平方误差。计算直线的截距和单个特征的系数。
features2 = ['bedrooms','bathrooms','sqft_living','sqft_lot','floors','waterfront','view','grade','sqft_above','sqft_basement','lat','sqft_living15']
reg= linear_model.LinearRegression()
reg.fit(train_data[features1],train_data['price'])
pred = reg.predict(test_data[features1])
print('Complex Model_2')
mean_squared_error = metrics.mean_squared_error(y_test, pred)
print('Mean Squared Error (MSE) ', round(np.sqrt(mean_squared_error), 2))
print('R-squared (training) ', round(reg.score(train_data[features1], train_data['price']), 3))
print('R-squared (testing) ', round(reg.score(test_data[features1], test_data['price']), 3))
print('Intercept: ', reg.intercept_)
print('Coefficient:', reg.coef_)
R 平方检验:0.672
多项式回归
多项式回归是线性回归的一种形式,其中自变量 x 和因变量 y 之间的关系被建模为 n 次多项式。多项式回归拟合 x 的值和 y 的相应条件均值之间的非线性关系,表示为 E(y |x)。
对于度=2,建立线性模型。计算均方误差,并为训练和测试找到 r 的平方。
polyfeat=PolynomialFeatures(degree=2)
xtrain_poly=polyfeat.fit_transform(train_data[features1])
xtest_poly=polyfeat.fit_transform(test_data[features1])
poly=linear_model.LinearRegression()
poly.fit(xtrain_poly,train_data['price'])
polypred=poly.predict(xtest_poly)
print('Complex Model_3')
mean_squared_error = metrics.mean_squared_error(test_data['price'], polypred)
print('Mean Squared Error (MSE) ', round(np.sqrt(mean_squared_error), 2))
print('R-squared (training) ', round(poly.score(xtrain_poly, train_data['price']), 3))
print('R-squared (testing) ', round(poly.score(xtest_poly, test_data['price']), 3))
R 平方检验:0.759
对于度数=3,建立线性模型。计算均方误差,并为训练和测试找到 r 的平方。
polyfeat=PolynomialFeatures(degree=3)
xtrain_poly=polyfeat.fit_transform(train_data[features1])
xtest_poly=polyfeat.fit_transform(test_data[features1])
poly=linear_model.LinearRegression()
poly.fit(xtrain_poly,train_data['price'])
polypred=poly.predict(xtest_poly)
print('complex model_4')
mean_squared_error=metrics.mean_squared_error(test_data['price'],polypred)
print('Mean Squared Error (MSE) ', round(np.sqrt(mean_squared_error), 2))
print('R-squared (training) ', round(poly.score(xtrain_poly, train_data['price']), 3))
print('R-squared (testing) ', round(poly.score(xtest_poly, test_data['price']), 3))
R 平方检验:0.664
观察
复杂模型 3 给我们的 R 平方(测试)分数为 0.759。从上述报告中,我们可以得出结论,次数=2 的多项式回归是最佳解决方案。
对于笔记本,请参见此处的。我将很高兴收到关于上述任何反馈或问题。
用正则化技术回归。
本文假设您对回归技术有一些简单的了解,这种技术可以从由统计方法实现的数据集中记录的分层和公平分布来预测所需的变量。开个玩笑!你所需要的是足够的数学知识来理解基本的图表。
进入正题之前,稍微温习一下…
回归:回归模型是一种统计程序,允许我们估计两个或更多变量之间的线性或多项式关系。它主要基于预测变量的显著变化对输出变量的改变量,基本上是变量之间的相关性。
回归可以分为:
- 线性回归
- 多项式回归
- 逻辑回归
- 里脊回归
- 套索回归
- 弹性网络回归
从这些回归技术中也有一些其他的衍生模型服务于一个特殊的需求。
本文主要关注正则化过度回归方法,以获得更准确的预测。
正则化:正则化是一个非常重要的概念,用于避免数据的过度拟合,尤其是当训练和测试数据变化很大时。
通过将“惩罚”项添加到从训练数据得出的最佳拟合中来实现正则化,以实现测试数据的较小方差,并通过压缩预测变量的系数来限制预测变量对输出变量的影响。
里脊回归
岭回归是一种通过向多线性回归模型添加偏差来实现的技术,以损失训练数据的准确性为代价,期望用测试数据进行更准确的回归。
多线性回归的最佳拟合线的一般方程为
y = β0 + β1x1 + β2x2 + βkxk
其中 y 是输出变量,x1,x2…xk 是预测变量。
岭回归的惩罚项是λ(斜率),其中λ表示通过限制预测变量的系数而偏离原始曲线的程度,但不会使它们为零。
因此,岭回归方程为
y = β0 + β1x1 + β2x2 + βkxk + λ(斜率)
Let us take consider an example by taking the salary_data dataset, the ridge regression-scatter plot using a lambda value of 100 is:
套索回归
套索回归与岭回归非常相似,但区别仅在于惩罚项。
lasso 回归的惩罚是λ|slope|。
Lesso 回归甚至可以通过使变量的系数为零来消除变量,从而消除与其他预测变量具有高协方差的变量。
套索回归的方程式是
y =β0+β1x1+β2 x2+βkxk+λ| slope |
Taking the same example for the lasso regression, the lasso regression-scatter plot using a lambda value of 10000 is:
用线性回归模型比较 lasso 和 ridge,我们得到:
注意:所有三个图必须通过一个点,即(x̄,ȳ),其中 x̄是预测变量的平均值,ȳ是输出变量的平均值。
Elasticnet 回归是岭回归和套索回归的一个更好的组合,能够在更大程度上消除过度拟合模型。
选择合适的λ值,模型可以正则化,精度可以达到。
正则表达式
Stanley Cole Kleene, 1978. Photograph by Konrad Jacobs, Erlangen. Copyright: MFO, https://opc.mfo.de/detail?
在计算机科学、数理逻辑和语言学中,正则表达式指的是提取和处理文本模式的技术集合。正则表达式有时被称为正则表达式,它是一组精确的字符,用来对目标文本中的字符组模式进行操作。例如,用户输入到微软 Word 中熟悉的find
和find and replace
功能中的文本作为正则表达式;查询的文本序列的每个文档实例被定位、突出显示、计数,然后被单独或成批处理。
在计算中,复杂的正则表达式技术提供了比那些在find
中使用的更复杂的功能。事实上,模式匹配正则表达式的理论是由美国数学家斯坦利·科尔·克莱尼——阿隆佐·邱奇的学生——在 20 世纪 50 年代初首次系统化的,这比现代编程的出现早了几十年。然而,20 世纪 70 年代 Unix 和 Unix 邻近操作系统的发展使得正则表达式无处不在。实现正则表达式的两个主要语法标准之一在当代编程语言中仍然存在:继承自 POSIX 的标准和继承自 Perl 的标准。
Perl 是 Python 内置re
模块的祖先。使用re
,Python 程序员可以编写以各种方式作用于字符串的字符串,而不是简单地将输入字符串中的单个字符与文本中的其他字符串进行元素匹配。其中,正则表达式搜索中最常用的技术之一叫做通配符。
>import re
>
>string = 'This is a wildcard.'
>x = re.findall('wil.*', string)
>
>print(x)['wildcard.']
通配符——有时称为占位符——在上面的代码中由字符对.*
表示。这个.*
指示解释器在目标文本中搜索它左边的任何字符,然后它右边的任何字符可以跟随它。在本例中,通配符的功能类似于 Bash 中文件搜索时的 tab 补全,它允许用户只键入文件的前几个字母,然后让 autocomplete 处理其余部分。在 SQL 中,通配符只是星号*
,前面没有.
。
>string = 'This is a wildcard.'
>x = re.findall('wil.', string)
>
>print(x)['wild']
如果我们删除*
但保留.
,单个通配符将表示在该位置允许任何一个字符。换句话说,.
将告诉解释器在目标文本中搜索它左边的字符序列,并打印它和紧随其后的下一个字符。正则表达式理论中的单个字符被称为原子。添加更多的.
原子字符将打印序列后面更多的字母。
>string = 'This is a wildcard.'
>x = re.findall('wil...', string)
>
>print(x)['wildca']
我们也可以在表达式中间使用通配符。
>string = 'This is a wildcard.'
>x = re.findall('wil....d', string)
>
>print(x)['wildcard']
通配符在正则表达式理论中被称为元字符,在re
中有很多这样的元字符。另一个特别有用的元字符允许我们搜索目标文本是否以正则表达式的开头。这个正则表达式用^
表示。其他元字符包括以$
、非此即彼|
结尾,以及特定数量的实例{}
。
>string = 'This is a wildcard.'
>x = re.findall('^This', string)
>
>print(x)['This']
除了元字符之外,re
还有大量的特殊字符、、,它们允许表达式对模式进行不同类型的检索或操作。这些特殊字符各由\
表示;这与该字符在 Python 字符串中的用法一致。这些特殊字符之一就是d
。d
返回目标文本中所有匹配的整数。
>string = '1These2are3not4numbers5.'
>x = re.findall('\d', string)
>
>print(x)['1', '2', '3', '4', '5']
与此相反,我们可以通过调用\D
返回所有非数字字符。
>string = '1These2are3not4numbers5.'
>x = re.findall('\D', string)
>
>print(x)['T', 'h', 'e', 's', 'e', 'a', 'r', 'e', 'n', 'o', 't', 'n', 'u', 'm', 'b', 'e', 'r', 's', '.']
我们也可以将正则表达式视为集合。这是通过将我们的表达式放在括号[]
中来实现的。下面,我们在目标文本中搜索表达式中的任何字符,并在每次匹配时返回该字符:
>string = 'I am looking for all five vowels.'
>x = re.findall('[aeiou]', string)
>
>print(x)['a', 'o', 'o', 'i', 'o', 'a', 'i', 'e', 'o', 'e']
与此相反,如果我们以^
开始表达式,那么集合的补集——正则表达式中除以外的任何字符——都将被打印出来。
>string = 'I am looking for all five vowels.'
>x = re.findall('[^aeiou]', string)
>
>print(x)['I', ' ', 'm', ' ', 'l', 'k', 'n', 'g', ' ', 'f', 'r', ' ', 'l', 'l', ' ', 'f', 'v', ' ', 'v', 'w', 'l', 's', '.']
使用连字符时,正则表达式将返回任何没有指定范围的小写字母的字符的匹配。
>string = 'I am looking for all five vowels.'
>x = re.findall('[a-l]', string)
>
>print(x)['a', 'l', 'k', 'i', 'g', 'f', 'a', 'l', 'l', 'f', 'i', 'e', 'e', 'l']
这里给出的每个例子都使用了findall()
方法。但是我们也可以split()
、sub()
、search()
、span()
、match()
、group()
。因此,这仅仅是对re
的一些概念基础的简单介绍。此外,Python 中的正则表达式超越了re
固有的功能。例如,一个流行的第三方包regex
提供了更多的正则表达式方法,并且向后兼容原生的re
。
第二部分:关于正则表达式您需要知道的一切
Python 和反斜杠瘟疫的简短教程。
假设你知道什么是正则表达式(如果你不知道,请查看本教程的第 1 部分以获得快速概述)我们现在将学习如何在 Python 中使用它们。😃
“re”模块为正则表达式引擎提供了一个接口,并允许我们将 re 编译成对象,然后对它们执行匹配。
我们将从导入模块开始。然后,我们将通过将正则表达式作为字符串传递来组合它,并将其转换为模式对象。
>>> import re
>>> pat_obj = re.compile('[a-z]+')
>>> print(pat_obj)
re.compile('[a-z]+')
如何处理模式对象?
- match(): 判断 RE 是否匹配字符串的开头。
>>> m = pat_obj.match('helloworld')
>>> print(m)
*<_sre.SRE_Match object; span=(0, 10), match='helloworld'>***#Note how it doesn't take into account white spaces.**
>>> m = pat_obj.match('hello world')
>>> print(m)
*<_sre.SRE_Match object; span=(0, 5), match='hello'>***# Note that it is case-sensitive.**
>>> m = pat_obj.match('Helloworld')
>>> print(m)
*None***#To ignore case** >>> pat_obj = re.compile('[a-z]+', re.IGNORECASE)
>>> m = pat_obj.match('Helloworld')
>>> print(m)
*<_sre.SRE_Match object; span=(0, 10), match='Helloworld'>*
- search(): 扫描一个字符串,寻找这个 re 匹配的任何位置。
**#Note how it only prints the first match**
>>> s = pat_obj.search('Hello World!')
>>> print(s)
*<_sre.SRE_Match object; span=(1, 5), match='ello'>*
- 要打印所有匹配项,
findall(): 查找 re 匹配的所有子字符串,并将它们作为一个列表返回。
>>> s = pat_obj.findall('Hello World!')
>>> print(s)
*<_sre.SRE_Match object; span=(1, 5), match='ello'>
['ello', 'orld']***#To find all the numbers in a string**
>>>pat_obj_num = re.compile(r'\d+')
>>> pat_obj_num.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
*['12', '11', '10']*
- group(): 返回 RE 匹配的字符串。因为说实话,这才是你感兴趣的。没人有时间听这些信息。
**#Using group with search**
>>> s = pat_obj.search('Hello World!')
>>> print(s)
*<_sre.SRE_Match object; span=(1, 5), match='ello'>* >>> print(s.group())
*ello***#Using group with match**
>>> m = pat_obj.match("hello world")
>>> print(m)
*<_sre.SRE_Match object; span=(0, 5), match='hello'>* >>> print(m.group()) *hello***#Using group with findall** >>> m = pat_obj.findall("hello world")
>>> print(m)
*['hello', 'world']* >>> print(m.group()) *Error!*
- span(): 返回一个包含匹配(开始,结束)位置的元组。
start(),end(): 分别返回匹配的开始和结束位置。
>>> pat_obj = re.compile('[a-z]+', re.IGNORECASE)
>>> m = pat_obj.match('Helloworld')
>>> print(m)
*<_sre.SRE_Match object; span=(0, 10), match='Helloworld'>*
>>> print(m.start())
*0* >>> print(m.end())
*10*
>>> print(m.span())
*(0, 10)*
分组
Photo by Jeffrey F Lin on Unsplash
组由()元字符标记。它们将包含在其中的表达式组合在一起,您可以使用重复限定符重复组的内容,例如*、+、?或者{m,n}。
组从 0 开始编号。组 0 始终存在;这是整个 RE,所以 match 对象方法都将 group 0 作为它们的默认参数。
子组从左到右,从 1 向上编号。组可以嵌套;要确定数字,只需从左到右计算左括号中的字符。
>>> pat_obj_group = re.compile('(a(b)c(d))e')
>>> m = pat_obj_group.match('abcde')
>>> print(m)
*<_sre.SRE_Match object; span=(0, 5), match='abcde'>* ***#Note m.group(0) matches the same regex as m.match()*** >>> print(m.group(0))
*abcde*
>>> print(m.group(1))
*abcd* ***#Note the number is determined left to right*** >>> print(m.group(2))
*b**>>> print(m.group(3))
d* ***# Note that multiple arguments can be passes to group()*** >>> print(m.group(2,1,3))
*('b', 'abcd', 'd')*
- groups(): 返回一个包含所有子组字符串的元组,从 1 到所有子组。
>>> print(m.groups())
*('abcd', 'b', 'd')*
代替
sub(): 返回用替换 repl 替换字符串中模式最左边不重叠出现的字符串。如果没有找到该模式,则返回不变的字符串。
repl 可以是字符串,也可以是函数;如果它是一个字符串,其中的任何反斜杠转义都会被处理。也就是说,\n 被转换为单个换行符,\r 被转换为回车符,依此类推。
模式的空匹配只有在不与先前的空匹配相邻时才被替换。
>>> print(re.sub('x','-','abxd'))
*ab-d*
>>> print(re.sub('ab*','-','abxd'))
*-xd*
>>> print(re.sub('x*','-','abxd'))
*-a-b-d-*
可选参数 count 是要替换的模式出现的最大数量;计数必须为非负整数。如果省略或为零,将替换所有出现的内容。
反斜杠瘟疫
Photo by Aarón Blanco Tejedor on Unsplash
尽管传递正则表达式有助于保持简单,但它有一个缺点。反斜杠字符(“\”)用于允许使用特殊字符而不调用它们的特殊含义,这与 Python 在字符串文字中使用相同字符的用法相冲突,在字符串文字中使用反斜杠字符以不同方式解释后面的字符。
例如,“n”本身只是一个字母,但是当你在它前面加一个反斜杠时,它就变成了\n,这是换行符。啊哦!
假设您想要编写一个匹配字符串'\ section【T6]'的 RE,这个字符串可能在 LaTeX 文件中找到。
我们将从想要匹配的字符串开始。接下来,我们必须通过在反斜杠前面加上反斜杠来转义任何反斜杠和其他元字符,从而得到字符串' \section '。必须传递给 re.compil()的结果字符串必须是' \section '。然而,要将其表示为 Python 字符串文字,必须再次对两个反斜杠进行转义,导致字符串“ \\section ”。
简而言之,要匹配一个文字反斜杠,必须将' \\ '写成 RE 字符串,因为正则表达式必须是\,并且每个反斜杠必须在一个常规 Python 字符串文字中表示为\。
Source: XKCD
解决方案是对正则表达式使用 Python 的原始字符串表示法;在以' r '为前缀的字符串文字中,不会以任何特殊方式处理反斜杠,因此 r'\n '是包含' \ '和' n '的双字符字符串,而' \n '是包含换行符的单字符字符串。
常规字符串和相应的原始字符串
"ab*" -> r"ab*""\\\\section" -> r"\\section""\\w+\\s+\\1" -> r"\w+\s+\1"
学习正则表达式的有趣工具和资源
我写的其他文章,我认为你可能会喜欢:D
- 8 分钟内学会 Git!
我很高兴你坚持到了这篇文章的结尾。🎉我希望你的阅读体验和我写这篇文章时一样丰富。💖**
请点击查看我的其他文章。
如果你想联系我,我会选择推特。
关于正则表达式你需要知道的
我的常用备忘单。
第一部分:揭开正则表达式的神秘面纱
Source: XKCD
什么是正则表达式,为什么你应该知道它们?
正则表达式是一种用字符序列匹配模式的通用方法。它们定义了一个搜索模式,主要用于字符串的模式匹配或字符串匹配,即“查找和替换”之类的操作。
假设你要搜索一个语料库,并返回其中提到的所有电子邮件地址。对于一个人来说,这是一个非常简单的任务,因为每个电子邮件地址都可以概括为一个字母数字字符串,其中包含一些允许的特殊字符,如。(点)、_(下划线)、-(连字符),后面跟一个' @ {域名}。' com '。
但是如何将这样的模板传递给计算机呢?电子邮件地址可以是可变长度的,没有固定的数字/特殊字符位置(可以在开头、结尾或中间的任何位置),这一事实并没有使计算机的任务变得更容易。
这就是正则表达式帮助我们的地方!通过使用它们,我们可以很容易地创建一个通用的模板,它不仅能被计算机理解,还能满足我们所有的限制。
Source: XKCD
正则表达式这个术语是从哪里来的?
正则表达式这个术语来源于数学和计算机科学理论,在这里它反映了数学表达式的一个特质叫做 正则性 。最早的 grep 工具使用的文本模式是数学意义上的正则表达式。虽然这个名字已经被记住,但是现代的 Perl 风格的正则表达式(我们仍然在其他编程语言中使用)在数学意义上根本不是正则表达式。
它们通常被称为 REs ,或正则表达式,或正则表达式模式。
如何写正则表达式?
基础知识:
#1 :大部分角色与自己匹配。因此,如果您必须为单词“wubbalubadubdub”编写正则表达式,那么它的正则表达式应该是“wubbalubadubdub”。请记住,REs 是区分大小写的。
但是有一些名为 的元字符 与它们本身并不匹配,而是表示一些不寻常的东西应该匹配,或者它们通过重复它们或改变它们的意思来影响 re 的其他部分。这些元字符使正则表达式成为强大的工具。
#2 : 复读机*,+,{} 。很多时候你会遇到这样的情况,你不知道一个字符会重复多少次,或者是否会重复。复读机让我们能够处理这种情况。
星号(*): 表示前面的字符出现 0 次或更多次。前面字符的出现次数没有上限。
In ‘a*b’, ‘a’ precedes the *, which means ‘a’ can occur 0/0+ times. So it will match to ‘b’, ‘ab’, ‘aab’, ‘aaab’, ‘aa..(infinite a’s)..b’.
加号(+): 与*相同,但暗示前面的字符至少出现一次。
‘a+b’ will match to ‘ab’, ‘aab’, ‘aaab’, ‘aaa…aab’ but not just ‘b’.
花括号{} :用于定义前一个字符出现的范围。
‘a{3},b’: will match ‘aaab’ only.
‘a{min,}b’: restricting minimum occurrences of ‘a’, no upper limit restrictions.
‘a{3,}b’ will match ‘aaab’, ‘aaaab’, ‘aaa…aab’.
‘a{min, max}b’: ‘a’ should occur at least min times and at most max times. ‘a{3,5}b’ will match ‘aaab’, ‘aaaab’, ‘aaaaab’.
#3 通配符(。):知道字符串中字符的顺序并不总是可行的。在这些情况下,通配符非常有用。
这意味着任何字符都可以在序列中占据它的位置。
‘.’ will match all strings with just one character.
‘.*’ will match all possible strings of any length.
‘a.b’ will match ‘aab’, ‘abb’, ‘acb’, ‘adb’, …. ‘a b’ [a(space)b], ‘a/b’ and so on. Basically, any sequence of length 3 starting with ‘a’ and ending with ‘b’.
#4 可选字符(?):有时候一个词可能有多种变体。就像“color”(美国英语)和“color”(英国英语)是同一个单词的不同拼法,都是正确的,唯一的区别是在英国版本中多了一个“u”。
那个“?”意味着前一个字符可能出现在最终字符串中,也可能不出现。在某种程度上,'?'意味着出现 0 或 1 次。
‘colou?r’ will match both ‘color’ and ‘colour’.
‘docx?’ will match both ‘doc’ and ‘docx’.
Caret(^):暗示一个字符串的第一个字符。
‘^a.*’ will match all strings starting with ‘a’.
‘^a{2}.*’ will match all strings starting with ‘aa’.
#6 美元($): 它暗示一个字符串的最后一个字符。
‘.*b$’ will match all strings ending with a ‘b’.
#7 字符类([]) :通常情况下,对于一个字符串中的一个特定位置,会有不止一个可能的字符。为了容纳所有可能的字符,我们使用字符类。它们指定了您希望匹配的一组字符。字符可以单独列出,也可以通过给出两个字符并用'-'分隔来表示一个字符范围。
‘[abc]’: will match ‘a’, ‘b’, or ‘c’.
‘[^abc]’:*Negation* will match any character except ‘a’, ‘b’, and ‘c’. **Note** -- Not to be confused with caret where ^ implies begins with. If inside a character class ^ implies negation.
Character range: ‘[a-zA-Z]’ will match any character from a-z or A-Z.
\d
匹配任意十进制数字;这相当于类[0–9]。
\D
匹配任何非数字字符;这相当于类[^0–9].
\s
匹配任何空白字符;这相当于类[\t\n\r\f\v]。
\S
匹配任何非空白字符;这相当于 class[^\t\n\r\f\v].
\w
匹配任何字母数字字符;这相当于类[a-zA-Z0–9]。
\W
匹配任何非字母数字字符;这相当于类[^a-za-z0–9].
#9 分组字符:正则表达式的一组不同符号可以组合在一起,作为一个单元,表现为一个块,为此,需要将正则表达式括在括号( )中。
‘(ab)+’ will match ‘ab’, ‘abab’,’abab…’.
‘^(th).*” will match all string starting with ‘th’.
#10 竖线(| ): 匹配由(|)分隔的任何一个元素。
th(e|is|at) will match words - the, this and that.
#11 转义符(): 如果你想匹配一个元字符本身,也就是匹配' * '和' * '而不使用通配符,该怎么办?
你可以在这个字符前加一个反斜杠()来实现。这将允许使用特殊字符而不调用它们的特殊含义。
\d+[\+-x\*]\d+ will match patterns like "2+2" and "3*9" in "(2+2)*3*9".
为电子邮件地址编写正则表达式
为了为任何电子邮件地址编写正则表达式,我们需要记住以下约束:
- 它只能以字母开头。【^([a-za-z】)
- 它的长度可变,可以包含任何字母数字字符和“.”, '_', '-'.(【a-zA-Z0–9 _ -\。])*
- 它应该有一个“@”后跟一个域名。@([a-zA-Z0–9 _ -\。]+)
- 它应该以点号结尾,通常有 2/3 字符长。
。([a-zA-Z]){2,3 } $
我们最后一个电子邮件地址的正则表达式:
^([a-za-z])([a-za-z0–9_-.]*)@([a-zA-Z0–9 _ -\。]+).([a-zA-Z]){2,3}$
正则表达式的实际应用
正则表达式在各种各样的文本处理任务中非常有用,更普遍的是在数据不需要是文本的字符串处理中非常有用。常见的应用包括数据验证、数据抓取(尤其是 web 抓取)、数据争论、简单解析、生成语法突出显示系统以及许多其他任务。
虽然正则表达式在互联网搜索引擎上很有用,但是根据正则表达式的复杂性和设计,在整个数据库中处理它们会消耗过多的计算机资源。尽管在许多情况下,系统管理员可以在内部运行基于正则表达式的查询,但大多数搜索引擎并不向公众提供正则表达式支持。
进一步阅读:
本教程的第 2 部分到此为止,我们在 python 中通过他们的 re 模块使用 REs。还讨论了编写正则表达式时面临的一些复杂问题,即“反冲瘟疫”。那里见!👋
参考资料:
- 维基百科:正则表达式
- 极客 forgeeks
- Python 文档
- Steven Levithan,Jan Goyvaerts 的正则表达式食谱
我写的其他文章,我认为你可能会喜欢:D
我很高兴你坚持到了这篇文章的结尾。🎉
我希望你的阅读体验和我写这篇文章时一样丰富。💖请点击这里查看我的其他文章。
如果你想联系我,我会选择 Twitter。
正则化和几何
一、偏倚-方差权衡
当我们执行统计建模时,目标不是选择适合所有训练数据点的模型并获得训练数据的最小误差。目标是让模型能够很好地概括新的和看不见的数据。
Bias and variance contributing to generalization error [1]
随着越来越多的参数被添加到模型中,模型的复杂性增加,即,它可以拟合训练数据中的更多噪声,并导致过度拟合。这意味着我们在增加模型的方差,减少模型的偏差。从上图可以看出,如果我们不断提高模型的复杂度,泛化误差最终会超过最优点并继续增加。
总之,如果我们的模型复杂性超过了最佳点,我们就有陷入过度拟合区域的风险;而如果复杂度没有达到最佳点,我们就处于不适合区域。
正则化是一种有助于防止统计模型陷入过度拟合区域的技术。它通过阻碍模型的复杂性来做到这一点。
二。正规化
线性回归
这是一个简单的线性回归方程。
Linear Regression
我们的目标是找到最小化残差平方和(RSS)的β集。
Residual Sum of Squares
L2 正规化
利用 L2 正则化的回归模型也称为岭回归。就线性回归而言,不仅仅是最小化 RSS。我们通过对测试版的约束为游戏增加了另一个元素。
L1 Regularization
“s”可以理解为 betas 版的预算。如果你想让第一个测试变大,第二个测试必须变小,反之亦然。这变成了一场竞争,因为我们有更多的测试版,不重要的将被迫变小。
由于平方项,RSS 方程实际上给出了椭圆的几何形状。黑点是使用正规方程的贝塔集,即没有正则化。红圈包含了我们“买得起”的所有测试集。红点是岭回归的最终 betas,在我们的预算内最接近黑点。红点将总是在约束的边界上。只有当法线方程的解,即没有正则化的线性回归的解,已经满足约束时,才能在约束内获得红点。
L1 正规化
利用 L1 正则化的回归模型也被称为 Lasso ( 最小绝对收缩和选择算子)回归。套索的目标类似于山脊,只是约束变为:
L2 Regularization
套索还为我们提供了一个美丽的几何图形,它具有独特的性质。
通过 L2 正则化,我们可以“承受”的贝塔集位于一个菱形内。红点在菱形的角上,将其中一个 betas 设置为 0。
如果红点在菱形的边缘,即椭圆接触到菱形的边缘,会怎么样呢?因此,两个 betas 都不会是 0。然而,二维空间中的菱形是一种特殊情况,如果红点在边缘上,则两个β都不为 0。
让我们考虑一下我们有 3 个 betas 的情况。约束的几何图形变为:
Lasso with 3 betas
上图由 6 个顶点和 8 条边组成。如果红点位于边缘,一个β将被设置为 0。如果它位于一个顶点上,两个β将被设置为 0。随着尺寸的增加,顶点和边的数量也增加,使得椭圆更有可能在这些位置之一与菱形接触。也就是说,套索往往在更高的维度上工作得更好。
L1 和 L2 正规化的差异
岭回归是线性回归的一种扩展,它将贝塔系数设置得很小,从而减少了不相关特征的影响。这样,统计模型将不适合训练数据中的所有噪声,并且落入过拟合区域。
套索回归带来了一些独特的属性表,因为它的美丽的几何图形。一些测试将被设置为 0,给我们一个稀疏的输出。我们也可以使用套索进行特征选择。虽然诸如最佳子集、向前逐步或向后逐步的特征选择技术可能是时间低效的,但是 Lasso 将更快地收敛到最终解。
三世。结论
具有高复杂性的统计模型可能易于过度拟合。在本文中,我介绍了两种正则化技术来阻止模型拟合训练数据中的所有噪声。而且,我借助几何解释了它们的性质和区别。
我的文章到此结束!祝大家有美好的一天:)
图像:
[1]丹尼尔·桑德斯,偏差-方差权衡 (2017)
机器学习模型的正则化
L1·拉索、L2·海岭和 L1+L2 弹性网正规化解释
机器学习中的一个常见问题是过拟合,其中模型错误地概括了训练数据中的噪声:
https://towardsdatascience.com/over-fitting-and-regularization-64d16100f45c
补救这个问题并使模型更健壮的一个流行方法是正则化:一个惩罚项被添加到算法的损失函数中。这改变了最小化损失函数所产生的模型权重。
最流行的正则化技术是套索、脊(又名吉洪诺夫)和弹性网。对于只有一个权重参数 w (线性拟合的斜率)的简单线性回归的示例情况,它们的罚项看起来像这样(包括一个比例参数 λ ):
- 拉索(L1) : λ |w|
- 山脊(L2) : λ w
- 弹性网(L1+L2):λ₁| w |+λ₂w
不同的项具有不同的效果:与 L1 相比,二次 L2 正则化在小权重(接近零)时变得可以忽略,但是在大权重时变得更强。这导致了以下行为,随便说说:
- 无正则化的线性回归:“我附和一切。”
- 拉索:“一开始我持怀疑态度,但是要顺应重大趋势。”
- 岭:“我很容易被说服,但有点迟钝。”
- 弹力网:“我感觉在山脊和套索之间的某个地方。”
让我们看看在实践中是什么样子。对于十个随机数,我们将使用上述四种方法中的每一种方法进行线性拟合(出于演示目的,对岭使用增加的λ参数):
当然,你会在数据中得到一个微小的随机趋势,这无疑是由线性回归得到的。岭回归也显示了这一趋势,但更弱。对于套索和弹性网,当最小化损失函数时,线性 L1 罚项足够高以迫使权重(即斜率)为零。
现在,我们向数据点添加一个小的线性分量,并重新运行拟合程序:
这已经足够让 Lasso 不再完全“忽略”坡度系数了。
如果我们进一步增加增加的线性分量,我们得到这个:
套索和弹性网现在几乎完全“接受”显著趋势,而对于山脊,二次惩罚项导致较低的斜率。
你错过什么了吗?在评论中分享你的观点或问题吧!
基于 Framingham 案例研究的神经网络正则化
L1,L2,弹性网,和组套索正规化
在这篇文章中,我将讨论 L1、L2、弹性网和神经网络上的套索正则化。我描述了正则化如何帮助您构建更有用和更易解释的模型,并且我包括了每种正则化类型的 Tensorflow 代码。最后,我提供了一个详细的案例研究,展示了正则化对神经网络模型的影响,这些神经网络模型应用于来自 Framingham 研究的真实临床和遗传数据。
正规化的好处
正则化可以通过减少过度拟合使模型更加有用
正则化可以通过减少过度拟合来提高你的神经网络对未知数据的性能。
过拟合是一种神经网络开始记忆训练数据的独特怪癖(如训练数据噪音)而不是学习普遍适用的原则的现象。“过度拟合”的模型将在训练数据上获得高性能,但在保留的测试数据上表现不佳,这意味着该模型在现实世界中不会有用,因为它不会在从未见过的数据上表现良好。由于神经网络模型的全部目的是解决新数据的实际问题,我们希望避免过度拟合,以便获得实际有用的模型。
下面是分类问题中过拟合的一个例子:
在这个分类任务中,我们要学习一条区分红点和蓝点的线。黑线代表一个很好的分类器,它似乎捕捉到了蓝点和红点在空间中的位置的一般原理。绿线代表一个过度拟合的分类器,因为它对于这个红点和蓝点的精确训练集来说太具体了。
观察绿色分类器线如何在一个看不见的测试集上表现更差,即使这个看不见的测试集遵循相同的蓝点和红点的一般布局。还要注意,没有过度拟合的黑色分类器行在测试集上仍然工作得很好:
当神经网络记住训练集中的所有例子时,过度拟合的最极端版本发生。当神经网络具有许多参数并且训练时间过长时,会发生这种情况。
正则化可以让模型更容易理解
具体来说,“套索”正则化试图强制模型中的一些权重为零。
- 在回归中,一个权重对应一个变量,因此套索正则化(使用 L1 罚函数)可以通过“清零”相应的权重来直接“清零”某个输入变量。
- 在神经网络中,我们需要使用“套索组”正则化,以便将整个输入变量归零,并获得更易解释的模型。这是因为神经网络将许多权重应用于单个输入变量,因此我们必须将所有这些权重视为一个“组”(详见后面章节。)
愚蠢的例子:
- 我们想建立一个模型来预测糖尿病的风险,这个模型是基于一个包含这些变量的临床数据集:[身高,年龄,过去的诊断,过去的药物,最喜欢的颜色,最喜欢的动物]
- 我们构建了包含 lasso 正则化的模型,并发现该模型选择了“清零”与“最喜欢的颜色”和“最喜欢的动物”相对应的权重,这告诉我们这些变量在预测未来的糖尿病诊断中没有用。
如何正则化神经网络模型
通用设置
以下是神经网络模型正则化的一般设置,其中 W 表示神经网络模型的权重:
每个神经网络都有一个损失函数,用于在训练中调整神经网络的权重。损失函数衡量神经网络的预测与事实有多大的不同(见这篇文章的评论)。)
正则化只是在损失函数中增加了一个“正则项”(上面用蓝色表示)。
- λ (lambda)决定正则化对网络训练的影响程度。如果设置λ=0,则根本没有正则化,因为您已经将整个正则化项置零。如果您设置λ= 1,000,000,000,那么这将是非常强的正则化,这将使您的模型很难学习任何东西。正则化强度λ的合理选择可以是 0.001、0.01、0.1、1.0 等。最后,要使用的最佳λ值取决于您的数据集和您正在解决的问题。您可以在验证集上用不同的λ强度检查模型的性能,然后选择给出最佳结果的λ。因此,正则化强度λ成为您的模型的超参数,您可以在验证集上对其进行调整。
- 数学 (W)表示实际的正则化运算。我们称神经网络的权重为 W,因此正则化只是对权重的数学运算。不同种类的正则化对应不同的数学运算。
L1 正规化
以下是 L1 正则化的公式(首先是简单的简写,然后更加精确):
因此,L1 正则化增加了具有大绝对值的权重的惩罚。L1 正则化鼓励您的模型使尽可能多的权重为零。
以下是如何在只有一层的微型神经网络上计算 L1 正则化惩罚的示例,由 2 x 2 权重矩阵描述:
当将 L1 正则化应用于回归时,它被称为“套索回归”
下面是张量流代码,用于计算名为 weights 的权重矩阵的 L1 正则化惩罚:
l1_penalty = tf.reduce_sum(tf.abs(weights))
L2 正规化
以下是 L2 正则化的公式(首先是粗略的简化,然后更加精确):
因此,L2 正则化增加了拥有许多大权重的惩罚。L2 正则化鼓励模型选择小数量级的权重。
下面是一个如何在只有一层的微型神经网络上计算 L2 正则化罚值的示例,由 2 x 2 权重矩阵描述:
如果你将 L2 正则化应用于回归,它被称为“岭回归”
下面是用于计算权重矩阵权重的 L2 正则化惩罚的张量流代码:
l2_penalty = tf.reduce_sum(tf.nn.l2_loss(weights))
张量流函数“l2_loss”计算 l2 范数的平方。平方 L2 范数是 L2 正则化的另一种写法:
L1 和 L2 正规化的比较
请注意,在 L1 正则化中,权重为-9 会得到 9 的惩罚,但在 L2 正则化中,权重为-9 会得到 81 的惩罚-因此,在 L2 正则化中,较大的权重受到的惩罚要严重得多。
另请注意,在 L1 正则化中,权重为 0.5 会得到 0.5 的罚分,但在 L2 正则化中,权重为 0.5 会得到(0.5)(0.5) = 0.25 的罚分-因此,在 L1 正则化中,仍然有将甚至很小的权重向零挤压的趋势,比在 L2 正则化中更是如此。
这就是为什么 L1 正则化鼓励模型使尽可能多的权重为零,而 L2 正则化鼓励模型使所有的权重尽可能小(但不一定为零)。
弹性网正规化
“弹性网络正则化”听起来很奇特,但它简单地意味着同时使用 L1 和 L2 正则化:
这里,我们有两个λ:一个控制 L1 正则项的强度,另一个控制 L2 正则项的强度。如前所述,这两个 lambda 值都可以使用验证集进行调整。
群组套索正规化
套索集团是由袁和林在 2006 年推出的:
明元和林逸。"分组变量回归中的模型选择和估计."J. R .统计学家。社会主义者 B (2006)。
(那篇论文后来被引用了 5000 多次。)
什么是套索组?回想一下,L1 正则化有时被称为“套索正则化”,其目的是将一些变量归零。同理,“群组套索”是一种允许你将整组变量归零的技术。特定变量组的所有成员要么一起包含在模型中,要么一起从模型中排除(归零)。
以下是“套索组”特别有用的两种情况:
对于分类变量:如果您已经将分类变量表示为一个热点向量——即,二元协变量的集合——组 lasso 可以确保与单个分类变量相对应的所有二元协变量一起“清零”或“保留”。例如,如果您有一个可能值为“红色”、“蓝色”和“绿色”的分类变量“颜色”,那么您可以用一个长度为三的一键向量来表示该分类变量,这相当于将一个单独的“颜色”列拆分为三个二进制列:“红色是/否”、“蓝色是/否”和“绿色是/否”。“组合套索”可以帮助您将所有三列一起清零,或者保留所有三列,将它们视为一个单元。
对于神经网络:如果你正在训练一个神经网络,组套索可以“清零”整个输入变量,并帮助你获得一个更可解释的模型。
- 如前所述,良好的旧 L1 正则化可以很容易地将回归中的整个变量归零,因为它只需将一个权重归零即可将一个变量归零。
- 但在神经网络中,许多权重作用于一个变量,这意味着我们必须同时将所有这些权重归零,以便将该变量归零。套索组让我们将所有对应于一个变量的权重组合在一起,以实现这一目标。
下图显示了“XW”:2 维数据输入矩阵 X 乘以神经网络权重矩阵 W。在这种情况下,W 将 2 维输入映射到 4 维隐藏层。输入 X 由“患者 A”和变量“血压”和“胆固醇”组成(已经按照此处描述的进行了适当标准化)。)您可以看到权重矩阵的第一行以红色突出显示,这对应于将乘以血压变量的权重。权重矩阵的第二行以蓝色突出显示,这对应于将乘以胆固醇变量的权重。因此,如果我们想要“归零”可变血压,我们需要“归零”权重矩阵顶行中的所有四个权重。
(注:在大多数论文中,神经网络数学都写成 WX+b,其中 W 是权重矩阵,X 是输入,b 是偏置向量。为什么我在这里写 XW?嗯……在 Tensorflow 中,全连接层的实现使用 XW 而不是 WX。参见这篇文章,了解更多关于理论与实践中的符号的评论。)
这里有一篇描述群组套索应用于神经网络的论文:
西蒙·斯卡达潘尼,达尼洛·科米涅罗,阿米尔·侯赛因和奥雷利奥·安西尼。"深度神经网络的组稀疏正则化."神经计算 (2017)。
这是论文的位存储库,作者解释说,
对于网络中的每个节点,我们包括一个正则化项,将整行输出权重同时推为零。这是通过约束行的 L2 范数来实现的,通过其维数的平方根来加权。
以下是群组套索正规化的公式:
这里有一个组套索惩罚的张量流函数,来自这个库:
# Define the group lasso penalty
returnT.sum(T.sqrt(x.shape[1])*T.sqrt(T.sum(x**2, axis=1)))
这是组套索惩罚的另一个 Tensorflow 实现:
euclidean_norm =tf.sqrt( tf.reduce_sum(tf.square(weights),axis =1) )
#Must cast num_outputs to a float in order for tensorflow to take the square root
account_for_group_size = tf.sqrt( tf.cast(num_outputs, dtype=tf.float32) )
penalty = tf.reduce_sum( tf.multiply(account_for_group_size, euclidean_norm) )
有些令人困惑的是,本文中的群组套索使用了 L2 范数,就像在 L2 正则化中一样(将元素的平方值相加)。但是传统的“套索”使用 L1 规范!这是怎么回事?
维基百科对“套索”的定义是:
Lasso(最小绝对收缩和选择算子)是一种回归分析方法,它执行变量选择和正则化,以提高其产生的统计模型的预测精度和可解释性。
“套索组”执行变量选择(通过将对应于特定输入变量的权重组归零)和正则化。此外,即使套索组包含 L2 规范,它也不同于 L2 正则化:
弗雷明汉案例研究
背景
弗雷明汉心脏研究始于 1948 年,一直延续至今。弗雷明汉研究为许多关于心脏病的现代知识做出了贡献,包括健康饮食、保持健康体重、不吸烟和定期锻炼可以降低患心脏病的风险。弗雷明汉心脏研究数据集包括临床变量(如年龄、吸烟状况)、遗传变量和心脏病结果(如患者是否有心脏病发作)。)
2018 年夏天,我花了几个月时间分析弗雷明汉心脏研究的部分数据,以确定同时包含临床和遗传数据的预测模型是否会比仅使用临床数据建立的预测模型表现更好。我怀疑在临床数据的基础上增加基因数据很难在预测性能上看到任何好处,因为:
- 许多临床变量(如胆固醇水平、甘油三酯水平、血压)总结了生活方式选择(如饮食、锻炼、物质使用)和遗传。因此,临床数据已经包括遗传学,尽管是隐含的。
- 人类基因组中有成千上万个影响心脏病的位点。这些点分布在整个基因组中。每一个斑点本身对心脏病风险的贡献都很小。然而,大约 50%的心脏病风险是遗传的——这意味着,总体而言,所有这些点一起对心脏病风险有显著影响。因为有这么多不同的贡献点,每一个都有很小的影响,我们需要一个巨大的样本量来挑选对预测有用的模式。不幸的是,在我的弗雷明汉数据子集中,我有 500,000 个遗传变量,但只有 3000 名患者,这意味着问题是欠定(变量多于训练样本。)
模型结果
我根据弗雷明汉数据集的临床和遗传数据训练了各种前馈神经网络,以预测心脏病风险。我对第一层权重矩阵应用了不同类型的正则化。下表显示了不同模型的性能(Acc = 精度,AUC = 面积在接收器工作特性,AP = 平均精度):
关于结果的要点:
- 表现最好的模型仅使用临床数据(第一行。)
- 仅使用遗传数据的模型(第二行)比仅使用临床数据的模型具有低得多的性能。
- 结合遗传和临床数据的模型都比单独使用临床数据的模型性能低,可能是因为 3000 名患者的样本量不够大,无法从遗传数据中了解到任何有意义的信息。该模型反而过度适应遗传训练数据中的噪声,然后不能推广到测试集中的遗传数据。这具有“混淆”测试集性能的效果(相对于其中临床变量是唯一输入的模型。)
第一层权重矩阵热图
通过检查不同正则化方法的第一层权重矩阵的热图,我们可以获得更多的见解。热图的每一行对应于一个不同的输入变量。前 20 行(genetic_0 到 genetic_19)对应于应用于 500,000 个遗传输入变量的已学习的 20 维表示的权重。底部行(从 SYSBP1 到 DIAB_1.0)对应于应用于临床变量的权重。
以下是采用(A)无正则化、(B) L1 正则化、L2 正则化和(D)弹性网络正则化的模型的热图:
面板 A 示出了没有应用正则化的第一层权重矩阵。我们可以看到大量的正负重量无特定模式地分散在各处。
面板 B 示出了应用了 L1 正则化的第一层权重矩阵。我们可以看到有更多的零值(黑色)权重。然而,在变量(行)级别没有特别强的模式,这是可以预期的,因为 L1 正则化独立地考虑每个权重的绝对值。
画面 C 示出了应用了 L2 正则化的第一层权重矩阵。这比非正则化的情况具有更多数量的较小量值的权重。
画面 D 示出了应用了弹性网正则化的第一层权重矩阵。对于这个数据集,弹性网正则化最终实现了所有考虑的正则化方法的最佳性能。它还产生了一个相当不错的第一层权重矩阵:所有的遗传变量都被“归零”,最亮的临床变量是“年龄”(这有点滑稽,因为我正在研究大约 40 年的心脏病风险,所以如果你在研究期开始时 80 岁开始,你将比 30 岁开始的人有更高的风险。)
最后,在面板 E 和 F 中,我们可以看到使用群组套索正则化训练的两个不同模型的结果。这些模型用不同的随机初始化进行训练,并最终找到不同的解决方案:
- 图 E 中的模型将所有的遗传变量“清零”,并保留了大部分临床变量(同样,与弹性网情况相似,权重最高的临床变量是“年龄”)。)在上面的结果表中,该模型被列为“套索组(1)”,并达到 0.690 精度、0.771 AUROC 和 0.767 AP。
- 图 F 中的模型最终“归零”了所有的临床变量,并试图使用遗传变量进行预测。最佳验证性能实际上是在第 15 个时期实现的,而不是第 61 个时期,因为在第 15 个时期,模型还没有完成杀死所有临床变量。在 epoch 15 时的性能是 0.605 精度、0.662 AUROC 和 0.670 AP,在模型决定要消除临床变量后,性能变得更差。
因此,这个实验也很好地展示了具有不同随机初始化的神经网络如何在同一数据集上找到不同的解决方案。
注意,在许多情况下,正则化的应用导致更好的测试集性能,这在这个例子中没有明确地示出。如果我在表现最好的“只有临床数据”模型中加入了正则化,也许会产生更高的性能。
结论
- L1、L2、弹性网和群组套索正则化可通过减少过度拟合来帮助提高模型在不可见数据上的性能。
- 回归中的 L1 正则化和用于神经网络的组套索正则化可以通过“归零”某些输入变量来产生更容易理解的模型。
- 在正则化神经网络模型中可视化带有热图的权重矩阵可以提供对不同正则化方法的效果的洞察。
关于特色图片
特色图片是 C.M. Russell 的一幅名为“牛群逃亡者”的油画,画的是牛仔试图套住一头公牛。牲畜套索也叫“套索”、“riata”、“reata”,或简称为“绳子”
原载于 2019 年 6 月 8 日http://glassboxmedicine.com。
梯度观点中的正则化[张量流中的手动反向传播]
正则化对渐变有什么影响?
GIF from this website
正则化就像上面展示的那只猫,当一些权重想要变得“大”时,我们惩罚它们。今天我想看看正则项给梯度带来了什么样的变化。下面是我们将要比较的不同正则化术语的列表。(θ是每层的重量。).
Z .基线 (无正则化) a .θ【岭回归】 b . ABS(θ)+sqrt(ABS(θ)(弹性网) c .θ (来自论文“ 【比较稀疏度】” e . ABS(θ)(p 值为 1 的 p-norm) f . sqrt(ABS(θ))(p-norm 带 p-的 (来自论文“**”* I .-tanh(θ)(来自论文“ 比较稀疏度” j*
简介
为了防止过拟合,或者控制过拟合的程度(过拟合的严重程度),我们使用正则化,例如去掉或增加 L1 或 L2 正则化项。正则化背后的一般思想(除了退出),是在最小化目标函数的同时最小化权重的大小,当然,一些正则化旨在创建‘稀疏’权重,这意味着大多数权重值为零。
接下来,对于神经网络架构中的任何训练过程,都有一些共同的元素,例如激活前后的值。相对于权重的梯度,以及传递到前面层的梯度。权重本身,以及使用 Adam 优化器时每个权重的动量值。
所以把两个和两个放在一起,正则项对那些值有什么样的影响?它们的均值、标准差、偏度、峰度和非零元素的数量,它们会随着基线表现增加、减少还是保持不变?
相关作品
关于如何解释正则化项,最有趣的观点之一是将其视为权重之前的贝叶斯。这篇的博文详细描述了我们理解正则化术语的不同观点。(我怀疑正则化的程度取决于先验的知情/不知情程度,我还认为随着训练的进行,最终可能性将对权重产生更大的影响。).
此外,如果有人对 L1 和 L2 正规化背后的基本直觉以及一些命名历史感兴趣,请查看此博客帖子。
实验设置
蓝色球体 →来自 STL 数据集的输入图像(20,96,96,3)的形状
黄色矩形 →带有 ReLU 激活的卷积层
红色正方形 →交叉熵损失项
整个实验只是一个分类任务,根据我们添加的正则项,黄色矩形在计算梯度时会有一个附加项。在继续之前,我希望澄清我将要用到的每个单词的意思。
**
结果
训练/测试准确性
**
当我们查看训练和测试数据的准确度图时,我们可以观察到…..
添加时达到最高训练精度:sqrt(θ)/θ*
添加时达到最高测试精度:-tanh(θ)
添加时达到最低性能:θ*
当我们添加术语 θ 时,每个权重的导数值就变成 1,我怀疑这可能会导致超调。
gradientp 的平均统计值(传递到上一层的梯度)
当我们查看传递到上一层的渐变值时,有一种颜色非常突出,那就是灰色。加上 -log(1+θ ) 这一项,似乎让梯度值变化很大。
梯度的平均统计值 w(相对于重量的梯度)
当我们将注意力集中在非零元素的数量上时,我们观察到,在没有任何正则化项的情况下,关于每个权重的梯度主要由零组成。(这也可能是造成收敛慢的原因。).
当我们把注意力集中在平均标准偏差值上时,我们注意到在训练的最后区域,粉红色和黄色的线相交。然而,案例 H(粉色)在训练/测试数据上的表现比案例 B(黄色)好得多。
层的平均统计数据(激活前的层值)
当我们查看每一层的值(激活函数之前)时,我们马上注意到,随着训练的继续,情况 C(绿色)的平均值不断下降。我不认为这种减少本身是一件坏事,但是,与其他情况相比,这是极端的,另外请注意,我们正在使用 ReLU 激活,这意味着任何小于零的值,都将被丢弃并被零取代。
层 a 的平均统计数据(激活后的层值)
我们已经知道,添加 -tanh(θ) (粉红色线)在测试图像上给了我们最好的结果,当我们将注意力集中在激活层之后的非零元素的数量时,情况 H(粉红色线)在其自己的区域中。
当其他案例高于或低于 60,000 时,奇怪的是案例 H 似乎集中在该区域。与其他情况相比,数据的内部表示更加稀疏。
重量的平均统计(每种情况下的重量值)
由于情况 C(绿线)过冲,我们得到了一个扭曲的图表,其中其他值被压缩,以适应情况 C 中重量的减少,因此在下一个图中,我已将情况 C 从平均重量图中移除。
移除后,我们可以清楚地看到不同权重值如何随时间变化。同样,我们注意到情况 H(粉线)位于它自己的区域,我不知道它为什么这样做,也没有意义,因为正则化的要点是最小化权重,为什么值比其他情况高?
矩的平均统计数据(Adam 优化器的动量部分)
从上面的图中,我们(也许能够)得出结论,情况 C(绿线)已经过冲。好像都是?或者说动量的大部分值为零。标准差都是零,表明动量内没有太多的变化。
讨论
我想以这句话开始这一部分,
我不能得出任何结论,这只是一个实验,因此从一个样本得出任何结论都是错误的。此外,我的实验的一个关键缺陷是,所有的权重没有被同等地初始化!我给出了完全相同的种子值和标准偏差(如下所示),但我不确定是否所有的权重都被同样初始化了。**
从所有这些实验来看,似乎没有规则可以保证一个模型在测试数据上表现良好。(或者会有更高的泛化能力)。然而,似乎有一个模型可以很好地概括的独特模式。
我将只关注情况 H(粉红色),通常,我们理解正则化是为了限制权重大小的增长,然而,从上图中我们可以清楚地看到情况 H 权重的平均值高于其他情况…所以…?问题就变成了它规范得好吗?使用 tanh 术语可能是这背后的原因吗?
但是另外,我们注意到在 ReLU 激活后,案例 H 的 layera 值比其他案例更稀疏。这意味着健康剂量的零被混合在内部表示中。我真的很想知道为什么案例 H 给出了最好的测试精度,目前只能用“因为它被很好地正则化了”来解释,但是我知道还有更多。
结论/代码
总之,权重大小和稀疏性之间的正确平衡似乎给出了良好的泛化性能。(手动波浪形)。
要访问 google collab 中的代码,请点击此处,要访问我的 GitHub 中的代码,请点击此处。
遗言
在做这些实验时,我不禁想到这些类型的正则化有一个(不那么关键的)缺陷。
它们都是被动正规化方法。
更具体地说,网络中的每个权重,不管它们位于何处,它们倾向于捕捉什么样的特征,它们都被正则化。我当然相信这是一个有趣的研究领域,例如,我们可以有一个简单的条件语句,即“如果权重的大小大于 x,则执行正则化”或更复杂的语句“如果该权重和类标签之间的互信息已经很高,则执行正则化”。我想知道这些方法将如何改变训练的整体动力。
最后,我要感谢我的导师,Bruce 博士给我推荐了论文“稀疏度的比较”。更多文章请访问我的网站。
附录(每种情况下每层的 GIF 动画)
情况 Z:按梯度、梯度、层、层 a、力矩、重量的顺序
**
情况 A:按梯度 p、梯度 w、层、层 A、力矩、重量顺序
**
情况 B:按梯度 p、梯度 w、层、层 a、力矩、重量顺序
**
情况 C:按梯度 p、梯度 w、层、层 a、力矩、重量顺序
**
情况 D:按梯度 p、梯度 w、层、层 a、力矩、重量顺序
**
情况 E:按梯度 p、梯度 w、层、层 a、力矩、重量顺序
**
情况 F:按梯度 p、梯度 w、层、层 a、力矩、重量顺序
**
情况 G:按梯度 p、梯度 w、层、层 a、力矩、重量顺序
**
情况 H:按梯度 p、梯度 w、层、层 a、力矩、重量顺序
**
情况一:按梯度、梯度、层、层、力矩、重量的顺序
**
情况 J:按梯度 p、梯度 w、层、层 a、力矩、重量的顺序
**
附录(衍生品)
参考
- n .布鲁斯(2016)。尼尔·布鲁斯。尼尔·布鲁斯。检索于 2019 年 1 月 4 日,来自http://www.scs.ryerson.ca/~bruce/
- Hurley 和 s . Rickard(2008 年)。稀疏度的比较。arXiv.org。检索于 2019 年 1 月 4 日,来自https://arxiv.org/abs/0811.4706
- 用 Python 进行数值和科学计算:用 Python 和 Matplotlib 创建子图。(2019).python-course . eu . 2019 年 1 月 4 日检索,来自https://www . python-course . eu/matplotlib _ multiple _ figures . PHP
- SciPy . stats . Kurt osis—SciPy v 1 . 2 . 0 参考指南。(2019).Docs.scipy.org。检索于 2019 年 1 月 4 日,来自https://docs . scipy . org/doc/scipy/reference/generated/scipy . stats . Kurt osis . html
- scipy.stats.skew — SciPy v0.13.0 参考指南。(2019).Docs.scipy.org。检索于 2019 年 1 月 4 日,来自https://docs . scipy . org/doc/scipy-0 . 13 . 0/reference/generated/scipy . stats . skew . html
- numpy.count _ 非零—NumPy 1.15 版手册。(2019).Docs.scipy.org。2019 年 1 月 4 日检索,来自https://docs . scipy . org/doc/numpy-1 . 15 . 1/reference/generated/numpy . count _ 非零值. html
- 数组?,E. (2017)。高效计算 numpy 数组中的零元素?。堆栈溢出。检索于 2019 年 1 月 4 日,来自https://stack overflow . com/questions/42916330/efficiency-count-zero-elements-in-numpy-array
- 解析,S. (2013)。语法错误:分析时出现意外的 EOF。堆栈溢出。检索于 2019 年 1 月 4 日,来自https://stack overflow . com/questions/16327405/syntax error-unexpected-eof-while-parsing
- Matplotlib . py plot . legend-Matplotlib 3 . 0 . 2 文档。(2019).Matplotlib.org。检索于 2019 年 1 月 4 日,来自https://matplotlib . org/API/_ as _ gen/matplotlib . py plot . legend . html
- 行与列——谷歌搜索。(2019).Google.com。2019 年 1 月 4 日检索,来自https://www.google.com/search?q=row+vs+column&rlz = 1 C1 chbf _ enca 771 ca 771&OQ = row+vs+col&aqs = chrome . 0.35 i39 j 69 I 60j 69 I 57j 0l 3.2289j 1j 7&sourceid = chrome&ie = UTF-8
- 图例指南— Matplotlib 2.0.2 文档。(2019).Matplotlib.org。检索于 2019 年 1 月 4 日,来自https://matplotlib.org/users/legend_guide.html
- 正则项导数的随机注释。(2019).中等。检索于 2019 年 1 月 4 日,来自https://medium . com/@ SeoJaeDuk/archived-post-random-notes-for-derivative-for-regulation-terms-1859 B1 faada
- IPython r .(2013 年)。IPython 中释放大数组内存。堆栈溢出。检索于 2019 年 1 月 5 日,来自https://stack overflow . com/questions/16261240/releasing-memory-of-huge-numpy-array-in-ipython
- 内置神奇命令— IPython 7.2.0 文档。(2019).ipython . readthe docs . io . 2019 年 1 月 5 日检索,来自https://ipython . readthe docs . io/en/stable/interactive/magics . html
- j . Chapman(2017 年)。如何用 Python 制作 gif?多余的六分仪。检索于 2019 年 1 月 5 日,来自http://superfluoussextant.com/making-gifs-with-python.html
- 岭回归、套索和弹性网之间的区别是什么?。(2017).兼收并蓄的秘传。检索于 2019 年 1 月 5 日,来自https://blog . alexlenail . me/what ' s-the-difference-the-ridge-regression-the-lasso-and-elastic net-EC 19 c 71 c 9028
- (2019).Web.stanford.edu。检索于 2019 年 1 月 5 日,来自https://web . Stanford . edu/~ hastie/Papers/b 67.2% 20% 282005% 29% 20301-320% 20 Zou % 20&% 20 hastie . pdf
- 面向数据科学的 L1 和 L2 正则化方法。(2017).走向数据科学。检索于 2019 年 1 月 5 日,来自https://towards data science . com/L1-and-L2-regulation-methods-ce 25 e 7 fc 831 c
- 岭回归、套索和弹性网之间的区别是什么?。(2017).兼收并蓄的秘传。检索于 2019 年 1 月 5 日,来自https://blog . alexlenail . me/what ' s-the-difference-the-ridge-regression-the-lasso-and-elastic net-EC 19 c 71 c 9028
- STL-10 数据集。(2019).Cs.stanford.edu。检索于 2019 年 1 月 5 日,来自https://cs.stanford.edu/~acoates/stl10/
- plot,H. (2010 年)。如何更改 matplotlib 绘图的字体大小?堆栈溢出。检索于 2019 年 1 月 5 日,来自https://stack overflow . com/questions/3899980/how-to-change-the-font-size-on-a-matplotlib-plot
- matplotlib?,H. (2015)。如何使用 matplotlib 在同一行中绘制多个图形?。堆栈溢出。检索于 2019 年 1 月 5 日,来自https://stack overflow . com/questions/34291260/how-can-I-plot-multiple-figure-in-the-same-line-with-matplotlib
- 正文,I. (2016)。IPython 笔记本键盘快捷键搜索文本。堆栈溢出。检索于 2019 年 1 月 5 日,来自https://stack overflow . com/questions/35119831/ipython-notebook-keyboard-shortcut-search-for-text
- 创建和导出视频剪辑— MoviePy 0.2.3.2 文档。(2019).zulko . github . io . 2019 年 1 月 5 日检索,来自https://zulko . github . io/movie py/getting _ started/video clips . html
- 用 Python 制作视频文件的 gif—_ _ del _ _(self)。(2014).zulko . github . io . 2019 年 1 月 5 日检索,来自http://zulko . github . io/blog/2014/01/23/making-animated-gifs-from-video-files-with-python/
权重观点中的正则化[张量流中的手动反向传播]
不同的正则化如何影响最终的权重值?
GIF from this website
我要感谢我的导师布鲁斯博士鼓励我进一步研究这个想法。此外,我想感谢我的实验室成员,在瑞尔森视觉实验室、贾森关于正规化的有益讨论。
更多类似的文章,请访问我的网站, Jaedukseo.me 。
简介
为了防止我们的模型过度拟合,我们可以使用不同种类的正则化技术。其中一种技术是在我们想要优化的损失函数中加入一个正则项。因此,当我们对模型中的权重求导时,我们会对权重添加额外的梯度。
但是不同的正则项如何影响权重呢?更具体地说,它会如何影响价值观的传播?意味着直方图的形状。
实验设置
蓝色球体 →输入图像数据( STL10 或 CIFAR10 )
黄色矩形 →带 ReLU 激活的卷积层
红色方块 →交叉熵损失项用于分类
网络本身只由六层组成,并不是一个大网络。然而,我们将使用两个不同的数据集,CIFAR 10 和 STL 10。
此外,我们将在有和没有批量标准化的情况下训练网络 10 集,这是为了观察相同的现象是否会反复发生。(现象是,权重收敛到直方图的特定形状。).最后,下面是我们要比较的所有正则项的列表。
Z:基线(无正则化)
A:ABS(Theta)
B:Theta
C:sqrt(Theta)
D:—log(1+Theta)
E:—tanh(Theta)
F:—tanh(Theta)
G:—tanh(ABS(Theta))
H:—tanh(ABS(Theta)
I:sin(Theta)
J:ABS(sin
结果位移
最左边的 gif 显示了 10 集的重量直方图和粉红色的平均直方图。
如上所述,从红色开始,它代表使用 Adam optimizer 150 个周期后的最终重量。粉色直方图代表平均重量值的直方图。现在放大可视化中最右边的图像。
每个方框显示了每一层的最终直方图,最终图显示了最大/最小/平均训练(红色)/测试(蓝色)性能。
结果
Z:基线(无调整)
without Batch Normalization (STL)
With Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
答:ABS(θ)
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
B:θ
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
C: sqrt(Theta )
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
D:——log(1+Theta)
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
E:——tanh(Theta)
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
F:--tanh(Theta)
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
G:——tanh(ABS(Theta))
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
H: -tanh(abs(Theta) )
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
I:sin(θ)
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
J: abs(sin(Theta))
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
K:对数(θ)
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
L: Theta * log(Theta )
without Batch Normalization (STL)
with Batch Normalization (STL)
without Batch Normalization (CIFAR)
with Batch Normalization (CIFAR)
讨论/代码
虽然没有任何明确的证据或定理,我可以从这个实验中证明。我能够做出一些经验性的观察。
- 批量标准化(没有任何 alpha 或 beta 参数)很可能导致模型过度拟合。
- 增加批次归一化,使训练更加稳定。此外,它还使权重收敛于类高斯分布。(我们怀疑这可能和中心极限定理有关。)
- 小批量导致更严重的过度拟合。
- 在权重的稀疏性和过度拟合程度之间似乎存在微弱的负相关。(如果权重值稀疏,意味着权重中有许多零值,过度拟合程度越低)。
事后看来,最后的观察非常有意义,如果网络权重本身包含大量零值,并且有一些约束将权重保持在那些区域中,那么网络自然很难过度拟合。
我想提出的一些有趣的联系是关于我们的大脑是如何编码视觉输入的。从多个实验中,我们知道 V1 细胞创建了给定视觉输入的稀疏表示,这与具有稀疏权重集非常不同,然而,在稀疏的名义下,它似乎有一些联系。也许,仅仅是也许,对于任何有效的学习模型来说,可能需要一个好的稀疏的权重集。
要访问 CIFAR 10 的代码请点击这里,要访问 STL 10 的代码请点击这里。
最后,如果您希望访问 CIFAR 10 和 STL 10 的每一层的完整结果,无论是否进行批规格化。
请点击此处访问 CIFAR 10 的完整结果。
请点击此处访问 STL 10 的完整结果。
超级有用的数学推理,关于你完全(不应该)信任的每个正则化子在做什么
在这一节中,我想简单介绍一下每个正则项对权重的影响。但是,请注意,这不是一个数学定义。直线代表调节项的值,而虚线代表梯度大小。
上面显示了正则化项 abs(x),x,和 sqrt(x)的样子以及它的导数。需要注意的一点是,当导数的幅度结束时,特别是对于 abs(x),我们注意到,当 x 位于 0 时,梯度的幅度停止。
因此,该模型将不得不平衡它应该具有多少稀疏权重和它将从没有稀疏权重得到多少惩罚。而具有 x 正则项的网络可以承受多个小数量级的权重。
对于涉及 log 的正则化项,我们注意到,由于梯度增加接近无穷大,训练会极不稳定。(对于正无穷大和负无穷大)
对于带有双曲正切的正则化项,我们可以看到只有某些区域的梯度值大于零。
最后,对于 sin 类型的正则项,我们可以看到,网络试图收敛到某些数字,目标并不真正涉及稀疏性。
最后的话
在 ICA 中,目标之一是对给定数据进行稀疏表示。虽然使网络的权重稀疏,可以达到类似的结果,我想知道他们的性能会有什么不同。
具有稀疏性约束可以在增加神经网络的泛化能力方面发挥巨大作用。然而,不同风格的稀疏约束可能是一个更重要的问题来解决。
更多类似的文章,请访问我的网站, Jaedukseo.me 。
参考
- 笔记本,o .,&达利,S. (2017)。覆盖 jupyter 笔记本中以前的输出。堆栈溢出。检索于 2019 年 1 月 15 日,来自https://stack overflow . com/questions/38540395/overwrite-previous-output-in-jupyter-notebook
- n .布鲁斯(2016)。尼尔·布鲁斯。尼尔·布鲁斯。检索于 2019 年 1 月 15 日,来自http://www.scs.ryerson.ca/~bruce/
- 在和 Alpha 之间填充— Matplotlib 3.0.2 文档。(2019).Matplotlib.org。检索于 2019 年 1 月 15 日,来自https://matplotlib . org/gallery/recipes/fill _ between _ alpha . html
- Matplotlib . py plot . plot-Matplotlib 3 . 0 . 2 文档。(2019).Matplotlib.org。检索于 2019 年 1 月 15 日,来自https://matplotlib . org/API/_ as _ gen/matplotlib . py plot . plot . html
- plots,h .,Raviv,o .,Castro,s .,Isaac,é。,& Twerdochlib,N. (2010 年)。在 matplotlib 图中隐藏轴文本。堆栈溢出。检索于 2019 年 1 月 17 日,来自https://stack overflow . com/questions/2176424/hiding-axis-text-in-matplotlib-plots
- NumPy . histogram—NumPy 1.15 版手册。(2019).Docs.scipy.org。检索于 2019 年 1 月 17 日,来自https://docs . scipy . org/doc/numpy-1 . 15 . 0/reference/generated/numpy . histogram . html
- Matplotlib . axes . axes . hist 2d-Matplotlib 3 . 0 . 2 文档。(2019).Matplotlib.org。检索于 2019 年 1 月 17 日,来自https://matplotlib . org/API/_ as _ gen/matplotlib . axes . axes . hist 2d . html
- matplotlib——条形图、散点图和直方图——生物学家的实用计算。(2019).People.duke.edu。检索于 2019 年 1 月 17 日,来自http://people . duke . edu/~ CCC 14/pcfb/numpympl/matplotlibbarplots . html
- mplot3d 示例代码:bars3d_demo.py — Matplotlib 1.3.1 文档。(2019).Matplotlib.org。检索于 2019 年 1 月 17 日,来自https://matplotlib . org/1 . 3 . 1/examples/mplot3d/bars 3d _ demo . html
- mplot3d 示例代码:poly 3d _ demo . py—Matplotlib 1 . 3 . 0 文档。(2019).Matplotlib.org。检索于 2019 年 1 月 17 日,来自https://matplotlib . org/1 . 3 . 0/examples/mplot3d/polys3d _ demo . html
- 直方图?,P. (2017)。绘制一系列直方图?。Mathematica 堆栈交换。检索于 2019 年 1 月 17 日,来自https://Mathematica . stack exchange . com/questions/158540/plot-a-sequence-of-histograms
- 图形?,W. (2013)。“np.histogram”和“plt.hist”有什么区别?为什么这些命令不绘制相同的图形?。堆栈溢出。检索于 2019 年 1 月 17 日,来自https://stack overflow . com/questions/20531176/what-is-the-difference-between-NP-histogram-and-PLT-hist-why-dont-these-co
- NumPy . Lin space—NumPy 1.15 版手册。(2019).Docs.scipy.org。检索于 2019 年 1 月 17 日,来自https://docs . scipy . org/doc/numpy-1 . 15 . 0/reference/generated/numpy . linspace . html
- 结果,第(2017)页。PLT . hist()vs NP . histogram()-意外结果。堆栈溢出。检索于 2019 年 1 月 17 日,来自https://stack overflow . com/questions/46656010/PLT-hist-vs-NP-histogram-unexpected-results
- plot,c .,& Navarro,P. (2012 年)。更改 matplotlib 3D 绘图的轴平面的背景颜色。堆栈溢出。检索于 2019 年 1 月 17 日,来自https://stack overflow . com/questions/11448972/changing-the-background-color-of-a-matplotlib-3d-plot-planes/12623360
- NumPy . arange—NumPy 1.11 版手册。(2019).Docs.scipy.org。检索于 2019 年 1 月 17 日,来自https://docs . scipy . org/doc/numpy-1 . 11 . 0/reference/generated/numpy . arange . html
- LLC,I. (2019)。命令行工具:Convert @ ImageMagickImagemagick.org。检索于 2019 年 1 月 17 日,来自 https://imagemagick.org/script/convert.php
- 使用 Python 的 Matplotlib 制作 3D 绘图动画。(2012).糖分过高。检索于 2019 年 1 月 17 日,来自https://zulko . WordPress . com/2012/09/29/animate-your-3d-plots-with-python-matplotlib/
- 鼠,H. (2017)。如何在 python 中旋转 3d 绘图?(或作为动画)使用鼠标旋转三维视图。堆栈溢出。检索于 2019 年 1 月 17 日,来自https://stack overflow . com/questions/43180357/how-to-rotate-a-3d-plot-in-python-or-as-a-a-animation-rotate-3d-view-using-mou?noredirect=1 & lq=1
- 贾,S. (2019)。贾森——概述。GitHub。检索于 2019 年 1 月 28 日,来自https://github.com/SenJia
- 瑞尔森视觉实验室。(2018).Ryersonvisionlab.github.io 于 2019 年 1 月 28 日检索,来自https://ryersonvisionlab.github.io/
- STL-10 数据集。(2019).Cs.stanford.edu。检索于 2019 年 1 月 28 日,来自https://cs.stanford.edu/~acoates/stl10/
- https://www.cs.toronto.edu/~kriz/cifar.html
- 德斯莫斯图表。(2019).德斯莫斯图形计算器。检索于 2019 年 1 月 29 日,来自https://www.desmos.com/calculator
神经网络的正则化技术
在我们的上一篇文章中,我们学习了前馈神经网络以及如何设计它们。在这篇文章中,我们将学习如何解决机器学习领域中出现的一个最核心的问题,即如何使我们的算法不仅找到训练集的完美匹配,而且找到测试集的完美匹配。当一个算法在训练集上表现很好,但在测试集上表现很差时,该算法被称为在训练数据上过度拟合。毕竟,我们的主要目标是在从未见过的数据上表现良好,即减少过度拟合。为了解决这个问题,我们必须使我们的模型在训练数据上一般化,这是使用各种正则化技术完成的,我们将在本文中学习。
以增加训练误差为代价减少测试集误差的策略或技术统称为正则化。深度学习实践者可以使用许多这样的技术。事实上,开发更有效的正则化策略一直是该领域的主要研究工作之一。
正则化可以定义为我们对学习算法进行的任何修改,其目的是减少其泛化误差,而不是训练误差。这种正则化通常是通过对机器学习模型施加一些额外的约束来完成的,例如对参数值添加限制,或者通过在目标函数中添加额外的项,这些额外的项可以被认为对应于对参数值的软约束。如果选择正确,这些可以减少测试误差。一个有效的规则化者被认为是通过显著减少方差而不过度增加偏差来进行盈利交易的人。
参数范数惩罚
这种技术是基于限制模型的容量,通过添加一个参数范数惩罚到目标函数 j。
其中α是一个超参数,它对范数惩罚ω的相对贡献进行加权。将 alpha 设置为 0 意味着没有正则化,alpha 值越大,正则化程度越高。
对于神经网络,我们选择使用参数范数惩罚,该惩罚对仿射变换的权重进行惩罚,并使偏差不被调节。这是因为偏差比权重需要更少的数据来精确拟合。由于权重用于表示两个变量之间的关系,并要求在各种条件下观察两个变量,而偏差仅控制单个变量,因此可以不进行调整。
L2 参数正则化
这种正则化通常被称为权重衰减。该策略通过添加正则化项ω来驱动权重更接近原点,正则化项ω定义为:
这种技术也称为岭回归或吉洪诺夫正则化。
正则化后的目标函数表示为:
相应的参数梯度:
更新权重的单一梯度步骤:
我们可以看到,在执行通常的梯度更新之前,权重衰减项现在在每一步上以常数因子倍增地收缩权重向量。
L1 正则化
这里正则项定义为:
这使得我们的目标函数为:
相应的梯度:
通过观察梯度,我们可以注意到梯度是如何通过符号等于符号(wi)的常数因子来缩放的。
数据集扩充
使模型一般化的最好和最简单的方法是在大量数据上训练它,但大多数情况下我们只能获得有限的数据。一种方法是创建假数据,并将其添加到我们的训练数据集中,对于某些领域来说,这相当简单明了。
这种方法主要用于分类问题,分类器需要接受复杂的高维输入 x,并用单个类别标识 y 对其进行总结。这意味着分类器面临的主要任务是对各种变换保持不变。我们可以通过转换训练集中的 x 输入来轻松生成新的(x,y)对。这种方法并不总是适合于诸如密度估计任务的任务,除非我们已经解决了密度估计问题,否则很难生成虚假数据。
数据集扩充是用于诸如图像分类或对象识别的计算机视觉任务的非常流行的方法,因为图像是高维的,并且包括大量变化因素,其中许多可以容易地模拟。像在每个方向上将训练图像平移几个像素、旋转图像或缩放图像这样的操作通常可以极大地提高泛化能力,即使已经通过使用卷积和池化技术将模型设计为部分平移不变的。
噪声鲁棒性
噪声通常作为数据集扩充策略引入到输入中。在模型的输入端添加具有无穷小方差的噪声相当于对权重的范数施加惩罚。噪声注入比简单地收缩参数要强大得多,尤其是当噪声被添加到隐藏单元时。
噪声被用于正则化模型的另一种方式是将其添加到权重中。这种技术主要用于递归神经网络。这可以解释为贝叶斯推理在权重上的随机实现。
半监督学习
在半监督学习中,来自 P (x)的未标记样本和来自 P (x,y)的标记样本都用于估计 P (y | x)或从 x 预测 y。深度学习的上下文中,半监督学习通常指学习一种表示 h = f (x)。目标是学习一种表示法,这样来自同一个类的例子就有相似的表示法。无监督学习提供了关于如何在表示空间中对训练样本进行分组的线索。在应用我们的分类器之前,使用主成分分析作为预处理步骤是这种方法的一个例子。
代替对无监督和有监督组件使用单独的模型,可以构建这样的模型,其中 P (x)或 P(x,y)的生成模型与 P(y | x)的判别模型共享参数。现在,P(x)的结构与 P(y | x)的结构以一种被共享参数化捕获的方式相连接。通过控制在总标准中包含多少生成标准,可以找到比使用纯生成或纯区别训练标准更好的折衷。
多任务学习
多任务学习是一种通过汇集几个任务中产生的例子来提高概括能力的方法。同样地,额外的训练示例对模型的参数施加更大的压力,使其趋向于概括得好的值,当模型的一部分在任务之间共享时,模型的该部分更倾向于好的值,通常产生更好的概括。
该模型一般可分为两类部分和相关参数:
特定于任务的参数只有从其任务的实例中受益才能实现良好的泛化。
所有任务共享的通用参数受益于所有任务的池化数据。
提前停止训练
当在足够大的数据集上训练大型模型时,如果训练进行了很长时间而不是增加模型的泛化能力,则会增加过度拟合。在训练过程中,训练误差不断减少,但在某个点之后,验证误差开始增加,因此表明我们的模型已经开始过度拟合。
Loss comparison of training and Validation
考虑提前停止的一种方式是作为一种非常有效的超参数选择算法。提前停止训练的想法是,一旦验证误差开始增加,我们就冻结参数并停止训练过程。或者,我们也可以在每次验证集上的误差改善时存储模型参数的副本,并在训练终止时返回这些参数,而不是最新的参数。
早期停止比权重衰减具有优势,早期停止自动确定正则化的正确量,而权重衰减需要具有不同超参数值的许多训练实验。
制袋材料
Bagging 或 bootstrap 聚合是一种通过组合几个模型来减少泛化误差的技术。想法是分别训练几个不同的模型,然后让所有的模型对测试示例的输出进行投票。这是机器学习中一个叫做模型平均的一般策略的例子。采用这种策略的技术是已知的
作为集合方法。这是一种有效的方法,因为不同的模型不会产生相同类型的错误。
打包包括构建 k 个不同的数据集。每个数据集都具有与原始数据集相同数量的示例,但是每个数据集都是通过从原始数据集进行替换采样来构建的。这意味着,每个数据集很可能会丢失原始数据集中的一些示例,并且还包含几个重复的示例。然后,在数据集 I 上训练模型 I。每个数据集中包括的示例之间的差异导致训练模型之间的差异。
拒绝传统社会的人
Dropout 是一种计算成本低廉但功能强大的正则化方法,dropout 可以被认为是一种使 bagging 适用于非常多的大型神经网络的方法。bagging 方法不能直接应用于大型神经网络,因为它涉及训练多个模型,并对每个测试示例评估多个模型。因为训练和评估这样的网络在运行时间和存储器方面是昂贵的,所以这种方法对于神经网络是不切实际的。Dropout 为训练和评估指数型神经网络的袋装集合提供了一种廉价的近似方法。Dropout 训练由所有子网络组成的集合,这些子网络可以通过从底层基础网络中移除非输出单元来形成。
在大多数现代神经网络中,基于一系列仿射变换和非线性,我们可以通过将其输出值乘以零来有效地从网络中删除一个单元。这一过程需要对模型(如径向基函数网络)稍加修改,径向基函数网络采用单元状态和某个参考值之间的差值。在这里,我们呈现
为了简单起见,dropout 算法是用零的乘法来表示的,但是它可以被简单地修改以与从网络中移除单元的其他操作一起工作。
辍学训练和打包训练不太一样。在装袋的情况下,模型都是独立的。在丢失的情况下,模型共享参数,每个模型从父神经网络继承不同的参数子集。这种参数共享使得用易处理的存储量来表示指数数量的模型成为可能。dropout 的一个优点是计算量非常小。在训练期间使用丢弃只需要每次更新每个例子 O(n)次计算,以生成 n 个随机二进制数并将它们乘以状态。辍学的另一个显著优势是,它不会显著限制可以使用的模型或培训程序的类型。它几乎适用于任何使用分布式表示的模型,并且可以通过随机梯度下降进行训练。
对抗性训练
在许多情况下,神经网络似乎已经达到了人类水平的理解任务,但为了检查它是否真的能够在人类水平上执行,网络在对立的例子上进行测试。对立例子可以定义为,如果对于数据点 x 附近的输入 a,模型输出在 a 处非常不同,那么 a 被称为对立例子。通过使用优化过程有意地构造对立的例子,并且模型在这些例子上具有接近 100%的错误率。
对抗训练有助于模型的正则化,因为当模型在用对抗例子扩充的训练集上被训练时,它改善了模型的泛化。
数据科学和机器学习中的法规和伦理
Artwork by: Nina Michailidou
不管我们喜欢与否,机器学习改变了我们的生活。
统计推断、强化学习、深度神经网络和其他术语最近吸引了很多关注,事实上,这是有根本原因的。统计推断扩展了我们决策的基础,并改变了决策的审议过程。这种变化构成了从我称之为前数据科学到随后的数据科学时代的本质区别。在数据科学时代,决策是基于数据和算法做出的。通常情况下,决策完全由算法做出,只有在收集、清理、构建数据和建立算法选择框架的过程中,人类才是重要的参与者(通常情况下,算法本身是通过一个指标来选择的)。鉴于这一根本性变化,在数据科学时代做出决策时,密切关注决策的扩展基础以及在考虑这一扩展基础时思维过程的变化非常重要。
“所有的模型都是错的,但有些是有用的。”
额外的步骤导致:
"所有的模型都是错误的,有些是有用的,但有些也可能是危险的."
另一方面,大量研究证明,人类行为——以及决策——是情境驱动的[cit]。当将人类的准确性与算法的预测进行比较时,算法的预测准确性一贯甚至将专家的判断打得落花流水。对这一点的详尽讨论超出了本文的范围,但是在附录 1、中有一些不错的资料,以防读者有兴趣进一步研究这个主题。
好吧,接下来是什么?就像每一次技术进步一样,在某个时刻,关于西方资本主义最关键的辩论,一些悄悄话会变成声音:我们把监管的门槛放在哪里?我们需要更多的监管吗?具体来说:我们应该审核我们的算法和数据,以确保它们满足准确性、有效性和偏差的最低要求吗?
为什么监管至关重要?
每个统计学习算法都应该满足三个要求,即准确性、有效性和偏倚。简而言之,准确性表示模型的性能与基于可用数据集的可接受基线或预定义正确答案的比较。有效性考虑如何收集数据的更广泛背景,以及由于测量误差、校准失败等,数据在多大程度上没有反映真实世界。偏差是指对特定人群的预测系统性地偏低或偏高的情况,通常是由人工标注和不完善的数据质量、缺失数据,以及更一般地说,采样偏差和模型设定错误造成的。
那么,我们可以安全地假设算法应该被审计,并且它们满足上面提到的要求吗?最后,我认为与社会和健康决策系统相关的算法需要监管。然而,从数据科学的角度来看,我们应该以更广阔的视角开始开发算法,而不是仅仅依赖 MSE 和 AUC 来说明准确性。遵循并向风险评估工具延伸负责任的机器学习原则,算法需要确保我们的预测满足以下要求:
- 数据科学和机器学习过程应该通过设计包括人在内的系统来尽可能地增加人的干预。此外,特别是对于风险评估工具,统计决策工具的关键挑战之一是自动化偏差现象,即机器提供的信息被认为是内在可信的,不容置疑的。这可能导致人类过度依赖自动化系统的准确性或正确性。最后,主题专家应该能够验证结果和过程。他们还应该接受足够的教育,以便理解伴随算法开发的潜在假设。
- 统计模型中的偏差必须在估计值的方差容许范围内进行测量和减轻。在风险评估工具中训练算法时应该考虑的一个关键因素是所谓的遗漏变量偏差问题。每当从不包括所有相关因果因素的数据中训练模型时,就会出现遗漏变量偏差。
- 工具不得合并多个不同的预测。对于不同的风险,应衡量不同的得分,而不是反映各种结果风险的单一风险。
- 模型再现性。使机器学习模型可再现需要抽象其组成组件的过程,即数据、配置/环境和计算图。如果把这三点都抽象出来,就有可能有模型再现性的基础。决定抽象级别通常是至关重要的,因为可以专注于构建非常复杂的层来抽象具有特定数据输入/输出格式的多个机器学习库。
- 信任靠隐私。适当级别的隐私。与用户和相关利益方建立信任的一个基本方法是通过展示适当的流程和技术来保护个人数据。技术专家应该做出明确的努力来理解所涉及的元数据的潜在含义,以及元数据是否会暴露相关用户或利益相关者的意外个人信息。
给我问题而不是解决方案,尽管有时后者会有所帮助。
为了应对这些挑战并降低其对业务的风险(包括道德实践的实施),通过算法开发风险评估的公司应在以下方面投入时间:
首先,在探索性数据分析 (EDA)阶段,应进行适当的数据分析,以确定数据不平衡。此外,对特征进行相关性分析以及适当地平衡训练-验证-测试分割是非常重要的。
第二个,模型可解释性至关重要,尤其是对于复杂的数据集,它包含了所谓的黑色模型(梯度推进、神经网络等)。).为此,开发了不同的方法,包括 SHapley Additive explainions(SHAP)和 LIME 等模型。前者基于可能的联盟如何有助于作为一个整体的群体的影响的想法,这是一个从合作博弈论借用的概念,而后者侧重于局部近似。(LIME 更快,但不太准确,目前不在讨论范围内)。而且很少有像 Pachyderm 和 ModelDB 这样优秀的开源库,可以帮助数据科学家和机器学习工程师在透明性和模型再现性的基础上进行构建。
第三,当将模型投入生产时,应结合性能的连续诊断,以捕捉与模型训练数据集的任何偏差。例如,学习系统的行为应该包括随着时间的推移腐蚀发生的漂移。此外,KL Divergence 和 Wasserstein 等分数也应该用于捕捉数据偏差。
最后、在处理关键事件诊断和行动时,应始终考虑自动化偏差。结果应该由主题专家阅读,他们可以批判性地质疑结果并理解输入/输出和遵循的过程。
Ps 1:这篇文章的内容旨在告诉读者一个相当活跃的话题,所有数据科学家迟早都要解决这个问题。我试图涵盖我用作参考资料的大部分材料,以供希望进一步加深知识的读者参考。
Ps 2:请联系我以获得更正和讨论点。
参考文献
【2】:https://ethical.institute/
[4]:https://sloanreview . MIT . edu/article/the-regulation-of-ai-should-organizations-be-worried/
[5]:https://sloanreview . MIT . edu/article/the-risk-of-machine-learning-bias-and-how-to-prevent-it/
用 NLP 重构 Plutarch:第 1 部分
普鲁塔克的《高贵的希腊人和罗马人的生活》通过自然语言处理;这部分包括 NLTK 和词云
序文
普鲁塔克的《高贵的希腊人和罗马人的生活,也叫平行生活或简称普鲁塔克的《生活,是一系列著名的古希腊人和罗马人的传记,从忒修斯和吕库古到阿非利加努斯·戈狄亚努斯二世。在这篇文章/教程中——继上一篇关于文本生成的文章之后——我将继续这种文本类型,并使用一些自然语言处理技术来探索这本书。
为了便于复制,我修改了代码以适应 Google Colab,并强调了平台的独特之处——否则整个代码可以在 Python 3.6+上本地运行。代码在整篇文章中依次出现,Github 文件的链接嵌入在文章的最后,因为我可能会跳过一些次要的细节或代码。
探测
首先,让我们设置基础…
在 Colab 上,让我们将运行时类型更改为 GPU,然后导入 OS 库并保存+打印文件路径以备将来参考:
让我们将文本导入到 Google Colab 驱动器中——我们需要记住,我们在那里的文件是短暂的,我们需要在每次使用该平台较长时间后上传它们:
当执行这段代码时,我们将看到 Colab 上传文件,然后我们可以单击左边的 Colab Files 选项卡,以确保该文件与 Google 的默认示例数据目录在一起。
在这个阶段,我们将把重点放在单词级分析上,即忽略字符和句子级。因此,我们需要将文本分割成单独的单词——这就是标记化。此外,我们需要删除英语停用词,并可以对词频进行排序——所有这些都是通过使用 NLTK 和 matplotlib 实现的。
在下面的代码中,我们读取原始文本文件,对其进行标记化,删除英语停用词(NLTK 标准加上一些额外的词),绘制一个包含 40 个最常用词的图表,并将标记化的文件保存为“Plutarch_tokens.txt”以供将来使用:
整篇文章超过 674,000 字,下面是 40 个最常用单词的图表:
不出所料,凯撒是最受皇帝们欢迎的,紧随其后的是庞贝——他们是仅有的两个进入前 40 名的人。没有真正读过这本书——向那些非常熟悉文本的人道歉——人们可以很容易地感觉到,由于“战争”、“敌人”、“军队”、“朋友”、“士兵”、“权力”和“战斗”等词的出现频率,这本书在很大程度上专注于战争和冲突;我推测甚至“男人”这个词——第三个最常见的——也经常被用来指士兵。
成对的单词怎么样?
我推测“三百”——第二个最常见的词——在一个或几个例子中指的是传说中的塞莫皮莱战役(其主要历史来源是希罗多德)和在那里战斗的三百名斯巴达战士,但经过“低技术”检查(查找文本中的表达),结果证明情况并非如此。这个数字似乎在各种情况下普遍流行:罗穆卢斯征募所有成年人携带武器进入军事公司(又名军团),每个公司由三千名步兵和三百名骑兵组成,Numa 重新计算一年的天数,建议饲养蜜蜂时不要把它们放在三百英尺内,Mucius 智胜 Porsenna,威胁(不存在)三百名罗马人等待攻击,三百艘船来支持 Demetrius,Cato 召集三百名罗马人作为他的议会等。所有类型的数字评估在整个作者的文本中都很流行——有几个是最常见的二元模型,有几个是最常见的三元模型。
词干化和词汇化
为了更深入的理解,我们可能不需要担心基本相同的单词的时态和其他形式/派生词。这时词干化和词汇化就来帮忙了。
词干化通常通过砍掉单词的一部分(例如,以“-ing”结尾,复数结尾)或改变成可能与实际单词不同的词干形式(例如,“citi”代表“城市”和“city”)来帮助将单词简化为其词根(词干)。
词汇化与词干化不同,它关心单词的预期含义(包括词性和使用该单词的上下文),找到词根只是一部分,因此它是一种更复杂的算法,相对于词干化可能有更大的发展空间。幸运的是,在我们的例子中,词干化和词汇化都很容易应用,这是 NLTK 的优点:
我们会注意到,原始标记化文本有 20,214 个唯一单词,平均 6.48 个字母,而词汇化文本有 17,864 个,平均 6.34 个字母,词干化文本有 12,722 个,平均 5.49 个字母;砍真的在后一个里表现出来了。现在,我们有三组标记可供选择,以进行进一步的分析。
以上代码如下:
词云
单词云是可视化文本的一种很好的方式,但在处理大型书籍时显然有其局限性——很难在一个计算机屏幕上看到 20,000+的单词。此外,可能不属于 NLTK 或 wordcloud 库的无用(用于频率计数)单词可能会脱颖而出,并从其他单词那里夺走不动产——幸运的是,NLTK 和 wordcloud 库都可以轻松增加它们的停用词;前者的调整在前面展示过,后者包含在 Github 笔记本中。
让我们在标记化的文本上运行基本的单词云:
请注意,当我使用预定义的停用词时,没有必要将它包含在代码中,因为文本本身就是停用词。然而,我想保留这一行作为提醒,以防单词 cloud 独立于 NLTK 运行,或者需要应用库自己的停用词。
现在让我们运行词干词的词云:
wordcloud library 的一个很酷的功能是叠加图片的能力——示例库给了我们各种可能性的感觉,包括使用图片和自定义颜色。有了上面的代码,我利用机会把 cloud 这个词和罗马皇帝奥古斯都的一张图片结合起来。
对于词汇化的单词集,单词云图片在文章的顶部——我不确定这种美学是不是库作者的本意,但它起作用了。代码与上面的非常相似,但如果你需要查找,它在 Github 上。
中断
在本文的第 1 部分中,我们着重于利用 NLTK 和 wordcloud 库来探索一个文本示例——本文中显示的全部代码以及更多内容可以在 Github 上找到。在第 2 部分中,我们将深入研究单词嵌入和可视化,
用 NLP 重构 Plutarch:第 2 部分
普鲁塔克通过自然语言处理研究希腊和罗马贵族的生活:这部分包括 word2vec、降维(PCA 和 t-SNE)和 Tensorflow 投影仪
序文
普鲁塔克的《高贵的希腊人和罗马人的生活,也被称为平行生活或者仅仅是普鲁塔克的生活,是一系列著名的古希腊人和罗马人的传记,从忒修斯和吕库古到阿非利加努斯·戈狄亚努斯二世。在这篇文章/教程中——继最近出版的第 1 部分之后——我将继续使用一些自然语言处理技术来探索这本书。
为了便于复制,我将代码改编为 Google Colab,并强调了该平台的独特之处——否则整个代码都可以在 Python 3.6+上本地运行。代码在整篇文章中依次出现,Github 文件的链接嵌入在文章的最后,因为我可能会跳过一些次要的细节或补充代码。
古登堡计划已经提供了本分析中使用的文本。
设置事物
在 Colab 上,我们先把运行时类型改成 GPU,然后导入 OS 和正则表达式库,保存+打印文件路径备查:
*import os
import re
fpath = os.getcwd(); fpath*
让我们将文本(Plutarch.txt)导入到 Google Colab 驱动器中——我们需要记住,我们在那里的文件是短暂的,我们需要在每次使用该平台较长时间后上传它们:
上面的代码也可以在 Colab 的 Code Snippets 选项卡下找到——还有许多其他非常有用的代码。当执行这段代码时,我们将看到 Colab 上传文件,然后我们可以单击左边的 Colab Files 选项卡,以确保该文件与 Google 的默认示例数据目录在一起。
接下来,我们需要对文本进行标记—但是,与上一篇文章不同,我们希望保持类似句子的结构,并且不希望删除停用词:
通常在 NLP 任务中,停用词不经思考就消失了,而且在许多情况下是有意义的。然而,由于我们将处理单词嵌入,其中单词的训练和它的上下文是相互依赖的,我们希望确保这样的上下文(停用词是其中的一部分)得到保留。
单词嵌入和相似性
让我们继续训练文本,以便我们可以例如计算彼此之间的单词相似度(被算法理解为几何邻近度)。如果你更喜欢从更理论化的方法开始,我认为这个斯坦福大学 word2vec 讲座非常棒——可能最好是喝一杯你最喜欢的饮料。我获得的信息金块之一是每个单词都有两个向量:作为中心单词和上下文单词(视频中的 41:37),因此当我在一个散点图的两个地方看到同一个单词时,我最初的困惑得到了解决。
接下来,让我们使用 word2vec 模型的四个变体:连续单词包(CBOW,基于上下文单词预测当前单词)和 skip-gram(CBOW 的逆-基于当前单词预测上下文单词),每个都具有负采样和分层 softmax 选项:
在上面的代码中, min_count 允许根据单词的频率忽略它们,所以在这种情况下,我们希望每个单词都被计算在内;尺寸表示尺寸的数量;窗口是当前字和预测字之间的最大距离; iter 是文本上的历元/迭代次数; sg=1 表示我们正在使用 skip-gram,否则为 CBOW hs=1 表示我们在使用分层 softmax,否则就是负采样(分层 softmax 对于不常用的词更好)。如果你想更深入了解,还有更多选择。
四个选项的结果差异很大,但为了时空的利益,让我们更深入地研究第一个选项,负采样的 CBOW:
我们会注意到“凯撒”和“国王”之间的相似度非常高,考虑到这两个词是统治者的同义词,这是有道理的——尽管当时罗马人厌恶“国王”的称号。下面是上面代码中的类似单词:
正如我们将看到的,皇帝的名字与其他皇帝和政治家的名字非常相似。“百”是接近其他数字和货币名称。“国王”与皇帝的名字和“死亡”联系在一起——可能部分是因为那时政治中的暗箭伤人更加字面化。真理接近上帝,反之亦然。
您的结果可能与我的不同,因为哈希随机化和模型不局限于单个工作线程(这里的解决方案)。
降维
除非你是《星际迷航》中的 Q,为了可视化你的单词嵌入,你需要大幅减少维数,理想情况下最多两到三个。现在,我们有 100 个。有两种流行的方法,我们将在本文中提到:主成分分析和 t-SNE。
PCA ( 主成分分析)是一种线性和无监督的方法,允许提取数据的低维表示,从说明数据中大部分可变性的主成分开始:
该片段将产生一个数据帧,每个单词有两个坐标。
t-SNE(t-分布式随机邻居嵌入)是一种非线性且无监督的降低数据维数的方法。它主要集中在可视化上,所以——不像 PCA——我们不能在超过三个维度上运行它。有一篇关于如何有效使用 t-SNE 的优秀文章。
运行下面的代码需要一段时间,所以请确保您有时间:
如果你想试验各种超参数的变化,代码很容易操作;这对于 SNE 霸王龙来说尤其重要,因为它可以更好地了解自己的行为。t-SNE 的另一个棘手之处是它的非确定性(概率性)本质,这意味着每次运行时,我们可能会对相同的数据得到不同的结果——这是因为用于最小化目标函数的梯度下降优化是随机启动的。然而,尽管它比 PCA 年轻 75 岁(SNE 霸王龙是在 2008 年发明的,而 PCA 是在 1933 年发明的),SNE 霸王龙还是很管用。
形象化
现在我们已经控制了尺寸,我们可以开始画一些图了。然而,如果我们试图绘制整个唯一单词集,我们将得到这个(PCA 版本):
即使在扩大图片后,也很难提取东西——我甚至没有贴标签,因为这样散点图看起来简直糟透了。我们稍后将使用 Tensorflow 投影仪解决这个问题,但现在让我们只关注相似词子集,从 PCA 二维图开始:
*from matplotlib.pyplot import figure
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCAfig = matplotlib.pyplot.gcf()
fig.set_size_inches(18, 14)simwords = sum([[k] + v for k, v in similar_words.items()], [])
wvs = model_cbow.wv[simwords]pca_wvs = PCA(n_components=2, random_state=0)
np.set_printoptions(suppress=True)
Tpca = pca_wvs.fit_transform(wvs)
labels = simwordsplt.figure(figsize=(16, 12))
plt.scatter(Tpca[:, 0], Tpca[:, 1], c='purple', edgecolors='purple')
for label, x, y in zip(labels, Tpca[:, 0], Tpca[:, 1]):
plt.annotate(label, xy=(x, y), xytext=(0, 0), textcoords='offset points')*
我们看到数词聚集在图的右侧。在左上角,我们看到许多皇帝,随着我们沿着 Y 轴往下走,皇帝的名字越来越与地理名称混在一起。t-SNE 当量看起来不同,但相似的距离逻辑是显而易见的:
使用张量流投影仪进行可视化
如果不提到谷歌的一个令人惊叹的可视化工具——tensor flow Projector,我们会觉得很不妥;它允许动态地与单词嵌入进行交互,并通过点击按钮进行更深入的挖掘。
在左上角,我们选择 Word2Vec All,在右边的搜索栏中,我们键入并单击“caesar”。原始空间中最近的点显示在下面,我们可以在平台上进行切换,在 PCA 和 t-SNE 之间切换,增加邻居的数量,选择球形化数据,选择余弦或欧几里德距离等。让我们根据我们的普鲁塔克分析将这些结果与“ceasar”进行比较。
但首先我们应该为投影仪准备数据,即两个 csv / tsv 文件,其中一个包含向量,另一个包含这些向量表示的单词(投影仪称之为元数据):
*import pandas as pd
project_wvs = [(term, voc.index, voc.count) for term, voc in model_cbow.wv.vocab.items()]
project_wvs = sorted(project_wvs, key=lambda k: k[2])
ordered_terms, term_indices, term_counts = zip(*project_wvs)
df_cbow100 = pd.DataFrame(model_cbow.wv.vectors[term_indices, :], index=ordered_terms)df_cbow100['word'] = df_cbow100.index
df_cbow100['word'].to_csv('df_cbow100word.tsv', sep='\t', encoding='utf-8', index=False, header=False)df_cbow100vector = df_cbow100.iloc[:,0:100].copy()
df_cbow100vector.to_csv('df_cbow100vector.tsv', sep='\t', encoding='utf-8', index=False, header=False)*
上面,我们从之前生成的 word2vec 输出中创建了一个 dataframe (df_cbow100)。然后,我们将数据帧分成所需的仅标签(df_cbow100word.tsv)和仅矢量(df_cbow100vector.tsv)文件。要将文件下载到我们的本地机器上,我们只需双击 Colab 中相应的文件名。
然后,让我们回到投影仪,点击左上角的“加载”按钮,上传两个文件。瞧——现在我们自己的单词嵌入被反映出来了,我们可以使用投影仪工具来操纵我们认为合适的可视化。正如所料,与“caesar”最近的点相对于 Word2Vec All 有很大不同,word 2 vec All 是在更大的数据集上训练的。
结论
Github 上的提供了完整的代码和更多内容,而《重新想象普鲁塔克》的第 1 部分可以在这里阅读。在 Reimagining Plutarch 的两个部分中,我们谈到了使用 NLTK、Wordcloud、Word2Vec 嵌入和可视化来分析文本的方法,并为那些有兴趣深入研究的人提供了额外的资源。NLP 相关知识和编程诀窍的可访问性,以及像 Google 的 Colab 这样的工具,使得实现高级概念和跟踪该领域的进展比以往任何时候都更容易。
用 Tensorflow 2.0 重新想象 Plutarch
Original photo by Sandra Povilaitis; Vincent van Gogh style transferred using VGG19
通过 TensorFlow 2.0 中的单词嵌入看普鲁塔克的希腊和罗马贵族生活
序文
普鲁塔克的《高贵的希腊人和罗马人的生活,也被称为平行生活或者仅仅是普鲁塔克的生活,是一系列著名的古希腊人和罗马人的传记,从忒修斯和吕库古到阿非利加努斯·戈狄亚努斯二世。
在最近发表的文章中,我们研究了使用 gensim 库训练我们自己的单词嵌入。这里,我们将主要关注利用 TensorFlow 2.0 平台的单词嵌入层;目的是更好地理解该层是如何工作的,以及它如何有助于大型 NLP 模型的成功。
* [## 用 NLP 重构 Plutarch:第 2 部分
普鲁塔克通过自然语言处理研究希腊和罗马贵族的生活:这部分包括 word2vec…
towardsdatascience.com](/reimagining-plutarch-with-nlp-part-2-dc4e360baa68) [## 用 NLP 重构 Plutarch:第 1 部分
普鲁塔克通过自然语言处理研究希腊和罗马贵族的生活:这部分包括 NLTK 和 word…
towardsdatascience.com](/reimagining-plutarch-with-nlp-part-1-24e82fc6556)
为了便于复制,我将代码改编成了适用于 Google Colab 的代码,并强调了该平台的独特之处——否则,整个代码可以使用 Python 3.6+和相关包在您的本地机器上运行。整篇文章中都有代码,但我会跳过一些补充或次要的代码——完整的代码可以在我的 Github 库中找到。
古登堡计划已经提供了本分析中使用的文本。
设置事物
在 Colab 上,让我们将运行时类型更改为 GPU,然后导入最新的 TensorFlow 版本——下面的代码片段仅适用于 Colab,否则只需使用 pip 或 conda install 命令在您的机器上上传最新的 TensorFlow 。
我们还需要 OS 和正则表达式库,然后保存&打印文件路径以备将来参考:
import os
import re
fpath = os.getcwd(); fpath
让我们将文本(Plutarch.txt)导入到 Google Colab 驱动器中——我们需要记住,我们在那里的文件是短暂的,我们需要在每次使用该平台较长时间后上传它们:
上面的代码也可以在 Colab 的 Code Snippets 选项卡下找到——还有许多其他非常有用的代码。当执行这段代码时,我们将看到 Colab 上传文件,然后我们可以单击左边的 Colab Files 选项卡,以确保该文件与 Google 的默认示例数据目录在一起。
让我们阅读文本并做一些基本的正则表达式操作:
import recorpus = open(fpath + '/Plutarch.txt', 'rb').read().lower().decode(encoding='utf-8')corpus = re.sub('\n', ' ', corpus) #remove new line
corpus = re.sub('\r', ' ', corpus) #remove "return"
因为我们将把文本分成句子,所以新行对我们的分析没有意义。此外,在使用文本标记器时,我注意到“\r”(表示回车)会产生错误的唯一单词,比如“we”和“we \ r”——同样,这在我们的例子中并不重要。因此“\n”和“\r”都需要删除。
建立字典
随着我们逐渐接近实际的单词嵌入,让我们将文本标记成句子:
import nltk
from nltk.tokenize import sent_tokenize
nltk.download('punkt') #need in Colab upon resetting the runtime
# tokenize at sentence level
sentences = nltk.sent_tokenize(corpus)
print("The number of sentences is {}".format(len(sentences)))
我们会看到这篇课文总共有 16989 个句子。接下来,我们需要计算最长句子中的单词数——原因将在本教程的后面变得显而易见:
from nltk.tokenize import word_tokenizeword_count = lambda sentence: len(word_tokenize(sentence))
longest_sentence = max(sentences, key=word_count)
length_longest_sentence = len(word_tokenize(longest_sentence))print("The longest sentence has {} words".format(length_longest_sentence))
原来最长的句子有 370 个单词长。接下来,让我们将整个文本转换为正数,以便我们可以开始使用 TensorFlow 说一种通用语言:
从上面我们还发现,该文本有 20241 个唯一的单词,因为记号赋予器对每个相同的单词只赋予一个数字。为了标准化所有句子的长度(即,将输入数据转换为单个相同形状的张量,以使其可处理/更容易用于模型——我们在这里是为了满足机器的需求),我们需要将表示单词的数字列表(sent_numeric)转换为实际的字典(word_index),并添加填充。我们也可以将截断很长的句子和填充短句子结合起来,但是在这种情况下,我们只填充最长句子的长度。
词汇大小(也称为独特单词的数量)将增加 1,达到 20,242,这是添加 0 进行填充的结果。键入“data[0]”(即第一句话),看看第一句话在填充后会是什么样子。
为了能够在单词和它们的数字表示之间来回转换,我们需要为查找添加反向单词索引:
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])def decode_data(text):
return ' '.join([reverse_word_index.get(i, '?') for i in text])
仔细检查单词 indexing 和 conversion 是有意义的——一个错误就可能使整个数据集混乱不堪,让人无法理解。在我的 Github 库中可以找到转换前后的交叉检查的例子。
Photo by Sandra Povilaitis
模型
最后,让我们构建并运行模型。TensorFlow 提供了一个不错的教程,我们正在根据自己的需要进行修改。
但是首先,我们可以简单地只运行嵌入层,这将产生一个嵌入的数组。我读到过这样一个数组可以被保存并在另一个模型中使用——是的,它可以,但是除了跳过新模型中的嵌入步骤之外,我不太确定它的实用性,因为为每个单词生成的向量对于所解决的问题是不可知的:
我们不会在上面花太多时间,而是将重点放在嵌入只是第一部分的模型上。
在导入相关库之后,让我们继续构建新的、非常基本的模型架构:
嵌入层(通常可用作模型中的第一层)会将数字编码的唯一单词序列(提醒一下,其中 20,241 个单词加上填充编码为零)转换为向量序列,后者在模型训练时被学习。每个向量将有 100 个维度(embedding_dim=100),因此我们将得到一个 20242 x 100 的矩阵..输入长度将固定为最长句子的长度,即 370 个单词,因为每个单词由于填充而被模型感知为具有相同的大小。Mask_zero 通知模型输入值 0 是否为应被屏蔽的特殊填充值,这在模型可以处理可变输入长度的重复图层中特别有用。
在对足够多的有意义的数据进行训练之后,具有相似含义的单词将可能具有相似的向量。
下面是模型总结(带有额外密集层的模型在 github 库中):
在模型摘要中,我们将看到嵌入层的参数数量是 2,024,200,这是 20,242 个单词乘以嵌入维度 100。
前面提到的 TensorFlow 教程使用了一个评论数据集,每个评论根据积极或消极的情绪标记为 1 或 0。我们没有奢侈的标签,但仍然希望测试这个模型,所以将简单地创建一个 0 的数组,并附加到每个句子;模型需要这样的结构。这不会是机器智能第一次也不会是最后一次遇到无法解决的任务,但仍然会迫使我们找到解决方案。让我们来训练这个模型:
import numpy as npadam = tf.keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])batch_size = 16989 #number of sentences
data_labels = np.zeros([batch_size, 1])history = model.fit(
data,
data_labels,
epochs=200,
batch_size=batch_size,
verbose = 0)
嵌入被训练。在我们转向可视化之前,让我们快速检查一下 gensim 上的单词相似性。首先,我们需要创建 vectors 文件——临时保存在 Colab 中或下载到本地机器:
f = open('vectors.tsv' ,'w')
f.write('{} {}\n'.format(vocab_size-1, embedding_dim))
vectors = model.get_weights()[0]
for words, i in tokenizer.word_index.items():
str_vec = ' '.join(map(str, list(vectors[i, :])))
f.write('{} {}\n'.format(words, str_vec))
f.close()# download the file to the local machine by double-clicking the Colab file or using this:
try:
from google.colab import files
except ImportError:
pass
else:
files.download('vectors.tsv')
第二,让我们
import gensimw2v = gensim.models.KeyedVectors.load_word2vec_format('./vectors.tsv', binary=False)w2v.most_similar('rome')
最后,让我们检查一下庞贝和凯撒之间的相似性,这在我们之前培训的 CBOW 模型中显示得很高:
round(w2v.similarity('pompey', 'caesar'),4)
词与词之间的关系很高。同样,正如人们所料,凯撒表现出与罗马高度相似。
对于那些对更复杂的模型感兴趣的人来说,额外的变体,包括递归神经网络(长短期记忆)可以在我的 Github 文件中找到,但请记住,它们的训练速度将比上面的简单模型慢得多。
形象化
对于嵌入的可视化来说,TensorFlow Projector 无与伦比,因此让我们创建矢量和元(即对应于这些矢量的单词)文件供其使用:
在本地导入文件,然后我们可以前往 TensorFlow 的投影仪,上传文件以替换默认数据,并尝试网站上可用的各种选项。这里是文本的整个向量空间的主成分分析视图:
这是 100 个单词的向量空间,这些单词和“罗马”最相似。
结论
在本文中,我们简要地看了一下单词嵌入层在深度学习模型中的作用。在这种模型的上下文中,该层支持解决特定的 NLP 任务,例如文本分类,并通过迭代训练单词向量,使其最有助于最小化模型损失。一旦模型被训练,我们可以通过相似性计算和可视化来检查嵌入层输出。
嵌入层还可以用于加载预训练的单词嵌入(例如 GloVe、BERT、FastText、ELMo),我认为这通常是利用需要这种嵌入的模型的更有效的方式,部分原因是生成它们所需的“工业级”工作和数据量。然而,在专门文本的情况下,尤其是如果可以训练单词嵌入的语料库相当大,训练自己的嵌入仍然会更有效。*
强化学习:微妙的介绍
1996 年 2 月 10 日,IBM 的深蓝人工智能在一场国际象棋比赛中击败了世界冠军加里·卡斯帕罗夫。
谷歌的阿尔法围棋人工智能是世界上最好的围棋选手,一次又一次地击败了世界冠军。
但是这怎么可能呢?计算机怎么可能比人类聪明?答案… 强化学习。
什么是强化学习?
强化学习是机器学习和 AI 的一个分支。创建模型来做某些事情需要一种非常特殊的方法。强化学习的目标是教会计算机/机器以高度成功的方式执行某项任务。(例如。赢得一场国际象棋比赛,玩马里奥赛车并获胜,等等。)
注意什么是强化学习也很重要。这些模型是人工特定智能(ASIs),这意味着它们只能执行非常特定的任务。这些不是普通的人工智能机器(AGIs),不能执行任何任务。这是人工智能的下一个目标,然而在本文中不会讨论。
A reinforcement learning model playing Mario
强化学习是如何工作的?
为了理解强化学习的本质,让我们用这个简单的类比来分解它:
想象一个孩子第一次看到壁炉。孩子对壁炉充满了好奇和好奇…所以他很自然地靠近了壁炉。当孩子靠近时,它感觉到壁炉的温暖,因此孩子感到温暖和快乐。
此外,孩子想感受更多的快乐和温暖,所以孩子靠近壁炉,直到它能碰到壁炉。* 🔥* 孩子受伤了,从壁炉边退了回来。
下一次孩子遇到壁炉时,它已经学会了不要靠得太近,而是保持一个合理的距离,这样孩子就会得到温暖的奖励,而不会受到被烫伤的惩罚。这个动作是取悦孩子的。
感受温暖的回报是这个场景中孩子的目标。如果我们从人工智能的角度来看,人工智能或代理希望通过执行一些动作序列来最大化一些奖励值。
人工智能就像孩子一样,受到奖励的激励。他们都想获得尽可能多的奖励,这可以通过试错来实现,在试错过程中,他们学习寻找奖励时的模式。在儿童场景中,儿童很快了解到靠得太近会牺牲奖励,不值得。一台计算机也可能做同样的事情,尝试不同的事情,直到它找到一种给予持续高回报的模式。它强化了给予高回报的模式,并持续完成特定的任务。
环境是行动发生或任务执行的地方。例如,在我们上面的场景中,环境是有壁炉的房间。该环境还可以是视频游戏环境、诸如保龄球馆或厨房的某些场景房间以及其他一切。特定任务的环境范围。
代理是控制某个实体的计算机或机器。例如,在我们的场景中,代理是孩子。另一个例子是计算机控制超级马里奥兄弟中的马里奥。代理对实体可以执行的控制是有限制的。它只能使用一组预定义的规则。
动作是由代理执行的一个移动或一组连续移动。例如,在我们的场景中,它靠近或远离壁炉。简单地说,这是我们试图解决的问题的实际部分。我们如何创造适合任务的最佳行动。
奖励是对它在一个环境中完成一项任务的表现以及如何激励代理变得更好的衡量。在我们的场景中,奖励是壁炉的温暖,这也是代理做了好事的一个指标。
最后,状态是提供给代理的数据的计算,基本上告诉它在环境中的位置。在我们的场景中,是让孩子在完成一个动作后知道它在哪里。它是用来计算更多的行动,并达到一个总体目标。
它们都通过一个简单的程序连接起来。首先,我们的代理做一个动作。该动作通过环境进行处理,然后将奖励和状态反馈给代理。奖励告诉它动作做得有多好,以及代理在环境中的位置,所以它知道将来要做什么。
代理人不断尝试,直到有人奖励高价值。它将开始更多地实现这些模式,直到为环境创建一个系统。在这一点上,它将知道如何在环境中的任何状态下执行任务,从根本上解决我们的问题!
然而,仍然有一个问题需要回答……我们如何创造有效的奖励,使代理能够完成任务?
奖励——强化学习的原则。
奖励是智能体/计算机在特定任务中变得更好的动机,例如,在国际象棋中,奖励可以是获胜。因为奖励的必要性是强化学习的基础,所以了解如何通过一个叫做奖励形成的过程来创建有效的奖励系统是很重要的
对于机器来说,收敛于某些行为,重要的是学会知道什么是想要的,什么不是。比如玩单人纸牌或者跳棋的时候想要的目标是什么?这对我们来说似乎是显而易见的,但对计算机来说就不那么清楚了。在这些情况下,目标就是简单地获胜,这意味着达到某些参数。所以在给机器塑造奖励模型的时候,你可以告诉它,当它赢的时候,给它+1 奖励,输的时候,-1。这迫使机器想办法总是达到+1,这是我们的预期目标。
但是,我们如何为不像游戏那样明确的东西制定奖励,比如自动驾驶汽车?诀窍是始终考虑更大的目标。在这种情况下,它是在不坠毁或造成伤害的情况下到达 a 点到 b 点。这本身就是对机器的奖励,不管它能走多远而不崩溃。因此,无论何时你试图创建一个奖励函数,只要简单地问自己机器的目标是什么,并为这些参数编写一个程序。理论上计算机应该会变得更好。
因此,我们具备了创建这些代理/机器来执行特定任务的知识…所以,让我们开始吧!
嗯…还有一件事要弄清楚…
模拟和如何训练强化学习模型
很容易看出很多游戏都经过了强化学习。经典的视频游戏,如国际象棋、乒乓球、马里奥、跳棋、围棋……(你明白了)都是电脑碾压人类的游戏。
为什么?因为很简单。
在一个游戏中,有规则可循,有许多迭代。一次模拟许多游戏很容易,计算机可以以指数速度学习。电脑不会累,饿,困等。不像人类那样只有有限的时间来学习,计算机可以连续学习几个小时。更不用说,他们能够每秒钟玩多个游戏。这就是为什么计算机可以轻易胜过我们的根本原因。难怪一个 40 天的国际象棋程序能够击败国际象棋冠军加里·卡斯帕罗夫。
但是那些没有具体规则,可以应用到现实世界的任务呢?我们如何应用强化学习?
以开车为例。如果让一台机器在现实生活中“试错”一辆汽车,那就太傻了。你只能想象它会带来的恐惧。那么我们如何应用强化学习呢?同样的方法,用模拟。
“trial and error” approach in real life 😬
我们可以在一个游戏引擎中模拟我们世界的物理,比如 Unity。我们可以给计算机特定的规则,比如前进和后退。我们可以把机器放入一个类似真实世界的环境,比如道路。我们用我们的奖励系统在环境中训练机器,直到它变得足够好,几乎不犯错误。
然后我们把我们的模型放入真实世界的机器中,在那里它做完全相同的事情。不需要真实世界的混乱!
嗯…有一点不好的地方…
这样做的缺点是模拟只是…模拟。没有什么能完全模拟我们的世界。如果环境和现实世界之间有一点点差异,这个模型可能在现实世界中不起作用(看看 gif 就知道了)。在为现实世界中的应用程序训练模型时,如果你能克服这个障碍,你就能成功。但是为了确保它能正常工作,你必须仔细观察环境,以确保它是正确的。
这就引出了一个问题…有了创建真实世界钢筋模型和机器的能力…在真实世界中有哪些应用?
真实世界的应用
自动驾驶汽车
通过模拟训练,自动驾驶汽车成为强化学习的对象已经有一段时间了。从自动驾驶汽车到自动驾驶飞机,自动驾驶汽车的领域是无限的。
卫生保健
强化学习已经被用来通过在模拟中反复试验来找出哪种诊断对某些药物最有效。随着 AI 接管医疗行业,试错将变得更加有用。
制造业
在传统制造中,机器会执行定时程序移动。强化学习的加入,让这些机器更能适应做某项任务,随心所欲地改变任务。这模仿了许多行业的快速变化。
关键要点
- 强化学习是通过在一个环境中使用奖励系统来训练一个智能体执行某个任务。
- 奖励是强化学习的原则,我们使用奖励成形来创建强化学习模型的奖励模型。
- 模拟可以用来训练代理
- 强化学习如今在很多行业都有应用。
用井字游戏进行强化学习和深度强化学习
在这篇文章中,我想分享我在井字游戏中实现强化学习和深度强化学习方法的项目。
该文章包含:
1.将博弈严格定义为马尔可夫决策过程。
2.如何实现称为 TD(0)的强化学习方法,以创建一个在游戏的每个状态下都发挥最佳行动的代理。
3.如何实现深度强化学习,这与第 2 节非常相似,但这里我使用了神经网络来学习价值函数(什么是价值函数将在后面定义)。
所以让我们开始…
井字游戏的马尔可夫决策过程
为了简单起见,让我们将第一个玩家定义为玩 X 符号的玩家,将第二个玩家定义为玩 O 符号的玩家,让我们将注意力集中在 X 玩家上。
首先要注意这不是一个对称博弈,X 有优势,因为他先玩,他最多有 5 次机会,而 O 最多有 4 次机会。
MDP(马尔可夫决策过程)是一个 4 元组,它包含:
- 状态设置
当轮到玩家 X 出牌时,他的状态集包含所有的棋盘,所以在我们的例子中,状态集包含所有具有相同数量的 X 和 O 的棋盘。例如,空板处于 set 状态。此外,当游戏结束时,所有的棋盘也在状态集中,它们被称为结束状态。
我们将把一个状态写成一个 9 字符串,其中包含数字 1-9,从左上到右下代表棋盘上的空白点,用 X 和 O 代替玩家所在位置的数字。例如,字符串 X234O6789 表示 X 在左上角播放,O 在中间播放的状态。
2。 动作设定(一)
动作集包含了玩家 X 可以玩的所有选项,也就是特定状态下的所有数字。
这里要注意的是,玩家 X 出牌后的棋盘不是玩家 X 的状态集中的状态,因为 X 不能在这个棋盘上执行某个动作(轮到 O 了)。该动作将导致的新状态将是玩家 O 完成其回合后的棋盘。
3。概率函数(P)
概率函数,定义通过采取行动从 S 到 S 的转移概率a-**p:s✕s✕a→【0,1】。在我们的例子中,S 取决于 O 的话轮。我们可以把它想成:X 采取一个动作,环境做出反应,在 O 的回合后返回一个新的状态。每个可能的状态都有自己的概率,而概率取决于 O 的玩家。
这里需要注意的是,我们的目标是找到一个函数,将一个状态映射到 X 可以采取的最佳动作。这个动作显然取决于 O 怎么玩(因为它改变了概率函数)。举例来说,如果我们和一个人类玩家或者一个同样随机的玩家进行游戏,那么这个动作可能会有所不同。
例如,假设我们开始了一个新游戏(新一集),状态是空板,我们需要执行一个动作。我们有 9 个选择。假设现在,我们选择在棋盘中间玩。现在参与人 O 有 8 个选择。如果 O 是一个同样随机的玩家,他将以同样的概率从 8 个选择中挑选一个。对于那些熟悉条件概率的人,我们可以这样写:
P(S =O234X6789|S =0123456789,a = 5)= P(S = 1 o 34 x 6789 | S = 0123456789,a=5) = …=1/8
对于人类玩家来说,在角落玩比在边缘中间玩更有可能,所以概率函数会不同。
4。奖励(R)
奖励:我们将它定义为 1 如果 X 赢了,-1 如果 O 赢了,0.5 如果是平局,否则 0。
政策和价值功能
策略是从状态集映射到动作集的功能。最优策略是使每个州的未来回报最大化的策略。
当从状态 S 开始并遵循策略π时,策略π的价值函数是将状态 S 映射到期望回报(未来回报的平均值)的函数。最优价值函数是最优策略的价值函数。
我们的目标是学习这个最优值函数,然后根据这个函数作用于每个状态。但首先,让我们假设我们已经知道这个函数,我们如何从一个给定的状态中选择我们的最优行动?
我们假设对手,O 玩家是一个理性的玩家,在 X 的回合之后,他会采取使下一个状态的价值最小化(从而使他的价值最大化)的行动。我们将选择使所有可能的下一个状态的最小值最大化的动作。
比如在空板,X 有 9 个选项可以玩。每个选项可以导致 8 种不同的状态(O 有 8 个选项可以玩)。对于每个 X 移动,我们将从下一个状态计算 8 个可能的值,并记住这些值的最小值。我们将有 9 个价值,我们将决定采取最大化这 9 个价值的行动。
强化学习代理
我们现在的目标是学习最优值函数,并创建一个根据该函数进行最优移动的代理。为了学习价值函数,我们将使用 TD(0)方法:
首先,我们将每个状态的值函数初始化为 0。对于游戏访问的每一个状态,我们都会按照更新后的规则更新前一个状态的值函数:v(s)= v(s)+α(v(s ')+R-v(s))
其中 s 是要更新的状态(前一状态)s’是当前状态, R 是奖励, α 是学习率。我们将选择我们的下一步棋作为概率为 0.8 的最优棋和概率为 0.2 的随机棋,以鼓励探索。
每学习 100 集,我们将随机播放 100 集最佳动作,以检查我们的学习。
在下图中,我们可以看到学习过程。左图对应 X 玩家,右图对应 O 玩家。开始时,我们有两个随机的玩家,由于游戏的性质,X 赢的多一点。在学习过程之后,我们可以看到每个玩家几乎总是在学习和获胜。
深度强化学习代理
现在我们可以尝试用不同的方法来学习价值函数。我们不需要学习一个将每个状态映射到一个值的值函数,而是可以尝试将这个函数学习为一个神经网络,它接受一个状态并返回一个值。
馈送给网络的状态是长度为 9 的向量。x 标记为 1,空点标记为 0,O 标记为-1。
该网络包含两个隐藏的密集层,第一层包含 27 个具有 Relu 激活功能的神经元,第二层包含 18 个具有 Relu 激活功能的神经元。网络的最后一层是具有 1 个输出神经元的密集层,该输出神经元具有线性激活函数。
为了训练网络,我们为每个状态计算一个目标值:target = v(s)+α(v(s ')+R-v(s))其中 v(s) 和 v(s') 是从神经网络本身计算的。每次目标计算后,执行一次随机梯度下降迭代。这就是为什么在这个井字游戏的特殊例子中,与以前的方法相比,需要更多的片段来训练网络以执行良好的结果。
这种方法被称为深度强化学习,因为我们在这里使用的是深度学习方法。
为了实现神经网络,我使用了 Keras 框架。
下图显示了深度学习方法的学习过程:
摘要
在这篇文章中,我们看到了两种创建完美井字游戏玩家的方法。第一种方法使用直接的方法——在每个状态学习状态的值。这种方式需要多次访问每个状态,以便了解完整的值函数。在这种情况下是可能的,因为游戏没有很多状态。
第二种方式是一种更通用的方式:训练一个将状态映射到值的神经网络。神经网络学习闭合状态(如旋转、镜像等。)有相同的价值观。这意味着我们不需要访问所有国家。然而,因为我们使用随机梯度下降,我们需要播放更多的剧集,以便学习一个完美的神经网络。
原代码可以在:https://github.com/giladariel/TicTacToe_RL.git找到
你现在可以自己和代理人比赛,看看你是否能赢。
用一个简单的游戏强化学习和可视化
Photo by Chris Ried on Unsplash
游戏是学习强化学习(RL)概念的最佳方式。但是选择极其琐碎的游戏作为例子并不能反映这种技术的真正力量。另一方面,选择一个有很多图形组件的复杂游戏是一个很酷的演示,但是对于新手来说很难跟上。
本文将通过一个简单的游戏来指导你,这个游戏使用基于 Q 表的强化学习,并且很容易使用 Tkinter 来可视化。游戏的目标是让一个随机移动的绿色球学会如何到达一个小圆圈的中心。如果球没有在 200 步内到达现场,它就输了,游戏重新开始。
运行 RL 训练及其可视化的所有代码都可以在这里获得
Basic Gameplay
要进行任何 RL 培训,需要明确 3 件事情。
- 代理:它是游戏的组件,会学习一个策略并做出决定。对于我们的游戏来说,代理就是绿球。
- 状态:把状态想象成代理在游戏中特定点的“描述”。状态需要捕捉决定代理的最终目标(或中间目标)是否实现所需的所有信息。这些信息应该是必要和充分的。在我们的游戏中,州被绿球的 2D 坐标捕获。它们足以告诉我们球是否到达了期望的最终位置。
- 动作:动作是改变代理状态的任何事情。通常一个代理在任何给定的状态下都有一个有限的可能动作集。最佳行动的选择最初是随机的(探索阶段),代理人试图找出采取所选行动的后果。一旦代理开始通过多轮游戏获得经验,它就开始制定一个政策来指导它的行动选择,而不是随机探索。这就是我们所说的剥削阶段。对于我们的游戏,代理只有 8 个可能的方向可以选择。但是我们给它一个选择,让它每边移动 10 个像素或者 20 个像素。因此,动作集的大小为 16。
让我们检查一下为我们的游戏设置状态空间(所有可能状态的集合)和动作空间(所有可能动作的集合)的代码。
mov_list = [-20,-10,10,20]
#Set up Q table
state_space = {}
temp_list = []
for n in range(0,500,10):
for m in range(0,360,10):
temp_list.append((n,m))
for k in range(1800):
state_space[k] = temp_list[k]action_space = {}
temp_list = []
for n in mov_list:
for m in mov_list:
temp_list.append((m,n))
for k in range(16):
action_space[k] = temp_list[k]
这段代码假设游戏窗口为 500 像素 x 360px 像素。所以,我们的状态空间应该有 18000 的大小(代理可以到达的每个 x,y 像素)。但是我们已经定义了可能的移动(mov_list)仅仅是 10 的倍数。所以,这将我们的状态空间缩小了 10 倍到 1800。动作空间类似地由所有可能的运动(x 和 y 的组合)组成,给出一组 16 个。
好了,现在我们已经为游戏定义了代理、状态和动作。但问题是代理人如何知道它所采取的行动是有益的还是无益的?这就是奖励功能发挥作用的地方。奖励(或惩罚)可以在每次行动后或游戏结束时提供。一般来说,保持奖励系统简单是个好主意。例如,在我们的游戏中,球最多有 200 步才能到达圆圈。每一步都没有奖励。如果球在 200 步之前找到圆圈,则奖励 100。
那么,这种奖励是如何用来制定政策的呢?有多种方法可以做到这一点,但我们使用了 Q 表,这是最简单的策略更新工具之一。Q 表只是状态空间 x 动作空间的矩阵。
q_table = np.zeros([len(state_space),len(action_space)])
对于我们的游戏,它是一个 1800 x 16 的矩阵,每个单元初始化为 0。如果任何动作导致奖励,我们更新对应状态的 Q 表,动作对。
old_q_value = q_table[state, action]
next_state = list(state_space.keys())[list(state_space.values()).index((pos_x1, pos_y1))]
next_max = np.max(q_table[next_state])
q_target = reward + gamma * next_max
q_delta = q_target - old_q_value
q_table[state, action] = old_q_value + alpha * q_delta
我在这里引入了两个新术语。“alpha”设置算法的学习率,“gamma”是未来奖励的折扣因子。gamma 值越高,可能的未来回报就越重要。我们使用了 0.9 的 alpha 和 1 的 gamma。
这留给我们最后一件事。设定勘探与开发比率。这是由项ε设定的。如果随机数(0 到 1)低于ε,那么代理可以根据 Q 表自由探索和忽略当前策略。
if random.random() < epsilon:
x1 = random.choice(mov_list)
y1 = random.choice(mov_list)
action = list(action_space.keys())[list(action_space.values()).index((x1, y1))]
else:
action = np.argmax(q_table[state])
x1, y1 = action_space[action]
整个脚本可在这里获得
可视化强化学习如何进行的最好方法是通过一些 GUI 跟踪球的运动。我将 RL 代码与可视化代码分开,这样 RL 运行起来非常快。你可以在一定数量的游戏中运行 RL(代码中的剧集参数),然后运行 GUI 来观察球的行为。GUI 是基于 Tkinter 的,应该可以在任何平台上轻松工作。需要记住的主要事情是,对于 RL 运行,epsilon 设置为 0。因此,它在 RL 训练期间全面探索所有游戏(并建立策略)。请随意将它设置得更高,并在 GUI 上观察结果。
如果你想想象探索之后的渐进开发,在同一个报告中查看这个脚本。注意不要设置太少的探索集,否则小球学不到多少东西,开始钻政策的空子。
就是这样!摆弄参数,一旦你适应了,就开始创建更复杂的游戏。你很快就会意识到,一旦状态空间变得太大,Q 表的更新就会变得非常慢。这就是深度 Q 网络的用武之地。改天再讨论的话题。
强化学习基础:平稳和非平稳多臂土匪问题
Photo by Benoit Dare on Unsplash
多臂(也称为 k 臂)bandit 是一个介绍性的强化学习问题,其中代理必须在 k 个不同的选项中做出 n 个选择。每个选项都提供了(可能)不同于未知分布的回报,该分布通常不随时间变化(即它是固定的)。如果分布随时间变化(即,它不是静态的),问题会变得更难,因为先前的观察(即,先前的游戏)几乎没有用处。无论哪种情况,目标都是获得最大的总回报。
这篇文章回顾了一个简单的解决方案,包括 1000 个游戏中的固定和非固定的 5 臂强盗。注意这里只展示了部分完整代码的备注,完整功能的笔记本请看这个 github 库。
5 个固定的强盗
首先,让我们来定义下图中显示的 5 个固定土匪,这将成为代理的选项。
class Bandit:
def __init__(self, mean, std):
self.mean = mean
self.std = std
def sample(self, n=None):
return np.random.normal(self.mean, self.std, n)
Distribution of each bandit (unknown for the algorithm)
为了简单起见,它们中的每一个分别遵循均值为 1、2、3、4 和 5 的正态分布,并且它们都具有 5 的标准偏差。这意味着,比如说,在一次拉动中,所有的强盗都很有可能获得 3 英镑的奖励,但是 1000 场游戏的预期奖励在不同的强盗之间会有很大的差异。事实上,如果一个人总是选择强盗 b1,预期奖励是 1000,而如果一个人选择强盗 b5,那么预期奖励上升到 5000(5 倍增长)。记住,在这个例子中,最好的强盗是 5 号。
当然,如果一个人事先知道这些分布,那么问题将是微不足道的:只需选择期望值最高的土匪并坚持下去。这就是探索和利用之间的权衡所在:假设一个人对环境的信息不完善,那么就有必要继续探索(即尝试不同的强盗),以便获得关于最佳选择的知识,或者很可能陷入局部最优(纯粹的利用,贪婪的算法),但如果一个人只探索,那么所获得的信息就没有被使用,也不会获得最优(纯粹的探索)。
为了确保上述概念得到理解,假设在尝试每个土匪一次后,他们的结果是:
那么一个纯粹的利用算法会拉真正的最差土匪(b1)很长一段时间(直到 b1 的平均值低于 0,可能永远不会),只是因为它在初始化步骤中随机地碰巧是最好的。相反,纯探索算法将对五个盗匪进行均匀采样,并且其期望值将为:
这是次优的结果。
一个简单的解决方案是结合这两种方法,只是贪婪,但探索的时间比例为ε。在下图中,可以看到ε = 0(纯剥削)、ε = 0.01 和ε = 0.10 的实现。贪婪算法在搜索的早期阶段占主导地位,但那些探索的人很快意识到有更好的强盗,并胜过贪婪算法。
# Plays the bandits n times during t time steps
datas = {}
n = 20
t = 1000
es = [0, 0.01, 0.10]for e in es:
# Play n times
for i in range(n):
# Get t time-steps of each bandit
if i == 0:
data = sample_bandits(bandits, e, t)
else:
data = data.append(sample_bandits(bandits, e, t))
datas[e] = data
Average score for ε = 0, ε = 0.01 and ε = 0.10
由于问题是固定的,一旦一个人有信心成为最好的强盗,就不再需要探索;因此,在极限情况下(即有∞步),ε = 0.01 算法将是最好的算法。然而,如果对问题的平稳性有信心,那么最佳策略将是进行初始搜索(ε = 0.10),然后切换到利用模式(ε = 0)!
下图显示,通过玩这个游戏 20 次,混合算法在更高的时间百分比内一致地采样到最好的强盗。请注意,ε = 0.10 看起来停滞在 90%附近,这很自然,因为它被编码为在 10%的时间里选择一个非最优的 bandit。相反,ε = 0.01 不断增加,随着时间的推移,它将达到 99%。
Percentage of optimal action for each ε policy across 20 games.
另一种方式是检查 20 个游戏中每个土匪的样本数,如下所示,贪婪算法通常会混淆土匪 4 和土匪 5,而ε = 0.10 很容易找到最好的土匪。
Number of samples per bandit per policy.
5 个不稳定的强盗
在现实生活中,发现随时间变化的分布是很常见的。在这种情况下,问题变得更难解决,只是因为以前的观察不太有用:它们可能没有反映出土匪当前状态的真相。处理这个问题的一个简单(但非常严格)的方法是只考虑 m 个先前的观察,这就是这里使用的方法。请注意,这引发了许多问题,例如:
- 变化可能与 m 非常不同,在这种情况下,信息要么被混淆,要么被浪费。
- 这种方法假设 bandit 的新发行版与以前的发行版无关,但事实往往并非如此。
考虑到问题的性质,使用指数加权平均法、加权块平均法或甚至拟合时间序列模型来寻找分布何时改变的指标并相应调整勘探率等替代方法可能更准确。
为了将这些土匪调整为非平稳的,使用了对分布的平均值和标准偏差的简单概率突变(具有 1%的突变概率),但是变化也可以每 X 步发生一次,或者具有不均匀的概率,或者它们甚至可以改变分布的形状。
def mutate_bandit(bandits, proba):
for bandit in bandits:
if np.random.random() < proba:
bandit.mean += np.random.randint(-100,200)/100
bandit.std += np.random.randint(-50,75)/100
在这种情况下,人们会认为纯粹的利用算法性能很差。这个直觉用下图证实了,图中显示ε = 0 算法只在 30%左右的时候选择了最好的 bandit,比纯粹的随机选择(20%)好不了多少。ε = 0.10 设法发现最佳 bandit 何时更频繁地改变,并保持为最佳执行算法。另一方面,ε = 0.01 不再提高,因为它的低探测率不允许它快速找到变化的最佳 bandit。
Percentage of optimal action for each ε policy across 20 games on a non-stationary bandit problem.
外卖
最后,如果你需要记住这篇文章的一些东西,那应该是:就像 k-bandit 问题一样,真实世界的问题,其中的真实性质是未知的,需要探索和利用的混合才能有效地解决。
强化学习:超越监督和非监督方式
在机器学习中,根据提供给你的数据类型,有两种主要的方法来训练你的模型:
- 监督学习:你被提供了一组输入和输出,因此你的数据已经被标记,你知道它们背后的“基本事实”。这意味着,一旦你的算法在训练集上得到训练,并在测试集上做出预测,你就可以立即得到它的性能反馈:事实上,你已经知道了真实的输出。让我们用一个简单的例子来形象化它,其中我们的数据被标记为“三角形”和“正方形”,因此我们的算法将被要求为新数据分配一个现有的类:
- 无监督学习:在这个场景中,你被提供的数据既没有被标记也没有被分类。基本上,你事先不知道你的数据点是正方形还是三角形。因此,无监督算法的目标是推断这些数据的内部结构,找到共同的模式,并试图将它们归类(记住,没有目标!).也就是说,我们的无监督算法可能能够从三角形中分离出正方形,但实际上并不称它们为“正方形”和“三角形”。
到目前为止一切顺利。但是如果根本没有给你提供数据,而你又想让你的算法从周围环境中学习,那会怎么样呢?如果你想一想许多自动化系统,像自动驾驶汽车和机器人,你可以看到那些机器(汽车、机器人)没有提供历史数据:它们必须在工作时收集这些数据。因此,这个想法是,这些机器必须通过几次尝试来完成任务,从它们的错误中学习(即撞向墙壁),并在下一次尝试中避免它们。
让我们通过考虑下图(指的是马尔可夫决策过程)来稍微解释一下这个概念:
想法是我们有一个代理(机器人)和一个环境(迷宫)。那个代理有一个环境的个人表示,称为状态。然后,它需要与环境互动,其方式是通过动作。在每一个行动之后,代理将会有一个新的环境状态,以及对其行动的反馈,以奖励或惩罚的形式。
为了简单起见,想象你第一次参观一个公寓,突然,环境变暗了,你什么也看不见。你想到达门口,但你不知道路。你会怎么做?你可能会从非常缓慢和随意地行走开始(第一组动作),记住公寓的某种表现(状态)。然后,你撞上了右边的一堵墙:现在你可以在精神上更新环境的状态,同时,你正在接收对你的行动的负面反馈(惩罚)。现在,你知道你所做的动作是不正确的,因此你将朝着另一个方向前进,令人惊讶的是,你到达了门口!现在你将会收到积极的反馈(奖励),因为你已经达到了目标。
这个小机器人(代理人)试图穿过迷宫(环境)并到达奖品(任务的目标)时也会发生同样的情况。
所以,强化算法的思想是这样的:找到一套行动(所谓的政策),使奖励的现值(或贴现值)最大化。
正如预期的那样,RL 有各种各样的应用,但在我看来,最具革命性的元素是它不同于任何其他 ML 方法的方式。事实上,如果你考虑分类或聚类方法(分别是有监督的和无监督的),你基本上是在试图让模型“模仿”你完成任务的方式。然而,在 RL,故事是不同的。在这里,代理将自己探索环境,并且根据响应,它将更新它的策略,这不是对该过程背后的某些人的策略的模仿。
强化学习、大脑和心理学:导论
强化学习、人工智能和人类
强化学习与人类联系系列介绍。
"甚至在天气预报中也能找到灵感。"
人脑可能是世界上最复杂的系统之一,因此它是任何人工智能研究人员的灵感源泉。几十年来,强化学习不仅从自然中,也从我们自己的心理学中借鉴思想,在技术和人类之间架起了一座桥梁。
在这些系列中,我们将深入探究是什么激发了 RL 领域的发展,以及是什么在未来引发了它的发展。
本主题分为 9 个部分:
- 第一部分:引言。
- 第 2 部分:古典和仪器条件反射。
- 第 3 部分:延迟强化、认知地图和行为。
- 第 4 部分:神经科学基础 1。
- 第 5 部分:神经科学基础 2。
- 第六部分:多巴胺。
- 第七部分:演员-评论家。
- 第八部分:上瘾。
- 第九部分:边境。
在本系列中,我们不打算研究 RL 本身,假设您已经对它有所了解。希望会有另一个系列,这将是 RL 的重点,将涵盖一切从动态编程开始,并以复杂的事情结束,如 AlphaZero。
这里所有的想法都来自不同的来源,包括我自己的经历和对这个话题的思考。但我必须强调我最推崇的来源,也是我获取最多知识的来源——理查德·萨顿和安德鲁·巴尔托的“强化学习:简介”。这是少数几本关于 RL 的书之一,也是唯一一本涵盖了 RL 基础和起源的书。
在这篇文章中,我们将使用一些真实世界的例子来介绍 RL 的基础知识,因为这个系列不是关于数学、神经网络或编程的。它更多的是关于理解我们自己的思想和我们可以应用于人工智能的事物。
"在我们了解我们的大脑如何工作之前,我们很可能会建造 AGI . "
强化学习
RL 关键概念对我们来说非常简单,因为我们看到它并将其应用于我们生活的几乎每个方面。一个初学走路的小孩就是一个例子。
你可能在每个 RL 课程中都看到过类似的图片,这里没有什么新的东西,但它给了我们一个想法。
一个蹒跚学步的小孩坐在地板上(这是他目前的状态做出一个动作,a 试图站起来,在这个之后得到一个奖励。三个字就是强化学习。
蹒跚学步的孩子不知道如何走路,但他通过反复试验来学习。当他跌倒时,环境会给予他疼痛的反馈,当他迈出一步时,环境会给予他一个充满爱心的母亲的拥抱。这听起来熟悉吗?是的,这就是许多人所知的正负强化,或者更一般的说法操作性条件反射。例如,当我们教狗叫或打滚时,我们也会用到它。
RL 的关键词
代理 是许多人所说的人工智能,但它基本上是在环境中运行的算法的化身。一个人、一只狗或一个蹒跚学步的孩子都可能是一个代理人。
环境 是围绕代理的东西,也是代理从那里拿奖励的东西。比如我们周围的世界或者你玩的一个游戏。
政策 是逻辑、道德和大脑的代理。它给了代理人一个洞察力,告诉他为了成功应该做什么。更专业地说,它试图预测在某种给定情况下代理人行动的结果。
奖励 是代理做某事时得到的。这可能是积极的,也可能是消极的,取决于代理的表现。给打滚的狗一块饼干是积极奖励的一个例子,而你的教练的一声怒吼是消极奖励的一个例子。
状态 是代理进入的一种情况。它是你所拥有的信息的某种表现,比如你有多少钱,你住的离工作的地方有多远,你有多懒。代理根据状态决定做什么。
因此,基本上 RL 研究人员所做的是试图创建这样一个智能体(就 RL 而言,我们的幼儿是一个智能体),它将在环境(例如幼儿的世界)中运行,并能够理解在给定情况下什么是最佳举措。回到蹒跚学步的例子,他应该如何摆放他的身体以保持平衡并迈步。
是什么让我们这些人与众不同
我们这些人和 RL 特工不同的是,我们环境给的奖励并不是那么清晰易懂。事实上,我们在这个问题上有很多说法:“每个人都有自己版本的真相”,“真相到底意味着什么?”、“善恶只在一个角度不同”等。
简而言之,我们不知道哪些行为是好的,哪些是坏的。我们总是用一种经验主义的方式来解决这个问题,没有人能告诉你你做得有多好。很明显,我们有老师和父母帮助我们学习,但总的来说,我们在这个黑暗可怕的世界里是孤独的。没有人能告诉你我们的哪些行为会导致成功,哪些会导致失败。
外在和内在奖励
所以,就像我说的,与强化学习代理不同,我们无法从我们的环境中获得可解释的奖励,也称为 外在奖励 ,但是我们有所谓的 内在奖励 。
从人类的角度来看, 内在奖励 是自我激励、好奇心、完成目标的欲望,只是因为而没有任何理由。它就在我们内心的某个地方,它是一个火花,我们中的一些人会把它变成火。
当然,我们想出了给 RL 代理商这种奖励的办法。例如,在 OpenAI 的这篇漂亮的论文中——好奇心驱动学习的大规模研究——研究人员制作了一个对世界好奇的智能体。长话短说,当代理到达之前未被发现的位置时,它会得到一份内在奖励。结果是惊人的,智能体设法解决了 蒙特祖马的复仇 ,这对于强化学习算法来说是极其复杂的,因为它的分层遍历(去拿钥匙,然后找到门,打开它等等。).
当然,有更多的技术解释为什么 蒙特祖马的复仇 如此难以解决,但它在本系列之外,需要更多关于强化学习算法的知识。
结论
强化学习可能是通往 AGI 的道路,也可能不是。老实说,我不知道,可能也没人知道。我相信这是我们拥有的机器学习技术中最接近 AGI 的技术,但是我有什么资格去评判呢?
我可以肯定的是,RL 不断受到我们自身本性的影响,在这个系列中,我们将揭示我们大脑和思想中发生的事情,并发现人工智能领域从我们人类那里借鉴了什么。
跟我连线上 推特 , 领英 , 脸书 并关注上GitHub!
强化学习—悬崖行走实现
开和关策略比较
强化学习的本质是代理通过试验迭代更新其状态估计、动作对的方式(如果您不熟悉值迭代,请查看我之前的示例)。在以前的帖子中,我一直在重复谈论 Q-learning 以及代理如何基于这种方法更新其 Q 值。事实上,除了在 Q-learning 中定义的更新方法之外,还有更多其他方法来更新状态、动作对的估计。在这篇文章中,我们将一起探索另一种叫做 SARSA 的方法,将这种方法与 Q-learning 进行比较,看看更新方法的不同如何影响代理的行为。
先说时差,这是一个更新方法的核心。我们知道,在每次迭代或事件中,代理通过遵循策略(比如ϵ-greedy)采取行动来探索环境,并基于其最新观察(概括为状态-行动的值),它通过将当前估计向最新观察调整一点来更新其当前估计,最新观察值和上次观察值之间的差异称为时间差异。正是从这个时间差中,我们的代理学习和更新自己。
时间差异的定义将各种方法区分开来。为了给你一个更具体的感觉,让我们直接进入算法定义,并检查不同之处。
SARSA & Q-学习
SARSA(from Sutton’s book)
Q-learning(from Sutton’s book)
很明显,唯一的区别在于更新 Q 函数。在 SARSA 中(顺便说一下,SARSA 这个名字明确来自于代理的过程,即状态、动作、奖励、状态、动作…),时间差异被定义为:
[R + Q(S', A') - Q(S, A)]
其中下一状态、动作对的观察 Q 值直接有助于当前状态的更新。 SARSA 也称为 on-policy,因为更新过程与当前策略一致。
然而,Q-learning 中定义的时间差异是:
[R + max_a(Q(S', a)) - Q(S, A)]
其中观察到的下一状态、动作对的 Q 值可能不会直接有助于当前状态的更新。Q-learning 总是使用下一个状态的最大值,在这种情况下,更新 Q 值所采取的状态、动作可能与当前策略不一致,因此被称为非策略方法。
事实上,这种差异会导致代理的不同行为。直觉认为,Q-learning(非策略)在价值评估方面更乐观,它总是假设在过程中采取最佳行动,这可能导致代理人更大胆的行动。而 SARSA(非策略)在值估计上更保守,这导致代理的储蓄器动作。
悬崖漫步
为了清楚地证明这一点,让我们来看一个例子,悬崖行走,它摘自 强化学习入门 。
Cliff Walking
这是一个标准的不打折扣的、偶发的任务,有开始和目标状态,以及引起向上、向下、向右和向左运动的常见动作。除了进入标有悬崖的区域外,所有转换的奖励都是-1。进入该区域将获得最佳路径 100 的奖励,并使代理立即返回起点。
履行
这是一个典型的二维棋盘游戏,所以棋盘设置与我在这里描述的例子基本相同。在接下来的章节中,我将主要强调 SARSA 和 Q-learning 的实现,以及这两种方法所产生的 agent 行为的比较。
悬崖背景
在坚果壳中,我们将有一个 Cliff 类,它代表能够:
- 跟踪代理的当前位置
- 给定一个动作,决定代理的下一个位置,并判断是否游戏结束
- 给予反馈作为奖励
这些是课件中的主要功能。nxtPosition
函数接受一个动作,并返回代理在棋盘上的下一个位置,如果代理将其头部撞到墙上(到达边界),它将保持在同一位置。giveReward
函数将奖励-1 赋予除悬崖区域之外的所有状态,悬崖区域的结果是奖励-100。
让我们看看我们实现的板。
Cliff Walk Board
代理人从棋盘左端的符号 S 开始,结束游戏的唯一方法是到达棋盘右端的符号 G 。而 ***** 代表悬崖区域。
博弈
就玩游戏而言,我们将有一个代理类来代表我们的代理,在代理类中,有一个函数决定代理的动作,这也是ϵ-greedy 策略。(点击查看完整实施
关键区别在于play
功能:
在每一集(游戏的每一轮)中,我们在列表self.states
中记录我们的代理的行动、状态和奖励。在游戏结束时,我们以相反的方式更新 Q 函数(T1),如果方法是 SARSA(on-policy),新更新的 reward
(本质上是 Q(S', A')
)将直接应用于下一次更新,如果方法是 Q-learning,还有一个步骤
reward = np.max(list(self.state_actions[pos].values()))
取该位置所有动作的最大值到下一轮更新。最大化操作塑造了代理的行为,并使其能够采取更冒险的行动。
开/关策略比较
我用探索率为 0.1 的两种方法运行了 500 轮,并采用了他们学习的最后一个(state, action)
。
Result of SARSA
Result of Q-learning
我学到的结果与书中的最优结果略有不同,但这足以清楚地看出两者之间的差异。
结论
结论第一部分将引用 Sutton 的书,该书完美地总结了两种方法之间的差异:
Q-learning 学习沿着悬崖边缘行进的最优策略的值。不幸的是,这导致它偶尔会因为“ε-贪婪”的行动选择而掉下悬崖。另一方面,SARSA 将动作选择考虑在内,并通过网格的上部学习更长但更安全的路径。虽然 Q-learning 实际上是学习最优策略的值,但是它的在线性能比学习迂回策略的 SARSA 差。当然,如果ϵ逐渐减小,那么这两种方法都将渐近收敛于最优策略。
最后,请点击查看完整代码。欢迎您投稿,如果您有任何问题或建议,请在下面发表评论!
参考
[1]http://incompleteideas.net/book/the-book-2nd.html
基于 DQN 的车杆强化学习概念
深度 Q-网络简介
CartPole,也称为倒立摆,是一种游戏,你要尽可能长时间地平衡杆子。据推测,在杆子的顶端,有一个物体使它不稳定,很可能摔倒。此任务的目标是左右移动手推车,以便杆子可以尽可能长时间站立(在某个角度内)。
Figure 1: We can move the cart ONLY to the left and right.
在这篇文章中,我们将看看强化学习,这是人工智能中的一个领域,人工智能通过多次玩游戏来探索环境,直到它学会正确的游戏方式。
(Figure 2) Left: start of the training. Center: After a few episode of training. Right: Agent fully trained
正如您在此处看到的,在培训开始时,代理不知道将推车移动到哪里。过了一会儿,代理向一个方向移动,但是,当然,不可能以这样的速度把杆子带到另一边。对于最后一个问题,代理知道平衡杆子的正确方法,即反复左右移动。
奖励
让我们试着多理解一下这个游戏。同样,目标是尽可能长时间地活着。你撑竿的时间越长,你得到的分数就越多。这个分数,也叫奖励,是我们给代理人的,用来知道它的动作好不好。基于此,代理将尝试优化并选择正确的操作。请注意,当杆子超过 12 度角或手推车飞出屏幕时,游戏结束。
但是代理如何知道杆子的当前状态呢?数据应该是什么样的?
州
车杆的当前状态(向左或向右倾斜)被称为状态。一个状态可以是当前帧(以像素为单位),也可以是能够表示推车杆的一些其他信息,例如,推车的速度和位置、杆的角度和尖端的杆速度。对于这篇文章,让我们假设购物车的状态是上面提到的 4 个属性。
根据我们采取的行动,它可以导致不同的其他状态。假设极点开始是直的,如果我们向左走,极点多半是向右走,这是一个新的状态。因此,在每个时间步中,我们所做的任何动作都会导致不同的状态。
Figure 3: When we move the cart to the left, the pole tends to fall to the right side, and vice versa for the other direction.
q 学习
从上面的状态图可以看出,如果我们做了正确的决定,杆子不会倒,我们会得到奖励。换句话说,对于那些状态和动作对导致越来越进一步的状态也是期望得到一大笔奖励。因此,让我们称每个状态-动作对的期望回报为 Q 值,记为 Q(s,a) 。
在一个状态 (s) 期间,代理人采取了一个动作 (a) ,他们将立即获得该动作的奖励(如果游戏仍在进行,则为 1,否则为 0)。然而,早些时候我们提到我们想要考虑国家行动对的潜在未来回报。让我们用下面的等式来正式考虑这种情况。
Equation 1 : Idea behind Q-Learning
直觉上,我们想知道 Q(s,a) 如果我们处于 (s) 状态,做出 (a) 动作,我们能得到的预期回报是什么。通过做一个动作 (a) 得到一个奖励 (r) 后,我们会到达另一个状态(s)。然后,我们只需在 Q 表中查找,找到在状态(s’)下采取的最佳行动。所以,这里的想法是我们不需要考虑整个未来的行动,而只需要考虑下一个时间步的行动。伽马符号 (γ) 表示我们应该把多少注意力放在国家 s’的未来回报上。
在训练开始时,我们不知道任何状态-动作对的 Q 值。基于上面的等式,我们可以朝着最佳值的方向一点一点地改变 Q 值。
Equation 2 : Updating Q(s,a)
这个等式可能看起来有点可怕。别担心。我们将通过下图对其进行分解,看看这里发生了什么。
Figure 4: Breaking down equation 2
这里, Q(s,a) 会根据我们认为我们对 Q(s,a) 的了解和当前剧集告诉我们的 Q(s,a) (应该是什么)之间的差异进行更新。如果我们的 Q(s,a) 被高估,红色虚线框中的值将为负,我们将稍微降低 Q(s,a) 的值。否则,我们将增加 Q(s,a) 的值。我们对 Q(s,a) 的改变量取决于差值(红框)和学习速率(α)。
目前的 Q-Learning 有一个问题。那就是状态空间是巨大的。杆子角度或小车速度的每一个微小变化都代表一种新的状态。我们需要一个非常大的内存来存储所有可能的状态。对于这种手推车来说,处理这么多状态也许是可能的,但对于更复杂的游戏,如星际争霸 2 或 Dota 2,Q-Learning 本身不足以完成任务。
深度 Q 学习
为了解决这个问题,我们需要一些东西来近似一个函数,该函数接受一个状态-动作对 (s,a) ,并返回该对的预期回报。这就是深度学习的用武之地。它以仅根据训练数据逼近函数而闻名。请记住,我们不会在这篇文章中详细讨论神经网络。这将只是一个关于我们如何将深度学习与强化学习相结合的简介。
Figure 5: Incorporating network network in Q-Learning
假设我们想知道 Q(s,a=right) ,我们将环境的状态 (s) 输入到模型中。让神经网络进行计算,它将返回 2 个值。一个是向左移动时的预期回报,另一个是向右移动时的预期回报。由于我们对 a=right 感兴趣,我们将只从该输出的较低节点获取值。现在我们通过使用网络得到了 Q(s,a) 。
为了充分训练网络,损失函数是必不可少的。直观地说,在网络输出一个近似值 Q(s,a) 之前,我们已经知道这个值应该是什么(基于等式 2)。因此,我们可以惩罚网络所犯的错误,并让它通过反向传播来学习这个错误。
把它放在一起
现在我们已经讨论了状态、奖励、行动、Q-learning 和 DQN,特别是在这个车杆环境中。让我们看看 DQN 在杆位环境下的结果。
Figure 6: Playing cart-pole with DQN after fully trained
结论
这就是了。我们刚刚在一个推车杆子游戏中经历了 DQN 的概念。DQN 成功地应用于更多的游戏,尤其是雅达利游戏。它非常通用和健壮。所以,下次你心中有了一个环境,你可以直接插入 DQN,让它自己学习玩游戏。请记住,最近有许多其他深度强化学习技术可以更好更快地学习更复杂的游戏,如围棋或 Dota 2,但这是另一个时间的主题。
参考
- https://arxiv.org/pdf/1312.5602.pdf
- https://www . analyticsvidhya . com/blog/2019/04/introduction-deep-q-learning-python/
- https://web . Stanford . edu/class/psych 209/Readings/suttonbartoiprlbook 2 nded . pdf
- https://gym.openai.com/envs/CartPole-v1/
新闻推荐强化学习介绍(DDPG 和 TD3)
推荐系统暴露的深度学习方法
Photo by Juliana Malta on Unsplash
TL;DR:强化学习是推荐系统的理想框架,因为它具有马尔可夫性。状态是由用户分级的电影。动作是下一部要看的电影,奖励是它的评级。我用 DDPG/TD3 实现了这个想法。本文的主要部分涵盖了实现细节,讨论了 RL 的参数选择,介绍了动作评估的新概念,提出了优化器的选择(生命的拉达姆),并分析了结果。
我还发布了一个 ml20m 数据集版本,专门用于马尔可夫决策过程和 RL。
强化学习是一个相当难的话题。当我开始深入调查时,我意识到需要一个好的解释。这篇文章,加上代码是我的学校项目。 我目前是一名高二学生,我以一种更“社会研究”的方式理解难懂的数学概念。我希望这篇文章能对我这样的新人有所帮助。
我创建了一个 GitHub 项目,您可以克隆并跟随它!一定要去看看。你可以在下载部分下载我在电脑上处理过的所有东西。以及常见问题解答、数据集描述、一些文档、操作指南等。它经常更新。因为在写这篇文章,一周没推了。希望你喜欢!https://github.com/awarebayes/RecNN
本文提供了最流行的推荐方法的比较,以及对各种强化学习算法的深入研究,概述了每个可调整的参数以及更改它的后果。我还提出了评估深度学习推荐器的替代方法,并讨论了该应用程序的不同优化器。这也是我的遗产,因为我高中的最后一年就要到了,所以我没有足够的时间来完成它。如果你有兴趣支持这个项目,欢迎你的贡献!
内容
介绍
一个伟大的优化故事
- 静态与动态时间序列数据集
- 为什么您应该选择 HDF5
- 编码时间序列
新闻推荐方法
- 相似性搜索
- 矩阵分解
- 受限玻尔兹曼机器
- 因式分解机器
- 强化学习
- 方法比较
嵌入概述
- 深度学习中的信息论
- 信息平面定理
- 为什么嵌入=“瓶颈特性”有意义
马尔可夫材料概述
- 马尔可夫性质、链、游戏和决策
- 回报与价值
- 连续状态马尔可夫过程
非政策方法:
DDPG:深度确定性政策梯度
- 简单的解释
- 高级解释
- 用代码实现
- 为什么它不起作用
- 优化器选择
- 结果
TD3:双延迟 DDPG
- 说明
- 履行
- 结果
结论
政策上的方法:(下一篇文章……)
- PPO:最接近的策略优化
- 盖尔:生成性对抗模仿学习
无探索的非策略深度强化学习。)
介绍
这篇文章花了这么长时间来写有几个原因。
首先,因为数据集是动态的令人沮丧。当我开始构建原型时,仅仅一次迭代就要花费 40 多个小时。随着基本熊猫和优化的完成,它缩小到 1.5。当我实现动态数据集时,需要 10 分钟。如果你用状态表示法对状态进行编码,结果是 3。此外,我不能让 DDPG 工作,它增加了相当多的影响。因此,我最终使用了一个静态时间序列数据集+ TD3。不过,以后再说吧。
然而,最重要的是,大多数关于 TDS 的文章都是付费的。因此,没有优质的文章,没有 Patreon,没有钱乞讨。你可以多次点击这篇文章(请点击左上角的按钮),然后进入 GitHub 页面开始回购。
这是我的学校项目,主演,对我来说是必不可少的。这也会给我赢得项目竞赛的更好机会,甚至可能减少大学的付款。
时间序列的提示和技巧
完全避开熊猫!
正如你所看到的,pandas 是可以优化的,但最终,它的运行成本仍然很高,因为即使是我最好的优化也不能很好地扩展。x 轴代表 10 的幂。y 轴是花费的时间(秒)。此外,深度学习的问题是,我们经常在同一个数据集上反复运行模型。因此,让我们的数据集完全静态,消除所有熊猫的互动是完全有意义的。让我们运行数据集生成器并保存结果。如果你已经找到了我的回购协议,并继续跟进,笔记本位于 notes/1 下。香草 RL/ 1。生成静态 dataset.ipynb 。注意:完全是强制的;你可以下载我生成的数据集。
Scaling for different approaches
以 HDF5 格式存储您的数据!
有时时间序列不能完全输入你的内存。此外,HDF5 格式也是专门为此开发的。尽可能使用它,因为它比 PyTorch 快得多,并且自带 numpy 支持。唯一的限制是你的固态硬盘,所以你可能想买一个 PCI Express 的快速读取。
编码尺寸!
如果您使用静态大小的时间序列(也称为“滚动”ts),请确保将数据编码到较低的维度中。对于经典的 ML 方法,我们有主成分分析或简称 PCA。如果这对你来说是一个新单词,这里有一段视频。
您也可以使用 LSTM 自动编码器动态长度时间序列。从我的实验中,我注意到线性 AEs 对于滚动 ts 表现不佳。然而,我使用国家代表作为论文的作者提出。DL 的规则#1337 指出,90%的实际学习发生在前 10 分钟。所以我运行 TD3 模型,并使用它的状态表示模块来编码 ts。
新闻推荐方法
当我第一次开始钻研这些东西时,我意识到甚至连基本的推荐技巧都没有全面的指南。我最近发现了受限玻尔兹曼机器。本节旨在解决这个问题。我试图概述一些最流行的,并做一个快速的比较。更多的分析结果,请看下面的迷因。
相似性搜索
SS 是最容易理解的概念。只需在用户中寻找喜欢或不喜欢的类似电影。状态(被分级的电影)通常被表示为度量空间。有几种方法可以从原始电影索引中对其进行编码。第一个是使用嵌入层,这是现代 DL 应用程序中的常见情况。然后使用余弦或欧几里德距离等相似性度量对它们进行良好的排序。然而,回头看看更经典的 ML 方法,我们有局部敏感散列法。LSH 是一种算法技术,它以很高的概率将相似的输入项散列到相同的“桶”中。无论哪种方式,我们最终都会得到一堆与我们预测的状态相似的排序状态。然后我们看用户喜欢/不喜欢的电影并推荐它们。如果你想用这个方法,建议你去看看脸书的 Faiss 库: GitHub 链接。
矩阵分解
分解矩阵的思想,即把一个大矩阵分解成多个小矩阵的乘积,进一步扩展了相似性搜索。这个大矩阵可以表示为一个表格,行是电影,列是用户,值是收视率。我们通过假设大矩阵可以表示为两个较小矩阵的点积来扩展这个想法。它们代表隐藏(嵌入)表示。使用 PyTorch 可以轻松实现该过程:
user_matrix = user_embedding(users)
film_matrix = film_embedding(films)
ratings = (user_matrix * film_matrix).sum(1)loss = MeanSquares(ratings, target_ratings)
loss.backward()
“Users”是 userId 的整数向量。“Films”是 film_id 的整数向量。用户和电影矩阵是相应索引的 2D 嵌入。我们计算点积,因为我们想知道评级。您可能已经注意到,由于使用了嵌入,这种方法非常有限。你不能添加新的电影/用户到现有的电影/用户中,除非你使用类似增量 SGN 或水库计算的东西。只是上面方法的一篇很好的综述文章:链接。另外,如果你想深入了解 MF,我强烈推荐这个由 Luis Serrano 制作的视频。
受限玻尔兹曼机器
RBS 是自动编码器的早期变体。它属于基于能量的方法。作为自动编码器,用于降维。命名的受限部分意味着没有层间传播。该架构看起来像一个普通的两层线性网络。正向传球看起来很像前馈网络。
关键的区别在于 RBM 是概率性的。他们用贝叶斯方法工作。每当你试图计算网络的状态,也就是说,从这些权重和偏差分布的样本,你会遇到玻尔兹曼方程。这是粒子物理学中的一个方程。该模型的学习包括两个主要步骤:Gibbs 抽样和对比发散。
我从吴恩达对杰佛瑞·辛顿的采访中发现了这些机器。当被问及他最大的成就时,后者承认了他对 RBMs 训练算法的贡献。提醒一下:G.H .是一个支持反向传播的人。事实上,RBM 在网飞竞赛中取得了最高水平的成绩。如果你想了解更多基于能源的模型:这里有 Yann LeCun 的笔记。
RBM structure
因式分解机(非个性化)
因数分解机器已经被证明对点击率预测非常有用。它们的速度允许它们高度可伸缩,但是它们只适用于具有分类特征的数据。然而,它们值得大声疾呼。我们需要以某种方式将特征数据合并到我们的因子分解过程中。当然,我们可以认为一个特性就足够了:
ratings = linear(features.size(1), 1)loss = MeanSquares(ratings, target_ratings)
loss.backward()
如您所见,它们不能用于个性化推荐!
然而,考虑特征的标签-标签互相关是很酷的。我们刚刚学习了订单的概念。阶数是计算互相关的要素数。假设阶数为 2,我们需要计算两个特性的 CC。然而,这个特征是一个分类变量,那么如何计算两只猫的点积呢?更多的潜变量给了潜变量之神!可以使用向量来描述特征标签,并且可以使用我们用于矩阵分解的相同嵌入思想来回归这些向量。
ratings = linear(features.size(1), 1)(features)# factorization machine
latent = latent_embeddings(features)
latent_gram = latent * latent.T
features_gram = features * features.T
ratings += (latent_gram * features_gram).sum(1)loss = MeanSquares(ratings, target_ratings)
loss.backward()
这里有一篇文章帮助我更好地理解了这个概念:链接。
强化学习
使用 RL 进行新闻推荐的关键优势是马尔可夫性质和状态表示。因为我们不依赖任何嵌入,所以我们可以向任何用户推荐任何电影。为此应用程序生成的电影嵌入不依赖于嵌入层。我使用了简单的统计数据,如平均评级、收入、文本的 TF-IDF、流派等。… + PCA。因此,您可以添加新电影进行推荐,而无需重新训练网络。或者,您可以使用这些新的嵌入来表示状态。马尔可夫性保证了我们可以使用静态长度的时间序列。稍后详细介绍。
比较
警告:讽刺
Reinforcement Learning
Restricted Boltzmann Machines
Matrix Factorization
综上所述:RL 允许在任何规模的迷你批次上学习,静态长度时间序列的输入,不依赖于静态嵌入,在客户端工作,可用于迁移学习,具有可调的对抗率(在 TD3 中),支持集成,工作速度比 MF 快,并保留马尔可夫属性。最重要的权衡是准确性:像网飞/亚马逊这样的大公司仍然依赖 MF/RBM。
解释嵌入
与 Q-Learning 不同,这个特殊的应用旨在解决连续控制问题。在 Q-Learning 状态下往往是连续的,但动作本身是离散的。然而在我们的例子中,动作(=电影)不是离散的,而是一个向量。
但是我们如何得到这个向量,我们以后会尝试回归这个向量?上次我检查 ML20M 数据集时,没有找到任何向量。答案很简单:我自己生成了这些数字索引电影的矢量表示。大多数东西都是琐碎的:我解析了 IMDB/TMDB 数据,并应用了基本的统计数据来制作收集到的数据的向量(通过对类别进行编码,使用 TF-IDF,应用 PCA ),但我使用的最重要的东西之一是用于文本数据嵌入的 Google 的 BERT。我知道,嵌入在技术上是一个不同的东西,这些被称为“瓶颈特性”,但我将坚持这个词。
然而,为什么神经网络的一些中间层有意义呢?为什么可以将这些数据用作上下文信息?这些问题都可以在信息论领域找到答案。这在数字图书馆的背景下并不普遍,但是 Naftali Tishby 关于“保留信息的最大化”和其他关于为什么网络学习的提示的讲座很有意思。我推荐你看看这些!
一些亮点:
- 00:19:00 信息平面定理——对于一个相当大的典型 X,DNN 的样本复杂度完全由最后一个隐层的互编码器信息 I(X,T)决定;解码器信息确定前一隐藏层的精度(泛化误差),I(T,Y)。这个现象就是我在这个 app 里用的东西。你可以在 00:23 看到这个现象的可视化。
- 【https://www.youtube.com/watch?v=pFWiauHOFpY
马尔可夫材料概述
既然我们已经让我们的数据集工作了,理解了我如何将电影 id 转换成上下文向量,现在是时候回顾一些关于强化学习和博弈论的事情了。如果你阅读关于 DL/RL 的 Arxiv 论文,很容易看到基础知识被整理出来。
新闻推荐可以被认为是一个我们正在努力赢得的游戏。我们基于状态采取行动,而状态就是我们对用户的了解:收视率和观看的电影。动作是基于状态产生的,并描述空间中的一个点。
马尔可夫性质
从现在开始一切都严格遵守马尔可夫性质。引用维基百科:“如果一个随机过程的未来状态的条件概率分布(取决于过去和现在的状态)只取决于现在的状态,而不取决于之前的事件序列,那么这个随机过程就具有马尔可夫性质。”你可能会问,我为什么要在乎?我们假设我们只能基于当前状态采取行动,而忽略之前发生的任何事情。记住这一点,问题就变得更容易解决,因为我们不必担心过去。马尔可夫方法提供了一个框架,让你可以专注于当下发生的事情。
马尔可夫链
你也听过这个名字,因为 DeepMind 的 AlphaGo 用的是马尔可夫链蒙特卡罗。蒙特卡洛部分仅用于国际象棋或围棋等有限状态游戏。但是,马尔可夫链无处不在!为了简单起见,让我们考虑一个离散状态。我们还假设推荐是一个随机过程,这意味着我们随机遍历数据集。像任何其他物理链一样,马尔可夫链由称为节点的“循环”组成。每个节点都有一个条件转移概率。想象一下,这是一个随机的图遍历,当前访问的每个节点都有概率决定下一个访问哪个相邻节点。这里有一篇短文,有 19k 个赞,详细介绍。酷的事情是,它保留了马尔可夫属性:转移只取决于当前状态,即被访问的节点。
马尔可夫决策过程
马尔可夫链的思想可以进一步应用到我们的‘游戏’中。我们希望在我们的应用程序中使用 Markov 框架,因为它非常方便。然而,你如何将一个抽象的链条应用到状态-行动-回报-状态-行动…过程中呢?还记得我介绍的图表示例吗?马尔可夫决策过程也可以解释为一个图。我们假设我们当前的状态是图中的某个节点。因为它保留了确切的属性,所以我们不需要知道在到达那个状态(节点)之前发生了什么。从那个节点开始,有大量的动作可以以指定的概率被采取。这些动作可以被解释为将我们带到新状态的相邻边。当我们到达新状态时,我们会立即收到一个奖励。数据集中还有一件事用于 TD — Done 因为我们不想在最后一步之外传播时间差异。虽然,稍后会详细介绍。
States are green, actions are red, and the rewards are yellow
我构建的数据集由 State-Action-Reward-Next _ State-Done 值组成。GitHub 上有一个例子
连续状态马尔可夫过程
要完全理解正在发生的事情,最后一件事是行动不是离散的。我已经提到过几次,这个动作是一个矢量。我可以理解如何基于一个离散的数字在图形中移动,但是你用一个向量去哪里呢?所以不要把 MDP 想象成图形,而是一个 N 维的平面。为了简单起见,我将使用 2D 飞机作为例子。让我们考虑一个蚂蚁代理在操场上移动。此刻他知道他可能需要带一些树叶到它的房子里。唯一的问题是它的大脑中没有这种离散的“硬编码”动作。因此,它需要在环境中采取连续的步骤:移动它的四肢,咬紧它的下巴,躲避邪恶的蚂蚁。每走一步,奖励就会增加。它可能会意识到树叶就在附近的某个地方,而且方向是正确的。另一个重要的区别是我们假设时间步长是离散的。只有当我们知道一定数量的电影和用户指定的分级时,推荐才是可能的。考虑到 5.6 的电影和 1.3 的收视率,试图提出一些建议是很奇怪的。
如果你看一下上面的“连续行动与离散行动”的例子,就会发现有一个多智能体。它将肢体位置和角速度作为输入来提供环境。事实上,还有很多有趣的代理可以摆弄,如猎豹和波士顿动力公司的机器人模型。
.
.
.
价值功能与奖励
这一部分对于理解时间差异损失是必不可少的,这将在稍后讨论。在马尔可夫博弈中,我们有价值函数这种东西。所以价值函数并不意味着是一个估计回报的函数。价值只能表示行动对当前状态有多好。尽管,正如你将会看到的,它并不一定意味着对那个行为和状态的“给我奖赏”。它是一种更抽象的‘好’的度量,可以表示为一个连续的实值函数。函数的范围可以是任何实数。因此,该值不是[-5,5]中的整数。
第 1 部分:深度学习
现在,让我们暂时忘记我们学过的所有马尔可夫理论,试着从一个基本的 DL 方法开始。所以你决定建立一个基于深度学习的推荐系统,已经了解马尔可夫决策过程和数据集结构,总体上非常渴望直接投入行动。让我们尝试一种更基本的方法,暂时不用强化学习。你所拥有的只是一个简单的线性感知器和数据集:一堆状态、相应的动作和对这些动作的奖励。翻译成更人性化的语言:观看的电影,用户选择的下一部电影及其评级。我希望你继续思考你会用这些工具做些什么。
我们想推荐好电影;因此,我们训练网络来生成像动作这样的电影:
generated_action = model(state)
if is_good(reward):
loss = MeanSquares(generated_action, action)
loss.backward()
这种方法被称为“政策学习”,因为我们学习的是政策,是行动。它有它的应用,但是在端点上,PL 是非常有限的。如果你像这样训练一个网络,它会工作得很好,而且有点用。不过,你注意到‘is _ good’功能了吗?我们只学习“好”的行为,而不考虑其他任何事情。
Rewards distribution
第二部分:行动和批评
到目前为止,我们一直把奖励作为我们“学习”的标准。然而,分析动作不是更明智吗?这是演员-评论家方法背后的主要思想。为了清楚起见,让我介绍一下网络的命名。我们已经考虑过的网络叫做 Actor,它基于状态来行动。试图根据状态和行动者的行动来预测报酬的网络称为 critical。我们都知道,从看鲍勃·罗斯:每个人都需要一个朋友。所以让我们给我们孤独的演员增加一个人来嘲笑他的行为。
#teach the critic
generated_reward = critic(state, action)
reward_loss = MeanSquares(generated_reward, reward)
reward_loss.backward()# teach the actor
generated_action = actor(state)
value = critic(state, generated_action)if value > 0:
# learn the action
action_loss = MeanSquares(generated_action, action) # learn action
action_loss.backward()
最终,行动者会采取更好的行动(也许是也许),损失会收敛到零。然而,从那以后,我们在乍得 Pytorch 工作;我们可以在亏损的情况下做一些奇怪的事情,而不用担心反向传播!如果我们想直接使用评论家对演员产生的行为的奖励作为损失度量呢?Pytorch 让一切变得前所未有的简单!
#teach the critic
generated_reward = critic(state, action)
reward_loss = MeanSquares(generated_reward, reward)
reward_loss.backward()# teach the actor
generated_action = actor(state)
action_loss = -critic(state, generated_action)
action_loss.backward()
我们在这里做的是,我们用批评家作为我们的损失函数!从一开始就是这么打算的。注意标准前的减号。我们希望回报最大化。尽管如此,在机器学习中没有“最大化”这样的东西。我们经常反其道而行之:将负面因素最小化。
这就是 DDPG 算法。不过,如果你看报纸,评论家培训的代码会有所不同。这就是我们接下来要讨论的内容。
第 3 部分:实现时间差异
我们的评论家有问题。我们不需要估计回报。让我们引导动作的值。你为什么会问?答案很简单:未来的回报可能取决于当前的行动。将动作视为单个马尔可夫链步骤,我们希望最大化价值。什么是价值?
Markov 游戏环境中的 Value 是一个实值函数:V(state,action ),它表示(不是用整数奖励来表示——5 到 5,可以是任何实数)特定的操作对于相应的状态有多合适。
这就是我们需要把马尔可夫链带回来的地方。在这个特定的应用中,我使用 TD(1)版本的算法,这意味着我提前 1 步引导值。可以实现 TD(n),但是值迭代的次数是线性增加的。
为了学习价值函数,我们引导奖励和下一个状态和文本动作的值。你可以在这里阅读更多关于 TD 的内容。
# train the actor
next_action = actor(state)
action_loss = -critic(state, next_action)
action_loss.backward()
reward_loss.backward()# train the critic
next_value= critic(next_state, next_action )
expected_value = reward + next_value
value = value_net(state, action)
value_loss = MeanSquares(value, expected_value))
第四部分:你是在抄袭我吗?
要完全理解 DDPG,你只需要做最后一件事。它使用了目标和学习网络的概念。目标网络比学习网络更稳定,因为它通过软更新使用学习参数来更新。它显示出较少的过度拟合趋势,总体表现更好。此外,TD 损失略有调整。我们不需要为残局动作引导值。伽马参数服务于稳定性,我把它设置为 0.9 左右。
# train the actor
action_loss = -critic(state, actor(state))
action_loss.backward()# train the critic
next_action = target_actor(state)
target_value= target_critic(next_state, next_action )
expected_value = reward + (1 — done) * gamma * next_value
value = value_net(state, action)
value_loss = MeanSquares(value, expected_value))
value_loss.backward()# soft update
def soft_update(*networks, soft_tau=1e-2):
for target, learning in networks.parameters():
target= target.data * (1.0 — soft_tau) + learning .data * soft_tausoft_update(actor, target_actor)
soft_update(critic, target critic)
这是我使用的更新功能的实际截图
这就是 DDPG 的基本情况。
解释结果
在下一节中,我们将尝试比较并主要评估不同的强化学习算法。但是我们如何判断结果是好是坏呢?批评家网络为我们的行为赋予价值;但是,你确定这个值是否有意义。嗯,他们是基于评论家的损失。如果批评者的损失很小,而政策损失是合理的,我们就教演员。但是这些指标还不够。我也考虑动作的欧几里德距离和余弦距离。矩阵通常代表这一点。你可以看到用不同颜色的单个网格描述的距离。天气越暖和,距离就越大。例如,下面是真实的动作(我用统计嵌入产生的那些动作)看起来是什么样子。
Pairwise distances example
稍后,您将看到类似的培训和测试行动矩阵。另一种评估动作“人为性”的方法是使用自动编码器重建误差。我训练自动编码器模型来重构嵌入动作。重建误差被用作人为度量。这种技术被广泛用于异常检测,因为它是无监督的。此外,我对误差分布进行了核密度估计,以便进行漂亮的绘图和视觉比较。也可以暗示 Wasserstein 距离或 KL 散度。
An example of reconstruction error KDE
目标是使生成的测试分布接近真实的分布。生成的列车(或刚刚生成的列车)可以是不同的形式。
DDPG:深入观察
DDPG Training
GENERATED Actions
REAL actions
在这一点上,我所做的只是复制粘贴 Higgsfield 的 RL 冒险代码,并做了一些小的调整,以适应 torch 1.1
看起来我们有发现了!矩阵看起来很酷?一些相关性正在显现…损失在下降…等等,说一下比例尺上是什么?为什么我几乎没有余弦距离?为什么保单亏损会落入幽冥境界?为什么我的宠物人工智能不能正常工作?
这才是 RL 真正的快乐!
无数事情都可能出错!也许我应该玩玩学习率?诚然,这是熟悉 DL 的人首先想到的。然而,为什么我的错误首先在增长呢?我在 DL 里没遇到过这些事… WTF 正在跟 v 网优化发生关系,PyTorch?当过程开始时,它似乎没有太大的影响,但随后梯度爆炸,一切都被遗忘了…所以,很可能,学习率是非常好的。也许那是因为时差自举?但 TDB 不仅使用通过软 tau、TD 软更新的目标值网络,它还利用一个称为 gamma 的参数对未来预期进行加权。
P_gamma = 0.9
P_min_value=-5
P_max_value=5
P_soft_tau=1e-2
P_policy_lr = 1e-5
P_value_lr = 1e-6
P_actor_init_w = 3e-4
P_critic_init_w = 3e-4
我该怎么做?也许我设置了错误的参数来剪裁值:
expected_value = torch.clamp(expected_value, min_value, max_value)
让 DDPG 明白
有一件事让我迷惑不解,那就是“重量限制”的工作原理与人们的预期略有不同。如果我们用较小的数字初始化网络的最后一层的权重,它将生成较小的向量。不对!它的作用正好相反。所以这是余弦距离与实际作用的分布相比如此之短的主要原因。但是,对于欧几里得来说,似乎没有太大的影响。
此外,您是否注意到值裁剪的最小和最大参数分别是最小和最大奖励?这也需要改变,正如我在马尔科夫财产中提到的。我设置为奖励* n_td_steps。这很好,最后,损失很少低于 6-7。
你可能没有意识到,但是一个较小的批评家学习率会导致演员过度适应。如果政策损失下降得非常快,改变 LR,因为参与者过度适应了。记住:不是最直观的东西!
始终调试并跟踪以下参数:value、target_value (mean,std)、expected_value (mean,std)、generated_action(余弦距离、Gramian、方差、std、means、samples KL 到原始分布的距离)。总是在测试结束时绘制这些指标。
P_critic_init_w=3e-5
P_actor_init_w=3e-1
P_min_value=-10 # or -100
P_max_value=10 # or 100
我们解决了一个不工作网络的 RL 部分,现在损耗增长的原因完全是 DL。这里有一些给你的建议:
- 和优化者一起玩。有这么多是有原因的。从 Adam 开始,试试 Hinton 的 RMS prop,纯 SGD,带温重启的 SGD 和 CosineAnnealingLR。虽然,如果你不在乎,有一个整洁的新算法供你尝试!它叫 RAdam: GitHub link 。我尽可能使用它,因为它减少了要优化的参数数量。后面会解释。
- 极其小心地使用 grad_clip。在价值网络上使用它会改变价值函数的符号。我不明白为什么会这样。但是政策似乎运作良好。我花了将近一周的时间才弄明白。不,是真的。
- 重量衰减对于避免过度拟合至关重要。此外,它很容易与 Pytorch 优化器一起使用。将其设置为较小的值,爆炸渐变会在几秒钟内消失。此外,使用它与 grad 剪辑的演员。
这应该会让您/我的数据中的 DDPG 重现生机。
DDPG 参数会改变什么:
- 价值网络学习率-影响生成的操作之间的欧氏距离。它还改进了余弦距离,但规模较小。仅适用于 SGD/Adam,对拉达姆无关紧要。
Value LR is too big: Euc is skyrocketing value LR is balanced
- 演员权重初始化-改变动作空间中余弦距离的多样性。如果您发现您的动作距离几乎没有变化,请从更改此参数开始。
Small Cosine distance as the result of lousy weight initialization
- 软 tau —负责目标网络更新。它影响应用于目标网络的损失函数的“过山车”的延迟。你可以看到这两种损失彼此相似。如果您运行代码,您将看到价值损失慢慢转化为策略损失。正如我所说,它影响了这种翻译的通顺性。如果某样东西对你不起作用,这是另一个需要考虑的关键参数,但是不要高估它。
- γ—是时间差异中预期动作的权重。Imho 不那么重要。较小的值可能会导致梯度爆炸。
- 最小/最大值—我将它们设置为+- 10。你可以用另一个大数字做实验。或者,您可以使用 x*n_td_iterations,其中 x 是最小/最大可能回报。它使学习过程更加严格,但违背了价值函数的性质。或者,如果你根本不在乎过山车的损失,你可以使用 numpy infinity。该参数对值测试损失有积极影响。
总是看损失函数的尺度。该值应该在[0,10]之间,而策略在 TD 削波的最小/最大值范围内。如果涨到 10e7,你就是在浪费时间调试!
为什么优化器的选择很重要
我已经注意到了这一点,但我怎么强调都不为过。始终使用最先进的优化程序。每天查看 Arxiv,订阅 twitter bot 并保持警惕,因为机器学习社区现在正处于生产力的巅峰。
Adam 通常是优化的默认选择。此外,这种情况应该改变。亚当是你最糟糕的选择之一。为什么?它对学习速度非常敏感。回想一下学习率调度程序:仔细记住将里程碑放在哪个步骤,使用 CosineAnnealingLR 热重启 SGD,CyclicLR。以上所有的技术都已经成为过去——不要再摆弄学习速度了。就用 RAdam!自适应学习率的方差及超越!
RAdam 是 Adam 的意识形态扩展,它使用了一个叫做学习率热身的聪明绝招。不幸的是,拉达姆的作者没有受到足够的欢迎,所以没有详细的解释。你可以阅读他们的 Axriv 论文。
As in Figure 8, we assume gradients follow a normal distribution (mean: \mu, variance: 1). The variance of the adaptive learning rate is simulated and plotted in Figure 8 (blue curve). We can see that the adaptive learning rate has a significant variance in the early stage of training.
然而,我声称仅仅通过改变优化器,我就能够用 DDPG 算法达到 TD3 那样的性能。并且在两种情况下都有更少的过度拟合
让我们继续关注亚当,看看它的表现如何。
这是亚当损失的样子。人们不必是博士也能发现明显的值过度拟合。还有,你注意到保单损失了吗?它看起来出奇的小。最大奖励 5,最大 TD 削波 10。
火车动作似乎过拟合,没有太多的欧几里德距离显示出来,但好吧…
Adam train actions: looking good
损失在 7.5 似乎是合理的。是吗?好吧,让我们看看自动编码器重构误差。
and_that_was_the_moment_he_knew.png
只需查看 ae rec 误差分布和/或比较它们之间的各种指标,就可以发现问题所在。最愚蠢的选择是只计算 KL/w 距离。你也可以看看更有意义的统计指标,比如均值/标准差/峰度/偏斜度。
Adam test actions: oops! All overfit copies!
CosDist < 0.4,Euc < 3。无需言语。还有我的一个观察:余弦矩阵定义了向量方向的角度分布。你可以用基本的数学来形象化它。
哇,那是一些美好的回忆!我希望我能记住那么多。不幸的是,这不是倾斜。你可以直接跳到 inro TD3,这无疑会有助于过拟合,但让我们尝试使用 RAdam 代替。换 optim 就行了。当你定义优化器时,从 Adam 到 RAdam。
搬到拉达姆
所以我用 RAdam 运行了同样的代码,这就是事情的经过。
DDPG Radam Error
Radam train actions
首先,没有令人讨厌的价值过度拟合。而且,价值损失较少。与 Adam 相比,收敛要慢得多。在 400 左右,你可以看到一个明显的下降趋势。这里需要两倍的迭代次数才能注意到这个模式。还有,价值损失平滑多了。火车的动作在欧几里德距离上有更大的距离。余弦距离似乎在所有实验中都保持不变。好了,让我们看看测试动作:
RAdam test actions: As you can see, we gained three times as much Euclidian distance and 1.5x cosine
成绩不言自明!使用 RAdam 可以更好地近似测试分布,但是训练分布更加模糊。然而,我们只关心测试。
Radam results for the reconstruction error.
然而,RAdam 有一个缺点。很难用它来微调模型。如果让模型运行 RAdam,训练分布将很快收敛到真实分布。此外,测试发行版将在最右边像一个小松果。需要注意接近-5 的策略损失,或者手动停止学习。如果你不阻止它,就会发生这样的事:
RAdam overfitting
政策网络过度拟合:价值正在迅速下降。亚当的情况并非如此。
Value tends to deteriorate for some reason as we will find out in a moment that is due to overfitting.
结合两者
我的最终解决方案是结合这两个优化器。首先,我用 RAdam 学习,通过在过度拟合之前创建检查点,我确保我有一个出色的预热模型。然后我加载这些模型,用 Adam 训练它们,以获得更好的性能。不幸的是,没有自动化的空间:您找到最小的策略损失,并从最近的检查点开始。
它可以更好地表现训练版,但是测试版要差得多。但是这种微调方法对 TD3 算法更有用。我们正在切换到…现在!
附注:所有模型都可以在 github 页面上下载(包括原始的拉达姆和经过微调的亚当)
TD3
TD3 代表双延迟 DDPG。三是论文作者提出的改进数量。正如我已经说过的,它是深层确定性政策梯度的延伸。区别如下:
- 无剪辑双 Q 学习。在这个算法中,我们有两个价值网络。此外,我们没有裁剪期望值,而是取最小的目标值。这个简单的技巧大大减少了政策代理人利用和愚弄批评家的机会,因为现在它必须愚弄他们两个。
#ddpg
target_q_value = target_value_net(next_state, next_action)
expected_value = reward + (1.0 - done) * gamma * target_q_value
expected_value = torch.clamp(expected_value, min_value, max_value)#td3
target_q_value1 = target_value_net1(next_state, next_action)
target_q_value2 = target_value_net2(next_state, next_action)
target_q_value = torch.min(target_q_value1, target_q_value2)
expected_value = reward + (1.0 - done) * gamma * target_q_value
2.延迟的策略更新。与价值观相比,我们更新政策的频率较低。对于每三个值的更新,我们只更新 actor 一次。这允许更好的价值估计,也防止演员愚弄。附注:这不是一个很难的概念,而且非常容易实现。我对 DDPG 使用了延迟策略更新。
3.动作平滑。TD3 向目标动作添加了噪声,通过平滑 Q 以及动作中的变化,使得策略更难利用 Q 函数错误。在我的例子中,噪声是从~Normal(0,0.1)中提取的,并被剪裁以适合[-.3,.. 3]。
next_action = target_policy_net(next_state)
noise = torch.normal(torch.zeros(next_action.size()), noise_std)
noise = torch.clamp(noise, -noise_clip, noise_clip)
next_action += noise
TD3 结果
该算法具有与 DDPG 几乎相同的参数(不包括最小/最大剪辑,添加噪声参数)。所有的代码/数据集/预训练模型都在 GitHub 上。TD3 位于 notes/1 下。香草 RL/2.ddpg
TD3: Value loss is growing if you do not stop it. I stop it at 1000
Final loss
Test distribution is way better approximated
TD3: Train action pairwise distances 3x cosine 4x euclidean (compared to ddpg Adam)
TD3: Test action pairwise distances 3x cosine 4x euclidean (compared to ddpg Adam)
Real Action Distances. Most of them are somewhat between 10–12
唷!我们成功了!你看到的是我对政策方法的最终结果。现在让我们讨论损失和其他东西。首先:价值损失正在增加。这种现象是合理的,因为如果我们看价值观,他们不是过度拟合。在 ddpg 中,它们先上升,然后又下降。
TD3: value over time
真实动作和生成动作中的距离余弦距离不同。它大约产生 0.6,而真实值是 1。可以通过将噪声 std 设置为更高的值来增加噪声。然而,我认为这是欺骗,因为我们增加了更多的噪音。或者,您可以结合策略损失使用另一个损失函数来增加更多余弦多样性
在我以前的一次提交中,我用新的 Pytorch JIT 编译器实现了余弦和欧几里德距离损失惩罚。它返回成对距离矩阵,如上所示。你可以对这个东西做任何你想做的事情(即比较方差、标准差、均值、KL),使它看起来像一个真实的动作。
@torch.jit.script
**def** torch_cdist_euc(x1, x2):
x1_norm = x1.pow(2).sum(dim=-1, keepdim=**True**)
x2_norm = x2.pow(2).sum(dim=-1, keepdim=**True**)
res = torch.addmm(x2_norm.transpose(-2, -1), x1,
x2.transpose(-2, -1), alpha=-2).add_(x1_norm)
res = res.clamp_min_(1e-30).sqrt_()
**return** res@torch.jit.script
**def** torch_cdist_cos(x1, x2):
x1_norm = x1 / x1.norm(dim=1, p=2).unsqueeze(1)
x2_norm = x2 / x2.norm(dim=1, p=2).unsqueeze(1)
res = 1 - torch.mm(x1_norm, x2_norm.transpose(0,1))
**return** res
对预测进行排序
是时候测试我们的算法了。你可以下载所有预先训练好的模型,自己测试。该文件在 notes/results/1 下。排名/ (可点击)。
下面你会看到距离排名的例子。它支持 scipy。空间距离还是你的空间距离。在笔记本里,我收录了以下内容:欧几里德、余弦、相关、堪培拉、闵可夫斯基、切比雪夫、布雷-柯蒂斯、城市街区(曼哈顿)。余弦排名允许更好的语言和流派多样性,看起来非常类似于相关性。
DDPG
DDPG euclidian ranking
DDPG cosine ranking
TD3
TD3 euclidian ranking
TD3 Cosine Ranking
就是这样!你可以在这里看到两种算法的所有排名示例。
结论
所以我们在这里。如果你最终成功了,祝贺你。这似乎是一个简单的项目:只是使用现有的 Higgsfield 算法实现新数据,但我在过去的一个月里每天工作 6 个小时,以使它工作,计算出 DDPG 的参数,并了解 PyTorch 的深度,尽管这篇文章是最难的部分。我已经在写这个结论了,但是我还没有写完比较部分的受限玻尔兹曼机。回购未推出。我想知道结果如何…你明白了吗?
TD3 的实施前景看好。此外,排名很好,尽管还有改进的空间。我用的是 O(n)算法。如果你想在生产中使用嵌入,强烈推荐你查看一下 Milvus 库。
我也还没有实现一个网络应用程序。已经得到了我的另一个反应和基本布局回购提交。希望它能很快出版。如果没有,你可以自己做:所有的型号都发布了。
老实说,我没什么可说的了。我已经通过 7131 个单词了。
无论如何,这是我的一些想法:
- 因为这是一个推荐项目,你可以使用前 k 排名来采取行动。这些排名结果可用于帮助学习过程:
- 您可以添加另一个损失来计算实际排名和生成的操作之间的距离。(评论家的又一次损失)
- 分级行动的价值函数有何不同?它能根据距离进一步调整吗?
2.向生成的动作添加另一个余弦/欧几里德损失。上面公布了脚本。
3.实现一个排名网络。这是政策的延伸。它将动作作为输入,并根据 top k 排名学习生成真实动作。
如果你碰巧实现了这些,请随意提交。
谢谢您:
中:郭平、/ 기계공학부 ]、杰基·诺亚、沙迪·哈萨布、亚历山大·马凯夫、希瓦姆·阿克豪里、迪克沙·加尔格、西达斯·普拉布、佐哈尔·科马罗夫斯基、哈里·普拉萨德、帕纳吉奥蒂斯·卡普罗斯、维沙尔·施里尼瓦斯、伊维特·李、Lxs Lxs、尼尔斯·施吕特、阿尤什·库马尔、迪安·索、科迪·布什内尔、马库斯·奥、、谢纳维、桑惠恩、西蒙·于、张玉洲、黄、兰杰德·本、阿克塞尔·施万科
GitHub: 海军-谢、骑士 ofK9 、托马托、利斯塔希、 jungi21cc 、 nutorbit 、大卫江特、金明、 hb1500 、耶林敏、萨利赫-哈桑 陈明霞,阿什图,丁达诺维塔萨里,kk-海恩克,巴兹图,尤尤安尤,维-斯里,桑杰门,伊维特里——在我的项目实施之前,你们就相信了。 由你开始的那些开端激励我继续工作。
如果没有你出色的课程和指导,我不会写这篇文章。希望明年我能去 MIPT。
对新来者:
请随意介绍你自己。上了高中就开始深度学习了。尽管那时,我创建了无数其他主题的 GitHub 项目,但这些项目并不逊色。唯一的问题是没有人知道这件事——除了几个朋友,没有一个人知道。如果你正在努力做某件事,一定要告诉你这件事。是别人的欣赏让你不断前进。附言:不要再为学龄前儿童写另一个 Keras 教程;)
下一篇文章
最近,我发表了一篇新文章,内容涉及强化推荐系统:
在我的强烈推荐下,OffKTopPolicy 现在可以开箱即用,没有任何先决条件…
towardsdatascience.com](/top-k-off-policy-correction-for-a-reinforce-recommender-system-e34381dceef8)
还会有什么
下一篇文章将解决一些我们没有探索的问题。这当然需要一些时间,但在我看来,BCQ 很容易融入 DDPG。如果您想了解更多关于使用静态数据集的 RL 应用程序的信息,请访问以下链接:
Arxiv 文章:【https://arxiv.org/abs/1812.02900
Pytorch 代码:【https://github.com/sfujim/BCQ
有问题吗?评论是开放的…
GitHub 回购:https://github.com/awarebayes/RecNN
别忘了鼓掌!
再见!
组合优化的强化学习
使用深度强化学习和图形神经网络解决困难优化问题的学习策略。
为什么优化很重要?
早在几百万年前人类诞生之初,每一项技术创新和每一项发明都是由聪明人的聪明才智设计出来的,它们改善了我们的生活,提高了我们在地球上生存和发展的能力。从火到轮子,从电学到量子力学,我们对世界的理解和周围事物的复杂性已经增加到我们常常难以直观地把握它们的程度。
今天,飞机、汽车、船舶、卫星、复杂结构的设计者和许多其他努力都严重依赖算法的能力来使它们变得更好,通常是以人类永远无法实现的微妙方式。除了设计,优化在网络路由(互联网和移动)、物流、广告、社交网络甚至医学等日常事务中也起着至关重要的作用。未来,随着我们的技术不断改进和复杂化,解决巨大规模难题的能力可能会有更高的需求,并将需要优化算法的突破。
组合优化问题
广义地说,组合优化问题是涉及从有限的对象集合中找到“最佳”对象的问题。在这种情况下,“最佳”由给定的评估函数来衡量,该评估函数将对象映射到某个分数或成本,目标是找到值得最低成本的对象。大多数实际上感兴趣的组合优化问题(从现在开始称为 COPs)也非常困难,因为即使问题规模很小,集合中的对象数量也会快速增加,使得穷举搜索不切实际。
为了使事情更清楚,我们将把重点放在一个具体的问题上,即众所周知的旅行商问题(TSP)。在这个问题中,我们有 N 个城市,我们的销售人员必须访问所有的城市。然而,城市之间的旅行会产生一些费用,我们必须找到一个旅行,使旅行到所有城市并返回起始城市的总累积费用最小化。例如,下图显示了美国所有首都城市的最佳游览:
这个问题自然出现在许多重要的应用中,例如规划、递送服务、制造、DNA 测序和许多其他应用。寻找更好的旅游有时会产生严重的财务影响,促使科学界和企业投入大量精力寻找解决此类问题的更好方法。
在为包含 K 个城市的 TSP 实例构建旅程时,我们在旅程构建过程的每个阶段都要删除一个城市,直到没有城市了。在第一阶段,我们有 K 个城市可以选择开始旅行,在第二阶段,我们有 K-1 个选项,然后 K-2 个选项,等等。我们可以构建的可能旅程的数量是我们在每个阶段拥有的选项数量的乘积,因此这个问题的复杂性表现为 O(K!)。对于少数人来说,这似乎还不算太糟。假设我们有一个 5 个城市的问题,可能的旅游次数是 5!=120.但对于 7 个城市,它增加到 5040,对于 10 个城市,它已经是 3628800,对于 100 个城市,它是一个巨大的 9.332622e+157,这比宇宙中的原子数量多很多个数量级。现实世界中出现的 TSP 的实际实例通常有数千个城市,并且需要在大量文献中已经开发了几十年的高度复杂的搜索算法和试探法,以便在合理的时间(可能是几个小时)内解决。不幸的是,现实应用中出现的许多复杂问题都有独特的细微差别和限制,这使得我们无法使用最先进的解决方案来解决已知的问题,例如 TSP,而需要我们开发针对该问题的方法和启发式算法。这个过程可能是漫长而艰巨的,并且可能需要领域专家的工作来检测特定问题的组合搜索空间中的一些结构。
由于近年来深度学习在许多领域取得了巨大成功,让机器学习如何自己解决我们的问题的可能性听起来非常有希望。将为困难的 COP 设计算法的过程自动化可以节省大量的金钱和时间,并且可能产生比人类设计的方法更好的解决方案(正如我们在 AlphaGo 等成就中看到的那样,alpha go 击败了人类数千年的经验)。
用图形表示法学习
对这个问题的早期尝试出现在 2016 年,一篇名为通过图学习组合优化算法的论文。在本文中,作者训练了一种称为 structure2vec 的图神经网络(我在另一篇文章中讨论了图神经网络)来贪婪地构造几个硬 COP 的解决方案,并获得了非常好的近似比率(生产成本和最优成本之间的比率)。****
基本思想是这样的:问题的状态可以表示为图形,神经网络在图形上构建解决方案。在解决方案构建过程的每次迭代中,我们的网络观察当前的图,并选择一个节点添加到解决方案中,之后根据该选择更新图,并重复该过程,直到获得完整的解决方案。
作者使用 DQN 算法训练他们的神经网络,并展示了学习模型归纳到比训练时大得多的问题实例的能力。他们的模型甚至可以很好地推广到 1200 个节点的实例(同时在大约 100 个节点的实例上进行训练),并且可以在 12 秒内产生解决方案,有时比商业求解器在 1 小时内找到的解决方案更好。他们方法的一个很大的缺点是他们使用了一个“助手”函数,来帮助神经网络找到更好的解决方案。这个助手功能是人为设计的,并且是特定于问题的,这是我们想要避免的。
这种基于图的状态表示的使用很有意义,因为许多 COP 可以非常自然地以这种方式表达,如 TSP 图的这个示例所示:
节点代表城市,边包含城市间的距离。可以在没有边属性的情况下构建一个非常相似的图(如果我们出于某种原因不知道距离)。近年来,对图形进行操作的神经网络模型的流行程度令人难以置信地上升(无论是否假设知道结构),最显著的是在自然语言处理领域,其中变压器风格的模型已经成为许多任务的最先进技术。
有很多优秀的文章详细解释了 Transformer 架构,所以我不会过多地钻研它,而是给出一个非常简要的概述。谷歌研究人员在一篇名为“ 注意力是你所需要的全部 ”的著名论文中介绍了 transformer 架构,并用于处理 NLP 中出现的序列问题。不同之处在于,与 LSTMs 之类的递归神经网络(明确地输入一系列输入向量)不同,变换器将输入作为一组对象输入,并且必须采取特殊手段来帮助它看到“序列”中的顺序。转换器使用几个层,由多头自关注子层和全连接子层组成。
与图的关系在关注层中变得很明显,这实际上是输入“节点”之间的一种消息传递机制。每个节点观察其他节点,并关注那些看起来对它更“有意义”的节点。这与 图注意力网络 中发生的过程非常相似,事实上,如果我们使用一个掩码来阻止节点向非相邻节点传递消息,我们会得到一个等效的过程。
学会在没有人类知识的情况下解决问题
他们在发注意!学会解决路由问题 ”,作者解决了几个涉及图上路由代理的组合优化问题,包括我们现在熟悉的旅行推销员问题。他们将输入视为一个图,并将其提供给一个修改过的 Transformer 架构,该架构嵌入了图的节点,然后依次选择节点添加到旅程中,直到构建了一个完整的旅程。将输入视为一个图表是比输入一系列节点更“正确”的方法,因为它消除了对输入中给出的城市顺序的依赖性,只要它们的坐标不变。这意味着,无论我们如何排列城市,给定图形神经网络的输出将保持不变,这与序列方法不同。
在本文介绍的体系结构中,图是由 transformer 风格的编码器嵌入的,它为所有节点生成嵌入,并为整个图生成单个嵌入向量。为了产生解决方案,每次给定一个单独的解码器网络一个特殊的上下文向量,该向量由图嵌入、最后一个和第一个城市的嵌入以及未访问城市的嵌入组成,并且它输出未访问城市的概率分布,该概率分布被采样以产生下一个要访问的城市。解码器按顺序产生城市,直到旅程完成,然后根据旅程的长度给予奖励。
作者使用称为增强的增强学习算法来训练他们的模型,这是一种基于策略梯度的算法。他们版本的伪代码可以在这里看到:
它们使用展开网络来确定性地评估实例的难度,并定期用策略网络的参数更新展开网络。使用这种方法,作者在几个问题上取得了很好的结果,超过了我在前面提到的其他方法。然而,他们仍然在多达 100 个节点的小实例上训练和评估他们的方法。虽然这些结果很有希望,但与现实世界相比,这种情况微不足道。
扩展到非常大的问题
最近,论文“ 通过深度强化学习 在大型图上学习启发式算法”向现实世界规模的问题迈出了重要的一步。在本文中,作者训练了一个图卷积网络来解决诸如最小顶点覆盖(MVC)和最大覆盖问题(MCP)之类的大规模问题。他们针对这些问题使用了一种流行的贪婪算法来训练神经网络嵌入图并预测每个阶段要选择的下一个节点,然后使用 DQN 算法对其进行进一步训练。
他们在有百万节点的图上评估了他们的方法,并取得了比当前标准算法更好更快的结果。虽然他们确实使用了手工制作的启发式方法来帮助训练他们的模型,但未来的工作可能会消除这种限制,并学会从头开始解决巨大的问题。
总的来说,我认为在具有巨大搜索空间的问题中寻找结构是强化学习的一个重要而实用的研究方向。许多 RL 的批评者声称,到目前为止,它只被用于解决游戏和简单的控制问题,将它转移到现实世界的问题仍然非常遥远。虽然这些说法可能是真的,但我认为我在这篇文章中概述的方法代表了非常真实的用途,可以在不久的将来使 RL 受益,很遗憾它们没有像视频游戏的方法那样吸引那么多的关注。
我实现了一个相对简单的算法,使用图卷积网络来学习解决最小顶点覆盖问题的实例。随意查看。
手机游戏的强化学习
使用最先进的强化学习来学习大规模玩 Android 游戏
Image Source: pixabay.com
介绍
自从 5 年前随着最初的 DQN 论文被引入以来,深度强化学习已经引起了很大的轰动,该论文显示了强化学习如何结合神经网络进行函数逼近,可以用来学习如何从视觉输入中玩雅达利游戏。
从那以后,算法有了许多改进,不断超越以前的基准。研究和测试新算法通常使用快速稳定的 Atari 基准,以及定制的环境,如在 OpenAI Gym 和 DMLab 中发现的那些环境。此外,我们可以使用模拟器运行数百个使用 Gym Retro 库的经典主机游戏。
对于现代游戏来说,最近的主要焦点是最难的竞技游戏,特别是 Dota2 和 Starcraft2。两者都从 OpenAI 和 DeepMind 中取得了令人印象深刻的成果,在一个巨大的分布式集群中进行训练,达到了数千年游戏经验的总和。在这两种情况下,观察/输入都是数字特征,而不是视觉帧,绕过了 AI 学习如何提取这些特征的需要,就像通常对 Atari 游戏所做的那样。所需的计算资源也不是大多数研究人员或小公司所能提供的。
在这里,我试图将 RL 应用到一些现代的移动 android 游戏中,仅使用视觉输入作为观察,并使用合理的预算量的计算资源,与学习玩 Atari 游戏时通常被认为是“样本高效”的一样。
Android 环境
我使用可配置数量的 Android 模拟器作为 RL 代理学习游戏的环境。每个仿真器由异步驱动程序控制,该异步驱动程序通过抓取视觉帧、使用 RL 策略选择动作、将该动作发送回仿真器以及将转换数据发送回用于训练来收集训练经验。
不是真正的仿真
就其核心而言,android 仿真器是一个“真正的仿真器”,能够仿真 ARM 指令集,并可能能够用作完全仿真的 RL 环境,类似于 ALE 或 gym-retro 环境,其中当需要下一个动作/观察步骤时,可以根据需要暂停/恢复仿真。然而在现实中,Android 模拟器上的模拟速度非常慢,尤其是对于游戏,对于我们的任务来说是不可行的。
唯一的选择是使用 CPU 的硬件加速来运行仿真器(在 windows/linux 上使用 HAXM/KVM)。在这种情况下,使用 x86 android 映像,android 指令使用虚拟化直接在主机 CPU 上实时运行。这让我们达到了我们需要的稳定的 android 性能,但也有一些缺点:
- 这意味着仿真器实时运行。这意味着我们需要一致地抓取帧、选择动作并以最小的延迟发送这些动作。例如,代理不能暂停并等待训练步骤完成,因此每个环境实例必须异步运行
- 这也意味着我们受限于“实际游戏时间”,例如 60FPS,相比之下,模拟环境如 ALE 可以将模拟游戏时间加快几个数量级,从而加快训练速度
- 因为 android 模拟器现在运行的是 CPU 虚拟化,所以在流行的云提供商的 VM 实例上运行模拟器是有问题的。其中一些提供者为此支持“嵌套虚拟化”,但实际上,我无法很好地实现这一点。模拟器要么无法启动,要么成功启动但运行速度比在非 VM 服务器上慢得多。这限制了我们在定制服务器版本或“裸机”云服务器上运行这些环境,而这种情况很少见。
帧抓取
环境驱动程序以固定的可配置速率从仿真器获取可视帧,并跟踪由于代理中的延迟而导致的“丢帧”数量。主要目标是确保最少的丢帧,这可能对游戏不利。这需要限制在一台机器上运行的模拟器的数量,特别是当训练也在同一台机器上进行时,以确保有足够的 CPU 带宽用于表演和训练。每个模拟器需要 2 个专用 CPU 内核(4 个 vcpu)才能获得稳定的游戏体验。
我将帧抓取配置为 30FPS,跳帧为 2 或 4(相比之下,Atari 培训中通常使用 60FPS 的跳帧为 4)。
android 模拟器以 320x480(纵向)分辨率运行,以最小化渲染开销。这是游戏仍能正常运行的最低分辨率。这为我们提供了大小为 320x480x3 的原始观察值,然后将其缩小到 80x120x3,用于作为策略输入的最终观察值(与大多数 Atari 研究中使用的 84x84x1 灰度观察值相比)
行动延迟
我遇到的另一个问题是,从我发送动作到游戏实际接收/执行动作,Android 模拟器存在固有的延迟。延迟大约为 60-90 毫秒,这似乎可以忽略不计,学习应该能够解释这一点(甚至 DeepMind 最近的星际争霸 2 作品也提到了大约 250 毫秒的延迟),但实际上,我发现这些会损害最佳学习如何玩的能力。
为了证实这一点,我为 OpenAI gym 的 Atari 环境创建了一个定制的包装器,其中插入了一个人工的可配置的延迟,从代理发送一个动作开始,直到它被发送到实际环境。即使有 60-90 毫秒的延迟,与没有延迟相比,当训练有延迟的调谐 RL 算法时,我看到最终性能有不可忽略的下降。
这并不是说我们不应该学习如何处理这种延迟,因为在将 RL 应用于机器人或无人机等实时任务时,这些延迟可能是常见的情况。但是,在测试和比较 RL 算法时,可能值得考虑将这种延迟插入到常用的基准任务中,以确保算法对它们是健壮的。
检测和跳过屏幕
为了提供可用于 RL 的环境,我们需要通过不相关的屏幕处理检测和点击:
- 点击正确的位置开始新游戏
- 检测表示游戏结束的屏幕,点击适当的位置开始新的游戏
- 检测各种弹出屏幕并关闭它们(消息、新角色解锁、新项目等)..)
以上可能会以某种方式自动化,甚至可能使用某种人工智能/学习,但这是一个完全不同的主题,我没有处理。目前,我只是手动配置了每个游戏的相关屏幕以及遇到这样的屏幕时在哪里点击。
奖励
我使用了基于“分数变化”的奖励信号。这使得每次分数变化时都有+1 的奖励。我发现,在这种情况下,不需要处理实际得分值的 OCR,只需检测得分值的变化并给出+1 就足够了,而且也更容易。对于大多数游戏,这转化为实际分数(除了一些偶然的错误检测)。此外,由于许多 RL 算法将奖励限制为-1/+1,因此在这种情况下检测实际分数就不那么重要了。
示例高效可扩展 RL
由于在 Android 模拟器上训练的缓慢和高资源成本,我去寻找一个样本有效的 RL 算法,它可以很好地扩展到多种环境。
我尝试了各种 RL 算法,但最终专注于 q-learning 变体,特别是由于我试图学习的游戏具有离散的动作空间,对错误的容忍度接近零(即,选择单个错误的动作经常会导致游戏结束)。这使得 q-learning 等基于价值的方法比 actor-critic 变量等随机算法更合适(尽管随机算法仍有可能收敛到一个好的策略,但我最初使用 PPO 获得了相当好的结果,但使用 DQN 变量总体上更稳定、更好)。
当前用于离散动作的去样本高效 RL 算法是彩虹。Rainbow 采用了原始的 DQN 算法,并将 6 种独立的改进结合到一个代理中,在 Atari 基准测试中达到了 200M 总帧数阈值(约 38 天的“播放时间”)的最先进结果。
IQN 是 DQN 的改进分布式版本,超越了之前的 C51 和 QR-DQN ,能够几乎匹配彩虹的性能,没有彩虹使用的任何其他改进。
不过,彩虹和 IQN 都是“单代理”算法,在单个环境实例上运行,需要 7-10 天的时间来训练。以 60fps 的速度对 200M 帧实时运行一个 android 模拟器代理需要 38 天。
对于多角色/分布式 q 学习,最先进的是 R2D2。R2D2 是一种分布式多角色算法,在之前发布的 APEX 的基础上进行改进,增加了额外的改进,特别是使用了 DQN 模型的“递归”版本,在中间添加了 LSTM 层,以帮助代理保持到目前为止发生的事情的“记忆”,并对其行动进行更好的长期规划。
LSTM 被证明是一个很大的帮助,即使在雅达利上,大多数游戏都是完全可见的(即游戏的完整状态可以在屏幕上看到),这似乎不会受益于 LSTM 记忆。没有太多关于它为什么有帮助的研究,但一个可能的解释是它允许策略“遵循计划”,这允许它更有效地学习和玩耍。
R2D2 在几乎所有的 Atari 游戏上都获得了极高的分数,几乎没有改进的空间,然而,这是以样本效率为代价的,需要看到比样本效率算法多 50 倍的环境帧。尽管如此,由于其高度分布式架构在使用 256 个 CPU 的高速 Atari 模拟器上运行 256 个异步角色,它能够在比 Rainbow/IQN 更短的时间(5 天)内实现这一目标。这对于我的 android 系统来说是不可行的,环境运行速度慢了 10 倍,每个实例需要 2 个 CPU。
为了最大化我的资源利用率和最小化训练时间,我致力于将 IQN/彩虹/R2D2 的特征结合到一个“递归 IQN”训练算法中(完整细节在此),该算法在 Atari 基准测试中实现了改进的样本效率结果,并可以选择并行运行多个参与者,使我能够在合理的时间内(最多几天)在缓慢的 android 环境中有效地进行训练。
培训设置
为了进行培训,我使用了一个带有 32 个 CPU 和一个 NVIDIA 1080ti GPU 的定制(非 VM)服务器。我在每个培训课程中运行了 12 个 Android 实例,每个实例使用主策略的共享内存副本在不同的进程中异步收集经验,以避免其中一个参与者不得不暂停时的延迟(例如在游戏结束后重新开始)。从训练步骤之间的过程中检索经验,以填充训练重放缓冲器。
我使用了与 Atari 基准测试相同的超参数和'递归 IQN' 算法,并做了一些修改:
- 从 12 ENVs 减少到 12 ENVs
- env 异步运行,而不是矢量化运行,共享内存策略每 1000 步更新一次,权重来自训练策略
- 固定的衰减探索率,每个演员从 1.0 到 0.001(需要极低的探索率,因为我正在使用的游戏对“错误动作”非常敏感,所以常见的 0.01 率会使训练演员很难达到更长的剧集)
- 视觉游戏帧从 320x480x3 分辨率缩放到 80x120x3 RGB 观察值(与 Atari 中常用的 84x84x1 灰度观察值相比)
- 以 30FPS 的速度从模拟器中抓取帧,根据游戏的不同,跳帧次数为 2 或 4,没有“最大合并”(即代理转换为每秒 15 或 7.5 步,而 Atari learning 通常为每秒 15 步)。在一些游戏中需要较低的速率,否则这些动作会比步进时间更长(例如滑动动作)
游戏和结果
我使用以下 3 个游戏来集中测试:
- 对于人类玩家来说,这是一个非常困难和令人沮丧的游戏,需要非常快速和精确的反应时间,但是有非常简单的机制和恒定的视觉效果,所以总体的学习策略应该是相对简单的
- 地铁冲浪者:流行的无尽街机游戏,通过在 3 条车道之间滑动来躲避火车,跳跃或蹲在障碍物上方和下方,并试图收集沿途的硬币
- Crossy Road :臭名昭著的斗鸡游戏要求代理人提前计划,并在正确的时间开始行动,同时考虑迎面而来的交通和汽车轨迹,漂浮的积水和快速通过的火车
所有比赛都使用最终训练政策进行评估,没有随机行动。
拍打鸟
A high score for Flappy Bird. Reached the 30-minute time limit without dying
Flappy Bird 以 30FPS 的速度训练,跳帧为 2(每秒 15 步),总共 25M 步(相当于样本高效 Atari 训练中使用的总“游戏时间”的一半)。使用 12 个模拟器训练大约需要 40 个小时。
动作空间有一个单独的动作(点击)和一个附加的“无操作动作”。每次分数改变时(即每次小鸟通过一个管道时),奖励为+1
Training chart for Flappy Bird, average reward of last 100 episodes
这个游戏因需要时间开始学习而臭名昭著,因为最初的奖励只有在通过第一个管道后才能收到,这对于使用随机探索的未经训练的代理来说可能是极其困难和随机的。0 奖励的初始步骤有几十万,也就是说代理根本没有反馈,没有办法学习。只有在我们获得了一些通过第一个管道的经验(这完全是随机的)之后,代理才最终开始弄清楚它,从那一点开始,它相当稳定地改进,但是它需要经过 2M 步骤才能到达那一点。
这个游戏对错误的动作非常敏感,例如,用 0.001 的随机动作 epsilon 进行评估会产生 143 的平均奖励,而不是 420,这也可以在训练图表最终结果中看到(训练也使用 0.001 作为最终探索率)
评估分数:平均 420,最高 1363 (10 集评估)
地铁冲浪者
2 high scoring Subway Surfer games
对于这个游戏,我使用了硬币收集计数作为奖励,以鼓励代理收集硬币,这本身并不是为了进步所必需的,而是一种重要的学习能力。我还在游戏结束时增加了一个负(-1)奖励,以鼓励代理学会不要输,不管收集了多少硬币。
该游戏以 30FPS 的速度训练,跳帧为 4(每秒 7.5 步,而雅达利通常使用的是 15 步,因为滑动手势需要的时间超过 66 毫秒),共 25 米步(总游戏时间相当于使用 200 米帧、60FPS 的普通样本高效雅达利训练)。使用 12 个模拟器训练大约需要 90 个小时。
这里的动作空间有 4 个动作(上/下/左/右滑动)和“noop 动作”。
有趣的是,代理人几乎从不选择 noop 动作,而总是喜欢跳或滑下,即使它并不真的需要。这有点道理,因为这样做没有坏处,而且只在某些情况下有帮助(不是所有的训练都是这样,有些有更多的 noop 动作)。我们也许可以通过对每一个行动增加一个小的负奖励(例如-0.1)来减轻这一点。
Training chart for Subway Surfers, average reward of last 100 episodes
评估分数:平均 142,最高 434 (30 集评估)
十字路口
3 high scoring Crossy Road games
克罗斯路与地铁冲浪者以相同的帧/步速率进行训练。每一次分数变化的奖励是+1(也就是鸡每向前移动一步)。
代理显然倾向于只向前移动,但它知道向左/向右移动,甚至在需要时向后移动。
Training chart for Crossy Road, average reward of last 100 episodes
评估分数:平均 41,最高 139 (30 集评估)
结论
到目前为止,结果看起来很有希望,尽管仍然不是我们认为的“超人”(除了 Flappy Bird)。尽管如此,看到 RL 能够在合理的时间、框架和资源范围内,使用与 Atari 相同的超参数,从视觉输入中实时学习现代休闲游戏,还是很有希望的。
从图表中也可以很清楚地看到,学习并没有停滞不前,看看我们在 50 米甚至 100 米甚至更远的步数上,通过一些超参数调整可以得到什么结果,这将是很有趣的。
[## 基于递归 IQN 的快速样本高效 Q 学习
一篇关于用于这些结果的“递归 IQN”训练算法的文章
opherlieber.github.io](https://opherlieber.github.io/rl/2019/09/22/recurrent_iqn) [## 奥菲利贝尔/rltime
RLtime 是一个强化学习库,专注于最先进的 q 学习算法和功能
github.com](https://github.com/opherlieber/rltime)
现实世界机器人的强化学习
来自现实世界机器人控制的 RL 文献的想法
机器人——承诺
机器人在现代工业中无处不在。与上个世纪的大多数科幻作品不同,人形机器人仍然没有洗我们的脏盘子和倒垃圾,也没有施瓦辛格式的终结者在战场上战斗(至少目前如此……)。但是,几乎在每一个制造工厂里,机器人都在做着几十年前人类工人曾经做过的那种单调乏味、要求苛刻的工作。任何需要在可以仔细控制和监控的环境中重复和精确工作的东西都是机器人取代人类的良好候选对象,今天的前沿研究正在快速接近自动化任务的可能性,这些任务非常困难,即使我们可能认为它们很乏味(如驾驶)。
我们迷恋机器人背后的动机显而易见;对许多人来说,一个人类从艰苦无聊的体力劳动中解放出来的未来似乎是非常令人向往的。此外,机器特有的精确性和一致性可以减少由于人为错误而发生的灾难,如车祸和手术中的医疗事故。我们开始在生产线之外看到这场革命的第一个先兆;在亚马逊这样的大型仓库中,机器人正被用来代替人工运输板条箱。
虽然我们仍然没有在战场上使用杀人的人形机器人,但我们确实有在世界各地执行侦察和战斗任务的半自动无人机。军事高级研究机构正在努力使士兵远离危险,让机器进行实际战斗,我希望在未来的几十年里我们确实会看到这样的发展。
机器人强化学习
为什么几十年前的科幻小说几乎总是认为我们不久的将来包括智能人形机器人做一切事情,而我们似乎离它很远?为什么我们的制造工厂到处都是机器人,而我们的街道和家庭却没有?对于一个在给定环境中成功操作的机器人来说,它必须以某种方式理解它,计划它的行动并使用某种驱动手段执行这些计划,同时使用反馈来确保一切按照计划进行。
事实证明,这些组成部分中的每一个都是一个非常困难的问题,而我们人类容易做到的事情(如识别视觉场景中的物体并在某种程度上预测人们的意图)对计算机来说往往具有难以置信的挑战性。近年来,深度学习在计算机视觉的各种任务中占据了突出地位,但理解典型步行街场景所需的广泛技能仍不在当前技术的掌握范围内。
事实证明,在流水线上工作和在街上工作有着天壤之别。在装配线上,环境中的一切通常都可以精确控制,机器人需要执行的任务往往非常具体和狭窄。尽管有这些优势,为制造机器人设计运动规划和控制算法是一个漫长而乏味的过程,需要许多领域专家的共同努力。这使得这一过程非常昂贵和漫长,凸显了我们目前的能力与需要在更广泛的环境中操作并执行一系列任务的机器人所需的能力之间的巨大差距。如果我们在为那些狭窄的任务设计算法时有困难,我们怎么能把机器人扩展到我们的家庭呢?这些机器人将不得不在城市空间通常复杂的景观中导航,处理混乱的现实世界(比较一下洗碗池中随意留下的盘子和油漆汽车外部,在装配线上精确放置和定时),并在确保安全的情况下与人类互动。
近年来,深度学习和强化学习的成功使得许多研究人员开发了使用强化学习控制机器人的方法。动机很明显,我们能否通过让机器人自主学习来自动化设计传感、规划和控制算法的过程?如果可以,我们会立刻解决我们的两个问题;节省我们花费在为我们知道如何解决的问题(工业机器人)设计算法上的时间和精力,并为那些我们目前没有解决方案的更困难的问题获得解决方案。
深度强化学习是在各种视频游戏和棋盘游戏,或者相对简单的模拟控制问题中取得惊人成功后才引起公众注意的。在这些任务中,代理学习的环境和它必须操作的环境是相同的,我们可以有效地使用模拟来允许代理在学习解决任务之前进行多次尝试。深度强化学习算法是出了名的数据低效,在学习解决一个任务(如玩 Atari 游戏)之前,通常需要进行数百万次尝试。如果我们试图在现实世界中应用同样的方法来训练我们的机器人,这将花费不切实际的时间,并且很可能在这个过程中摧毁机器人。或者,我们可能天真地试图使用模拟来训练我们的代理,然后在真实的机器人上部署训练好的策略。但是模拟真实世界的复杂性是非常困难的,并且这种策略在物理机器人上通常表现不佳。
将 RL 应用于机器人技术存在许多挑战,在我看来,其中许多挑战可以粗略地分为以下四类:
样本效率(Sample efficiency):如果我们希望使用物理机器人来训练我们的政策,我们必须开发出只需要少量尝试就能学会的算法,这样训练才是可行的,不像我们今天拥有的许多算法。
Sim2Real :如果我们希望在模拟环境中训练我们的策略,然后部署它们
奖励规格:下象棋或者星际争霸 2 的时候目标非常明确,容易量化;无论输赢。然而,在洗碗这样的事情上,你如何量化成功的程度呢?还是叠衣服?
安全:我们的机器人政策必须是安全的(在机器人训练和部署到现实世界期间),以确保机器人本身的完整性以及环境中人员和财产的安全。
我将主要讨论前两个类别,简单谈一下第三个类别,避开最后一个。
样品效率
传统上,当希望 RL 中的样本复杂度极低时,首选方法是基于模型的 RL。在基于模型的 RL 中,代理试图学习环境的模型并使用它来计划和改进它的策略,从而大大减少它需要与环境交互的次数,而不是仅基于通过与环境交互获得的奖励来学习策略。然而,与无模型算法相比,这种方法通常导致较低的渐近性能,并且有时由于学习模型中的误差而遭受灾难性的失败。
基于模型的 RL 在动力学可以由简单模型(例如线性模型)充分表示的问题中表现出巨大的成功,但是在需要非线性模型(例如深度神经网络)的更复杂的环境中还没有取得巨大的成功。2018 年,来自伯克利的研究人员就该主题发表了一篇论文,其中他们确定了不稳定问题的一个可疑原因,并提出了一个解决方案。
在他们的论文中,他们声称,在学习和规划期间,该策略倾向于利用状态空间中学习模型表现不佳的那些区域,这使得代理“偏离路线”,从使用学习模型可以可靠地提前规划的区域转向完全盲目的区域,使其无效。他们的解决方案相对简单;学习几种不同的环境模型,并在规划期间从这些不同的模型中统一取样,有效地规范学习过程。这使得基于模型的 RL 能够应用于比以前更复杂的任务,以更少的数量级尝试实现与无模型算法相当的渐近性能。
有趣的是,最近的一个无模型算法已经展示了出色的样本复杂性,以至于有可能在相对较短的时间内在一个真实的机器人上训练一个策略。2019 年,来自伯克利和谷歌大脑的研究人员发表了一篇论文,其中他们描述了一种称为软演员评论家(SAC)的非政策演员评论家算法。他们在几个传统的 RL 控制基准上证明了这种算法在低样本复杂度的情况下表现非常好,然后继续训练机器人在仅 4 小时的环境交互中行走。
该机器人被训练在平坦的表面上行走,然后在不同障碍的表面上成功测试,显示了所学策略的鲁棒性。
另一个不错的论文走了一条不同的道路来采样效率;通过抛弃策略必须从零开始学习的概念,并且应该利用现有的不完善的控制算法来提供一个“框架”,在该框架上发展策略。通过利用现有控制算法对于该问题表现良好的事实,该策略可以学习微调控制系统,而不是像大多数 RL 算法那样从随机行为开始。他们使用这种方法来训练机器人完成涉及复杂动力学的真实积木组装任务。
模拟现实
在过去的几年中,许多研究论文已经证明了他们学习的 RL 策略在物理机器人平台上操作的能力,但是这些策略通常局限于狭窄的任务,并且通常需要大量的手动调整才能正常工作。特别是对于使用视觉传感的机器人来说,逼真地模拟机器人可能遇到的图像是极其困难的,这就产生了著名的 Sim2Real gap。
在动力学可以通过模拟充分捕获的问题中,RL 实际上可以很好地工作,正如在这篇论文中可以看到的那样,在这篇论文中,一个策略被训练为使用模拟来学习四足机器人的恢复策略,并且它很好地转移到真实的机器人,具有令人印象深刻的 97%的成功率。然而,在这个问题中,状态是相对低维的,不像视觉表现。
为了解决处理视觉输入的问题,OpenAI 和 Berkeley 在 2017 年发表的一篇很好的论文提供了一个非常简洁的解决方案;将环境提供的视觉输入随机化,并训练策略对这些变化非常稳健,希望真实世界会喜欢模拟的另一种变体。
这非常有效,他们能够在真实的机器人抓取系统中使用仅在模拟中训练过的物体检测器。
这项工作的一个非常酷的延续发表在 2019 年的一篇论文。在这篇论文中,研究人员使用了类似的随机化模拟来帮助训练策略变得鲁棒,但同时训练了一个条件 GAN (cGAN)来将随机化图像转换回原始模拟的规范形式。在测试期间,cGAN 将真实图像转换为策略熟悉的标准图像形式,从而有助于减少模拟真实图像的差距。使用这种方法,他们在模拟中训练了一个代理,并将其用于一个机器人上,成功率为 70%。在真实的机器人上使用一些微调,他们能够达到 91%甚至 99%的成功率。
奖励规格
假设你想让你的机器人学会把书放在书架上,并且你有一个样本复杂度非常低的算法。如何为此设计一个奖励函数呢?在一篇非常酷的 2019 年论文中,来自伯克利的研究人员正是这么做的。他们没有指定奖励函数,而是为算法提供了一个目标状态的几个图像(排列好的书架),并允许它询问用户(非常少的次数)当前状态是否是一个目标状态。使用之前提到的 Soft Actor Critic 算法和其他几种算法,他们在几个小时内就在一个真实的机器人上训练了他们的策略。他们针对不同的任务训练不同的策略,比如把书放在书架上,在盒子上盖一块布。
结论
将 RL 应用于现实世界机器人问题的挑战还远远没有被宣布解决,但已经取得了很大进展,希望我们将继续看到这一令人兴奋的领域的进一步突破。
强化学习框架和工具包(Gym 和 Unity)
介绍强化学习框架,以及环境 Cart-pole(健身房)和 Banana collector(Unity)
强化学习为学习策略提供了一个框架,该学习策略将状态映射为行动,目标是最大化累积回报。在这篇文章中,我们提出了这个框架是如何数学公式,以及哪些算法可以用来解决 RL 问题。我们还将讨论(1) Gym 和(2) Unity 的使用,这两个工具包用于开发和比较强化学习算法。
Gym — classic control environments https://gym.openai.com/envs/#classic_control
强化学习框架
强化学习是基于迭代学习思想的机器学习的一个领域。学习者,或者决策者,被称为代理,它与环境互动,接收被称为奖励的反馈。代理的目标是通过与环境的迭代来最大化回报。在强化学习问题中,我们认为时间步长是离散的。在第一时间步,代理观察环境的状态,选择动作作为响应。随后,环境向代理呈现一个新的状态和一个奖励,显示它的动作是多么恰当。这个过程在下面的时间步骤中继续,获得一系列的状态、动作和奖励。在反复试验之后,代理人学会执行适当的行动,以最大化预期累积报酬。
Sequence of states, actions, and rewards
建立奖励,以便当代理试图最大化它时,也学习特定的行为(例如,玩视频游戏或驾驶汽车)。智能体的设计不是为了最大化即时报酬,即时报酬是执行一个动作后环境提供的报酬,而是期望的累积报酬。预期累积奖励是从下一个时间步开始的奖励总和,用 Gt 表示;我们使用预期这个术语,因为代理人不能确定地预测未来的回报是什么。
Expected cumulative reward at time step t
为了强调比未来奖励来得更早的奖励,我们计算了折现奖励,代表γ折现率。折扣率是介于 0 和 1 之间的数字,由开发者在定义强化学习任务时设置。
Discounted reward at time step t
折现率γ=1 代表未折现的奖励,而γ=0 代表最直接的奖励,这意味着γ越大,代理人考虑的未来奖励就越多。
使用马尔可夫决策过程来描述强化学习的环境。这个过程定义为:(1)一组状态 S ,(2)一组动作 A ,(3)一组奖励 R ,(4)环境的一步动力学p(S′,r|s,a) ,(5)一个贴现率 γ 。环境在时间步长 t+1 做出响应,仅考虑前一时间步长的状态和动作。单步动态和奖励描述了环境如何工作;因此,代理不知道它们,它通过与环境迭代来学习如何采取适当的行动。
一个策略描述了代理的行为,是从一组状态到一组动作的映射。该策略可以是(1)确定性的,或者(2)随机的。一个确定性策略将状态映射到动作 π:S→A ,将一个状态作为输入,提供一个动作作为输出。相反,一个随机策略π:SxA→【0,1】取一个状态和一个动作,输出在那个状态下采取那个动作的概率。**
代理的目标是学习最优策略。如果预期收益大于或等于所有州的所有其他策略的预期收益,则认为策略是最优的。在我们深入了解最优性的概念之前,我们先介绍两个在强化学习中经常会遇到的函数:(1)状态值函数和(2)动作值函数。状态值函数是从状态 s 开始并遵循策略 π 时所有时间步长的预期收益,用小写的 v. 表示****
State-value function
有一个公式可以简化状态值函数的计算,称为贝尔曼期望公式。根据这个等式,可以使用下一个状态的期望值和期望的即时报酬来计算任意状态 s 处的状态值函数。
Bellman expectation equation
另一个有趣的函数是用小写字母 q 表示的动作值函数。该函数不仅依赖于环境的状态,还依赖于代理的动作,表示期望的回报,如果代理在状态 s 开始,采取动作 a ,然后对于所有未来的时间步骤遵循策略【π。**
Action-value function
智能体的目标是通过与环境的迭代获得最优动作值函数q∫,然后使用这个动作值函数获得最优策略π∫。我们可以通过选择动作 a 来轻松实现,该动作为每个状态提供最大q∫******
Optimal policy
强化任务的目标是获得代表最优代理行为的最优策略。为此,我们可以采用多种多样的算法,这些算法通常分为两组:(1) 基于值的方法,以及(2) 基于策略的方法。基于价值的方法通过学习最优行动价值函数Q∫(s,a)** 间接计算最优策略。然后,我们可以通过为每个状态选择最大化 Q 的动作来获得最优策略。相反,基于策略的方法直接找到最优策略,而不必计算动作值函数估计。下表显示了最著名的算法。****
Reinforcement learning algorithms
所采用的算法取决于状态和动作空间的类型:(1)离散的,或(2)连续的。离散的空间呈现有限的一组状态和动作。在离散空间中,我们可以将 Q 表(动作值函数估计)表示为字典或查找表。前述算法 Q-Learning 和 Sarsa 只能在离散空间中运行。然而,大多数强化学习应用需要连续的状态和动作空间。例如,在机器人学中,通常使用速度、位置和扭矩等连续变量。连续空间不呈现有限的可能性集合;它们可以取一系列的值。为了处理连续空间,我们可以采用两种策略:(1) 离散化,以及(2) 函数逼近。离散化允许我们使用算法 Q-Learning 和 Sarsa,只需很少或不需要修改。当需要的离散空间数量非常大时,离散化是不可行的,函数逼近成为唯一的选择。深度神经网络成为处理连续空间的最有吸引力的替代方案,可以轻松捕捉状态和动作之间的非线性关系。深度 Q 学习算法可以应用于呈现连续状态空间的强化学习问题,但是动作空间仍然必须是离散的。为了与连续状态和动作空间一起工作,必须使用基于策略的算法,例如增强或近似策略优化。另一种选择是使用行动者-批评家方法(基于价值的方法和基于政策的方法的结合),例如深度确定性政策梯度。
在以后的文章中,我们将解释如何使用 Pytorch 编写这些算法来训练代理。然而,本文主要关注于理解强化学习框架和工具包(Gym 和 Unity)。这两个库都提供了用于训练的代理,这意味着我们可以将上述算法之一应用于这些代理,以便它们学习特定的任务。
强化学习工具包——健身房
Gym 是开发强化学习算法的开源库。该工具包提供了从 Atari 游戏到机器人的各种环境。用户可以很容易地与代理交互,目的是应用一种算法来教会他们一个特定的任务(例如,在游戏中最大化得分,训练机器人行走,或平衡汽车上的杆子)。
第一步是在你的电脑上安装 Gym。要做到这一点,我们可以查阅官方网页,
****[## Gym:开发和比较强化学习算法的工具包
健身房图书馆是一个测试问题——环境——的集合,你可以用它来制定你的强化…
gym.openai.com](https://gym.openai.com/docs/#installation)****
或者,我们可以阅读 Genevieve Hayes 在《走向数据科学》上发表的以下文章。
**** [## 如何在 Windows 环境下安装 OpenAI Gym
一步一步的指导如何建立和运行 OpenAI 健身房
towardsdatascience.com](/how-to-install-openai-gym-in-a-windows-environment-338969e24d30)
为了了解库是如何工作的,我们将解释 Gym 提供的 CartPole-v1 环境。我们开始吧💪!
CartPole-v1 环境
小车-V1 环境由一根通过非驱动关节连接到小车上的杆组成,小车沿无摩擦轨道运动。代理可以向推车施加-1 到 1 之间的力,目的是尽可能长时间地保持杆的平衡。柱子保持直立的每一步都获得+1 的奖励。当柱子偏离垂直方向超过 15 度,或者手推车偏离中心超过 2.4 个单位时,该集结束。
CartPole-v1 Environment
第一步是导入库 gym ,使用 gym.make 函数加载 CartPole-v1 环境。一旦环境被创建,我们需要一个初步的观察。第一个状态通过调用复位函数获得,由一个(4)维 numpy 数组组成,包含以下信息:(1)小车位置,(2)小车速度,(3)电极角度,以及(4)尖端的电极速度。
状态空间指的是我们的代理可能遇到的所有可能情况的集合。类似地,动作空间是我们的代理在特定状态下可以采取的所有可能动作的集合。两个空间的类型和大小可以通过使用环境观察 _ 空间和环境动作 _ 空间方法来查询。
健身房空间可以是:(1)离散的,(2)多离散的,(3)盒子,和(4)元组。在 CartPole-v1 环境中,动作空间是离散的,这意味着该空间包含从 0 到 n-1 的 n 个离散点。我们可以通过键入 env.action_space.n 来获得动作的总数。相反,状态空间是一个多维连续空间(箱式),其中每个变量都位于区间[low,high]内,通过使用env . observation _ space . low和env . observation _ space . high获得两个边界。
我们可以通过使用env . action _ space . sample()获得一个随机动作。然而,强化学习问题的目标不是随机选择一个动作,而是找到要采取的最佳动作,这意味着我们使用一种算法来输出我们的代理应该采取的动作,以使其报酬最大化。
选择动作后,环境向代理呈现一个新的状态和一个奖励,显示这个动作是多么合适。为了获得下一步和奖励,我们使用了 env.step() 方法。此方法使环境步进一个时间步长,并返回:
- 观察→代表环境的下一个状态。
- 奖励→采取行动后获得的奖励。
- 完成→表示剧集是否已经结束。
- 信息→用于调试目的的诊断信息。
下面可以看到 step 方法返回的对象的值和类型。
现在是时候把所有的放在一起了!:)我们创建一个代理,它采取随机的行动,直到剧集结束,返回该剧集中获得的总分数(奖励的总和)。请注意,当我们训练代理时,操作将通过策略(训练的算法)获得,而不是像这里一样随机获得。
车杆环境具有连续的状态空间,但是动作空间是离散的。为了训练这个代理,可以采用基于值的方法,例如深度 Q 学习。该算法为给定状态选择最佳动作;因此,使用该方法获得的策略是确定性的。为了获得随机策略,可以应用基于策略的方法,例如近似策略优化。
强化学习工具包— Unity
Unity Machine Learning Agents(ML-Agents)是一个开源的 Unity 插件,使游戏和模拟成为训练智能代理的环境。
为了了解图书馆是如何工作的,我们将解释香蕉收集器的环境。在这种环境下,代理可以拿黄色或蓝色的香蕉,目标是收集尽可能多的黄色香蕉,避免蓝色的。
首先,我们克隆存储库,然后导入 Unity 并加载Banana collector环境。
Unity 使用了大脑的概念。学习环境中的每个代理都与一个大脑相连,这个大脑负责为所有相连的代理做出决策。
Unity Learning Environment
我们可以检查可用的大脑,并将其中一个设置为我们要用 Python 控制的大脑,如下所示。
在香蕉收集器环境中,状态空间是连续的,有 37 个维度,包含代理的线速度和代理前进方向上基于光线的物体感知。动作空间是离散的,具有 4 个维度:(1)向前移动,(2)向后移动,(3)向左转,以及(4)向右转。收集一个黄色香蕉的奖励为+1,收集一个蓝色香蕉的奖励为-1。
我们可以通过使用以下函数来检查状态和动作空间(大小和类型):
Unity 提供了一个类似健身房的界面来培训代理。为了得到一个初步的观察结果,我们需要调用 env.reset() 函数,就像我们之前对 gym 所做的那样。类似地,为了向环境发送一个动作,我们使用了 env.step() 函数。
正如我们之前在健身房推车杆示例中所做的那样,我们创建了一个代理,它采取随机行动,直到该集结束,返回该集的总得分(奖励的总和)。请注意,当我们训练代理时,操作将由策略(训练的算法)获得,而不是像这里一样随机获得。
正如我们所观察到的,获得的奖励是-1,这意味着代理人比黄色的香蕉摘得更多。训练后,代理人区分两者,获得的总回报更高。
与车杆环境一样,状态空间是连续的,但动作空间是离散的。因此,为了训练这个代理,我们可以使用基于值的方法,例如深度 Q 学习,或者基于策略的方法,例如近似策略优化。
在以后的文章中,我们将解释如何训练这两者:推车杆和香蕉收集代理。所以,敬请期待!😊
文学
- Udaciy 课程深度强化学习https://www . uda city . com/course/Deep-Reinforcement-Learning-nano degree-nd 893
- https://gym.openai.com/envs/CartPole-v0/
- https://unity3d.com/machine-learning
有趣的读物
- https://towards data science . com/introduction-to-variable-reinforcement-learning-algorithms-I-q-learning-sarsa-dqn-ddpg-72 a5 E0 CB 6287
- https://towards data science . com/the-complete-reinforcement-learning-dictionary-e 16230 b 7d 24 e
感谢阅读🍀 😃****
强化学习:从网格世界到自动驾驶汽车
0.代理、环境和奖励
在过去几年中,人工智能研究人员的许多重大声明背后是一个被称为强化学习(RL)的学科。最近的突破主要是由经典 RL 想法的微小转变推动的,这是由强大的计算硬件和利用该硬件的软件实现的。
为了了解现代深度 RL 模型对计算的渴望程度,下表收集了最近的 RL 进展和完成每项任务所需的计算资源的估计,但并不详尽。
请注意,上表中的任务都是在模拟中训练的(即使是灵巧的机器人手),在大多数情况下,这是所需训练时间易于处理的唯一方式。对于像自动驾驶汽车这样的现实世界应用来说,这可能会变得特别棘手——稍后会有更多关于这个主题的内容。
当 RL 代理在日益复杂的环境中解决任务时,他们陷入了维度诅咒。这种复杂性的组合爆炸解释了为什么像 Dota Five 这样的团队游戏机器人需要在非常强大的硬件上每天训练 900 年,以击败顶级人类玩家。即使拥有像 OpenAI 为 Dota Five 所使用的那些可笑的计算资源,deep RL 尤其有许多棘手的症结,在最好的情况下,这会使训练非常低效,在最坏的情况下,会使许多问题变得基本上难以解决。
值得注意的是,在击败 99.5%的前职业选手后,OpenAI 的 Dota Five 在 2018 国际输了两场与顶级职业选手的比赛。学习曲线只会在接近精通时变得更加陡峭,对于 RL 代理来说,这是双倍的。对于 Dota Five 来说,要从顶级玩家的 99.5%提高到 99.99%,可能需要代理人迄今为止完成的自我游戏训练时间,以及暂时满足移动目标的时间。想要体验一下 RL 特工学习游戏有多难,试试玩有假面前科的雅达利游戏。
现代 RL 产生于最优控制和行为的心理社会研究领域,后者主要包括对动物学习过程的观察。虽然 RL 的动物行为主义起源至少可以追溯到 19 世纪 50 年代亚历山大·贝恩(Alexander Bain)通过“摸索和实验”进行学习的概念,但也许更令人难忘的例子是 J.F .斯金纳(J.F. Skinner)的同名斯金纳盒子,又称操作性条件反射室。这些小室提供了一个 RL 问题的所有主要组成部分:一个具有某种变化状态的环境,一个主体,以及一个主体可以采取的潜在选择的行动空间。在动物行为中,奖励可能是由像按下杠杆以获得食物奖励这样的事情触发的,但对于 RL 问题,奖励通常可以是任何东西,精心设计一个好的奖励函数可能意味着有效代理和行为不端代理之间的差异。
1.Gridworld 中的质量和价值函数
到目前为止,我们已经讨论了越来越多的强化学习突破和运行 RL 模型的高性能计算需求的同时增长,以及 RL 在动物行为研究中的根源。
最优控制和动态规划是另一个重要领域,有助于我们对 RL 的现代理解。特别是,这些领域为我们提供了贝尔曼方程,用于理解给定环境状态下的最大回报(价值函数)和从给定状态下获得最高潜在回报的最佳可用行动(质量函数)。
下图是一个常见的例子,你几乎肯定会在任何 RL 课程的第一堂课上看到。
在一个简化的“网格世界”中,代理可以上下移动或左右移动。代理不能离开网格,某些网格可能会被阻止。这个环境中的状态是网格位置,而绿色笑脸表示积极的奖励,红色方框表示消极的奖励。积极和消极的奖励都伴随着退出游戏。在这个例子中,价值函数(对于给定状态的最大潜在回报)由每个方块的绿色饱和度表示,而箭头的大小和颜色对应于质量函数(对于在给定状态中采取的行动的最大潜在回报)。因为代理人对未来的奖励打折扣,而倾向于眼前的奖励,对于需要更多移动来达到目标的状态来说,价值和质量函数被削弱了。
在网格世界这样一个简单的例子中,价值和质量函数可以有效地存储在查找表中,以确保代理在给定的环境中总是做出最佳决策。对于更现实的场景,这些函数事先是未知的,并且必须探索环境以生成质量函数的估计,之后代理可以通过利用其对环境及其回报的理解来贪婪地寻求最大化回报。探索和利用 RL 环境的一种有效方式是使用深度神经网络来估计质量函数。
2.深度 Q 学习网络和政策梯度:端到端深度学习者
在 2013 年的一篇开创性论文中,Deepmind 的研究人员发表了一个通用强化学习器,它能够在 49 个经典雅达利视频游戏中的 29 个游戏中达到或超过人类水平。这篇论文的主要成就是,与可能特别访问游戏机制信息的更简单的强化学习问题不同,这篇论文中演示的模型仅使用游戏的像素作为输入,就像人类玩家一样。此外,同一个模型能够学习各种不同类型的游戏,从拳击到海上探险。这种方法被称为端到端深度学习,在这种方法中,输入由一端的神经网络读取,所需的行为直接学习,而无需手动编码模块将代理的不同方面粘合在一起。在 Deepmind 的 DQN 模型中,输入是视频游戏的最后几帧,输出是质量函数,描述了代理对不同行为的预期回报。
几年后,先进的深度强化学习代理变得更加简单。政策梯度代理不是学习预测每个行动的预期回报,而是训练在给定当前环境状态的情况下直接选择一个行动。这实质上是通过将强化学习问题转化为监督学习问题来实现的:
- 智能体根据一组将智能体定义为神经网络的参数θ执行一些任务(例如,玩游戏、从 A 点开车到 B 点、操纵一个积木)。
- 多次任务执行构成一个批次,每次任务执行的最终回报形成损失函数。
- 代理使用梯度下降来最小化损失函数,增加了为正奖励运行做出的每个决策的概率,反之亦然。
- 重复步骤 1 到 3,直到代理性能收敛和/或达到某个基准。
增加每一次行动(包括错误)最终产生积极回报的概率的功效似乎令人惊讶,但实际上,在许多次运行中平均下来,获胜的表现将包括更多正确的行动,而较低回报的表现将包括更多错误。这是 RL 代理学习跑酷式运动、机器人足球技能,以及自动驾驶的简单基础,使用策略梯度进行端到端深度学习。Wayve 的一个视频演示了一个 RL 代理在大约 20 分钟内学会在一条孤立的乡村道路上驾驶一辆实体汽车,人类操作员干预之间的距离作为奖励信号。
这是一个非常引人注目的演示,尽管非常简单。还记得前面提到的维数灾难吗?现实世界的驾驶比单车道有更多的变数。对于 RL 来说,每一个新的方面都需要指数级的训练要求。鉴于目前的技术水平,完全自动驾驶汽车不可避免地需要在模拟环境中进行 soem 程度的学习,大量的手工编码模块将功能联系在一起并处理边缘情况,或者两者兼而有之。
3.像深度学习吃掉自动驾驶一样走向现实世界
机器学习的现代复兴承诺的最明显的应用之一是自动驾驶汽车。汽车可能是最危险的现代技术,因为世界卫生组织估计全球每年有 125 万人死于道路交通事故。确定自动驾驶汽车的经济影响很困难,但保守估计仅在美国每年就有 190 亿美元(T2)到 6420 亿美元(T4)不等。
现代自动驾驶起源于 20 世纪 80 年代和 90 年代的项目,如控制卡内基梅隆自动驾驶试验台的 ALVINN 和德国联邦国防军大学的 Ernst Dickmann 的工作。现代自动驾驶开发人员可能对这些项目的许多组件很熟悉:ALVINN 利用神经网络从 30×32 视频馈送和激光测距仪输入中预测转弯曲率。为了绕过计算瓶颈,Dickmann 的动态视觉系统根据预期重要性将计算集中在图像的预定义区域,这一概念与现代网络中的神经注意力非常相似。
上世纪 80 年代和 90 年代自动驾驶汽车的许多创新都是克服数据吞吐量或处理瓶颈所必需的。最近,计算能力的可用性不再是瓶颈,克服完全汽车自动驾驶的最后 10%左右的挑战的主要挑战与确保训练数据的可靠性和有效处理不寻常的边缘情况有关。
4.结论:你什么时候能期待你的车来接你?
几十年前的自动驾驶汽车领先于他们的时代,受到处理时间和数据吞吐量的计算限制的约束。那时和现在的主要区别在于强大计算资源的可用性。许多研究人员指出,2012 年在图形处理单元(GPU)上训练的卷积神经网络在 ImageNet 大规模视觉识别挑战赛中的惊人表现点燃了机器学习的现代复兴,其特点是在大数据集上训练大模型,并利用GPU的并行处理能力。这已经形成了一个良性循环,吸引了更多的兴趣和资金,导致了进一步的成就和更广泛的实用领域,并最终推动了旧思想的新突破。要实现我们可以信任的完全自动驾驶汽车,仍有大量挑战需要克服,随着计算资源的不断改善,肯定会有更多令人兴奋和未知的机会来解决有趣的问题。
鉴于混乱的现实世界条件的组合爆炸的后果和涉及的高风险,RL 可能需要根本性的突破才能使完全自动驾驶成为现实。学习如何处理看不见的边缘情况,或者训练像“道路的基本规则是在不造成伤害的情况下绕过”这样的高级规则,都不是 RL 擅长的事情。例如,专注于正确识别磨损或涂错的车道标志,远不如教会驾驶代理人预测并避免骑自行车的人避开自行车道以避开坑洞重要。从车道保持和识别明显和已知的障碍到零干预驾驶的学习曲线很陡,正确地爬坡是收获全自动驾驶汽车等技术的回报和推迟未来(也许是无限期地)的灾难性后果之间的区别。
从零开始的强化学习:应用无模型方法和详细评估参数
这个项目是作为在 Python 笔记本中独立学习强化学习(RL)的一种手段而创建的。无需与复杂的虚拟环境交互即可应用 RL。通过完全定义概率环境,我们能够简化学习过程,并清楚地展示改变参数对结果的影响。这在任何机器学习任务中都是有价值的,但在强化学习中尤其如此,在强化学习中,如果没有清晰明确的示例,很难理解影响变化的参数。
Initial TD(0) Output Example
介绍
目的是在扔或移动到更好的位置之间找到最佳动作,以便将纸放入垃圾箱(垃圾桶)。在这个问题中,我们可以从房间的任何位置投掷,但它的概率与当前距离垃圾箱的距离和纸张投掷的方向有关。因此,可以采取的行动是将纸向任何 360 度方向扔,或者移动到一个新的位置,尝试增加扔进垃圾箱的概率。
在前面的第 1 部分中,我们介绍了这样一个问题,即箱子的位置是已知的,可以用值迭代法直接求解。
在第 2 部分中,我们现在展示了如果使用无模型方法(如 Q 学习、蒙特卡罗等)隐藏概率,如何类似地使用 RL 来寻找最优策略。
[## RL 从头开始第 2 部分:了解 RL 参数| Kaggle
编辑描述
www.kaggle.com](https://www.kaggle.com/osbornep/rl-from-scratch-part-2-understanding-rl-paramters)
此外,我们以此为契机,引入一种新的可视化方法来检查参数。当我们改变强化学习中的参数时,我们通过多次尝试(或片段)来观察结果,我们希望显示稳定性和收敛性。这是一个二维比较(x =事件,y =输出),当我们想要观察结果时,如果我们改变一个参数,这就变成了三维比较(x =事件,y =输出,z =参数)。最简单和最常用的解决方案是为每个参数选择生成多个图。另一种更复杂的视觉选择是三维绘图。
相反,我们介绍了一种新的交互式动画方法,通过这种方法可以显示参数随时间的变化。
这种可视化的目的是改善你比较参数选择的方式。然而,由于参数选择通常是一个需要快速执行的过程,我们承认这一要求必须易于实现。最终的参数选择可以被适当地格式化,但是决策过程中的视觉美感可能不太严格。
因此,尽管这是一个我们在之前已经介绍过的方法,但我们后来进一步将它正式定义为一个无需大量了解 Plot.ly 库就可以轻松下载和使用的包(Github 正在发布)。
我们将在本笔记本中演示如何使用绘图功能。下面显示了一个可以使用的交互式动画的快速示例,我们可以看到前面讨论过的尺寸。
最后,模型可解释性的最新研究强调了清晰一致地用图解法概述方法的需求。
来自谷歌的研究人员引入了模型卡作为一种在训练算法中提供透明度的手段。
经过训练的机器学习模型越来越多地用于执行执法、医学、教育和就业等领域的高影响力任务。为了阐明机器学习模型的预期用例,并尽量减少它们在不太适合的环境中的使用,我们建议发布的模型应附有详细描述其性能特征的文档。
Model Cards Spec
此外,我的一位同事正在介绍一个框架,用于将图表方法正式化,以便熟练的研究人员共享他们的工作;称为拨。这项研究试图识别人工智能系统的重复出现的原语和构建模块,并提出一种示意性符号来尝试和促进关于人工智能系统研究的改进的交流。
目前,还没有一致的模型来可视化或形式化地表示人工智能系统的架构。这种表示的缺乏给现有模型和系统的描述带来了可解释性、正确性和完整性的挑战。DIAL(图形化的人工智能语言)是为了成为人工智能系统的“工程示意图”而创建的。它在这里被作为一个面向 AI 系统的公共图形语言的社区对话的起点。
因此,我们创建了一个视觉效果来展示和总结整个工作流程,以生成最终输出:
Complete RL Process Diagram
预处理:介绍概率环境
根据之前定义的环境(参见元笔记本),我们还发现了通过价值迭代计算出的最优策略。
最佳策略可以从数据文件中导入,并且是固定的,假定条柱在(0,0)处,概率的计算如下面的函数所示。
RL 环境定义
一个策略是当前为所有给定状态推荐的动作。状态( s 和s′)是房间中的位置,而动作( a ) 要么在 8 个方向(北、东北、东、…西北)中的一个方向上移动,要么从正北向任何 360 度方向(0、1、2、3、4、…、359、360 度)投掷(参见导航方位。
在我们的概率环境中,我们已经定义了移动具有被正确跟随的保证结果(即,你不会错过步伐),但是向一个方向投掷不能保证进入箱子。投掷成功进入箱子的概率与当前位置到箱子的距离和从真实方向投掷的方向有关。
这定义了我们的概率环境和转移函数:
P(s,s′)= P(s _ { t+1 } = s′| s _ t = s,a_t=a)
是在动作 a(https://en.wikipedia.org/wiki/Reinforcement_learning)下从状态 s 转移到状态 s’的概率。
(注:bin 是垃圾桶/垃圾箱/垃圾桶/垃圾筐/垃圾桶/垃圾桶/垃圾桶/废纸篓的英文说法)
概率函数
该函数定义了从任何给定状态成功投掷的概率,并通过以下公式计算:
首先,如果位置与箱相同(即人已经直接在箱内),则概率固定为 100%。
接下来,我们必须在两种情况下重新定义投掷方向,以适应 360 度与 0 度相同的事实。例如,如果我们在箱子的西南方,并投掷 350 度,这将与-10 度相同,然后将正确地与从人到箱子的小于 90 度的方位相关联。
然后计算欧几里得距离,接着是人可能离箱子的最大距离。
然后,我们按照前面的图计算从人到容器的方位,并计算限制在+/- 45 度窗口内的分数。最接近真实方位的投掷得分较高,而较远的投掷得分较低,任何大于 45 度(或小于-45 度)的投掷都是负的,然后被设置为零概率。
最后,给定当前位置,总概率与距离和方向都相关。
初始化状态-动作对
在应用算法之前,我们将每个状态-动作值初始化到一个表中。首先,我们为所有投掷动作形成这个,然后是所有移动动作。
我们可以向任何方向投掷,因此每度有 360 个动作,从北 0 顺时针到 359 度。
虽然运动看起来很简单,因为有 8 种可能的动作(北、东北、东等),但不像从任何位置向任何方向投掷,有些运动是不可能的。例如,如果我们在房间的边缘,我们不能移动超出边界,这需要考虑。虽然这可以编码得更好,但我已经用 if/elif 语句手动完成了,如果位置和移动是不可能的,就跳过这一行。
Initialised Q Table
定义无模型强化学习方法
我们介绍了三种无模型方法,它们被认为是最容易应用的,并比较了它们的优缺点。然而,在我们这样做之前,我们考虑无模型方法和我们以前使用的基于价值迭代模型的方法之间的差异。简而言之,基于模型的方法使用概率环境的知识作为指导,并相应地计划最佳行动。在无模型方法中,算法不知道这个概率,它只是尝试动作并观察结果。
在本例中,我们已经计算了概率,并将使用这些概率来查找操作的结果,但它们不会直接用于算法的学习中。
此外,在基于模型的方法中,我们在大的“扫描”中更新所有动作,其中所有状态的值在一次通过中被更新。在无模型方法中,我们使用情节,其中仅更新被访问的状态。片段是从开始状态到结束状态的路径;在我们的例子中,终端状态是当算法抛出试卷时,结果可能是成功或失败。
形成情节并定义行动选择过程
如果我们定义起始位置,一集就是从那个位置一直到扔纸为止所采取的动作。如果它到达垃圾桶,那么我们有一个正的目标奖励+1。然而,如果我们错过了 bin,那么我们的目标奖励为-1。
动作选择
我们可以继续这个选择过程,但是这是一个非常低效的选择行动的方法。当我们实施我们的学习过程时,我们将开始学习哪些行动会导致积极的目标,所以如果我们继续随机选择,我们就浪费了所有的努力。
因此,我们引入一种考虑到这一点的方法,称为ε贪婪。
试验的比例 1−ϵ 选择最佳杠杆,比例 ϵ 随机(等概率)选择一个杠杆。典型的参数值可能是ε= 0.1,但这可能会根据环境和偏好而有很大变化。 ( 维基)
换句话说,我们用概率ϵϵ随机选择一个动作,否则将选择最佳动作。如果我们有多个“最佳行动”,我们会从列表中随机选择。
那么,我们为什么不每次都选择最佳行动呢?如果我们有一个有效的行动,但不一定是最好的,这可能会导致一个问题。这在其他机器学习问题中经常被认为是局部最小值/最大值。如果我们一直使用一个似乎有效的行动,我们可能会错过尝试更好行动的机会,因为我们从未尝试过,这可能会导致结果的不稳定。
下面的动画演示了我们降低ε时的结果。ε值较高时,我们会随机选择行动,因此可能会选择不好的行动。随着我们减少ε,我们会越来越贪婪地选择行动来改善结果,同时仍然确保我们可以探索新的行动来最小化我们处于局部最大值而不是全局最大值的风险。
我们因此选择一个小的ε值 ϵ=0.1
RL 算法简介
我们已经介绍了情节和如何选择动作,但我们还没有演示算法如何使用它来学习最佳动作。因此,我们将正式定义我们的第一个 RL 算法,时间差异 0 。
时间差—零
时间差异λ是取决于λ的选择的一系列算法。最简单的方法是将其设置为零,此时更新规则如下:
定义:TD(0)更新规则: Wiki
其中:
- V(s)是状态 s 的值,
- α是学习率参数,
- r 是奖励,
- γ是贴现因子参数,
- v(s′)是下一个状态的值。
那么这个等式是什么意思呢?简而言之,我们基于当前状态的值是什么和采取行动到情节中定义的下一个状态的结果的组合,更新我们对当前状态的质量的知识,表示为 V(s)。
例如,假设我们开始学习过程,我们的第一个动作是从状态[-5,-5]投掷,并且它成功地击中了垃圾箱,那么我们因为达到目标而获得了+1 的正奖励。因此,我们有以下更新:
这似乎是一个微不足道的计算,但重要的是要记住,成功是不能保证的。因此,如果我们考虑所有可能的行动,第一次投掷的结果意味着我们相信这次投掷行动是当前的最佳选择。这个投掷动作的值为 0.5,相比之下,所有其他尚未测试的动作的值为 0。
因此,根据ϵ−greedy 的遴选程序,我们将再次尝试。然而,这一次,纸张没有进入垃圾箱,而是未命中,因此我们得到了负的终端奖励 1 1:
所以我们看到,这个状态的值现在稍微减少了,因为第二次投掷。
强化学习的核心概念是,我们通过重复采样来测试动作;我们需要重复样本的数量,直到结果收敛到真实概率结果的估计。
例如,如果我们考虑扔硬币两次,我们很可能两个结果都是正面,但如果我们扔 100 次,我们可能会看到正面和反面各占一半。在我们的例子中,如果从状态[-5,-5]投掷是一个好的动作,那么总的来说,重复尝试应该会产生积极的结果。起初这可能很难理解,但简单来说,我们正在通过反复试验来测试动作,并让我们的算法完成所有工作,所以我们不必这样做。
注:目前,我们将把起始状态固定为[-5,-5],参数固定为 ϵ=0.1 、 α=0.5 和 γ=0.5 ,直到我们稍后演示参数变化。
在 100 集之后,我们看到固定起始点周围的状态已经更新,但是如果我们将下面的热图与前面的线图并排比较,我们会发现在 100 集之后,它还没有完全收敛,并且仍在更新。
Initial TD(0) Output
因此,我们将剧集数量从 100 集大幅增加到 1000 集
由于我们开始发现这需要越来越长的时间,一个好主意是引入一种方法来跟踪循环的进程。为了做到这一点,我应用了这篇文章中介绍的方法。
Increase to 1,000 episodes
不同的奖励
我们注意到,这样的结果表明状态的值非常负,并且它们是发散的(即不稳定)。
我们可以采取一些措施来改善这一点,首先,我们将对其他行为进行奖励。目前,我们仅有的奖励是当算法投出正球并获得+1 或负球获得-1 时。
这是强化学习过程的一部分,它让我们控制算法优化的内容。例如,假设我们想阻止算法投掷,我们可以为每个移动动作引入一个小的正奖励(比如 0.1),如下所示。
Add reward for moving: r_move = 0.1
虽然这一开始看起来更糟,但状态振荡的值表明它试图找到一个值,但我们对参数的选择导致它发散。但是,我们至少可以看到它越来越接近收敛。
我们可以开始改变参数,但部分问题是我们总结了大量动作(360°投掷方向和 8 个移动方向)的状态值。因此,与其将此归纳为一个值,不如单独考虑每个状态-动作对的质量。
为此,我们可以介绍我们的第二种无模型方法: Q-learning 。
q 学习
与 TD(0)非常相似,Q-learning 在我们采取每一个动作的同时进行学习,而是通过搜索可能的后续动作来学习得更快。
定义:Q-学习更新规则: Wiki
其中:
- Q(s_t,a_t)是状态-动作对 s 的值,
- α是学习率参数,
- r 是奖励,
- γ是贴现因子参数,
- Q(s_t+1,a)是下一个状态中动作对的值。
和以前一样,我们将参数固定为ϵ=0.1,α=0.5,γ=0.5。
Q-Learning Initial Run
变化参数
我们有三个要改变的主要参数,学习率αα,折扣因子γγ和我们的ϵ−greedyϵ−greedy 动作选择值。
下面的解释直接来自维基百科并且已经详细介绍了ϵϵ参数。
探索与利用
学习速率或步长决定了新获得的信息覆盖旧信息的程度。因子 0 使代理什么也学不到(专门利用先前的知识),而因子 1 使代理只考虑最近的信息(忽略先前的知识来探索可能性)。在完全确定的环境中, αt=1 的学习率是最佳的。当问题是随机的时,算法在某些技术条件下收敛于学习率,这要求它下降到零。在实践中,经常使用恒定的学习速率,例如对于所有的 t ,αt=0.1 。3
折扣系数
贴现因子 γγ 决定了未来奖励的重要性。因子 0 会使代理人只考虑当前的奖励而“近视”(或短视),即 rt (在上面的更新规则中),而接近 1 的因子会使其争取长期的高奖励。如果折扣因子达到或超过 1,行动值可能会出现分歧。对于 γ=1 ,没有终端状态,或者如果代理从未达到一个终端状态,所有环境历史变得无限长,并且具有附加的、未折扣的回报的效用通常变得无限长。[4]即使贴现因子仅略低于 1,当用人工神经网络近似价值函数时,Q 函数学习也会导致误差传播和不稳定性。[5]在这种情况下,从一个较低的折扣系数开始,并将其提高到最终值,可以加速学习。【6】
那么这些意味着什么,更重要的是,我们选择参数的目的是什么?
总的目标是,我们试图为任何给定的状态找到最佳的行动,同时以合理的努力次数(以情节次数、所需的计算或时间来衡量)实现这一目标。对学习率的一个很好的解释是,高值意味着我们更重视在每个动作中获得的信息,因此学习更快,但可能会发现很难完全收敛,而小值将需要更长时间,但会稳定地收敛。
一个很好的类比是把它想象成我们只用一根球杆打高尔夫球;高α值对应于使用大击球杆,而小α值类似于使用小击球杆。击球大的球杆最初会让我们更接近果岭,但一旦我们接近,就很难准确地击球入洞。然而,一个小击球的俱乐部将需要更多的尝试来达到果岭,但一旦它做到了,我们就有更多的控制,可以更容易地到达球洞。
我们已经在我们早期的应用中观察到大α参数的影响,其中值在每一集之间振荡。因此,我们需要使用较小的值,但这带来了收敛所需的集数方面的挑战。我们已经需要数以千计的剧集来聚合一个固定的开始状态,并且我们有 100 集来考虑整个环境。
这是我们必须考虑的权衡,最佳决策可能是在需要时一次只学习一个固定的起始状态,而不是试图找到所有状态的最佳策略。
当我们在下面的动画中观察变化 alpha 的趋势时,我们看到,如果我们固定开始状态,我们能够使用一个小的 alpha 值,而不需要不可能的大量剧集。如果我们要考虑所有的状态,我们可能需要使用稍微大一点的 alpha 值来及时得到合适的结果。
因此,我们回到考虑[-5,-5]的单一固定起始状态,并选择α值 α=0.1 。
有了这些设定,我们再来评估 γ 的选择。根据维基百科的解释,我们知道这个值对应于我们是否认为未来的回报重要。当我们考虑这一点时,提醒我们自己 Q-learning 的更新规则是有帮助的。
在 Q-learning 更新规则中,我们看到γ缩放了从下一个状态获得最佳动作的 Q 值。这与作为同一等级的一部分的行为本身的奖励有关,因此,如果我们通过使用较小的 gamma 值来减少这一点,那么奖励就具有更大的权重。相反,如果我们取一个高的伽马值,我们认为从下一个状态获得的信息更重要。
因此,我们将理想地选择一个增加未来奖励价值的值,这样我们的决策将导致最佳的 bin,并选择值 γ=0.9 。
阿尔法分析
阿尔法= 0.9
阿尔法= 0.1
伽马分析
伽马= 0.9
最终参数输出
- alpha = 0.1
- gamma = 0.9
- epsilon = 0.1
- 10,000 episodes
- Fixed start state: [-5,-5]
输出:
The optimal action from the start state is to MOVE in direction: 2
结论
我们看到起始状态的最终输出是向东移动。如前所述,我们可能要考虑改变奖励,这样移动会稍微受到阻碍,因为我们的算法似乎是在收集移动的奖励,而不是达到最终目标。
剧集覆盖的所有州的结果都集中在 10,000 集内,尽管看起来许多还没有被完全探索并且不是最佳的。但是如果我们只关心起始状态,那么这些就无关紧要了。
我希望这篇笔记/文章对演示每个参数对学习的影响和一个独立例子中 RL 的整个过程是有用的。
谢谢
强化学习从零开始,无需复杂的虚拟环境包
这个项目是作为在 Python 笔记本中独立学习强化学习(RL)的一种手段而创建的。无需与复杂的虚拟环境交互即可应用 RL。通过完全定义概率环境,我们能够简化学习过程,并清楚地展示改变参数对结果的影响。这在任何机器学习任务中都是有价值的,但在强化学习中尤其如此,在强化学习中,如果没有清晰明确的示例,很难理解影响变化的参数。
Model-Based vs Model-Free Learning
介绍
目的是在扔或移动到更好的位置之间找到最佳动作,以便将纸放入垃圾箱(垃圾桶)。在这个问题中,我们可以从房间的任何位置投掷,但它的概率与当前距离垃圾箱的距离和纸张投掷的方向有关。因此,可以采取的行动是将纸向任何 360 度方向扔,或者移动到一个新的位置,尝试增加扔进垃圾箱的概率。
在前面的第 1 部分中,我们介绍了这样一个问题,即箱子的位置是已知的,可以用值迭代法直接求解。
在第 2 部分中,我们现在展示了如果使用无模型方法(如 Q 学习、蒙特卡罗等)隐藏概率,如何类似地使用 RL 来寻找最优策略。
[## RL 从头开始第 2 部分:了解 RL 参数| Kaggle
编辑描述
www.kaggle.com](https://www.kaggle.com/osbornep/rl-from-scratch-part-2-understanding-rl-paramters)
此外,我们以此为契机,引入一种新的可视化方法来检查参数。当我们改变强化学习中的参数时,我们通过多次尝试(或片段)来观察结果,我们希望显示稳定性和收敛性。这是一个二维比较(x =事件,y =输出),当我们想要观察结果时,如果我们改变一个参数,这就变成了三维比较(x =事件,y =输出,z =参数)。最简单和最常用的解决方案是为每个参数选择生成多个图。另一种更复杂的视觉选择是三维绘图。
相反,我们介绍了一种新的交互式动画方法,通过这种方法可以显示参数随时间的变化。
这种可视化的目的是改善你比较参数选择的方式。然而,由于参数选择通常是一个需要快速执行的过程,我们承认这一要求必须易于实现。最终的参数选择可以被适当地格式化,但是决策过程中的视觉美感可能不太严格。
因此,尽管这是一个我们在之前已经介绍过的方法,但我们后来进一步将它正式定义为一个无需大量了解 Plot.ly 库就可以轻松下载和使用的包(Github 正在发布)。
我们将在本笔记本中演示如何使用绘图功能。下面显示了一个可以使用的交互式动画的快速示例,我们可以看到前面讨论过的尺寸。
最后,模型可解释性的最新研究强调了清晰一致地用图解法概述方法的需求。
来自谷歌的研究人员引入了模型卡作为一种在训练算法中提供透明度的手段。
经过训练的机器学习模型越来越多地用于执行执法、医学、教育和就业等领域的高影响力任务。为了阐明机器学习模型的预期用例,并尽量减少它们在不太适合的环境中的使用,我们建议发布的模型应附有详细描述其性能特征的文档。
Model Cards Spec
此外,我的一位同事正在介绍一个框架,用于将图表方法正式化,以便熟练的研究人员共享他们的工作;称为拨。这项研究试图识别人工智能系统的重复出现的原语和构建模块,并提出一种示意性符号来尝试和促进关于人工智能系统研究的改进的交流。
目前,还没有一致的模型来可视化或形式化地表示人工智能系统的架构。这种表示的缺乏给现有模型和系统的描述带来了可解释性、正确性和完整性的挑战。DIAL(图形化的人工智能语言)是为了成为人工智能系统的“工程示意图”而创建的。它在这里被作为一个面向 AI 系统的公共图形语言的社区对话的起点。
因此,我们创建了一个视觉效果来展示和总结整个工作流程,以生成最终输出:
Complete RL Process Diagram
预处理:介绍概率环境
根据之前定义的环境(参见元笔记本),我们还发现了通过价值迭代计算出的最优策略。
最佳策略可以从数据文件中导入,并且是固定的,假定条柱在(0,0)处,概率的计算如下面的函数所示。
RL 环境定义
一个策略是当前为所有给定状态推荐的动作。状态( s 和s′)是房间中的位置,而动作( a ) 要么在 8 个方向(北、东北、东、…西北)中的一个方向上移动,要么从正北向任何 360 度方向(0、1、2、3、4、…、359、360 度)投掷(参见导航方位。
在我们的概率环境中,我们已经定义了移动具有被正确跟随的保证结果(即,你不会错过步伐),但是向一个方向投掷不能保证进入箱子。投掷成功进入箱子的概率与当前位置到箱子的距离和从真实方向投掷的方向有关。
这定义了我们的概率环境和转移函数:
P(s,s′)= P(s _ { t+1 } = s′| s _ t = s,a_t=a)
是在动作 a(https://en.wikipedia.org/wiki/Reinforcement_learning)下从状态 s 转移到状态 s’的概率。
(注:bin 是垃圾桶/垃圾箱/垃圾桶/垃圾筐/垃圾桶/垃圾桶/垃圾桶/废纸篓的英文说法)
概率函数
该函数定义了从任何给定状态成功投掷的概率,并通过以下公式计算:
首先,如果位置与箱相同(即人已经直接在箱内),则概率固定为 100%。
接下来,我们必须在两种情况下重新定义投掷方向,以适应 360 度与 0 度相同的事实。例如,如果我们在箱子的西南方,并投掷 350 度,这将与-10 度相同,然后将正确地与从人到箱子的小于 90 度的方位相关联。
然后计算欧几里得距离,接着是人可能离箱子的最大距离。
然后,我们按照前面的图计算从人到容器的方位,并计算限制在+/- 45 度窗口内的分数。最接近真实方位的投掷得分较高,而较远的投掷得分较低,任何大于 45 度(或小于-45 度)的投掷都是负的,然后被设置为零概率。
最后,给定当前位置,总概率与距离和方向都相关。
初始化状态-动作对
在应用算法之前,我们将每个状态-动作值初始化到一个表中。首先,我们为所有投掷动作形成这个,然后是所有移动动作。
我们可以向任何方向投掷,因此每度有 360 个动作,从北 0 顺时针到 359 度。
虽然运动看起来很简单,因为有 8 种可能的动作(北、东北、东等),但不像从任何位置向任何方向投掷,有些运动是不可能的。例如,如果我们在房间的边缘,我们不能移动超出边界,这需要考虑。虽然这可以编码得更好,但我已经用 if/elif 语句手动完成了,如果位置和移动是不可能的,就跳过这一行。
Initialised Q Table
定义无模型强化学习方法
我们介绍了三种无模型方法,它们被认为是最容易应用的,并比较了它们的优缺点。然而,在我们这样做之前,我们考虑无模型方法和我们以前使用的基于价值迭代模型的方法之间的差异。简而言之,基于模型的方法使用概率环境的知识作为指导,并相应地计划最佳行动。在无模型方法中,算法不知道这个概率,它只是尝试动作并观察结果。
在本例中,我们已经计算了概率,并将使用这些概率来查找操作的结果,但它们不会直接用于算法的学习中。
此外,在基于模型的方法中,我们在大的“扫描”中更新所有动作,其中所有状态的值在一次通过中被更新。在无模型方法中,我们使用情节,其中仅更新被访问的状态。片段是从开始状态到结束状态的路径;在我们的例子中,终端状态是当算法抛出试卷时,结果可能是成功或失败。
形成情节并定义行动选择过程
如果我们定义起始位置,一集就是从那个位置一直到扔纸为止所采取的动作。如果它到达垃圾桶,那么我们有一个正的目标奖励+1。然而,如果我们错过了 bin,那么我们的目标奖励为-1。
动作选择
我们可以继续这个选择过程,但是这是一个非常低效的选择行动的方法。当我们实施我们的学习过程时,我们将开始学习哪些行动会导致积极的目标,所以如果我们继续随机选择,我们就浪费了所有的努力。
因此,我们引入一种考虑到这一点的方法,称为ε贪婪。
试验的比例 1−ϵ 选择最佳杠杆,比例 ϵ 随机(等概率)选择一个杠杆。典型的参数值可能是ε= 0.1,但这可能会根据环境和偏好而有很大变化。 ( 维基)
换句话说,我们用概率ϵϵ随机选择一个动作,否则将选择最佳动作。如果我们有多个“最佳行动”,我们会从列表中随机选择。
那么,我们为什么不每次都选择最佳行动呢?如果我们有一个有效的行动,但不一定是最好的,这可能会导致一个问题。这在其他机器学习问题中经常被认为是局部最小值/最大值。如果我们一直使用一个似乎有效的行动,我们可能会错过尝试更好行动的机会,因为我们从未尝试过,这可能会导致结果的不稳定。
下面的动画演示了我们降低ε时的结果。ε值较高时,我们会随机选择行动,因此可能会选择不好的行动。随着我们减少ε,我们会越来越贪婪地选择行动来改善结果,同时仍然确保我们可以探索新的行动来最小化我们处于局部最大值而不是全局最大值的风险。
我们因此选择一个小的ε值 ϵ=0.1
RL 算法简介
我们已经介绍了情节和如何选择动作,但我们还没有演示算法如何使用它来学习最佳动作。因此,我们将正式定义我们的第一个 RL 算法,时间差异 0 。
时间差—零
时间差异λ是取决于λ的选择的一系列算法。最简单的方法是将其设置为零,此时更新规则如下:
定义:TD(0)更新规则: Wiki
其中:
- V(s)是状态 s 的值,
- α是学习率参数,
- r 是奖励,
- γ是贴现因子参数,
- v(s′)是下一个状态的值。
那么这个等式是什么意思呢?简而言之,我们基于当前状态的值是什么和采取行动到情节中定义的下一个状态的结果的组合,更新我们对当前状态的质量的知识,表示为 V(s)。
例如,假设我们开始学习过程,我们的第一个动作是从状态[-5,-5]投掷,并且它成功地击中了垃圾箱,那么我们因为达到目标而获得了+1 的正奖励。因此,我们有以下更新:
这似乎是一个微不足道的计算,但重要的是要记住,成功是不能保证的。因此,如果我们考虑所有可能的行动,第一次投掷的结果意味着我们相信这次投掷行动是当前的最佳选择。这个投掷动作的值为 0.5,相比之下,所有其他尚未测试的动作的值为 0。
因此,根据ϵ−greedy 的遴选程序,我们将再次尝试。然而,这一次,纸张没有进入垃圾箱,而是未命中,因此我们得到了负的终端奖励 1 1:
所以我们看到,这个状态的值现在稍微减少了,因为第二次投掷。
强化学习的核心概念是,我们通过重复采样来测试动作;我们需要重复样本的数量,直到结果收敛到真实概率结果的估计。
例如,如果我们考虑扔硬币两次,我们很可能两个结果都是正面,但如果我们扔 100 次,我们可能会看到正面和反面各占一半。在我们的例子中,如果从状态[-5,-5]投掷是一个好的动作,那么总的来说,重复尝试应该会产生积极的结果。起初这可能很难理解,但简单来说,我们正在通过反复试验来测试动作,并让我们的算法完成所有工作,所以我们不必这样做。
注:目前,我们将把起始状态固定为[-5,-5],参数固定为 ϵ=0.1 、 α=0.5 和 γ=0.5 ,直到我们稍后演示参数变化。
在 100 集之后,我们看到固定起始点周围的状态已经更新,但是如果我们将下面的热图与前面的线图并排比较,我们会发现在 100 集之后,它还没有完全收敛,并且仍在更新。
Initial TD(0) Output
因此,我们将剧集数量从 100 集大幅增加到 1000 集
由于我们开始发现这需要越来越长的时间,一个好主意是引入一种方法来跟踪循环的进程。为了做到这一点,我应用了这篇文章中介绍的方法。
Increase to 1,000 episodes
不同的奖励
我们注意到,这样的结果表明状态的值非常负,并且它们是发散的(即不稳定)。
我们可以采取一些措施来改善这一点,首先,我们将对其他行为进行奖励。目前,我们仅有的奖励是当算法投出正球并获得+1 或负球获得-1 时。
这是强化学习过程的一部分,它让我们控制算法优化的内容。例如,假设我们想阻止算法投掷,我们可以为每个移动动作引入一个小的正奖励(比如 0.1),如下所示。
Add reward for moving: r_move = 0.1
虽然这一开始看起来更糟,但状态振荡的值表明它试图找到一个值,但我们对参数的选择导致它发散。但是,我们至少可以看到它越来越接近收敛。
我们可以开始改变参数,但部分问题是我们总结了大量动作(360°投掷方向和 8 个移动方向)的状态值。因此,与其将此归纳为一个值,不如单独考虑每个状态-动作对的质量。
为此,我们可以介绍我们的第二种无模型方法: Q-learning 。
q 学习
与 TD(0)非常相似,Q-learning 在我们采取每一个动作的同时进行学习,而是通过搜索可能的后续动作来学习得更快。
定义:Q-学习更新规则: Wiki
其中:
- Q(s_t,a_t)是状态-动作对 s 的值,
- α是学习率参数,
- r 是奖励,
- γ是贴现因子参数,
- Q(s_t+1,a)是下一个状态中动作对的值。
和以前一样,我们将参数固定为ϵ=0.1,α=0.5,γ=0.5。
Q-Learning Initial Run
变化参数
我们有三个要改变的主要参数,学习率αα,折扣因子γγ和我们的ϵ−greedyϵ−greedy 动作选择值。
下面的解释直接来自维基百科并且已经详细介绍了ϵϵ参数。
探索与利用
学习速率或步长决定了新获得的信息覆盖旧信息的程度。因子 0 使代理什么也学不到(专门利用先前的知识),而因子 1 使代理只考虑最近的信息(忽略先前的知识来探索可能性)。在完全确定的环境中, αt=1 的学习率是最佳的。当问题是随机的时,算法在某些技术条件下收敛于学习率,这要求它下降到零。在实践中,经常使用恒定的学习速率,例如对于所有的 t ,αt=0.1 。3
折扣系数
贴现因子 γγ 决定了未来奖励的重要性。因子 0 会使代理人只考虑当前的奖励而“近视”(或短视),即 rt (在上面的更新规则中),而接近 1 的因子会使其争取长期的高奖励。如果折扣因子达到或超过 1,行动值可能会出现分歧。对于 γ=1 ,没有终端状态,或者如果代理从未达到一个终端状态,所有环境历史变得无限长,并且具有附加的、未折扣的回报的效用通常变得无限长。[4]即使贴现因子仅略低于 1,当用人工神经网络近似价值函数时,Q 函数学习也会导致误差传播和不稳定性。[5]在这种情况下,从一个较低的折扣系数开始,并将其提高到最终值,可以加速学习。【6】
那么这些意味着什么,更重要的是,我们选择参数的目的是什么?
总的目标是,我们试图为任何给定的状态找到最佳的行动,同时以合理的努力次数(以情节次数、所需的计算或时间来衡量)实现这一目标。对学习率的一个很好的解释是,高值意味着我们更重视在每个动作中获得的信息,因此学习更快,但可能会发现很难完全收敛,而小值将需要更长时间,但会稳定地收敛。
一个很好的类比是把它想象成我们只用一根球杆打高尔夫球;高α值对应于使用大击球杆,而小α值类似于使用小击球杆。击球大的球杆最初会让我们更接近果岭,但一旦我们接近,就很难准确地击球入洞。然而,一个小击球的俱乐部将需要更多的尝试来达到果岭,但一旦它做到了,我们就有更多的控制,可以更容易地到达球洞。
我们已经在我们早期的应用中观察到大α参数的影响,其中值在每一集之间振荡。因此,我们需要使用较小的值,但这带来了收敛所需的集数方面的挑战。我们已经需要数以千计的剧集来聚合一个固定的开始状态,并且我们有 100 集来考虑整个环境。
这是我们必须考虑的权衡,最佳决策可能是在需要时一次只学习一个固定的起始状态,而不是试图找到所有状态的最佳策略。
当我们在下面的动画中观察变化 alpha 的趋势时,我们看到,如果我们固定开始状态,我们能够使用一个小的 alpha 值,而不需要不可能的大量剧集。如果我们要考虑所有的状态,我们可能需要使用稍微大一点的 alpha 值来及时得到合适的结果。
因此,我们回到考虑[-5,-5]的单一固定起始状态,并选择α值 α=0.1 。
有了这些设定,我们再来评估 γ 的选择。根据维基百科的解释,我们知道这个值对应于我们是否认为未来的回报重要。当我们考虑这一点时,提醒我们自己 Q-learning 的更新规则是有帮助的。
在 Q-learning 更新规则中,我们看到γ缩放了从下一个状态获得最佳动作的 Q 值。这与作为同一等级的一部分的行为本身的奖励有关,因此,如果我们通过使用较小的 gamma 值来减少这一点,那么奖励就具有更大的权重。相反,如果我们取一个高的伽马值,我们认为从下一个状态获得的信息更重要。
因此,我们将理想地选择一个增加未来奖励价值的值,这样我们的决策将导致最佳的 bin,并选择值 γ=0.9 。
阿尔法分析
阿尔法= 0.9
阿尔法= 0.1
伽马分析
伽马= 0.9
最终参数输出
- alpha = 0.1
- gamma = 0.9
- epsilon = 0.1
- 10,000 episodes
- Fixed start state: [-5,-5]
输出:
The optimal action from the start state is to MOVE in direction: 2
结论
我们看到起始状态的最终输出是向东移动。如前所述,我们可能要考虑改变奖励,这样移动会稍微受到阻碍,因为我们的算法似乎是在收集移动的奖励,而不是达到最终目标。
剧集覆盖的所有州的结果都集中在 10,000 集内,尽管看起来许多还没有被完全探索并且不是最佳的。但是如果我们只关心起始状态,那么这些就无关紧要了。
我希望这篇笔记/文章对演示每个参数对学习的影响和一个独立例子中 RL 的整个过程是有用的。
谢谢
强化学习——连续状态空间中的推广
随机游走例子的函数逼近
到目前为止,我已经介绍了离散状态、动作设置的强化学习的最基本的思想和算法。回想一下我们到目前为止已经实现的例子,网格世界,井字游戏,多臂强盗,悬崖漫步,二十一点…等等,其中大多数都有一个棋盘或网格的基本设置,以便使状态空间可数。然而,强化学习的力量并不止于此,在现实世界的情况下,状态空间大多是连续的,有不可计数的状态和动作组合供代理探索。在本文中,我将把我们以前学到的概念扩展到连续空间,并通过应用函数逼近实现一个更一般的随机行走例子。
从这篇文章中,我将介绍:
- 如何使用参数方法逼近值函数
- 半梯度 TD 方法(是 n 步 TD 方法的扩展)
- 用于近似的一些通用函数
- 在随机漫步例子中应用函数
一般化的想法
对于离散的状态空间,理论上一个智能体能够经历每一个状态并探索每一个状态的回报。当情况被扩展到连续状态空间时,为了概括价值函数,我们将需要状态的表示。
函数逼近
考虑一个监督学习问题,无论应用什么算法,被训练的模型都能够对它从未见过的数据进行预测,神奇的是,它学习了y = f(x)
的表示,其中x
是输入特征,y
是目标。这种近似或概括的思想可以准确地复制到强化学习问题中,(事实上,机器学习中的大多数算法都可以应用于强化学习设置中的函数近似),其中我们尝试近似值函数v = v(s, w)
(其中s
是状态,w
是模型权重),并将状态、值作为训练示例。例如,在其最简单的形式中,我们可以定义价值函数v = w_0*s + w_1
,使用一阶线性近似。
更新权重
现在问题来了,我们有了一个价值函数的表示,那么我们如何能够更新参数的权重,以使值接近实际值呢?事实上,权重更新遵循随机梯度下降(SGD) 中的规则:
weight update
其中v(S_t)
表示步骤t
的实际值,v(S_t, w_t)
表示带有权重参数w_t
的近似函数。请注意,实际值和估计值之间的平方差衡量近似函数的误差,通过对w_t
求导,砝码会稍微向正确的方向调整。
随机梯度下降(SGD)方法通过在每个示例之后在最能减少该示例的误差的方向上少量调整权重向量来做到这一点。
对于具有多个权重参数近似函数,应该通过分别求导来更新每个权重:
n 步半梯度 TD 方法
现在让我们来看看在连续状态空间中应用的算法:
TD Method in Continuous Space
看起来有很多步骤,但是如果你仔细看,你会发现它和我们在这里学的 n 步 TD 方法超级相似。看看离散空间中的 n 步 TD 方法:
TD Method in Discrete Space
这里的 Q 函数可以用价值函数来代替。通过比较连续空间和离散空间的 TD 方法,可以看出唯一的区别在于价值函数的更新,而在离散空间,价值函数(或 Q 函数)是直接更新的,在连续空间,价值函数是通过权重更新隐式更新的,因为这里的价值函数用权重 w
表示。你需要注意的另一件事是,在连续空间中,目标值取为*G*
,在 1 步 TD 法中是前一步的累积值,在蒙特卡罗模拟(本质上是我们之前讲过的无限 TD 法)中是直到一集结束的累积值。
一般近似函数
正如我们上面提到的,在连续空间设置中,值函数是状态(V = V(S, w)
)的表示,大多数机器学习算法都可以在这里应用。在这篇文章中,我将介绍一些最基本的近似函数,它们很容易实现,并帮助你了解如何在强化学习问题中应用它们。
状态聚合
函数逼近的最简单形式。比如,假设空间中有 10 个状态(1,2,3,…,10),我们设 1 到 5 有相同的值,6 到 10 有另一个值,那么这就叫状态聚合。数学表示可以是:
V(S) = w_0 if 1≤S≤5
V(S) = w_1 if 5<S≤10
函数很简单,但非常重要,因为这个想法在 Tile 编码中非常关键,Tile 编码是一种函数泛化技术,在强化学习问题中被大量使用。状态聚合的优点是每个聚合会话中状态的导数为 1,该状态的值为相应的权重。
多项式
我们将在此应用的多项式函数可以写成:
V(S) = w_0*S^0 + w_1*S^1 + ...
在这种情况下,权重参数的导数总是其对应于状态的幂的值。
傅里叶
与多项式情况类似,这里应用的傅立叶函数为:
V(S) = w_0*cos(0*πs) + w_1*cos(1*πs) + ...
重量 w_i 的导数为 cos(iπs)。*
请注意,这里介绍的多项式和傅里叶在权重参数方面都是线性的,因为这保证了收敛性。此外,这里我只介绍了一个国家的情况,更普遍的形式,请参阅萨顿的书。
1000 态随机行走
对于定理来说已经足够了,让我们应用我们所学的,并得到一个实际的案例。
规则
考虑一个 1000 状态版本的随机行走任务。这些状态从左到右从 1 到 1000 编号,并且所有情节都在状态 500 中的中心附近开始。状态转换是从当前状态到其左侧的 100 个相邻状态之一,或者到其右侧的 100 个相邻状态之一,所有这些都具有相等的概率。当然,如果当前状态接近一个边,那么在它的那一边可能有不到 100 个邻居。在这种情况下,那些丢失的邻居的所有概率都变成了在该侧终止的概率(因此,状态 1 有 0.5 的机会在左侧终止,而状态 950 有 0.25 的机会在右侧终止)。像往常一样,左边的终止产生-1 的回报,右边的终止产生+1 的回报。所有其他转换的奖励为零。
还记得我们在另一篇文章中谈到的 100 态随机漫步吗,这里的规则基本相同。不同之处在于
- 每一步的范围从 1 到 100
- 当代理闯入边界时,它在那里结束
Python 实现
我之前实现了离散状态空间上的随机行走,你可以在这里查看。下面的实现中,我将重点介绍两者的区别。
近似函数
连续状态空间中强化学习的灵魂。价值函数应该能够做到
- 获取给定状态的值
- 给定状态和时间差异,更新权重
聚集状态函数
对于状态聚合,1000 个状态被分成 10 组,每组 100 个状态(即状态 1-100 为一组,状态 101-200 为另一组,依此类推)
1000 个状态被分成 10 组,每组都有一个值存储在self.values
中。value
函数仅返回存储在相应组中的值,而update
函数通过添加delta*dev
来更新该值,如上所述,这里导数为 1,delta
为*G-V(S, w)*
。(注意,这里的value
实际上是权重参数)
多项式&傅立叶函数
LinearValueFunction
包括多项式函数和傅立叶函数。在value
函数中,features
是值函数表示的组件列表,在update
函数中,导数等于组件值,如上所述。
采取行动
与之前的随机行走不同,这里代理可以走得更快(从 1 步到 100 步),当它的位置到达边界外时,该集结束,奖励将为-1 或 1。
玩游戏
有了以上所有的准备工作,播放功能就容易实现了。该结构与我们之前的实现非常相似:
如果你一直在跟进我以前的帖子,你一定见过这个结构很多次了。这里唯一的区别是价值函数被valueFunction
代替了。
学习结果
应用了三个不同的值函数,让我们比较一下学习结果。(全面实施)
Aggregate State
对于具有 1 个步骤的聚集状态函数,1000 个状态被聚集成 10 个组,每个组有 100 个状态,这就是为什么您会看到类似楼梯的图形。
Polynomial Function
这是具有 5 阶和 1 阶多项式函数的学习图,从中我们看到在较低状态的发散和在较高状态的收敛。这是因为对于多项式函数近似,总是存在截距,从而使得状态 0 的值是非零的(通常,多项式函数不被识别)。
Fourier Function
这是目前最好的近似,通常傅里叶函数比多项式函数具有更好的性能。
结论
我们在这里学习了连续空间中强化学习的基本理论,并实现了一些基本的近似函数。当然,这个想法不仅仅局限于这些功能。在更高级的设置中,可以利用神经网络功能,这产生了深度强化学习问题。
在下一篇的中,我将介绍 tile 编码,并将其应用于连续状态空间中的 Q 函数学习,这比随机游走例子更具一般性。
参考:
- 【http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/JaeDukSeo/reinforcement-learning-an-introduction
强化学习——非策略学习的概括
贝尔德反例
到目前为止,我们已经将我们的强化学习主题从离散状态扩展到连续状态,并详细阐述了将瓦片编码应用于基于策略的学习,即学习过程遵循代理所采取的轨迹。现在让我们来谈谈在连续环境下的非政策学习。虽然在离散的设置中,基于策略的学习可以很容易地推广到非策略的学习(比如,从 Sarsa 到 Q-learning),但在连续的设置中,这种推广可能有点麻烦,在某些情况下可能会导致分歧问题。在本文中,我将:
- 介绍由政策外学习的延伸所引起的问题
- 举贝尔德反例来说明这个问题
- 介绍解决问题的潜在方法
政策外学习的问题
偏离政策学习最突出的结果是,它可能不一定在连续的环境中收敛。主要原因是由于非策略情况下的更新分布不符合策略分布,即状态,用于更新的动作可能不是代理采取的状态、动作。下面进入更新公式,进一步说问题。在偏离策略学习的连续状态下,1 步更新流程如下:
注意,与政策上的概括相比,多了一个术语ρ
,称为重要性抽样比率。ρ
由目标策略π
除以行为策略b
,计算。在控制中,目标策略通常是相对于动作值函数的当前估计的确定性贪婪策略。该策略成为确定性的最优策略,而行为策略保持随机且更具探索性,例如,ϵ-greedy 策略。回想一下,在 Q 学习的离散状态空间中,时间差异是max{Q(S', A')} — Q(S, A)
(不考虑奖励),因此在每次状态更新时,最大 Q 值(来自贪婪策略)用于更新,而不是实际状态的值,即代理采取的动作(行为策略)。在连续空间中,使用行为策略利用重要性抽样来接近目标策略值。关于ρ
的更多解释,可以参考这里的和这里的(关于重要性抽样的更多解释,可以参考这里的)。
公式的其余部分与 on-policy learning 相同,其中w
是权重向量,δ
是时间差异(注意,根据问题是否是情节性的,δ略有差异,对于非情节性的情况,请参考此处的)。
根据萨顿在书中的描述,政策外学习的差异是由以下原因造成的:
一个转换重复发生,而
w
不会在其他转换中更新。这在非策略训练下是可能的,因为行为策略可能选择目标策略永远不会选择的那些其它转变上的动作。
不要担心,如果你有一点困惑,让我们继续一个例子,看看权重如何发散。
贝尔德反例
这是一个著名而简洁的例子,说明了偏离政策学习的发散特征。
问题描述
Baird Example
虚线动作以相等的概率将系统带到六个上状态之一,而实线动作将系统带到第七个状态。 *behaviour policy b*
选择概率为*6/7*
*1/7*
的虚线和实线动作,使其下的下一状态分布均匀(所有非终结状态相同),这也是每集的起始分布。目标策略* *π*
总是采取稳健的行动,所以策略上的分布(对于 *π*
)集中在第七个状态。所有转场的奖励是 *0*
。折现率为 *γ = 0.99*
。(仅出于简单和说明的原因,目标策略设置为固定)*
请注意,每个圆圈内是使用权重向量的每个状态的表示。
在下面的实现中,步长α = 0.01
和初始权重是w = (1, 1, 1, 1, 1, 1, 10, 1)
。
履行
检查完整的实现
初始化
尽管有一些常规设置,注意self.features
是每个状态的表示,而self.weights
是权重向量(初始值是特意设置的)。权重和特征的乘积是每个状态的值。
行动
行动的选择和采取遵循规则。
价值函数
如上所述,值函数通过将特征和权重相乘来返回状态的值。
违反政策运行
有了上面的准备,我们就可以让代理学习了。在每一轮中,代理重复状态、动作、下一个状态、下一个动作……的过程,因为我们设置目标策略总是选择solid
行,当代理采取动作dash
时,重要性抽样比率将为 0,当它采取solid
动作时,重要性抽样比率为1/self.prob
。sarsa
参数用于控制是否使用基于策略的学习(在基于策略的学习中,目标策略总是行为策略,因此ρ = 1
),这仅用于结果比较。
学习结果
看到在偏离策略的学习中,权重发散到无穷大,而在策略上的方法(在这种情况下是 Sarsa)收敛。现在我们再来看一下图像,解释一下原因:
例如,当代理从最左边的状态(2w1+w8)到底部的状态(w7+2w8)采取一个固体动作时,如果 w8 通过上面的公式增加它的值,这将导致两个状态的值增加,因为它们共享权重 w8。然而,从底部状态开始,通过采取 dash 动作不会有助于偏离策略学习,因为在这种情况下ρ
为 0,这导致 w8 的值总是增加但从不减少。萨顿是这样说的:
一个转换重复发生,而
*w*
不会在其他转换中更新。这在非策略训练下是可能的,因为行为策略可能选择目标策略永远不会选择的那些其它转变上的动作。
解决方法
就解决方案而言,第一个是在连续空间设置上不使用偏离策略的学习,而总是使用符合策略的学习。另一种方法是改变目标误差函数。到目前为止,所有的函数逼近更新都是基于(true_value — current_value)^2
的目标误差,但是为了使训练过程收敛,萨顿在他的书中建议最小化投影贝尔曼误差(PBE)。详细解释请参考他的书这里,第 11 章。
这里我给出了这种方法的一个简单实现,并将其与经典的偏离策略学习进行了比较。通过最小化 PBE,可以得到一个更新公式:
其中β
是另一个步长参数,而vt*xt
(xt 是特征向量)是ρ*δ
的近似值。这种方法被称为带梯度修正的时延估计(TDC)
贸发局的实施
唯一的区别在于run
功能:
这个过程完全遵循上面的公式,使用 TDC,我们得到一个学习过程:
Learning Process of TDC
请注意,权重会慢慢收敛到最佳值。还有其他介绍的解决问题的方法,有兴趣的可以自己了解一下(查看完整实现)。
最后,提到萨顿的书的结尾部分:
政策外学习的整个领域相对较新且不稳定。哪种方法是最好的,甚至是合适的,现在还不清楚。本章末尾介绍的新方法的复杂性真的有必要吗?其中哪些可以和方差缩减法有效结合?政策外学习的潜力仍然诱人,实现它的最佳方式仍然是个谜。
参考:
- *【http://incompleteideas.net/book/the-book-2nd.html *
- https://github . com/Shang tongzhang/reinforcement-learning-an-introduction
强化学习——连续任务的概括
服务器访问示例实现
到目前为止,我们已经经历了许多强化学习的例子,从基于策略到不基于策略,从离散状态空间到连续状态空间。所有这些例子在某些方面都有所不同,但你可能已经注意到它们至少有一个共同的特点——情节性,即所有这些都有一个明确的起点和终点,每当代理达到目标时,它就会一次又一次地重新开始,直到达到一定数量的循环。在本文中,我们将把这一思想扩展到非情节任务,即没有明确终点的任务,并且主体在环境设置中永远继续下去。在本文中,我们将
- 学习应用于非情节任务的思想和算法
- 实现服务器访问示例(瓦片编码是必需的)
平均报酬
应用于非偶发性任务的主要概念是平均报酬。平均奖励设置也适用于持续问题,即代理和环境之间的交互永远持续下去而没有终止或开始状态的问题。然而,与这种设置不同,这里没有折扣——代理人对延迟奖励的关心和对即时奖励的关心一样多。所以关键是
- 在此设置下没有折扣系数
- 平均奖励将被引入算法
让我们直接进入算法,我会解释为什么会这样。
差分半梯度 Sarsa
首先,该算法适用于连续状态空间,实际上,智能体的探索过程和权重更新过程与我们之前谈到的其他算法是相同的,不同之处在于这里引入的平均奖励项。
关键区别在于δ的定义,在继续任务中,奖励定义为R(S, A) — R(average)
,即当前状态下收到的奖励与直到当前状态的平均奖励之差。我给大家直观的解释一下为什么这里要引入平均奖励,回想一下R(S, A) + Q(S', A')
的定义,它是对Q(S, A)
的价值的估计,等于代理人一路走到游戏结束要收集的奖励。然而,在一个连续的任务中,游戏永远不会结束,因此收集的奖励可能趋于无穷大,它需要一个项来约束估计值,然后得到平均奖励!
随着步骤的进行,平均奖励也需要更新(注意,β是奖励更新专用的学习率)。对于平均奖励设置,就像为代理设置了一个基线,只有当代理进行一个给出高于平均奖励的行为时,权重才能被正向更新,否则为负向(不考虑下一个状态的 q 值)。如果你仍然不相信这个解释,并且怀疑如果没有平均奖励项会发生什么,我会在帖子的最后给你看没有平均奖励的服务器访问示例的学习结果。
服务器访问实现
现在让我们将该算法应用于一个具体的连续任务示例,该示例引自 Sutton 的书,名为访问控制排队任务。
问题描述
这是一个决策任务,涉及到对一组 10 台服务器 的访问控制。 四个不同优先级 的客户到达一个队列。如果被给予访问服务器的权限,客户向服务器支付 奖励 1、2、4 或 8 ,这取决于他们的优先级,优先级越高的客户支付的越多。在每个时间步中,队列最前面的客户要么被接受(分配给其中一个服务器),要么被拒绝(从队列中删除,奖励为零)。在这两种情况下,在下一个时间步,考虑队列中的下一个客户。队列永远不会清空,队列中客户的优先级是平均随机分布的。当然 如果没有免费的服务器 顾客就无法得到服务;在这种情况下,顾客总是被拒绝。 每个繁忙的服务器在每个时间步长上以概率 *p = 0.06*
空闲。 任务是在每一步决定是否接受或拒绝下一个顾客,依据他的优先级和免费服务员的数量,从而最大化长期报酬而不打折扣。
概括地说,我们的代理需要根据客户的优先级和当前的免费服务器数量来决定是否接受客户,以便获得最大的长期回报。这个游戏设置肯定是一个持续的任务,因为这个过程永远不会结束,因为等待队列永远不会是空的。状态为(numberOfFreeServers, customerPriority)
,行动为拒绝或接受,根据客户的优先级,奖励为 1、2、4、8。如果你清楚这些规则,让我们开始执行吧。(全面实现)
价值函数
这是一个离散状态任务,但是由于我们已经集中讨论了在连续状态上应用瓦片编码,我们将在状态空间的表示中再次应用它,即使它是离散的(我们在这里应用的瓦片编码函数在这里讨论)。
这实际上是一个 Q 值类,我们在里面设置了 8 个 tilings,总共 2048 个网格。动作 1 代表接受,0 代表拒绝。value
函数根据当前状态(n_server,priority)和动作给出值,update
函数相应地更新权重。stateValue
函数返回状态的最大值(这个函数只会用在可视化部分),注意当空闲服务器数为 0 时,它返回动作 0 的值(总是拒绝)。
现在让我们进入主类:
初始化
所有这些初始化都是不言而喻的,并且对于每个服务器,免费概率是 0.06。
动作选择
numFreeServers
函数根据当前状态给出当前空闲服务器的数量。chooseAction
函数基于当前状态和我们上面讨论的值函数选择动作,动作选择方法也是ϵ-greedy.
下一个状态和奖励
在代理采取行动之后,我们需要判断下一个状态,如果行动被接受,空闲服务器的数量将减 1,如果行动被拒绝,空闲服务器的数量保持不变。下一个客户的优先级是随机生成的。
giveReward
函数只是根据客户的优先级给出奖励。在拒绝动作的情况下,奖励总是 0。
滚动游戏
最后的run
函数,我们会把整个过程组装起来,让代理学习。
该函数非常简单,因为一切都完全按照算法中的步骤进行。(全面实施)
结果
现在让我们看看我们的代理表现如何:
这是 50,000 轮后的结果,其中α=0.01,β=0.01,exp_rate=0.1。图表右侧的下降可能是由于数据不足;这些状态中有许多是从未经历过的。
最后,让我告诉你如果没有平均回报期限会发生什么。
状态值比实际值大得多,事实上,我们运行的轮数越多,状态值就越大,因为δ没有被很好地限制。
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/Shang tong Zhang/reinforcement-learning-an-introduction
强化学习——实现网格世界
引入值迭代
当你试图着手强化学习时,很可能网格世界游戏是你遇到的第一个问题。这是强化学习中最基本也是最经典的问题,我相信,通过自己实现它,是理解强化学习基础的最好方法。与此同时,实现你自己的游戏,看看一个机器人如何自己学习也是非常有趣的!
规则
Grid Board
规则很简单。你的代理人/机器人从左下角(“开始”符号)开始,并以相应的奖励+1 或-1 结束。在每一步,代理人有 4 个可能的动作,包括上、下、左、右,而黑色的方块是一堵墙,代理人无法穿过。为了使它更直接,我们的第一个实现假设每个动作都是确定性的,也就是说,代理将去它打算去的地方。例如,当代理决定在(2,0)采取行动时,它将在(1,0)而不是(2,1)或其他地方着陆。(我们将在我们的第二个实现中增加不确定性)然而,如果代理碰到墙,它将保持在相同的位置。
板
所以让我们开始破解代码吧!首先,让我们建立一些董事会的全局规则。(全码)
而作为一个网格游戏,它需要一个状态来为我们代理人的每个状态(位置)正名,根据其状态给予奖励。
当我们的代理人采取行动时,国家应该有一个功能来接受行动并返回下一个国家的法律地位。
代理人
这是人工智能部分,因为我们的代理应该能够从过程中学习,并像人类一样思考。魔术的关键是价值迭代。
值迭代
我们的代理最终将学习的是一个策略,而策略是从状态到动作的映射,简单地指示代理在每个状态下应该做什么。在我们的例子中,不是学习从状态到行动的映射,我们将利用价值迭代来首先学习状态到价值的映射(这是估计的回报),并且基于该估计,在每个状态,我们的代理将选择给出最高估计回报的最佳行动。
不会有任何古怪、令人挠头的数学问题,因为价值迭代的核心非常简洁。
value iteration
这就是价值迭代的精髓,超级利落吧?这个公式几乎适用于所有的强化学习问题,让我解释一下我们的智能体是如何基于这个公式从一个婴儿进化成专家的。价值迭代,顾名思义,在每次迭代(游戏结束)时更新其价值(预估奖励)。
起初,我们的代理对网格世界(环境)一无所知,所以它会简单地将所有奖励初始化为 0。然后,它开始通过随意走动来探索世界,当然它一开始会经历很多失败,但这完全没关系。一旦它到达游戏结束,奖励+1 或奖励-1,整个游戏重置,并且奖励以向后的方式传播,最终沿途所有状态的估计值将基于上面的公式更新。****
让我们仔细看看这个公式。左边的 V(St) 是该状态的更新值,右边的是当前未更新值, α 是学习率。该公式简单地说,状态的更新值等于当前值加上一个时间差,这是代理从玩游戏的迭代中学习到的减去先前的估计。例如,假设有两个状态,S1
和S2
,它们都有一个估计值 0,在这一轮游戏中,我们的代理从S1
移动到S2
并获得奖励 1,然后是S1 = S1 + α(S2 - S1)
的新估计值,即0 + 0.1(1-0) = 0
(假设α为 0.1,在S1
的奖励为 0)
我们记录代理的所有状态,在游戏结束时,我们将以reversed
的方式更新评估。
勘探&开采
我们还有最后一件事要谈。一旦我们的代理发现了一条获得+1 奖励的路径,它应该坚持下去并永远沿着这条路径走下去(剥削)还是应该给其他路径一个机会(探索)并期待一条更短的路径?实际上,我们将平衡探索和开发,以避免我们的代理陷入局部最优。在这里,我们的代理将基于某些exploration_rate
选择操作
玩
就是这样!这些都是我们玩网格世界游戏所需要的。我们可以开始,让我们的代理人玩游戏!
50 round of playing
这是每个州打完 50 轮游戏后的预估。由于我们的行动是确定性的,我们可以通过遵循最高的估计在每个状态下获得最佳行动!完整的代码是这里,去玩吧,如果你发现有什么需要更新的,欢迎投稿!
目前,我们都在关注价值迭代和确定性游戏世界。然而,在实际情况中,代理并不总是到达它希望到达的位置。让我们更深入地探索非确定性游戏和 Q-learning 。
参考文献
[1]https://www . cs . Swarthmore . edu/~ bryce/cs63/s16/slides/3-21 _ value _ iteration . pdf
[2]https://github . com/JaeDukSeo/reinforcement-learning-an-introduction
强化学习—实施 TicTacToe
两个代理人游戏介绍
我们通过迭代更新 Q 值函数,即(state, action)
对的估计值,实现了网格世界游戏。这一次,我们来看看如何在对抗性游戏中利用强化学习——井字游戏,其中有更多的状态和动作,最重要的是,有一个对手与我们的代理人对抗。(查看之前的帖子)
强化学习的优势
然而,在一般的博弈论方法中,比如最小-最大算法,算法总是假设一个完美的对手是如此理性,以至于它采取的每一步都是为了最大化它的回报和最小化我们的代理人回报,在强化学习中,它甚至没有假设对手的模型,结果可能会出乎意料地好。
通过将对手视为智能体可以与之交互的环境的一部分,在一定数量的迭代之后,智能体能够在没有智能体或环境的任何模型的情况下提前计划,或者对可能的未来动作或状态进行任何搜索。优点是显而易见的,因为该方法省去了复杂的数学推导或探索大量搜索空间的努力,但是它能够通过简单的尝试和学习来达到最先进的技能。
在接下来的会议中,我们将:
- 首先,训练两个代理相互对战并保存他们的策略
- 第二,加载策略,让代理人扮演人类
状态设置
首先,我们需要一个州级机构来充当董事会和法官。它具有记录双方玩家棋盘状态的功能,并在任何一方玩家采取行动时更新状态。同时,它能够判断游戏的结束,并相应地给予玩家奖励。(点击 查看 代码)
tic-tac-toe board
为了阐明这个强化学习问题,最重要的是要清楚 3 个主要组成部分——状态,行动,和奖励。这个游戏的状态是代理人和它的对手的棋盘状态,所以我们将初始化一个 3×3 的棋盘,用 0 表示可用的位置,如果玩家 1 移动,用 1 更新位置,如果玩家 2 移动,用-1 更新位置。动作是玩家根据当前棋盘状态可以选择的位置。奖励在 0 到 1 之间,只在游戏结束时给出。
初始化
在init
功能中,我们初始化一个空棋盘和两个玩家p1
和p2
(我们初始化p1
以先玩)。每个玩家都有一个playSymbol
,当玩家采取一个动作时,它的playerSymbol
会被填入棋盘并更新棋盘状态。
董事会状态
getHash
函数对当前电路板状态进行哈希运算,以便将其存储在状态值字典中。
当玩家采取行动时,其对应的符号将被填入棋盘。并且在状态被更新后,棋盘还会更新当前棋盘上的空位,并依次反馈给下一个玩家。
检查赢家
在玩家采取每一个动作后,我们需要一个函数来持续检查游戏是否已经结束,如果结束,判断游戏的赢家,并给予双方玩家奖励。
winner
函数检查行、列和对角线的总和,如果p1
赢则返回 1,如果p2
赢则返回-1,如果平局则返回 0,如果游戏尚未结束则返回None
。在游戏结束时,1 奖励给赢家,0 奖励给输家。需要注意的一点是,我们认为平局也是一个糟糕的结局,所以我们给我们的代理人p1
0.1 的奖励,即使游戏是平局(可以尝试不同的奖励,看看代理人如何行动)。
播放器设置
我们需要一个代表我们代理的玩家类,玩家能够:
- 基于状态的当前估计选择动作
- 记录游戏的所有状态
- 每场比赛后更新状态值估计
- 保存并加载策略
初始化
我们将初始化一个dict
存储状态值对,并在每局游戏结束时更新估计值。
在init
函数中,我们在列表self.states
中记录玩家在每场比赛中的所有位置,并在self.states_value
dict 中更新相应的状态。在行动选择方面,我们使用ϵ-greedy 方法来平衡探索和开发。这里我们设置了exp_rate=0.3
,意思是ϵ=0.3
,所以 70%的时间我们的代理将采取贪婪的行动,这是基于状态值的当前估计选择行动,30%的时间我们的代理将采取随机行动。
选择操作
我们将板状态的散列存储到状态值字典中,并且在利用时,我们散列下一个板状态并选择返回下一个状态的最大值的动作。
状态值更新
为了更新状态的值估计,我们将应用基于以下公式更新的值迭代
Value Iteration(From Reinforcement Learning an Introduction)
公式简单的告诉我们 状态 t 的更新值等于状态 t 的当前值加上下一个状态的值和当前状态的值之差,再乘以一个学习率α(假设中间状态的奖励为 0) 。
逻辑是我们基于我们最新的观察慢慢更新当前值。
正如我上面提到的,每场比赛的位置存储在self.states
中,当代理到达比赛结束时,估计值以reversed
的方式更新。
培养
既然我们的代理能够通过更新价值评估来学习,并且我们的板都设置好了,那么是时候让两个玩家互相对战了(这个部分放在 State 类中)。
在训练期间,每个球员的过程是:
- 寻找空缺职位
- 选择操作
- 更新棋盘状态并将动作添加到玩家状态
- 判断游戏是否结束,并给予相应的奖励
保存和加载策略
在训练结束时(在一定数量的回合之后玩),我们的代理能够学习它的策略,它存储在状态值字典中。我们需要保存这个策略来对抗人类玩家。
人类 VS 计算机
现在我们的代理已经设置好了,在最后一步,我们需要一个人类类来管理与代理的游戏。
这个类只包含了一个可用的函数chooseAction
,它要求我们输入我们想要的棋盘位置。
而且我们还需要修改一下play
函数内部的状态:
大致相同,我们让 1 号玩家(也就是我们的代理人)先玩,每走一步,棋盘就印好了。
玩得开心!
Play against human
play2
功能我们显示棋盘状态,并要求你在游戏过程中输入你的位置。
自己去试试,玩得开心!(点击 查看 代码)
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/JaeDukSeo/enforcement-learning-an-introduction
作业调度中的强化学习
In October 2015, AlphaGo, an AI-powered system, beat Mr Fan Hui, the reigning 3-times European Champion of the complex board game Go, by 5 points to 0. It was the first time an AI conquered a human in such a sophisticated game.
写我的第一篇媒体文章的想法引起了我的兴趣,因为我相信这可以给我一个平台来分享和贡献我想从社区成员那里读到的东西。一个外行人很难理解科学出版物和研究论文,以至于他/她要花几天甚至几周的时间才能彻底理解术语和院士工作的新颖性细节。因此,我以此为媒介(这是一个巧合的双关语)开始撰写和解释一个特定的科学贡献,尽我所知,鼓励其他作家以类似的方式做出贡献。
我想以基于出版物的第一篇文章开始我的系列文章,标题为“使用深度强化学习的多资源管理和突发时间预测”。
从技术细节开始,有必要向读者介绍我们生活中各种科技方面普遍存在的资源分配问题。我们可以谈论任何领域的资源,比如无线电网络、无线通信网络、云计算、软件网络等等。无论系统出现在哪里,只要它将一组任务/作业作为输入,就总是涉及到为这些任务/作业组分配资源的概念。
谈到资源需求,我们会想到资源集群和集群调度的概念。考虑一个在线多资源分配问题,它包括 CPU、I/O 单元、内存等资源。(参见下图)。
这样一组聚集在一起的不同资源可以被称为资源集群,并且到达的每个任务/作业将需要属于该集群的每个资源的一定数量的单元。我们的目标必须是最大限度地减少任何资源的浪费,也就是说,这些资源不应该长时间闲置,特别是如果未来的工作需要它们来完成。因此,集群利用率和效率被视为适当的资源管理和调度决策的重要指标。
为了解决手头的问题,作者提出了 SchedQRM,这是一个在线多资源调度器,它接受一组作业及其作业签名作为输入(这里,作业签名指的是 BSS、ROdata 等值。对于一组编程应用程序/代码来说,使用一些基本的 Linux 命令就可以很容易地实现这一点。调度程序使用两层方法来执行上述任务:
- 根据签名对作业的突发时间进行分类
SchedQRM takes job signature as an input and predicts the burst time for the job using a Deep Neural Network (DNN).
2.采用强化学习算法来寻找最优调度策略
The second section consists of the reinforcement learning model, which outputs a scheduling policy for a given job set.
目标:优化平均工作减速或工作完成时间。
我想我在这里介绍了一些非常不同的术语。从突发时间开始,它被定义为过程完成所需的时间。作业减速被定义为作业完成时间与其突发时间之比。(注意——作业完成时间包括突发时间以及自调度程序收到作业后的其他等待时间。)
面临的最困难的挑战之一是最终确定特定的状态表示,其中给定的状态将包含关于要调度的作业的所有期望信息、正在使用的资源单元的数量以及在特定时间步长可用于即将到来的作业的资源单元的数量。下图显示了所使用的状态表示。(请参考 原创研究论文文章 以便更好地理解同一。)
Pictorial representation of a sample state.
这项工作背后的一个基本假设是,不允许工作被抢占,也不允许任何工作被优先分配。这展示了一个看似合理的未来机会,可以深入研究这个问题陈述,并处理一个更真实的场景,在这个场景中,这些假设是不存在的。
谈到本文和研究出版物的核心概念,简单地说,强化学习指的是一种学习,其中代理存在于给定的环境中,并能够根据它在做出特定决策时获得的奖励类型(正面或负面)自行做出合适的决策。这个问题陈述的形成和自动化端到端调度过程的想法仅仅基于这个概念,因此,我们相信,尽管强化学习已经成为许多研究人员关注的中心,但它确实可以成为解决各种问题陈述的有前途的方法。
我希望我已经能够以简单易懂的方式总结了上面讨论的研究文章。最后,我会进一步鼓励感兴趣的读者阅读研究论文以及研究机构对这一问题陈述做出的其他相关贡献,以获得更深入的见解。
关于这篇文章以及研究出版物的任何反馈都是最受欢迎的。如果有人愿意伸出手来分享他们对这一特定问题陈述的看法,我将不胜感激。
强化学习充满了操纵性的顾问
当用于训练强化学习算法的环境存在方差差异时,奇怪的事情就会发生。不管回报如何,价值评估网络更喜欢低方差的领域,这使他们成为一个善于操纵的顾问。Q-learning 算法陷入了“无聊区域陷阱”,并且由于低方差而无法摆脱。奖励噪音可以有所帮助,但必须小心谨慎。本文基于我的论文“用于强化学习的自适应对称奖励噪声
操纵顾问
我想象一下你去找一个投资顾问,你先问他如何收费。是根据你将获得的利润吗?“不,”他说。“我对你回报的预测越准确,你给我的报酬就越高。但我将只在你选择的投资上接受考验。”
这有点可疑,你开始四处寻找其他使用这个顾问的人。结果,他只向他们推荐了低回报、低波动的政府债券。他甚至告诉他们这是最高的平均回报!他们都相信他,买了债券,当然他对回报的预测非常准确,误差很小。所以他们不得不付给他最高的费用。
Source: South Park
你觉得这个人怎么样?我觉得他是一种“操纵型顾问”。
而强化学习中的每一个人都在用的正是这个家伙。
目前,在强化学习(RL)中有两个主要的算法家族:深度 Q 网络(DQN)和 Actor Critic。两者都使用顾问功能或“价值评估”功能——一种深度神经网络(DNN ),用于评估状态和/或行动的价值。在 DQN,这是 Q 网络,在演员评论家这是评论家网络。这基本上是一个好的决定:价值评估功能可以学习偏离政策,这意味着他们可以通过观看别人比赛来学习,即使他不太好。这使他们能够从过去已经放弃的政策中吸取经验。
然而,有一个问题:我们根据这个顾问的准确性“支付”他:用于优化网络的损失函数是基于网络的预测误差。并且网络在它选择的行动上被测试:政策将做网络建议的最好的,并且这将是经验的唯一未来来源。
现在,每个人都抱怨说 RL 还不能工作并且 Deep 几乎不能帮助。理应如此。训练 RL 算法是脆弱的:它强烈依赖于网络和参数的初始化,所以你必须一次又一次地重复相同的实验,每次都有不同的初始化。你看你的算法进步了,然后退步了。你感到困惑,因为它这样做的同时,损失函数继续显示改善的性能。你可以选择一路上最好的临时网络,然后就到此为止,但是你无法通过 RL 来进一步改善结果。
所以我们在这里声明的是,你只是选错了顾问。或者至少——选择了错误的支付方式。他选择了低回报的行动,并告诉你所有其他选择都更糟。他会更准确,因为他推荐的行动的回报是可以预测的。你永远不会发现他在操纵你,因为你一直在测试他的选择。
首先,让我们证明这些亏损缺口确实存在。拿一个简单的游戏来说:两台老丨虎丨机(RL 里叫“多臂土匪”),右边的一台给 1 奖励但方差高,左边的一台坏了,所以给 0 奖励方差 0。我们称之为断臂强盗。
现在,你必须决定在游戏的每一集使用哪一个。似乎很容易?不是为了 Q-learning。
请看下图中的两条细线。它们显示了当前选择右手柄(细线,绿色)和当前选择左手柄(细线,红色)的代理的 Q 表的更新项。在 DQN,这个更新术语将是功能丧失。从图中可以明显看出,选择左边的人做得更好,损失也更小:
现在,每一个好的 RL 算法都有它的探索方案。这里我们使用ε-贪婪方案,ε是衰减的。事实上,100%探索测试了顾问没有推荐的东西,并且得到了基本相同的损失。但这只是在训练开始的时候。随着ε衰变,探索减少,红色细线不断衰减。现在,如果你在一次真正的训练中看到那句话,你会不会认为一切都很好,因为损失正在下降?实际上,你看到的是一个懒惰的网络,它摆脱了艰苦的探索测试。
我们看到的是失败的差距,无聊的决定会赢。当我们通过最小化这种损失来优化深层网络时,有时它会偏向于最小化其损失的无聊决策。但是如果我们根本不用 DNN 呢?如果我们使用好的 Q 学习,用 Q 表呢?还有一个问题,叫做“无聊区域陷阱”。
无聊区域陷阱
想象一下,你有一辆自行车,有人在离你家一英里远的地方给你一份免费的比萨饼。你有两个选择:你可以放弃去那里,你会得到一个均值为 0 方差为 0 的披萨。另一方面,你可以决定骑到那里,然后你平均得到 1 个比萨饼,但差异很大:以非常小的概率,你可能会发生事故,你将在石膏中度过 6 个月,在极度痛苦中,为你毁坏的自行车赔钱,没有比萨饼。
Source: Lego Grad Student
通常,这是一个简单的决定:你以前从未发生过车祸,你估计现在发生车祸的可能性很低,你更喜欢较高的比萨饼平均值。所以你去那里买披萨。
但是如果你运气不好,仅仅骑了 100 次就出了事故怎么办?现在你估计事故发生的几率比真实的概率要高得多。开车去吃免费披萨的平均回报估计为负,你决定待在家里。
现在问题来了:你再也不能骑马了,因此也永远不会改变你骑马的想法。你会一直相信它有负的平均回报,你呆在家里的经历会验证你关于呆在家里的平均回报的信念,什么都不会改变。
无论如何,你为什么要离开家?嗯,必须发生的是一个互补错误。比如你呆在家里,一个架子掉在你头上。又一次,极度的痛苦。现在,你只能怪你的架子。你对呆在家里的评价也变得消极了。而如果低于你对离家的估计,你还会再出去吃那个披萨。
注意,这里没有优化:你有一个状态的 Q 表:饥饿状态,和两个动作:去或不去比萨饼。你直接从得到的奖励算出了手段。这是你能做的最好的事情,但是你最终被困在家里,饿着肚子,直到这个架子把你弄出来。
这个现象可以用上面的同一个断臂大盗来模拟。但是现在我们可以尝试使用 Q-learning 来解决这个问题。
让我们来看看 10 名代理就此任务接受的培训:
我们可以看到,他们所有人,在某个时候,都去获得零回报,这意味着他们选择拉故障的手臂。想象一下,他们站成一排,拉着死去的机器手臂,无视右边所有灯都亮着的工作着的机器。他们看起来不傻吗?好吧,笑话是关于我们利用他们作为我们的专家。注意:为了加快速度,我们选择了 0.1 的高学习率,所以通常经过几百万次迭代后发生的事情会发生得非常快。现在,让我们找 100 个代理,看看有多少人选择了左边不工作的手臂。他们在红线上:
再次,这需要一些时间,但他们最终都选择左臂作为他们的最佳选择。
为了了解发生了什么,我们将查看一个代理的内部参数——其 Q 表中 Q_left 和 Q_right 的值。我们删除了所有的探索,看看到底发生了什么,并初始化参数为最佳,所以这是一个训练有素的代理,至少在开始。右臂像以前一样有很高的方差。这里我们也给了左臂一个小的方差,所以这是一个具有方差差异的常规双臂土匪问题:
右臂方差大。因此,它的估计 Q_right 也有很高的方差,尽管由于它是与过去的回报相加而低得多。Q_right 因为几个集中的坏奖励,在第 40 集就变得比 Q_left 低了。
从那以后,代理只选择左边的手柄。所以它进入了“无聊区域陷阱”。现在 Q_right 改不了,由于缺乏实例。Q_left 由于方差较小,几乎没有变化。女士们先生们,这就是为什么我们称之为陷阱!
在第 320 集,出现互补错误。Q_left 变得比假低的 Q_right 低。这是当我们走出陷阱,并开始拉右臂,获得更好的 Q_right 估计。
什么方差差异导致了这个问题?这里我们可以看到不同σ_l 和σ_r 值的评分图,显示在 10,000 集后,50 个代理中有多少选择了右臂:
在右下角有一个黑色区域,由于方差差异较大,所有代理都失败了。由于较低的方差差异,在中心有另一个区域,代理在该区域进出陷阱。只有当方差差异很低时,Q-learning 才起作用。较低的学习率会使黑暗区域进一步向右移动,但是会降低学习率,所以训练会非常慢。
奖励噪音
提出的解决方案来自人类认知的一个实验。一些科学家进行了一项名为“行进中的农业”的实验,该实验与双臂土匪相同,但每个动作都移动了两台机器的方式。他们发现,给奖励增加一点噪音自相矛盾地帮助了人们【排除简单假设】和鼓励【选择抽样】,实际上帮助他们获得了更多的奖励!我们也可以这样做。我们可以给奖励增加一个对称的噪声,这样它就不会影响平均奖励。
但如果我们把噪音平均加到所有奖励上,还是会有有利于左机的损失差距。所以我们希望它是自适应的,这意味着我们将只给低方差动作添加噪声。
如果我们这样做,就会得到我们已经看到的图表中的粗线:
这表明我们在所有奖励中添加了大量噪声,但现在两台机器中的噪声量大致相同。这就是 ASRN 或自适应对称奖励噪声所做的:它估计哪些状态/动作具有低方差,并主要向它们添加噪声。它是如何估算的?使用 Q_table 的更新。更新越大,奖励越惊喜,得到的噪音也就越少。
你可以在这里看到它是如何实现的。当然,ASRN 有它自己的训练期,所以在上面的例子中,变化只在 1000 集之后开始。
当我们检查上面断臂强盗的 ASRN 时,我们看到它帮助特工们走出无聊区域陷阱。以下是上面的 10 个代理:
他们中的一些人到达了无聊区域陷阱,但是利用我们添加的噪音设法逃脱了。
噪声驾驶
现在,所有这些用在强盗身上很好,但是用在真正的东西上呢?
嗯,开车就是一个很合适的例子。就像上面的比萨饼一样,有一个策略会给你低方差的低回报,比如“向左直到你崩溃”。另一方面,还有实际驾驶的策略,由于“达到目标”大奖,它可以有很高的平均奖励,但它伴随着很高的方差——沿途有许多危险等待着。我们使用 AirSim 邻域驾驶模拟训练了一个代理。这是一个非常逼真的驾驶模拟器:
他们已经实现了一个 DQN 代理。因此,剩下要做的就是查看插入 ASRN(绿色)后的平均驾驶时间,与没有 ASRN(红色)和具有统一奖励噪声(青色)的平均驾驶时间进行比较:
这样肯定更好,不是吗?这里可以看到修改后的代码。
这里的是试驾的上策。这不是一个很好的司机。然而,这对于只参加 2750 场比赛的训练来说是一个相当大的成就。
综上所述:我们看到了方差差异给 RL 带来的问题。有些是全球性的,如无聊区域陷阱,有些是深度强化学习(DRL)特有的,如 M 被动顾问。我们还看到,奖励噪声可以有所帮助,特别是如果噪声是对称的,并适应实际的行动差异。我们探索了 Q-learning 和 DQN,但它很可能也适用于演员评论和其他算法。显然,奖励降噪并不是一个完整的解决方案。许多复杂的探索需要并行进行,还有其他 RL 技巧,如剪辑等。操纵性顾问和无聊区域陷阱问题提出的问题至少和它们回答的问题一样多。但是当我们坐下来计划我们的 RL 策略时,记住这些问题是很重要的。思考这一点至关重要:在这种环境中有任何方差差异吗?它们如何影响所选择的算法?也许这将导致一个更稳定的 RL。
感谢:什洛莫·科恩、塔利亚·索尔伯格、奥娜·科恩、吉利·伯克和吉尔·索德·御名方守矢
强化学习正在成为主流。这是可以期待的。
在游戏中击败世界冠军的相同技术将很快彻底改变任何可以模拟的东西(因为一切的核心都是物理——随着时间的推移,这就是一切)
我把这篇文章变成了一个 20 分钟的演讲,所以如果你喜欢看,你可以看:
我上周在拉斯维加斯参加了 AWS re:MARS 会议,本周的主题是机器学习、自动化和机器人(有时在太空中)的结合将如何塑造未来。许多人可能认为这个节目的明星是小罗伯特·唐尼,但在我看来是模拟和强化学习,它出现在会议的几乎每个主题演讲中:
第 1 天:通过强化学习,波士顿动力公司的机器人学会了后空翻、跳上壁架和举起数据。迪士尼幻想工程将这一点推向了一个新的高度,人形机器人表演了挑战死亡的特技。
第二天:亚马逊在他们的 Go 商店使用模拟来训练模型应对困难场景。亚马逊履行中心的机器人被训练使用强化学习来分拣包裹。Alexa 使用模拟交互来自动学习对话的流程。亚马逊无人机送货利用模拟数据训练模型,用于探测无人机下方的人。像 Insitro 这样的公司已经开始使用 RL 通过生成生物交互数据来解决生物医学问题。
第三天:吴恩达称元学习为人工智能的“下一件大事”,在元学习中,数百个不同的模拟器被用来构建更通用的强化学习代理。自动驾驶汽车公司 Zoox 和 Aurora 使用 RL & meta-leraning 来解决在城市环境中驾驶的复杂性。DexNet 正试图建立一个大规模的 3D 模型数据集来帮助利用模拟解决问题。杰夫·贝索斯同意达芙妮·柯勒的观点,RL 生物工程将在 10 年内发展壮大。
综上所述:
如果一个领域中的任务可以被精确模拟,强化学习将在未来几年内极大地提高该领域的技术水平。
物理学有什么用处?
如果你读了我之前的帖子,你会知道我的第一个女儿已经四岁了。这使她坚定地进入了人生的“为什么”阶段,在这个阶段,她的大脑从简单的学习任务转变为想要了解世界的一切。作为一个超级书呆子,我总是开玩笑说,每当她问“为什么”时,我会很乐意带她一路下兔子洞去学物理。事实证明,我的父母错了,甚至一个四岁的孩子也会厌烦地问“为什么?”然后去做一些更有趣的事情,比如涂颜色或者假装在看书。下面是一个典型的交换:
Created using http://cmx.io
这些和数据科学有什么关系?
我最近看了杰夫·迪恩在今年谷歌 I/O 大会上关于深度学习状态的演讲。他提到,神经网络已经被训练为逼近物理模拟器的结果,并以 30 万倍的速度得出结果,研究人员有可能在午餐时测试 1 亿个分子。
Image Source: Jeff Dean presentation at Google I/O 2019
这是一个巨大的进步,因为它应该允许我们使用与 re:MARS 中的明星相同的强化学习技术来解决一系列新的问题。在这些进步之前,为每个潜在的奖励运行一个完整的物理模拟器的周期时间对于 RL 来说太长了,以至于不能达到奖励状态。现在,RL 应该能够了解分子的物理性质,这将优化化学工程师的预期属性。
鉴于一切都可以归结为物理,我开始想象一个世界,在这个世界里,有可能从第一原理构建更多的解决方案。在参加会议时,我曾以为生物学多年来都无法用于模拟,但我刚刚得知,今天已经有像 Insitro 这样的公司开始解决这个问题。
其他最近的发展只会加速我们进入未来状态,在这种状态下,RL 可以用于“更高水平”的科学,如心理学:
- 原始计算能力:谷歌还发布了 T3 TPU 吊舱的私人测试版,其处理能力超过 100 Petaflops ,为运行神经网络训练架构而定制。有了这种能力,像材料分析这样的任务可以很快学会。此外,谷歌已经开始使用 RL 来设计芯片本身,随着时间的推移,这应该会导致额外的改进。
- 更好的可重用性 : DeepMind 正在研究多层网络架构,其中初始 RL 代理为给定任务选择合适的下游网络。这种类型的 RL 代理可以被训练成将高级任务分解成组件,并使用迁移学习解决多个任务。
- 更好的推广:前面提到的元学习技术正在提高 RL 代理适应他们以前没有见过的场景的能力。
- 更好的优化:麻省理工学院的彩票假说论文表明,通过找到“中奖彩票”路径,然后仅使用这些路径进行重新训练,可以进一步压缩神经网络。
- 更好的训练数据生成:像 AutoCad 的创成式设计这样的接口可以帮助设计师/工程师发现需要提供的规范,以便 RL 代理向正确的方向移动。每当有人必须接管时,自动驾驶汽车公司都会产生新的培训场景。
你该怎么办?
首先,你应该去了解强化学习:有许多 伟大的 教程和课程可以教你 RL 的直觉和内部工作方式,所以我们在这里将保持简短:RL 代理获得他们环境的解释状态,选择影响环境的行动,观察新的环境状态,并重复这个过程。如果行动产生了积极的结果,代理人会得到奖励,并且在未来类似的状态下更有可能选择同样的行动。
这种情况会重复很多集,最终,代理变得非常擅长获得奖励(因此也非常擅长我们训练它的任务)。用一些实际操作来补充这种体验的最佳方式之一是使用 AWS Deep Racer ,这是一辆按比例缩小的赛车,它提供了一个模拟环境、一个 RL 训练设置和一个与模拟相对应的物理硬件。你只需玩奖励功能来训练你的赛车代理。从那里你可以
其次,你应该开始积极地寻找方法来模拟你的企业中可以优化的系统。任何现有的模拟器都是一个很好的起点,但新的模拟器可能会产生巨大的影响。同样,AWS 在这一领域有一个名为 RoboMaker 的服务,但有许多替代方案,其中大部分基于开放 API Gym 。如果你想得到一个环境设置,你可以使用英特尔的蔻驰。它将代理、网络和内存结合在一起,让你在几十个不同的预配置代理中进行选择,这些代理针对各种任务进行了优化,然后轻松地将它们连接到 OpenAI 健身房环境。
最后,你应该留意那些乘着这股技术浪潮的新公司。我预计,最终将会有一系列开源模拟器开发出来,以彼此为基础,用深度神经网络来压缩每一层可以学习的关键信息。在此之前,很可能会有专利解决方案,在许多领域超越最先进的技术。随着时间的推移,这将在制药、材料科学、医药、下游石油和天然气等许多科学领域带来巨大收益。
如果你对快速入门感兴趣,我的同事 Ryan Keiper 做了一个演讲,详细讲述了他如何快速入门强化学习来构建一个下棋代理。
强化学习:让我们教出租车司机如何驾驶
强化学习是机器学习的一个子领域,其任务不同于“标准”的学习方式。事实上,你希望你的强化算法从周围环境中从头开始学习,而不是获得历史数据并根据这些数据做出预测或推断。基本上,你希望它像你在类似情况下所做的那样(如果你想了解更多关于 RL 的结构,点击这里阅读我以前的文章)。
在本文中,我将向您展示如何使用 Python 及其库 gym-OpenAI 实现 RL 解决方案,您可以通过在 Jupyter 控制台上运行 pip install gym 来轻松安装它。我要向你提出的问题如下:
您的环境由一个 5x5 矩阵组成,其中每个单元都是您的出租车可以停留的位置。然后,你有 4 个坐标,分别代表上下车地点,分别是(0,0),(0,4),(4,0),(4,3)(为了和 Python 语言的连贯性,第一个索引是 0 而不是 1)。我们将它们称为 R,G,Y,B,并分别用 0,1,2,3 来表示它们的位置。最后,有一名乘客既可以上车,也可以下车,还可以被运送(因此要花时间在出租车上)。具体来说,这个乘客想要到达 b 点。
现在,如果我们导入我们的健身房模块并初始化出租车环境,我们可以看到它复制了我们到目前为止所说的内容:
import gym
env = gym.make("Taxi-v2").env
env.render()
如您所见,我们的 5x5 空间有 4 个位置,其中蓝色字母代表当前乘客的位置,紫色字母代表下车位置。我们在那个空间中也有我们的出租车/代理,它是黄色的矩形,还有一些墙,用符号“|”表示。
现在有两个因素需要我们注意:国家和行动。
让我们首先检查我们的行动。根据导入的模块,代理可以采取 6 种方式:
- 0:向下(南)
- 1:向上(北)
- 2:向右(东)走
- 3:向左(西)走
- 4:拿起
- 5:下车
第二,我们有多少个州?嗯,至少 25 个:事实上,有一个 5x5 的空间,我们知道驾驶室可以简单地占用这些单元。此外,出租车也可以处于搭载或放下乘客的状态(不管它实际上是否在那里:记住出租车将通过尝试前进),因此我们还有 4 种状态。最后,我们必须计算乘客实际上车、下车的状态(+ 4 个状态,因为乘客可能在的位置是 4 个)或只是被运送的状态(+ 1 个状态)。因此,总共有 5x5x4x5=500 个状态。
我们的代理的每个状态由一个向量值【出租车的行,出租车的列,乘客索引,目的地索引】表示,因此用 0 到 499 之间的值进行编码。也就是说,我们可以像这样复制上一张图片的位置:
state = env.encode(4, 2, 3, 2)
print("State:", state)env.s = state
env.render()
如您所见,已知我们的出租车位于位置(4,2),乘客索引=3,下车位置=2,我们可以推导出编码状态为 454。在接下来的实验中,我们将使用这个起点,但在深入之前,我们需要介绍最后一个要素:奖励系统。
奖励系统是强化学习背后的主要思想:代理人在任何表现良好的时候都会得到奖励,否则就会受到负面奖励的“惩罚”。在这个特定的例子中,一旦创建了 env,就会创建一个嵌入式奖励表 P 。逻辑如下:
- 如果出租车正确接送乘客,奖励+20 分
- 如果出租车非法上落客,将被扣-10 分
- 不包括上述情况的每一步,减 1 分
让我们看看我们的状态 454 是什么样子的:
env.P[454]
首先要注意的是,我们的 P 表的每个条目都是一个字典,其结构为{action: [(probability, nextstate, reward, done)]}
- 动作:范围从 0 到 5
- 概率:在这种情况下,总是为 1
- Nextstate:这是动作完成时出现的状态
- 奖励:与该行为相关的奖励/惩罚
- done:如果为真,说明这一集结束了,否则不是。
让我们试着读一下我们的结果:第一行告诉我们,如果我们往下走(动作 0 =南),我们将保持在相同的位置,因为我们有一个边界,因此奖励是-1,情节没有结束;第二行,对应于 action=north,会把我们的滑行带向位置 354,但是奖励永远是-1,剧集没有结束。所有动作的推理都是一样的。注意,如果动作是上车或下车,由于出租车不在正确的位置(R,Y,G,B ),如在最后两行(对应于动作 4 和 5 ),它收到-10 的惩罚。
现在是时候训练我们的算法了。我们要用的算法叫做 Q-learning。我已经在这篇文章中解释了背后的思想,因此在这里我不再深入探讨。
以下代码解释了该过程:
import random# setting yperparameters
lr = 0.1 #learning rate
gamma = 0.6 #discount factor
epsilon = 0.1 #trade-off between exploration and exploitationfor i in range(1, 1000): #we will see 1000 episodes
state = env.reset() #let's reset our envepochs, penalties, reward, = 0, 0, 0
done = False
while not done:
if random.uniform(0, 1) < epsilon:
action = env.action_space.sample() # explore action space
else:
action = np.argmax(q_table[state]) # exploit learned valuesnext_state, reward, done, info = env.step(action)
old_value = q_table[state, action]
next_max = np.max(q_table[next_state])
new_value = (1 - alpha) * old_value + lr * (reward + gamma * next_max)
q_table[state, action] = new_valueif reward == -10:
penalties += 1state = next_state
epochs += 1
现在,想象一下,你必须决定哪一个动作能最大化你的效用(翻译过来,这导致对位置 3 的乘客的最佳可能方式)。你的答案可能是北,因此行动 1:事实上,这将是到达你的乘客所在位置(4,3)的最快方式。我们的算法会怎么说?
np.argmax(q_table[454]) #argmax function return the position of the
#maximum value among those in the vector examined
1
如您所见, argmax 函数返回位置 1,这对应于动作“北”。因此,对于每一个位置,我们的 q 表会告诉我们哪一个动作可以最大化当前和未来的回报。
强化学习:贝尔曼方程和最优性(下)
#优化 RL
这个故事是上一个故事的延续, 强化学习:马尔可夫决策过程(第一部分) 故事中,我们谈到了如何为给定的环境定义 MDP。我们还谈到了贝尔曼方程,以及如何找到一个国家的价值函数和政策函数。在这个故事中,我们将更深入一步并了解贝尔曼期望方程,我们如何找到给定状态的最优值和最优策略函数,然后我们将定义贝尔曼最优方程。
Google’s Parkour using Reinforcement Learning
让我们快速浏览一下这个故事:
- 贝尔曼期望方程
- 最优策略
- 状态值函数的贝尔曼最优性方程
- 状态-行为价值函数的贝尔曼最优性方程
所以,一如既往地拿起你的咖啡,直到你感到自豪才停下来。🤓
先说,什么是贝尔曼期望方程?
贝尔曼期望方程
快速回顾一下我们在前面的故事中谈到的贝尔曼方程:
Bellman Equation for Value Function (State-Value Function)
从上面的等式可以看出,一个状态的值可以分解为即时奖励(r【t+1】)加上后继状态的值(v【s(t+1)】)加上一个贴现因子( 𝛾 )。这仍然代表贝尔曼期望方程。但是现在我们正在做的是找到一个特定状态服从某种策略( π )的值。这就是贝尔曼方程和贝尔曼期望方程的区别。
数学上,我们可以将贝尔曼期望方程定义为:
Bellman Expectation Equation for Value Function (State-Value Function)
让我们称之为等式 1。上面的等式告诉我们,当我们在遵循某个政策( π ) 时,特定状态的值是由眼前的回报加上后继状态的值决定的。
类似地,我们可以将我们的状态-动作值函数(Q-函数)表达如下:
Bellman Expectation Equation for State-Action Value Function (Q-Function)
让我们称这个为等式 2。从上面的等式中,我们可以看到,一个状态的状态-动作值可以分解为我们在状态( s 执行某个动作并移动到另一个状态(s’)时获得的即时奖励,加上状态(s’)的状态-动作值相对于的贴现值,我们的代理人将从该状态向前采取某个动作( a )。
深入贝尔曼期望方程:
首先,让我们借助备用图来理解状态-值函数的贝尔曼期望方程:
Backup Diagram for State-Value Function
这个备份图描述了处于特定状态的价值。从状态 s 来看,我们有可能采取这两种行动。每个动作都有一个 Q 值(状态-动作值函数)。我们平均 Q 值,它告诉我们在一个特定的状态下有多好。基本上它定义了 V π(s)。【看等式 1】
数学上,我们可以定义如下:
Value of Being in a state
这个等式也告诉我们状态-值函数和状态-动作值函数之间的联系。
现在,让我们看看状态-动作值函数的备份图:
Backup Diagram for State-action Value Function
这张备份图表明,假设我们从采取一些行动(a)开始。因此,由于动作(a ),代理可能被环境吹到这些状态中的任何一个。因此,我们在问这个问题, 采取行动有多好(a)?
我们再次对两种状态的状态值进行平均,加上即时奖励,这告诉我们采取特定的行动(a)有多好。这就定义了我们的 q π(s,a)。
数学上,我们可以这样定义:
Equation defining how good it is to take a particular action a in state s
其中 P 是转移概率。
现在,让我们将这些备份图拼接在一起,以定义状态值函数 V π(s) :
Backup Diagram for State-Value Function
根据上图,如果我们的代理处于某个状态,并且从该状态假设我们的代理可以采取两个动作,由于哪个环境可能将我们的代理带到任何状态。请注意,我们的代理可能从状态 s 采取行动的概率由我们的策略加权,并且在采取该行动后,我们到达任何状态(s’)的概率由环境加权。
现在我们的问题是,在采取一些行动并降落在另一个州(s ')之后,在另一个州(s)并遵循我们的政策( π )有多好?
这与我们之前所做的类似,我们将对后续状态的值(s’)进行平均,并使用我们的策略对一些转移概率(P)进行加权。
数学上,我们可以定义如下:
State-Value function for being in state S in Backup Diagram
现在,让我们对状态-动作值函数 q π(s,a) 做同样的处理:
Backup Diagram for State-Action Value Function
这与我们在状态值函数中所做的非常相似,只是它是相反的,所以这个图基本上说我们的代理采取一些行动( a ),因为环境可能会将我们带到任何状态( s ),然后从那个状态我们可以选择采取任何行动(a’),用我们策略的概率( π )加权。同样,我们将它们平均在一起,这让我们知道始终遵循特定策略( π )采取特定行动有多好。
数学上,这可以表示为:
State-Action Value Function from the Backup Diagram
所以,这就是我们如何为一个给定的 MDP 制定贝尔曼期望方程,找到它的状态-价值函数和状态-行为价值函数。 但是,它并没有告诉我们 MDP 的最佳行为方式 。为此,让我们来谈谈什么是最优值和最优政策函数 T21。
最优值函数
定义最佳状态值函数
在 MDP 环境中,根据不同的政策,有许多不同的价值函数。 最佳价值函数是与所有其他价值函数 相比产生最大值的函数。当我们说我们正在求解一个 MDP 时,实际上意味着我们正在寻找最优值函数。
因此,数学上最优的状态值函数可以表示为:
Optimal State-Value Function
上式中,v∫(s)告诉我们,我们能从系统中得到的最大回报是什么。
定义最佳状态-动作值函数(Q-Function)
类似地,最优状态-行动价值函数告诉我们,如果我们处于状态 s 并从那里开始采取行动 a,我们将获得的最大回报。
数学上,它可以定义为:
Optimal State-Action Value Function
最优状态值函数:所有策略的最大值函数。
最优状态-动作值函数:是所有策略的最大动作值函数。
现在,让我们看看,什么是最优政策?
最优策略
在我们定义最优策略之前,让我们先了解一下, 一种策略比另一种策略更好是什么意思?
我们知道,对于任何一个 MDP 来说,都有一个政策(【π】)比其他任何政策(【π】)都要好。但是怎么做呢?
如果针对所有状态的策略 π 的价值函数大于针对所有状态的策略π’的价值函数,则我们说一个策略( π) 优于其他策略(π’)。直观上,它可以表示为:
现在,让我们定义 最优策略:
最优策略是产生最优价值函数的策略。
请注意,在一个 MDP 中可以有多个最优策略。但是, 所有的最优政策都实现相同的最优价值函数和最优状态-行动价值函数(Q-function) 。
现在,问题来了,我们如何找到最佳政策。
寻找最佳策略:
我们通过最大化超过 q *** (s,a)即我们的最优状态-行为价值函数来找到最优策略。我们求解 q(s,a),然后选择给出最佳状态-动作值函数(q(s,a))的动作。
上面的陈述可以表达为:
Finding Optimal Policy
这里说的是,对于状态 s,我们选择概率为 1 的动作 a,如果它给我们最大的 q(s,a)。所以,如果我们知道 q(s,a),我们可以从中得到一个最优策略。
我们用一个例子来理解一下:
Example for Optimal Policy
在这个例子中,红色弧线是最优策略,这意味着如果我们的代理遵循这条路径,它将从这个 MDP 中获得最大的回报。同样,通过查看每个状态的 q* 值,我们可以说我们的代理将采取的行动产生了最大的回报。因此,最优策略总是采取 q值较高的行动(状态-行动值函数)。例如,在值为 8 的状态中,有值为 0 和 8 的 q。我们的代理选择具有更大的 q* 值的那个,即 8。
现在问题来了, 我们怎么求这些 q(s,a)值?*
这就是贝尔曼最优方程发挥作用的地方。
贝尔曼最优方程
最优值函数与贝尔曼最优方程递归相关。
贝尔曼最优方程和贝尔曼期望方程是一样的,但是唯一的区别是,我们不是取我们的代理可以采取的行动的平均值,而是取最大值的行动。
让我们借助备份图来理解这一点:
Backup diagram for State-Value Function
假设我们的代理处于状态 S,从该状态它可以采取两个动作(a)。因此,我们查看每个动作的动作值,并且不同于、贝尔曼期望方程、而不是取平均值,我们的代理采取具有更大 q*值的动作。这给了我们处于状态 s 的价值。
数学上,这可以表示为:
Bellman Optimality Equation for State-value Function
同样,我们来定义状态-作用值函数(Q-Function) 的贝尔曼最优性方程。
让我们看看状态-动作值函数(Q 函数)的备份图:
Backup Diagram for State-Action Value Function
假设,我们的代理人在一些州 s 采取了行动 a。现在,它取决于环境,它可能会把我们吹到这些州中的任何一个(s’)。我们仍然取两个状态的平均值,但是唯一的差异是在贝尔曼最优方程中,我们知道每个状态的最优值。不像在贝尔曼期望方程中,我们只知道状态的值。
数学上,这可以表示为:
Bellman Optimality Equation for State-Action Value Function
让我们再次缝合这些状态值函数的备份图:
Backup Diagram for State-Value Function
假设我们的代理处于状态 s,并从该状态采取了一些行动(a ),其中采取该行动的概率由策略加权。并且由于动作(a),代理可能被吹到概率由环境加权的任何状态(s’)。为了找到状态 S 的值,我们简单地对状态(S’)的最优值进行平均。这给了我们处于状态 s 的价值。
数学上,这可以表示为:
Bellman Optimality Equation for State-Value Function from the Backup Diagram
等式中的最大值是因为我们最大化了代理在上弧中可以采取的行动。这个方程也显示了我们如何把 V*函数和它本身联系起来。
现在,让我们看看状态-动作值函数 q*(s,a)的贝尔曼最优方程:
Backup Diagram for State-Action Value Function
假设,我们的代理处于状态 s ,它采取了一些动作( a )。由于该动作,环境可能会将我们的代理带到任何状态(s’),并且从这些状态我们可以最大化我们的代理将采取的动作,即选择具有最大 q*值的动作。我们回到顶点,这告诉我们动作 a 的值。
数学上,这可以表示为:
Bellman Optimality Equation for State-Action Value Function from the Backup Diagram
让我们看一个例子来更好地理解它:
Example for Bellman Optimality Equation
请看红色箭头,假设我们希望找到值为 6 的 state 的值(红色的),我们可以看到,如果我们的代理选择脸书,我们将获得-1 的奖励,如果我们的代理选择学习,我们将获得-2 的奖励。为了找到红色状态的值,我们将使用状态值函数的贝尔曼最优方程,即,考虑到其他两个状态具有最优值,我们将对两个动作取平均值并最大化(选择给出最大值的一个)。因此,从图中我们可以看到,对于我们的红色州来说,去脸书得到的值是 5,去学习得到的值是 6,然后我们将这两个值最大化,得到的答案是 6。****
现在,我们如何求解大型 MDP 的贝尔曼最优方程。为了做到这一点,我们使用动态编程算法,如策略迭代和值迭代,我们将在下一个故事中介绍,以及其他方法,如 Q-Learning 和 SARSA ,它们用于时间差异学习,我们将在未来的故事中介绍。
太棒了!
恭喜你走到这一步!👍
希望这个故事能增加你对 MDP 的了解。很乐意在 insta gram上与您联系。
谢谢你与我分享你的时间!
如果你喜欢这个,请点击让我知道👏。它帮助我写更多!
关于马尔可夫决策过程的第 1 部分、第 2 部分和第 3 部分:
- 强化学习:马尔可夫决策过程(第一部分)
- 强化学习:贝尔曼方程和最优性(下)
- 强化学习:使用动态规划解决马尔可夫决策过程(第三部分)
- 强化学习:蒙特卡罗学习
参考资料:
- https://web . Stanford . edu/class/psych 209/Readings/suttonbartoiprlbook 2 nded . pdf
- 使用 Python 进行强化学习
- 大卫·西尔弗的 DeepMind 强化学习课程
待得深
强化学习——基于模型的规划方法
学习环境模型的例子
在以前的文章中,我们已经谈到了基于无模型方法的强化学习方法,这也是 RL 学习的关键优势之一,因为在大多数情况下,学习环境的模型可能是棘手和艰难的。但是,如果我们想学习一个环境模型,或者如果我们已经有了一个环境模型,我们如何利用它来帮助学习过程呢?在这篇文章中,我们将一起探讨以环境为模型的 RL 方法。以下内容的结构如下:
- 从如何建模环境的基本概念开始
- 用我们刚刚学到的理论用 Python 实现一个例子
- 将理论扩展到更一般情况的进一步想法
模拟环境
一个代理从一个状态开始,通过在那个状态采取一个可用的动作,环境给它反馈,相应地代理进入下一个状态并接收奖励(如果有的话)。在这个一般的设定中,环境给了一个代理两个信号,一个是它在设定中的下一个状态,另一个是奖励。因此,当我们说对环境建模时,我们是在对从(state, action)
到(nextState, reward)
的函数映射建模。例如,考虑一个网格世界设定中的情况,一个代理用头撞墙,作为回应,代理呆在原地,获得奖励 0,那么最简单的格式,模型函数会是(state, action)-->(state, 0)
,表示这个特定状态和动作的代理,代理会呆在原地,获得奖励 0。
算法
现在让我们来看看一个环境模型是如何帮助改善 Q-learning 过程的。我们首先介绍一种最简单的算法,叫做 Dyna-Q :
Q-learning 利用模型来备份策略的方式简单而直接。首先,a, b, c, d
步骤与一般 Q-learning 步骤完全相同(如果你不熟悉 Q-learning,请查看我这里的例子)。唯一的区别在于步骤e
和f
,在步骤e
中,基于确定性环境的假设记录环境的模型(对于非确定性和更复杂的环境,可以根据具体情况制定更一般的模型)。步骤 **f**
可以简单概括为应用正在学习的模型并更新 Q 函数 n
乘以,其中n
是预定义的参数。步骤f
中的备份与步骤d
中的备份完全相同,并且您可能认为这是重复代理已经经历过几次的事情,以便强化学习过程。
典型地,如在 Dyna-Q 中,相同的强化学习方法既用于从真实经验中学习,也用于从模拟经验中规划。因此,强化学习方法是学习和规划的“最终共同路径”。
The general Dyna Architecture
上图更直接地显示了 Dyna 方法的一般结构。请注意Policy/value functons
中的两个向上的箭头,在大多数情况下是我们之前讨论过的 Q 函数,其中一个箭头来自direct RL update
到real experience
,在这种情况下,它相当于代理在环境中探索,另一个来自planning update
到simulated experience
,在这种情况下,它重复代理从real experience
学习的模型。因此,在每次采取行动时,通过更新来自实际行动和模型模拟的 Q 函数来加强学习过程。
实施 Dyna Maze
我认为理解算法的最好方法是实现一个实际的例子。我将从强化学习 an introduction 中取例子,用 Python 实现并与一般的没有规划步骤的 Q 学习(模型模拟)进行比较。
游戏设置
Dyna Maze Board
考虑图中插图所示的简单迷宫。在 47 个状态中的每一个状态中都有四个动作,up
、down
、right
和left
,它们将代理确定性地带到相应的邻近状态,除非当移动被障碍物或迷宫的边缘阻挡时,在这种情况下代理保持在它原来的位置。在所有转换中,奖励为零,除了那些进入目标状态的转换,它是+1
。在到达目标状态(G)
后,代理返回到开始状态(S)
以开始新的一集。
该实现的整个结构有两个类,第一个类代表电路板,也是环境,它能够
- 接受一个动作并输出代理的下一个状态(或位置)
- 给予相应的奖励
第二类代表代理,它能够
- 在棋盘上探索
- 跟踪环境的模型
- 一路更新 Q 函数。
董事会实施
第一类的棋盘设置与我们之前谈过的许多棋盘游戏相似,你可以在这里查看完整的实现。我将在这里删除我的解释(您可以查看我以前的文章以查看更多示例),因此,我们将有一个类似于以下内容的板:
Board Implementation
棋盘用一个 numpy 数组表示,其中z
表示块,*
表示代理的当前位置,0
表示空的和可用的位置。
代理实现
初始化
首先,在init
函数中,我们将初始化算法所需的所有参数。
除了那些通用的 Q-learning 设置(learning rate,state_actions,…)之外,(state, action) -> (reward, state)
的一个模型也被初始化为 python 字典,该模型只会随着 agent 在环境中的探索而更新。self.steps
是模型在每一个动作采取中用于更新 Q 函数的次数,self.steps_per_episode
用于记录每一集的步数(在下面的算法比较中我们会把它作为一个关键的度量)。
选择操作
在chooseAction
函数中,代理仍将采取ϵ-greedy 行动,其中它有self.exp_rate
概率采取随机行动,有1 — self.exp_rate
概率采取贪婪行动。
模型学习和策略更新
现在,让我们使用随着代理的探索而学习的模型来了解策略更新的关键点。
这个实现完全遵循我们上面列出的算法。在每一集(玩游戏)中,第一轮 Q 函数更新后,模型也会用self.model[self.state][action]=(reward, nxtState)
更新,之后 Q 函数会重复更新self.steps
的次数。注意,在循环中,state
和action
都是从之前的观察中随机选择的。
尝试不同的步骤
当步数设置为 0 时,Dyna-Q 方法本质上是 Q 学习。我们来对比一下 0、5、50 步的学习过程。
Dyna-Q with different steps
x 轴是集数,y 轴是达到目标的步数。任务是尽可能快地达到目标。从学习曲线中,我们观察到规划代理人(具有模拟模型)的学习曲线比非规划代理人稳定得更快。提到萨顿书中的话:
在没有计划的情况下(n = 0),每一集只向策略添加一个额外的步骤,因此到目前为止只学习了一个步骤(最后一个)。有了计划,在第一集期间也只学习了一个步骤,但是在第二集期间已经开发了一个广泛的策略,在该集结束时将几乎回到开始状态
额外的模型模拟和备份进一步增强了代理的体验,从而导致更快和更稳定的学习过程。(结帐完全实现)
如何概括这个想法?
我们在这里探索的例子肯定有有限的用途,因为状态是离散的,而动作是确定的。但是模拟环境以加速学习过程的想法有着无限的用途。
对于具有非确定性动作的离散状态
可以学习概率模型,而不是我们上面介绍的直接的一对一映射。概率模型应该在学习过程中不断更新,并且在备份阶段,可以用概率分布非确定性地选择(reward, nextState)
。
对于连续状态
Q 函数的更新将略有不同(我将在以后的文章中介绍),关键是学习一个更复杂和通用的环境参数模型。这个过程可以包括一般的监督学习算法,其中当前状态、动作作为输入,下一个状态和奖励作为输出。
在接下来的帖子中,我们将进一步学习改进 Dyna 方法的想法,并讨论模型错误时的情况!
最后,请在这里查看完整的代码。欢迎您投稿,如果您有任何问题或建议,请在下面发表评论!
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/JaeDukSeo/reinforcement-learning-an-introduction
强化学习——基于模型的规划方法扩展
Dyna-Q+和优先级扫描的实现
在上一篇文章中,我们介绍了如何在强化学习环境中建模,以及如何利用该模型加速学习过程。在本文中,我想进一步阐述这个主题,并介绍另外两个算法, Dyna-Q+ 和优先级扫描,这两个算法都基于我们在上一篇文章中学习的 Dyna-Q 方法。(如果你觉得有些游戏设定混乱,请查看我上一篇文章)
在下面的段落中,我们将利用这两种算法来解决两个问题:
- 模型错了怎么办?
- 如何更高效的更新 Q 函数?
模型错了怎么办?
在上一篇文章中,我介绍了一个 Dyna-Maze 的例子,其中的动作是确定性的,代理通过记录它所经历的步骤来学习模型,这是从(currentState, action) -> (nextState, reward)
开始的映射,然后在规划阶段,正在学习的模型被应用n
次以加强学习过程。简而言之,这个过程可以概括为
- 通过经验学习模型
- 充分信任该模型,并应用它来强化价值函数
但是事情并不总是这样,因为环境可能是复杂和动态的。
模型可能是不正确的,因为环境是随机的,并且只有有限数量的样本被观察到,或者因为模型是使用函数近似法学习的,而函数近似法并不完全概括,或者仅仅因为环境已经改变并且其新的行为还没有被观察到。当模型不正确时,规划过程可能会计算出一个次优的策略。
捷径迷宫
考虑一个叫做捷径迷宫的案例,环境是动态变化的。
一个代理从S
出发,目的是尽快到达G
,黑灰色的区域是代理不能通过的区域。左边的图片代表原始设置,我们的代理能够使用 Dyna-Q 方法找到最短的路径,通过棋盘的左侧一直到G
。但是,环境会在某个时间戳发生变化,棋盘最右边的一个快捷方式会打开。在这种设置下,Dyna-Q 代理还能找到最优解吗?
答案是否定的。即使使用ϵ-greedy 方法,代理人总是以一定的概率探索,也不太可能找到从最左边到最右边的最优路径,因为已经学习的 q 函数将总是引导代理人选择左边的路径,并且没有足够强的动机或奖励推动代理人探索其他路径。
Dyna-Q+和实现
如何解决这个问题?其本质是保持代理人能够探索新的状态以适应不断变化的环境,而驱动代理人探索的诀窍是给予奖励。因此,这里我们介绍一下 Dyna-Q+的理论:
代理跟踪每个状态-动作对,记录自从该对在与环境的真实交互中最后一次尝试以来已经过去了多少时间步。经过的时间越长,这一对的动态变化和模型不正确的可能性就越大(我们可以假设)。为了鼓励测试长期未尝试行为的行为,对涉及这些行为的模拟体验给予特殊的“额外奖励”。特别是,如果转换的模型奖励是
r
,并且在τ
时间步中没有尝试转换,那么计划更新被完成,就好像对于一些小的κ
,转换产生了r + κ*sqrt(τ)
的奖励。这鼓励代理继续测试所有可访问的状态转换,甚至找到长的动作序列来执行这样的测试。
总而言之,该算法与 Dyna-Q 完全相同,除了它跟踪一个状态被访问的次数,并奖励长期未被访问的状态(因为这些状态可能会随着时间的推移而改变)。
现在让我们对 Dyna-Q 进行一些修改,并实现 Dyna-Q+(由于基本设置基本相同,下面的代码我将主要关注不同之处)。你也可以在这里查看完整的实现。
初始化
在 init 函数中,添加了两个组件来奖励未访问的状态。self.time
记录每集内的总时间步数(游戏结束后会重置),而self.timeWeight
本质上是奖励函数中的κ
,表示我们希望代理探索的程度。除了这些通用设置之外,环境模型再次被初始化,但这次是(currentState, action) -> (reward, nxtState, timestep)
的映射。
模型更新
为了使代码更有条理,定义了一个更新模型函数:
该函数在每个时间步更新模型。需要注意的是我们希望在计划阶段考虑从未尝试过的行动,我们将这些行动定义为将代理带回到原始状态,奖励为 0 ,因此您可以看到,对于从未发生的行动,模型为:
self.model[state][a] = (0, state, 1)
奖励设置为 0,状态设置为相同,时间步长设置为 1(因此未访问该状态的次数可能很高)。此外,对于在该状态下发生动作,将用当前时间步长进行标记。
播放功能
播放函数遵循与 Dyna-Q 方法相同的结构:
在每一步之后,我们通过调用self.updateModel()
函数来更新模型,存储在模型中的时间步长在下面的循环中使用,以添加到奖励中:
_reward += self.timeWeight * np.sqrt(self.time - _time)
除了在一个州采取特定行动的原始奖励之外,还分配了额外的奖励。self.time - _time
本质上是未被访问的次数。
Dyna-Q 和 Dyna-Q+比较
通过对非探索状态给予额外奖励,Dyna-Q+更容易察觉到环境的变化,而 Dyna-Q 几乎做不到。
From Reinforcement Learning an Introduction
参考 Sutton 书中的结果,当环境在时间步长 3000 发生变化时,Dyna-Q+方法能够逐渐感知这些变化,并最终找到最优解,而 Dyna-Q 总是遵循它之前发现的相同路径。事实上,由于规划步骤加强了 Dyna-Q 中的经验,规划步骤越多,Dyna-Q 代理找到最佳路径的可能性就越小,相反,Dyna-Q+中的规划步骤增加了未充分探索的状态和动作的值,从而使代理更有可能探索和找到最佳路径。
优先级扫描(更新更高效)
我们现在已经了解了动态环境下形成强化学习的基础知识。你可能注意到了在计划阶段,实际上有很多无效更新,尤其是在所有状态和动作的 Q 函数都为 0,沿途奖励也为 0 的开始阶段。在这些场景中,暂时的差异,
R + Q(S', A') - Q(S, A)
等于 0,因而 Q 函数更新了许多状态,动作仍为 0。那么问题来了:我们能够更高效地更新吗?
这里我将介绍一种叫做优先级扫描的方法,重点是在规划阶段更新非零值。直觉是,由于许多更新是 0,我们是否能够只更新高于某个阈值的值,从而使学习更快?
根据更新的紧急程度确定更新的优先级,并按照优先级顺序执行更新是很自然的。这就是优先清扫背后的想法。维护每个状态-动作对的队列,这些状态-动作对的估计值如果被更新将会发生非平凡的变化,并根据变化的大小区分优先级。
Priority Sweeping
有几点你需要注意:
- 模型是
(currentState, action) -> (reward, nxtState)
的映射 - 只有大于
θ
的时间差值将被包括在队列中 - 在计划阶段,所有导致所选状态的状态也将被更新
在非平凡更新状态之后,所有在先状态需要被更新的原因是因为当前状态更新值是非平凡的,向后更新将绝对导致非零更新。 (考虑我们在值迭代中谈到的例子,当目标达到时,我们进行向后更新,在此过程中更新的所有状态值都是非零和有用的)
算法实现
是时候着手实现了,您可以在这里查看完整的实现。
初始化
在init
函数中,我们初始化了一个阈值θ
,一个根据优先级存储状态和动作对的优先级队列,以及一个前趋字典,以便更新所有导致当前更新状态的状态。
播放功能
主要区别在于播放功能:
在每一步,不是直接更新当前状态动作对的 Q 值,而是记录一个tmp_diff
,如果该值足够大,则将其插入优先级队列。然后,模型和前任都被更新,注意前任字典是一个nxtState -> List((currentState, action), ...)
的映射,因为许多状态和动作可能导致相同的状态。
在计划阶段(在for
循环中),最高优先级状态,动作对被检索(self.queue.get(1)
,并且导致该状态的所有状态(在pre_state_action_list
内)被更新。
Dyna-Q 和优先级扫描比较
如上所述,优先级扫描会在整个过程中更新重要的值,因此效率更高,速度更快。
From Reinforcement Learning an Introduction
参考 Sutton 书中的情节,priority 比 Dyna-Q 更快地找到最优解。
上面介绍的算法是针对确定性环境,针对非确定性环境,正如萨顿所说:
将优先扫描扩展到随机环境是简单的。通过记录每个状态-动作对已经经历的次数以及下一个状态是什么来维护该模型。然后,很自然地,不是像我们到目前为止一直使用的那样用样本更新来更新每一对,而是用预期更新来更新,考虑所有可能的下一状态及其发生的概率。
结论
在这篇文章中,我们学习了两个算法,要点是:
- Dyna-Q+是为不断变化的环境而设计的,它对未充分利用的状态、动作对给予奖励,以驱动代理进行探索
- 优先级扫描能够通过用非平凡更新来更新和传播值来加速学习过程
最后,请查看我的 Github。欢迎您投稿,如果您有任何问题或建议,请在下面发表评论!
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/JaeDukSeo/reinforcement-learning-an-introduction
强化学习——多臂土匪实现
ϵ-greedy 与加州大学的比较
多臂强盗是一个经典的强化学习问题,其中一个玩家面对k
吃角子老丨虎丨机或强盗,每一个都有不同的奖励分配,并且玩家试图在试验的基础上最大化他的累积奖励。
制定
让我们直接切入这个问题。强化学习问题有 3 个关键组成部分——状态、动作和奖励。让我们回忆一下这个问题——k 台机器放在你面前,在每一集里,你选择一台机器并拉动手柄,通过这个动作,你会得到相应的奖励。因此,状态是所有机器的当前估计值,开始时为零,动作是您决定在每集选择的机器,奖励是您拉下手柄后的结果或支出。有了这三项,我们就可以编写Bandit
的init
功能了(这里查看代码):
k
是我们希望初始化的盗匪数量,actions
用数字表示,每个数字代表我们要搭载的机器,我们和往常一样有exp_rate
(探索率)和lr
(学习率)来控制探索和价值更新。total_reward
和avg_reward
用于衡量我们的结果。每台机器的赔付额是由正态分布生成的随机值,最终的初始估值被设置为 0。
行动
选择行动
要找出报酬最高的机器,最直接的方法是尝试,尽可能多地尝试,直到对每台机器都有一定的信心,并从现在开始坚持使用最好的机器。问题是,我们可能可以用更明智的方式进行测试。由于我们的目标是沿途获得最大的回报,我们当然不应该浪费太多时间在一台总是给予低回报的机器上,另一方面,即使我们偶然发现了某台机器的诱人回报,我们仍然应该能够探索其他机器,希望一些没有被探索过的机器能够给我们更高的回报。
因此,在选择行动时,我们将探索方法:
- ϵ-greedy
- UCB(置信上限)
我们已经多次谈到ϵ-greedy,在那里我们以ϵ概率采取随机行动,以 1 - ϵ概率采取最大行动。这在探索和开发之间取得了良好的平衡。让我们谈一谈基于以下公式的 UCB:
UCB
其中 *lnt*
表示 *t*
的自然对数(为了等于 *t*
而不得不将 *e = 2.71828*
的数字),而 *Nt(a)*
表示动作 a 在时间 *t*
之前被选择的次数(公式中的分母,数字 *c > 0*
控制探索的程度)。如果 *Nt(a)=0*
,那么 *a*
被认为是一个最大化动作。(摘自 强化学习:入门 )
所以随着试验次数的增加,如果一个强盗还没有被探索,它的Nt(a)
将会变小,因此公式的右边将会变大。这样,该公式有助于平衡当前估计值Q
和勘探速度。
为了实现 UCB,我们需要在init
函数中添加一些变量:
self.times
计算试验的总次数,而self.action_times
计算每个土匪的行动次数。
现在我们可以将ϵ-greedy 和 UCB 放入我们的方法chooseAction
函数中:
当self.ucb
打开时,我们将根据公式选择动作。如果值除以 0,则self.action_times
增加 0.1。如果exp_rate
if 设置为 0 并且self.ucb
为真,动作将完全由 UCB 选择,但是如果exp_rate > 0
,那么我们将有一个混合ϵ-greedy 和 UCB 的混合方法。
采取行动和更新估计
takeAction
函数接收一个动作,并在收到奖励后更新该动作的估计值。
正如问题所描述的,每个强盗的支付符合一定的分布,因此我们给每个真实的奖励增加了一些随机性。在收到奖励后,将通过添加当前观察和先前估计之间的差乘以学习速率来更新估计。
玩
最后,我们需要一个函数来开始播放。
结果
我们初始化了一个 5 臂 bandit,并比较了不同方法的平均增益。(点击查看代码)
这是使用不同探索率的ϵ-greedy 方法超过 2000 次迭代的平均回报。当勘探率收敛时,0.1 的勘探率超过 0.3 的勘探率。
我们加入不同c
值的 UCB 方法进行比较。两种 UCB 方法的勘探率都是 0.1。从结果中,我们看到,一般来说,UCB 优于ϵ-greedy,但除了 bandit 之外,在许多其他问题上也很难应用 UCB。
请在这里查看完整的代码,欢迎您贡献和提出问题!
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/JaeDukSeo/reinforcement-learning-an-introduction
强化学习——策略函数逼近的推广
将 Q 函数应用于连续状态空间
在以前的帖子中,我们已经将强化学习的思想从离散状态空间扩展到连续状态空间,并且实现了 1000 个状态的随机行走示例,在这种情况下,给定了一个策略,因为在所有状态下向左或向右的动作总是具有相等的概率,并且唯一的问题是基于给定的策略来测量每个状态的值函数(我们将这类问题称为预测问题)。
在本文中,让我们将这个想法扩展到更一般的情况,称为控制问题,其中没有给定策略,我们的目标是使用 Q 函数来学习每个状态下的最佳行动。在这篇文章中,我将:
- 介绍连续状态空间设置的策略算法
- 实现并应用该算法解决经典的山地汽车问题
(注:我们将应用 tile 编码作为近似函数,如果您不熟悉,请参考我上一篇帖子)
控制问题
与行为分布已知的预测问题不同,在控制问题中,代理的任务是探索环境并学习每个状态下的最佳行为,因此,当公式化问题时,考虑的是Q(s, a)
函数而不是价值函数V(s)
。
半梯度 Sarsa
另一方面,像预测问题一样,参数值函数的算法可以自然地扩展到参数 Q 函数,只需用 Q 函数替换值函数。让我们直接进入我们要应用的算法:
如果你一直关注我以前的帖子,你会再次看到这个算法非常熟悉。类似于离散状态空间中的 n 步 Sarsa,这种半梯度 n 步 Sarsa 与完全相同,只是在每个时间步,参数w
被更新,而不是直接更新 Q 函数。其思想是在每次更新时间 τ
时,使用到 τ+n
的累积值来校正当前估计,并根据梯度下降的思想,将参数权重 w
与其导数和增量成比例地稍微向实际值更新。
山地车问题
如果你仍然有一些困惑,那完全没问题。我相信理解一个算法的每个细节的最好方法是实现它,并把它应用到一个实际问题上。我们来做一个经典的强化学习问题,山地车。
山地汽车场景
Mountain Car
考虑驾驶一辆动力不足的汽车在陡峭的山路上行驶的任务,如图所示。困难在于重力比汽车的发动机更强,即使在全油门的情况下,汽车也无法加速上陡坡。唯一的解决办法是先离开目标,然后爬上左边的反坡。
这个问题中的奖励在所有时间步长上都是-1,直到汽车在山顶移动经过它的目标位置,这就结束了这一集。有三种可能的操作:全油门向前(+1)、全油门向后(-1)和零油门(0)。汽车根据简化的物理学原理行驶。其位置、 *x_t*
和速度、 *x_ ̇t*
由更新
Update Rule
此处绑定操作强制执行 *-1.2 <= x_t+1 <= 0.5*
和 *-0.07 <= x_ ̇t+1 <= 0.07*
。另外,当 *x_t+1*
到达左界时, *x_ ̇t+1*
被复位为零。到了右边界,目标达到,插曲终止。每集从 *[-0.6, -0.4)*
中的任意位置 *x_t*
和零速度开始。(抱歉无格式的语法编辑,我不知道如何在媒体上编辑数学语法)
简单来说,汽车以 0 速度从-0.6 到 0.4 之间的位置出发,有 3 个离散动作,停留(0),前进(1),后退(-1),目标是到达最右边的山顶。所以这个问题中的状态包括 (position, velocity)
,动作集合为 (-1, 0, 1)
,奖励为 -1
除了目标状态(注意状态是连续的,动作是离散的)。
价值函数
了解了问题设置,我们现在需要一个 Q 值函数来跟踪所有状态的值,并在探索过程中更新值估计。记得在上一篇文章中,我们已经讲述了使用 tile 编码对连续状态空间进行编码并将其应用于更新过程的基础知识。在本帖中,我们将继续在我们的值函数中使用平铺编码,但代码略有不同:
这里使用的图块编码功能是指这里的和。我没有使用上一篇文章中介绍的 tile 编码的原因是,我介绍的那个有点基本,具有均匀分布的偏移,我亲自测试的结果不如这个,而且这似乎是 Sutton 在他的书中介绍的 tile 编码函数。
不管怎样,让我们回到正题。这里的想法是完全相同的,每个连续的状态都被编码到一些图块的索引中,在每集的每一步,其对应图块的权重都被更新。
让我们仔细看看这个函数。numberOfTilings = 8
和maxSize = 2048
,意味着我们设置了 8 个 tilings,每个 tilings 有16*16
个网格数,所以16*16*8 = 2048
。更具体地说,(position, velocity)
的状态由一个维度为16*16*8
的 3D 立方体表示,而tiles
函数,从我提到的文件中,能够获得给定状态和动作的活动瓦片。您可能已经注意到,在init
函数中,状态被重新调整为:
# position and velocity needs scaling to satisfy the tile software
self.positionScale = self.numOfTilings / (POSITION_BOUND[1] - POSITION_BOUND[0])self.velocityScale = self.numOfTilings / (VELOCITY_BOUND[1] - VELOCITY_BOUND[0])
老实说,我不知道它为什么以这种方式缩放,但看起来像是使用这种平铺编码功能,状态的连续值总是要被重新缩放。
像所有 Q 值函数一样,它至少有两个函数:
value
功能:返回当前状态的值,以及动作。当代理达到目标状态时,返回 0。update
功能:根据新的估计值更新权重(记住在 tile 编码中,权重参数的导数总是 1,因此更新是直接加上delta
值)。
costToGo
函数用于后面步骤的可视化,它简单地返回该状态和动作的最大负值(因为奖励总是-1,所以结果被赋予一个-
符号)。
山地汽车实施
到目前为止,我们实际上已经完成了最棘手的部分,剩下的是我们一直在重复做的事情。(全面实施)
初始化
像往常一样,在init
函数中,我们指定了动作和状态范围,以及所有强化学习问题中的一些通用元素。
动作功能
takeAction
采取行动并决定汽车的下一个状态。更新规则遵循我在上面介绍的公式。chooseAction
函数仍然使用ϵ-greedy 方法,在贪婪部分,它选择由我们上面描述的valueFunc
给出的最大估计值的动作结果。
报酬
除了目标状态获得奖励0
,其他所有状态都获得奖励-1
。
发动汽车!
这是所有函数中最长的一个,但不用担心,事实上,一切都和它在离散设置中一样(我实际上是从我以前的代码中复制粘贴的),除了值函数被改为我们刚才介绍的函数。目标G
是累积的 n 步值,包括第tau+n
步的值,在更新过程中state, action and G
一起发送给valueFunction.update()
函数。
(英)可视化(= visualization)
在本节中,我们将使用在ValueFunction
中定义的costToGo
函数来衡量在给定状态和行动的情况下达到目标的成本。图的代码如下所示:
让我们看看步骤 100 和步骤 9000 的结果:
Step 100
Step 9000
成本越低,越接近目标状态。事实上,较低的成本要么出现在最左边的位置,要么出现在最右边的位置,这验证了只有到达目标的相反方向,智能体才能到达最终的目标状态。
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/Shang tong Zhang/reinforcement-learning-an-introduction
强化学习——策略近似
政策梯度法的理论与应用
到目前为止,所有引入的算法都是基于值函数或 Q 函数的梯度算法,也就是说,我们假设对于不同的状态S(or [S, A])
存在真实值V(or Q)
,并且为了接近真实值,我们使用公式中带有∇V or ∇Q
的梯度方法,并且在学习过程的最后,通过基于V or Q
函数估计在每个状态选择最有回报的动作来生成策略π(A | S)
。然而,策略梯度方法对强化学习问题提出了完全不同的观点,人们可以直接学习或更新策略,而不是学习一个值函数。所以在本帖中,我们将:
- 学习政策梯度法的理论
- 将其应用于短走廊示例
政策梯度理论
记得在以前的帖子中,学习过程中使用的策略总是ϵ-greedy,这意味着代理将在某个概率下采取随机行动,在其余概率下采取贪婪行动。然而,在梯度策略方法中,问题被公式化为,P(A|S, θ) = π(A|S, θ)
,也就是说,对于每个状态,策略给出了从该状态可能采取的每个动作的概率,并且为了优化策略,它被参数化为θ
(类似于我们之前介绍的价值函数中的权重参数w
)。
另一件值得一提的事情是,在这种情况下,性能变量被定义为:
*J(θ)*
是当前参数化策略*π*
、下*V*
的真值,目标是最大化性能 *J*
,因此我们得到一个梯度更新过程:
并且由于*J*
是策略π
的一个表示,我们知道θ
的更新会包含当前的策略,经过一系列的推导(详情请参考 Sutton 的书,第 13 章),我们得到更新过程:
我们的第一个政策梯度方法是:
G
仍为累计折扣奖励,参数θ
将更新为当前保单的衍生产品。
策略近似的优势
首先,策略梯度方法的明显优点是,与值函数近似法相比,该方法简化了过程,在值函数近似法中,我们首先学习一个值函数V(S, A)
,并从中推断出策略π(A|S)
,在策略近似法中,在每次迭代中,通过更新π(A|S, θ)
中的参数θ
来直接更新策略。
其次,在价值函数更新过程中,我们通常使用ϵ-greedy 方法,这样代理人总是有一个ϵ采取随机行动的概率。然而,策略梯度方法能够通过将某些动作的概率更新为零来逼近确定性策略。
第三,如果你还记得,在以前的文章中,我们总是要求动作空间是离散的,因为一般的价值函数逼近方法在处理具有严格连续空间的动作时有点棘手。但是在策略近似定义中,动作实际上可以相对于状态是连续的,例如,可以将策略定义为:
在这种情况下,动作a
将具有正态分布的概率,μ和σ由状态s
定义。
最后但同样重要的是,在最优策略是非确定性的情况下,它允许选择具有任意概率的动作,并且总是选择具有最优概率的动作。
短走廊示例
现在让我们举一个例子来应用我们的知识。
问题描述
考虑下图中插图所示的小走廊网格世界。奖励是-1 每一步,像往常一样。在三种非终结状态的每一种状态下,都只有两个动作,右和左。这些动作在第一和第三种状态下有它们通常的结果(在第一种状态下左不动),但是在第二种状态下它们是相反的,所以右向左移动,左向右移动。这个问题很难,因为在函数近似下,所有的状态都是相同的。特别是,我们为所有的s
定义了x(s, right) = [1, 0])
和x(s, left) = [0, 1])
。
在这种情况下,状态、动作表示使用最简单的格式,并将所有状态视为相同(二进制表示与图块编码中的表示相同)。
下面列出了算法和组件:
因此,在这里,使用 softmax 函数(也可以应用其他函数)定义策略π(a|s, θ)
,该函数生成 0 到 1 之间的概率,并且组件h
被定义为具有参数θ
的简单线性函数。
现在让我们开始实现。
初始化
在init
函数中,我们有上面讲过的self.x
和self.theta
的定义,其初始权重为self.x
,起始状态为 0。
行动
函数softmax
接受一个向量,并返回向量中每个分量的概率。动作由softmax
生成的概率选择,takeAction
函数接受一个动作并返回下一个状态(注意第二个状态是相反的)。
报酬
如问题所述,除了最终状态,所有状态的奖励都是-1。
运行游戏!
在每一集里,代理都要经历一个过程current_state -> take_action -> next_state -> get_reward
。当它到达状态(3)的终点时,我们计算累计奖励G
。梯度grad
是为该步骤中采取的特定动作计算的(j
是该动作的索引)。reward_sum
只记录每集的奖励,用于显示目的。
让我们用alpha = 2e-4
和gamma = 1
运行游戏 1000 集,得到结果:
从增加回合中的概率来看,我们看到 agent 在逐渐更新策略,实际上在这个博弈设定中,最优策略是概率[0.4, 0.6]
,我们的学习结果正在接近最优值(完全实现)。
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/Shang tong Zhang/reinforcement-learning-an-introduction
强化学习—解决 21 点
用 Q-learning 实现 21 点
我们已经讨论了如何使用蒙特卡罗方法来评估强化学习中的策略在这里,我们以 21 点为例,设定了一个固定的策略,通过重复采样,我们能够获得策略和状态的无偏估计,以及沿途的值对。下一个直接的想法是,我们能否通过使用价值迭代来解决 21 点问题,我们在前面的文章中已经介绍过了。
答案听起来是肯定的,因为我们可以清楚地定义 21 点的三个主要组成部分(state, action, reward
,并且我们也知道对手的策略,这也将被视为环境的一部分,所以这个过程将类似于我们在井字游戏实现中讨论过的,我们站在 1 个玩家的立场上,对手的相应动作将被视为环境的反馈(这样我们就不需要对手的任何模型,这是强化学习的优势之一)。
二十一点规则
简单回顾一下21 点规则和庄家采取的一般策略:
游戏从发给庄家和玩家的两张牌开始。庄家的一张牌面朝上,另一张面朝下。如果玩家立即有 21(一张 a 和一张 10 的牌),这叫自然牌。然后他赢了,除非庄家也有一个自然牌,在这种情况下,游戏是平局。如果玩家没有自然牌,那么他可以一张接一张地要求额外的牌(命中),直到他停止(坚持)或超过 21(破产)。如果他破产了,他就输了;如果他坚持,那么就轮到庄家了。庄家根据固定的策略不加选择地打或坚持:他坚持任何 17 或更大的和,否则就打。 如果庄家破产,那么玩家获胜;否则,结果——赢、输或平——取决于谁的最终总和更接近 21。如果玩家拿着一张可以算作 11 而不会破产的王牌,那么这张王牌就可以用了。
履行
先明确一下状态,动作,奖励。游戏的状态是决定和影响胜算的因素。首先,最重要的是卡的金额,目前手头的价值。其次,还有两个因素有助于赢得游戏,这是我们在上面的规则介绍中描述的,是可用的 ace 和庄家的扑克牌。因此状态将有 3 个组成部分:玩家当前的牌总数、可用的 ace 和庄家的出牌。动作清晰,因为在 21 点中一个人只能有 2 个动作,要么击中,要么站立。奖励将基于游戏的结果,赢了给 1,平了给 0,输了给-1。
由于我已经谈到了 21 点上的 MC 方法,在下面的部分中,我将介绍两者实现的主要差异,并尝试使代码更加简洁。(全码)
初始化
在 init 函数中,我们定义了将在下面的函数中频繁使用或更新的全局值。与我们的玩家遵循固定策略的 MC 实现相反,这里我们控制的玩家不使用固定策略,因此我们需要更多组件来更新其 Q 值估计。
在这个init
函数中定义的组件通常用于强化学习问题的大多数情况。与 MC 方法中的init
函数相比,增加的部分包括self.player_Q_Values
,它是(state, action)
的初始化估计,每集之后会更新,self.lr
,它用于控制更新速度,以及self.exp
,它用于采取行动。
交易卡和经销商政策
giveCard
和dealerPolicy
功能完全相同。因为我们的对手,庄家,在这场游戏中仍然持有相同的策略,我们正在探索一种可以与庄家的策略一样有竞争力甚至更好的策略。
行动选择
这一次我们的玩家不再遵循固定的政策,所以它需要考虑在平衡探索和开发方面采取什么行动。
我们的玩家有两个动作要做,其中 0 代表站立,1 代表击中。当当前牌的和等于或小于 11 时,一个人将总是击中,因为击中另一张牌没有害处。当牌的总数超过 11 时,我们的玩家将采取ϵ-greedy 策略,其中exp_rate
百分比的时间,它采取随机行动,否则采取贪婪行动,这是基于 q 值的当前估计获得最多奖励的行动。
判断下一个状态
通过采取一个动作,我们的玩家从当前状态移动到下一个状态,因此playerNxtState
函数将采取一个动作并输出下一个状态,并判断是否游戏结束。
为了进入下一个状态,函数需要知道当前的状态。它在开始时通过将当前状态分配给固定变量来实现这一点。下面的逻辑是如果我们的动作是 1,代表 HIT,我们的玩家再抽一张牌,根据抽的牌是不是 ace,相应的加上当前的牌和。另一方面,如果动作是 STAND,游戏马上结束,返回当前状态。值得注意的是,在函数的最后我们增加了另一个部分,根据玩家手上是否有可用的 ace 来判断游戏是否结束。
给予奖励并更新 Q 值
像所有的强化学习更新一样,在游戏结束时(这被认为是一集),我们的玩家会收到基于自己和庄家的牌值的奖励,并将该值向后传播以更新对(state, action)
的估计。
Q-value update
这两个功能可以合并成一个,我把它们分开是为了在结构上更清晰。winner
函数判断游戏的获胜者并相应返回奖励,_giveCredit
函数根据上面的公式更新奖励,这与我们在网格世界 Q-learning 中介绍的完全相同,Q 值以相反的方式更新,而最后更新的值将用于更新当前的 Q 值。
培养
在培训阶段,我们将模拟许多游戏,让我们的玩家与庄家对打,以更新 Q 值。
与 21 点的 MC 方法不同,在开始时我增加了一个功能deal2cards
,它只是简单地向玩家连续发 2 张牌。原因是遵循规则如果任一玩家用前 2 张牌得到 21 分,游戏直接结束,而不是继续等待下一个玩家到达其终点。这避免了这样的情况,一个玩家用前 2 张牌得到 21 分,而另一个玩家也用 2 张以上的牌得到 21 分,但是游戏以平局结束。
玩庄家和结果
有了我们配备了智能的代理,我们就可以让它与庄家对弈了(保存和加载策略功能与 MC 21 点中的相同, *playWithDealer*
功能与训练过程的结构类似,只是将 *exp_rate*
调至 0 )。
用exp_rate=0.2
和lr=0.1
训练了一万回合后,我保存了策略,让它和庄家打一万回合,得到的结果是:
- wining: 4122
- 图纸:1639 年
- 失败:4239
这是一项无法超越经销商的政策。肯定存在比 HIT17 执行得更好的策略(事实上,这是一个公开的秘密),我相信,我们的代理没有学习到最优策略并且执行得同样好的原因是,
- 没有足够的训练
- 探索率和学习率的调整(修正它们可能对这种情况不好)
- 一步 Q 值更新有其自身的局限性
你能做什么?
我强烈建议你在当前实现的基础上进行更多的尝试,这既有趣又有利于加深你对强化学习的理解。你可以试试:
- n 步更新而不是 1 步(我也会在以后的文章中介绍)
- 根据当前保存的策略 (这是一个有趣的想法,值得一试,因为我们知道 AlphaGo 通过与大师对弈而变得强大,但 AlphaGo Zero 通过学习与自己对弈以 100:0 击败了它。你也可以利用这个想法,试着训练一个代理和自己一起玩)
请点击查看的完整代码。欢迎您投稿,如果您有任何问题或建议,请在下面发表评论!
参考
[1]http://incompleteideas.net/book/the-book-2nd.html
强化学习— TD(λ)简介(3)
用 Sarsa(λ)扩展 Q 函数上的 TD(λ)
在上一篇文章中,我们学习了 TD(λ)与合格迹的思想,这是 n 步 TD 方法的组合,并将其应用于随机游走的例子。在这篇文章中,让我们将 lambda 的思想扩展到更一般的用例——不是学习状态值函数,而是学习状态的 Q 函数,动作值。在本文中,我们将:
- 了解 Sarsa(λ)的概念
- 将其应用于山地车实例
萨尔萨(λ)
与我们已经阐述的许多扩展一样,将价值函数V(S)
扩展到 Q 函数Q(S, A)
是非常自然的,因为所有的公式和逻辑都是相同的,当公式化问题时,将只考虑动作。回想一下 TD(λ)这里介绍的,更新过程类似:
唯一不同的是∇V
被∇q
取代,并且合格跟踪将扩展为:
仍在这里的∇V
换成了∇q
。
因此,我们得到 Sarsa(λ)的备份图:
其中每列是 n 步 Sarsa,1-λ
,(1-λ)λ
…是权重。
扩展的算法将是:
注意,这里的算法是专门为二进制特征表示而设计的,即每个状态、动作对将被表示为二进制特征,例如(3.2, 1)
可以被表示为[1, 0, 0, 1]
(更具体地,我们已经广泛地讨论了如何在瓦片编码中将连续状态表示为二进制特征)
乍一看,你可能觉得算法有点复杂,但实际上和TD(λ)
是一样的,我们试着这样理解一下:
首先,我们来关注一下底部。你应该对此很熟悉,因为它看起来几乎与TD(λ)
— δ
相同,这是时间上的差异,权重w
基于δ
和资格跟踪z
进行更新,其中z
跟踪先前的状态。z
提供了两个更新:
- 积累痕迹:
z = z + 1
;那么1
从何而来?这其实是q(S, A)
的衍生!请记住,这里我们使用状态、动作的二进制表示,活动特征的导数是 1。其实也可以写成z = z + ∇q
,代入w
updates 时,跟踪之前的导数。 - 替换轨迹:
z = 1
,仅使用当前导数更新w
。
F(s, a)
在这里你可以把它想成是 tile 编码函数或者任何其他给出状态、动作二进制表示的函数。
这个算法就这么多了。忽略其他部分,将其与我们在之前的讲座中所学的内容联系起来,现在让我们开始实施一个示例。
山地车上的 Sarsa(λ)
我们已经在 n 步 Sarsa 示例中讨论了山地车,这里是,设置是(如果你对下面的实现有任何困惑,我强烈建议你阅读以前的帖子以更好地理解这个过程):
如图所示,考虑驾驶一辆动力不足的汽车爬上陡峭的山路。困难在于重力比汽车的发动机更强,即使在全油门的情况下,汽车也无法加速上陡坡。唯一的解决办法是先离开目标,然后爬上左边的反坡。
这个问题中的奖励在所有时间步长上都是-1,直到汽车在山顶移动经过它的目标位置,这就结束了这一集。有三种可能的操作:全油门向前(+1)、全油门向后(-1)和零油门(0)。汽车根据简化的物理学原理行驶。其位置、、*x_t*
、和速度、、*x_ ̇t*
、,均由更新
其中绑定操作强制执行 *-1.2 <= x_t+1 <= 0.5*
和 *-0.07 <= x_ ̇t+1 <= 0.07*
。另外,当 *x_t+1*
到达左界时, *x_ ̇t+1*
被复位为零。到了右边界,目标达到,插曲终止。每集从 *[-0.6, -0.4)*
中的任意位置 *x_t*
和零速度开始。
下面的过程将与我们在 n 步 Sarsa 中陈述的大部分相同,所以我将主要集中于解释不同之处。
价值函数
在init
函数中,区别在于self.z
的初始化,T7 是合格跟踪向量,在开始时设置为 0。
value
函数返回值给定状态,动作配对。主要的区别是在update
函数中,在更新权重之前,我们首先更新self.z
。
- 在
accumulating
方法中,使用z = γλz + 1
更新活动图块 - 在
replacing
方法中,活动图块更新为:z = 1
costToGo
功能相同。
一般功能
上面的功能与之前的实现相同,所以我将简单介绍一下。reset
函数在代理到达目标或最左侧状态时将代理复位到初始状态;takeAction
函数接收一个动作,并根据预定义的公式返回代理的下一个状态;chooseAction
函数根据ϵ-greedy 策略的当前估计选择操作;并且giveReward
根据代理的状态给予奖励。
玩游戏
最后是play
功能,启动游戏。逻辑简单明了——一个代理从current state
→ takes an action
→ reaches next state
→ receives reward
→ takes next action
…,和target = reward + Q(nextState, nextAction)
开始,它被传递给我们上面定义的值函数来更新资格跟踪z
和权重w
。
结果
整个游戏设置与我们在 n 步 Sarsa 上介绍的完全相同,因此我们比较 Sarsa(λ)和 n 步 Sarsa 之间的学习结果:
Image from Reinforcement Learning an Introduction
我们使用相同数量的镶嵌和其他参数。参考 Sutton 的书,Sarsa(λ)比 n 步 Sarsa 更有竞争力,因为它学习更快以达到目标(更多说明,请参考这里的完整实现)。
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/Shang tong Zhang/reinforcement-learning-an-introduction
强化学习— TD(λ)简介(1)
对随机漫步应用 offline-λ
在本文中,我们将讨论 TD(λ),这是一种通用的强化学习方法,它结合了蒙特卡罗模拟和一步 TD 方法。我们一直在详尽地讨论 TD 方法,如果您还记得,在 TD(n) 方法中,我说过它也是 MC 仿真和 1 步 TD 的统一,但在 TD(n)中,我们必须跟踪沿途的所有轨迹,并根据 n 步前的值更新当前估计,在 TD(λ)中,我们将看到更优雅的统一。
在本文中,我们将:
- 学习 TD(λ)的思想
- 介绍前向视图更新方法—离线—λ返回
- 将该方法应用于随机游走实例
TD(λ)的概念
TD(λ)实际上是 TD(n)方法的扩展,记住在 TD(n)中,我们有如下形式的累积报酬:
直到步骤t+n
的该值估计用于更新步骤t
的值,TD(λ)所做的是平均该值,例如,使用
0.5*Gt:t+2 + 0.5*Gt:t+4
作为目标值。但是它没有使用直接权重,而是使用λ作为参数来控制权重,使其总和为 1:
TD(λ)
我打赌这个图像看起来很熟悉,一个代理从一个状态开始,通过采取一个动作,它到达下一个状态,然后它选择另一个动作,SARSA 过程继续下去。所以第一列实际上是 TD(1)方法,它被赋予了1-λ
的权重,第二列是 TD(2),它的权重是(1-λ)λ
,…,直到最后一个 TD(n)被赋予了λ^(T-t-1)
的权重(T 是一集的长度)。注意,权重随着 n 的增加而衰减,总和为 1。TD(λ)更一般的形式是:
从公式中可以看出,当λ = 1
时,只保留最后一项,这本质上是蒙特卡罗方法,作为状态,动作过程一直进行到最后,当λ = 0
时,该项减少到G_t:t+1
,这是一步 TD 方法,对于0 < λ < 1
,该方法变成了加权 TD(n)混合方法。
离线λ-返回(前视图)
随着目标G_t
的定义,我们现在开始我们的第一个算法定义。概括的更新公式可以定义为:
offline λ-return
更新规则与一般的半梯度法相同,唯一的区别在于上述目标值 I。
参考 Sutton 书中的一幅图像,这种方法也被称为前视学习算法,因为在每个状态下,更新过程都会前视G_t:t+1
、G_t:t+2
、……的值,并基于该值的加权值来更新当前状态。
随机漫步的正向更新
现在让我们来看看随机漫步例子中算法的实现。我们已经在这里学习了随机漫步示例,但是仅供参考,在随机漫步中,一个代理从中间位置开始,在每一步,它都有相等的概率向左或向右移动一步(行动策略是固定的),并且通过仅在左侧或最左侧结束,它可以停止一集。
我们将实现一个 19 态随机游走,尽管状态空间实际上是离散的,我们仍然可以对其应用一般化算法。
价值函数
价值函数简单明了。我们有 19 个状态和 2 个结束状态,所以总共有 21 个状态,每个状态都有一个权重,本质上就是它的值估计。value
函数返回特定状态的值,而learn
函数基于差值delta
更新电流估计,在本例中差值为Gt — v(St, wt)
( alpha
为学习速率)。
一些常规功能
由于这不是我们第一次实现随机漫步,我将列出一些常见的共享函数:
在每个状态下,一个代理人chooseAction
→ takeAction
→ giveReward
并重复直到游戏结束。
播放和更新
同样,主要区别在于播放过程和计算每个状态的增量。
在每一集,我们将需要首先跟踪所有的状态,直到游戏结束,以便在更新每个状态的值时获得一个前瞻性的视图。self.states
记录沿途所有状态,self.reward
只保存最新的奖励,因为沿途所有奖励都是 0,除了最终状态。
第二部分是在游戏结束后更新状态值估计。回想一下公式:
对于在时间t
和步骤n
的每个状态,我们需要计算G_t:t+n
的值,并将它们与衰减的权重相结合,以便得到St
的目标值。因此函数gt2tn
计算给定t
和n
的值,定义为:
而前面代码片段中的gtlambda
就是目标值。此外,我们还设置了一个截尾值,当lambda_power
太小时,我们干脆忽略该值。利用目标值gtlambda
和来自valueFunc
的当前值,我们能够计算差值delta
并使用我们上面定义的函数learn
更新估计值。
离线λ-返回和 TD(n)
记得在 TD(n)会议中,我们用完全相同的设置对随机漫步应用了 n 步 TD 方法。现在随着off-line λ-Return
的介绍,让我们比较一下两者的学习结果:
Image from Reinforcement Learning an Introduction
我们可以看到,两条均方根误差曲线相似,结果具有可比性。一般来说,最好的学习结果通常出现在中等学习速率和λ值的情况下(我从 Sutton 的书中复制了图像,因为这张比我绘制的要清晰得多)。
这就是前视更新,请在这里查看完整的实现。在下一篇文章中,我们将学习向后更新,这是一种通过使用资格跟踪的更优雅的 TD(λ)方法。
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/Shang tong Zhang/reinforcement-learning-an-introduction
强化学习:python 中的时差、SARSA、Q 学习和期望 SARSA
TD、SARSA、Q-Learning &预期的 SARSA 及其 python 实现和比较
如果一个人必须确定一个核心的和新颖的强化学习的想法,它无疑将是时间差异(TD)学习。——安德鲁·巴尔托和理查德·萨顿
先决条件
- 强化学习的基础
- 马尔可夫链,马尔可夫决策过程(MDPs)
- 贝尔曼方程
- 价值、策略功能和迭代
一些心理学
你可以跳过这一部分,这是可选的,不是这篇文章的先决条件。
我喜欢研究人工智能概念,同时将它们与心理学——人类行为和大脑——联系起来。强化学习也不例外。我们感兴趣的话题——时差是由理查德·萨顿创造的一个术语。这篇文章来源于他和安德鲁·巴尔托的书——《T4 强化学习导论》,可以在这里找到。为了理解时间差异的心理学方面,我们需要理解著名的实验——巴甫洛夫实验或经典条件反射。
伊凡·巴甫洛夫用狗做了一系列实验。一组狗接受了外科手术改造,这样它们的唾液可以被测量。这些狗被给予食物(非条件刺激——US ),在食物的反应中观察到唾液的排泄(非条件反应——UR)。这种刺激-反应对是自然的,因此是有条件的。现在,又增加了一个刺激因素。就在端上食物之前,铃响了。铃声是一种条件刺激(CS)。因为这个 CS 是在美国之前送给狗的,过了一会儿,人们发现狗听到铃声就开始流口水。这种反应被称为条件反应(CR)。实际上,帕沃洛夫成功地让狗在听到铃声时分泌唾液。情景喜剧《办公室》中展示了一个有趣的实验。
CS 和 US 发作之间的时间间隔称为刺激间隔(ISI ),是巴甫洛夫条件反射的一个非常重要的特征。基于 ISI,整个实验可分为以下类型:
Source: Introduction to Reinforcement learning by Sutton and Barto — Chapter 14
如上面容易理解的图表所示,在延迟条件作用中,CS 出现在我们之前,并且一直沿着我们。这就像铃响之前,一直呈现食物。而在痕迹条件作用中,CS 在 US 出现之前出现并终止。
在一系列实验中,观察到较低的 ISI 值显示更快和更明显的反应(狗流涎),而较长的 ISI 显示较弱的反应。由此,我们可以得出结论,为了加强刺激-反应对,条件刺激和非条件刺激之间的间隔应该更小。这形成了时间差异学习算法的基础。
依赖模型和无模型的强化学习
依赖于模型的 RL 算法(即值和策略迭代)在转换表的帮助下工作。一个转换表可以被认为是一本生活帮的书,它包含了代理在它所存在的世界中成功所需的所有知识。自然,写这样一本书是非常乏味的,并且在大多数情况下是不可能的,这就是为什么模型依赖的学习算法几乎没有实际用途。
时间差分是一种无模型的强化学习算法。这意味着代理通过实际经验学习,而不是通过现成的无所不知的手册(转换表)。这使我们能够引入随机元素和大量的状态-行为对序列。代理对奖励和转换系统一无所知。它不知道在任意状态下采取任意动作会发生什么。代理人必须与“世界”或“环境”互动,并自己找出答案。
时间差异学习
时间差分算法使代理能够通过它采取的每一个动作进行学习。TD 在每个时间步(动作)而不是在每个情节(达到目标或结束状态)更新代理的知识。
目标值称为目标误差。步长通常用表示,α 也称为学习速率。它的值介于 0 和 1 之间。
上面的等式通过在每个时间步长进行更新,帮助我们实现 目标 。目标是一种状态的效用。更高的效用意味着代理转换到更好的状态。为了这篇文章的简洁,我假设读者知道贝尔曼方程。根据它,一个国家的效用是贴现回报的期望值,如下所示:
通俗地说,我们让一个代理人自由地进入一个世界。代理不知道状态、奖励和转换。它与环境相互作用(做出随机或明智的行动),并通过在采取每一个行动后不断更新其现有知识来学习新的估计(状态-行动对的值)。
到目前为止的讨论将产生几个问题,例如——什么是环境?代理将如何与环境交互?代理将如何选择动作,即在特定状态(策略)下代理将采取什么动作?
这就是 SARSA 和 Q-Learning 的用武之地。这是两个控制策略,它们将在一个环境中指导我们的代理,并使它能够学习有趣的东西。但在此之前,我们将讨论什么是环境。
环境
一个环境可以被认为是一个微型世界,在这个世界中,一个主体可以观察离散的状态,采取行动,并通过采取这些行动来观察回报。把电子游戏想象成一个环境,把你自己想象成代理。在游戏《毁灭战士》中,你作为代理人将观察状态(画面)并采取行动(按下前进、后退、跳跃、射击等键)并观察奖励。杀死一个敌人会给你带来快乐(效用)和积极的回报,而向前移动不会给你带来太多的回报,但你仍然想这样做来获得未来的回报(找到并杀死敌人)。创建这样的环境可能是乏味而艰难的(一个 7 人团队工作了一年多才开发出《毁灭战士》】T1。
OpenAI 健身房前来救援!gym 是一个 python 库,它有几个内置环境,您可以在这些环境中测试各种强化学习算法。它已经成为分享、分析和比较结果的学术标准。健身房是非常好的记录和超级容易使用。在继续下一步之前,您必须阅读文档并熟悉它。
对于强化学习的新应用,你必须创造你自己的环境。建议总是参考和编写健身房兼容环境,并公开发布,以便每个人都可以使用它们。阅读健身房的源代码将帮助你做到这一点。这是乏味的,但很有趣!
萨尔萨
SARSA 是SState-Action-Reward-State-Action 的首字母缩写**
SARSA 是一种政策性 TD 控制方法。策略是状态-动作对元组。在 python 中,你可以把它想象成一个字典,以键作为状态,以值作为动作。策略映射了每个状态下要采取的操作。基于策略的控制方法通过遵循特定的策略(通常是它自己评估的策略,就像在策略迭代中一样)在学习期间为每个状态选择动作。我们的目的是估计出 Qπ(s,a) 对于当前策略【π和所有状态-动作【s-a】对。我们通过让代理从一个状态-动作对转换到另一个状态-动作对,使用在每个时间步长应用的 TD 更新规则来实现这一点(不像依赖于模型的 RL 技术,其中代理从一个状态转换到另一个状态)。
Q 值- 你一定已经熟悉了一个状态的效用值,Q 值是一样的,唯一的区别是定义在状态-动作对上,而不仅仅是状态。它是状态-动作对和表示其效用的实数之间的映射。Q-learning 和 SARSA 都是策略控制方法,用于评估所有动作-状态对的最优 Q 值。
SARSA 的更新规则是:
Source: Introduction to Reinforcement learning by Sutton and Barto — 6.7
如果一个状态 s 是终端(目标状态或结束状态)那么, Q(S,a)= 0ɐa∈a其中 A 是所有可能动作的集合
Source: Introduction to Reinforcement learning by Sutton and Barto —Chapter 6
上述算法中的动作A’是通过遵循相同的策略(ε-对 Q 值贪婪)给出的,因为 SARSA 是基于策略的方法。
ε-贪婪政策
ε-贪婪政策是这样的:
- 生成一个随机数r∈【0,1】**
- If r < ε 选择一个从 Q 值导出的动作(产生最大效用)
- 否则选择一个随机动作
在阅读 python 代码后,这一点会变得更加清楚。
请注意:在《萨顿与巴尔托的 RL》这本书里,如果 r > ε,则采取随机动作。 T 他们取了 ε =0.1 而对我来说 ε =0.9。这两个基本上是一回事。
ε的值决定了代理的探索-开采。
如果 ε 很大,则随机数 r 几乎不会大于ε,并且几乎不会采取随机行动(更少的勘探,更多的开采)
如果 ε 较小,则随机数 r 往往会大于ε,这将导致代理选择更多的随机动作。这种随机特性将允许智能体更多地探索环境。
根据经验, ε 通常选择为 0.9,但可以根据环境类型而变化。在某些情况下, ε 会随着时间的推移而退火,以允许更高的勘探程度和更高的开发程度。
下面是在 Taxi-v2 健身房环境中应用的 SARSA 的一个快速简单的 python 实现
q 学习
Q-Learning 是一种非策略 TD 控制策略。它与 SARSA 完全一样,唯一的区别是,它不遵循策略来寻找下一个动作,而是以贪婪的方式选择动作。类似于 SARSA,其目的是评估 Q 值,其更新规则是:**
Source: Introduction to Reinforcement learning by Sutton and Barto — 6.8
注意:与 SARSA 通过遵循某个策略来选择动作 、A’不同,这里的动作A’(在这种情况下为A)是通过简单地取 Q 的最大值来贪婪地选择的。**
这是 Q 学习算法:
Source: Introduction to Reinforcement learning by Sutton and Barto — Chapter 6
下面是 Q-learning 的 python 实现:
预期 SARSA
预期 SARSA,顾名思义,取当前状态下每一个可能动作的 Q 值的期望值(均值)。目标更新规则应使事情更加清楚:
Source: Introduction to Reinforcement learning by Sutton and Barto —6.9
这是 python 的实现:
比较
我已经使用以下参数在 Taxi-v2 健身房环境中测试了三种算法
- 阿尔法= 0.4
- 伽玛= 0.999
- ε= 0.9
- 剧集= 2000
- max_steps = 2500(单集可能的最大时间步数)
以下图表展示了上述三种政策控制方法之间的比较:
收敛:
显然,通过下面的图,Q 学习(绿色)在 SARSA(橙色)和预期的 SARSA(蓝色)之前收敛
SARSA, Q-learning & Expected SARSA — Convergence comparison
性能:
对于我的三个算法的实现,Q-learning 似乎表现最好,而 Expected SARSA 表现最差。
SARSA, Q-learning & Expected SARSA — performance comparison
结论
时间差异学习是最重要的强化学习概念。它的进一步衍生,如 DQN 和双 DQN(我可能会在另一篇文章中讨论它们)已经取得了突破性的成果,在人工智能领域享有盛名。谷歌的 alpha go 使用 DQN 算法和 CNN 打败了围棋世界冠军。你现在已经具备了基本 TD 的理论和实践知识,出去探索吧!
如果我犯了一些错误,请在回复中提及。感谢阅读。
强化学习——瓦片编码实现
分块编码的逐步解释
我们已经走了这么远,并将我们的强化学习理论扩展到连续空间中(连续空间中的一般化)。如果你想更进一步,你需要知道瓦片编码,这可能是在连续空间,强化学习问题中使用的最实用和计算效率最高的工具。本质上,瓦片编码是连续状态空间中的特征表示,在本帖中,你将:
- 学习瓦片编码的思想
- 逐步实现图块编码
- 用 Q 函数整合并应用它
什么是瓷砖编码?
最简单的例子是我们在上一篇文章中学到的状态聚合。回想一下,在 1000 个状态的随机行走示例中,我们将 1000 个状态分成 10 组,每组 100 个状态,这样我们可以用二进制格式表示每个状态,也就是说,对于特定组内的状态,它是 1,否则是 0。其实这就是最简单形式的瓦片编码,只有 1 个状态分量和 1 个平铺(你可以把它想成一个表现层)。
毫无疑问,仅用 1 个分块来表示要素是有缺陷的(您可以将它想象成网格),因此这里出现了多个分块和多维要素:
Tile Coding
图中示出了在 2D 连续状态空间中使用瓦片编码的例子。在图的左边,状态空间由 1 个平铺显示表示,它本质上只是一个 2D 网格。注意灰色区域是特征空间,蓝色线条的 2D 网格是我们的平铺,它覆盖了整个状态空间区域(不一定要紧密贴合在特征空间中)。在这个表示中,白点,也就是我们的状态值,对于它所属的网格可以表示为 1,对于其余的网格可以表示为 0。
在右侧,该表示扩展到多个镶嵌,每个镶嵌具有不同的偏移。在此设置下,白点由 4 个不同的镶嵌表示,这 4 个不同的网格包括每个镶嵌中的白点。
从图中我们可以看到,只有一个切片的切片编码本质上是状态聚合,其中一个要素将只由它所属的切片来表示,而多个切片通过用属于每个切片的多个切片来表示一个要素来扩展这一思想。这种扩展更加强大,因为每个状态值可以共享一些瓦片,同时也属于不同的瓦片,这是一般化的本质。
逐步实施
如果你仍然对这个想法感到困惑,不要担心,在这个环节中,我们将一步一步地实现一个平铺编码。(全面实施)
让我们首先为 1 个要素创建 1 个切片:
我认为这个单行函数解决了您的大部分困惑。例如,给定一个范围为[0, 1]
的特征,该函数将它平均分成10
个箱,最后的格网加上一个0.2
的偏移量。测试结果显示在底部,范围从0.3
到1.1
,一个值的编码将是它所属的 bin 的顺序,例如给定一个特征值0.35
,它在0.3
到0.4
的范围内,它的编码将是1
,同样,小于0.3
的值编码为0
,大于1.1
的值编码为9
。
由于该函数能够为一个要素创建一个切片,让我们将其扩展到多个要素的多个切片:
现在输入feature_ranges
将是多个特征的特征范围列表。bins
是每个图块上设置的面元列表,offset
也是如此。例如,假设我们有 2 个要素,每个要素的范围分别为[-1, 1]
和[2, 5]
,我们想要创建3 tilings
,每个要素都有一个大小为10x10
的 2D 格网和不同的偏移,那么结果切片形状将为(3, 2, 9)
,代表n_tilings x n_features x (n_bins - 1)
(注意,箱数减 1,以确保大于范围的值得到 n _ 箱的编码)。
最好把它想象成一个立方体,正面是特征值的网格,第三维是镶嵌的数量。
现在我们已经准备好了镶嵌,让我们为每个输入特征值进行编码:
对于每个镶嵌和每个特征,这个函数得到它在那个维度上的编码,并最终连接结果。以我们上面设置的镶嵌为例,给出一个特征[0.1, 2.5]
,它的编码在第一个镶嵌(层)上是[5, 1]
,在第二个镶嵌上是[4, 0]
,在最后一个镶嵌上是[3, 0]
(注意这里偏移是如何起作用来区分不同镶嵌上的特征的)。
与 Q 函数集成
准备好平铺编码后,是时候将它用于 Q 值函数了。(点击查看完整实现)
这是将瓦片编码与 Q 函数结合的一般形式。在init
函数中,我们定义了一个self.q_tables
,其中每个q_table
都有一个大小为n_bins x n_bins x n_actions
的n_tilings
q 个表。想法是给定一个状态、动作和目标值,该动作将有助于对每个 q 表中的特定切片进行切片,并且该切片值将相应地更新。
value
函数获取状态、动作并返回其值。瓦片编码的主要优点之一是其计算效率。回想一下随机漫步中的状态聚集示例,给定状态的值就是该状态所属的 bin 的值,类似地,给定状态的值,这里的 action 等于每个平铺中平铺值的总和 ( 返回值被 num_tilings 除的原因是在更新过程中每个平铺都被未除的学习率更新。如果我们设置 self.lr = lr/num_tilings
,那么返回值就不需要除以)。
在update
函数中,由于这里的导数实际上是 1,所以用时间差乘以一个固定的学习率来更新每个图块,并且因为init
函数中的学习率没有除以图块的数量,所以加在一起的更新值近似于n_tilings*lr
,因此需要在value
函数中进一步除。
结论
在这篇文章中,我们一起实现了一个平铺编码,并学习了如何使用它的 Q 函数。与参数函数逼近相比,瓦片编码将连续空间离散化,通过获取活动瓦片的索引并进行一些简单的运算,使得学习过程在计算上更加高效。瓷砖编码是一个强大的工具,我们将在未来的帖子中使用它来解决一些更有趣的例子。
最后,感谢您的跟进,如果您有任何问题,请在下面留下您的评论。
参考:
- http://incompleteideas.net/book/the-book-2nd.html
- https://github . com/uda city/deep-enforcement-learning/tree/master/tile-coding
强化学习教程第 1 部分:Q-学习
这是关于强化学习的系列教程的第一部分。我们将从一些理论开始,然后在下一部分的中继续讨论更实际的东西。在这个系列中,您不仅将学习如何训练您的模型,还将学习使用 Valohai 深度学习管理平台在具有完全版本控制的云中训练它的最佳工作流程。
什么时候使用强化学习?
当你没有关于问题的训练数据或足够具体的专业知识时,强化学习是有用的。
在高层次上,你知道自己想要什么,但不知道如何去实现。毕竟,就连李·塞多尔也不知道如何在围棋中击败自己。
幸运的是,你所需要的只是一个奖励机制,如果你让它“玩”足够长的时间,强化学习模型会找出如何最大化奖励。这类似于教狗用零食坐下。起初,这只狗毫无头绪,在你的命令下尝试随机的事情。在某个时候,它意外地用屁股着地,得到了突然的奖励。随着时间的推移,并给予足够的迭代,它会找出专家的策略,坐在提示。
地牢中的会计师示例
这是强化学习的官僚版本。一个会计发现自己在一个黑暗的地牢里,他所能想到的就是走来走去填写电子表格。
会计知道的:
- 地牢有 5 块瓷砖长
- 可能的操作有向前和向后
- 向前总是一步,除了最后一个瓷砖碰到墙
- 后退总是带你回到起点
- 有时会有风把你的动作吹向相反的方向
- 您将在一些瓷砖上获得奖励
会计不知道的是:
- 进入最后一张牌会给你+10 奖励
- 进入第一个方块给你+2 奖励
- 其他瓷砖没有奖励
会计师,作为一名会计师,将遵循一个安全(但幼稚)的策略:
- 总是根据你的会计选择最有利可图的行动
- 如果会计显示所有选项都为零,请选择一个随机操作
让我们看看会发生什么:
会计师似乎总是喜欢向后走,即使我们知道最优策略可能总是向前走。最好的奖励(+10)毕竟在地下城的尽头。因为有一个随机因素有时会使我们的行动转向相反的方向,会计师实际上有时会不情愿地到达另一端,但根据电子表格仍然犹豫选择向前。这是为什么呢?
很简单,因为他选择了一个非常贪婪的策略。在非常短暂的初始随机性中,会计师可能愿意选择向前一次或两次,但一旦他选择向后一次,他就注定永远选择向后。玩这个地下城需要长期的计划,拒绝较小的直接奖励,以获得更大的奖励。
什么是 Q-learning?
q 学习是所有强化学习的核心。AlphaGO 战胜 Lee Sedol 或 DeepMind 击败老款 Atari 游戏从根本上来说都是在糖的基础上进行的 Q 学习。
Q-learning 的核心是像马尔可夫决策过程(MDP) 和贝尔曼方程这样的东西。虽然详细理解它们可能会有好处,但现在让我们将其简化为一种更简单的形式:
行动的价值=即时价值+所有最佳未来行动的总和
这就像估算一个大学学位相对于退学的经济价值。你需要考虑的不仅仅是你第一份薪水的直接价值,而是你一生中所有未来薪水的总和。一个行动总是导致更多的行动,你选择的道路总是由你的第一个行动决定。
也就是说,仅仅关注行动是不够的。执行的时候需要考虑自己所处的状态。当你 17 岁和 72 岁时进入大学是完全不同的。第一个可能是一个财务上积极的赌注,而后者可能不是。
那么你如何知道哪些未来行动是最优的呢?嗯——你不知道。你要做的是根据你当时掌握的信息做出最佳选择。
想象一下,你可以不止一次,而是一万次地重演你的人生。起初,你会很随意地去做,但是在几千次尝试之后,你会有越来越多的关于产生最佳回报的选择的信息。在 Q-learning 中,“你所拥有的信息”是从你以前的游戏中收集的信息,并编码到一个表格中。
所以从某种意义上说,你就像上一个例子中的会计,总是随身携带一个电子表格。不过,你将会以一种更微妙的方式更新和阅读你的电子表格。你也会把它叫做 Q 表而不是电子表格,因为它听起来更酷,对吗?
Q 学习算法
Q-learning 算法的形式如下:
它看起来有点吓人,但是它做的很简单。我们可以将其概括为:
根据我们得到的奖励和我们下一步期望的奖励,更新行动的价值评估。
这是我们正在做的根本事情。T2 学习率 T3 和 T4 折扣 T5 虽然是必需的,但只是用来调整行为。折扣将决定我们对未来预期行动价值与我们刚刚经历的行动价值的权衡程度。学习率是一个总的油门踏板。开得太快,你会错过最佳时机,开得太慢,你永远也到不了。
但是这个算法是不够的——它只是告诉我们如何更新我们的电子表格,但没有告诉我们如何使用电子表格在地牢中的行为!
地牢里的赌徒的例子
让我们看看我们将如何在一个地牢里用我们的花式 Q 表和一点赌博来行动。我们将选择一些更加细致入微的东西,而不是我们的会计师使用的照章办事的策略
我们的战略:
- 默认情况下,从我们的电子表格中选择最有利可图的行动
- 有时赌博并选择随机行动
- 如果会计显示所有选项都为零,请选择一个随机操作
- 从 100%赌博(探索)开始,慢慢向 0%移动
- 使用折扣= 0.95
- 使用 learning_rate = 0.1
为什么我们需要赌博和随机行动?原因和会计被困住了一样。因为我们的默认策略仍然是贪婪的,也就是说,我们默认选择最有利可图的选项,我们需要引入一些随机性来确保所有可能的
为什么我们需要停止赌博,降低我们的探索率?是因为达成最优策略的最佳方式是先积极探索,然后慢慢走向越来越保守。这个机制是所有机器学习的核心。
说够了。我们的赌徒正在进入地牢!
唷!那是一大堆东西。
注意,为了举例,我们做了很多赌博来证明一个观点。不仅仅是赌博,我们把硬币抛向右边,所以这通常是非常不寻常的前十几步!
与会计师的策略相比,我们可以看到明显的不同。这种策略收敛较慢,但我们可以看到顶行(向前)比底行(向后)得到的估值更高。
还要注意在最初的+10 奖励后,估价开始从右到左“泄漏”到顶行。这是允许 Q 表“预见未来”的基本机制。关于发生在最后一块瓷砖上的奖励丰厚的事情的消息慢慢流向左侧,最终到达我们电子表格的最左侧,这种方式允许我们的代理提前许多步预测好事情。
如果你被上面一步一步运行的信息过载搞糊涂了,就冥想这张图片,因为它是本文中最重要的一张。如果你理解了为什么信息会“泄露”以及为什么它是有益的,那么你就会理解整个算法是如何工作的以及为什么会工作。
就是这样!在的下一部分中,我们将提供一个教程,介绍如何使用 Valohai 深度学习管理平台在云中用代码实现这一点并运行它!
原载于blog.valohai.com。
强化学习教程第 2 部分:云 Q 学习
在第一部分中,我们用一个非常简单的地牢游戏研究了 Q-learning 背后的理论,这个游戏有两个策略:会计和赌徒。第二部分使用 Valohai 深度学习管理平台,将这些例子转化为 Python 代码,并在云中训练它们。
由于我们示例的简单性,我们不会故意使用任何像 TensorFlow 这样的库或像 OpenAI Gym 这样的模拟器。相反,我们将从头开始自己编写代码,以提供完整的画面。
所有的示例代码都可以在 https://github.com/valohai/qlearning-simple 的找到
代码布局
典型的强化学习代码库有三个部分:
- 模拟
- 代理人
- 管弦乐编曲
模拟是代理人操作的环境。它根据其内部规则和代理执行的动作更新状态并分发奖励。
Agent 是在模拟中操作、学习和执行策略的实体。它执行动作,接收带奖励的状态更新,并学习一种策略来最大化它们。
编排是所有剩余的样板代码。解析参数,初始化环境,在模拟和代理之间传递数据,最后关闭商店。
模拟
我们将使用第 1 部分中介绍的地牢游戏。这些是规则:
- 地牢有 5 块瓷砖长
- 可能的操作有向前和向后
- 向前总是一步,除了在最后一个瓷砖碰到墙
- 后退总是带你回到起点
- 有时会有风把你的动作吹向相反的方向
代理未知:
- 进入最后一张牌会给你+10 奖励
- 进入第一个方块给你+2 奖励
- 其他瓷砖没有奖励
代理人
在教程的第一部分,我们介绍了两种策略:会计和赌徒。会计只关心过去的业绩和保证的结果。赌徒更渴望探索风险更高的选项,以在未来获得更大的回报。也就是说,为了保持第一个版本的简单,引入了第三个策略:酒鬼。
酒鬼是我们的基本策略,有一个非常简单的启发:无论如何都要随机行动。
管弦乐编曲
现在我们已经有了模拟和代理,我们需要一些样板代码将它们粘在一起。
地牢模拟是回合制的,所以流程很简单:
- 向代理查询下一个动作,并将其传递给模拟
- 获取新的状态和奖励,并将其传递给代理
- 重复
基础设施
虽然有可能在本地运行这样的简单代码,但目标是提供一个如何正确编排更复杂项目的示例。
机器学习不等于软件开发。仅仅将代码推送到 Git 存储库是不够的。为了完全的再现性,您需要对数据、超参数、执行环境、输出日志和输出数据进行版本控制。
在本地运行也会让你慢下来。虽然玩具示例通常会给人一种快速迭代的错觉,但为真实问题训练真实模型并不适合您的笔记本电脑。毕竟,它一次只能运行一个训练执行,而基于云的环境让你可以同时启动几十个训练执行,同时拥有快速的 GPU、轻松的比较、版本控制和对同事更大的透明度。
瓦罗海设置
前往valohai.com并创建一个账户。默认情况下,您的帐户上有价值 10 美元的信用,足以在云实例上运行以下培训。
注册后,点击跳过教程或者打开右上角的项目下拉菜单,选择创建项目。
给你的项目起一个有意义的名字,然后点击下面的蓝色创建项目按钮。
在 https://github.com/valohai/qlearning-simple的示例 git 存储库中,我们已经有了我们的代码和 valohai.yaml。
我们只需要告诉瓦罗海他们在哪里。点击上面截图中的项目库设置链接或导航到设置>库选项卡。
将存储库 URL 粘贴到 URL 字段,确保获取引用为“主”,然后点击保存。
执行!
一切就绪,现在是我们第一次执行的时候了。
点击 Valohai 项目执行选项卡中的蓝色创建执行按钮。
Git 存储库中的 valohai.yaml 文件为我们提供了所有正确的默认值。如果你想了解更多关于 valohai.yaml 的信息,请查阅文档。
点击底部的蓝色创建执行按钮。
在 Valohai 中运行一个执行意味着大致会发生以下序列:
- 启动一个新的服务器实例
- 您的代码和配置(valohai.yaml)是从 git 存储库中获取的
- 下载训练数据
- 下载并实例化 Docker 映像
- 基于 valohai.yaml +您的参数执行脚本
- 所有标准输出都存储为 log + JSON 格式的元数据,并针对图表进行解析
- 为了以后的可再现性,整个环境是受版本控制的
- 脚本完成后,服务器实例会自动关闭
只需点击一下鼠标,你就能得到如此多的东西,这难道不令人惊奇吗?
如果您前往执行的元数据标签,您可以看到我们的酒鬼策略代理如何收集奖励。毫不奇怪,采取随机行动的策略会产生一条几乎有轻微抖动的直线,这告诉我们没有学习发生。
会计
在运行了基线随机策略之后,是时候带回在教程的第一部分中介绍的两个原始策略了:会计和赌徒。
会计师有以下策略:
- 总是选择基于会计的最有利可图的行动
- 如果所有选项都为零,则选择一个随机操作
要执行会计,记得更改执行的代理参数,然后再次单击蓝色的创建执行。
查看元数据选项卡,会计在学习方面也好不到哪里去。曲率甚至更直,因为在最初的几次迭代后,它将学会总是选择向后,以获得一致的+2 奖励,而不是像随机的醉汉一样摇摆。
不过,总奖励大约是+4000。至少有所改善!
赌徒
从我们的三个代理人,赌徒是唯一一个做真正的 Q 学习。还记得我们在第一部分中的算法吗:
该战略如下:
- 默认情况下,从我们的 Q 表中选择最有利可图的行动
- 有时赌博并选择随机行动
- 如果 Q 表显示两个选项都为零,选择一个随机动作
- 从 100%赌博(探索)开始,慢慢向 0%(剥削)移动
最后,我们可以看到一些真正的 Q 学习正在发生!
在以高探索率缓慢开始后,我们的 Q 表充满了正确的数据,与我们的其他代理相比,我们达到了几乎两倍的总回报。
并行执行
到目前为止,我们一次只运行一个执行,如果您想快速迭代您的模型探索,这并不能很好地扩展。在我们最后的努力中,我们将尝试运行 Valohai 任务,而不是一次性执行。在 Valohai 中,一个任务仅仅意味着执行一组具有不同超参数的执行。
切换到 Valohai 中的任务选项卡,然后点击蓝色创建任务按钮。
让我们看看 learning_rate 参数如何影响我们的性能。选择倍数,然后在不同行输入三个不同的选项(0.01,0.1,0.25)。最后,点击底部蓝色的创建任务开始执行。
Valohai 现在将并行启动不是一个而是三个服务器实例。每个带有数字的方框代表一个具有不同 learning_rate 的运行实例。一旦颜色变成绿色,就意味着执行已经完成。您还可以在执行过程中实时查看元数据图表!
下面是 learning_rate 三个不同值的奖励。看起来我们最初的 0.1 比 0.25 表现得好一点。使用 0.01 显然更糟,并且对于 10000 次迭代似乎根本学不到任何东西。
在我们的下一部分中,我们将更深入地研究并行执行,以加速我们的迭代,并看看如何有效地使用 Valohai 来搜索那些最优的超参数。敬请期待!
原载于blog.valohai.com。
强化学习教程第 3 部分:基本深度 Q 学习
在第 1 部分中,我们通过纸笔示例介绍了 Q-learning 的概念。
在第 2 部分中,我们用代码实现了这个例子,并演示了如何在云中执行它。
在第三部分中,我们将把我们的 Q 学习方法从 Q 表转移到深度神经网络。
使用 Q-table,你的内存需求是一个由状态 x 动作组成的数组。对于状态空间 5 和动作空间 2,总的内存消耗是 2 x 5=10。但是国际象棋的状态空间大约是 10 ⁰,这意味着这种严格的电子表格方法不能扩展到现实世界。幸运的是,你可以从媒体压缩的世界里偷到一个窍门:用一些准确性换取内存。
在无损压缩的情况下,以每秒 60 帧的速度存储 1080p 视频每秒大约需要 1gb。使用有损压缩的相同视频可以很容易地成为 1/10000 大小,而不会损失太多保真度。幸运的是,就像视频文件一样,用强化学习训练模型从来都不是 100%真实的,一些“足够好”或“比人类水平更好”的东西已经让数据科学家微笑了。因此,我们很乐意用准确性换取记忆。
我们不是从 Q 表中取一个“完美的”值,而是训练一个神经网络来估计这个表。毕竟,神经网络只不过是一个美化了的权重和偏好表而已!
我们的示例游戏是如此简单,以至于我们很可能用神经网络比用 Q 表使用更多的内存!任何真实世界的场景都比这复杂得多,所以这只是我们试图保持示例简单的一个假象,而不是一个普遍趋势。
培养
我们之前做 Q-learning 的时候,用的是上面的算法。用神经网络代替 Q 表,我们可以简化它。
不再需要学习率,因为我们的反向传播优化器已经有了。学习率只是一个全球油门踏板,你不需要两个。一旦去除了学习率,你意识到你也可以去除两个 Q(s,a)项,因为它们在去除学习率后相互抵消。
强化学习通常被描述为独立于监督学习和非监督学习的一个类别,然而这里我们将从我们的监督表亲那里借用一些东西。据说强化学习不需要训练数据,但这只是部分正确。事先不需要训练数据,但是在探索模拟时收集训练数据,并且使用非常类似。
当代理探索模拟时,它将记录体验。
单次体验=(旧状态,动作,奖励,新状态)
用单一体验训练我们的模型:
- 让模型估计旧状态的 Q 值
- 让模型估计新状态的 Q 值
- 使用已知的奖励,计算行动的新目标 Q 值
- 用输入=(旧状态),输出=(目标 Q 值)训练模型
注意:我们的网络不像 Q 学习函数 Q(s,a)那样得到(状态,动作)作为输入。这是因为我们没有复制 Q 学习作为一个整体,只是 Q 表。输入只是状态,输出是该状态下所有可能动作(向前、向后)的 Q 值。
代码
在上一部分中,我们足够聪明地将代理、模拟和编排作为单独的类分开。这意味着我们可以只引入一个新的代理,其余的代码基本保持不变。如果你想看剩下的代码,请看第二部分或者 GitHub repo。
定量
在我们的例子中,我们在模拟的每一步之后重新训练模型,一次只有一次体验。这是为了保持代码简单。这种方法通常被称为在线培训。
更常见的方法是将所有(或许多)经历收集到记忆日志中。然后,根据从日志中批量提取的多个随机经验来训练该模型。这被称为批量训练或小批量训练。它比强化学习更有效,并且通常提供更稳定的整体训练结果。将这个例子转化为批量训练是非常容易的,因为模型的输入和输出已经成形为支持批量训练。
结果
这里是一些使用 Valohai 贝叶斯优化器的不同学习率和折扣的训练运行。请注意,这里我们衡量的是绩效,而不是像前几部分那样衡量总薪酬。上升趋势是两件事的结果:学习和剥削。学习意味着模型像往常一样学习最小化损失和最大化回报。开发意味着,既然我们从赌博和探索开始,并越来越线性地转向开发,我们会在最后得到更好的结果,假设学习的策略已经开始在这个过程中有任何意义。
用深度神经网络训练这样的玩具模拟无论如何都不是最优的。模拟不是非常细致,奖励机制非常粗糙,深度网络通常在更复杂的场景中茁壮成长。通常在机器学习中,最简单的解决方案最终会成为最好的解决方案,所以在现实生活中不建议像我们这样用大锤砸坚果。
既然我们已经学会了如何用神经网络来取代 Q-table,我们就可以处理更复杂的模拟,并在下一部分中充分利用 Valohai 深度学习平台。回头见!
在 GitHub 开始这个 Q-learning 教程项目。
原载于blog.valohai.com。
使用单一演示的强化学习
从演示中学习
强化学习对未来有很大的希望;最近的成就显示了它在超级人类水平上解决问题的能力,像玩棋盘游戏,控制机械臂和在专业水平上玩实时策略游戏。这些成就展示了发现新策略的能力,这些新策略优于我们人类能够设计的策略,这是一个令人兴奋的前景。
RL 的另一个可能用途是在人的表现足够好的情况下,使人的决策自动化。在这个设置中,我们希望我们的代理模仿人类专家使用的策略,这为我们的代理提供了完成任务的“正确”方法的演示。这在几种情况下非常方便,例如:
a)当我们不能制定奖励函数,但是我们可以询问专家来指导学习过程,或者已经记录了专家的行为及其结果的数据时。这方面的一个实际例子可能是尝试学习“帮助台”风格的政策,其中我们的代理需要与客户互动并帮助解决他们的问题。由于我们不能很容易地对顾客的回报函数进行建模,我们不能采用标准的 RL 技术,但是我们可以利用人类专家的日志来学习策略。
b)当我们有一个“标准”类型的学习问题,但从头开始学习太难了,我们的算法完全失败了。专家的示范可以帮助我们的学习算法朝着正确的方向前进
需要注意的重要一点是,专家不一定必须是人类。也许我们有一个优化或搜索算法可以完成这项工作,但对于我们的实时应用程序来说,它太慢了,我们需要使用学习的神经网络策略来近似它。在这种设置下,搜索算法可以在整个过程中为学习算法提供专家演示。
在某种意义上,从人类演示中学习更具挑战性,因为让人类在整个学习过程中坐下来并在必要时提供建议通常是不实际的,不像我们的搜索算法那样。人类专家的时间很可能是昂贵的,因此我们通常只有少量的这种数据。
模仿学习
那么,我们如何利用专家的演示来学习政策呢?一个显而易见的和天真的方法是使用演示作为标记数据,并使用监督学习来尝试和预测专家在不同状态下采取的行动。监督学习比 RL 更容易理解,如果我们能够很好地预测行动,那么我们的代理就会表现得相对较好,或者至少在某种程度上接近专家。
然而,可悲的是,这种方法在许多情况下单独使用时非常失败。在大多数现实问题中,状态空间是非常大的,我们可能演示的状态的数量只是其中的一小部分。由于政策学习本质上处理多步骤过程,并且我们的天真的监督学习方法学习对单个状态的响应,所以一个事件开始时的小分歧可能会产生复合效应,将我们的代理带到它从未观察到并且不知道如何行动的状态。
这种行为克隆的另一个问题是,我们的学习过程没有优化我们想要的指标,即从剧集中累积的回报,而是最小化模型预测和专家行动之间的距离。显然,如果我们的模型完美地预测了走势,它也会产生相同的回报,但是预测误差如何转化为回报的差异呢?小错误可能会对代理在我们任务中的表现产生很大影响。
为了有希望成功地使用这种方法,我们必须有大量的数据,涵盖非常广泛的国家,这可能是我们所没有的。即便如此,行为克隆也经常被用作另一种强化学习算法的初始化,以加快学习基础知识的过程。例如,最初的 AlphaGo 使用从在线游戏中收集的 3000 万人类专家棋步数据集来训练其策略网络,最近的 AlphaStar 代理使用职业玩家游戏进行初始化,然后两者都使用 RL 算法进行进一步训练。
从一次演示中学习
近年来的几篇论文研究了使用人类演示来帮助代理学习困难问题的选项。经常被用作基准的一个众所周知的难题是 Montezuma 的复仇,这是一个 Atari 游戏,奖励极其稀疏和延迟,大多数标准 RL 算法都无法在其中取得哪怕是很小的进展。
谷歌 DeepMind 的研究人员发表了一篇关于这个主题的非常有趣的论文,名为“通过观看 YouTube 玩艰难的探索游戏”。在这篇论文中,研究人员收集了许多人类玩家玩游戏的 YouTube 视频,训练了一个神经网络来预测同一集不同帧之间的时间差。这产生了来自不同来源的游戏状态的有意义的嵌入,具有视觉变化,如略微不同的颜色和分辨率,这使得沿着嵌入轨迹“种植”虚拟奖励成为可能,代理人可以从嵌入轨迹中得知它在正确的轨道上。
虽然这种方法很好地利用了丰富的资源——YouTube 视频,但它可能不适用于许多数据很少的问题。OpenAI 的研究人员在最近一篇名为“从一次示威中学习蒙特祖马的复仇”的论文中解决了这个问题。解决方案非常简单:给定一个由专家提供的状态-动作轨迹,在轨迹的末端重新启动代理,并让它使用一些 RL 算法自行学习,然后在轨迹的早期逐步重新启动它,直到最终从头重新启动它,并让它从那里学习。
其背后的想法是,通过在轨迹的末端重新启动它,我们将它放置在奖励附近,事实上如此接近,以至于标准的 RL 算法将毫不费力地找到它。当代理已经学会满意地找到奖励时,我们在专家给出的状态-行动轨迹的更早部分重新启动它,并让它从那里学习。
为了直观地理解为什么这是一个好主意,让我们看看作者在论文中提供的一个简单的玩具问题;盲崖行走问题。在这个问题中,代理人必须使用两个动作中的任何一个,穿越一维悬崖回到安全的地方。第一个动作使它沿着悬崖前进,第二个动作使它坠落并死去。我们假设一个表格设置,其中代理不能在状态之间进行归纳,并且必须学习一个为每个状态指定一个动作的表格。
代理人只有在达到目标状态时才会收到奖励,因此必须首先使用随机动作来探索其环境。然而,期望达到回报所需的行动数量是悬崖长度的指数,这使得它在很短的长度之外不切实际。作者表明,通过一次成功的演示并使用所提出的方法,解决这一任务的时间与悬崖的长度成二次关系,这是一个巨大的进步。
作者指出,这非常像动态编程,在动态编程中,我们通常从最后开始向后解决问题,并引导我们的后期解决方案来帮助快速解决早期阶段。在动态编程中,我们实际上观察到对于诸如图中最短路径的问题,计算复杂性的非常相似的减少。
研究人员将这种方法用于臭名昭著的蒙特祖马的复仇,并获得了当时最先进的结果,以相当大的优势击败了 DeepMind 论文的分数,并使用了少得多的数据。
这种方法的一个明显的缺点是,它需要有能力在沿着规定轨迹的不同状态下重新启动我们的代理,这意味着我们必须自由控制环境,或者它是确定性的,以便采取相同的动作序列将总是导致相同的状态。但是,如果该方法适用,它有两个主要优点:
1)它需要很少的数据,正如论文中所证明的,甚至一个单独的轨迹就足以解决困难的问题。
2)它直接针对返回进行优化,因为轨迹仅用于初始化代理,并从那里开始使用标准 RL 进行学习。这使得原则上代理实际上比专家演示者表现得更好成为可能。
我总是喜欢简单的想法非常有效,这是一个很好的例子。检查纸。
强化学习——价值函数
利用价值函数的代理学习井字游戏的强化学习算法
直觉
在漫长的一天工作之后,你在两个选择之间做决定:回家写一篇中型文章或者和朋友去酒吧。如果你选择和朋友出去玩,你的朋友会让你感到快乐;然而,当你回家写文章时,在工作了一整天后,你会感到疲惫。在这个例子中,享受自己是一种奖励,感觉疲劳被视为一种消极的奖励,那么为什么要写文章呢?
因为在生活中,我们不会只考虑眼前的回报;我们计划了一系列的行动来决定未来可能的回报。也许写一篇文章会让你对某个特定的话题有更好的理解,得到认可,最终让你得到你梦寐以求的工作。在这个场景中,得到你梦想中的工作是从你采取的一系列行动中得到的延迟回报,然后我们想为处于这些状态的人分配一些值(例如“回家写一篇文章”)。为了确定一个状态的值,我们称之为“价值函数”。
那么我们如何从过去吸取教训呢?假设你做了一些伟大的决定,并且处于人生中最好的状态。现在回顾一下你为达到这个阶段所做的各种决定:你把你的成功归功于什么?之前让你走向这种成功的状态是什么?你过去做过的哪些行为让你达到这种收到这个奖励的状态?你现在正在做的事情和你将来可能得到的回报有什么关系?
奖励与价值函数
一个奖励立竿见影。它可以是在收集硬币的游戏中得分,赢得井字游戏或获得你梦想的工作。这个奖励就是你(或者代理)想要获取的。
为了获得奖励,价值函数是确定处于状态的价值的有效方法。用 V(s) 表示,这个价值函数衡量我们在这种状态 s 下可能获得的潜在未来回报。
定义价值函数
Fig 1: State A leads to state B or C
在图 1 中,我们如何确定状态 A 的值?有 50–50%的机会在下两个可能的状态中结束,状态 B 或 c。状态 A 的值就是所有下一个状态的概率乘以达到该状态的奖励。状态 A 的值为 0.5。
Fig 2: One-way future states
在图 2 中,您发现自己处于状态 D,只有一条可能的路径通往状态 E。由于状态 E 给出的奖励为 1,状态 D 的值也为 1,因为唯一的结果是获得奖励。
如果你处于状态 F(在图 2 中),这只能导致状态 G,接着是状态 H。由于状态 H 的负奖励为-1,状态 G 的值也将为-1,对于状态 F 也是如此
Fig 3: Being in state J brings you closer to state K
在这个井字游戏中,连续得到 2 个 X s(图 3 中的状态 J)并不能赢得游戏,因此没有奖励。但是处于状态 J 会使你离状态 K 更近一步,完成一行 X 就能赢得游戏,因此处于状态 J 会产生一个好的值。
Fig 4: State M has a higher value than state N
在图 4 中,您会发现自己处于状态 L,正在考虑将下一个 X 放在哪里。您可以将它放在顶部,这样就可以将您带到状态 M,在同一行中有 2 个 X s。另一种选择是将其放在最下面一行。与状态 N 相比,状态 M 应该具有更高的重要性和值,因为它导致更高的获胜可能性。
因此,在任何给定的状态下,我们可以执行动作,通过选择产生最高值的状态,使我们(或代理人)更接近获得奖励。
井字游戏—初始化值函数
井字游戏的价值函数 V(s) 是达到状态 s 的获胜概率。完成该初始化以定义获胜和失败状态。我们将状态初始化如下:
- V(s) = 1 —如果代理在状态 s 中赢得游戏,则为终止状态
- V(s) = 0 —如果代理在状态 s 中输掉或打平游戏,则为终止状态
- V(s)= 0.5——否则为非终止状态的 0.5,这将在训练期间进行微调
井字游戏—更新值函数
更新值函数是代理如何从过去的经验中学习,通过更新在训练过程中经历的那些状态的值。
Fig 5: Update the value of state s
状态s’是当前状态 s 的下一个状态。我们可以通过添加状态 s 和s’之间的值的差值来更新当前状态 s 的值。α是学习率。
由于在任何给定的状态下可以采取多种行动,所以在一个状态下经常只选择一种行动可能会导致错过其他更好的状态。在强化学习中,这就是探索-利用困境。
通过探索策略,代理采取随机行动来尝试未探索的状态,这可能会找到其他方法来赢得游戏。通过利用策略,代理能够增加那些在过去有效的行动的信心,以获得奖励。在探索和利用之间取得良好的平衡,并通过玩无限多的游戏,每个状态的值将接近其真实概率。探索和利用之间的良好平衡由ε贪婪参数决定。
当游戏结束时,在知道代理人是赢了(奖励= 1)还是输了/平了(奖励= 0)之后,我们只能更新代理人在该特定游戏中已经玩过的每个状态的值。终端状态只能是 0 或 1,我们确切地知道哪些是在初始化期间定义的终端状态。
代理的目标是在游戏结束后更新价值函数,以了解已执行的动作列表。当每个状态的值使用下一个状态的值更新时,在每个游戏结束时,更新过程向后读取该特定游戏的状态历史,并微调每个状态的值。
井字游戏—利用价值函数
Fig 6: Values of various next states
给定足够的训练,代理将会学习任何给定状态的值(或获胜概率)。因此,当我们与我们训练有素的代理人进行游戏时,代理人会使用利用策略来最大化胜率。看能不能打赢代理。
在游戏的每一个状态,代理循环通过每一种可能性,挑选具有最高值的下一个状态,从而选择最佳的行动过程。在图 6 中,代理将选择右下角来赢得游戏。
结论
在除了结束阶段(记录了赢、输或平)之外的任何进展状态,代理采取了导致下一个状态的行动,这可能不会产生任何奖励,但会导致代理向接收奖励靠近一步。
价值函数是确定处于一种状态的值的算法,即获得未来奖励的概率。
每个状态的值通过游戏的状态历史按时间顺序反向更新,通过使用探索和利用策略进行足够的训练,代理将能够确定游戏中每个状态的真实值。
有许多方法可以定义一个值函数,这只是一个适合井字游戏的方法。
40%的吸尘器,40%的看门人,20%的算命师。
towardsdatascience.com](/data-scientist-the-dirtiest-job-of-the-21st-century-7f0c8215e845)
嗨!,我是叮当。我喜欢构建机器学习项目/产品,我在迈向数据科学上写了它们。在 Medium 上关注我或者在 LinkedIn 上联系我。
用 AWS DeepRacer 进行强化学习
从玩具车到 AlphaGo 和自动特斯拉
2016 年 3 月,过去十年最伟大的围棋选手李·塞多尔(Lee Sedol)被 AlphaGo 以 4 比 1 击败。计算机以前在国际象棋上击败过最好的人类,但是围棋在复杂性上又上了一个台阶。你知道更疯狂的是什么吗?这台机器在比赛前 8 小时才学会如何玩。
今年 2019 年 1 月,谷歌 DeepMind 团队将 AlphaGo 带到了另一个高度,制作了 AlphaStar 。星际争霸是最复杂的视频游戏之一,它从来没有被电脑掌握过🤖以前,直到现在。AlphaStar 淘汰了两名世界级选手,以 5 比 0 击败了他们。
就在上个月,OpenAI(前 Elon Musk's)发布了 多智能体捉迷藏 ,一个双方,寻找者和隐藏者之间的模拟。隐藏者必须避开视线👁在一个有墙、盒子和斜坡的世界里。出现了大量的策略,包括建造庇护所和箱子冲浪!查看下面的视频,了解更多信息👇
OpenAI’s video on their Multi-Agent Hide and Seek Simulation
最后但同样重要的是,就在两周前,OpenAI 发布了另一个惊人的结果,它训练了一只成功的机器人手解魔方。它不仅能在 60%的时间里用一只手解决不同大小的 3x3 魔方,还能在有干扰的情况下解决问题(比如被一只毛绒长颈鹿推来推去)🦒 ).
所有这些惊人的突破有什么共同点?他们都使用目前超级热的强化学习(RL)* 🔥机器学习领域。在高层次上,RL 涉及到一个演员在某个环境中通过试错来学习做什么。它被机器人、自动驾驶汽车甚至股市预测者雇佣来安全驾驶并给出准确的预测!***
说到自动驾驶汽车,亚马逊网络服务(AWS)最近创建了一个名为AWS DeepRacer的挑战🚗,主要目的是向开发人员介绍 RL。通过训练一辆汽车在赛道上行驶,参赛者比赛以达到最快的时间。我决定参加他们的挑战以及相应的 Udacity 课程,以更深入地了解 RL,我愿意与你分享它们!😃****
更深入地了解 RL
本质上,强化学习是模仿现实世界,在进化中,以及人们如何👦和动物🐶学习。通过经验,我们人类学会了在不同的情况下做什么和不做什么,并将其应用到我们自己的生活中。RL 以同样的方式通过模拟体验来帮助机器学习。
让我们以 AWS DeepRacer 为例,通过描述一些关键术语来描述这个问题:
- ****代理/参与者:在环境中执行动作的实体(AWS DeepRacer 和控制它的模型)
- 动作:代理可以做什么(汽车可以转弯、加速等)********
- 环境:代理存在的地方(轨迹)
- ****状态:给定时间内的关键特征(轨道上的位置)
- ****奖励:根据代理在前一状态中的动作给予代理的反馈(做得好的奖励高,做得差的奖励低)
下面是一个基本的 RL 模型是如何学习的:一个环境中的代理在其给定的状态下执行一个动作。环境给了代理一个奖励💸这取决于其行动的质量。然后代理执行另一个操作,循环继续。一个训练集由一定数量动作的整个循环组成。****
让我们更深入地研究一下奖励吧!
奖励里有什么?
奖励函数是 RL 模型中非常重要的一部分。对于一个训练有素的代理人来说,拥有一个激励最佳行为并抑制不良行为的机制是至关重要的。
在 AWS DeepRacer 中,我们创建了奖励函数💰用输入参数。这些包括汽车的位置、离中心的距离等等。下面是一个基本奖励函数的例子:****
Image by author
在该函数中,我们使用输入参数 params['track_width'] 和params[' distance _ from _ center ']。我们创建了三个标记,并将赛车与中心线的距离与这些标记进行比较。如果汽车与中心的距离在 10%以内,它会得到 1 的奖励😊。如果在 25%以内,则给予 0.5 的奖励。如果在轨道上,它得到 0.1。如果偏离了轨道,我们给它 0.001,基本上等于零😢
Image by author
这个奖励功能会给坚持在赛道中间的车很高的奖励。知道了这一点,就会避免脱轨,这就是我们想要的!虽然这个奖励函数没有针对速度进行优化,但至少我们可以放心,我们可能会完成比赛。😅
调谐超参数
让我们讨论超参数:我们可以调整或“调整”的模型设置。通过在训练前调整超参数,我们可以尝试提高模型的性能💯。以下是我们可以调整的一些超参数的示例:
- ****学习速率:模型学习的速度。如果学习率高,它学得快但可能达不到最佳状态。如果太低,可能需要很长时间训练。
- ****贴现因子:模型考虑未来的程度。如果更高,DeepRacer 就越看重未来,对考虑到未来的行动给予更高的奖励。如果低,DeepRacer 会以短期的方式思考。
- ****熵:不确定的程度。较高的值允许模型更彻底地探索环境,而较低的值允许模型利用它已经知道的东西。
- 还有更多!
有很多方法可以调整超参数,但没有正确的方法,只能通过实验来实现🔬🧪and 试错法。
培训和评估我们的模型
现在你已经知道了 AWS DeepRacer 的强化学习,让我们来训练和评估我们的虚拟模型吧!以下是步骤(注意,您可以通过创建一个 AWS 帐户来遵循这里的和):
- 在 AWS DeepRacer 控制台中创建一个模型。
- 设置名称、描述和轨道。
- 设置您的行动空间(模型可能采取的行动)。
- 创建你的奖励函数。
- 设置你的超参数。
- 开始训练!
在训练过程中,您的模型将按照您指定的时间⌚在虚拟赛道上进行训练,从一个状态转换到另一个状态,并在途中获得奖励。
The training dashboard for AWS DeepRacer, including training stats and a video stream; image by author
训练结束后,在任何赛道上对模型进行评估,看看效果如何。如果它表现良好,提交到排行榜🥇!如果没有,试着改变你的奖励函数和超参数,看看你能如何改进。毕竟,这是一个反复的过程😁
我们能从 AWS DeepRacer 身上学到什么?
我希望你在训练你的模型和在赛道上比赛时玩得开心!尽管与我们在 OpenAI 或谷歌的 DeepMind 上看到的相比,这是一个简单得多的模型,但我们仍然可以得出一些有价值的结论🔑
- 训练一个好的模型需要大量的时间、资源和实验。想想 DeepMind 花了多少时间训练 AlphaStar!这是一个真正的迭代过程。
- ****设定一个最优的奖励函数至关重要。没有一个好的奖励函数,模型就不能正确地学习它的任务。如果一辆车没有动力留在赛道上,你可以指望它会很快崩溃。
- 强化学习正在掀起波澜。 AWS 让任何有资源的人都可以非常容易地拥有一个真正好的 RL 模型。我们已经看到了过去几个月的疯狂进步;想象一下我们将来会看到什么!
在 RL 领域有超级有趣的工作正在进行,你应该兴奋!不知不觉中,你就再也不能开自己的车了😏****
Photo by Bram Van Oost on Unsplash
希望你喜欢阅读 RL!我也将很快在 NLP 中做更深入的探索,所以一定要关注我并在 LinkedIn 上联系我!如果你想联系我,在 albertlai631@outlook.com 给我发信息。很想聊聊:)
祝您愉快,敬请期待更多精彩!👋
基于随机网络提取的探索式强化学习
自从 2013 年 DeepMind 的开创性 DQN 工作(其中一个代理人成功地学会了以高于人类平均水平的水平玩 Atari 游戏)以来,强化学习(RL)就经常成为头条新闻。从雅达利游戏到机器人技术,以及 AlphaGo 击败世界围棋冠军李世石,RL 似乎即将席卷世界。
事实上,虽然大多数 Atari 游戏现在都可以很好地学习,但有些游戏直到最近才取得相对较小的进展。这些游戏包括臭名昭著的蒙特祖马的复仇,陷阱!和冒险,其共同点是回报极其稀少。
为了理解为什么这是一个主要问题,让我们看看大多数强化学习算法的基本结构。
强化学习代理在与环境交互的同时通过试错来学习,并为自己的行为获得奖励。使用这些奖励信号,代理更新它的行为,并希望学会在未来做出更好的决定。在许多情况下,为了帮助代理探索环境并偶然发现导致更高回报的状态动作,我们通过从代理的当前策略中取样动作,或者通过随机选择具有某种概率的动作(ε-贪婪)来将随机性引入代理的行为。这些简单策略的基本假设是,随机行为最终会导致代理人获得某种回报。
在奖励很少的环境中,情况非常不同,因为代理可能大部分时间都没有收到任何奖励,因此可能很难学习。在极端的情况下,为了获得任何奖励,代理可能需要表现得非常聪明,并采用长而复杂的动作序列来获得第一次反馈。在一些艰难的探索游戏中就是这种情况,例如蒙特祖马的复仇,在这种游戏中,代理人必须避开敌人和致命的障碍,并在看到积极的奖励之前聪明地行动数百步。使用普通探索策略的标准 RL 算法在这些游戏中经常不能实现任何回报,并且这种情况一直持续到最近。
那么,你如何着手解决这样的问题呢?一个看起来很吸引人的方法是以某种方式鼓励代理去探索那些它到目前为止还没有看到的状态。如果我们能让它变得“好奇”,甚至在没有任何回报的情况下寻找新奇的状态,也许它最终会探索得足够多,找到一些。在某种程度上,这让我们想起了儿童学习的方式,好奇心是一种内在奖励。
我们想要做的是,计算代理访问每个州的次数,并向稀疏的外部奖励(来自环境)添加另一个元素,以到达访问次数较低的州的内在奖励的形式。如果我们能做到这一点,那么代理人将不断发现它以前没有见过的新状态,并最终达到一个具有积极外部奖励的状态。显然,为了得到想要的行为,必须在外在和内在奖励之间保持谨慎的平衡。
然而,在所有这些游戏中,状态的数量太大,无法一一列举,因此我们必须找到一种方法来近似计算访问次数。解决这个问题的早期建议是这样的:在训练代理人玩游戏的同时,训练另一个神经网络来预测代理人在玩游戏时遇到的状态转换和奖励。其思想是,最初,神经网络对这些转变和奖励的预测很差,但最终对于网络被训练的那些状态以及与它们相似的状态(由于 NNs 的泛化能力),预测和实际情况之间的距离减小。这意味着我们可以将这个神经网络的预测误差视为访问计数的近似值;如果给定状态的误差很高,则这表明该状态是新的,如果预测误差很低,则我们可以假设与此类似的状态已经被足够频繁地访问过。
这似乎是一个非常优雅的解决方案,但不幸的是,它有一个严重的缺点;在某些州,模型预测误差可能会更高,这是由于不经常访问之外的另一个原因。如果环境具有随机转变,我们的解决方案可能会导致代理被具有高随机性的转变所吸引,因为这些将不可避免地导致更高的预测误差。在实践中已经观察到这种现象,并且这种现象是这种方法通用性的主要缺点。
另一个缺点与模型容量有关;我们正试图使神经网络适应环境的动态,但在某些情况下,这对我们的模型来说可能是一项太难的任务,损害了它充分减少许多状态的预测误差的能力。具有渐近高误差的状态导致代理的探索行为中的偏差,并且可能使它“停留”在状态空间的这些区域中。
2018 年底,OpenAI 的研究人员前来救援,并发表了一篇题为“通过随机网络蒸馏进行探索”的论文,我从现在开始将他们的方法称为 RND 。作者回顾了这种近似访问计数的几种现有方法,并从识别预测误差的来源开始:
-
训练数据量 :预测误差在未被充分访问过的州较高(这是我们所希望的)。
-
随机性 :动态变化大的状态下预测误差大。
-
模型设定错误 :如果我们的模型缺乏近似环境动态的能力,则预测误差较高。
-
学习动态 :如果学习环境动态的过程不稳定且不能收敛,预测误差可能很高。
来源 2-4 是不可取的,因为我们希望预测误差仅反映大致的访问次数。作者随后提出了一个简单而优雅的解决方案:不预测环境动态,而是尝试预测随机神经网络的输出,因此得名“随机网络蒸馏”。
那么到底是什么意思呢?我们随机初始化一个目标网络,它将在整个学习过程中保持固定,并初始化另一个神经网络,它将试图预测目标网络的输出,我将把它称为预测网络。这些网络都以状态作为输入,并输出一个向量。目标网络的输出与转移无关,只是游戏状态的随机函数。最初,目标网络和预测网络是不相关的,并且预测误差将会很高。然而,在学习过程中,对于代理经常访问的状态,该误差将减少,就像我们之前讨论的动态预测方法一样。
通过尝试预测固定目标网络的输出,我们避免了误差源 2–4 中的问题:
-
训练数据量 :我们还是保留这个想要的误差源。
-
随机性 :目标网络是确定性的,所以这个误差源就消失了。
-
模型误设定 :目标网络和预测网络属于同一个模型类,因此具有相同的能力,所以这个误差源消失。
-
这与环境动态学习任务相反,环境动态学习任务是不稳定的(当代理发现新的状态时,它也可能遇到新的转换现象)。
现在,我们准备看看算法的伪代码,如论文中所示:
作者将 RND 方法与一种叫做近似策略优化(PPO)的普通 RL 算法结合使用。从这个伪代码中要得到的重要的东西是,内在的回报是预测网络的损失,并且它在由代理收集的用于更新策略的相同样本上被优化。
其余的细节在很大程度上是针对本文中使用的 RL 算法的,但事实上,RND 是一种完全通用的方法,原则上可以应用于任何 RL 算法,无论是 on 还是 off 策略,因为 RND 只通过奖励与 RL 算法进行交互。
在其出版时,RND 提供了蒙特祖马对纯 RL 算法的报复的最先进的结果(使用各种形式的人类演示获得了一些不错的结果),考虑到这种方法的通用目的,这是令人印象深刻的。
我为登山车问题实现了一个 RND 的极简版本,以演示如何在没有通常的奖励工程的情况下解决它。请随意查看:https://github.com/orrivlin/MountainCar_DQN_RND
后知后觉的强化学习经验回放
稀疏和二进制奖励
近年来,由于一些引人注目的成功,如击败围棋世界冠军和(最近)在流行的实时战略游戏《星际争霸 2》中击败顶级职业选手,强化学习获得了很大的人气。AlphaZero(最新的围棋代理)等成就令人印象深刻的一个方面是,它从稀疏的二进制奖励中学习,要么赢得比赛,要么输掉比赛。在大多数情况下,没有中间奖励会使学习变得非常困难,因为代理人可能永远不会真正获胜,因此没有关于如何改进其表现的反馈。显然,像围棋和星际争霸 2 这样的游戏(至少在比赛中是这样玩的)有一些独特的品质,使得用这些二进制奖励学习成为可能:它们是对称零和游戏。我现在不打算深入探讨这个问题,但我可能会在未来的一篇文章中专门讨论 AlphaZero 背后的算法。
问题是,大多数问题都不是对称的零和游戏,让我们再次没有反馈,没有学习。作为一个例子,我们可以看看一个经典的 RL 问题称为山地汽车。在这个问题中,一辆汽车试图到达山顶的旗帜,但由于它缺乏足够的加速度直接开车上山,它必须来回摆动以获得速度并最终到达目标。
只要汽车没有到达旗帜,它每走一步就获得-1 的奖励,直到该集在固定的步数后终止。一个经常使用的实用方法是使用领域知识来增加奖励,这被称为奖励工程或奖励形成。在我们的山地车示例中,因为我们知道汽车必须加快速度才能爬山,所以一个合理的方法是将汽车的速度添加到奖励中,鼓励它加快速度。如果我们足够仔细地设计奖励,我们的代理人将会加快速度,最终偶然发现这面旗帜,并避免一些本来会得到的负面奖励。
这种方法的问题是它并不总是容易做到。在某些情况下,我们可能不知道如何塑造奖励来帮助学习;换句话说,我们必须知道一些如何解决问题的知识,以便恰当地塑造奖励。这方面的知识并不总是有的,尤其是对于难题。另一个危险是,一旦我们设计了奖励,我们就不再直接优化我们真正感兴趣的指标,而是优化一个代理,我们希望它能使学习过程更容易。这可能会导致相对于真正目标的绩效妥协,有时甚至会导致意想不到和不想要的行为,这可能需要频繁微调设计的奖励,以使其正确。
多目标 RL
许多著名 RL 成就的另一个明显方面是,这些游戏与一个非常具体的目标有关,例如“在突围中尽可能多地得分”。在这些问题中,代理观察到一个状态,选择一个动作,并获得一个奖励。在这种情况下,我们的政策可以表述为:
其中“a”是候选动作,“s”是当前状态。
但许多现实世界的问题并不像这样,我们必须执行一个单一的全球任务。在许多情况下,我们希望我们的代理能够实现许多不同的目标,如“获取红色的球”,但也“获取绿色的立方体”。我的意思不是说代理需要以某种方式立即执行这些目标,而是我们希望它能够根据请求执行这些任务中的任何一个。在这种情况下,我们可以将我们的政策表述为:
其中“g”是期望的目标。在本文中,我们将把目标视为我们希望代理达到的状态。这是一个多目标学习问题。如果我们将多目标问题与稀疏二元奖励的额外困难结合起来,我们就会陷入一些真正的困难。
OpenAI 的研究人员在他们的论文“后见之明体验回放”中给出了这样一个问题的简单例子。假设我们有一个由二进制数(0–1)的向量组成的状态,我们希望训练一个代理到达给定的二进制目标向量的任何一个。可能的行动是每次切换一位,未达到目标的每个时间步长奖励-1。显然,如果我们将状态和目标向量的大小设置得足够大,我们就没有希望用传统的方法解决这个问题。随机交换比特和偶然发现想要的目标向量的机会是极不可能的,即使使用专门的探索方法(就像我在以前的文章中写的方法)我们也很可能失败,因为每个目标向量对这些方法来说就像是一个完全不同的问题。状态-目标空间太大了。作者证明了 DQN 的最大可解向量大小是 13,之后成功率急剧下降到零。
后知后觉的经历回放——从失败中学习
政策外学习
但是人类如何处理这样的问题呢?有时当我们未能完成某项任务时,我们会意识到我们所做的在另一种情况下或另一项任务中是有用的。这篇论文(这是我最喜欢的 RL 论文之一)的作者正是利用这种直觉来开发他们的方法。
即使我们最终失败了,为了转化检查过去行为并从中推断有用信息的能力,我们将转向一种称为非策略学习的学习范式。
在 RL 中,我们试图学习一种策略,在给定初始状态分布的情况下,使期望的累积回报最大化。我们通过反复试验与环境互动来学习政策,并使用在此过程中收集的数据来改进我们的政策。但是一些 RL 算法可以从由另一个策略收集的数据中学习一个策略。这另一个策略记录了它与环境的相互作用,我们的学习算法可以使用它来推断一个潜在的更好的策略。从现在起,我将把我们试图学习的政策简称为政策,而把另一个政策称为探索政策。探索策略的目的是探索足够多的状态-动作空间,以便我们的学习算法可以从中推断出在不同状态下应该采取什么动作。非策略学习算法的经典例子是 DQN(深度 Q 网络)和 DDPG(深度确定性策略梯度),这些算法可以在给定由探索策略收集的数据的情况下学习状态-动作对的值。
相比之下, On-Policy 学习算法必须只依赖于被学习的同一个策略收集的数据,这意味着它们不能使用另一个策略收集的历史数据,包括它们自己的旧版本(例如,在 SGD 更新到神经网络之前)。基于策略的学习算法的典型例子是各种策略梯度方法,例如加强和 A3C(异步优势行动者-批评家)。
后知后觉的经历回放
在著名的 DQN 算法中,通过对用于更新神经网络的每一批中的训练样本去相关,使用过去经验的缓冲区来稳定训练。这个缓冲区记录了过去的状态、在这些状态下采取的行动、收到的奖励以及观察到的下一个状态。如果我们希望将此扩展到我们的多目标设置中,除了状态之外,我们还必须保存目标,并了解状态-目标-行动三元组的价值。
正如我们已经看到的,体验重放缓冲区中的数据可以源自探索策略,这提出了一种有趣的可能性;如果我们可以通过想象如果情况不同会发生什么来添加虚拟数据,会怎么样?这正是后见之明经验回放(她)事实上做的。
在她的文章中,作者提出了以下策略:假设我们的智能体执行了一集,试图从初始状态 S 到达目标状态 G,但未能成功,并在该集结束时到达某个状态 S’。我们将轨迹缓存到重放缓冲区中:
其中带下标 k 的 r 是该集第 k 步收到的奖励,带下标 k 的 a 是该集第 k 步采取的动作。她的想法是想象我们的目标实际上一直都是‘S’,在这个替代现实中我们的代理人已经成功地达到了目标,并因此获得了积极的回报。因此,除了缓存之前看到的真实轨迹,我们还缓存以下轨迹:
这个轨迹是想象出来的,是由人类从失败的尝试中学到有用的东西的能力所驱动的。还需要注意的是,在想象的轨迹中,在这一集的最后一步得到的奖励现在是达到想象的目标所获得的积极奖励。
通过将想象的轨迹引入我们的重放缓冲区,我们确保了无论我们的策略有多糟糕,它总会从中获得一些积极的回报。在这个阶段,我们可能会问自己,学习去实现我们不感兴趣的目标有什么用?很明显,在训练的开始,那些想象的目标将只是我们糟糕的随机初始化策略可以达到的状态,没有实际用途。然而,神经网络函数逼近的魔力将确保我们的政策也能达到类似于它以前看到的那些状态;这是泛化属性,是成功深度学习的标志。起初,代理将能够到达初始状态周围相对小的区域中的状态,但是它逐渐地扩展状态空间的这个可到达区域,直到最后它学会到达我们实际上感兴趣的那些目标状态。
这个过程与深度学习中的另一种常见做法有很多相似之处;课程学习。在课程学习中,我们希望我们的神经网络学习一些困难的东西,但如果我们让它在真正的任务上训练,它很可能会失败。我们能做的是让它开始在更小的问题实例上进行训练,这要容易得多,并逐渐增加实例的难度,直到我们的模型学会在我们着手解决的任务上表现良好。课程学习通常在实践中运行良好,但需要设计者手动设计课程,并产生更简单的任务实例。这并不总是容易做到的,因为有时我们可能无法产生一个更简单的问题,并且成功地设计课程可能是困难和耗时的。
与此相反,她给了我们一个非常相似的结果,而不需要我们修改问题或设计课程。我们可以把她看作是一个隐性的课程学习过程,在这个过程中,我们总是向我们的代理提供它确实能够解决的问题,并逐渐增加这些问题的范围。
作者在几个机器人操纵任务上测试了她,在这些任务中,代理人必须从初始状态实现不同的目标,例如捡起物体或将其滑动到某个目标位置。在这些任务中,如果代理人按时完成了任务,就会得到奖励,如果没有按时完成,就没有奖励。作者使用 DDPG 作为基本算法对她进行了测试,并表明她在学习完成这些任务方面取得了成功,而其他算法无法学习。
作者还证明了,只要我们能为训练提供其他目标,即使在我们真正关心某个特定目标的任务中,她也能提高表现。
这是一个非常优雅和简单的方法来解决许多 RL 应用中的一个困难和重要的问题。检查纸。我已经用用她的实现了比特翻转实验,另外还用她训练了一个智能体在 2D 网格世界环境中导航,请随意看看。
无梯度强化学习:用遗传算法进化智能体
在假期里,我想提高我的强化学习技能。对这个领域一无所知,我上了一门课程,在那里我接触到了 Q-learning 和它的“深度”等价物(深度 Q 学习)。那是我接触 OpenAI 的健身房的地方,那里有几个环境供代理人玩耍和学习。
课程仅限于深度 Q 学习,所以我自己读了更多。我意识到现在有更好的算法,如政策梯度及其变体(如行动者-批评家方法)。如果这是你第一次参加强化学习,我推荐以下资源,它们对建立良好的直觉很有帮助:
- 安德烈·卡帕西的深度强化学习:来自像素的 Pong】。这是一个经典的教程,引发了人们对强化学习的广泛兴趣。必读。
- 通过 Q-Learning 深入强化学习。这篇文章对最基本的 RL 算法 : Q-learning 做了一个很好的、有插图的概述。
- 各种强化学习算法介绍。RL 算法世界的漫游。(有趣的是,我们在这篇文章中将要讨论的算法——遗传算法——不在列表中。
- 直觉 RL:优势介绍——演员——评论家(A2C) 。一个非常非常好的漫画(是的,你没听错)关于 RL 目前最先进的算法。
我感到很幸运,作为一个社区,我们分享了这么多,以至于在对强化学习一无所知的几天内,我能够复制仅仅 3 年前的艺术状态:使用像素数据玩雅达利游戏。这里有一个我的代理人(绿色)只用像素数据和 AI 玩 Pong 的快速视频。
This sort of feels like a personal achievement!
强化学习的问题是
我的代理使用策略梯度算法进行了很好的训练,但这需要在我的笔记本电脑上进行整整 2 天 2 夜的训练。即使在那之后,它也没有完美地播放。
我知道总的来说,两天并不算多,但我很好奇为什么强化学习的训练如此缓慢。通过阅读和思考,我意识到强化学习缓慢的原因是因为梯度(几乎)不存在,因此不是很有用。
梯度有助于监督学习任务,如图像分类,它提供了关于如何改变网络参数(权重、偏差)以获得更高精度的有用信息。
Imagine this surface representing error for different combinations of weights and biases (the lower the better). Starting from a randomly initialized point (of weights and biases), we want to find the values that minimize the error (the lowest point). Gradients at each point represent the direction of downhill, so finding the lowest point is equivalent to following the gradient. (Wait, did I just describe the stochastic gradient descent algo?)
在图像分类中,在每次小批量训练之后,反向传播为网络中的每个参数提供了清晰的梯度(方向)。然而,在强化学习中,梯度信息只是在环境给予奖励(或惩罚)时偶尔出现。大多数时候,我们的代理人在采取行动时并不知道这些行动是否有用。梯度信息的缺乏使得我们的误差范围看起来像这样:
Image via the excellent blog post Expressivity, Trainability, and Generalization in Machine Learning
奶酪的表面代表我们的代理人网络的参数,无论代理人做什么,环境都不会给予奖励,因此没有梯度(即,因为没有错误/奖励信号,我们不知道下一次在哪个方向改变参数以获得更好的性能)。表面上的几个孔代表对应于与表现良好的代理相对应的参数的低误差/高回报。
你现在看到政策梯度的问题了吗?一个随机初始化的代理很可能位于平面上(而不是一个洞)。如果一个随机初始化的代理在一个平坦的表面上,它很难达到更好的性能,因为没有梯度信息。因为(错误)表面是平的,一个随机初始化的代理或多或少做了一次随机游走,并在很长一段时间内被坏策略所困。(这就是为什么我花了几天时间来训练一个代理。提示:也许政策梯度法不比随机搜索好?)
正如标题为为什么 RL 有缺陷的文章明确指出的:
如果你想学的棋盘游戏是围棋,你会如何开始学习?你会阅读规则,学习一些高水平的策略,回忆你过去如何玩类似的游戏,得到一些建议…对吗?事实上,这至少部分是因为 AlphaGo Zero 和 OpenAI 的 Dota 机器人的从头学习限制,与人类学习相比,它并不真正令人印象深刻:它们依赖于比任何人都多得多的游戏数量级和使用更多的原始计算能力。
我认为这篇文章切中要害。RL 是低效的,因为它没有告诉代理它应该做什么。不知道该做什么的代理开始做随机的事情,只是偶尔环境会给出奖励,现在代理必须弄清楚它采取的数千种行动中的哪一种导致了环境给出奖励。人类不是这样学习的!我们被告知需要做什么,我们发展技能,奖励在我们的学习中扮演相对次要的角色。
If we trained children through policy gradients, they’ll always be confused about what they did wrong and never learn anything. (Photo via Pixabay)
强化学习的无梯度方法
当我在探索基于梯度的 RL 方法的替代方法时,我偶然发现了一篇题为深度神经进化:遗传算法是训练用于强化学习的深度神经网络的有竞争力的替代方法。这篇论文结合了我正在学习的东西(强化学习)和我一直很兴奋的东西(进化计算),所以我着手实现论文中的算法并进化出一个代理。
请注意,严格来说,我们甚至不必实现遗传算法。如上所述,同一篇论文发现甚至完全随机的搜索也能发现好的代理商。这意味着,即使你继续随机生成代理,最终,你会找到一个表现良好的代理(有时比策略梯度更快)。我知道,这很疯狂,但这只是说明了我们最初的观点,即 RL 从根本上是有缺陷的,因为它几乎没有什么信息可供我们用来训练算法。
什么是遗传算法?
这个名字听起来很花哨,但实际上,这可能是你能设计出的探索风景的最简单的算法。考虑一个通过神经网络实现的环境中的代理(如 Pong)。它获取输入层中的像素,并输出可用动作的概率(向上、向下或不做任何动作)。
Image via Deep Reinforcement Learning: Pong from Pixels
我们在强化学习中的任务是找到神经网络(权重和偏差)的参数(权重和偏差),这些参数使代理更经常获胜,从而获得更多奖励。到目前为止还好吗?
遗传算法的伪代码
- 简单地把代理想象成一个有机体,
- 参数将是指定其行为(策略)的基因
- 奖励将指示有机体的适应性(即,奖励越高,生存的可能性越高)
- 在第一次迭代中,您从带有随机初始化参数的 X 个代理开始
- 他们中的一些人可能会比其他人表现得更好
- 就像现实世界中的自然进化一样,你实现了适者生存:简单地选取最适的 10%的代理,并为下一次迭代复制它们,直到下一次迭代又有了 X 个代理。击杀最弱的 90%(如果这听起来很病态,可以把击杀功能改名为 give- 木沙!)
- 在复制前 10%最适合的代理的过程中,向其参数添加一个微小的随机高斯噪声,以便在下一次迭代中,您可以探索最佳代理参数周围的邻域
- 让表现最好的代理保持原样(不添加噪声),这样你就可以一直保留最好的,以防止高斯噪声导致性能下降
就是这样。你已经理解了遗传算法的核心。遗传算法有许多(奇特的)变种,其中两个代理之间有各种各样的(肮脏的)性(性重组),但关于深度神经进化的论文用上面的伪代码实现了香草遗传算法,这也是我在代码中实现的。(你可以在我的 Github 库上用代码访问Jupyter 笔记本)。
Yellower regions are regions with lower error (higher rewards/performance). Blue dots are all agents. Green ones are the top 10% and the red dot is the best of the best. Notice how gradually the entire population moves towards the region with the lowest error. (Image via Visual Guide to Evolutionary Strategies)
关于进化算法如何工作的更多可视化,我强烈推荐阅读这篇做得非常好的帖子:进化策略可视化指南。
用于实现强化学习的深度神经进化的代码
我 t̸r̸a̸i̸n̸e̸d̸进化出了一个移动小车上的代理平衡杆(又名 CartPole-v0 )。下面是完整的代码:https://github.com/paraschopra/deepneuroevolution
使用 PyTorch,我们通过 2 个隐藏层的神经网络(希望保留“深层”部分:)对代理进行参数化,对于 CartPole,一个层的网络也可以做得很好。
这是进化的主循环:
这段代码基本上是不言自明的,并且遵循了我在本文前面写的伪代码。将细节映射到伪代码:
- 我们的人口规模是 500 ( num_agents ),我们在第一次迭代中随机生成代理( return_random_agents )
- 从 500 个中,我们只选择前 20 个作为父代( top_limit )
- 我们想要运行循环的最大迭代次数是 1000 次(代)。尽管通常对于 CartPole 来说,在几次迭代中就能找到一个表现良好的代理。
- 在每一代中,我们首先运行所有随机生成的代理,并在 3 次运行中获得它们的平均性能(曾经可能是幸运的,所以我们想要平均)。这是通过 run_agents_n_times 函数完成的。
- 我们按照奖励(绩效)的降序对代理进行排序。排序后的索引存储在 sorted_parent_indexes 中。
- 然后,我们选择前 20 名代理,并在其中随机选择,为下一次迭代生成子代理。这发生在 return_children 函数中(见下文)。该函数在复制代理时向所有参数添加一个小的高斯噪声,但保留一个最佳的精英代理(不添加任何噪声)。
- 现在将子代理作为父代理,我们再次迭代并运行整个循环,直到完成所有 1000 代或者我们找到具有良好性能的代理(在 Jupyter 笔记本中,我打印了前 5 名代理的平均性能。当它足够好时,我手动中断循环)
return_children 函数是这样的:
您可以看到,首先,它从前 20 个代理中选择一个随机代理(索引包含在 sorted_parents_indexes 中),然后调用 mutate 函数添加随机高斯噪声,然后将其添加到 children_agents 列表中。在第二部分中,它调用 add_elite 函数将最佳代理添加到 children_agents 列表中。
下面是 变异 的功能:
你可以看到,我们迭代所有参数,并简单地添加高斯噪声(通过 np.random.randn() )乘以一个常数( mutation_power )。乘法因子是一个超参数,大致类似于梯度下降中的学习速率。(顺便说一下,这种遍历所有参数的方法速度慢,效率低。如果你知道 PyTorch 中更快的方法,请在评论中告诉我)。
最后,函数 add_elite 如下:
这段代码简单地选取前 10 名代理并运行 5 次,以根据平均表现双重确定哪一个是精英(通过 return_average_score )。然后它通过 copy.deepcopy 复制精英,并原样返回(无突变)。如前所述,精英确保我们总是有一个我们以前最好的副本,它防止我们随机漂移(通过突变)到一个没有好代理的区域。
就是这样!让我们看看进化后的钢管舞特工的表现。
You, Sir, are a product of evolution.
遗传算法并不完美。例如,在添加高斯噪声时,没有关于如何选择乘法因子的指导。你只需要尝试一堆数字,看看哪一个有效。而且,在很多情况下,可能会彻底失败。我多次尝试为 Pong 开发一个代理,但它非常慢,我放弃了。
我联系了深度神经进化论文的作者,费利佩这样的。他提到,对于一些游戏(包括 Pong)来说,神经进化失败了,但对于其他游戏(如 Venture )来说,它比政策梯度要快得多。
你会进化成什么样?
我的知识库中用于深度神经进化的代码足够通用,可以与 PyTorch 中实现的任何神经网络一起工作。我鼓励你尝试各种不同的任务和架构。如果你成功了,失败了或者卡住了,请告诉我!
祝你好运进化你自己的世界。
PS:查看我以前的实践教程 a) 从小语料库中生成哲学 和 b) 贝叶斯神经网络
感谢 Nirant Kasliwal 和 Felipe 审阅这篇文章的草稿。
在 Twitter 上关注我
我定期发关于人工智能、深度学习、创业公司、科学和哲学的推特。跟着我上https://twitter.com/paraschopra
[## Paras Chopra (@paraschopra) |推特
Paras Chopra 的最新推文(@paraschopra)。@Wingify |的创始人兼董事长写道…
twitter.com](https://twitter.com/paraschopra)
为人工智能时代重塑商场
设置背景
全球每月只有几十亿人逛商场和购物中心。这不仅反映了购物中心在零售业中不可或缺的地位,也反映了等待利用的数据驱动洞察的巨大潜力。购物中心可以使用大数据、机器学习和人工智能来获得有意义的见解,以最大限度地降低运营成本,建立更好的客户参与,探索新的收入途径,使租户能够提高生产力,等等。然而,我们看到和读到的新闻预示着一个新时代的到来,更多的购物中心将停止营业(分析师估计,到 2022 年,美国每 4 个购物中心中就有 1 个可能停业)。
最近,欧洲一家超大型购物中心管理服务公司的资产管理负责人在一次私人讨论中告诉我们:
“我们在做决定时很慢,但在询问结果和指向别处时却很快……我们发现很难做出充满不确定性的决定,也很难少做我们应该做的实验。我们想知道哪些品牌创造了更多的流量,但我们没有衡量品牌的停留时间。世界各地的购物中心和购物中心都在快速变化——我们只有在受到重创时才会做出反应,而我们通常在利用新技术方面动作迟缓。”
今天,大多数大型全球购物中心运营商的资产管理和运营领导人都敏锐地意识到,技术推动的破坏性创新、受过教育的年轻人口的偏好变化以及在线购物正在迅速缩短传统购物中心的生命周期,并创造新的机会将购物中心改造成不同于现状的东西。这些领导人被迫重新思考支持商业战略的技术投资,以便在这个新的世界秩序中生存和发展。然而,许多这样的领导人和他们的组织也遭受着失败的恐惧,缺乏内部支持,和实践的责任,特别是当开始雄心勃勃的计划时。
领导人面前的挑战
购物中心/购物中心正处于一场完美风暴的中心,这场风暴是由不同的内部和外部力量造成的,这些力量逐渐迫使高管将稀缺资源投入到多个相互矛盾的方向。
“购物中心作为购物大厅的传统概念正在成为‘历史的错误’,迫切需要彻底改造。”
-零售开发商 Caruso 附属公司首席执行官 Rick Caruso
- 过去十年左右,在线/移动购物的迅速崛起导致大品牌零售商的客流量下降,这些零售商是许多购物中心的核心商店。由于一些商店因财务原因关闭,商场客流量减少。
Of all the things we do on our phones, the fastest-growing segment in 2017 was shopping, up 54% year-over-year. Source: Mary Meeker 2018 State of the Internet report
- 大衰退的打击降低了整体支出,大多数千禧一代现在更注重体验而非所有权。旅游业蓬勃发展,酒店入住率高得惊人,餐饮服务和饮酒场所增长迅速,而购物中心的核心店铺——服装支出却在下降。随着消费者开始寻找便宜货,快时尚商店和俱乐部商店从百货商店那里抢走了一些市场份额。
- 并非所有的商场都是平等的。购物中心“可出租总面积”(GLA)——美国的人均购物面积比加拿大多 40%,比英国多 5 倍,比德国多 10 倍。这是一个数量过多的问题,许多分析师认为有必要对 T4 市场进行一次必要的调整,尤其是当购物中心不在市区范围内或者维护不善的时候。虽然目的地购物中心(如美国购物中心)将能够成功地创造出值得离开沙发开车去的体验,但其余的购物中心将在关注如此广阔空间中塑造人类体验的细节方面挣扎或死亡。
This report clearly highlights the excess GLA that many countries have Source: A study commissioned by the South African Council of Shopping Centres to understand the GLA relative to the world.
- 商场管理层对测量工具的有限投资一直是一个很少被提及的话题,但却是一个关键的内部挑战。大多数商场业主都不愿意和/或缓慢地采用新技术,并进行充分的测量,以了解在这个新世界中什么可行,什么不可行。例如,虽然大多数购物中心资产经理总是在寻找下一个突破性品牌、新时代杂货连锁店和继续将流量带到他们家门口的活动,但这些领导者没有/只有有限的工具集来了解当前的基线数字,导致与零售商之间的相互不信任。一级和二级商场的运营和营销团队充分意识到,他们正在与提供个性化、便利性和无缝体验的在线聚合商激烈竞争,但大多数人仍忙于按照过去 20 年左右的方式查看客流量。
可见的中奖趋势
“独自购物或主要购物不再是人们会来购物中心的原因。随着越来越多的空地、充足的停车位和通往主干道的通道,购物中心现在开始问‘这些地方还能用来做什么?’
- Peter Muoio,Ten-X 首席经济学家
商场业主和购物中心管理层有一个传统的剧本——现有的结构、古老的治理流程、集中的资本要求&投资战略、长期运行的技术创新周期、本地有限的营销 —这是过时的,不适合在这个新的变化环境中推动增长。应对压力已经迫使许多一级和二级商场走上战略弯路。我们见证的最大趋势是购物中心的重新定位,从购物交易场所到以顾客体验创新为核心的消费者参与中心。这已经反映在
- 不断变化的租户组合模式已经从纯粹的零售转变为餐饮、娱乐、健康和一系列多样化业务的结合,包括办公空间,有时甚至是公寓。这种类似微型城市的发展已经成为千禧一代的磁石,他们离开市中心前往郊区,但仍然希望生活在一个密集、可步行的社区,并靠近他们想要的一切。
- 也有一个明显的转变,从只有长期租赁到灵活的短期租赁和弹出窗口,并增加了营销投入,以获得全年正确的租户组合。GenZ 和千禧一代中的很大一部分人生活在 Insta 和其他社交媒体的潮流中,Westfield 通过推出有史以来第一个人工智能驱动的“潮流商店”来捕捉他们的兴趣,该商店实时显示社交媒体上的热门产品。
The Trending Store operated by Westfield London — a pop-up selling clothes which are trending online. Source: https://www.standard.co.uk/fashion/westfield-trending-store-ai-pop-up-save-the-children-a4154196.html
- 线上和线下模式的日益融合导致前者在受欢迎的购物中心开设实体店,而购物中心大量投资数字界面,以实现混合购物体验。现在,在购物中心看到过多的数字信息亭和显示器并不罕见,它们超越了正常的“在购物中心找到你的路”——技术可能是实体商店重生的关键。
- 此外,由于购物中心在价格或其他便利选项上无法击败在线玩家,许多一级购物中心提供差异化服务,如忠诚客户的 VIP 待遇,举办产品学习会、音乐表演等。科威特的 Gate Mall 推出了一项为顾客提购物袋的礼宾服务,以帮助他们舒适地购物。事实证明,这是一项非常受顾客欢迎的服务,增加了购物时间,提高了转化率。
Listing of special concierge services at the Gate Mall in Kuwait: Source: http://www.thegatemall.com.kw/The-Gatemall/Services
前进前进策略
“我们将继续与品牌紧密合作,提供创新的零售空间,为他们和我们的访客创造理想的环境,包括开发融合数字和实体购物的技术,以增强在一流环境中的额外体验。”
-Myf Ryan,Westfield 英国和欧洲首席营销官
追逐商业房地产,尤其是购物中心的资本数量惊人,其核心信念是,实体环境具有更接近客户的根本优势,可以提供在线不可能提供的令人愉快的服务。我们看到,在全球范围内运营商业房地产服务业务的客户驱动型运营模式正在逐步但肯定地演变。基于上述趋势以及我们与众多领导者的闭门讨论,我们将以下内容确定为购物中心房地产开发商繁荣发展的三大赌注。
#1 为租户创造相互价值&商城开发商
我们预计将会出现一股采用新的灵活租赁模式的强劲浪潮,这种模式强调了实体店在更广泛的全渠道零售中的作用,为零售商和购物中心物业经理创造了双赢的机会。这将有助于从商场所有者到零售商的相对自由的度量和见解流动,反之亦然,创造一个信任的环境,这是今天所缺少的。
Next-gen rental models are on the rise and forward-looking malls are going to adopt them. Source: ICSC Research Envision 2020
新兴的混合购物模式,如展厅和网络空间,将被纳入租金公式,尊重开发商和零售商的需求和利益,并定义对双方公平公正的商业结果。与绩效相关的指标将成为这种共同价值创造的关键,并取决于净购物时间(停留时间)、顾客量、转换率和购物篮大小。根据零售商之间的剥离计算率,通过确定任何单个零售商的净客流量贡献,这将得到进一步完善。
#2 将购物中心重新定位为目的地,而不是购物中心
为了保持相关性,大型购物中心必须不仅仅是“商品集散地”,而是要发展成为社区中心和文化中心。一级和二级玩家正在认真考虑他们的投资组合,以确定将公寓、酒店、电影院、健身俱乐部、餐厅、活动区和其他类型的用途纳入其中的机会,从而增加宝贵的密度、客流量和活力。受过良好教育的年轻千禧一代和 Zs 一代不断涌入大城市,导致某些市中心市场的零售、公寓和写字楼需求增加,为重新定位现有城市中心和进行有限的开发创造了机会。
#3 投资人工智能技术
计算机视觉(AI)等数字跟踪技术的快速发展实现了准确的计算(而不是容易出错的基于 wifi 的估计或传统的人数计算),并为生物识别驱动的营销、运营效率和潜在的新收入渠道创造了机会。
这里有几个关键领域,这种技术可以推动针,我们希望领导人迅速实施它们。
Computer Vision is used to securely analyze the visitor flow and related demographics and mood index of areas inside and outside the malls without compromising on individual privacy. Source: RealValue.ai
作战
- ****保护场所和资产:面部识别可以通过防止潜在威胁和快速管理情况,为商场提供一种强大的安全和监控机制。
- ****提高运营效率:通过准确估计访客流量和管理相关资源和资产,管理电梯、洗手间、停车场的排队时间或自动扶梯和入口的拥挤情况。这使我们能够预测交通模式,并相应地提前计划人员需求。这可以非常有效地减少人员过剩的成本,避免在拥挤时期出现人员不足的情况。
- ****优化布局和标志:通过性别、年龄和情绪分析精心制作的热图可以帮助跟踪消费者的旅程,识别热点和瓶颈。这可用于设计布局变化,以提供最佳的客户购物路径,衡量数字标牌板和邻近营销的影响。
新收入
- ****广告收入:根据热图分析,确定针对特定受众创建新广告空间的最佳位置和时间。将现有的数字内容货币化,如开店视频、活动、产品发布等。将它们与产品/品牌发现 KPI 联系起来。
- 从互动信息亭中获取更多:信息亭在很大程度上仍未得到充分利用,仅仅作为方向提供者。智能信息亭可以快速分析客户人口统计数据,以提供量身定制的产品推荐、个性化促销,帮助发现商店、特色、设施等。这可以通过手势和情绪分析增强内容的相关性来进一步参与。
- ****让弹出式商店更赚钱:不仅仅是出租你的空间给弹出式商店。从访客分析中获得洞察,为参与的品牌带来显著价值。使用面部识别功能方便支付。
营销&品牌
- ****帮助租户确定他们的视觉营销:橱窗展示对品牌认知影响最大,在将路人转化为店内访客方面发挥着至关重要的作用。通过研究顾客对零售展示的反应,获得见解,帮助租户确定最有效的橱窗展示形式、产品组合和价格点,从而吸引顾客进店。
Simple dwell time, attention time analysis can help boost advertisement revenues inside and outside the malls. Source: RealValue.ai
- ****消除营销活动中的猜测:确定实施营销活动的最佳条件,并用真实数据衡量其有效性。芬兰赫尔辛基的 Kamppi 购物中心分析了步行交通模式,发现购物者聚集在午餐时间,而不是之前认为的下班后——他们能够通过调整时间来创造更有效的营销活动。
- ****创建能够转化的促销活动:利用能真正打动客户的内容,生成有针对性的信息。今天的顾客眼光更加敏锐,不会被折扣所左右或诱惑,只会受到价值的影响。
最终……
“如果我们有数据,你就可以进行智能对话。这真的很重要。想想伙伴关系,所有的关系都是如此,因为数据会让你有能力很好地分析关系,也会让你有能力真正了解如何改善。”
—行为分析学院(Behavior Analytics Academy)创始人罗尼·马克斯(Ronny Max)谈到数据在提高零售商和商场开发商之间的互信方面的重要性
勇气、雄心和毅力是所有三个建议奏效的先决条件:对当前商业模式施加压力的勇气、打破惯性的雄心和通过使用技术跟随变化的毅力。虽然多次访问硅谷和观看类似 TED 的视频启发了领导者,但现在是时候将这些战略迅速付诸行动,并接受数字化转型之旅中的不确定性。承诺是零售商和物业管理公司之间更好的合作,对终端消费者的透明度和便利性,以及快速响应市场变化的能力。
购物中心和购物中心已被证明是很好的生意,在那里有房地产开发商、零售商和其他供应商的利益汇合,当然还有像你我这样的消费者。我们正在见证这个行业为适应社会和技术变化而进行的缓慢但确定的演变。
Realflow 是来自 Calculai 的人工智能视觉智能平台,它对我们工作、娱乐和购物的物理空间产生了有意义的影响,从而提高了参与度、安全性和转化率。我们植根于硅谷、印度和法国,将前沿的人工智能和创新带给全球的本地企业。
来源
https://www . the verge . com/2019/5/24/18638782/Amazon-mall-kiosk-shopping-new-presented-by-stores
https://www . the guardian . com/us-news/2017/jul/22/mall-of-America-Minnesota-retail-周年庆
https://www . theatlantic . com/business/archive/2017/04/retail-meltdown-of-2017/522384/
https://www . Forbes . com/sites/geristengel/2018/02/21/6-ways-retailers-is-prospering-in-malls/# 3 dbdb 9 c 02 be 9
https://time.com/4865957/death-and-life-shopping-mall
重塑客户体验的个性化
为什么?什么?怎么会?
“记住,对一个人来说,他的名字是任何语言中最甜美、最重要的声音。”—戴尔·卡耐基,如何赢得朋友并影响他人
说到与客户建立良好的关系,记住他们的名字对于任何级别的企业都是必不可少的一步。当涉及到与他们做生意的品牌时,消费者希望被当作个体对待。记住一个人的名字,并在适当的时候使用它,这是赢得那个人接受你的思维方式的关键。这一事实得到了科学的支持,科学认为听到自己的名字会对听者的大脑产生强大的影响。因此,合乎逻辑的做法是,不仅要记住并使用客户的名字,还要记住并使用他们的好恶,让他们感到受到重视——换句话说,为消费者提供个性化的客户体验可以让他们立刻成为品牌的忠实客户。
Personalizing the customer experience across all touch points
客户时代标志着一刀切的信息时代的结束。如今,一条信息无法完成工作,除非它能与每个客户完美契合。在这个时代,消费者比以往任何时候都更有权力,更能控制他们与品牌的关系。这些消费者在整个购买过程中不断要求个性化。
生活在一个喧嚣的即时满足的世界,一家企业如何在一个已经过度拥挤的领域留下印象?实际上很简单——利用所谓的“鸡尾酒会”效应。鸡尾酒会效应是这样的:当你在一个鸡尾酒会上,有几十个人围着你聊天,你会发现你很容易模糊掉那些对话。对你来说,它们只是背景噪音。但是,一旦有人说了你的名字或你特别感兴趣的事情,你的耳朵就会竖起来,进入那个特定的对话。这个信息会超越噪音,因为它对你来说很重要。
同样,在客户体验中加入个人风格,例如,在电子邮件中使用动态收件人姓名标签,可以让企业发出自己的声音,从而在过度拥挤的市场中脱颖而出。
个性化——制胜策略
公司不能再依赖他们的产品和服务作为他们的主要竞争优势;如今,他们只能在提供卓越体验的基础上竞争。
据 Janrain 称,48%的消费者在他们的体验个性化时会花更多的钱,而 74%的人讨厌看到与 T2 无关的内容。那么,这说明了什么是个性化?在客户体验中,个性化是一种成功的策略,可以帮助公司增进与客户的关系。88%的营销人员声称,在实施客户体验个性化策略后,他们的业务有了明显的改善。
然而,只有 33%的企业对他们拥有的适当个性化客户体验的工具有信心。因此,企业如何利用数字化转型赢得客户体验竞赛,而不是因为这个事实而气馁?
这里的指南可以帮助企业为他们的客户创造更个性化的体验,不管他们目前的情况如何。
- 鼓励客户创建用户档案
创建完美个性化公式的基本要素之一是准确和完整的信息。为了获取这些信息,企业鼓励客户在他们的平台上创建用户档案是至关重要的。客户非常乐意让公司跟踪他们的行为,只要这只是用来提升他们的体验。顾客现在希望公司通过他们的个人资料来监控他们的行为,因为超过一半的顾客承认他们希望品牌能预测他们的需求,这样他们就能收到相关的建议。
因此,这个年龄段的客户希望公司:
- 为他们提供更个性化的体验
- 在多个频道上增强 CX
- 给他们有效的建议
据咨询公司麦肯锡估计,高达 35%的亚马逊购买来自推荐。网飞关于个性化的咒语很好地从顾客的角度总结了重要性:个性化=享受最大化+搜索时间最小化。
记住,激励客户建立个人资料的最好方法是让这个过程变得非常简单——不需要在注册表格中有数百个不相关的字段。
2。细分是成功的关键
无论是收集电子邮件还是在社交媒体上制作广告,细分都是关键。对于电子邮件,对电子邮件订户进行细分至关重要,因此只有相关内容才会发送给每个订户。尽管每个注册公司时事通讯的人都可能对该品牌感兴趣,但这并不一定意味着他们有相同的需求。例如,女装打五折与男性电子邮件收件人没有任何关系;对他来说,这是普通的垃圾邮件,没有人喜欢被垃圾邮件。因此,将用户分组或划分到不同的列表中有助于确保没有人被“垃圾邮件”
同样,细分受众可以帮助企业通过广告锁定潜在客户。
3。为未来保存信息—使用基于云的技术实现个性化
同样,用户配置文件在这里是最重要的。公司需要确保他们只要求相关信息来完成一次购买。之后,可以存储这些信息,以便通过任何渠道、在任何设备上、在任何时间加速未来的购买过程。
4。实施地理定位实践
客户的位置可以在几个方面有助于提升来自同一地区的所有潜在客户的客户体验。例如,一家公司可以通过允许网站访问者选择他们的国家来为他们提供定制的 CX。因此,如果它是一个零售电子商店,巴基斯坦人将看到公制计量,而美国人将看到 USCS 的公制计量。位置信息还可以以其他方式使用,如向电子邮件订户发送与天气或特殊场合相关联的报价。
5。听取客户反馈
所有伟大的公司都把客户放在第一位。根据研究,68%的消费者放弃一项业务,因为他们觉得这个品牌不关心他们。
向客户寻求反馈是对的,倾听反馈更好,但是仅仅为了反馈而实施改变并不是一个好主意,因为这不会带来投资回报。然而,如果大部分客户给出了类似的反馈,明智的做法是实施变革,不仅改善流程,还改善客户-品牌关系。
6。让顾客成为个性化过程的一部分
互动过程与个性化策略的融合有助于为顾客创造难忘的体验。即使一些客户没有个人资料,企业仍然可以使用交互工具为他们提供卓越的个性化体验。美宝莲的虚拟“试戴”功能就是一个很好的例子,它允许人们在购买前虚拟试戴化妆品。
Maybelline’s virtual ‘Try It On’ feature
7。不要一直拘谨
保持正式总是好的,但正式往往会使品牌难以与人们联系起来。为了与客户建立个人关系,在撰写内容时使用第一个词的视角极其重要。通过这样做,一个品牌能让它的顾客感觉更舒服,就像他们在和朋友交谈一样。
8。个性化电子邮件
个性化电子邮件内容与分割电子邮件列表一样重要。精心设计完美的主题是成功的电子邮件营销策略的第一步。毕竟,如果没有人打开那封邮件,它很可能是垃圾邮件。在 Inqline,我们使用电子邮件作为渠道,向客户提供个性化和周到的回复,这有助于改善客户体验。我们鼓励我们的团队使用客户的名字,以及感同身受的词语和写作风格,以便我们在保持专业的同时营造一种友爱感。一个很好的例子是,当我们的一位客户以歌曲的形式向我们发送他们的关注时,我们用一首歌来回复,为他创造了一个难忘的客户体验。
定论
我们知道,客户正在迅速转变为聪明的买家,这使得客户体验成为品牌之间唯一的竞争优势。面对激烈的竞争,品牌不断寻找不同的策略来保持客户的忠诚度和参与度。如果执行得当,客户体验的个性化可能是在让客户满意的同时获得更高回报的最可靠方法之一。
(拒绝)来自我的第一次数据科学面试
这一篇写起来有点有趣,可能看起来有点夸张,但我想涉及一个你在媒体上不会遇到的数据科学和机器学习领域。这不是编码教程或另一篇关于人工智能将如何取代你的工作的文章。是我们的老朋友拒绝。
Photo by Raj Eiamworakul on Unsplash
媒体描绘了这样一种看法,即数据科学家和机器学习工程师到处都在被雇佣,以至于有人声称人才短缺。但在现实中,公司正在寻找 1%的高技能数据科学家,你知道,有八年经验的 10 倍工程师,本质上是独角兽。
所以我被一个数据科学面试拒绝了,我正在媒体上写这个。但是这不是一篇令人遗憾的文章,相反,这是一篇有抱负的数据科学家和机器学习工程师有望从中获得一些价值的文章。
提供价值有多种形式;在这种情况下,这是通过我的第一次数据科学面试的经验。因此,我将提供以下一些信息:
- 数据科学/机器学习面试流程的结构
- 某人闯入数据科学/机器学习市场的学术和职业背景(剧透一下,是我)
- 一些资源有助于面试的各个阶段
- 为什么拒绝只是开始
在我们继续之前,我的学术和职业背景是有益的,因为它提供了对进入数据科学行业的个人素质的洞察。主要是,你下一个角色的竞争会是什么样的。
对于机器学习和数据科学相关的职位来说,硕士或博士学位是非常普遍的要求,所以我获得了计算机视觉、机器学习和机器人学的硕士学位。在攻读硕士学位之前,我在软件开发(Web)领域有三年的商业经验,并获得了软件工程本科学位。我在公司和创业公司工作过,也在软件工程(Web)领域担任过一些合同角色。而现在,我目前正在闯入数据科学/机器学习领域。
并非所有的面试都是一样的,但以下是我第一次面试的概要结构:
- 第一阶段 : 30 分钟的电话交谈(大概是检查我是否能沟通并知道一些角色需要的东西)。
- 第二阶段:3-4 小时的技术测试(趣味点,数据科学相关任务,以衡量您的编程能力和机器学习库知识)。
- 第三阶段 : 1 小时的技术测试解决方案演示,之后是一些问答。
前两个阶段很常见,我对此并不陌生,但最后一个阶段让我措手不及。这让我措手不及,因为人们希望我详细说明我将如何度过头三个月。除此之外,我还整理了一份我引以为豪的时髦简报。
我将提供一些见解和技巧,告诉你我是如何度过所有阶段的。希望提供的一些建议对你有所帮助,也许在你的下一次面试中。
第一阶段:电话交谈
电话交谈是我和这家初创公司的一位创始人进行的。这是一次持续约 30 分钟的谈话,内容涉及公司的背景、我的技能和经验,以及双方对未来的期望。
在申请大多数职位时,你和雇主之间的电话交谈是家常便饭。电话交谈的目的是让雇主评估你和你的技能,同时,这也是一个机会让你问一些关于这个职位的问题。谁知道呢,你可能会发现一些你不喜欢的职位的信息。
我为这个阶段准备的最好方法是做以下事情:
- 仔细阅读工作说明书,确保我具备了这个职位所需的所有基本技能
- 研究公司和他们从事的行业。还有,我通过 LinkedIn 对公司内部的团队进行了一些调研。
- 围绕之前的工作和展示该角色所需技能的项目准备谈话要点。
- 我准备了五个在电话交谈中要问的问题,但最后只问了三个。
第二阶段:技术测试(带回家编码作业)
我不会分享太多技术测试的细节,但它有两个任务要完成。
第一项任务是分析 excel 表格中的一些虚拟客户数据,并从这些数据中获得一些见解和发现。我利用标准的数据科学工具和库,如 Pandas、Numpy、Matplotlib 和 Jupyter Notebook 来完成第一个任务。
第二个任务更侧重于使用 Python 和 Flask 的后端实现,伴随着 API 集成任务。
我为技术测试准备的最好方法是做以下事情:
- 没事
你可能会有点困惑,但老实说,我几乎没有什么可以确保我通过技术测试。嗯,除了我每天都在做的事情。就像外面的许多数据科学家一样,我在我的笔记本电脑上花了几个小时在黑暗主题的 Jupyter 笔记本上,试验机器学习库,在 StackOverflow 上搜索答案,从事个人项目,并尝试各种深度学习模型。事实上,这是我通过技术测试所需要的。
如果你没有做我提到的任何事情,那么开始做一些个人项目和探索机器学习库。竞争对手做到了这一点,甚至更多。
第三阶段:演示和问答
最后一个阶段包括讨论用于解决技术测试的方法,讨论您从第二阶段进行的分析中发现了哪些见解,以及您将如何应对前三个月的数据科学角色。所有这些都将在两天内提交给公司的创始人和一位常驻数据科学家。
我讨厌承认这一点,但是一天 8 小时不与他人交流或联系的编码似乎会降低你的社交技能。我的演讲技巧大受影响。
那么一个开发者如何在一夜之间成为 5%的 TED 演讲主持人呢?
嗯,我只是做了以下的事情:
- 我看了这个关于史蒂夫工作介绍的视频
- 然后我看了这个视频,这个视频,还有这个视频(请不要带着烟去面试,而是带着幽默感)
- 最后,我使用 Prezi 创建了一个有望从标准 powerpoint 幻灯片中脱颖而出的演示文稿。
要点:找到一种不同于常规的方法,要么在展示时提供卓越的质量,要么描绘出一种可能不一定被期望的创造力。
仅此而已。
我在准备过程中采取的所有行动和步骤让我通过了面试的所有阶段,并让我处于被考虑担任该角色的位置。
你们中的一些人可能想知道为什么我被这个角色拒绝了,简单的答案是我对需要开发的算法没有直接的经验。这个职位有几个候选人,有些在第一阶段就被淘汰了,有些在技术测试阶段就被淘汰了。最后一个阶段是在我和另一个候选人之间,这个候选人有开发机器算法的经验,可能比我更适合这个角色。
拒绝不是结束,而是开始。拒绝让你知道你的知识、技能和经验有什么差距。所以当你被拒绝时,你要做的就是寻找一个有效的方法来填补这个空缺,这样做,你就离下一个角色更近了一步。
向前看,我将通过探索更多的机器学习算法并在正在进行的项目中利用它们来填补我的空白。请随意评论你的拒绝经历以及你是如何处理的。
面向数据专业人员的关系数据库管理(RDBMS)基础
数据专业人员权威指南
使用 Python SQLite3 和 SQLAlchemy 的基本 RDBMS
Source from Unsplash
数据科学家需要每天与数据库打交道。作为数据分析师和工程师,我们需要精通 SQL 和数据库管理。了解 RDBMS 将有助于我们访问、交流和处理数据。它将允许我们更快、更稳健地存储和过滤替代数据。
在本教程中,我们将学习如何:
- 设置 SQLite 磁盘连接
- 创建具有结构的表
- 将数据框值插入表中
在本教程中,我们将学习在 Python 中执行的两种方法。第一个是使用 SQLite 3,这里我们将使用 Python 和 SQL 来执行每个学习点。但是,我们也将简要讨论一下 SQL 炼金术,它允许我们仅用 4 行代码就能执行这些学习要点。(不开玩笑!)
在此之前,我们先来谈谈 RDBMS
什么是 RDBMS?
一个关系数据库是一种数据库。它使用的结构允许我们识别和访问数据库中与另一条数据相关的数据。通常,关系数据库中的数据被组织成表。法典编纂
关系数据库使用被称为记录的表。这些记录拥有多个列,这些列具有不同的名称和数据类型。然后,我们可以通过使用主键和外键来识别表模式关系,从而在记录之间建立连接。
Data Schema Sample for RDBMS
为什么不只是?csv 或。xlsx 对比 RDBMS (SQL)?
如今,Excel 和 csv 在存储我们的数据需求方面存在许多限制,而 RDBMS 可以解决这些限制:
容量
数据生态系统每天都在变化,今天被认为是大而快的东西,明天可能就不是了。这意味着我们需要一个能够灵活承载大量数据的专用存储。我们需要比 Excel 和 csv 更具可扩展性的存储。RDBMS 是解决方案—它允许基于服务器分布的可伸缩性,而不是基于行数和列数有限的 Excel,048,576 行乘以 16,384 列)。
具有已定义关系的依赖性
RDBMS 允许用户在表之间建立定义的关系。这将给用户一个完整的数据定义画面。例如,在您的购物收据中,您可能有几个实体,如产品描述、商品价格、商店分店位置等。所有这些都可以根据需要进行分离和合并。
分析没有从数据中分离出来
我们现在可以将数据与分析分开存储。在 Excel 中,我们需要管理不同的版本来与您的团队成员协作。每个文件都需要结合不同版本的数据和分析。但是,在 RDBMS 中,我们现在可以使用 SQL 指令分别重现和分析数据。这样,我们可以确保您的团队从中央数据服务器生成更新的数据和分析。
如果您想了解更多信息,请参考这篇 Codecademy 文章。
如果您在工作中使用 Excel 或 Google Sheets 等电子表格应用程序,这些问题可能对您来说很熟悉:它…
news.codecademy.com](https://news.codecademy.com/excel-to-sql-why-switch/)
对于数据专业人员来说,这项技能很有价值。它创建了一个一站式数据存储,每个人都可以从他们的 SQL 指令中获得相同的更新数据。
为什么我们选择 SQLite 而不是 PostgreSQL?
SQLite 为基于磁盘的数据库提供了一个轻量级的 C 库,允许 SQL 处理 CRUD 进程。这意味着我们可以在许多小型应用程序/用例中依赖 SQLite:
- SQLite 用于快速方便的内部数据存储
- SQLite 快速开发小型原型
- 在通过 PostgreSQL 或 Oracle 迁移到更大的数据库之前,SQLite 托管概念证明(POC)。
PostgreSQL 是一个非常先进的开源数据库,提供专用的数据服务器来运行其数据库。但是,SQLite 提供了不需要专用数据服务器的轻量级设置。
如果我们的数据需求包括适当的管理和安全性,那么 PostgreSQL 将是合适的选择。否则 SQLite 也行。
[## SQLite 与 PostgreSQL——使用哪个数据库,为什么?
SQLite 和 PostgreSQL 是最广泛使用的关系数据库管理系统(RDMS)。他们都是…
tableplus.io](https://tableplus.io/blog/2018/08/sqlite-vs-postgresql-which-database-to-use-and-why.html)
为了构建本文的 POC,我们将使用 SQLite。但是可以尝试使用 PostgreSQL。
将来自 Lazada 的数据提取插入 SQLite
问题陈述
我们将重用从 Lazada 中提取关键产品信息的问题。我们将把它导出到 SQLite 数据库,而不是导出到 csv。
product_df to store scraped information at Lazada Website
如果你对此不熟悉,请随意浏览我下面的文章。
[## 10 分钟内:为数据专业人员提供美味汤和硒的网络刮擦
使用 BS4 和 Selenium 快速提取关键信息
towardsdatascience.com](/in-10-minutes-web-scraping-with-beautiful-soup-and-selenium-for-data-professionals-8de169d36319)
对于本教程,我们将首先使用 SQLite3 来生成到 SQLite 引擎的连接。这将允许我们执行 SQL 命令来插入值。之后,我们将研究 SQLAlchemy 来缩短和简化这个过程,而不需要创建任何 SQL 命令。
Python SQLite3
连接到 SQLite 磁盘
我们首先建立到磁盘文件 lazada.db 的连接,这是 SQLite 引擎用来存储数据的磁盘。如果 lazada.db 不存在,它将创建一个新的,下次我们可以连接它。
import sqlite3
conn = sqlite3.connect("lazada.db")
c = conn.cursor()
注意,当我们打开连接时,我们也建立了一个游标。数据库游标是一种遍历数据库记录的工具。使用这个游标,我们可以创建表并在数据库磁盘中执行 SQL 命令。
创建 lazada_product 表
在将我们的 SQLite3 连接到 lazada.db 之后,我们将使用游标执行 SQL 查询并创建 lazada_product 表。我们将我们的元数据标识如下。
c.execute('''
CREATE TABLE lazada_product (
time date_time ,
id **INTEGER** ,
link **TEXT** NOT NULL,
product_title **TEXT** NOT NULL,
product_price **DOUBLE** NOT NULL,
category **TEXT** NOT NULL,
PRIMARY KEY (time, id)
);
''')
注意我们是如何将 time 和 id 指定为主键的。这意味着每一行都有唯一的 id 和日期时间。如果我们插入具有相同 id 和日期时间的行;SQLite 会抱怨并返回一个重复的错误。这种验证有助于防止不干净的冗余数据进入数据库。
将 df 行插入 lazada_product 表
让我们将提取的 product_df 插入到 lazada_product 表中。
def write_from_df_with_sqlite3(df):
for index, row in df.iterrows():
c.execute(
'''
INSERT INTO lazada_product VALUES
(*CURRENT_TIMESTAMP*,?,?,?,?,?)
''',
(row['id'], row['link'],row['product_title'],row['product_price'],
row['category'])
)
一旦运行这个方法,您将成功地将每个值转储到您的 lazada_product 表中。
祝贺您,您已经创建了 RDBMS 表并向其中插入了数据
注意,SQLite3 Python 有一个限制。当您将 SQL 命令和 Python 代码组合在一个文件中时,代码可能很难阅读。它看起来也很冗长。
因此,我们将看看如何使用 SQLAlchemy 以一种更短的、无 SQL 的方法来执行表和数据插入。
Python 对象关系映射器(ORM) SQLAlchemy
SQLAlchemy 是一个激活数据库引擎的 Python ORM。它在 SQLite 的 SQL 执行之上创建了一个 pythonic 包装器。这允许您在不接触任何 SQL 命令代码的情况下对表运行逻辑。
什么是对象关系映射器(ORM)?
ORM 提供了一个高级抽象,允许开发人员编写 Python 代码来调用数据库中 CRUD 和模式的 SQL。每个开发人员都可以使用他们熟悉的编程语言,而不是处理 SQL 语句或存储过程
连接到 SQLite 引擎
from sqlalchemy import create_engine
disk_engine = create_engine('sqlite:///lazada_alchemy.db')
创建 lazada_product 表并插入 df 行
def write_from_df_with_alchemy(df):
df.to_sql('lazada_product', disk_engine, if_exists='append')
看看这段代码有多简洁。运行这个方法后,我们立即根据 df 数据类型创建带有默认设置的表。同时,我们将把值追加到 lazada_product 表中,而不涉及任何 SQL。
因此,SQLAlchemy 最大的优点是促进 SQL 命令的高级抽象,以帮助 Python 开发人员使用同一种语言提取数据。
执行 SQL 而不运行 SQL 查询。— SQLAlchemy
当然,这不应该取代懂 SQL 语言的重要性。我们可以用 SQL 更好地处理更多的复杂性。然而,要对数据表的设置和插入进行编码,SQLAlchemy 将为您节省大量时间和精力。
访问我们的 SQLite 磁盘
为了检查我们磁盘的内容,我们可以使用下面的 Web Dashboard 工具。
[## SQLite 浏览器- SQL Online
JavaScript 上的 SQL 在线。用户友好的界面。不下载,不安装。在线测试 SQL 脚本…
sqliteonline.com](https://sqliteonline.com/)
从这里,您可以将磁盘作为文件插入,并编写一个简单的 SQL select 语句。
SELECT * from lazada_product
单击 run,这将显示您在 lazada_product 中的所有数据。
The results after inserting lazada_product inside the table. In total there are 108 products appended
恭喜你,你已经学会了 RDBMS 和使用 Python SQLite3 和 SQLAlchemy 插入值
结论
- RDBMS 为 csv 或 excelsheet 提供了许多好处,因为它具有更大的容量、依赖性检查以及分析和数据的分离
- 创建一个简单的 RDBMS 并不需要太多时间,我们可以使用 SQLAlchemy 来创建模式,只需用的 4 行代码。
- 我们可以通过使用 SQLite 浏览器在线或下载 Linux 或微软 SQLite 浏览器来恢复读取和 CRUD 操作。
目的、Github 代码和您的贡献
美汤硒网刮。为 VincentTatan/Web 抓取开发做出贡献,创建一个…
github.com](https://github.com/VincentTatan/Web-Scraping/tree/master/Selenium Web Scraping)
请随意克隆存储库并做出贡献。
最后…
我真的希望这是一本很棒的读物,是你发展和创新的灵感来源。
请在下面评论出来建议和反馈。
快乐编码:)
关于作者
Vincent Tatan 是一名数据和技术爱好者,拥有在 Visa Inc .和 Lazada 实施微服务架构、商业智能和分析管道项目的相关工作经验。
Vincent 是土生土长的印度尼西亚人,在解决问题方面成绩斐然,擅长全栈开发、数据分析和战略规划。
他一直积极咨询 SMU BI & Analytics Club,指导来自不同背景的有抱负的数据科学家和工程师,并为企业开发他们的产品开放他的专业知识。
请通过LinkedIn、Medium或 Youtube 频道 联系文森特
验证人群健康慢性指标之间的关系
糖尿病、慢性肾病和心血管疾病之间的联系
在的最后一个故事中,我们开始研究美国疾病控制和预防中心(CDC)15 年的慢性病数据集。探索性数据分析始于理解数据的列和行,以及与进一步分析相关的内容。
在这篇文章中,我们将深入理解这 40 万行和 17 个主题类别,这需要将数据帧转换成数据透视表汇总和可视化的格式。在看了前面的 df_new.head()之后,我认为我们不会使用下面的列,这导致了 15 列的较小集合:
df_new = df_new.drop(columns=['YearEnd','LocationDesc','DataSource','DataValue','DataValueFootnoteSymbol','DatavalueFootnote','LowConfidenceLimit','HighConfidenceLimit','GeoLocation'])<class 'pandas.core.frame.DataFrame'>
RangeIndex: 403984 entries, 0 to 403983
Data columns (total 15 columns):
YearStart 403984 non-null int64
LocationAbbr 403984 non-null object
Topic 403984 non-null object
Question 403984 non-null object
DataValueUnit 374119 non-null object
DataValueType 403984 non-null object
DataValueAlt 273666 non-null float64
StratificationCategory1 403984 non-null object
Stratification1 403984 non-null object
LocationID 403984 non-null int64
TopicID 403984 non-null object
QuestionID 403984 non-null object
DataValueTypeID 403984 non-null object
StratificationCategoryID1 403984 non-null object
StratificationID1 403984 non-null object
dtypes: float64(1), int64(2), object(12)
表 1:按主题、问题和值汇总
使用数据透视表(很像 Excel),让我们总结每个问题及其相关值。为了通知每个问题和值,我们将从每个问题的类别(主题)、问题 ID、问题、数据单元(数据值单元)以及与稍后的分层相关的数据类型(数据值类型)创建多个索引。Pandas Pivot_table 需要数值,默认为平均值(numpy.mean)。此外,我已经删除了 LocationID 和 YearStart 列,因为我以后不会使用它们,并且为了可读性,将其四舍五入为两位小数:
df_QD = df_new.pivot_table(index=['Topic','QuestionID','Question','DataValueUnit','DataValueType'],columns=None,dropna=True)df_QD.drop(columns=['LocationID','YearStart']).round(2).head(25)
Table 1. Pivot Table showing the Question and Values
表 2:使用带有分层、问题和值的 Groupby】
除了 pivot_table,我还可以使用 groupby()创建一个类似的汇总表。我想在生成的数据帧中展示更多关于分层的信息。
df_unittype_table1 = df_new.groupby(['Topic','QuestionID','Question','StratificationID1','Stratification1','DataValueUnit','DataValueType']).mean().round(2)df_unittype_table1.drop(columns=['YearStart','LocationID'])
Table 2. Using groupby() to summarize stratification
表 3:按问题和地点汇总
一种有趣的方法是用数据值按每个状态(LocationAbbr)显示数据。下面的数据透视表包括额外的索引,这些索引为诸如单位和类型之类的数字提供了上下文。
df_new_qloc = df_new.pivot_table(values='DataValueAlt',index=['Topic','QuestionID','Question','DataValueUnit','DataValueType'], columns='LocationAbbr',aggfunc='mean',dropna=True).round(2)
Table 3. Pivot Table of Question and Location
可视化所有指标之间的相关性
现在,我们已经看到这些表格按问题、分层和位置呈现数据值。那还是很多信息啊!我们先来了解一下问题指标本身说明了什么。每对问题指示器之间有什么关系?这就是数据可视化将描绘出一幅理解整体关系的图画的地方。
最初,我使用表 3 中的 pivot_table,但是轴标签太长了,很难阅读。稍微倒退一下,我们将基于新的列问题创建一个不同的 pivot_table (df_new_qloc2 ),取问题的前 37 个字符:
df_new['QuestionAbbr'] = df_new['Question'].str[:37]df_new_qloc2 = df_new.pivot_table(values='DataValueAlt',index=['Topic','QuestionID','QuestionAbbr'], columns='LocationAbbr',aggfunc='mean',dropna=True).round(2)
通过转置 df_new_qloc2 数据透视表,我们准备应用关联方法。corr()并将数据可视化。使用来自 seaborn 文档的代码,我们可以绘制一个相关矩阵热图。这使每一对指标可视化,以了解正相关对位于何处。由于相关矩阵会在对角线的上方和下方产生重复的视图,为了简单起见,我们将通过使用 np.zeros_like()创建一个零数组并使用 triu _ indices _ from()返回对角线上方区域的索引来屏蔽热图的上半部分。使用 matplotlib,我们设置了一个大的图形尺寸,以允许在 jupyter 笔记本上放大。cmap 为图形设置色彩映射表(更多选项此处)。最后,sns.heatmap()使用遮罩呈现热图。
# Table 4 - Using Table 3 with question indicators as columns
new_qloc2_corr = df_new_qloc2.transpose().corr()# Generate a mask for the upper triangle
mask = np.zeros_like(new_qloc2_corr, dtype=np.bool)
mask[np.triu_indices_from(mask)] = True# Set up the matplotlib figure
f, ax = plt.subplots(figsize=(150, 150))
f.suptitle('All Chronic Indicators Correlation Heatmap', x=0.4,y=0.85,fontsize=150)
ax.tick_params(labelsize=50)# Generate a custom diverging colormap
cmap = sns.diverging_palette(190, 10, as_cmap=True)# Draw the heatmap with the mask and correct aspect ratio
sns.heatmap(new_qloc2_corr, mask=mask, cmap=cmap, vmax=.3, center=0,square=True, linewidths=2, cbar_kws={"shrink": .3})
Figure 1. All Indicators Correlation Heatmap (Higher Correlation in Pink)
即使做了一些调整,信息也是密集的,可以更方便用户阅读(我们将在下一篇文章中解决这个问题)。尽管如此,热图轴显示了主题、问题 ID 和缩写问题 QuestionAbbr。我们可以看到一些粉红色的区域正相关程度更高,绿色的区域负相关程度更高。从视觉上看,心血管疾病(CVD)和癌症(CAN)的某些领域似乎具有更高的相关性。看到这个演示很有帮助,但最终,我们希望通过创建一个顶级相关性列表来获得更细粒度的外观。
表五。指标对顶部关联表
仅从 df_new 中取出 QuestionID、LocationAbbr 和 DataValueAlt,我创建了 new_qloc2_1_corr 表。使用线性代数,我们可以通过将 new_qloc2_1_corr 相关数据帧和与先前数据帧形状相同但值为 1 的数组的下半部分相乘来对数组进行矢量化。的。stack()将数组放入一个列表中。sort_values()将列表按降序排序。Top_corr 由大约 36k 项组成。
top_corr = (new_qloc2_1_corr * np.tril(np.ones(new_qloc2_1_corr.shape),-1)).stack().sort_values(by=['DataValueAlt'],ascending=False)
通过几个额外的步骤来重置索引,更改列名,并根据 QuestionID 添加几个新列,我们就有了一个包含顶部相关对的数据框架。由于主题有许多重复对,我将删除重复项,不包括主题类别的相同指标对,这样会产生大约 33k 个项目:
top_corr_pair_dd = []for row in range(len(top_corr_pair)): if top_corr_pair.loc[row]['Topic1'] != top_corr_pair.loc[row].
['Topic2']:
top_corr_pair_dd.append(top_corr_pair.loc[row])
Table 5. Top Correlation by Topic Descending
在这一点上,我们看到了指标中出现的主题。表 5 向我们展示了基于主题类别的特定模式。例如,慢性肾病(CKD)和心血管疾病(CVD)中的那些问卷(QID1 和 QID2 列);慢性肾病和糖尿病患者(DIA);CVD 和 DIA 内的那些;总体条件内的指标(OVC)和先前指标;最后,患有 DIA 和 CVD 慢性阻塞性肺病(COP)的患者。
总的来说,我们看到 CVD、CKD 和 DIA 等指标之间的关系,这有意义吗?
心血管疾病包括许多与心脏相关的疾病,包括心律失常(不正常的不规则心脏跳动)、高血压(对动脉壁的高作用力)、心脏骤停(功能突然丧失)、冠状动脉疾病(主要血管受损)和充血性心力衰竭(心脏泵血不畅的慢性疾病)。这是一种非常常见的疾病,源于血管堵塞,影响着四分之一的美国人。据 CDC 称,增加这种疾病的风险因素包括饮食、肥胖、糖尿病、过度饮酒和缺乏锻炼。
慢性肾脏疾病是肾脏及其功能丧失导致衰竭的长期疾病,也称为终末期肾脏疾病(ESRD)。这也是一种常见的疾病,影响着七分之一的美国人。根据梅奥诊所的说法,增加这种疾病的风险因素包括糖尿病、高血压、吸烟、心血管疾病、老年和某些种族背景。在肾病患者中,心血管疾病倾向于“诊断不足和治疗不足”(S,Hernandez GT。慢性肾脏疾病和心血管疾病之间的联系。 J 肾病学。2014;3(3):99–104.).根据美国肾脏基金会的说法,当肾脏的功能没有达到最佳状态时,这需要心脏和心血管系统更加努力地工作。
糖尿病与体内葡萄糖失调有关,包括一些疾病,如 1 型、2 型和妊娠糖尿病。虽然 1 型糖尿病的原因不明,如家庭背景和环境,但妊娠期糖尿病通常伴随着妊娠而来。二型糖尿病与上述疾病有相似的风险因素,包括缺乏锻炼、年龄、家庭背景、高血压、体重、多囊卵巢综合征和胆固醇/甘油三酯水平异常(来源:梅奥诊所)。患有糖尿病会导致各种并发症,包括心血管和慢性肾脏疾病。
答案是肯定的!该数据集与文献一致,表明心血管疾病、慢性肾病和糖尿病之间存在高度相关性。
在本系列的最后一篇博文中,我们将继续深入了解以下内容:
- 首要条件是什么?
- 具体的顶级指标还有哪些亮点?
- 按年份和分层我们能看到什么趋势?
希望你喜欢读到这里,并随时给我一些想法和建议!
相对与绝对:如何进行成分数据分析?第二部分
这是我早先关于成分数据分析的文章的延续,在那篇文章中,我展示了将成分数据视为绝对数据而不是相对数据的缺陷。在这篇文章中,我将总结我们可以用来正确分析成分数据的技术,并用具体的例子展示使用 RNA-Seq 数据。
有两种主要策略用于处理成分数据,特别是 NGS 数据:
1。归一化以取回绝对计数
2。成分数据分析(CoDA)方法,在样品参考范围内转换数据(例如:ALR、CLR)
绝对计数标准化
当需要跨样本比较时,这是 NGS 数据预处理中最广泛使用的技术。相对读取计数被“标准化”为总读取深度,以“恢复”绝对计数。然而,当 RNA 或细胞的总绝对量或相关生物材料的量在样品间显著变化时,这不能恢复绝对计数。这通常会给分析人员带来错误的安全感,并导致将这些“标准化”样品视为绝对计数。在样本间进行比较时,这可能会导致错误的结论。让我们用模拟数据来证明这一点。
模拟细节
这里,我模拟了 100 个基因的数据,其中
a. 5 个基因在对照和实验条件之间具有 1 的真实对数倍数变化(在选择下接近耐受或不生长);
b . 2 个基因在实验条件下具有与> 1 相同的真实对数倍数变化(在选择下耐受并表现出生长);
c . 2 个基因在实验条件下具有与< 1 相同的真实对数倍数变化(不耐受或耐受),
我模拟了其余 91 个基因的不同比例发生变化的 5 种不同情况。在发生变化的基因中,约 90%被耗尽,约 10%被富集。
其他基因的缺失/富集影响相对计数值和读取深度标准化计数,即使总读取深度固定在 200K 读取
读取深度标准化(RDN)计数
- 差异表达或丰度:即使所有读数具有相同的总深度(计数之和),使用读数深度标准化计数(RDN 计数)计算的基因对数倍数变化(LFC)与真实的对数倍数变化相比有所偏移(见下图 1)。有趣的是,转变的方向并不总是可以根据基因改变的比例来预测的。例如,当大约 70%的基因改变时,使用 RDN 计数计算的 LFC 与真实的 LFC 相比下移。另一方面,当 90%的基因改变时,使用 RDN 计数计算的 LFC 与真实 LFC 相比向上移动。这是因为前一种情况下的绝对真实计数高于后一种情况。一般来说,我们无法预测或估计样本的真实总绝对计数。
Fig 1: Comparing True Log-Fold Changes to Log-Fold Changes Calculated using RDN Counts
2。基因之间的相关性:看事物如何在相对计数和绝对计数之间进行比较。,我计算了所有 5 个样本中非恒定基因的相关性(每个样本都有 0.1、0.2、0.4、0.6、0.9 个比例的变化基因)。在 200K 读取深度下,我使用了真实计数和使用聚酯模拟计数数据的相对计数。
Fig 2: Comparing True Correlations Between Genes to Correlations Calculated using RDN Counts
从上图可以看出,使用 RDN 计数计算的一些相关系数与真实相关系数有显著差异,存在负偏差。
上面的两个例子显示了使用 RDN 计数来估计基因之间的差异表达或相关性的缺陷。当试图从相对组成数据中恢复绝对计数时,应始终使用加标控制,而不是使用 RDN 计数。接下来我们将展示这一点
峰值标准化计数
为了真正校正绝对计数的变化,我们需要在测序步骤之前以相同的丰度(数量)添加到所有样品中的掺入对照或基因。这样做可以将所有样本标准化到相同的总丰度级别,并使比较正确。这仅在数据由于测序而关闭时有效(因为我们是在测序之前添加掺入物),如果约束是生物学的或者发生在测序步骤的上游,这将没有帮助。在这种情况下,我们需要在这个约束步骤之前添加尖峰,但是由于添加尖峰的物理和生物限制,这并不总是可能的。
让我们用我们的数据来看看这是如何工作的。在我们的数据中,我们有 92 个不同的对照或掺入基因,它们具有真正的绝对丰度。让我们使用这些来“标准化”数据,从而使所有样本达到相同的绝对计数范围。
- 差异表达或丰度:下面的图 3 类似于图 1,但是用掺入标准化计数代替 RDN 计数。该图添加了人工抖动(噪声)来显示所有数据,但真实数据都位于对角线上。这表明了插队的力量。如果刚好在导致数据闭合或约束的步骤之前添加尖峰信号,则适当设计的尖峰信号可以恢复绝对计数(达到常数乘法因子),但这并不总是可能的。
Fig 3: Comparing True Log-Fold Changes to Log-Fold Changes Calculated using Spike-in Normalized Counts
2.基因之间的相关性:查看基因之间的相关性,我们看到使用尖峰标准化计数计算的系数可以恢复真实的系数。下图 4:
Fig 4: Comparing True Correlations Between Genes to Correlations Calculated using Spike-in Normalized Counts
看来我们找到了解决问题的方法。我们所要做的就是添加一些控制,我们很好!不幸的是,没那么快。在这个模拟的案例中,组成数据的闭合来源是测序,我们能够在模拟测序数据之前添加一些控制。在现实生活的数据生成过程中,闭包的来源可以出现在提取 DNA/RNA 的通常复杂的工作流程中的任何地方。此外,生物系统本身可能是固有组成的(例如,细胞产生 RNA 的能力是有限的),在这种情况下,细胞外引入的尖峰信号不能恢复真实的绝对计数。
成分数据分析(CoDA)方法
一种替代掺入归一化的方法是使用 CoDA 方法,这种方法通常根据样本内参考转换计数数据。加法对数变换(ALR)和中心对数变换(CLR)是一些常用的尾波变换的例子。这些方法最初是由 John Aitchison 在 1986 年提出的。核心思想是组件相对于另一个参考组件的对数比变换可以被视为任何其他无约束数据。这将数据从原始的单纯形空间(如我们在第一部分中的三元图)转换到欧几里得空间。这使得我们可以对这些数据使用所有经典的分析技术。
注意:这些技术并不像前一节中的“规范化”方法那样要求开放数据。这些技术也适用于所有数据,无论是相对数据还是绝对数据。另一点需要注意的是,使用尖峰信号进行归一化与使用加性对数比(ALR)变换是一样的。使用一般 ALR 变换的好处是,即使我们没有样品间丰度恒定的掺入,它也是适用的。一般 ALR 变换的缺点是,我们需要正确选择基准电压源,以理解数据并回答相关问题。现在让我们使用和以前一样的数据集来更详细地看看 CoDA 方法。
1。差异表达或丰度:有许多方法可以发现处理前后成分数据的变化。令人惊讶的是,这些方法中有许多来自微生物组文献,而基因表达文献主要依赖于传统方法,如 DESeq2 和 EdgeR ,这些方法没有明确考虑数据的组成性质。DESeq2 和 EdgeR 隐含地假设绝对丰度不会因处理而改变。这相当于使用 CoDA 方法的中心对数比(CLR)转换。这种转化使用基因或组分的几何平均值作为参照,因此所有结果都必须根据几何平均值来解释。在这个阶段,很容易将这种假设解释为基因的几何平均值在对照组和治疗组之间没有变化。也许几何平均数改变了,也许没有,除了来自测序的相对计数之外,没有正交信息,没有办法确切知道。DESeq2 和其他差异表达工具的大多数用户都落入了这个陷阱,并认为算法调用的任何重大变化都意味着绝对计数的重大变化。相反,这些只是相对于所有组件的几何平均值的显著变化。
有一些新兴的方法将统计学的严谨性应用于成分数据中的 DA。最流行的方法是 ALDEx2 和 ANCOM 。这些方法的主要原理是依靠相对于参考成分的转换相对数据的对数比测试,并仔细解释这些结果。这些方法的主要问题是只能根据所选的参比来解释结果,并且没有提供如何选择参比的指导。朱利亚诺·克鲁兹给我介绍了一种更近的方法,这种方法使用了差异排名(DR)并提出了一种更合理的选择参考的方法。这是我将在这里简要使用的,并希望在将来的某个帖子中深入到运行这些算法的血淋淋的细节。
DR 的主要思想是选择一些随机参考成分来计算治疗和对照中所有成分的对数比。在下一步中,这些成分按照它们在处理和控制条件之间的差δ(对数比)的顺序排列。使用已知相对计数计算的δ(对数比)值的等级顺序应该与使用未知真实绝对计数计算的δ(对数比)值的等级相同。例如,对于 90%的基因差异表达的情况,我在下面显示了使用相对计数计算的δ(对数比)值与使用绝对计数计算的δ(对数比)值:
Fig 5: Δ(log-ratio) values Calculated using Absolute vs. Relative Counts
如您所见,δ(对数比)值的大小因我们使用相对计数还是绝对计数而异,但δ(对数比)值的等级保持不变。这并不意味着排名靠前的基因在治疗中的数量高于对照组,而排名靠后的基因数量较低。可能发生的情况是,与对照条件相比,在治疗条件下,排名靠前的基因已经耗尽了绝对计数,但是在治疗条件下,排名靠后的基因的耗尽甚至更糟。简而言之,我们不能说治疗和病情之间的绝对读数有什么变化。
我现在将选择排名第一的基因作为我的参考,并使用这个新的参考再次计算δ(对数比)值。
Fig 6: Δ(log-ratio) Values Calculated using the Top-Ranking Gene as Reference
从该图中,我们可以使用 0.5 的任意截止值,并选择超过该值的任何基因作为我们的潜在 DA 基因进行进一步测试。当然,如果我们想测试更多的基因,我们可以放宽截止日期。
另一个避免选择参照的建议是在人群中建立某种阳性或阴性对照。假设,我们知道一个在治疗条件下绝对丰度会增加的基因,那么我们可以使用这个基因作为计算对数比的天然参考,并对δ(对数比)值进行排序。任何大于 1 的对数比意味着该基因优于阳性对照,而小于 1 的对数比意味着比阳性对照差。更好的是,有 2 个对照来限制效应大小,并参照这两个基因来解释对数比。
在我的模拟中,我每次复制只有一个样本,因此无法进行任何统计分析。在以后的文章中,我将为每个条件生成多个重复,并使用 ALDEx2、ANCOM 和 DR 算法来测试它们的灵敏度和特异性。
2.基因之间的相关性:如本系列第 1 部分所示,相关性不是亚组成连贯的,因此不遵循 CoDA 的原则之一。简而言之,任何两个基因之间的相关系数取决于数据中存在的其他成分或基因。Aitchison 首先提出使用对数比转换值的方差(VLR)来估计两个变量的相关性。例如,为了计算跨 n 个样本的特征或基因 g 和 h 之间的相关性,我们将使用:
VLR 是子成分相干的,因此不会导致伪相关。使用 VLR 的主要问题是,即使当基因 g 和 h 完全相关时,它等于 0,但当基因完全独立时,它没有上限。由于这个比例问题,很难将 VLR 的一个基因对与 VLR 的另一个基因对进行比较。基于 VLR 提出了几种方法/度量来估计组合之间的依赖关系,最著名的是 SparCC、SPIEC-EASI 和比例。在这篇博客中,我只是稍微详细地回顾一下比例。所有这些方法都试图使用 VLR 来导出类似于相关系数的度量,因此可以在不同的成分对之间进行比较。
基于洛弗尔等人的工作,在 R 包 propr 中提出了三个基于比例的度量标准。艾尔。和奎恩等人。艾尔。这些指标是根据对数转换数据计算的。定义见 propr 包。下面的 Ai 是指数据中基因或成分“I”的对数转换值。Ai 可以是绝对计数或相对计数,这些定义仍然适用。
- phi(φ)= var(Ai-Aj)/var(Ai)
- ρ(⍴)= var(ai-aj)/(var(ai)+var(aj))
- phis(φs)= var(Ai-Aj)/var(Ai+Aj)
与传统相关系数最接近的度量是 rho,范围从-1 到 1。phi 是无界的,可以从 0 变化到 Inf,phis 是 phi 的对称变体,是 rho 的单调函数。在博客的其余部分,我将重点关注 rho。
a .使用绝对计数 :如果我们有一个尖峰控制,我们可以从相对计数恢复绝对计数。由于我们已经有可用的峰值数据,我将使用峰值转换后的数据计算 rho 值,即使用峰值 TPM 计数作为归一化计数的基因 1 的 A = log(TPM _ counts/Spike _ TPM _ counts)。这将恢复原始绝对计数。现在,我们可以使用上面的等式计算ρ值。我将绝对计数和 rho 值之间的相关性绘制如下:
Fig 7: Correlations of True Absolute Counts Between Genes vs. Rho Values Calculated using Spike-Normalized Data
从该图中可以看出,使用比例关系,我们可以捕获真实绝对计数之间的大部分原始相关性。当然,这是一个虚构的例子,我们有一个很好的 spike-in 来检索绝对计数。即使有了这个人为的例子,我们仍然可以看到真实的相关性和使用峰值归一化计数计算的比例值之间的一些差异。这是由于基于比例的度量的计算方式使得它们对对数变换值的方差估计极其敏感。这里我们只有 5 个样本来计算方差,在大多数情况下,前 3 个样本具有相同的值。我怀疑这导致了计算分解指标的公式。我得多琢磨琢磨这个。这一假设的证据是,如果我们只寻找在至少 4 个不同样本中具有不同值的分量,则相关值和比例度量匹配得相当好,如下所示:
Fig 8: Correlations of True Absolute Counts Between Genes vs. Rho Values Calculated using Spike-Normalized Data: Only for Genes with At Least 4 Distinct Values out of 5 Samples
一般而言,rho 和其他基于比例的度量具有良好的精度和较差的召回率,并且具有更多样本给出了对方差的更好估计,因此给出了 rho 值的更好估计。此外,引导通常用于建立一个重要关系的界限。例如,在上面的图中,重要“rho”值的临界值可能是 0.75。
b .使用相对计数 :这个世界复杂得不公平,不幸的是,我们身边通常没有一个好的替代物可供我们使用😢。因此,我们必须使用相对数据,或者更具体地说,加性对数转换(ALR)相对数据。或者,如果我们确信样本间计数的几何平均值不会改变,我们可以使用中心对数变换(CLR)(我们知道这不适用于此处的模拟数据)。本质上,在这种情况下,我们能做的最好的事情就是计算相关数据之间的关系。因此,让我们比较相对数据(相对于选择的参考基因)的 rho 值与真实绝对计数之间的相关性。下图显示了使用 2 个随机选择的参考基因计算的相对计数之间的相关性:
Fig 9: Correlations of True Absolute Counts Between Genes vs. Rho Values Calculated using 2 randomly chosen reference genes
从上面的图中可以明显看出,参考基因的选择对我们称之为成比例的基因对产生了巨大的影响。我们无法事先知道如何选择比例值的截止值,以确保精确度和召回率之间的良好平衡。Aitchison 提出的 VLR,他的公式在这篇文章的前面已经展示过了,不会有这样的问题,因为当我们取一个基因对中的两个基因的对数比时,参考被抵消了,但是我们不能用 VLR 来比较基因对,因为它没有一个可解释的尺度。不幸的是,我们又回到了起点。这在数学上用 Erb 和 Notredame 来解释。另一种选择是不去考虑比例本身,而是计算不同条件下的微分比例。要做到这一点,我们只需要比较不同条件下的基因对,VLR 就足够了,我们不必担心缩放。这篇文章已经太长了,这可能是另一篇文章的讨论。此外,现在我已经看到了基于比例的度量的问题,其他方法,如 SparCC 似乎是一个不错的选择,至少尝试一下。再说一次,也许是为了另一篇文章。总的来说,对于成分数据,基于比例的度量提供了一种有趣的替代基于相关性的度量,但在缺乏良好的加标控制的情况下解释这些数据是很棘手的。
外卖食品
总之,在没有加标控制的情况下,没有从相对数据中恢复绝对计数的灵丹妙药。然而,学习 CoDA 方法帮助我更好地理解解释成分数据的细微差别。我认为这类似于贝叶斯统计和频率统计,前者迫使从业者以先验的形式列出所有的假设。在 CoDA 方法的情况下,选择参考迫使用户警惕对数据的错误解释。
你可以在这里找到这篇文章和之前的文章的所有代码和数据:https://github.com/kimoyerr/CODA
相对与绝对:用模拟理解成分数据
我在工作中经常被要求做的一件事是比较不同样本的 ngs 数据。这些可能是复制,也可能来自完全不同的环境或处理步骤。我们都直觉地理解这些数据总是受到测序深度的限制,因此需要仔细地得出结论。直到我看到 @ WarrenMcG 的这篇论文的预印本,我才缺乏分析这些数据的词汇或技术。这开始了几天对成分数据的深入挖掘,我生成了一些合成数据,以便更好地理解其中的细微差别。在这篇文章中,我试图展示我所学到的东西,并希望有助于传播将组成数据视为常规无约束数据的危险。
什么是成分数据
成分数据是指数字构成整体比例的任何数据。例如,你将一枚硬币抛 10 次,得到的正面和反面的数量就是成分数据。这些数据的主要特征是它们是“封闭的”或受限的,如果我告诉你我们通过投掷双面硬币得到了 6 个正面,你就知道有 4 个反面,而我没有给你提供任何进一步的信息。从概率的角度来说,这意味着数据中的所有成分并不是相互独立的。因此,组成数据不存在于欧几里得空间中,而是存在于一个称为单形的特殊约束空间中。对于那里的工程师来说,每次绘制多相平衡图时,你可能会遇到单纯形图,就像这里使用 R 库三元绘制的水的多相平衡图一样:
本质上,一个特定的固定量的水可以在不同的条件下存在于不同的相中,但是蒸汽、液态水和冰的总量应该总是等于我们开始时的固定量。成分数据存在于比我们想象的更多的地方。一些例子包括投票数据,食品标签上的营养信息,你呼吸的空气中不同气体的比例,甚至你屏幕上像素的 RGB 值。
将成分数据视为无约束数据的问题
根据 Aitchison ,一般来说,任何成分数据分析方法都应满足 4 个不同的标准。传统的分析通常不能满足所有这些要求,因此会导致错误的结果。我将用模拟数据来说服我自己,希望你能理解传统分析方法的这些缺陷。我使用absimseq生成一些虚拟的 RNA-seq 之类的数据。简而言之,我有 4 个来自控制条件的样本和 4 个来自处理条件的样本。每个样本由 100 个天然基因和 92 个刺突(对照)基因组成,样本中所有基因的计数总计约 20K 个读数。与对照条件相比,模拟处理条件具有 20%的差异表达的天然基因(用于描述细胞/组织内基因拷贝数变化的奇特生物学术语)。差异表达的确切大小与我们在此试图证明的无关。既然我们已经建立了数据,让我们继续讨论传统分析方法在处理成分数据时通常无法考虑的 4 个标准。
你可以在这里找到我使用的所有数据和代码:https://github.com/kimoyerr/CODA.git
比例不变性
组成数据的一个共同属性是它们可以用不同大小的向量来表示。空气由 78%的氮气、21%的氧气和 1%的剩余体积组成。在向量符号中,这可以写成[78,21,1]。就体积的百万分率(ppmv)而言,这也可以指定为[780840、209460 和 9780]。尽管这些符号非常不同,但它们代表了相同的物理样本。然而,传统的分析方法,如欧几里德距离和层次聚类,会被这种表示上的差异所迷惑。让我们用模拟的 RNA-Seq 数据来证明这一点。在 R 中,执行以下操作:
load('sim_counts_matrix_100.rda')
orig.dist <- dist(t(counts_matrix))orig.dendro <- as.dendrogram(hclust(d = dist(t(counts_matrix))))
# Create dendro
dendro.plot <- ggdendrogram(data = orig.dendro, rotate = TRUE)# Preview the plot
print(dendro.plot)
Clustering of original data
正如所料,我们看到四个对照样品(样品 1 至 4)聚集在一起,四个处理样品(样品 5 至 8)聚集在一起。
现在让我们缩放一些不同的样本,如下所示。例如,如果您对一些样品进行了比平时更高深度的测序,但仍想一起分析所有样品,就会发生这种情况。
# Scale the samples differently
scaled.counts_matrix = counts_matrix %*% diag(c(1,1,5,5,1,1,5,5))
scaled.dist <- dist(t(scaled.counts_matrix))scaled.dendro <- as.dendrogram(hclust(d = dist(t(scaled.counts_matrix))))
# Create dendro
scaled.dendro.plot <- ggdendrogram(data = scaled.dendro, rotate = TRUE)# Preview the plot
print(scaled.dendro.plot)
Clustering of scaled data
新的树状图现在显示了聚集在一起的缩放样本(样本 3、4、7 和 8 ),这是不正确的,因为唯一改变的是这些样本的读取总数,但它们的单个组件相对于彼此是相同的。
扰动不变性
这与我们的分析结论不应依赖于用来表示成分数据的单位的观察结果有关。回到空气成分的例子,我们可以混合使用百分比和 ppmv 值来表示数据,比如:[78%、21%和 9780ppmv]。这仍然代表着相同的物理样本,我们应该能够将它与另一个类似空气的样本进行比较,在这个新的坐标系和旧的坐标系中,并得出相同的结论。让我们再次使用模拟数据来计算新的扰动坐标空间中样本之间的距离:
#Multiply each row (gene) with a scalar value
perturbed.counts_matrix = counts_matrix * c(seq(1,192,1))
colnames(perturbed.counts_matrix) = colnames(counts_matrix)
perturbed.dist <- dist(t(perturbed.counts_matrix))perturbed.dendro <- as.dendrogram(hclust(d = dist(t(perturbed.counts_matrix))))
# Create dendro
perturbed.dendro.plot <- ggdendrogram(data = perturbed.dendro, rotate = TRUE)# Preview the plot
print(perturbed.dendro.plot)
Clustering of perturbed data
从上面的图可以清楚地看出,与比例不变性问题相比,这是一个小得多的问题。来自对照和处理条件的样本聚集在一起,但是样本之间的距离不同。这可能会导致错误的结论,具体取决于所提的问题。在大多数 RNA-seq 或 NGS 数据中,在不同条件下比较样品时,扰动方差不是大问题。
亚位置相干性
这一特性确保了无论包含哪些数据成分,分析都会得出相同的结论。例如,在我们的空气示例中,我们可以删除代表 1%体积的组件。现在样本在 2 维空间([78.5%,21.5%])中表示,而不是在原始的 3 维空间([78%,21%,1%])。在这个低维空间中的任何分析都不应不同于在原始三维空间中的比较。从下一代测序(NGS)数据的角度来看,这是一个重要的属性,在这种情况下,我们并不总是能够保证始终找到数据中的所有成分。这可能有很多原因,有时是有意的,有时是无意的,不可避免的。
为了在传统分析方法中模拟这种特性(或缺乏这种特性),我从由 100 个基因+ 92 个对照组成的原始数据集生成了由前 50 个基因+ 92 个对照组成的第二个数据集。较小数据集中的 50 个基因具有与原始数据集中相同的绝对(无约束)值。然后,通过使所有读取的总和为大约 20K(如在原始数据集中一样),这些不受约束的数据被封闭(受约束)。
计算两个数据集中 50 个常见基因之间的相关系数,然后进行比较:
load('sim_counts_matrix_100.rda')
counts.all <- counts_matrix
# Load the sub-compositional data made up of only the first 50 genes (features) + 92 controls from the original data of 100 genes (features) + 92 controls
load('sim_counts_matrix_50.rda')
counts.sub.comp <- counts_matrix# Get the correlation between the 50 common genes
cor.all <- as.vector(cor(t(counts.all[1:50,])))
cor.sub.comp <- as.vector(cor(t(counts.sub.comp[1:50,])))
tmp <- as.data.frame(cbind(cor.all,cor.sub.comp))
names(tmp) <- c('correlation_all', 'correlation_sub_comp')
tmp$abs.diff <- as.factor(ifelse(abs(tmp$correlation_all - tmp$correlation_sub_comp)>0.5,1,0))# Plot
ggplot(tmp,aes(correlation_all,correlation_sub_comp, color=abs.diff)) + geom_point(size=2) + th + scale_colour_manual(values = c("1" = "Red", "0" = "Blue")) + theme(legend.position = "none")
Differences in the correlation between genes (features) depending on what other genes are present in the data
在上面的图中,我们可以看到两个数据集中的大多数相关系数是相似的,有些系数有显著差异(以红色显示)。根据所提问题的不同,这些差异可能会导致结论的显著差异。这可能是基因网络分析中的一个主要问题。
置换不变性
这一特性意味着不管原始数据的顺序如何,分析方法都应该得出相同的结论。我能想到的大多数分析方法一般都遵循这个特性。请让我知道,如果你知道任何违反这一点的分析方法,我会在帖子中包括它们。
如何正确分析成分数据
现在,我们确信传统的分析方法并不总是满足分析成分数据的所有 4 个重要属性,我们能做什么?三十多年来,Aitchison 做了一些令人难以置信的工作,想出了更好的技术。根据我处理 NGS 数据的经验,我感觉他的建议在很大程度上被当成了耳旁风。希望这篇博文能够说服其他人在分析成分数据时更加谨慎。在下一篇文章中,我将展示一些分析成分数据的方法,再次强调 NGS 数据和应用。
https://quotecites.com/quote/Hermann_Hesse_378
不懈追求 1%:分析部门的角色。
当我与希望购买我的团队服务的营销人员交谈时,或者他们希望建立自己的分析团队时,我经常告诉他们,一个合适的分析团队就是要在他们的营销组织中安装智能。这并不意味着适用于每个营销部门——有些部门很小,没有专家也能很好地分析他们的数据——但是一旦一家公司达到他们需要专业化的规模,你就有几个方向可以选择。在本帖中,我们将探讨营销人员可以投资的三个主要领域,以提高他们的营销智能能力。
智能:进化,而不是革命。
智力是一个有趣的词。很美,也很有争议。智能是一种选择的工具,它引导人类主宰食物链,保护我们的家庭,发展文明,并创造我们茁壮成长的地方来做刺激我们大脑的事情。(作者注:在这篇博文中,我主要关注智力的积极方面。)
那么什么是智能,为什么它对可持续、可实现的业务增长如此重要?智能是利用数据获取有关营销环境的知识并利用这些知识进行调整的能力。是动作驱动;它导致适应;这是任何企业为了保持竞争优势都必须履行的基本职能。这也不是我们(作为决策者)能够在一夜之间实现的。智能依赖于准确的信息才能智能。一个根据错误信息采取行动的营销部门,最终会因为缺乏真正的环境知识而受到伤害。
智能是利用数据获取和应用知识的能力。这是每个企业保持竞争优势所需要的。
强大的情报能力始于干净的数据。我们可以信赖的数据和捕捉营销环境重要方面的数据。对于我领导的团队来说,干净有用的数据来自强大的数据运营团队的规划、协调和工程。
强大的情报能力始于干净的数据。
数据操作:获取干净的数据。
从强大的分析能力开始的稳步增长之旅始于良好的数据运营实践。在我工作的团队中,数据运营可以是数据工程师、产品经理和信息技术团队代表的组合。
如果营销组织很小,也可以简单到拥有合适的工具和基础设施。
可靠数据运营的目标是识别一个组织拥有的数据、我们需要的数据,并创建一个计划,以建立一个关于公司、客户和该组织所处的营销环境的可信的真实来源。
要了解您是否需要投资数据运营,请问自己这样一个问题:如果我正在查看的数据与我的想法和决策相矛盾,我会改变主意吗?我有信心数据是好的吗?如果答案是否定的,那么让我们通过看一看我们的数据操作来开始智能进化。
分析和统计:在不确定性下改变我的想法的科学
如果数据操作正常,下一个主要投资是分析师和统计学家,他们可以使用方法来创建关于我们收集的数据的有用见解。这些人有各种各样的口味,所以让我把他们放在两个桶里,冒犯了他们中的大多数。
第一桶:数据挖掘专家/故事讲述者/灵感来源。
第二桶:统计学家/智囊团/风险——秀逗魔导士。
这种过于简化的做法非常有用,因为它有助于我们理解分析团队中的一些基本角色。这两个组拥有独特的技能,您将在非常具体的用例中求助于它们。
数据挖掘专家正在探索数据,以帮助激励营销决策者。他们在我们已经知道的东西中找到洞察力。他们的工具是性能报告、数据可视化和分析。这种风格的分析师充满好奇,是一个伟大的故事讲述者。他们有着卓越的商业头脑,只是在他们小心翼翼的洞察力发展过程中黯然失色。这是您在监控营销绩效时最先接触到的角色之一。
统计学家与数据挖掘者相关,但拥有不同的技能。他们专注于具有不确定性的决策,并将这种不确定性的风险降至最低。他们会用数学来帮助你理解你可能采取的不同决策路径中的风险。利用大脑互动体的最佳时机是当你有关于你要做的决定的极好的数据时——但是你有几个选择。
数据科学家和技术专家:构建认知解决方案
一旦你掌握了数据挖掘,并通过统计将风险最小化,现在是时候创建商业解决方案,利用你正在收集的数据的力量。这将把您的分析能力扩展到您提供的产品和服务中——注入它以解决特定的问题,或者用更智能/个人/相关的产品取悦您的客户。
数据科学家和软件工程师—这两个角色可以帮助您构建数据驱动的解决方案。
认知解决方案是能够创造和应用知识的商业解决方案。
数据科学家/软件工程师组合非常强大。如果你能把这两个角色放在同一个房间里——由可靠的数据操作支持——那么你就有了一个正在形成的业务解决方案发电站。
仍然需要一些关于如何发展你的营销智慧的指导。在下面的评论区给我一个欢呼吧;或者查看一下我的其他博客,寻找一些灵感。
用空间和自然语言处理重温复仇者联盟 3:无限战争
发现地球上最强大的英雄的台词中的顶级名词、动词、实体和文本相似性
经过漫长的一年等待,复仇者联盟 4:终局之战终于来了。我和你一样,世界上大多数人都会在第一天赶到电影院看电影,体验复仇者联盟如何拯救世界,结束一个十年的故事。为了平静我的神经和缓解等待,我想重温以前的电影,无限战争,但不同的和互动的。而且,因为我是一个数据专家,当然,它必须涉及数据和一些流行词汇。
答案?自然语言处理,简称 NLP。
使用 spaCy ,一个 NLP Python 开源库,旨在帮助我们处理和理解大量文本,我分析了电影的脚本,以研究以下概念:
- 电影中的十大动词、名词、副词和形容词。
- 由特定角色说出的顶级动词和名词。
- 电影中的前 30 个命名实体。
- 每个字符对的台词之间的相似性,例如,托尔和灭霸的台词之间的相似性。
在本文中,我将讨论并展示我的发现,同时用代码解释我是如何用 spaCy 做到这一点的。
你对代码和技术词汇不感兴趣吗?今天是你的幸运日!我想说的是,我在这里使用的词汇和术语大多是非技术和用户友好的,所以即使你没有自然语言处理、人工智能、机器学习或在这里插入流行语的经验,你也应该能够掌握我想要传达的主要思想和概念。所以,请随意忽略这些代码:)
The Mad Titan. Credits: Marvel
处理数据
用于实验的数据或文本语料库——在 NLP 中通常被称为——是电影的剧本,可在这个链接获得。然而,在使用这些数据之前,我必须对其进行清理。因此,我删除了一些不必要的东西,如描述一个动作或场景的评论,如“[灭霸粉碎宇宙魔方,露出蓝色的太空石……]”,以及说这句话的角色的名字(实际上,这个名字是用来知道谁说了什么,但不是用于分析的实际语料库的一部分)。此外,作为空间数据处理步骤的一部分,我忽略了标记为停止词的术语,换句话说,即常用词,例如【我】【你】【安】。另外,我只使用了引理,这是每个单词的标准形式。例如,动词 "talks】、、、、、【talking】、是同一个词位的形式,其引理是、【talk】、。
要在 spaCy 中处理一段文本,首先,我们需要加载我们的语言模型,然后在文本语料库上调用该模型。结果是一个Doc
对象,一个保存已处理文本的对象。
Creating a Doc object in spaCy
现在我们有了一个干净的经过处理的语料库,是时候开始了!
十大动词、名词、副词和形容词
仅仅通过看动词就能知道电影的整体动作或情节是什么吗?本文的第一张图解决了这个问题。
“I know”, “you think” are some of the most common phrases
【知道】【走】【来】【得到】【想】【告诉】【杀死】【需要】【停止】**【想要】。从中我们可以推断出什么?因为我看过这部电影几次——这也暗示我有偏见——我愿意根据这些动词得出结论,复仇者联盟 3:无限战争是关于知道、思考和研究如何去阻止某事或某人。
这就是我们如何获得带有空间的动词:
描述动词的单词,即副词呢?
“I seriously don’t know how you fit your head into that helmet” — Doctor Strange
对于一部关于阻止一个人摧毁半个宇宙的电影来说,口语副词中有很多实证主义——“对”、“完全正确”和“更好”等词就是例子。
所以,我们知道了动作,以及它们是如何被描述的,现在是时候看看名词了。
“You will pay for his life with yours. Thanos will have that stone.” — Proxima Midnight
看到第一个结果是【stones】并不奇怪,毕竟电影讲的就是他们。在第二个位置,我们有术语“生命”,,这是灭霸想要摧毁的东西,接下来是“时间”,恰恰是复仇者联盟没有的(注意:“时间”也可能是因为提到了时间石)。
最后,我将用形容词或者描述名词的单词来结束这一节。与副词类似,我们有一些表达肯定的术语,如、、、【对】、,还有一些表达肯定的术语,如、、、【肯定】、。
“I’m sorry, little one.” — Thanos
特定人物提到的顶级动词和名词
之前,我们看到了电影中提到的最常见的动词和名词有哪些。虽然这些知识让我们对电影的整体感觉和情节有所了解,但它并没有说太多关于我们角色的个人冒险经历。因此,我应用了与查找前十名动词和名词相同的过程,但是是在字符级别上。
由于电影中有许多角色,我只选择了一些实际上说了合理数量台词的角色,加上一些我最喜欢的:)。这些角色是托尼·史塔克、奇异博士、加莫拉、托尔、火箭、彼得·奎尔(星际领主)、乌木·莫和灭霸。抱歉,队长,你没入选。然而,在我的 GitHub(链接在文章末尾)中,你可以找到一个文件夹,里面有每个角色的图形。
接下来的图片显示了这些人物使用的顶级名词。
What’s with Quill calling Drax so much?
我发现很奇怪,甚至令人耳目一新的是,在大多数情况下,我们亲爱的英雄们使用的顶级名词是提及船员。比如托尼说了【小子】九次(指蜘蛛侠),火箭叫了奎尔(星主)三次,而奎尔本身就叫了(更像是冲着)德拉克斯七次。
通过进一步的考察,我们可以推断出对每个角色来说什么似乎是最重要的。就钢铁侠而言,数据表明地球对他来说很有价值。与他相似的是加莫拉,他总是在思考更高的目标——、、、、、【行星】、——并最终为此付出代价。奇异博士还有另一个目的——保护他的宝石——他反复提到了这个目的。然后,还有托尔,他对灭霸有个人恩怨,说了八次他的名字,还有一个新的兔子最好的朋友。最后,还有疯狂的泰坦本身,灭霸,他无法停止思考收集无限宝石,或者他的女儿。
虽然名词富有表现力和意义,但动词却不是这样。正如你将在下一张图中看到的,动词不像名词那样丰富多彩。像、、、【想要】、、、这样的词占据了大部分的榜首。然而,有一个角色可能拥有整个语料库中最独特的动词:乌木·莫。如果你不记得,乌木的血盆大口,是灭霸的头号心腹。就像他是一个好仆人一样,他的目标是——除了得到时间之石——宣扬他主人的使命,这个任务他用了诸如、和“欢呼”这样的词来完成蠕变。
“Hear me, and rejoice. You have had the privilege of being saved by the Great Titan…” — Ebony Maw
此外,以下是格鲁特的热门名词。
“I am Groot”
命名实体
到目前为止,我们已经探索了我们的英雄和反派在这部史诗电影中使用的最常见的动词、名词、副词和形容词。然而,为了完全解释我们一直在仔细研究的所有这些词,我们需要一些上下文,即命名实体。
我引用 spaCy 网站上的话,一个命名实体是一个“被赋予名称的真实世界的物体——例如,一个人,一个国家,一个产品或者一本书的名字。”所以,知道实体,就意味着,意识到人物所谈论的事物。在 spaCy 包中,实体有一个预测标签,它将实体分类为许多类型中的一种,如人、产品、艺术作品等等(https://spacy.io/api/annotation#named-entities),为我们提供了额外的粒度级别,这对于进一步分类它们很有用。不幸的是,出于简单的原因,我不会使用实体类,而只是实体本身。
这些是排名前 30 的实体。
“MAYEFA YA HU” is the chant of Wakanda’s Jabari warriors
首先,我们有灭霸,考虑到这部电影全是关于他的,这一点也不奇怪。跟随他的是他的女儿加莫拉,影片的中心人物之一。然后在第三个位置,我们有格鲁特(我肯定我没有解释为什么),其次是托尼,其他复仇者,以及一些地方,如纽约,阿斯加德和瓦坎达[永远]。除了英雄和地点,两块【六】(见 14 号实体)无限之石——时间和灵魂石——出现在这个名单上(分别是第 15 和第 16 位)。令人惊讶的是,将灭霸带到地球的心灵之石不在名单上。
要访问空间中的实体,请读取Doc
的属性ents
,如下所示:
每个字符对的口语行之间的相似性
当我们讨论每个角色的顶级动词时,我们意识到,与名词不同,大多数动词都非常相似,并且传达相同的感觉。像【走】**【来】这样的术语给我们一种运动的印象或我们的角色想要去或到达某个特定地方的感觉,而像【杀死】**【停止】这样的动词暗示着确实有一个巨大的威胁必须被阻止。
带着这个想法,为了进一步研究相似性的概念,我计算了每个角色对的台词之间的相似性分数。
NLP 中的相似性概念描述了两段文本的合成或句法意义有多接近或相对——通常,相似性得分的范围是从 0 到 1,其中 0 表示完全不相似,1 表示完全相似(或者两个文本相同)。从技术上讲,相似度是通过测量单词向量之间的距离来计算的,即单词的多维表示。对于那些有兴趣了解这个主题的人,我推荐搜索 word2vec,这可能是用于生成这些单词嵌入的最常见的算法。下图显示了相似性矩阵。
Again, Ebony Maw is the most unique character
说实话,我没想到会是这个结果。一方面,我可以接受所有的相似性接近于 1,因为毕竟,电影有一个主要情节,它应该有跨对话的关联。然而,让我感到不安的是,分数非常非常相似。我的意思是,看看灭霸的分数;我希望看到一个恶棍的分数与那些想要阻止他的人的分数相比有很大的不同。从更积极的角度来看,有趣的是,彼得·帕克(蜘蛛侠)的得分变化最大。毕竟,他只是一个在混乱中被抓住的孩子,所以,有这个结果是意料之中的。
这是一个如何计算空间中两个Doc
之间相似性的例子:
总结和结论
在电影《复仇者联盟 3:无限战争》中,我们跟随一群超级英雄踏上了阻止灭霸的旅程,这个威胁的目标是毁灭宇宙一半的生命。通过这部电影,我们了解到大多数英雄都有拯救世界的动机和动力,这反映在他们表达自己的方式上。在本文中,我们在 Python、NLP 和 spaCy 的帮助下,探索我们的英雄和反派如何通过研究他们的每一句台词来表达和交流。通过关注他们最常用的动词和名词等特征,我们学习、确认并重温了钢铁侠对地球的忠诚、奇异博士保护时间之石的宣誓职责、托尔复仇的渴望以及灭霸完成自己命运的雄心。
复仇者联盟周快乐,等残局剧本出来后再见。
在我的 GitHub 上可以找到用于生成这个实验的代码,链接如下:
在 GitHub 上创建一个帐户,为 juandes/infinity-war-spacy 开发做贡献。
github.com](https://github.com/juandes/infinity-war-spacy)
如果你有任何问题,评论,疑问,或者想聊天,请在这里或 Twitter 上留下评论,我将很乐意帮助你。
[## 胡安·德迪奥斯·桑托斯(@ jdiosantos)|推特
胡安·德迪奥斯·桑托斯的最新推文(@ jdiossantos)。机器学习/数据工程师。还有,口袋妖怪大师,还有…
twitter.com](https://twitter.com/jdiossantos)
啊哦…我变成了一只恐龙
用这些技能保持相关的金融专业。
据金融高管国际公司称,
【两年前】78%的首席财务官认为精通 Excel 是他们 FP & A 团队最重要的技能。今天只有 5%的人有同样的感觉。相反,首席财务官将对新技术的适应能力视为新员工的首要技能。
科技正在改变一切。它改变了传统的工作,创造了新的角色,并带来了对更新技能的需求——包括当前的 FP & A 专业人员。根据哈克特集团(Hackett Group)2018 年的数字技能调查,在不断变化的人才需求方面,金融业远远落后于形势,目前似乎没有一种跟踪供需趋势的既定方法。
如今,FP&A 的员工需要掌握以前根本不存在的新技能,否则就有被更年轻的新员工超越的风险。进入金融科技专业人士的时代——在金融、技术和 IT 领域拥有强大背景的个人。虽然今天这种知识受到高度重视,但在不久的将来,我们会看到它从重视转变为必需。我们应该期待在短短几年内看到财务政策和会计职位的角色和组成发生巨大变化。所需的后端技能无疑会发生变化。更多的数据科学家和有分析思维能力的个人将是必要的,我们将看到以前的金融巨星变得过时。
虽然今天这种知识受到高度重视,但在不久的将来,我们会看到它从重视转变为必需。
在 EY 对金融领导者的一项调查中,近 80%的受访者表示,他们不认为自己具备必要的技能来满足 10 年后的工作需求。这应该是一个紧急的警钟,大声喊出迫切需要的技能提升。
既然是这样,我们决定涵盖未来的 FP&A 的技术技能。如果你想让自己成为一名有吸引力的员工,并确保自己不会过时,可以考虑学习下面我们介绍的技能。为了在财务政策和会计领域保持相关性,这里有一些工具和技巧可以帮助你达到并保持这种状态。
“越来越多的公司和职位描述将要求财务职位描述中的大数据[和] 建模经验”——Geetanjali tan don,AFP FP &咨询委员会,拜耳作物科学数字& IT 转型财务主管
数据和技术敏锐度=职业生存的关键
理想情况下,FP&A 专业人员应该对大量数据感到舒适,理解数据是如何构造的,理解集成是如何发生的,并且能够有效地使用包括云应用在内的多个系统。
编程能力
能够做一些简单的编码或者理解使用一个系统是必要的,以便用不同的技术改进流程是一种优势。与 FP & A 专业人士最相关的编码语言有:
Java
Python
c#
Murex
由于金融科技员工的需求越来越大,以下是与每个角色相关的编程语言:
区块链专家和开发者: C、C++、Java
App 开发者: C#、C++、Java、Python
数据科学家: 数据科学工具包:R、Python、Weka、NumPy、MatLab
数据可视化工具:D3.js、ggplot
查询语言使用熟练程度:SQL、Hive、Pig
NoSQL 数据库:MongoDB、Cassandra、
有很多在线学习平台让学习编码语言变得容易和有趣。Coursera 就是这样一个平台,它提供的课程从、【面向所有人的 Python】、到、【使用 SQL 的现代大数据分析】你所要做的就是留出一些时间,带着开放的心态来。
数据可视化和分析技能 大数据工具执行数据分析,以便从大型数据集中提取洞察。FP &专业人士可以从使用可视化来解释他们的数据中受益匪浅。学习如何使用领先的分析工具可以帮助你发展你的可视化和分析技能。
你应该熟悉的一个可视化工具是 Power BI 。微软的业务分析工具 Power BI 提供交互式可视化功能,帮助各部门创建报告和仪表板。向管理层展示所有最新的财务报告,以便他们做出最佳、最明智的决策。
考虑看看 Udemy 的微软 Power BI 入门课,了解这个平台,熟悉它的特性。
财务专业人员将继续需要在分析技能和技术悟性方面具有适应性、灵活性和技能提升。
熟悉技术 为了增加自己的市场价值,FP &专业人士应该熟悉一系列与行业相关的技术。这类技术包括 SPSS、Excel、SQL、SAS、R、MatLab、Linux、Hadoop 等。与金融敏锐度相结合,熟悉这些技术对 FP & A 专业人士来说是一个巨大的优势。
此外,对自动化的日益依赖促使更多的招聘经理寻找具备适当 IT 技能的金融专业人士来利用新的金融系统。能够证明自己在预测分析或应付账款自动化等领域的知识和能力的候选人会发现自己很受欢迎。
根据毕马威的说法,“没有改变的是金融的基础作用。财务部门仍需要为组织的其他部门提供洞察力,确保有效的控制和风险管理,并推动自身和组织的效率……这些目标(预计)将保持不变。然而,不同的是在每一项上花费的时间和精力的比例以及交付方式。”
一个大大改善了 FP&A 专业人员工作方式的自动化平台是 DataRails 。DataRails 通过自动整合基于 Excel 的数据,消除了传统手动流程中的繁重工作。这节省了以前浪费在繁琐的手动工作上的大量时间。通过最大限度地将时间花在分析数字上,而不是浪费时间将它们放在一起,以高超的洞察力打动管理层。
“自动化将继续让财务和财务与会计专业人员真正反思他们的工作方式,减少他们在日常和重复的手动密集型工作上花费的时间,并腾出更多时间作为重要的业务合作伙伴。金融专业人士将继续需要在分析技能和技术悟性方面具有适应性、灵活性和技能提升。但有如此多的资源可以提供帮助,所以现在不应该是担心或恐惧的时候,相反,对于那些相信终身学习的专业人士来说,这应该被视为一个巨大的机会。”
- Rachele Collins 博士,APQC 首席研究员
用 Keras 估计剩余寿命
从时间序列到图像…问 CNN“下一次故障什么时候发生?”
在许多人工智能解决方案中,预测罕见事件正成为研发的重要课题。生存分析、客户流失预测、预测性维护和异常检测是处理罕见事件的最受欢迎的应用领域的一些例子。考虑到这些情况,我们可以将罕见事件想象为在特定条件下发生的特定状态,不同于正常行为,但在经济利益方面起着关键作用。
在这篇文章中,我开发了一个机器学习解决方案来预测特定发动机组件的剩余使用寿命( RUL )。这类问题在预测性维护领域起着关键作用,这里的目的是说' 距离下一次故障还剩多少时间?’。为了实现这个目标,我在 Keras 中开发了一个卷积神经网络,以图像的形式处理时间序列。
数据集
对于数据科学家来说,在处理这种任务时,最重要的问题是缺乏可用的观察形式的罕见事件。因此,实现良好性能的第一步是尝试处理最丰富的数据集,以处理各种可能的情况。
由 NASA 提供的涡扇发动机退化模拟 数据集 ,正在成为一个同类型(共 100 台)发动机机群剩余使用寿命( RUL )估算的重要基准。数据以时间序列的形式提供:3 个操作设置、21 个传感器测量值和周期,即工作寿命的时间观察值。
发动机在每个时间序列开始时正常工作,在序列中的某个点出现故障。在训练集中,故障在数量上增长,直到系统故障。在测试集中,时间序列在系统故障前的某个时间结束。目标是预测测试组中故障前的剩余运行循环数,即发动机将继续运行的最后一个循环后的运行循环数。
为了更好地理解这个解释,我们试着看一下数据:
train_df.id.value_counts().plot.bar()
Life Cycles for each engine before a fault in train set
发动机有不同的寿命。列车数据中的平均工作时间为 206 个周期,最少 128 个周期,最多 362 个周期。
在单个发动机的列车设置中,绘制了操作设置和传感器测量值,亲爱的:
engine_id = train_df[train_df['id'] == 1]engine_id[train_df.columns[2:]].plot(subplots=True, sharex=True, figsize=(20,30))
settings 1–3, sensors 1–9 for engine1
sensors 10–21 for engine1
绘图总是一个好主意……这样,我们可以对我们所掌握的数据有一个印象深刻的总体概述。在大部分系列的结尾,我们可以观察到一个不同的行为,这预示着未来的失败。
准备数据
为了预测每台发动机的 RUL,我们采用了一种分类方法,通过以下方式自行生成标签:
从 0(故障)到 15 个剩余周期,我们标记为 2;从 16 到 45 个周期,我们标记为 1,其余的(> 46)标记为 0。很明显,在现实场景中,标记为 2 的类别是最有经济价值的。预测该类的良好性能将允许我们运行一个适当的维护程序,避免未来的故障并节省资金。
为了让我们能够处理列车的最大数量的数据,我们使用固定窗口和 1 步滑动来分割序列。例如,引擎 1 具有 192 个训练周期,窗口长度等于 50,我们提取长度为 50 的 142 个时间序列:
窗口 1 - >从周期 0 到周期 50,窗口 2 - >从周期 1 到周期 51,…,窗口 142 - >从周期 141 到周期 50,窗口 191。每个窗口都标有该窗口所考虑的最终循环的相应标签。
sequence_length = 50def gen_sequence(id_df, seq_len, seq_cols):data_matrix = id_df[seq_cols].values
n_elem = data_matrix.shape[0]
for a,b in zip(range(0,n_elem-seq_len), range(seq_len,n_elem)):
yield data_matrix[a:b,:]
def gen_labels(id_df, seq_len, lab):
data_matrix = id_df[lab].values
n_elem= data_matrix.shape[0]
return data_matrix[seq_len:n_elem,:]
从时间序列到图像
为了让事情变得更有趣,我决定将这个系列转化成图像。以便用它们来填充我们的分类模型。
我根据这个惊人的资源创建了这些图片。这个概念很简单…当我们试图将时间序列转换成图像时,我们总是利用声谱图。这个选择很聪明,但并不总是最好的选择(你可以在这里阅读)。在这篇文章中,作者解释了他对用声谱图表示处理音频系列的困惑。他谈到了声音,但意思可以在我们的场景中翻译。光谱图是强大的,但它们的使用可能会导致信息的丢失,特别是如果我们试图用计算机视觉的方式来解决问题。为了有效,2D CNN 需要空间不变性;这建立在一个假设上,即一幅经典图像(比如一张照片)的特征无论在哪里都有相同的含义。另一方面,声谱图意味着由两个不同的单位(频率和时间)构成的二维表示。
出于这些原因,我决定利用循环图来转换我的时间序列窗口(长度为 50 个周期)。它们很容易用 python 实现,只需几行代码,利用 Scipy。
from scipy.spatial.distance import pdist, squareformdef rec_plot(s, eps=0.10, steps=10):d = pdist(s[:,None])
d = np.floor(d/eps)
d[d>steps] = steps
Z = squareform(d)
return Z
使用这个函数,我们能够为我们处理的每个时间序列生成一个 50x50 的图像(我已经排除了方差为 0 的恒定时间序列)。因此,每一次观察都是由一组大小为 50x50x17 (17 是没有零方差的时间序列)的图像组成的,如下所示。
Example of a train observation
模型
至此,我们已经准备好构建我们的模型了。我采用了经典的 2D CNN 架构:
model = Sequential()
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(50, 50, 17)))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(3, activation='softmax'))model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
我只对 10 个时期进行了拟合,达到了 0.832%的精度。
从混淆矩阵中我们可以看到,我们的模型可以很好地区分发动机何时接近故障(2 个标签:<16 cycles remaining) or when it works normally (0 label: > 45 个循环)。一点点噪音出现在中级(> 15,<46 cycles). We are satisfied to achieve a great and clear result for the prediction of class 2 — i.e. near to failure.
SUMMARY
In this post, we try to solve a 预测性维护问题。估算发动机的 RUL 由于收集这类数据的难度,我们有意识地应对罕见事件。我们提出了一个有趣的解决方案,利用循环图将时间序列转换成图像。通过这种方式,我们能够区分处于工作寿命末期的油井发动机。
保持联系: Linkedin
遥感基础:归一化差异植被指数
卫星图像在生态学研究中的应用
NDVI visualization of continental US (Source: GIS Geography)
如果你还没有,请查看我之前的帖子,它总结了我在大会数据科学沉浸式课程中的顶点项目: 巴西亚马逊地区的土地使用和森林砍伐 。它很好地介绍了我在机器学习、遥感和生态学方面的一些兴趣,也是这篇文章的一个很好的序言。
那么,我的下一步是什么?
我认为这个帖子是对自己的承诺。我承诺将继续寻找方法来建立我的工程和机器学习能力,并推进对生态系统的研究和理解。
我深深地投入到学习这些工具和我们可以用它们做的一切,并且被那些既推进技术又增加科学家使用它进行保护的公司所鼓舞。他们的努力让我能够继续追求我的兴趣。
归一化植被指数
卫星图像的一个应用是归一化差异植被指数(NDVI)。这是一个基本但非常强大的指数,可以在任何包含近红外颜色通道的卫星图像中计算。该指数将反射的近红外光与反射的可见红光进行比较,并通过以下等式简单计算:
The scale for NDVI is -1 to 1, with values near -1 representing water and those near 1 representing dense and healthy vegetation.
植被指数因影像内容而异。这是因为陆地物体对不同波长的光有不同的反应(见我关于卫星图片内容的技术贴)。植被反射大量的近红外光,因此植被密度越大,图像的植被指数就越大。
这对卫星图像分类中的目标或土地类型识别有影响。一个想法是计算图像中每个像素的 NDVI,并使用这些值作为图像中的附加颜色通道。这可能是传递到神经网络的额外信息层,并可能增加网络检测图像边缘的能力。例如,检测图像从密集到稀疏的植被、城市景观到乡村环境、或者森林到清晰的农业的区域。
NDVI 的另一个应用是用来跟踪生态系统随时间的变化。我们可以通过计算植被指数随时间的变化来衡量林业对生态系统的影响。现在,我们可以每天访问整个地球的图像,我们可以通过植被指数等指标来跟踪气候变化的影响。这对于理解不同尺度的气候变化的影响是有价值的。植被指数的变化将因地方和地区而异。这可以将保护工作引向变化较大的地区,或者有助于管理和规划工作。
野火对加州植被指数的局部影响
我想在更高的水平上使用植被指数来构建工具,以进一步丰富我在数据工程和数据科学方面的经验。在完成我的顶点项目之前,我对使用卫星图像来了解 2018 年加州野火对周围植被的影响产生了兴趣。直觉上,被野火烧毁的地区经历了植被密度的剧烈变化。这些变化将反映在 NDVI(没有双关语的意思)。利用遥感,我们可以跟踪植被随时间的变化,并回答诸如“生态系统从野火中恢复需要多长时间?”。
Satellite Image from USGS of the Camp Fire in November 2018: Paradise, California
这可能适用于最近的加州火灾,以及前几年的火灾。感谢像 Planet 的 Open California 这样的开放访问数据程序,我们可以使用 2015 年的图像立即构建这些应用程序。
我很兴奋去探索!
用异常检测去除拉曼光谱中的尖峰:Python 中的 Whitaker-Hayes 算法
Detecting and removing spikes from Raman spectra
摘要。在这篇文章中,我想对 D. Whitaker 和 K. Hayes 在《化学计量学和智能实验室系统杂志》上提出的一种去除拉曼光谱中尖峰信号的新方法进行评论。在他们的出版物中,作者使用了一种基于改进的 Z 分数异常值检测的算法来定位这种尖峰,如果存在的话,随后使用简单的移动平均来消除它们。他们不是计算光谱强度的 Z 值,而是计算一次差分光谱的 Z 值。他们还提供了用 r 实现算法的代码。在这里,我用 Python 实现了算法,并展示了如何将它应用于不同的数据集。
拉曼光谱是一种广泛使用的分析技术,它提供来自分子和固体的结构和电子信息。它适用于实验室和大规模生产规模,并在许多不同的领域,如物理,化学,生物,医学或工业应用。
拉曼光谱学中已知的一个典型问题是拉曼光谱有时被尖峰“污染”。尖峰是出现在频谱上随机位置的正的窄带宽峰值。它们起源于高能宇宙射线撞击用于测量拉曼光谱的电荷耦合器件探测器。这些尖峰是有问题的,因为它们可能会妨碍后续分析,特别是在需要多变量数据分析的情况下。因此,处理拉曼光谱数据的第一步是清除尖峰。
首先,加载所需的 Python 包:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
图 1 显示了石墨烯的拉曼光谱。在过去的几年里,石墨烯由于其卓越的物理性能,包括优异的电子、热、光学和机械性能,已经成为非常受欢迎的材料。其特征拉曼光谱由如图所示的几个峰组成。从它们的形状和相关强度,可以获知掺杂、应变或晶界等大量信息。该光谱是被尖峰污染的光谱的明显例子。
# load the data as data frame
df = pd.read_csv(‘folder_name.../spectrum.txt’, delimiter = ‘\t’)# Transform the data to a numpy array
wavelength = np.array(df.Wavelength)
intensity = np.array(df.Intensity)# Plot the spectrum:
plt.plot(wavelength, intensity)
plt.title(‘Spectrum’, fontsize = 20)
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel(‘Wavelength (nm)’, fontsize = 20)
plt.ylabel(‘Intensity (a.u.)’, fontsize = 20)
plt.show()
Figure 1. A spike was recorded while measuring the typical Raman spectrum of graphene (characterized by the G and 2D bands).
基于 Z 分数的拉曼光谱尖峰检测方法
尖峰强度通常高于光谱中其他拉曼峰的强度,因此使用基于 z 分数的方法可能是一个好的起点。z 得分以标准差为单位表示一个值离平均值有多远。因此,如果已知总体均值和总体标准差,则原始得分 x(i)的标准得分计算如下:
z(i) = (x(i)-μ) / σ
其中 μ 是平均值,σ 是总体 x 的标准偏差(x(i)代表单个拉曼光谱的值)。关于如何使用 Z 分数方法检测异常值的更多详细信息可以在参考文献3中找到。
让我们计算光谱中点的 z 分数:
def z_score(intensity):
mean_int = np.mean(intensity)
std_int = np.std(intensity)
z_scores = (intensity — mean_int) / std_int
return z_scoresintensity_z_score = np.array(z_score(intensity))
plt.plot(wavelength, intensity_z_score)
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel( ‘Wavelength’ ,fontsize = 20)
plt.ylabel( ‘Z-Score’ ,fontsize = 20)
plt.show()
Figure 2. Z-scores of the spectrum plotted in figure 1.
然后需要一个阈值来判断一个值是否是异常值。该阈值的典型值为 3.5,由美国质量控制协会提出作为异常值标记规则的基础,而该出版物的作者使用 6。为了应用阈值来排除峰值,必须采用 Z 得分的绝对值:
|z(i)| = |(x(i)-μ) / σ|
计算为
def z_score(intensity):
mean_int = np.mean(intensity)
std_int = np.std(intensity)
z_scores = (intensity — mean_int) / std_int
return z_scoresthreshold = 3.5intensity_z_score = np.array(abs(z_score(intensity)))
plt.plot(wavelength, intensity_z_score)
plt.plot(wavelength, threshold*np.ones(len(wavelength)), label = ‘threshold’)
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel( ‘Wavelength’ ,fontsize = 20)
plt.ylabel( ‘|Z-Score|’ ,fontsize = 20)
plt.show()
Figure 2b. Z-scores of the spectrum plotted in figure 1. The threshold still cuts the 2D Raman peak.
然而,z 分数非常类似于原始光谱,并且阈值仍然切断主要拉曼峰。让我们使用 3.5 的阈值来绘制检测到的峰值:
threshold = 3.5# 1 is assigned to spikes, 0 to non-spikes:
spikes = abs(np.array(z_score(intensity))) > thresholdplt.plot(wavelength, spikes, color = ‘red’)
plt.title(‘Spikes: ‘ + str(np.sum(spikes)), fontsize = 20)
plt.grid()
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel( ‘Wavelength’ ,fontsize = 20)
plt.ylabel( 'Z-scores > ' + str(threshold) ,fontsize = 20)
plt.show()
Figure 3.Using modified Z-Scores, 18 spectral point are above the threshold.
用于拉曼光谱中尖峰检测的改进的基于 Z 分数的方法
第二种选择是利用稳健统计并计算光谱的修正 z 分数。这种改进的 Z 得分方法使用中位数(M)和中位数绝对偏差(MAD ),而不是平均值和标准差:
z(i) = 0.6745 (x(i)-M) / MAD
其中 MAD = median(|x-M|)和|…|代表绝对值。中位数和 MAD 分别是集中趋势和离差的稳健度量。乘数 0.6745 是标准正态分布的第 0.75 个四分位数,MAD 将 to⁴.收敛到该四分位数
def modified_z_score(intensity):
median_int = np.median(intensity)
mad_int = np.median([np.abs(intensity — median_int)])
modified_z_scores = 0.6745 * (intensity — median_int) / mad_int
return modified_z_scoresthreshold = 3.5intensity_modified_z_score = np.array(abs(modified_z_score(intensity)))
plt.plot(wavelength, intensity_modified_z_score)
plt.plot(wavelength, threshold*np.ones(len(wavelength)), label = 'threshold')
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel('Wavelength (nm)' ,fontsize = 20)
plt.ylabel('|Modified Z-Score|' ,fontsize = 20)
plt.show()
Figure 4. Modified Z-scores of the spectrum plotted in figure 1. The threshold still cuts the 2D Raman peak.
仍然可以观察到相同的问题:
# 1 is assigned to spikes, 0 to non-spikes:
spikes = abs(np.array(modified_z_score(intensity))) > thresholdplt.plot(wavelength, spikes, color = ‘red’)
plt.title(‘Spikes: ‘ + str(np.sum(spikes)), fontsize = 20)
plt.grid()
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel( ‘Wavelength’ ,fontsize = 20)
plt.ylabel( 'Modified Z-scores > ' + str(threshold) ,fontsize = 20)
plt.show()
Figure 5. Using modified Z-Scores, 24 spectral points are above the threshold.
2D 拉曼峰值仍然被检测为尖峰,因此需要更灵敏的方法。
Whitaker 和 Hayes 的 改进的基于 Z 分数的拉曼光谱尖峰检测方法
Whitaker 和 Hayes 建议利用尖峰的高强度和小宽度,因此使用连续光谱点之间的差异∇x(i) = x(i)-x(i-1 来计算 z 分数,其中 x(1),…,x(n)是以等间距波数记录的单个拉曼光谱的值,i = 2,…,n。该步骤消除了线性和缓慢移动的曲线线性趋势,而尖锐的细尖峰将被保留。现在,
z(i) = 0.6745 (∇x(i)-M) / MAD
因此只包括一个额外的步骤,其中包括连续值之间的差。
# First we calculated ∇x(i):
dist = 0
delta_intensity = []
for i in np.arange(len(intensity)-1):
dist = intensity[i+1] — intensity[i]
delta_intensity.append(dist)delta_int = np.array(delta_intensity)
# Alternatively to the for loop one can use:
# delta_int = np.diff(intensity) intensity_modified_z_score = np.array(modified_z_score(delta_int))
plt.plot(wavelength[1:], intensity_modified_z_score)
plt.title('Modified Z-Score using ∇x(i)')
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel('Wavelength (nm)', fontsize = 20)
plt.ylabel('Score', fontsize = 20)
plt.show()
Figure 6. Modified Z-scores using ∇x(i) of the spectrum plotted in figure 1.
同样,为了应用阈值来排除尖峰,必须采用修改后的 Z 得分的绝对值:
|z(i)| =|0.6745 (∇x(i)-M) / MAD|
导致
threshold = 3.5intensity_modified_z_score = np.array(np.abs(modified_z_score(delta_int)))
plt.plot(wavelength[1:], intensity_modified_z_score)
plt.plot(wavelength[1:], threshold*np.ones(len(wavelength[1:])), label = 'threshold')
plt.title('Modified Z-Score of ∇x(i)', fontsize = 20)
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel('Wavelength (nm)', fontsize = 20)
plt.ylabel('Score', fontsize = 20)
plt.show()
Figure 7. Abosolute value of the modified Z-scores of ∇x(i) of the spectrum plotted in figure 1.
同样,检测到的尖峰数量可以计算如下
# 1 is assigned to spikes, 0 to non-spikes:
spikes = abs(np.array(modified_z_score(intensity))) > thresholdplt.plot(wavelength, spikes, color = ‘red’)
plt.title(‘Spikes: ‘ + str(np.sum(spikes)), fontsize = 20)
plt.grid()
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel( ‘Wavelength’ ,fontsize = 20)
#plt.ylabel( ‘Spike(1) or not(0)?’ ,fontsize = 20)
plt.show()
Figure 8. Using modified Z-Scores with ∇x(i), 17 spectral points are above the threshold = 3.5.
对于 3.5 的推荐阈值,分配了许多错误的尖峰。然而,与拉曼峰相比,通过这种方法得到的值比以前高得多。
plt.plot(wavelength[1:],
np.array(abs(modified_z_score(delta_int))), color='black', label = '|Modified Z-Score using ∇x(i)|')
plt.plot(wavelength, np.array(abs(modified_z_score(intensity))), label = '|Modified Z-Score|', color = 'red')
plt.plot(wavelength, np.array(abs(z_score(intensity))), label = '|Z-Score|', color = 'blue')
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel( 'Wavelength' ,fontsize = 20)
plt.ylabel( 'Score' ,fontsize = 20)
plt.legend()
plt.show()
Figure 9. Comparison between the three different approaches.
一般来说,必须根据数据集选择合适的阈值。对于这种情况,阈值= 7 已经足以获得清晰的选择。
Figure 10. Absolute values of the modified Z-scores with ∇x(i) of the spectrum plotted in figure 1.
Figure 11. Using modified Z-Scores with ∇x(i), 3 spectral points are above the threshold = 7.
固定拉曼光谱
一旦检测到尖峰信号,下一步就是移除它们并修正光谱。为此,通过计算每个候选波数的近邻的平均值(在 2m+1 个值窗口内),在每个候选波数处获得插值。
def fixer(y,m):
threshold = 7 # binarization threshold.
spikes = abs(np.array(modified_z_score(np.diff(y)))) > threshold
y_out = y.copy() # So we don’t overwrite y for i in np.arange(len(spikes)):
if spikes[i] != 0: # If we have an spike in position i
w = np.arange(i-m,i+1+m) # we select 2 m + 1 points around our spike
w2 = w[spikes[w] == 0] # From such interval, we choose the ones which are not spikes
y_out[i] = np.mean(y[w2]) # and we average their values
return y_out# Does it work?
plt.plot(wavelength, intensity, label = 'original data')
plt.plot(wavelength, fixer(intensity,m=3), label = 'fixed spectrum')
plt.title('Despiked spectrum',fontsize = 20)
plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.xlabel('Wavelength (nm)' ,fontsize = 20)
plt.ylabel('Intensity (a.u.)' ,fontsize = 20)
plt.legend()
plt.show()
Figure 12. Original and despiked Raman spectrum using modified Z-Scores with ∇x(i) with the threshold = 7.
因此,在计算了∇x 的修改的 z 分数,并且通过设置适当的阈值来进行阈值处理之后,通过应用移动平均滤波器来去除和平滑尖峰。
其他例子
最后,给出了两个具有不同强度信号的尖峰信号的例子,显示了这种方法的优点。
Figure 13. Examples of two more spectra in the first row of graphs, their Z-scores (blue lines) , modified Z-scores (red lines) and modified Z-scores using ∇x(i) (black lines) in the second row of graphs and thei despiked spectra in the third row, are presented.
承认。我要感谢豪尔赫·路易斯·希塔和安娜·索拉古伦-比斯科花时间校对这些笔记。
[1]惠特克,达伦 a .,和凯文海斯。"消除拉曼光谱尖峰的简单算法."化学计量学和智能实验室系统179(2018):82–84。
[2] Iglewicz 和 D. Hoaglin。" ASQC 质量控制基本参考:统计技术."如何检测和处理异常值16(1993):1–87。
3 Colin Gorrie 的数据故事:检测离群值的三种方法。http://colingorrie.github.io/outlier-detection.html
[4]若昂·罗德里格斯。“离群值让我们发疯:单变量离群值检测”。中等。https://medium . com/James-blogs/outliers-make-us-go-mad-单变量-离群值-检测-b3a72f1ea8c7
生产中数据科学的会合体系结构
如何构建一个前沿的数据科学平台来解决数据科学中的真正挑战:生产化。集合点架构介绍。
第 1 部分:数据科学的真正挑战
不可能错过数据领域如何获得一些新的流行词汇。它曾经是“大数据”,但最近,它被数据湖、机器学习、人工智能、区块链和数据科学独角兽所主导。随着数据科学的大肆宣传,围绕它的生态系统不断扩大,越来越多的大数据平台承诺让数据科学变得简单,并为大众带来商业成功。
但是,数据科学有什么不同之处,以至于它需要新的方法和所有这些新的平台和产品?
2016 年的一项调查得出结论: 80%的数据科学都在准备和清理数据(80/20 法则)。数据科学家的这项调查很快流行起来,并发展成为数据科学领域公认的问题陈述。不幸的是。因为如果你从这篇博文中拿走一样东西
“模型的生产是数据科学中最困难的问题” (Schutt,R & O'Neill C.《从第一线直接做数据科学》, O'Reilly 出版社。加利福尼亚州,2014)
而不是准备数据。
为什么数据科学不同于任何软件项目。
Source: Kenneth Jensen, (wikimedia)
为了理解为什么数据科学是不同的,我仍然从臭名昭著的 80/20 规则和数据挖掘的跨行业标准过程(CRISP-DM)开始。尽管 CRISP-DM 早于今天的数据科学学科,但它完美地描述了数据科学家日常工作的很大一部分。自 1996 年以来,似乎发生了变化的方面是大量集成不良的数据源,以及对数据准备步骤的日益重视。因此,80/20 法则变得如此流行就不足为奇了。
但是在数据科学中,CRISP-DM 只是图片的一半!模型不是普通的软件,也不仅仅是部署数据科学(在此插入 meme!).模型具有独特的生命周期管理,以及独特的集成、自动化和操作要求。
生产中的模型是动态的,具有复杂的生命周期。不幸的是,生产中的模型管理很少被讨论或解决。重点仍然是数据准备和 80/20 法则的重要性。
然而,管理单个模型也不是全部,数据科学的复杂性仍在继续。在某个时候,将会出现一个挑战者模型:
解决这个问题的一种方法是使用传统的 A/B 测试场景和流量分流。但是你只能孤立地看到一个单一的模型响应。假设您正在尝试测试一个严重依赖于被评分用户的上下文的推荐模型。对所有模型的请求进行并行评分,然后简单地比较它们的评分,这样不是更好吗?此外,你的挑战者模型可能不会工作得很好。不幸的是,你必须让 10%的用户经历一次糟糕的体验才能找到答案。这显然需要一个更好的方法。
但是我们还没有完成。在成功的数据科学研究中,开发和生产的界限越来越模糊。一个单一的业务目标将会看到许多不同的现任和挑战者模型,以及在一个不断变化的环境中对这些模型进行再培训的要求,其中包括持续的基准测试、监控和生产移交。真实世界的场景将很快变得更像这样:
这些都是让任何 IT 部门都物有所值的要求。挑战在于解决数据科学工具包日益增长的异构性、数据基础架构所需的弹性和灵活性,以及复杂数据科学模型生命周期的端到端自动化。
第 2 部分:解决方案
认识集合建筑
总结前面对问题陈述的介绍,我们正在寻找一些架构来
- 并行评估大量现有车型和挑战者车型
- 管理模型生命周期
- 处理日益多样化的数据科学工具包
- 允许在不影响用户体验的情况下进行生产实验,并将业务目标与数据科学目标分离
- 将 SLA 和 GDPR 等企业需求从数据科学模型中分离出来
- 扩展到每分钟 50+k 页面负载的峰值,而无需雇佣大批 DevOps 工程师
这个非常真实的数据科学问题的解决方案来自于 Ted Dunning 和 Ellen Friedman 在他们的书《机器学习物流》(O'Reilly 2017)( 免费电子书)中命名为 Rendezvous Architecture 。该架构的核心是作为流的输入数据和使用发布-订阅消息模式订阅数据的模型。通过一个流接收评分请求允许我们轻松地分发一个请求并并行评估大量的模型。
但是它没有解决如何从大量模型中健壮地返回响应,同时支持企业需求。
为了返回一个响应,架构还将模型分数视为一个流,并与名称 lendingRendezvous service相结合。从概念上讲,rendezvous 服务订阅原始的评分请求,将它们与来自模型响应流的模型评分相结合。
在 rendezvous 服务中订阅评分请求将从成功返回评分输出的模型中返回响应的能力分离开来。它还允许 rendezvous 服务实现 SLA:在模型失败或被延迟并且没有评分输出到达 SLA 内的 rendezvous 服务的情况下,rendezvous 服务可以例如发送有意义的默认响应。这是可能的,因为会合服务首先知道评分请求。rendezvous 服务实现了模型评分输出与可配置 SLA 和超时策略的竞争条件。
关于 rendezvous 架构更详细的介绍,你应该读一下 Ted Dunning 和 Ellen Friedman 的伟大著作:https://mapr . com/ebooks/machine-learning-logistics/ch03 . html
采用这种概念架构并将其应用于我们提出的要求,我们得到了以下数据科学平台:
我们根据需要将架构划分为一个业务目标层次结构,该层次结构实现了企业需求和数据科学团队的建模目标。
整个平台是用容器化的无状态服务构建的,这提供了期望的解耦和可伸缩性。甚至有状态模型也可以在模型数据丰富器的帮助下在平台上实现,如下面步骤 3 中所讨论的。
- 当评分请求到达时,入口控制器将该请求分配给集合服务实例的评分评估服务,该集合服务实例实例化异步评估策略。这为模型评分输出设置了竞争条件。每个策略实例就像一个邮箱,收集它们对应的评分请求的模型评分输出。
- 评分评估服务将策略实例 ID 和集合服务 ID 附加到评分请求,并将其发布到该业务目标的输入数据流。
- 模型数据丰富器订阅带有评分请求的输入数据流。该服务附加了额外的数据点,如元数据或有状态模型的外部状态。例如,推荐模型可能会考虑用户以前的行为来创建推荐。因此,数据丰富器可以交叉引用用户 ID 和以前用户交互的缓存。模型数据富集器然后将富集的评分请求发布到建模目标信息流。
- 每个模型的消息消费者订阅建模目标输入流,并将评分请求发送到相应的模型实例。每个模型目标可以拥有一系列不同的模型,只要它们共享输入数据模式。每个模型目标还拥有一个诱饵模型和一个金丝雀模型,前者将评分请求记录到日志流中,后者用于检测输入数据中的漂移,并提供一致的基线来比较模型性能。
- 消息生产者基于集合服务 ID 将模型评分输出发送到相应的集合流,该集合服务 ID 已经由评分评估服务附加到消息。
- 分数收集服务从其相应的集合流中读取所有进入的模型评分输出。每条消息都有一个策略实例 ID,该 ID 已由评分评估服务附加到消息上。消息策略实例 ID 是分数收集服务和分数评估服务之间的共享卷上的 Unix 套接字的名称,其允许收集服务将模型评分输出发送到相应评分请求的等待策略实例。
- 等待策略实例通过 unix 套接字服务器接收模型分数,并评估其策略逻辑是否以特定分数响应发起的评分请求。
实现集合服务
该平台的大部分相当简单,因为它由无状态的容器化服务和简单的发布/订阅消息模式组成。在生产中,这可以使用舵图和水平 pod 自动缩放器以及循环负载平衡在 Kubernetes 上轻松部署。实际上,业务和建模目标中的平台图中的每个分组实体都是水平缩放的豆荚。
主要的挑战是实现有状态的集合服务。从概念上讲,最好将 rendezvous 服务描述为邮箱。每个活动评分请求都有一个等待模型评分响应的活动邮箱。这些邮箱接收其相应评分请求的模型评分,并执行附加的评分评估策略。
当模型分数被发布到流时,每个邮箱可以订阅该流,并过滤出它们相关的模型分数进行评估(扇出模式)。这将为每个订阅的邮箱复制邮件。在每分钟 50+k 个请求的规模下,大量现有和挑战者模型并行返回分数,这将是不切实际的。为了实现可伸缩性,我们必须保持每个运行的策略实例尽可能的轻量级。
我们用 Python 实现了分数评估服务,使用 asyncio 库实现了异步事件驱动的策略评估。以下代码是该服务的简化版本:
import asyncio app.route(‘/topic/test’, methods=[‘POST’])def incoming_scoring_request(): scoring_request = SomeMessageDeserialisation( request.get_json(), os.environ['THIS_RENDEZVOUS_SERVICE_ID'] ) loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) scoring_response = loop.run_until_complete( async_score_evaluation_service, scoring_request, loop ) return jsonify(scoring_response)async def async_score_evaluation_service(scoring_request, loop): policy = SomePolicy(loop.create_future()) policy_coro = asyncio.start_unix_server( policy.handle_connection, policy.socket_path, loop=loop ) policy_task = asyncio.ensure_future(policy_coro) extended_scoring_request = SomeMessageSerialisation( scoring_request, policy.socket_path ) message_task = syncio.ensure_future( publish(extended_scoring_request) ) try: scoring_response = await asyncio.wait_for(
policy.result_future, timeout=policy.sla
) except asyncio.TimeoutError: scoring_response = policy.default_value() return scoring_response
如代码片段所示,模型分数评估策略启动一个异步 unix 套接字服务器。套接字的路径由策略实例的 uuid 给出。这是获得模型分数所需的全部内容。除了评估服务,sidecar 分数收集服务订阅模型响应流。
import pulsarimport socket pulsar_consumer = get_message_consumer(os.environ['THIS_RENDEZVOUS_SERVICE_ID']) while True: msg = pulsar_consumer.receive() scoring_response = SomeMessageDeserialisation( msg.data() ) policy_socket = scoring_response.policy_socket_path sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(policy_socket) sock.sendall(SomeMessageSerialisation(scoring_response)) sock.close() consumer.acknowledge(msg)
它根据策略实例 ID 将消息发送到相应分数评估策略实例的 unix 套接字。在将扩展的评分请求发布到评分评估服务中该业务目标的数据流之前,我们将该 ID 附加到扩展的评分请求中。
为了在 Score Collection sidecar 和 Score Evaluation Service 之间创建连接,我在 unix 套接字的两个容器之间使用了一个共享卷。这种实现模式比简单的扇出模式伸缩性好得多,单个 Rendezvous 服务实例可以托管大量并发的分数评估策略。
我使用Apache Pulsar(link)作为分布式发布-订阅消息系统。Pulsar 不仅仅是一个高性能的消息传递系统,它可以轻松扩展到大量的主题,并以高度可扩展的消息持久存储为主要目标。主题压缩和分层持久存储(链接)允许 rendezvous 平台在未来无限期地保存消息,并重放评分请求,例如测试和验证新的挑战者模型或预热保持内部状态的模型。
下图显示了 minikube 开发环境中的一个示例:
该请求贯穿会合平台的所有元素,总时间为 51 毫秒。测试主题通过模型数据丰富器获取一个随机数,模型目标 test-0 运行一个简单的模型,该模型返回评分请求中所有数值的总和。我用那个装置来测试会合平台的元件。实际模型是集装箱化和解耦的,这允许我们独立地测试它们。这意味着 rendezvous 架构的开销在 40-50 毫秒之间。相对于该架构提供的广泛优势,这是一个非常小的成本,并且留下了充足的时间来获取外部数据点和评估复杂的模型。
做好这件事的代价是 40 毫秒
minikube 开发环境的负载测试表明,每秒 100 个请求也不是什么难事:
参考实现展示了 rendezvous 架构的优势,并展示了非常有前途的性能。我目前正在研究 Kubernetes 的生产,关注舵手和操作员。一旦我们在生产 Kubernetes 集群上部署了我们的平台,我将在这篇博客文章之后跟进我们的生产负载测试结果。
信用
我们正站在巨人的肩膀上。信用到期时的信用:
- Ted Dunning 和 Ellen Friedman 以及他们的励志书籍《机器学习物流》(O'Reilly 2017)介绍了概念上的会合架构
- 来自www.advancinganalytics.co.uk的 Terry McCann 和 Christopher Conroy 他们是我努力的早期信徒、贡献者和支持者
来自数据科学节的录音:
www.datasciencefestival.com Day 2 at Zoopla
Jan 是公司数据转型方面的成功思想领袖和顾问,拥有将数据科学大规模应用于商业生产的记录。他最近被 dataIQ 评为英国 100 位最具影响力的数据和分析从业者之一。
在 LinkedIn 上连接:https://www.linkedin.com/in/janteichmann/
阅读其他文章:【https://medium.com/@jan.teichmann】
歌曲中的重复:Python 教程
一首艾德·希兰歌曲的个案研究
Credit: Unsplash
每个人都听过一首歌或者知道一首歌听起来像什么。我可以漫不经心地说,每个人都可以用自己的话来定义一首歌。为了方便起见,一首歌曲(根据维基百科)是一首音乐作品,通常由人声演唱,使用声音和沉默以及各种形式(通常包括部分的重复)来表现独特和固定的音高和模式。
在他名为“歌曲的复杂性”的期刊文章中,计算机科学家 Donald Knuth 利用了流行歌曲从冗长且内容丰富的歌谣演变为高度重复的文本的趋势。由于有些人可能会立刻同意他的观点,这确实提出了一些问题,如:重复真的有助于歌曲成为热门吗?随着时间的推移,音乐真的越来越重复吗?
为了以案例研究的形式教授一些基本的 python 代码,我将测试这个假设(流行歌曲真的是重复的吗?)用我最喜欢的一首歌。检验这一假设的一种方法是找出独特的词,并计算这些词占歌曲总词数的比例。
在本教程中,我们将介绍:
- 变量和数据类型
- 列表和词典
- 基本算术运算
- 内置函数和循环
必备知识
为了充分利用本教程,您可以自己运行代码。
- 我们将要演奏的音乐是艾德·希兰的《完美》。这里可以复制歌词。然而,我在这个分析中使用的歌词被清理掉了,以得到一个结论性的结果。例如,我把像“我们会”这样的词改成了“我们会”等等。你可以在这里得到我版本的歌词
- 使用的编辑器是木星笔记本。这里是如何安装和使用它的快速教程。
出于本案例研究的目的,我们将通过提出两个主要问题来简化我们的假设:
- 与我们的案例研究歌曲《艾德·希兰的完美》的整个歌词相比,使用了多少独特的词?
- 在整首歌中重复使用最多的词是什么,使用了多少次?
让我们开始分析吧
基本的
1。 **A String**
是字符列表。字符是你可以在键盘上一次击键输入的任何东西,比如一个字母、一个数字或一个反斜杠。但是,Python 将字符串识别为在字符或文本的开头和结尾用双引号(" ")或单引号(' ')分隔的任何内容。例如:“你好,世界”
对于这个案例研究,一个字符串是我们的歌词,如下所示
2。 **Variables**
通常是用于赋值或存储值的描述性名称、单词或符号。换句话说,它们是任何数据类型的存储占位符。为了在任何时候引用一个值,这是非常方便的。变量总是被赋予一个等号,后面跟着
变量的值。(查看代码输出的一种方法是使用打印功能。您可能已经知道,Jupyter 笔记本没有打印功能也可以查看输出)
为了存储歌词,我们将赋予它一个名为perfect_lyrics
的变量。
3。 **Lists**
只需将不同的逗号分隔值放在方括号中,即可创建。它可以有任意数量的项,并且它们可以是不同的类型(整数、浮点、字符串等。).它甚至可以将另一个列表作为一个项目。例如:
list1 = [1,'mouse', 3.5, [2,'is',5.0]]
#3.5 is a float
现在我们已经对列表有了一个大概的了解。让我们回到我们的数据。
因为我们的目标之一是计算出使用的独特单词的数量,这意味着我们需要做一些计算,即计算每个单词。为了实现这些,我们不仅要把我们的字符串放到一个列表中,还要用一个**.split()**
方法来分隔每个单词。因此,我们的数据集将看起来像这样
输入
输出
从上面的输出中,您会注意到每个单词都被分成了独立的字符串。并且整个歌词组成了名为 split_lyrics (也是一个变量)的列表
我们还需要将其余单词和计数中的独特单词分开。为此,我们需要使用 python 函数。
功能是一组有组织的、可重用的代码,用于执行单个相关的动作。Python 有很多内置函数,比如 print()-显示输出,list()-创建列表,len( )-计算列表或字符串中的字符数,等等。Python 还允许你创建自己的函数。但是在这个案例研究中,我们不会创建自己的函数。
我们将在案例研究中使用几个函数,但我们将从 set()函数开始。为了从整个歌词中分离出独特的单词,我们需要一个 set()和 print()函数,即
输入
输出
为了统计整首歌词的字数,我们需要一个 len()函数
输入&输出
对提取的唯一单词进行同样的操作
我们的上述分析帮助回答了我们的第一个问题:*How many unique words were used as compared to the whole lyrics of the song?*
简单地说,在总共超过 290 个单词中使用了 129 个独特的单词。
我们的下一个目标是解决问题的第二部分What are the most repetitive words used and how many times were they used?
为了回答这个问题,我们需要学习更多的数据结构。
中间的
4。 **Dictionaries**
在 Python 中是无序的物品集合。数据结构只有值作为元素,而字典有一个**key:value**
对。每个键-值对都将键映射到其关联的值。字典经过优化,可以在已知键的情况下检索值。您可以通过用大括号({}
)括起逗号分隔的键值对列表来定义字典。冒号(:
)将每个键与其关联的值分开。一个简单的德-英词典就是一个例子:
colours = {"red" : "rot", "green" : "grün", "blue" : "blau", "yellow":"gelb"}print en_de["red"]#output will be the value of 'red'( the key) which is 'rot'empty_dict = {} #a dictionary can also be empty waiting to be filled up with information
5。 **Loops**
在试图一遍又一遍地运行同一块代码时非常有用。在 python 中,有两种类型的循环:for 和 while。对于这个分析,我们将更多地关注for loop
。for 循环用于迭代序列中的元素。当你有一段代码想要重复 n 次的时候,经常会用到它。
它是这样工作的:“对于列表或字典中的所有元素,这样做”
例如
list_number = [2,3,4]#input
for item in list_number:
multiple = 2 * item
print(multiple)
回到我们的数据集
要知道重复次数最多的单词,我们需要知道每个单词在歌词中出现的次数。为此,我们需要使用字典(存储每个单词及其对应的计数)和 for 循环(在每个单词出现时迭代计数过程)
首先,我们需要将唯一的单词存储在字典中
输入&输出
然后我们需要再次使用 for 循环来统计每一个唯一单词在整个歌词中出现的次数。
输入&输出
现在我们已经知道了每个单词出现的次数,让我们使用 sorted ( ) 函数将它们从最高到最低排序
只出现过一次的词好像太多了。因为我们的目标是找到最流行的单词,所以我们将通过切片将列表缩小到 10 个单词。你可以在这里了解更多关于切片的
输入&输出
然后变回字典
另一个问题是:艾德·希兰的歌曲《完美》中最流行的 10 个词是什么?通过使用字典数据结构下的 key()方法,然后创建这些单词的列表,我们可以很容易地提取这些信息。
输入&输出
从上面的输出代码中,我们可以肯定地说,在艾德·希兰创作的歌曲《完美的 T9》中,出现了 24 次的单词“我”
让我们进一步改进我们的分析
先进的
6。 **Visualizing data with python.**
已经开发了各种技术来可视化地呈现数据,但是在这个分析中,我们将把数据可视化严格地集中在 Python 中的一个库上,即 Matplotlib。
让我们快速直观地分析一下案例研究中最流行的 10 个词
见解摘要
我们可以从这个案例研究中获得哪些关键的见解?我可以找出三个
- 根据选择的歌曲,我们看到独特的词只占总词数的 44%
- 在使用的 129 个独特的单词中,大约有 70 个单词出现过一次,约占总使用单词的 24%。
- “我”这个词在整首歌中被使用了 24 次,也就是说,有 8 %的时间,一个“我”被使用了。
结论
这个案例研究确实有助于发现歌曲中有很大一部分是由重复的词组成的。然而,我们不能仅凭一首歌就断定唐纳德·克努特理论是正确的。我们需要分析更多的歌曲,才能得出结论说热门歌曲是一首歌中单词重复的结果。尽管指出艾德·希兰的实际上是一首热门歌曲是件好事……(至今仍在《我的世界》中)。
延伸阅读
如果您想提高您的 Python 技能,这些文章可能会有所帮助
附注:像我一样,任何人都可以学习成为一名数据分析师,如果你想了解我的下一个项目或我的学习更新,请随时注册我的 简讯
使用 Python-2 构建高级会计模型
使用正确的数据科学工具充分利用会计公式
Photo by Carlos Muza on Unsplash
背景
如果你看了我之前的文章这里,你就知道我们可以很容易地从雅虎财经刮出财务报表。但是现在呢?当您进行任何类型的业务评估和财务分析时,我们的数据框架中的大多数特征都是重要的指标。它们都是公开的和经过审计的信息,最终决定了股票价格的变动。管理层希望他们看起来不错,所以他们经常操纵他们,并确保数字符合公众的期望。
现在,这就是数据科学和您的领域知识发挥作用的地方。为了解释会计比率,你需要理解这些特征的含义。这往往需要上几堂大学会计课。你可能已经学过一些比率,如每股收益、利润率、速动比率等。今天,我将重点讨论股本回报率、与股本相关的企业盈利能力。
股本回报率=净收入/股本
数据清理
在进行任何数值操作之前,我们需要整理数据。以下是我们的目标:
- 将数据类型从 object 转换为 numeric。
- 将日期索引转换为 DateTime 以进行时序分析。
我不会在清理数据上做太多的细节,因为这是另一个话题,但是可以随意检查我写的这个函数。当你真正检查数据帧时,它们更有意义。你可以暂时忽略它。
def convert_to_int(df):
col = df.columns
for col in df:
temp = df[col].to_string().replace(‘,’,’’).split(‘\n’) # Replace comma with space and clean out extra spaces temp.pop(0) #Remove first erronous element df.index = pd.to_datetime(df.index) # Convert index to datetime df[col]= [i[10:].strip() for i in temp] # stripping off nth characters df[col] = pd.to_numeric(df[col], errors=’coerce’).fillna(0).astype(int) # Transform columns from object to numeric return df
简介
简单的杜邦模型将净资产收益率分解为 3 个部分
净资产收益率=(净收入/销售额)(销售额/总资产)(总资产/股东权益)
第一个组成部分侧重于经营业绩:每笔销售产生多少净收入。第二个衡量公司利用其资产创造销售收入的效率。第三个关注股权管理:你每股产生多少资产。
然而,如果你仔细观察引擎盖下发生的事情,你会注意到那些组件非常嘈杂。例如,净收入由财务费用组成,这意味着运营 KPI 与投资 KPI 相结合。第二,什么样的资产最能反映整体经营状况?我们想看看运营方面可以产生销售的资产。
现在你可能会问,我们为什么要关注运营?我们为什么不考虑投资和财务方面呢?我们确实有来自投资和贷款的现金流入。嗯,要看行业和商业模式。一般来说,经营现金流是企业的血液。其他一切都只是支撑。
高级杜邦模型
净资产收益率=净资产收益率+财务杠杆*利差
上述公式的想法是,我们希望将运营和财务部分分开。 1。我们想知道每股股票的回报率是多少。好了,我们现在来看经营中资产的回报,基本上就是净收入加上利息之类的财务费用(因为是从投资方来的,这是一个不稳定不可靠的指标)和少数股权(实际上不属于你的普通股权益份额的东西)。
2。好了,现在是财务杠杆部分。我买了你的股份,但是你用了多少来偿还债务呢?这样,在扣除成本后,有多少金融债务实际上产生了利润。
不要被不熟悉的公式吓倒,下面我来做个分解。一旦你理解了逻辑流程,一切都会变得清晰。
净营运资产回报率=净营运利润率*净营运资产周转率
净营业利润率=(净收入+净财务费用)/净销售额
净营业资产周转率=净销售额/平均资产
财务杠杆=平均净财务责任/平均普通股权益
净借款成本=净财务费用/平均净财务义务
净财务责任=总债务+少数股东权益+优先股
净财务费用=净利息费用* (1-税率)+优先股股息+盈利中的少数股权
利差=净经营资产回报率-净借款成本
数据操作
在这里,我创建了一个新的数据框架来包含所有的比率计算,以得出最终的股本回报率。为了更清楚,我用粗体突出了重要的部分。
ratio = pd.DataFrame()
接下来,我发现有效税率是多少。
ratio[‘effective tax rate’]= Income_st[‘Income Tax Expense’]/Income_st[‘Income Before Tax’]
然后我从运营部分减去财务部分。记住,我们想从我们的税收中拿回那部分。
**ratio[‘net operating margin’]= (Income_st[‘Income Before Tax’]+Income_st[‘Interest Expense’]*(1-ratio[‘effective tax rate’]))/Income_st[‘Total Revenue’]**
在这里,我使用今年和去年之间的平均时间点来更好地表示总负债和权益的潜在价值。
ratio[‘net operating asset turnover’] = Income_st[‘Total Revenue’]/((balance_st[‘Total liabilities and stockholders\’ equity’]+balance_st[‘Total liabilities and stockholders\’ equity’].shift(1))/2)**ratio[‘Return on NOA’]= ratio[‘net operating margin’]*ratio[‘net operating asset turnover’]**ratio[‘Net financial expense’] = Income_st[‘Interest Expense’]*(1-ratio[‘effective tax rate’])ratio[‘Net borrowing cost’]= ratio[‘Net financial expense’]/(balance_st[‘Total Liabilities’]+balance_st[‘Total Liabilities’].shift(1)/2)**ratio[‘spread’]= ratio[‘Return on NOA’]-ratio[‘Net borrowing cost’]****ratio[‘leverage’] =(balance_st[‘Total Liabilities’]+balance_st[‘Total Liabilities’].shift(-1)/2) / (balance_st[‘Total liabilities and stockholders\’ equity’]+balance_st[‘Total liabilities and stockholders\’ equity’].shift(1))/2**
这是最终的净资产收益率。
ratio[‘ROE(Advanced dupont)’] = ratio[‘Return on NOA’]+ ratio[‘leverage’]*ratio[‘spread’]
数据可视化
这是我们新的数据框架和一些简单的数据可视化。
你注意到有很多 NaN 值,这只是因为我在计算中使用了平均值,而我们没有 2015 年的数据。如果您有更多的数据,并按季度或月份进行分析,您会看到一个更复杂的数据框架。
用 Python 替换 Excel
在与我的初恋情人 Excel 相处了近十年后,是时候继续前进,寻找一个更好的另一半了,他在我的日常任务中与我同甘共苦,比我好得多,也比我快得多,并且可以在充满挑战的技术时代给我带来优势,在这个时代,新技术正以非常快的速度被新事物抛弃。这个想法是在 Python 中复制几乎所有的 excel 功能,无论是使用简单的过滤器,还是从行中创建数据数组并处理它们以获得有趣结果的复杂任务
这里遵循的方法是从简单的任务开始,然后转移到复杂的计算任务。我鼓励你自己重复这些步骤,以便更好地理解。
创造这种东西的灵感来自于一个免费教程的不可用性。我大量阅读并关注 Python 文档,您会从该网站中找到很多灵感。
GitHub 回购链接
https://github.com/ank0409/Ditching-Excel-for-Python
将 Excel 文件导入熊猫数据框架
第一步是将 excel 文件导入 DataFrame,这样我们就可以在它上面执行所有的任务。我将演示熊猫的 read_excel 方法,它支持 xls 和 xlsx 文件扩展名。
read_csv 与使用 read_excel 相同,我们不会深入讨论,但我会分享一个例子。
虽然 read_excel 方法包含了数百万个参数,但是我会让你熟悉那些在日常操作中非常有用的最常见的参数。
虽然 read_excel 方法包括数百万个参数,但我会让您熟悉在日常操作中会非常方便的最常见的参数
我将使用 Iris 样本数据集,该数据集在网上免费提供,用于教学目的。
请点击以下链接下载数据集,并确保将其保存在保存 python 文件的同一文件夹中
https://archive.ics.uci.edu/ml/datasets/iris
第一步是用 Python 导入必要的库
我们可以使用以下代码将电子表格数据导入 Python:
pandas.read_excel(io,sheet_name=0,header=0,names=None,index_col=None,parse_cols=None,usecols=None,squeeze=False,dtype=None,engine=None,converters=None,true_values=None,false_values=None,skiprows=None,na_values=None,keep_default_na=True,verbose=False,parse_dates=False,date_parser=None,千位=None,comment=None,skip_footer=0,skip _ footer = 0
因为有太多的参数可用,让我们看看最常用的一个。
重要熊猫 read_excel 选项
如果我们使用本地文件的路径,默认情况下它由“\”分隔,但是 python 接受“/”,所以要更改斜线或简单地将文件添加到 python 文件所在的同一文件夹中。如果你需要以上的详细解释,请参考下面的文章。https://medium . com/@ ageitgey/python-3-quick-tip-the-easy-way-to-deal-of-file-paths-on-windows-MAC-and-Linux-11a 072 b 58 d5f
我们可以使用 Python 扫描目录中的文件,并挑选出我们想要的文件。
导入特定的工作表
默认情况下,文件中的第一个工作表按原样导入到数据框中。
使用 sheet_name 参数,我们可以明确地提到我们想要导入的工作表。默认值为 0,即文件中的第一张图纸。
我们既可以提到工作表的名称,也可以传递一个整数值来引用工作表的索引
使用工作表中的列作为索引
除非明确说明,否则在数据帧中添加一个索引列,默认情况下从 0 开始。
使用 index_col 参数,我们可以操作数据帧中的索引列,如果我们将值从 none 设置为 0,它将使用第一列作为我们的索引。
跳过行和列
默认的 read_excel 参数假设第一行是列名的列表,它作为列标签自动包含在数据帧中。
使用 skiprows 和 header 等参数,我们可以操作导入数据帧的行为。
导入特定的列
使用 usecols 参数,我们可以指定是否在数据帧中导入特定的列
这并不是可用功能的终结,而是一个开始,您可以根据自己的需求来使用它们
让我们来看看从 10,000 英尺高度的数据
现在我们有了数据框架,让我们从多个角度来看这些数据,以便掌握其中的窍门/
Pandas 有很多我们可以使用的功能。我们将使用其中的一些来浏览一下我们的数据集。
“头”对“尾”:
查看第一个或最后一个的五个行。
默认为 5,然而该参数允许我们使用一个特定的数字
查看特定列的数据
获取所有列的名称
信息方法
给出了数据帧的概要
形状方法
返回数据帧的维度
查看 DataFrame 中的数据类型
切片和切块,即 Excel 过滤器
描述性报告是关于数据子集和聚合的,当我们稍微理解我们的数据时,我们开始使用过滤器来查看更小的数据集或查看特定的列,可能会有更好的理解。Python 提供了许多不同的方法来分割数据帧,我们将使用其中的几种方法来了解它是如何工作的
查看特定列
选择列有三种主要方法:
- 使用点符号:例如 data.column_name
- 使用方括号和列名,例如 data['column_name']
- 使用数字索引和 iloc 选择器 data.loc[:,' column_number']
查看多列
查看特定行的数据
这里使用的方法是使用 loc 函数进行切片,在这里我们可以指定由冒号分隔的开始和结束行
记住,索引从 0 开始,而不是从 1 开始
将行和列切片在一起
筛选列中的数据
过滤多个值
使用列表筛选多个值
筛选不在列表中或不等于 Excel 中的值
在多列中使用多个条件进行筛选
输入应该总是列表
我们可以用这种方法复制 excel 中的高级过滤功能
使用数字条件过滤
在 Excel 中复制自定义筛选器
组合两个过滤器以获得结果
包含 Excel 中的函数
从 DataFrame 中获取唯一值
如果我们想要查看具有唯一值的整个数据帧,我们可以使用 drop_duplicates 方法
排序值
按某一列对数据进行排序,默认情况下是升序排序
数据的统计摘要
数据帧描述方法
生成描述性统计数据,总结数据集分布的集中趋势、离散度和形状,不包括 NaN 值
字符列的汇总统计信息
数据聚合
计算特定列的唯一值
产生的输出是一个序列。您可以将其称为单列透视表
细胞计数
对每列或每行的非 NA 细胞进行计数
总和
汇总数据以获得行或列的快照
复制针对每一行添加总计列的方法
向现有数据集中添加汇总列
特定列的总和,使用 loc 方法并传递列名
或者,我们可以使用下面的方法
不喜欢新列,使用 drop 方法将其删除
在每列下添加总和
上面已经做了很多,我们使用的方法是:
- Sum_Total:对列求和
- T_Sum:将串行输出转换为数据帧并转置
- 重新索引以添加缺少的列
- Row_Total:将 T_Sum 附加到现有数据帧
基于标准的总和,即 Excel 中的 Sumif
苏米夫斯
平均 if
最大
福建话
Groupby,即 Excel 中的小计
数据框架中的数据透视表,即 Excel 中的数据透视表
谁不喜欢 Excel 中的数据透视表呢?它是分析数据的最佳方式之一,可以快速浏览信息,用一个超级简单的界面帮助你分割数据,帮助你根据数据绘制图表,添加计算列等。不,我们不会有一个接口来工作,我们将不得不显式地编写代码来获得输出,不,它不会为您生成图表,但我不认为我们可以在不了解数据透视表的情况下完成一个教程。
一个简单的数据透视表向我们显示了行中的 SepalWidth 值、列中的 SepalLength 值和列标签中的 Name 值的总和
让我们看看能不能把它弄复杂一点。
通过使用 fill_value 参数,空格现在被替换为 0
我们可以使用字典方法对值进行单独计算,也可以对值进行多次计算
如果我们使用 margins 参数,我们可以添加总计行
纵向查找函数
Excel 中的 vlookup 是一个多么神奇的公式啊,我想这是每个人在学习加法之前都想学的第一件事。当有人应用 vlookup 时看起来很迷人,当我们得到输出时看起来很神奇。让生活变得简单。我可以非常自信地说,它是在电子表格上进行的所有数据争论的支柱。
很遗憾我们熊猫没有 vlookup 功能!
因为我们在 Pandas 中没有“Vlookup”功能,所以使用 Merge 作为替代,这与 SQL 相同。总共有四个合并选项可用:
- ‘left’—使用左侧数据帧中的共享列并匹配右侧数据帧。将任何 N/A 填写为 NaN
- ‘右’—使用右侧数据帧中的共享列,并与左侧数据帧匹配。将任何 N/A 填写为 NaN
- ' inner' —仅显示两个共享列重叠的数据。默认方法。
- ‘outer’—当左数据帧或右数据帧中存在匹配时,返回所有记录。
上面的例子可能不是支持这个概念的最好例子,但是工作原理是一样的。
正如他们所说,“没有完美的教程存在”,我的也没有:)
用 Python 从各种工作表中提取数据
或者如何学习统一 Google 工作表、Excel 和 CSV 文件——代码指南
Widespread tabular data storage file formats — CSV, Microsoft Excel, Google Sheets
Python 通常被称为粘合语言。这是因为随着时间的推移,开发了大量的接口库和特性——这是由它的广泛使用和令人惊叹的、广泛的开源社区推动的。这些库和特性提供了对不同文件格式以及数据源(数据库、网页和 API)的直接访问。
这个故事着重于数据的提取部分。下周的故事将更深入地分析综合数据,以获得有意义和令人兴奋的见解。
了解如何使用 Seaborn 快速生成漂亮而有见地的图表
towardsdatascience.com](/how-to-explore-and-visualize-a-dataset-with-python-7da5024900ef)
但是不要让这阻止你自己分析数据。
您将学到的内容:
- 从 Google Sheets 中提取数据
- 从 CSV 文件中提取数据
- 从 Excel 文件中提取数据
这篇文章是写给谁的:
- Python 初学者
- 不得不经常争论数据的人
由于本文旨在作为一篇代码文章,您应该设置您的开发环境(我推荐 Jupyter Notebook/Lab)并开始一个新的笔记本。你可以在这里找到源代码和文件。
如果你不知道如何使用 Jupyter/Python。请查看该指南:
到底是什么阻止了你?下面是如何开始!
towardsdatascience.com](/get-started-with-python-e50dc8c96589)
情况:
在今天的故事中,我将带你进入一个虚构但可能非常熟悉的场景。你要结合各种来源的数据来创建一个报告或运行一些分析。
免责声明:下面的例子和使用的数据完全是虚构的
你的任务是找出如何提高你的销售团队的业绩。在我们假设的情况下,潜在客户有相当自发的需求。当这种情况发生时,您的销售团队会在系统中输入一个订单线索。然后,您的销售代表会尝试在订单线索被发现时安排一次会议。有时在之前,有时在之后。你的销售代表有一个费用预算,并且总是把会议和他们付钱的一顿饭结合在一起。销售代表报销他们的费用,并将发票交给会计团队处理。在潜在客户决定是否接受你的报价后,勤奋的销售代表会跟踪订单线索是否转化为销售。
对于您的分析,您可以访问以下三个数据源:
- 100,000 条订单线索(谷歌表单)
- 约 50.000 份餐费发票(Excel 文件)
- 公司和负责这些公司的销售代表的列表(CVS 文件)
获取 Google Sheets 数据:
访问 Google Sheets 是三者中最复杂的,因为它要求您设置一些使用 Google Sheets API 的凭证。理论上,您可以抓取一个公开可用的 Google Sheet(即,提取 HTML 源代码),但是您必须使用 Beautiful Soup 之类的工具进行大量的数据操作,才能将 HTML 转储转换成有用的东西。我确实试过这个,但是结果很乱,不值得努力。那就 API 吧。此外,我们将使用 gspread 更加无缝地转换成熊猫数据帧。
获取 OAuth2 凭据
前往 谷歌开发者控制台 并创建一个新项目(或者选择一个已有的)。单击“创建项目”按钮。如果你的公司使用谷歌邮件,你可能想换成你的私人账户,以避免潜在的权限冲突。
为你的项目选择一个名字(名字不重要,我称之为矿媒数据提取)
点击 API&服务并前往库
启用 Google Sheets API。点击结果,在下一页点击启用 API。
创建服务账户&密钥文件。服务账户是用于具有有限访问权限的编程访问的专用账户。服务帐户可以而且应该由 project 设置,并具有尽可能具体的权限以及手头任务所必需的权限。
创建一个 JSON(另一种文件格式)密钥文件。对于角色,选择“项目->查看器”
如果在上一步中没有设置角色,现在就设置。
Note: Setting “Viewer” is somewhat restrictive. If you want to create google sheets programmatically, you’ll have to choose a different setting
您的私有 JSON 密钥文件将可以下载或者自动下载。我建议将该文件重命名为“medium _ Data _ Extraction _ key . JSON ”,并将该文件移动到您的 Jupyter 笔记本的文件夹中,因为这将使下面的示例无缝工作。JSON 文件包含您最近创建的服务帐户的凭证。
完美。你差不多完成了。
下载数据
首先,您必须通过在笔记本中运行以下命令来下载并安装附加的软件包。
!pip install gspread
!pip install oauth2client
其次,您必须确保将之前创建的 JSON 密钥文件移动到运行 Jupyter 笔记本的文件夹中,如果它还不在那里的话。或者,您可以指定一个不同的 GOOGLE_KEY_FILE 路径。
WORKBOOK_KEY 是我为本次会议准备的 Google 工作表的工作簿 id。
WORKBOOK_KEY = '10HX66PbcGDvx6QKM8DC9_zCGp1TD_CZhovGUbtu_M6Y'
该表是公开的。如果您想下载不同的数据,您需要更改 WORKBOOK_KEY。id 通常可以在问题 URL 的 Google 工作表的最后两个反斜杠之间找到。
获取 CSV 数据
我们既可以通过传统方式从 repo 下载 CSV 数据,也可以使用下面的代码片段。同样,您可能需要像这样安装缺失的请求包(在您的笔记本中运行):
!pip install requests
CSV 数据的美妙之处在于 Python / Pandas 可以开箱即用地处理它。对于 Excel,还需要额外的库。
获取 Excel 数据
在我们开始之前,你很可能必须安装 openpyxl 和 xlrd ,这使得你的熊猫也能打开 Excel 表格。
!pip install openpyxl
!pip install xlrd
完成之后,我们以同样的方式获得 Excel 数据,并将其加载到另一个数据框架中。
搞定!您已经创建了三个不同的 Pandas 数据框,并且可以在同一个 Jupyter 笔记本中访问它们:
- 销售 _ 数据
- 销售 _ 团队
- 发票
请继续关注下周的文章,届时我们将探讨如何组合这些数据框架并分析数据。
在 Excel 中用 Java 替换 VBA
几乎每个工作场所都有 Excel。从顶级投资公司和大规模工程公司到个体商人,人们都使用 Excel 完成工作。
本文将探讨使用 Excel 的一些问题和优势,以及如何使用嵌入 Excel 的Java来克服这些问题。
你不用找很远就能找到对 Excel 的批评和它的错误使用导致公司重大损失的案例。在过去的几年里,有许多案例表明,Excel 电子表格中的错误至少是令人尴尬且代价高昂的错误的部分原因。
一个简单的电子表格错误让一家公司损失了 2400 万美元。这个错误导致了加拿大大型电力公司 TransAlta
www.theregister.co.uk](https://www.theregister.co.uk/2003/06/19/excel_snafu_costs_firm_24m/) [## 伦敦鲸的崩溃部分是由于使用 Excel 时的一个错误
这是人们开始在博客圈谈论的事情,应该让整个华尔街暂停下来。结束…
www.businessinsider.com](https://www.businessinsider.com/excel-partly-to-blame-for-trading-loss-2013-2?r=US&IR=T)
有这样的风险,为什么公司还在用 Excel,有什么办法可以防止类似的情况发生?
Excel 被如此大量使用的主要原因是 工人生产率 。使用 Excel 的人可以比使用任何其他工具更有效地完成大量复杂的工作。
软件开发人员经常争辩说,用他们最喜欢的编程语言也能达到同样的效果。从技术上讲,他们可能是正确的,但这是假设每个人都有时间和兴趣学习成为一名开发人员(这需要我们大多数人很多很多年)。
大多数公司没有资源让开发人员专门为每个业务用户服务,即使他们有,那么沟通需要什么和迭代以获得期望的结果将很难与个人“拼凑”Excel 电子表格相竞争。
Excel 的问题
Excel 有什么地方容易出错?这本身没有什么,但是开发人员已经习惯了各种事情来减少非 Excel 解决方案中的风险。下面列出了 Excel 电子表格开发中的一些缺点。
- 太复杂。一个电子表格可能开始时相当简单,只有几个单元格和公式。然后它一点一点地成长。范围被复制以处理越来越多的情况或多组数据,直到很难理解发生了什么。这项任务可能仍然相当简单,但是由于需要复制,而且每个单元格只能容纳一个数据单元,电子表格可能会变得过于复杂。
- 最少或无测试。Excel 电子表格很少受到测试。通常没有为 VBA 代码编写的单元测试,唯一的功能测试通常由电子表格的作者在有限的输入集上进行。当另一个用户不得不使用同一个电子表格时,很有可能因为他们不熟悉其工作原理的细微差别,他们会偶然发现一些从未测试过的错误。
- 陈旧或过时的数据。将 Excel 连接到外部数据源可能很棘手。它可以直接连接到数据库,但是如果您需要的数据是由另一个系统产生的,或者您没有直接访问所需数据的数据库,该怎么办?数据经常从其他系统的报告中复制并粘贴到 Excel 中,通常无法知道数据上次是何时复制的,甚至无法知道数据是否完整。
- 虫子失控蔓延。即使您知道一个电子表格中有错误,并且您已经知道如何修复它,您如何找到复制并粘贴了相同 VBA 代码的其他电子表格的所有实例,或者甚至是完全相同的电子表格的副本?很可能你不能。电子表格被复制并通过电子邮件发送,电子表格、数据和代码之间没有分离。
- 版本控制地狱。当你正在处理一个大的电子表格,并且它已经稳定运行了,你会怎么做?最有可能的答案是你保存一份拷贝——也许在文件名上加上日期。这就是 Excel 中的版本控制。如果一个变化有意想不到的后果呢?你怎么知道这个变化是什么时候引入的?几乎不可能!
我们如何解决这些问题?
这些问题都源于采用表面上很简单的东西(相关数字的网格),并将其推到极难推理其行为和正确性的程度。
本质上,Excel 是一种表达事物之间关系的方式。 A1 是 B1 和 C1 之和,例如**。当这些关系变得越来越复杂时,问题就开始出现了。
如果你想计算“ A1 是时间序列的每日收益的方差 X ”,在 Excel 中会是什么样子?如果您是一位经验丰富的 Excel 用户,您可能会想象一个表示时间序列 B 的表,其中包含用于计算回报的额外列和用于计算方差的公式。但是,如果现在我们想计算另一个 N 时间序列的回报呢?复制并粘贴每个新时间序列的公式?这就是错误开始蔓延的原因!
更好的方法是将计算时间序列日收益方差的算法封装到一个函数中。然后我们可以重复调用这个函数,次数不限,不会有中间单元格被编辑或复制错误的风险。
现在,设想用 Excel 中的单个单元格来表示时间序列,而不是数据表。如果这可以实现,那么我们又回到了两个单元之间的简单关系—“A1 = daily _ returns _ variance _ of(B1)”。突然间,我们的电子表格开始看起来不那么复杂了!
我们仍然有时间序列数据必须来自某处的问题。与其从另一个系统或数据库复制粘贴,不如我们有一个函数直接从那个系统或数据库加载时间序列?这样,每次我们计算电子表格时,我们都知道数据是最新的和完整的!继续前面的例子,我们可能有“ B1 =负载时间系列(股票,开始日期,结束日期)”。稍后,我们将讨论如何在单个单元格中存储整个数据集。
通常不仅仅是使用 Excel 的人编写他们使用的函数。通过为最终用户提供一组可靠的 Excel 函数,技术团队可以比仅仅编写仅具有浅层 Excel 集成的应用程序(如导出报告)更有效地支持业务。
Java 对我们有什么帮助?
通过思考我们的电子表格,将算法放入函数中,并通过直接获取数据而不是复制和粘贴,我们已经解决了 Excel 电子表格的几个大问题。我们还没有触及如何编写这些函数,以及围绕测试、错误修复和版本控制的问题。
如果我们决定在 VBA 编写我们所有的函数(相信我,很多人都这么做!)那么我们就不能利用过去 20 年中软件开发的任何进步!
Java 与现代软件开发并驾齐驱,在 VBA 上有很大贡献。
- 测试。Java 有许多不同的测试框架,都有不同的优点和缺点。无论您选择哪一种,能够在您的代码库上运行自动化测试套件都会让您确信它在做正确的事情。这在 VBA 是不可能的。
- 广泛的库支持。编写 VBA 代码通常是编写网上找到的相当标准的算法,并把它们转换成 VBA。想做一些琐碎的事情,比如对一组数据进行排序?在 Java 中这不成问题,但在 VBA,你要负责确保你的排序算法有效,并且不需要任何测试。现在想象一下写一个复杂的衍生品定价模型!
- 将代码放在 Excel 之外。 VBA 代码通常保存在工作簿中,这就是为什么在共享工作簿时,错误变得如此难以追踪。如果您的电子表格引用了一个编译过的 Java 库(JAR ),那么它就在所有引用它的电子表格之外,可以很容易地更新。
- 版本控制。 Java 源代码只是文本,因此很容易被签入版本控制系统。大多数 Java IDEs 对此有很好的支持,因为这是现代软件开发的标准部分。
- 发展环境。VBA 编辑器(VBE)已经很多年没变了。它只提供了一个非常基本的文本编辑器,具有基本的调试功能。另一方面,Java 有一系列优秀的 ide 可供选择。
但是 Java 不是 Excel 的一部分!
的确如此,但是 Excel 有一个“加载项”的概念,允许开发人员扩展 Excel 的功能。一个这样的插件是 Jinx,Excel Java 插件。
使用 Jinx ,你可以完全抛弃 VBA,完全用 Java 编写工作表函数、宏和菜单。
用 Java 编写工作表函数就像在 Java 方法中添加 Jinx 的@ExcelFunction 注释一样简单:
**package** **com.mycompany.xladdin**;
**import** **com.exceljava.jinx.ExcelFunction**;
*/***
** A simple Excel function.*
**/*
**public** **class** **ExcelFunctions** {
*/****
** Multiply two numbers and return the result.*
**/*
**@ExcelFunction**
**public** **static** double multiply(double x, double y) {
**return** x * y;
}
}
您可以返回您期望的所有基本类型,以及 1d 和 2d 数组。对于更复杂的类型,您可以编写自己的类型转换器,或者您可以将 Java 对象作为对象句柄直接返回给 Excel,以便传递给另一个 Java 方法。
jinx免费下载。参见 Jinx 用户指南了解更多关于如何用 Java 替代 VBA 的信息。
将时间序列作为单个单元格返回是怎么回事?
Jinx 函数可以返回所有你期望的标准类型(整型、双精度型、数组等。),但是也可以返回 Java 对象!当一个复杂的 Java 对象(比如一个表示从数据库加载的时间序列的类)被返回时,它将作为一个对象句柄返回到 Excel。然后,可以将该对象句柄传递给其他 Jinx 函数,并将从第一个函数返回的原始 Java 对象传递给 Java 方法。
对于简化电子表格来说,这是一种非常有用的技术,可以避免电子表格中涉及到复杂的数据。需要时,可以使用 Jinx 数组函数将对象扩展为 Excel 数组。
您可以在用户指南的 Jinx 对象缓存部分了解更多关于这些对象句柄的信息。
其他语言
这些技术不是 Java 独有的。
其他 JVM 语言也是如此,比如 Scala T1 或 T2 kot Lin T3。Jinx 适用于所有 JVM 语言,不仅仅是 Java。
另一种编写 Excel 插件的流行语言是 Python。这可以通过使用 Excel 的 PyXLL 插件来实现。
复制多伦多图书语料库数据集——一篇综述
通过从原始来源收集和预处理图书,复制不再公开的多伦多图书语料库数据集
Front page of the Smashwords website
虽然 Toronto BookCorpus (TBC)数据集不再公开提供,但它仍然经常用于现代 NLP 研究(例如,像 BERT、RoBERTa、XLNet、XLM 等的变压器)。)因此,对于我们这些无法在数据集离线前获取其副本的人来说,这篇文章提供了一种尽可能复制原始 TBC 数据集的方法。
🔍了解原始的多伦多图书语料库数据集
因此,为了尽可能好地复制 TBC 数据集,我们首先需要查阅介绍它的 原始论文 和 网站 以更好地理解它的内容。
在论文中,朱等人(2015)写道:“我们从网络上收集了 11038 本书的语料库。[……]我们只收录了超过 2 万字的书籍,以过滤掉可能更嘈杂的短篇故事。”接下来,作者给出了一些汇总统计数据:
从网站上,我们了解到网站 Smashwords 是数据集中收集和使用的 11038 本书的原始来源。
📚收集书籍
现在我们已经(大致)知道了要收集多少本书,从什么来源收集,我们就可以开始收集这些书了。为此,我写了一些抓取 Smashwords 网站的代码,在 这个 GitHub 资源库 中公开。代码很快(并发),结构良好,有据可查,所以应该非常容易使用。
Inspector mode on a Smashwords book page (accessible through “Inspect Element” or F12 on Firefox)
🔗获取纯文本图书 URL
为了获得要下载的明文书籍的 URL 列表,我们首先需要从 Smashwords 的首页获取书籍页面的 URL(每本书在 Smashwords 上都有自己的页面)。接下来,我们可以从这些书籍页面中抓取明文书籍的 URL 进行下载。你可以使用我的代码 在这里 找到这样做的说明。
📥下载明文书籍
现在我们有了一个要下载的明文书籍列表(使用它们的 URL),我们需要…下载它们!这有点棘手,因为 Smashwords(暂时)阻止任何在一定时间内下载太多书(> 500 本)的 IP 地址。然而,这可以通过在下载书籍和经常切换 IP 地址(大约 30 次)时使用 VPN 来规避。你可以使用我的代码 在这里 找到这样做的说明。
⚙️预处理书籍
为了获得 Toronto BookCorpus 数据集在大小和内容方面的真实副本,我们需要对我们刚刚下载的明文书籍进行如下预处理:1 .句子标记的书籍和 2。将所有书籍写入一个文本文件,每行一句话。你可以使用我的代码 在这里 找到这样做的说明。
就这样,大功告成!🙌现在,您可以使用您刚刚创建的 Toronto BookCorpus 数据集的副本,亲自尝试 NLP 中最新最棒的内容。🤗
[1] Zhu,y .,Kiros,r .,Zemel,r .,Salakhutdinov,r .,Urtasun,r .,Torralba,a .,& Fidler,s .,对齐书籍和电影:通过观看电影和阅读书籍实现类似故事的视觉解释(2015),《IEEE 计算机视觉国际会议论文集》(第 19–27 页)。
使用 Keras 和 TensorFlow 报告时间执行预测
这篇文章的目的是用实践的方式向软件开发者解释机器学习。该模型基于企业系统中的一个常见用例—预测生成业务报告之前的等待时间。
Source: Pixabay
用例
业务应用程序中的报告生成通常需要时间,可能是几秒钟到几分钟。生成报告需要时间,因为通常会获取和处理许多记录,这个过程需要时间。用户经常感到沮丧,他们不知道要等多久才能完成报告,可能会关闭浏览器等。如果我们能够在提交报告请求之前通知用户——执行它需要多长时间,这将是一个很大的可用性改进。
我已经使用 Keras 回归实现了机器学习模型,根据训练数据(来自过去报告执行的日志信息)计算预期的报告执行时间。Keras 是一个将 TensorFlow 复杂性包装成简单且用户友好的 API 的库。
这篇文章的目标是为软件开发人员提供一步步的指导,告诉他们如何构建一个简单而有用的机器学习模型。
Python 源代码和训练数据可以在我的 GitHub repo 上获得。这段代码基于 Keras 教程。
数据
使用 Pandas 库从 CSV 文件中获取训练数据:
column_names = ['report_id','report_params','day_part','exec_time']
raw_dataset = pd.read_csv('report_exec_times.csv')
dataset = raw_dataset.copy()
数据有四个特征,其中 exec_time 是目标特征(我们将要学习预测的那个)。 Report_id (报告类型标识符)和 day_part (一天标识符的一部分——上午、中午或下午)是分类特征,我们需要对这些特征进行编码,以帮助机器学习模型从中学习。基于报表类型,不同的报表具有不同的复杂性,模型将学习计算报表执行时间。如果指定了更多的报告参数,则报告的执行速度会更快(在当前的训练数据中假设,但这可以更改)-要处理的数据会更少。假设报告在中午和下午执行速度较慢(同样,如果您的场景不同,这可以更改)。
数据处理
我们需要对分类特征进行编码( report_id 和 day_part ,并对 report_params 特征进行规范化。这将有助于机器学习模型以更少的错误从数据中学习。
分类特征编码以一种简单的方式完成-查找所有唯一值,创建与唯一值一样多的列,并为当前行中与值匹配的列赋值 1。
从数据集中移除分类要素:
report_id = dataset.pop('report_id')
day_part = dataset.pop('day_part')
当值与当前行中的值匹配时,通过向数据集添加新列并设置 1 来编码 report_id 和 day_part 功能:
dataset['report_1'] = (report_id == 1)*1.0
dataset['report_2'] = (report_id == 2)*1.0
dataset['report_3'] = (report_id == 3)*1.0
dataset['report_4'] = (report_id == 4)*1.0
dataset['report_5'] = (report_id == 5)*1.0dataset['day_morning'] = (day_part == 1)*1.0
dataset['day_midday'] = (day_part == 2)*1.0
dataset['day_afternoon'] = (day_part == 3)*1.0
拆分行的子集进行测试是一个好主意,这将有助于评估模型定型质量。通常的做法是使用大约 20%的数据进行测试:
train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)
下一步是为训练数据集生成统计数据(我们对目标变量的统计数据不感兴趣):
train_stats = train_dataset.describe()
train_stats.pop("exec_time")
train_stats = train_stats.transpose()
train_stats
创建标签(目标变量)—我们将训练模型来预测标签(执行时间):
train_labels = train_dataset.pop('exec_time')
test_labels = test_dataset.pop('exec_time')
归一化数据-将要素转换为相似的比例(数字之间不会有大的差异),这将有助于模型更好地学习。使用先前计算的数据集统计信息完成归一化:
def norm(x):
return (x - train_stats['mean']) / train_stats['std']normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)
Keras 车型
模型用 Keras API 定义。建立一个具有两层数据处理和第三层数据输出的神经网络。根据我对给定训练数据的测试,当每层有 50 个单元时,模型表现良好。使用 SGD(随机梯度下降)优化器(把它想成是一种从一步到另一步改进训练的工具)。训练质量——损失,通过均方误差度量来测量。这表明训练过程进行得有多顺利:
def build_model():
model = keras.Sequential([
layers.Dense(50, activation='sigmoid', input_shape=[len(train_dataset.keys())]),
layers.Dense(50, activation='sigmoid'),
layers.Dense(1)
])optimizer = keras.optimizers.SGD(0.001)model.compile(loss='mean_squared_error',
optimizer=optimizer,
metrics=['mean_absolute_error', 'mean_squared_error'])
return model
模型训练和评估
Keras 提供了一个选项来定义提前停止回调。这有助于防止模型过度拟合。如果在 10 次迭代中没有改进,您可以指定停止训练:
model = build_model()# The patience parameter is the amount of epochs to check for improvement
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)history = model.fit(normed_train_data, train_labels, epochs=EPOCHS,
validation_split = 0.2, batch_size=40, verbose=0, callbacks=[early_stop, PrintDot()])plot_history(history)
使用验证分割很重要,它会自动分配一部分训练数据,以便在训练过程中不断评估模型质量。
训练结果,由对照验证数据的训练误差表示:
Training results
让我们通过针对测试数据集运行模型来评估训练模型的质量:
loss, mae, mse = model.evaluate(normed_test_data, test_labels, verbose=0)print("Testing set Mean Abs Error: {:5.2f} Report Execution Time".format(mae))
结果——误差约为 4 秒,这非常合理:
Testing set Mean Abs Error: 3.65 Report Execution Time
新数据预测
我们已经准备好针对新数据运行我们的模型,新数据是训练或测试数据集中不存在的数据。我将使用类型 1 的报告,并告诉报告在下午执行(类型 3)。报告参数的数量等于 15,这样数量的参数在训练数据中不可用。让我们看看模型将如何执行,如果指定了更多的参数,它应该会选择更快的报告执行趋势。
数据帧结构:
headers = ['report_id', 'report_params', 'day_part']
dataset_input = pd.DataFrame([[1, 15, 3]],
columns=headers,
dtype=float,
index=['input'])
标准化:
report_id = dataset_input.pop('report_id')
day_part = dataset_input.pop('day_part')dataset_input['report_1'] = (report_id == 1)*1.0
dataset_input['report_2'] = (report_id == 2)*1.0
dataset_input['report_3'] = (report_id == 3)*1.0
dataset_input['report_4'] = (report_id == 4)*1.0
dataset_input['report_5'] = (report_id == 5)*1.0dataset_input['day_morning'] = (day_part == 1)*1.0
dataset_input['day_midday'] = (day_part == 2)*1.0
dataset_input['day_afternoon'] = (day_part == 3)*1.0
编码:
normed_dataset_input = norm(dataset_input)
使用定型的 Keras 模型预测报表时间执行:
res = model.predict(normed_dataset_input)
结果:429.1053772 秒
让我们看看训练数据。具有 10 个参数的类型 1 和日期时间类型 3 的报告被记录为在 431 秒内执行。在同一时间使用更多参数的相同报告执行速度更快,这意味着模型运行良好。
模型保存和重用
了解如何将训练好的模型保存到文件中以供将来重用是很有用的:
model.save("report_exec_times_model.h5")
模型还原:
from keras.models import load_modelmodelFromFile = load_model('report_exec_times_model.h5')
modelFromFile.summary()
您可以在恢复的模型上运行预测功能,就像在刚刚训练的模型上一样:
res = modelFromFile.predict(normed_dataset_input)
基巴纳的报告和数据可视化
简介
在本文中,我想根据我的个人经验展示一下 Kibana 的功能。我的目的是对 Kibana 的功能给出一个高层次的概述,并分析定制插件对旋转和报告的需求。在接下来的文章中,我希望对 Kibana 进行一次的深入探索,并更详细地介绍数据可视化过程。
什么是基巴纳
凭借 GitHub 上超过 11k 颗星星, Kibana 赢得了全世界开发者的心,多年来一直是弹性搜索数据可视化的最佳平台。不是没有原因的。
那么是什么让 Kibana 成为弹性搜索的必备工具呢?
它的主要目的听起来很简单,但它确实很强大:
- Kibana 旨在通过提供一个单一的接口,使与弹性堆栈的交互变得简单而省时,从而帮助您更好地理解您的数据。 Kibana 为您做了很多繁重的工作,包括通过 REST API 查询 Elasticsearch 的数据。通过这种方式,它消除了手工编写查询的需要。
- 你会喜欢的另一个特性是,Kibana 是 100% 开源的——它的源代码可以在 GitHub 库上找到,每个人都可以为它的开发做出贡献。由于这个原因,产品被积极地更新、维护和增强。
- 此外,社区非常强大并且支持——你可以在基巴纳讨论论坛上感受到这一点。
可视化能力
让我简单介绍一下可视化功能。
当您将数据导入到 Kibana 中时,神奇的事情就开始了。
有多个核心可视化,如区域、饼图、线条和条形图、直方图、日光、热度、区域和坐标图、量规、
控件值得特别关注——使用它们,您可以添加交互式输入(下拉菜单和单选滑块)并在实时中过滤仪表板的内容。
除了基本的可视化,Kibana 还支持Vega——一种高级语法,允许快速构建定制的可视化。
如果你对分析时间序列数据感兴趣,你可以利用 Timelion 提供的功能。Timelion 是一种特殊类型的可视化工具,它可以获取原始时间序列数据,并以某种方式呈现出来,从而帮助您从数据中获得可操作的见解。
一旦定义了索引模式并选择了可视化,就可以应用度量聚合和桶聚合来对符合特定搜索标准的文档进行分类。
人们可能会对各种口味和用途的 Y 轴聚合印象深刻,尤其是统计聚合:um、平均值、最小值、最大值、计数(唯一计数)、标准偏差、中值、百分位数、百分位数排名、最高命中率和地理质心。
对于 X 轴,您可以从桶聚合中受益,如日期直方图、范围、术语、过滤器和重要术语。除了聚合之外,您还可以通过应用后续的子聚合来进一步划分数据。
除了上述聚合,您还可以定义父管道和同级管道聚合。要详细了解所有可能的聚合,我推荐阅读这篇综合文章。
为了只显示符合特定标准的文档中的数据,您可以添加字段过滤器。
过滤有两个选项:
- 通过使用基巴纳查询语言 (KBL)或 Lucene 作为语法来编写搜索查询。
- 通过点击可视化元素。
添加过滤器的界面非常舒适——来看看吧:
没有任何东西限制您编写基于多个字段和条件的复杂过滤器。
可视化样本
以下是一个堆积条形图的示例,您可以创建该图来了解承运人飞往特定目的地的航班的平均延误时间:
这种可视化建立在样本飞行数据的基础上。
保存结果
一旦您对结果感到满意,您就可以保存创建的可视化。它已准备好添加到仪表板中,并与您的队友共享。可视化是完全可重复使用的。
向仪表板添加组件
下面是一个可以用 Kibana 构建的仪表板示例:
您可以通过查看底层的原始数据或聚合数据来检查每一个可视化,如果有必要,甚至可以将这些数据导出到 CSV。
为了数据分析过程的完整性,生成的仪表板可以转换为 PDF 和 PNG 格式的定制报告。
个人印象
最酷的一个优点是,Kibana 让你可以自由控制仪表盘的几乎每个方面。从提供给可视化效果的数据源到调整特定元素的单个颜色。其他强大的特性是聚合和过滤功能。
但是我特别喜欢仪表盘的元素是完全交互式和可配置的。每个组件都可以根据您的喜好定制—您可以更改颜色、图例、标题等。
增强了基巴纳语的报告功能
作为商业智能的工具,Kibana 是完美的。它的界面允许在几分钟内创建一个仪表板,并在它的帮助下分析数据。
尽管有大量的可视化工具,如果基巴纳有一个专门为高级报告目的设计的工具,那就太好了。它应该能够通过切片和切块从不同角度查看数据。在我看来,数据透视表最适合这项任务。Kibana 有一个插件,很容易安装和使用 Elasticsearch 数据。它叫 Flexmonster 。虽然最初是作为一个可以集成到任何使用 JavaScript 的应用程序中的数据透视表组件创建的,但它也可以作为 Kibana 的一部分。你可以将它连接到 Elasticsearch index ,从中获取文档并开始探索数据。
透视表的特性
Flexmonster 为有效的报告提供了多种功能,如聚合函数、过滤器、排序以及内置的将报告导出为 PDF、Excel 和其他格式的。
对于聚合,有 sum、count、distinct count、average、min 和 max 函数可用。
过滤选项
您可以按成员名称或报表筛选器来筛选数据,以保持报表井井有条。
但是我想特别强调的一个特性是通过 UI 完全交互地改变切片的能力。设置好一个报告后,你可以将 拖放到 网格的右边。要知道哪些记录支持聚合值,您可以钻取单元格。
一个额外的优势是组件的性能。人们可以注意到大量的行被足够平滑地渲染。
数据透视表
我喜欢的另一件事是在网格和图表模式之间切换的能力。通过单击工具栏上的按钮,您可以立即在图表中显示报告的层次结构。图表也支持过滤。
定制组件
数据透视表提供了通过在紧凑视图和经典视图之间切换来配置布局的自由。另一种定制组件外观的方法是应用主题,改变 CSS 样式和工具栏。
个人印象
今天,我尝试介绍了 Kibana 的数据可视化功能,并展示了一个名为 Flexmonster 的 web 报告插件。
在我看来, Flexmonster 补充了 Kibana 中可用的数据可视化——它们是很好的搭配。这个工具完全符合我在数据分析方面的要求。有了它,我可以专注于报告,并揭示隐藏在数据中的见解。
我建议尝试一下。希望它们能让你的数据分析大放异彩。
感谢您的阅读!
反馈
在 Kibana 中,你最喜欢哪种可视化?你使用任何第三方插件进行数据分析吗?我很高兴听到你的经历。
有用链接
代表性相似性分析
从神经科学到深度学习…然后再回来
TL;博士:在今天的博客文章中,我们讨论了表征相似性分析(RSA),它可能如何改善我们对大脑的理解,以及 Samy Bengio 和 Geoffrey Hinton 小组最近系统研究深度学习架构中的表征的努力。所以让我们开始吧!
大脑以分布式和层次化的方式处理感觉信息。例如,视觉皮层(神经科学中研究最多的对象)顺序提取低到高水平的特征。光感受器通过双极+神经节细胞投射到外侧膝状体核(LGN)。从那里开始一连串的计算阶段。在腹侧(“什么”vs 背侧——“如何”/“在哪里”)视觉流的不同阶段(V1 → V2 → V4 → IT),活动模式变得越来越趋向于物体识别的任务。虽然 V1 的神经元调谐主要与粗糙的边缘和线条有关,但它展示了更抽象的概念表征能力。这种调制层次对计算机视觉领域和卷积神经网络(CNN)的发展是一个很大的启发。
另一方面,在神经科学中,空间滤波器组模型已经有很长的历史(Sobel 等。)已经被用于研究视觉皮层的激活模式。直到最近,这些都是视觉感知的最先进的模型。这主要是因为计算模型必须以某种方式与大脑记录相比较。因此,研究的模型空间受到严重限制。回车:RSA 。RSA 最初是由 Kriegeskorte 等人(2008) 引入的,目的是将认知和计算神经科学社区聚集在一起。它提供了一个简单的框架来比较不同的激活模式(不一定在视觉皮层;见下图)。更具体地,可以在不同条件(例如,猫和卡车的刺激呈现)之间比较基于 fMRI 体素的 GLM 估计或多单位记录。然后,这些激活测量被表示为向量,并且我们可以计算在不同条件下这些向量之间的距离测量。这可以对许多不同的刺激进行,每对刺激允许我们填充所谓的表征相异矩阵的一个条目。
自从 RSA 的最初介绍以来,它已经得到了很多媒体的关注,许多受欢迎的神经科学家,如 James DiCarlo,David Yamins,Niko Kriegeskorte 和 Radek Cichy,一直在将 RSA 与卷积神经网络相结合,以研究腹侧视觉系统。这种方法的优点在于,特征向量的维度无关紧要,因为它被简化为单个距离值,然后在不同模态(即,大脑和模型)之间进行比较。 Cadieu 等人(2014) 例如声称,中枢神经网络是腹侧流的最佳模型。为了做到这一点,他们从 ImageNet-pre-trained Alex net 的倒数第二层提取特征,并将这些特征与两只猕猴的多单位记录进行比较。在一次解码练习中,他们发现 AlexNet 的特征比同时记录的 V4 活动具有更强的预测能力。相当惊人的结果。(就预测而言。)另一项由 Cichy et al. (2016) 进行的强大研究,结合了 fMRI 和 MEG 来研究视觉处理穿越时间和空间。CNN 不知道时间和组织的概念。一层人工神经元很难被视为与新皮层中的一层神经元相类似。然而,作者发现提取的特征序列反映了测量的空间(fMRI)和时间(MEG)的神经激活模式。
这些结果之所以惊人,不是因为 CNN 与大脑“如此相似”,而是因为完全相反。通过 backprop 和 SGD 最小化标准成本函数来训练 CNN。卷积是生物学上难以置信的操作,CNN 在训练期间处理数百万个图像阵列。另一方面,大脑通过遗传操作和无监督学习来利用归纳偏差,以便检测自然图像中的模式。不过 backprop + SGD 和几千年的进化似乎也想出了类似的解决方案。但最终,作为研究人员,我们对理解大脑动态和深层结构背后的因果机制感兴趣。RSA 在这方面能帮我们多少?
RSA 中计算的所有度量都是相关的。RDM 条目基于相关距离。R 平方捕捉由模型 RDM 中的变化解释的神经 RDM 的变化。最终,很难解释任何因果关系。声称 CNN 中的信息是视觉皮层如何工作的最佳模型是廉价的。这真的没有太大帮助。CNN 通过反向传播进行训练,并封装了一个巨大的归纳偏差,其形式是在单个处理层中涉及的所有神经元之间共享核权重。但大脑无法实现这些精确的算法细节(可能已经找到了比莱布尼茨的链式法则更聪明的解决方案)。然而,已经有一堆最近的工作(例如,由 Blake Richards、Walter Senn、Tim Lillicrap、Richard Naud 和其他人)来探索神经回路逼近规范梯度驱动的成本函数优化的能力。所以最终,我们可能不会太远。
在此之前,我坚信必须将 RSA 与实验干预的科学方法结合起来。正如在经济学中一样,我们需要借助于受控操纵的准实验因果关系。这正是最近由 Bashivan 等人(2019) 和 Ponce 等人(2019) 所做的两项研究!更具体地说,他们使用基于深度学习的生成程序来生成一组刺激。最终目标是提供一种形式的神经控制(即驱动特定神经位点的放电率)。具体来说, Ponce 等人(2019) 展示了如何关闭从生成性对抗网络生成刺激、读出神经活动和改变 GAN 的输入噪声之间的环路,以驱动单个单元以及群体的活动。作者能够识别记录位置的可复制的抽象调谐行为。使用灵活的函数逼近法的最大优势在于它们能够清晰地表达我们作为实验者无法用语言表达的模式。
对于许多深度学习架构,权重初始化对于成功的学习至关重要。此外,我们仍然没有真正理解层间表现差异。RSA 提供了一个有效且易于计算的量,可以衡量对这些超参数的稳健性。在最近的 NeuRIPS 会议上,Sami Bengio 的小组( Morcos 等人,2018 )引入了投影加权典型相关分析(PWCCA),以研究泛化以及窄网络和宽网络的差异。基于谷歌式的大型实证分析,得出了以下关键见解:
- 能够泛化的网络收敛到更相似的表示。直觉上,过拟合可以通过许多不同的方式实现。网络基本上不受训练数据的“约束”,可以在空间的那一部分之外为所欲为。泛化需要利用与真正的底层数据生成过程相关的模式。这只能通过一组更有限的架构配置来实现。
- 网络的宽度与代表性收敛直接相关。更多的宽度=更多的相似表示(跨网络)。作者认为,这是所谓彩票假说的证据:经验表明,宽修剪网络比从一开始就很浅的网络表现更好。这可能是由于宽带网络的不同子网被不同地初始化。然后,修剪程序能够简单地识别具有最佳初始化的子配置,而浅网络从一开始就只有单个初始化。
- 不同的初始化和学习率会导致不同的代表性解决方案集群。这些集群的泛化能力也很好。这可能表明损失面有多个定性不可区分的局部极小值。最终是什么推动了会员的加入还无法确定。
Geoffrey Hinton 的谷歌大脑小组最近的一项扩展( Kornblith 等人,2019 )使用了中心核对齐(CKA),以便将 CCA 扩展到更大的向量维度(人工神经元的数量)。就我个人而言,我真的很喜欢这项工作,因为计算模型给了我们科学家自由去打开所有的 nob。而且在 DL(架构、初始化、学习率、优化器、正则化器)也有不少。正如 Kriegeskorte 所说,网络是白盒。因此,如果我们不能成功地理解一个简单的多层感知器的动态,我们怎么能在大脑中成功呢?
总而言之,我是每一项试图揭示大脑深度学习近似原理的科学发展的超级粉丝。然而,深度学习并不是大脑中计算的因果模型。认为大脑和中枢神经系统在时间和空间上执行相似的顺序操作是一个有限的结论。为了获得真正的洞察力,这个循环必须被关闭。因此,使用生成模型来设计刺激是神经科学中令人兴奋的新尝试。但是如果我们想要理解学习的动力,我们必须走得更远。损失函数和梯度是如何表示的?大脑如何克服将训练和预测阶段分开的必要性?表象只是回答这些基本问题的一个非常间接的窥视孔。展望未来,从跳过和循环连接以及通过漏失采样的贝叶斯 DL 中有很多收获(从建模者的角度来看)。但那是另一篇博文的故事。
使用隐马尔可夫模型用社交网络数据表示人类移动模式
作者 : 王家卫,塞斯·李,蔡贤洙,贺飞
https://github.com/sethlee0111/MobilityHMMGithub
Hidden Markov Model
简介
理解并知道如何利用人类的移动性对于现代的各种应用非常有帮助。例如,通过了解人们如何在城市中移动,城市规划者和开发者可以更有效地设计城市。然而,利用人类的流动性并不容易,因为人们的生活方式多种多样。此外,城市每天都变得越来越复杂,越来越大。因此,我们需要一种更好的方法和模型来分析和描述人类的移动模式。
其中一种方法是使用地理标签社交媒体应用。现在,每个人都有一部随身携带的手机。此外,脸书、Instagram 和 Twitter 等社交媒体应用程序现在为用户的 show others 提供签到服务,并跟踪他们去了哪里。
这个收集的海量数据集包括用户的位置和活动,通过利用这个社交媒体服务,我们可以更好地表示人类的移动性。
对于这个项目,我们分析并利用 FourSquare 手机应用程序数据来建立一个模型,以便更好地预测人类的移动性。
数据集
我们使用 FourSquare 的纽约入住数据集。总共有 227428 个签到数据集,日期范围在 2012 年 4 月到 2013 年 2 月之间。总共有 1083 个用户,每人至少签到 100 次。此外,有 250 个场馆类别,每个场馆有 38333 个不同场馆 id。
adataset 的示例如下所示:
Figure: raw data
数据表现出高度的稀疏性和高度的复杂性。这主要是因为人们不会在所到之处持续不断地签到。此外,纽约市的人类活动非常复杂,因为它的人口密度高,场地密度大,所有东西都在彼此之上。因此,我们必须对数据进行预处理,以收集我们需要的正确和有意义的信息。
轨迹是从包含用户活动模式的用户签到记录中提取的有用特征。轨迹被定义为在定义的时间间隔内连接的用户活动的序列。对于这个时间差,我们使用了 3 个小时,并通过计算用户两次活动之间的时间差和定义轨迹来预处理数据。
Figure: pre-processed data after grouping by user and trajectory
数据集在这里可用。
机动性嗯
现有的移动模型大多使用 隐马尔可夫模型 来表示人体的移动性。隐马尔可夫模型是简单的具有隐藏状态的马尔可夫模型,其将更好地抽象用户的不可观察状态。其中一种是基于隐马尔可夫模型建立的,该模型具有由双变量高斯分布产生的发射概率,并预测用户的下一个位置。然而,我们想要使用所有三个特性;地点、时间和类别。这让我们设计并实现了一个隐马尔可夫模型,对于从每个状态观察到的每个特征,该模型具有不同的发射概率。在我们的模型中,一个状态生成三个特征,即位置(经度和纬度)、时间(秒)和类别。为了生成这些特征,高斯分布用于位置和时间,多项式分布用于类别。我们完全实现了这个模型,参考了 hmmlearn 库中 hmm 的现有实现。
Figure: Mobility Hidden Markov Model
简单模型
Figure. Global Model v.s. Personal Model
如上图所示,我们的简单模型有两个层次,一个是全局模型,另一个是个人模型。
全局模型是用所有用户数据训练的,它只代表所有用户的一般生活模式。对于没有足够数据生成高质量个人模型的用户来说,这是一个很好的替代模型,但它并不反映任何个人偏好。
个人模型是用每个用户自己的数据为每个用户训练的,它指示该用户的特定移动模式。然而,如前所述,数据集具有高度稀疏性,这意味着许多用户没有丰富的数据来生成其个性化模型。
总而言之:
全球化模式:
- 只能显示所有人的基本生活模式
- 不显示人的个性,过于概括
个性化模式:
- 只能展示每个人独特的生活方式
- 需要大量的轨迹数据供每个用户个性化
为了避免两种模型中任何一种的缺点,应该开发一些中级模型。
本地化型号
显然,对于这个复杂而难以解决的问题来说,简单的模型过于简单和幼稚。即使使用我们定制的移动性隐马尔可夫模型,这也表现不佳。此外,很明显,对于这个问题来说,全球模型过于一般化,而个人模型过于具体和昂贵。
启发式地,我们的模型的粒度应该被重新考虑。根据分组模式对用户进行分组和预测是一个很好的选择。分组不仅有助于我们最终模型的粒度,而且有助于处理数据稀疏问题。用户不会记录他们每天的活动,通常他们会在一个不可预知的时间登录。而且他们数据的稀疏性给我们预测他们的活动带来了很多麻烦。
Figure: Users sharing similar mobility pattern
而分组有助于发现一定数量的人的模式,这些人可能有相似的工作,有相似的兴趣或经常去相似的地方。只有根据经验,我们才能得出结论,通过预测这些人群的活动能把我们引向更好的结果。我们决定使用场所类别名称对用户进行分组,因为在相同类别场所登记的用户可能具有相似的生活模式。从图中我们可以看出,这三个用户很可能是大学生,他们都有非常相似的生活方式。
我们发明了基于贪婪和随机算法的算法。它被命名为 基于 Jaccard 的随机化算法 。
Alg: Jaccard-based Randomized Grouping Algorithm
Jaccard 相似系数 用来定义两个不同集合之间的相似性。我们随机选择一组,计算所有与其他组的 Jaccard 相似性。然后,我们将选择的组与他们登记入住的用户场地类别上的最大 Jaccard 相似性组相结合。我们一直这样做,直到所需的组数达到我们模型的要求。
Figure: localization model
Figure: users in the same group
幸运的是,我们的本地化模式奏效了。正如我们从上图中看到的,我们从分组算法结果集中抽取了三个用户,显然他们有一些共同的场馆活动签到。
然而,这种基于 Jaccard 的算法确实有一些限制。一方面,我们在整个时间讨论中讨论术语“轨迹”,即某些基于时间的活动的动作序列。在我们的算法中,我们只计算地点类别,这与轨迹不同,因为用户可能有不同类型的轨迹模式,但最终与其他用户在相同的地方登记。然而,他们的生活模式可以完全不同。另一方面,我们的模型侧重于将用户分成特定的组,这在某种程度上降低了他们的个性。例如,用户可以是学生,也可以是舞蹈演员。然而,使用我们的模型,我们只能将这个用户分配到一个特定的组,而不是根据权重或概率将用户分成不同的组。
因此,我们需要更先进的分组技术或算法来解决这个问题。
重组模型
如果这个模型不仅能学习移动模式,还能学习用户的分组方式,那就太棒了。我们的团队已经实现了一个新颖的迭代模型,它从拟合代表组的 hmm,到基于拟合的 hmm 对用户进行分组。
Figure: re-grouping model
在这个模型中,用户不属于一个单独的组。他们有个向量来记录他们属于某个群体的概率。这些向量是随机初始化的。在初始拟合之后,得到一个用户属于一个组的概率,我们计算它的后验概率,并使用贝叶斯定理从那里得到一个近似值。我们重复这个过程,直到模型收敛,这是用户分组没有变化的点。我们认为这可能揭示有意义的分组,因为它是随机初始化的,能够很好地代表其用户特征的组在分组阶段得到加强。
Figure. Weight Regrouping Algorithm
结果&评估
Figure: Best results for models
模型的评估是基于对数似然的度量来完成的。首先,我们使用 forward 算法计算测试数据集中样本的可能性,并根据测试数据集中的数据点数对其进行平均。如上图所示,与个人和全局这两个简单模型相比,本地化模型的性能要好得多。
Figure: hyperparameter tuning, Number of Group(left); Number of State(right)
为了获得我们本地化模型的最佳性能,有一些超参数可以在整个过程中进行调整。
组数:
从上图中我们可以看出,随着组数量的增加,模型表现得更好,这对于更多的组有能力表示不同的个性化组是有意义的。
状态数:
随着状态数量的增加,我们的模型表现得更好。隐马尔可夫模型的状态数说明了该模型表示复杂用户模式的能力。
Figure: re-grouping results
不幸的是,重新分组方案还没有显示出有希望的结果。上面的三个图表明,用户倾向于聚集到最能代表他们的移动模式的两个组,而不是被分组到几个群中。我们认为这是因为我们使用的组数量较少。像本地化模型一样,如果我们使用足够数量的组,它们可能会开始代表一些有意义的东西。然而,由于我们的代码是从基础实现的,所以运行拟合算法需要花费大量时间。我们试图通过实现多处理来克服这个问题,并且实际上成功地将部分实现的学习时间提高了十倍以上,但是还需要做更多的工作来使它更快。
未来工作
对于未来的工作,我们计划测试更多的模型,更好地代表移动模式。有一些现有的工作,通过不仅考虑先前的状态,而且考虑之前的状态,将隐马尔可夫模型向前推进了一步。此外,我们希望将我们的数据与具有类似特征的其他数据集进行测试,这意味着它们是稀疏的,但可以根据它们的模式进行分组。
此外,我们希望使用不同的评估指标,而不是对数似然,并希望能够将该模型推广到更一般的场合。潜在的,我们想在现实生活中应用模型,如广告和营销。
结论
在这个项目中,我们研究了是否可以提出一个模型来表示稀疏的移动数据。我们实现了一种新颖的隐马尔可夫模型 ,它可以采用具有不同发射概率的三个特征。最重要的是,我们试图获得人类移动性的最佳表示,从几个简单的模型到重新分组迭代方案。总之,我们发现基于 Jaccard 的随机算法的定位模型效果最好。然而,我们寻求用更高效的代码和计算能力来进一步开发我们的重新分组方法。
参考
[1]杨,张大庆,郑文生,和。
在 lbsns 中利用用户时空特征对用户活动偏好进行建模。
IEEE 系统、人和控制论汇刊:系统,45(1):129–142,2014。
[2],张克阳,,,张,蒂姆·汉拉蒂和韩佳伟。
Gmove:使用地理标记社交媒体的群体级移动性建模。
第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集,第 1305–1314 页。ACM,2016。
3韦斯利·马休、鲁本·拉波索和布鲁诺·马丁斯。
用隐马尔可夫模型预测未来位置。
《2012 年 ACM 普适计算会议论文集》,第 911-918 页。美国计算机学会,2012 年。
[4] Budhaditya Deb 和 Prithwish Basu。
发现人体运动痕迹中的潜在语义结构。
在欧洲无线传感器网络会议上,第 84-103 页。斯普林格,2015。
[5]格雷厄姆·W·泰勒、杰弗里·E·辛顿和萨姆·T·罗威斯。
产生高维时间序列的两种分布式状态模型。
《机器学习研究杂志》,2011 年第 12 期(3 月):1025–1068 页。
6克里斯蒂安·巴雷特、理查德·休伊和凯文·卡普勒斯。
评分隐马尔可夫模型。
生物信息学,13(2):191–199,1997。
用 Word2vec 表现音乐?
机器学习算法已经改变了视野和自然语言处理。但是音乐呢?近几年来,音乐信息检索领域发展迅速。我们将研究如何将自然语言处理中的一些技术移植到音乐领域。在最近由川,阿格雷斯,& Herremans (2018) 发表的一篇论文中,他们探索了 NLP 的一种流行技术,即 word2vec,如何用于表示复调音乐。让我们深入了解一下这是如何做到的…
Word2vec
单词嵌入模型使我们有可能以一种有意义的方式来表示单词,以便机器学习模型可以更容易地处理它们。它们允许我们用一个表示语义的向量来表示单词。Word2vec 是 Mikolov 等人(2013)开发的一种流行的向量嵌入模型,它可以以非常有效的方式创建语义向量空间。
word2vec 的本质是一个简单的单层神经网络,以两种可能的方式构建:1)使用连续词袋(CBOW);或者 2)使用跳格结构。这两种架构都非常高效,并且可以相对快速地进行训练。在这项研究中,我们使用 skip-gram 模型,因为 Mikolov 等人(2013 年)暗示它们对于较小的数据集更有效。跳格结构采用当前单词 w_t(输入层)并尝试在上下文窗口(输出层)中预测周围的单词:
Figure from Chuan et al (2018). Illustration of a word t and its surrounding context window.
由于网上流传的一些流行图片,人们对跳过程序的架构看起来有些困惑。网络输出不是由多个单词组成,而是由上下文窗口中的一个单词组成。它如何学会表示整个上下文窗口?在训练网络时,我们使用采样对,由输入单词和来自上下文窗口的随机单词组成。
这种类型的网络的传统训练目标包括计算𝑝(𝑤_{𝑡+𝑖}|𝑤_𝑡的 softmax 函数,其梯度的计算是昂贵的。幸运的是,噪声对比估计(Gutmann & Hyvä rine,2012 年)和负采样(Mikolov 等人,2013 年 b)等技术提供了一个解决方案。我们使用负采样来定义一个新的目标:最大化真实单词的概率,最小化噪声样本的概率。简单的二元逻辑回归将噪声样本从真实单词中分类出来。
一旦训练了 word2vec 模型,隐藏层的权重基本上代表了学习到的多维嵌入。
音乐作为文字?
音乐和语言有着内在的联系。两者都由一系列遵循一套语法规则的连续事件组成。更重要的是,它们都创造了期望。想象一下,我说:“我要去比萨店买一个…”。这产生了一个明确的期望…比萨饼。现在想象一下,我为你哼唱生日快乐的旋律,但我在最后一个音符前停下了…就像一个句子,旋律会产生期望。期望如此之高,以至于可以通过脑电图来测量,例如,大脑中的 N400 事件相关电位(Besson & Schö,2002)。
鉴于语言和文字之间的相似性,让我们看看一个流行的语言模型是否可以用作音乐的有意义的表示。为了将一个 midi 文件转换成“语言”,我们定义了音乐的“片段”(相当于单词)。我们数据集中的每个音乐片段都被分割成等时长、不重叠的一拍片段。每首乐曲的节拍时长可能不同,由 MIDI 工具箱估算。对于这些切片中的每一个,我们保留所有音高类别的列表,即没有八度音程信息的音高。
下图显示了肖邦玛祖卡舞曲作品 67 №4 的第一小节的切片是如何确定的。一拍在这里是四分之一音长。
Figure from Chuan et al (2018) — Creating words from slices of music
Word2vec 学习音调——音乐的分布语义学假说
在语言中,分布语义假设驱动矢量嵌入背后的动机。它认为“出现在相同语境中的词往往有相似的意思”(哈里斯,1954)。转换到向量空间,这意味着这些单词将在几何上彼此接近。让我们看看 word2vec 模型是否学习了音乐的类似表示。
数据集
川等人使用了一个包含八种不同风格(从古典到金属)的 MIDI 数据集。基于流派标签的存在,从总共 130,000 个作品中,仅选择了 23,178 个作品。在这些碎片中,有 4076 个独特的切片
超参数
仅使用 500 个最常出现的片段(或单词)来训练该模型,使用虚拟单词来替换其他单词。该过程增加了模型的准确性,因为更多的信息(出现)可用于所包括的单词。其他超参数包括学习率 0.1、跳过窗口大小 4、训练步骤数(1,000,000)和嵌入大小 256。
和弦
为了评估音乐片段的语义是否被模型捕获,让我们看一下和弦。
在切片词汇表中,所有包含三元组的切片都被识别。然后用罗马数字标注它们的音阶等级(在音乐理论中经常这样做)。例如,在 C 调中,和弦 C 是 I,另一方面,G 和弦被表示为 v。余弦距离然后被用于计算不同音阶度的和弦在嵌入中彼此相距多远。
在 n- 维空间,中,两个非零向量 A 和 B 之间的余弦距离 Ds(A,B)计算如下:
D𝑐(A,B)=1−cos(𝜃)=1−D𝑠(A,B)
其中𝜃是 a 和 b 之间的角度,Ds 是余弦相似度:
从音乐理论的角度来看,I 和弦与 V 和弦之间的“音调”距离应该小于 I 和弦与 III 和弦之间的距离。下图显示了 c 大调三和弦与其他和弦之间的距离。
Figure from Chuan et al (2018) — Cosine distance between triads and the tonic chord = C major triad.
一个 I 三和弦到 V,IV,vi 的距离更小!这与它们在音乐理论中被视为“音调更接近”的方式相对应,并表明 word2vec 模型学习了我们片段之间有意义的关系。
word 2 vec 空间中和弦之间的余弦距离似乎反映了和弦在乐理中的功能作用!
键
看看巴赫的《调和的克拉维尔》( WTC)的 24 首前奏曲,其中 24 个调(大调和小调)中的每一个都包含一段,我们可以研究新的嵌入空间是否捕获了关于调的信息。
为了扩充数据集,每个片段都被转置到其他每个主要或次要键(取决于原始键),这导致每个片段有 12 个版本。这些键中的每一个的切片被映射到先前训练的向量空间上,并且使用 k-means 进行聚类,使得我们获得新数据集中每一个片段的质心。通过将片段转置到每个键,我们确保质心之间的余弦距离只受一个元素的影响:键。
下图显示了不同调中各棋子形心之间的余弦距离。正如所料,相隔五分音符在音调上很接近,并表示为对角线旁边的较暗区域。音调相距较远的键(例如 F 和 F#)具有橙色,这证实了我们的假设,即 word2vec 空格反映了键之间的音调距离!
Figure from Chuan et al (2018)— similarity matrix based on cosine distance between pairs of preludes in different keys.
比喻
word2vec 的一个突出例子是图像,它显示了向量空间中国王→王后和男人→女人之间的翻译(Mikolov 等人,2013c)。这表明意义可以通过矢量翻译提出来。这也适用于音乐吗?
我们首先从和弦切片中检测和弦,并查看和弦对向量,从 c 大调到 G 大调(I-V)。不同 I-V 向量之间的角度非常相似(见右图),甚至可以认为是五分之一的多维圆。这再次证实了类比的概念可能存在于音乐的 word2vec 空间中,尽管需要更多的研究来揭示更清晰的例子。
Figure from Chuan et al (2018) — angle between chord-pair vectors.
其他应用—音乐生成?
Chuan 等人(2018)简要介绍了该模型如何用于替换音乐片段以形成新音乐。他们表示,这只是一个初步的测试,但该系统可以作为一个更全面的系统,如 LSTM 的代表方法。科学论文中给出了更多的细节,但下图给出了结果的印象。
Figure from Chuan et al (2018) — Replacing slices with geometrically close slices.
结论
Chuan,Agres 和 Herremans (2018)建立了一个 word2vec 模型,该模型可以捕捉复调音乐的音调属性,而无需将实际音符输入模型。这篇文章展示了令人信服的证据,表明关于和弦和键的信息可以在小说《嵌入》中找到,所以要回答标题中的问题:是的,我们可以用 word2vec 来表示复调音乐!现在,将这种表达嵌入到其他也捕捉音乐时间方面的模型中的道路是开放的。
参考
Besson M,schn D(2001)语言和音乐的比较。安纽约科学院科学 930(1):232–258。
传,陈春华,阿格雷斯,k .,&赫里曼斯,D. (2018)。从语境到概念:用 word2vec 探索音乐中的语义关系。神经计算与应用——音乐与音频深度学习特刊,1–14。 Arxiv 预印本。
Gutmann MU,hyv rinen A(2012)非标准化统计模型的噪声对比估计,以及对自然图像统计的应用。马赫学习研究 13(二月):307–361
哈里斯·ZS(1954)的分布结构。单词 10(2–3):146–162。
Mikolov,Chen,k .,Corrado,g .,& Dean,J. (2013 年)。向量空间中单词表示的有效估计。 arXiv 预印本 arXiv:1301.3781。
Mikolov T,Sutskever I,Chen K,Corrado GS,Dean J (2013b)对单词和短语及其组合性进行了分布式表征。《神经信息处理系统进展会议录》,第 3111-3119 页
Mikolov T,Yih Wt,Zweig G (2013c)连续空间单词表征中的语言规则。摘自:计算语言学协会北美分会 2013 年会议记录:人类语言技术,第 746-751 页
自然语言处理中的文本表示
理解书面单词:温习 Word2vec、GloVe、TF-IDF、单词袋、N-grams、1-hot 编码技术
本文着眼于自然语言处理(NLP)的语言表示。如果你是那些罕见的深度学习大师之一,你可能不会在这里学到任何新东西。如果没有,请和我一起进入将单词转换成算法可以理解的一些表示的迷人世界。我们激励我们为什么要这样做,存在哪些方法,以及它们如何在简单的例子中工作。我们将尽可能避免数学,我们将使用轻松的写作风格,以增加你真正读到文章结尾的机会。虽然文章看起来比较长,但是冲浪挺好玩的。
我们为什么关心语言?
每当婴儿开始说话时,语言起源的历史就会重演。事实上,当人类开始命名现实生活中出现的物体、动作和现象时,语言就开始了。当看到数十亿人共有的对神的创造的信仰时,我们可以认为语言和人类一样古老。每当我们写一条短信、一条推文、一次聊天、一封电子邮件、一个帖子甚至一个网页、一篇文章、一个博客或一本书时,我们都将思想转化为文字或符号。多亏了语言,人类能够将看不见的想法变成看得见的东西。此外,人类的思想变得可以被其他人获取,还有…,猜猜看?电脑!如果人类能够从文字中重建思想,计算机也能做到吗?
随着最近被称为人工智能的大肆宣传,让计算机能够处理、理解和生成人类语言是非常有用的。谷歌翻译是一个很好的例子,一个有用的例子。谷歌开始扫描大学图书馆的大量书籍并废弃网页,包括它们的人工翻译,并学习源和目标之间的模式(统计机器翻译)。今天,多亏了谷歌翻译和它的序列对序列模型(神经机器翻译),我们可以访问用我们还不会说的任何语言编码的思想。
在开始是神经元:梯度下降,反向传播,回归,自动编码器,细胞神经网络…
towardsdatascience.com](/why-deep-learning-works-289f17cab01a)
再比如文本分类。人类非常善于将事物分成不同的类别,例如“好”和“坏”。他们这样做已经很久了。同时,人类也非常善于以文本的形式生成和记录信息。根据谷歌的数据,全世界大约有 129,864,880 本书。我们敢打赌,你不会想用手将它们分类,即使给你世界上最大的图书馆,有足够的空间和书架。同时,你真的需要把这些书至少按类型分类:漫画、烹饪、商业、传记等等。在那里,你可以接受一个计算机程序,它可以读取书的内容并自动检测它的类型。让我们暂时离开书本。我们当中有越来越多的人不读书,他们更喜欢新闻。他们通常每天会收到数百条消息、帖子或文章。从相关更新(例如关于行业和市场的更新)中挑选出垃圾消息和假新闻,对于他们来说已经成为非常相关的任务,只要这是由计算机程序来完成的。你读这篇文章很可能是因为一个推荐算法把它从许多其他文章中整理出来,并发送到你的收件箱或移动应用程序中。该算法必须对成千上万篇文章进行分类,并根据你的阅读历史和你聪明的外表,选择这篇你可能会喜欢的文章。
问答机器人是如今的另一个炒作。想象一下,作为客户支持专家,如果你有一份自己的副本,每天接听客户打来的几十个电话,一遍又一遍地问同样的问题,你会节省多少时间。我们都听说过亚马逊 Alexa,苹果 Siri 或者谷歌助手。这些系统会自动回答人类用自然语言提出的问题。
希望上面的例子能激发为什么让计算机处理自然语言对你来说是一个吸引人的话题。如果没有,看看进一步说明语音识别、语音模仿和语音合成的例子肯定会让你大吃一惊。
电脑喜欢数字
现在,为什么所有这些谈论语言和计算机?你每天都在你最喜欢的文字处理器或电子邮件软件中输入文本。那么,为什么计算机很难理解你的文本呢?语言在各个层面都是模糊的:词汇、短语、语义。语言假设听者意识到世界,语境和交流技巧。如果你在搜索引擎中输入“鼠标信息”,你是在寻找一只宠物还是一个工具?文本的表示对于许多现实应用程序的性能非常重要。
现在,我们如何把语言变成计算机算法喜欢的东西?在基础上,计算机中的处理器执行简单的算术运算,如数字的加法和乘法。这就是计算机喜欢数字的原因吗?谁知道呢。无论如何,这个问题很好地解决了图像。例如,下图中标有圆圈的区域由三个数字矩阵表示,每个数字矩阵对应一个颜色通道:红色、绿色和蓝色。每个数字表示像素位置的红色、绿色或蓝色等级。(0,0,0)显示为黑色,颜色分量为(255,255,255)的像素显示为白色。
将文本转换成数字的过程,类似于我们对上图所做的,通常是通过构建一个语言模型来完成的。这些模型通常为单词、单词序列、单词组、文档部分或整个文档分配概率、频率或一些模糊的数字。最常见的技术有:1-热编码、N-grams、词袋、向量语义(tf-idf)、分布式语义(Word2vec、GloVe)。让我们看看我们是否理解这一切意味着什么。我们应该可以。我们不是电脑。至少是你。
1-热编码模型
如果一个文档的词汇表有 1000 个单词,我们可以用一个热点向量来表示这些单词。换句话说,我们有 1000 维的表示向量,我们将每个唯一的单词与这个向量中的一个索引相关联。为了表示一个唯一的单词,我们将向量的分量设置为 1,并将所有其他分量置零。
source: Fundamentals of Deep Learning, N. Buduma, 2017
这种表述是相当武断的。它忽略了单词之间的关系,并且没有传达关于它们周围环境的信息。这种方法对于大词汇量来说非常无效。在接下来的几节中,我们将会看到一些更令人兴奋的方法。
n 元语言模型
我们开始看最基本的 N-gram 模型。让我们来考虑一下我们从小最喜欢的一句话:“请吃你的食物”。2-gram(或 bigram)是由两个单词组成的单词序列,如“请吃饭”、“吃你的”或“你的食物”。一个三字组(或三元组)将是一个三个单词的单词序列,如“请吃你的”,或“吃你的食物”。N-gram 语言模型估计给定前面单词的最后一个单词的概率。例如,给定单词“请吃你的”的顺序,下一个单词“食物”的可能性比“勺子”高。在后一种情况下,我们的妈妈会不太高兴。计算任何一对、三对、四对……单词的这种可能性的最好方法是使用大量的文本。下图显示了从包含与餐馆和食物相关的问题和答案的相对较小的文本体中获得的几个概率。“我”后面经常跟动词“想要”、“吃”或“花”。
source: Jurafsky et al., 1994
谷歌(再次)实际上在多种语言中为 1 字、2 字、3 字、4 字和 5 字提供了更大的概率集。他们是根据 1500 年至 2008 年间印刷的资料计算出来的!Google Ngram Viewer 允许你下载并使用这个 n 元语法的大集合,用于拼写检查、自动完成、语言识别、文本生成和语音识别。
我们训练 N-gram 模型的上下文越长,我们可以生成的句子就越连贯。下图显示了从 1 克、2 克和 3 克模型中随机生成的 3 个句子,这些模型是从《华尔街日报》的 4000 万字中计算出来的。
source: Jurafsky et al., 2018
即使有非常大的语料库,一般来说,N-gram 也不是一个充分的语言模型,因为语言具有长距离依赖性。例如,在句子“我刚放进五楼机房的电脑死机了。”,虽然“计算机”和“崩溃”这两个词相距 15 个位置,但它们是相关的。一个 5 克重的模型将会错过这个链接,我们的计算机管理员可能会一直认为五楼的计算机运行良好。现在,如何处理德国文学中号称有 1077 个单词的最长句子呢!谁想训练一个 N-gram 语言模型来理解那些通常很长的交错的德语句子?
此外,N-gram 模型严重依赖于用于计算概率的训练语料库。这意味着概率通常编码了关于给定训练文本的特定事实,这不一定适用于新文本。这些原因促使我们进一步研究语言模型。
词袋语言模型
当我们对文本分类感兴趣时,基于情感对其分类,或者验证它是否是垃圾邮件时,我们通常不希望查看单词的顺序模式,如 N-gram 语言模型所建议的。相反,我们会将文本表示为一个单词包,好像它是一组无序的单词,而忽略它们在文本中的原始位置,只保留它们的频率。
source: Jurafsky et al., 2018
让我们在一个简单的情感分析示例中用两个类正(+)和负(-)来说明文本的单词包表示。下面我们有 5 个已知类别的句子(也称为文档),以及 1 个未知类别的句子。目的是将最后一句归类为肯定或否定。
source: Jurafsky et al., 2018
这项任务由所谓的朴素贝叶斯分类器来解决,它使用每个类别的词袋中的词频来计算每个类别的概率 c ,以及给定类别的每个词的条件概率,如下所示。
在我们的例子中,负类的概率是 3/5。正类将有 2/5 的概率。一点代数就会显示,给定负类的“可预测”、“有”、“没有”、“好玩”这些词的概率,比给定正类的样本概率要高。因此,基于训练数据,句子“可预测但没有乐趣”将被分类为负面的。
词袋语言模型依赖于词频 TF,它被定义为一个词在给定文本或文档中出现的次数。词汇袋有助于情感分析。这对于检测一篇文章是用哪种语言写的非常有用。它还用于确定作者身份,如性别和年龄。我们还可以使用术语频率信息来设计额外的特征,例如正面词汇的数量(“棒极了”、“不错”、“令人愉快”),或者第一和第二代名词的数量(“我”、“我”、“你”),并基于逻辑回归甚至神经网络来训练更复杂的分类器。但是,我们现在不要走那条令人头痛的路。
尽管有这样的荣耀,N-gram 和单词袋模型本身并不能让我们得出有用的推论来帮助我们解决与意义相关的任务,如问答、总结和对话。这就是为什么我们将在下一节研究语义。
向量语义学
我们应该如何表达一个词的意思?单词“mouse”可以在词汇词典中找到,但是它的复数形式“mice”将不单独描述。类似地,“sing”作为“sing”、“sang”、“sung”的引理将被描述,但是它的时态形式将不被描述。我们如何告诉计算机所有这些单词的意思是一样的?“工厂”一词根据上下文可能有不同的含义(例如,“特斯拉正在建造新工厂”,“气候变化对工厂有负面影响”)。向量语义学是目前建立计算模型的最佳方法,该模型成功地处理词义的不同方面,包括词义、上下位词、上位词、反义词、同义词、同形异义词、相似性、关联性、词汇场、词汇框架、内涵。我们为语言术语道歉。让我们通过查看上下文的概念来建立对向量语义的直觉。
在我们的例句“特斯拉正在建造新工厂”中,如果我们在人类写的许多其他句子中计算“工厂”一词的上下文,我们会倾向于看到像“建造”、“机器”、“工人”甚至“特斯拉”这样的词。这些词和其他类似的上下文词也出现在“工厂”一词周围,这一事实可以帮助我们发现“植物”和“工厂”之间的相似性。在这种情况下,我们不会倾向于将“植物”的含义与“特斯拉正在建造新工厂”这句话中的“植物”联系起来。我们宁愿认为特斯拉在建设新工厂。
因此,我们可以通过计算在一个单词的环境中出现的其他单词来定义这个单词,我们可以用一个向量、一列数字、N 维空间中的一个点来表示这个单词。这样的表示通常被称为嵌入。计算机可以利用这种欺骗手段来理解单词在上下文中的意思。
Word 文档表示法
为了更好地掌握向量语义,让我们假设我们有一组文本(文档),我们希望找到彼此相似的文档。这个任务与信息检索相关,例如在搜索引擎中,文档是网页。作为说明,下表中的每一列代表具有以下标题的 4 个文档之一:“如你所愿”、“第十二夜”、“朱利叶斯·凯撒”和“亨利五世”。文档中出现的单词表示为行。这些单词构成了我们的词汇。表格告诉我们,单词“battle”在文献“Julius Caesar”中出现了 7 次。这个表格也被称为术语-文档矩阵,其中每行代表词汇表中的一个单词,每列代表一个文档、一个章节、一个段落、一条推文、一条短信、一封电子邮件或其他任何内容。
source: Jurafsky et al., 2018
现在我们可以用一个文档向量来表示每个文档,例如“Julius Caecar”的[7 62 1 2]。我们甚至可以在二维向量空间中为任何一对单词画出这样的向量。下面我们有这样一个图表的例子。我们看到由“傻瓜”和“战斗”维度构建的空间的文档向量的空间可视化。我们可以得出结论,文献《亨利五世》和《尤利乌斯·恺撒》有类似的内容,与“战斗”的关系大于与“傻子”的关系。对于信息检索,我们也用一个文档向量来表示一个查询,长度也是 4,表示单词“battle”、“good”、“fool”和“wit”在查询中出现的频率。将通过将查询向量与所有四个文档向量进行比较以发现它们有多相似来获得搜索结果。
source: Jurafsky et al., 2018
单词-单词表示法
通过查看术语-文档矩阵的行,我们可以提取单词向量而不是列向量。正如我们看到的,相似的文档往往有相似的单词,相似的单词有相似的向量,因为它们往往出现在相似的文档中。如果我们现在使用单词而不是文档作为术语-文档矩阵的列,我们得到所谓的单词-单词矩阵,术语-术语矩阵,也称为术语-上下文矩阵。每个单元描述了行(目标)单词和列(上下文)单词在某个训练语料库的某个上下文中同时出现的次数。一个简单的例子是当上下文是一个文档时,那么单元格将告诉两个单词在同一个文档中出现的频率。一种更常见的情况是计算列字在行字周围的字窗口中出现的频率。在下面的例子中,当考虑“信息”周围的 7 个单词窗口时,“数据”在“信息”的上下文中出现了 6 次。
source: Jurafsky et al., 2018
上面的矩阵表明“杏子”和“菠萝”彼此相似,因为“pinch”和“糖”往往出现在它们的上下文中。两个单词 v 和 w 之间的相似度可以通过计算所谓的余弦相似度使用它们相应的单词向量来精确计算,定义如下:
在下面的例子中,“数字”和“信息”之间的相似度等于单词向量[0 1 2]和[1 6 1]之间的余弦相似度。通过应用上面的公式,我们获得 0.58,这高于“杏”和“信息”之间的余弦相似度 0.16。
词向量和余弦相似度是处理自然语言内容的有力工具。然而,有些情况下他们的锻炼效果并不好,我们将在下一节看到。
TF-IDF 语言模型
向量语义模型使用两个单词同时出现的原始频率。在自然语言中,原始频率是非常倾斜的,并且不具有很强的辨别能力。如下面的直方图所示,单词“the”只是一个常用单词,在每个文档或上下文中具有大致相同的高频率。
处理这个问题的方法很少。TF-IDF 算法是目前自然语言处理,特别是信息检索中对共生矩阵进行加权的主要方法。TF-IDF 权重被计算为术语频率和逆文档频率的乘积。这有助于我们重视更具区别性的单词。在我们的文件 d 中,用于计算每一项 t 的 TF-IDF 重量的两个分量描述如下。
词频
术语或词频计算为该词在文档中出现的次数。因为一个单词在一个文档中出现 100 次并不会使这个单词与文档的意义相关的可能性增加 100 倍,所以我们使用自然对数来稍微降低原始频率。在文档中出现 10 次的单词将具有 tf=2。在文档中出现 100 次的单词意味着 tf=3,1000 次意味着 tf=4,等等。
逆文档频率
给定术语或词的文档频率是它出现在文档中的数量。逆文档频率是文档总数与文档频率之比。这使得只在少数文档中出现的单词具有更高的权重。因为在许多集合中有大量的文档,所以通常对逆文档频率应用自然对数,以避免 IDF 的偏斜分布。
在下图的左侧,我们可以看到为前面介绍的例子中的单词计算的 TF 和 IDF。在图像的右侧,我们显示了给定文档中每个单词的原始频率,以及它在底部表格中的加权 TF-IDF 值。因为“good”这个词在所有文档中出现的频率很高,所以它的 TF-IDF 值就变成了零。这使得原本出现频率很低的区别性单词“battle”的权重更大。
source: Jurafsky et al., 2018
虽然用 TF-IDF 扩充的词袋模型是很好的模型,但是它们不能捕捉语义上的细微差别。让我们用下面的句子来说明这一点:“猫坐在破墙上”,“狗跳过砖结构”。虽然这两个句子描述的是两个独立的事件,但是它们的语义却是相似的。一只狗和一只猫相似,因为它们共享一个叫做的动物实体。一面墙可以被视为类似于一个砖结构。因此,虽然这些句子讨论不同的事件,但它们在语义上彼此相关。在经典的单词袋模型中(单词在它们自己的维度中被编码),编码这样的语义相似性是不可能的。此外,当使用大量词汇和单词向量变大时,这种模型表现出很少的计算问题。我们将在下一节介绍一种更好的方法。
Word2vec 语言模型
用稀疏而长的向量来表示单词或文档实际上是没有效率的。这些向量通常是稀疏的,因为许多位置被零值填充。它们很长,因为它们的维数等于词汇表的大小或文档集合的大小。
什么是单词嵌入?
与稀疏向量相反,密集向量可以更成功地作为特征包含在许多机器学习系统中。密集向量也意味着需要估计的参数更少。在上一节中,我们看到了如何计算语料库中任何给定单词的 tf 和 tf-idf 值。如果我们不是计算每个单词 w 在另一个单词 v 的上下文中出现的频率,而是训练一个二进制预测任务的分类器“单词 w 可能出现在 v 附近吗?”,那么我们可以使用学习的分类器权重作为单词嵌入。这些成为单词的连续矢量表示。如果我们想要计算单词之间的语义相似度,我们可以通过查看两个嵌入之间的角度来实现,即它们的余弦相似度,正如我们之前看到的。
我们如何计算单词嵌入?
嵌入向量通常至少约 100 维长才能有效,这意味着当我们有 100,000 个单词的词汇表时,分类器需要调整数千万个数字。对于给定的语料库,我们如何确定这些嵌入呢?这正是 word2vec 语言模型的设计目的。
Word2vec 有两种型号:CBOW 型号和 skip-gram 型号(由 Mikolov 等人提出)。艾尔。,2013,在谷歌(又来了!)).在 skip-gram 变体中,使用目标单词预测上下文单词,而使用周围单词预测目标单词的变体是 CBOW 模型。通常人们会在大型语料库中使用 word2vec 实现和预训练嵌入。
我们现在将开发 word2vec 模型的 skip-gram 变体背后的直觉。让我们假设下面的句子,其中“杏子”是目标单词,“汤匙”、“of”、“果酱”和“a”是考虑双单词窗口时的上下文单词。
我们可以构建一个二元分类器,它将任意一对单词 (t,c) 作为输入,如果 c 是 t 和 False 的真实上下文单词,则预测为真。例如,分类器将为(杏,汤匙)返回真,为(杏,捏)返回假。下面我们看到更多正面和负面类的例子,当把杏作为目标时。
更进一步,我们必须将每个(上下文窗口,目标)对分成(输入,输出)示例,其中输入是目标,输出是上下文中的一个单词。出于说明的目的,对(【of,杏,a,pinch】,果酱)将产生正例(果酱,杏),,因为杏是果酱的真实上下文词。(果酱、柠檬)会是一个反面例子。我们继续对每个(上下文窗口、目标)对应用该操作来构建我们的数据集。最后,我们用词汇表中的唯一索引替换每个单词,以便使用独热向量表示。
给定一组正的和负的训练样本,以及用于目标的初始组
嵌入 W 和用于上下文单词的初始组 C ,分类器的目标是调整这些嵌入,使得我们最大化正样本嵌入的相似性(点积),并且最小化负样本嵌入的相似性。典型地,逻辑回归将解决这个任务。或者,使用具有 softmax 的神经网络。
d-dimentional embeddings training on a V-size vocabulary — source: Jurafsky et al., 2018
我们为什么喜欢 Word2vec?
令人惊讶的是,Word2vec 嵌入允许探索单词之间有趣的数学关系。例如,如果我们从单词“king”的向量中减去单词“man”的向量,然后将结果向量加上单词“woman”的向量,我们将得到单词“queen”的向量。
source: Z. Djordjevic, Harvard
我们还可以使用嵌入向量元素的元素相加来询问诸如“德国+航空公司”之类的问题,并通过查看与复合向量最接近的标记来得出令人印象深刻的答案,如下所示。
source: Z. Djordjevic, Harvard
当在不同语言的可比语料库上训练时,Word2vec 向量应该具有相似的结构,从而允许我们执行机器翻译。
source: Z. Djordjevic, Harvard
嵌入还用于查找与用户指定的单词最接近的单词。他们还可以检测单词之间的性别关系和复数-单数关系。单词向量也可以用于从庞大的数据集中导出单词类别,例如通过在单词向量的顶部执行 K-means 聚类。
在本节中,我们讨论了 Word2vec 变体 CBOW 和 Skip gram,它们是本地上下文窗口方法。它们可以很好地处理少量的训练数据,甚至可以表示被认为是罕见的单词。然而,它们没有充分利用关于单词共现的全局统计信息。因此,让我们看看另一种声称可以解决这个问题的方法。
手套语言模型
GloVe(全局向量)采用了与 Word2vec 不同的方法。GloVe 不是从设计用于执行分类任务(预测相邻单词)的神经网络或逻辑回归中提取嵌入,而是直接优化嵌入,使得两个单词向量的点积等于这两个单词在彼此附近出现的次数的对数(例如,在两个单词的窗口内)。这迫使嵌入向量对在它们附近出现的单词的频率分布进行编码。我们认为有些读者可能在整篇文章中遗漏了 Python 代码。从现在开始,我们会让他们开心一点。
下面我们将说明如何使用来自预训练手套模型的单词嵌入。我们利用 Python 包 Gensim 。
嵌入(词向量)的美妙之处在于,你不必实现任何 Skip gram 算法,也不必构建大量文本并自己计算权重。你可以使用向量,慷慨的人们已经通过使用非常大的语料库和大量的 GPU 为公众准备了向量。我们将使用预训练的单词向量 glove.6B ,它是在 60 亿个标记的语料库上训练的,包含 40 万个单词的词汇量,从不同的大规模网络数据集(维基百科等)中获得。每个单词分别由 50、100、200 或 300 维的嵌入向量表示。我们将使用 100 维向量,它们存储在一个文件中。第一步是将 GloVe 文件格式转换为 word2vec 文件格式。唯一的区别是增加了一个小标题行。这可以通过调用 glove2word2vec()函数来完成。每一行都以单词开头,后面是该单词对应的所有向量值,每一行都用一个空格隔开,就像下图中单词“the”的情况一样。
正如我们在上一节中解释的那样,这些实值词向量已被证明对各种自然语言处理任务都很有用,包括解析、命名实体识别和机器翻译。例如,我们发现类似以下的声明适用于相关的单词向量:
国王男人+女人≈王后
也就是说,从“国王”中减去“男人”的概念并加上“女人”这个词,“女王”是最接近的词。“国王”中的“男子气”被“女子气”所取代,给了我们“女王”。这种关于向量的基本代数可以让你进行有趣的语义推理。
>>> result = model.most_similar(positive=['woman', 'king'],
negative=['man'],
topn=1)
>>> print(result)[('queen', 0.7698541283607483)]
使用单词嵌入的类比工具,我们甚至可以问哪个单词是“俄罗斯”,就像“巴黎”是“法国”一样?
>>> result = model.most_similar(positive=['russia', 'paris'],
negative=['france'],
topn=1)
>>> print(result)[('moscow', 0.8845715522766113)]
为什么这个效果这么好?让我们仔细看看“俄罗斯”、“莫斯科”、“法国”、“巴黎”这四个词的嵌入。我们可以使用 PCA 变换的前两个分量将 100 个单词的向量投影到 2D 空间中。我们也可以使用 t 分布随机邻居嵌入(t-SNE)方法绘制类似的图。下面的 PCA 图显示“法国”和“莫斯科”之间的直线几乎平行于“法国”和“巴黎”之间的直线。使用 t-SNE,我们获得的谱线比使用 PCA 获得的谱线更加平行。t-SNE 是一种降维技术,特别适合于高维数据集的可视化。与 PCA 相反,它不是一种数学技术,而是一种概率技术。
100 维向量也非常擅长回答以下形式的类比问题:“ a 对 b 就像 c 对?”。例如:
- 巴黎对于法国来说是什么?
- 女人和国王对男人有什么关系?
- 什么是狗,什么是猫?
- 对于厨师来说,什么是石头对于雕刻家?
- 什么是蜜蜂,什么是熊的巢穴?
下面,我们寻求这些问题的答案,并展示计算机如何使用单词嵌入赢得下一个电视节目的问答比赛。
上面的图清楚地显示了嵌入向量能够找到“莫斯科”作为“俄罗斯”的首都,因为“巴黎”是“法国”的首都。同样,“蜂巢”对于“蜜蜂”就像“巢穴”对于“熊”一样。
结论
在本文中,我们探讨了为什么用数字格式表示文本对于自然语言处理很重要。我们还介绍了最常用的方法,温和而直观地涵盖了底层算法的关键方面。我们讨论了几种语言模型:一键编码、N-gram、单词包、td-idf、word2vec 和 glove。有一些流行的语言模型没有被介绍。例如,fastText 是 word2vec 模型的扩展,它不是直接学习单词的向量,而是将每个单词表示为 n 元字符。这对于检测后缀和前缀特别有用。本文没有探讨的另一个领域是主题建模。有各种各样的技术用于主题建模,其中大多数涉及术语-文档矩阵的某种形式的矩阵分解(潜在语义索引、潜在狄利克雷分配)。
最近,开发了非常强大的语言模型,如 OpenAI GPT-2 和 Google BERT。在我关于谷歌 BERT 的文章中,我解释了如何微调一个预先训练的模型,以利用强大的单词向量表示来完成机器学习任务。
变压器 DIY 实用指南。经过实践验证的 PyTorch 代码,用于对 BERT 进行微调的意图分类。
towardsdatascience.com](/bert-for-dummies-step-by-step-tutorial-fb90890ffe03)
恰当地表达文本对结交新朋友很有帮助。为了能够在下面的句子中正确地大写我们朋友的名字,我们需要识别第一个“石头”是人名,第二个是物体。在我关于自然语言处理中的true caseing 的文章中,这个主题得到了进一步的发展。
如果你真的对表示自然语言文本的问题感兴趣,我们推荐以下书籍作为进一步阅读: 语音和语言处理,第 3 版。作者丹·茹拉夫斯基和詹姆斯·马丁,2018T5。我们在这篇文章中孜孜不倦地使用了那本书中的观点。
感谢您的阅读。请随意查看我下面的文章。
在开始是神经元:梯度下降,反向传播,回归,自动编码器,细胞神经网络…
towardsdatascience.com](/why-deep-learning-works-289f17cab01a) [## 基于 LSTM 的非洲语言分类
厌倦了德法数据集?看看 Yemba,脱颖而出。力学的 LSTM,GRU 解释和应用,与…
towardsdatascience.com](/lstm-based-african-language-classification-e4f644c0f29e) [## 基于序列对序列模型的自然语言理解
如何预测客户询问背后的意图?Seq2Seq 型号说明。在 ATIS 数据集上演示的槽填充…
towardsdatascience.com](/natural-language-understanding-with-sequence-to-sequence-models-e87d41ad258b) [## NLU 任务注意机制实用指南
测试动手策略以解决注意力问题,从而改进序列到序列模型
towardsdatascience.com](/practical-guide-to-attention-mechanism-for-nlu-tasks-ccc47be8d500) [## 自然语言处理中的真实大小写
恢复推文和短信中的大写字母可以提高可读性。正确的正确大小写对于…至关重要
towardsdatascience.com](/truecasing-in-natural-language-processing-12c4df086c21)
使用 Kaggle 和 GitHub 操作的可再现数据科学
本教程演示了如何将 Kaggle 与 GitHub 操作集成在一起,以便更好地再现数据科学项目。
Reproducibility means hitting the right target, every time (Photo by Oliver Buchmann on Unsplash)
随着数据科学中出现的再现性危机,对数据科学研究人员来说,提供对其代码的开放访问变得越来越重要。其中一个基本要素是确保现有实验在代码变化时的持续性能。通过使用测试和记录良好的代码,可以提高正在进行的项目的可重复性。
Kaggle 和 GitHub 操作
Kaggle 是最知名的数据科学社区之一,致力于寻找数据集、与其他数据科学家合作以及参加竞赛。对于所有级别的从业者来说,这是一个极好的资源,并且提供了一个强大的 API 来访问它的资源。通过使用这个 API,可以创建自动下载数据集的测试,算法可以根据这些数据集运行,确保算法在代码更新时继续按预期执行。
GitHub 最近发布了 GitHub Actions ,这是一个直接从 GitHub 仓库自动化工作流的集成平台。本文的其余部分演示了如何将 GitHub 动作与 Kaggle API 一起使用,以允许对数据科学应用程序进行连续测试。使用 Kaggle API 的 GitHub 动作的完整实现可以在这里找到。
工作流程分解
下面详细介绍了将 Kaggle 与 GitHub 动作集成的最基本设置。这不包括数据科学测试脚本的实际执行,因为它们依赖于语言。相反,它展示了如何在 GitHub 动作中运行 Kaggle API 命令,到达可以执行测试脚本的地方。
工作流程的基本要素如下:
- 在测试环境中设置 Python
- 安装 Kaggle Python API
- 执行 Kaggle 命令
- 运行测试脚本(省略)
履行
GitHub 操作是使用 YAML 文件创建作业并指定作业中的步骤来实现的。以下作业中的每个步骤都与上面工作流中的元素相对应。
- name: Setup python
uses: actions/setup-python@v1
with:
python-version: 3.6
architecture: x64
- name: Setup Kaggle
run: pip install kaggle
- name: Run Kaggle command
run: kaggle competitions list
env:
KAGGLE_USERNAME: ${{ secrets.KaggleUsername }}
KAGGLE_KEY: ${{ secrets.KaggleKey }}
这个实现利用了 Kaggle PyPi 包,该包允许 Kaggle API 命令通过命令行运行。在这个例子中,job 简单地列出了 Kaggle 上可用的竞争对手。可用 Kaggle API 命令的分类可以在这里找到。
也可以像 GitHub actions 中的其他任务一样,将多个 Kaggle 命令链接在一起。在这里,工作流步骤显示 Kaggle 版本,然后列出所有可用的竞赛。
- name: Run multiple Kaggle commands
run: |
kaggle --version
kaggle competitions list
env:
KAGGLE_USERNAME: ${{ secrets.KaggleUsername }}
KAGGLE_KEY: ${{ secrets.KaggleKey }}
向 Kaggle 认证
使用 Kaggle API 需要一个访问令牌。这些可以在 Kaggle 网站上创建。令牌通常通过文件提供给 Kaggle API,但是 KAGGLE_USERNAME 和 KAGGLE_KEY 环境变量也可以用来进行身份验证。可以在 GitHub actions 中配置环境变量,如上面代码中的 env 参数所示。令牌变量被保存为 GitHub secrets 以确保个人令牌不被暴露。
这段代码的完整实现可以在这里找到。希望本指南为您提供了在 GitHub actions 中使用 Kaggle API 的快速介绍,并允许您开始更彻底地测试您的数据科学代码!
可重复的模型训练:深度潜水
可重复的研究很容易。只需在某处记录您的参数和指标,修复种子,您就可以开始了
—我,大约两周前。
哦,天啊,我错了。
有很多关于可重复研究的研讨会、教程和会议。
大量的实用程序、工具和框架被用来帮助我们做出良好的可复制的解决方案。
然而,仍然存在问题。这些陷阱在一个简单的辅导项目中并不明显,但在任何真正的研究中必然会发生。很少有人谈论它们,所以我想分享我关于这些话题的知识。
在这篇文章中,我将讲述一个关于我对能够持续训练模型的追求的故事(所以每次跑步都给相同的重量)。
意想不到的问题
从前,我有一个与计算机视觉(笔迹作者识别)相关的项目。
在某个时候,我决定花时间重构代码和整理项目。我将我的大型 Keras 模型分成几个阶段,为每个阶段设计测试集,并使用 ML Flow 来跟踪每个阶段的结果和性能(这很难,但这是另一个故事了)。
经过一周左右的重构,我已经构建了一个很好的管道,捕获了一些 bug,设法摆弄了一下超参数,并略微提高了性能。
然而,我注意到一件奇怪的事情。我修复了所有随机种子,正如许多向导建议的那样:
def fix_seeds(seed):
random.seed(seed)
np.random.seed(seed)
tf.set_random_seed(seed)
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
但是由于某种原因,连续两次使用相同的超参数得到了不同的结果。
由于无法跟踪项目中的问题,我决定用一个小模型制作一个脚本来重现这个问题。
我定义了一个简单的神经网络:
def create_mlp(dim):
model = Sequential()
model.add(Dense(8, input_dim=dim))
model.add(Dense(1))
return model
因为数据在这里并不重要,所以我生成了一些随机数据来处理。之后,我们准备训练我们的模型:
model = create_mlp(10)
init_weights = np.array(model.get_weights()[0]).sum()
model.compile(optimizer=keras.optimizers.RMSprop(lr=1e-2),
loss=keras.losses.MSE)
model.fit(Xs, Ys, batch_size=10, epochs=10)
训练后,我们可以检查再现性。assert _ same _ cross _ runs是一个简单的函数,它检查传递的值在两次运行之间是否相同(通过将值写入文件来完成):
assert_same_across_runs("dense model data", Ys.sum())
assert_same_across_runs("dense model weight after training",
init_weights)
assert_same_across_runs("dense model weight after training",
np.array(model.get_weights()[0]).sum())
我运行了几次。每次执行的模型权重完全相同。
奇怪!我通过插入卷积层给模型增加了一点复杂性:
def create_nnet(dim):
input = Input(shape=dim)
conv = Conv2D(5, (3, 3), activation="relu")(input)
flat = Flatten()(conv)
output = Dense(1)(flat)
return Model([input], [output])
训练过程非常相似:我们创建模型,生成一些数据,训练我们的模型,然后检查指标。
瞧,它碎了。每次运行脚本时,都会打印不同的数字。
这个问题不会发生在没有 GPU 的机器上。如果你的机器有 GPU,你可以通过从控制台设置 CUDA_VISIBLE_DEVICES 环境变量为"",在脚本中隐藏它。
快速调查发现了丑陋的事实:再现性存在问题,一些层使模型不可再现,至少在默认情况下(对所有“你因为使用 Keras 而受苦”的人来说,Pytorch 有一个类似的问题
为什么会这样?
一些复杂的操作没有明确定义的子操作顺序。
比如卷积就是一堆加法,但是这些加法的顺序并没有定义。
因此,每次执行都会导致不同的求和顺序。因为我们使用有限精度的浮点运算,卷积产生的结果略有不同。
是的,求和的顺序很重要,(a+b)+c!= a+(b+c)!你甚至可以自己检查:
import numpy as np
np.random.seed(42)xs = np.random.normal(size=10000)
a = 0.0
for x in xs:
a += xb = 0
for x in reversed(xs):
b += xprint(a, b)
print("Difference: ", a - b)
应该打印
-21.359833684261957 -21.359833684262377
Difference: 4.192202140984591e-13
没错,就是“就 4e-13”。但是因为这种不精确发生在深度神经网络的每一层,并且对于每一批,这种误差随着层和时间而累积,并且模型权重显著偏离。因此,连续两次运行的损失可能如下所示:
重要吗?
有人可能会说,运行之间的这些小差异不应该影响模型的性能,事实上,固定随机种子和精确的再现性并不那么重要。
嗯,这个论点有可取之处。随机性影响权重;因此,模型性能在技术上取决于随机种子。与添加新功能或改变架构相比,改变种子对准确性的影响应该较小。此外,因为随机种子不是模型的重要部分,所以对不同的种子多次评估模型(或者让 GPU 随机化)并报告平均值和置信区间可能是有用的。
然而,在实践中,很少有论文这样做。相反,模型与基于点估计的基线进行比较。此外,还有担心论文报告的改进比这种随机性少,并且不恰当的汇总会扭曲结果。
更糟糕的是,这会导致代码中不可约的随机性。您不能编写单元测试。这通常不会困扰数据科学家,所以想象一种情况。
你已经找到了一篇描述一个奇特模型的论文——并且它已经清晰地组织了开源实现。你下载代码和模型,开始训练它。几天后(这是一个非常奇特的模型)
你测试这个模型。它不起作用。是超参数的问题吗?您的硬件或驱动程序版本?数据集?也许,回购作者是骗子,问题出在存储库本身?你永远不会知道。
在实验完全重现之前,故障排除是极其麻烦的,因为你不知道管道的哪一部分出现了问题。**
因此,拥有复制模型的能力似乎非常方便。
哦不。我们该怎么办?
求和的顺序未定义?好吧。我们可以自己定义,也就是把卷积重写为一堆求和。是的,它会带来一些开销,但是它会解决我们的问题。
令人高兴的是,CuDNN 已经有了大多数操作的“可再现”实现(而且确实更慢)。首先,你不需要自己写任何东西,你只需要告诉 CuDNN 使用它。其次,CuDNN 在堆栈中的位置
很低——因此,您不会得到太多的开销:
在你的代码和硬件之间有一个分层的管道
因为我们不直接与 CuDNN 交互,所以我们必须告诉我们选择的库使用特定的实现。换句话说,我们必须打开“我可以接受较慢的训练,让我每次跑步都有稳定的结果”的标志。
不幸的是,Keras 还没有那个功能,如
这些 问题中所述。
看来是 PyTorch 大放异彩的时候了。它具有支持使用 CuDNN 确定性实现的设置:
火炬能拯救我们吗?
让我们写一个简单的单卷积网络,用随机数据进行训练。确切的架构或数据并不重要,因为我们只是在测试再现性。
**class Net(nn.Module):
def __init__(self, in_shape: int):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 5, 3)
self.hidden_size = int((in_shape — 2) * (in_shape — 2) / 4) * 5
self.fc1 = nn.Linear(self.hidden_size, 1)def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2)
x = x.view(-1, self.hidden_size)
x = F.relu(self.fc1(x))
return x**
fix_seeds 函数也被修改为包括
**def fix_seeds(seed):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(42)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False**
同样,我们将使用合成数据来训练网络。
初始化后,我们确保权重之和等于特定值。类似地,在训练网络之后,我们检查模型权重。如果有任何差异或随机性,脚本会告诉我们。
**python3 reproducibility_cnn_torch.py**
给出一致的结果,这意味着在 PyTorch 中训练神经网络给出完全相同的权重。
有一些警告。首先,这些设置会影响训练时间,但是测试显示的差异可以忽略不计( 1.14 +- 0.07 秒对于非确定性版本; 1.17 +- 0.08 秒为确定性一)。其次,CuDNN 文档警告我们有几种算法没有再现性保证。这些算法通常比它们的确定性变体更快,但是如果设置了标志,PyTorch 就不会使用它们。最后,有些模块是不确定的(我自己无法重现这个问题)。
无论如何,这些问题很少成为障碍。所以,Torch 有内置的再现性支持,而 Keras 现在没有这样的功能。
但是等等!有一些 猜测由于 Keras 和 Torch 共享后端,在 PyTorch 中设置这些变量会影响 Keras。如果变量影响某些全过程参数,则可能出现这种情况。这样,我们就可以利用这些标志,并使用 Keras 轻松地编写模型。
首先,让我们看看这些标志是如何工作的。
我们再深入一点!从 Python 端
设置确定性/基准标志调用 C 源代码中定义的函数。这里,状态存储在内部。
之后,该标志影响卷积期间算法的选择。换句话说,设置这个标志不会影响全局状态(例如,环境变量)。
因此,PyTorch 设置似乎不会影响 Keras 内部(实际的测试 证实了这一点)。
补充:一些用户报告说,对于一些层(CuDNNLSTM 是一个明显的例子)和一些硬件和软件的组合,这个黑客可能会工作。这绝对是一个有趣的效果,但是我不鼓励在实践中使用它。使用一种有时有效有时无效的技术会破坏可复制学习的整体理念。
结论
修复随机种子非常有用,因为它有助于模型调试。此外,运行之间减少的度量方差有助于决定某个特性是否会提高模型的性能。
但有时这还不够。某些模型(卷积、递归)需要设置额外的 CuDNN 设置。Keras 还没有这样的功能,而 PyTorch 有:
**torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False**
再现谷歌研究足球 RL 结果
这篇文章记录了我试图(并成功)重现谷歌足球研究(GRF)论文中一些结果的旅程。具体来说,我成功地在单 GPU 云实例上使用 OpenAI 的 PPO 训练了一个强化学习(RL)代理,仅用了两天的最长时间。它复制了纸上的数字。
设置:云实例
我们先从用 PPO 设置好准备 RL 的云机器开始。如果你已经有这样做的机器,你可以跳过这一部分。
在你的谷歌云账户上,进入“市场”,搜索“深度学习虚拟机”模板。我变得很好奇,想看看你可以选择的各种 GPU、CPU 内核和 RAM 的成本/收益权衡,所以我用三种不同的设置进行了我的实验。我将在这里提供最具成本效益的方法,并在下面的“成本/时间权衡”一节中详细介绍这三种方法。我建议使用 12 个虚拟 CPU、12GB 内存、64GB 磁盘空间和一个英伟达 P100 GPU。务必选中“安装 NVIDIA 驱动程序”复选框
一旦机器被创建,SSH 进入它。
设置:软件和驱动程序
一旦你在你的机器上,我们可以开始设置软件。
注意:如果您在任何时候遇到由于
libGL
导致的错误,请参阅本文末尾的“修复 libGL 问题”一节。
首先,有一小组工具我再也离不开了,但是你可以跳过:sudo apt install tmux fish
,然后以env SHELL=
which fish tmux
的身份开始一个新的 tmux 会话。
接下来,我总是更喜欢使用 python 虚拟环境,所以让我们创建一个并在本教程的剩余部分使用它:sudo apt install python3-venv
,然后用python3 -m venv venv
在一个名为venv
的文件夹中创建它,然后通过. venv/bin/activate.fish
开始使用它(是的,该命令以点开始。)
如果您使用云实例,首先将 TensorFlow 的优化版本安装到 virtualenv 中,在撰写本文时,这是使用pip3 install /opt/deeplearning/binaries/tensorflow/tensorflow_gpu-1.14.0-cp35-cp35m-linux_x86_64.whl
完成的,在您阅读时,文件名可能会略有变化。
现在,我们终于可以按照 README 安装 gfootball 及其所有依赖项,使用“克隆的 repo”方式,因为我们将做一些轻微的更改。为了完整起见,这些是命令:
> **sudo** apt-get install git cmake build-essential libgl1-mesa-dev libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-gfx-dev libboost-all-dev libdirectfb-dev libst-dev mesa-utils xvfb x11vnc libsdl-sge-dev python3-pip
然后克隆 repo,切换到文件夹,并将其安装到 virtualenv 中,这需要一点时间:
> **git** clone https://github.com/google-research/football.git
> **cd** football
> **pip3** install .
接下来,我们想从 OpenAI 基线运行 PPO 算法,所以也要安装它和它的依赖项,同样按照自述文件,为了完整起见复制到这里:pip3 install "tensorflow-gpu<2.0" dm-sonnet git+https://github.com/openai/baselines.git@master
。
运行 PPO 培训
我正在复制的实验是在“简单”模式下的 11vs11 游戏,因为这似乎是导致在合理数量的步骤中合理地玩好 PPO 代理的原因。以下是我们试图复制的论文中的具体数字:
我们可以在论文的附录中找到所有的超参数。
让我们将带有所有参数的完整命令(可在本文的附录中找到)放在一个名为gfootball/examples/repro_scoring_easy.sh
的脚本文件中,以便于参考和运行:
#!/bin/bashpython3 -u -m gfootball.examples.run_ppo2 \
--level 11_vs_11_easy_stochastic \
--reward_experiment scoring \
--policy impala_cnn \
--cliprange 0.115 \
--gamma 0.997 \
--ent_coef 0.00155 \
--num_timesteps 50000000 \
--max_grad_norm 0.76 \
--lr 0.00011879 \
--num_envs 16 \
--noptepochs 2 \
--nminibatches 4 \
--nsteps 512 \
"$@"
max_grad_norm
是唯一不可用的设置,但是我准备了一个拉请求来暴露它。最后一位("$@"
)只是转发所有附加参数,因此现在我们可以如下调用它来运行训练:
> **gfootball/examples/repro_checkpoint_easy.sh** --dump_scores 2>&1 | tee repro_checkpoint_easy.txt
我喜欢将输出明确地tee
到一个日志文件中,以便于参考,但是请注意,OpenAI baselines 会在/tmp/openai-[datetime]/
的某个地方生成一个包含日志的文件夹,包括所有输出。虽然它们在/tmp 中,但是要注意它们 最终会 消失。
--dump_scores
标志指示环境也存储导致进球的两百帧的.dump
文件(在 16 个环境中的第一个上),因此我们可以稍后观看那些进球。另一个将使用更多磁盘空间的选项是使用--dump_full_episodes
标志为每个完整剧集(16 个环境中的第一个)生成一个转储。如果您想要创建高质量的渲染视频,这是当前必需的。
这里有趣的是最后一个(按日期时间)文件夹中的progress.csv
文件,包含整体训练进度,如果您启用了视频转储,第一个文件夹应该包含许多“得分转储”,这是两队得分前 20 秒的简短片段。
您可以使用标准的 unix 工具在训练期间获得一些统计数据,例如,我使用以下命令来计算平均 FPS 计数:
> **grep** fps repro_scoring_easy.txt | **awk** '{ FS="|"; total += $3; count++ } END { print total/count }'156.545
再现的结果
在使用“得分奖励”的三次跑步中(即只有当代理人得分时才给予奖励),我在训练 50 米步后达到了平均每集奖励 1.57、2.42、4.12,对应于2.70±1.06(标准偏差)。论文附录中的表 5 报告了该设置的 2.75-1.31。我只对“检查点奖励”进行了一次实验,它达到了平均每集奖励 6.31 ,落在报告的5.53±1.28内。
因此,虽然这再现了结果,但你可以从三次重复的原始数字中看到,在三次重复中,学习到的策略的质量变化相当大。为了让 RL 更可靠,我们还有很多工作要做!
训练后要做的事情
一旦训练完成,我们可以报告训练曲线,并查看平均每集奖励,这通常是研究论文所必需的。例如,这个命令给了我一段时间的平均剧集奖励:
**> grep** eprewmean repro_scoring_easy.txt | **awk** 'BEGIN{FS="|"} { print $3 }'
或者,我们甚至可以使用gnuplot
立即创建一个图,如下所示,在本例中为三种药剂中的最佳 PPO 药剂:
**> grep** eprewmean repro_scoring_easy3.txt | **awk** 'BEGIN{FS="|"} { print NR $3 }' | **gnuplot** -p -e "set terminal png size 400,300; set output 'eprewmean.png'; plot '< cat -' with lines title 'reward'"
但是我们也可以做一些更有趣的事情,比如看我们经纪人的视频,甚至和他比赛!
制作和观看视频
人们可以在事后使用dump_to_video
工具从“分数转储”中创建一个视频,比如:python -u -m gfootball.dump_to_video — trace_file /tmp/openai-2019–09–13–16–00–43–638465/score_20190913–204112398339.dump
。
它会在命令行输出中告诉您视频文件的存储位置,如下所示:
I0916 18:03:21.296118 139929219241792 observation_processor.py:383] Start dump episode_doneI0916 18:03:22.525743 139929219241792 observation_processor.py:234] Dump written to /tmp/openai-2019–09–13–16–00–43–638465/episode_done_20190916–180321296073.dumpI0916 18:03:22.525876 139929219241792 observation_processor.py:236] **Video written to /tmp/openai-2019–09–13–16–00–43–638465/episode_done_20190916–180321296073.avi**
默认情况下,这个视频是一个“调试视频”,它不是游戏的真实呈现,但有更多关于当前正在发生的事情的信息。下面展示了一个很好的视频,我们的球队(绿色 H )跑向对手(蓝色 A ),丢球(红色 B ),捡球得分。
要查看(并保存)一个轨迹的实际渲染视频,需要使用replay
工具,比如:python -u -m gfootball.replay --trace_file /tmp/openai-2019-09–13–16–00–43–638465/episode_done_20190913–161055711125.dump
。这将打开游戏窗口,并再次播放完整的游戏供您观看。一旦游戏结束,当它保存完整游戏的.avi
视频时,屏幕会出现大约 30 秒的停滞——请耐心等待它结束。我就是这样创作了文章顶部的视频。如果你想剪切出一个容易共享的.gif
文件,这个是怎么做的:
**> ffmpeg** -ss 98 -t 11 -i /tmp/dumps/episode_done_20191022-181100113944.avi -vf "scale=320:-1:lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 game.gif
看起来,至少在我写这篇文章的时候,它只能渲染从游戏开始时开始的痕迹,所以还没有完整图形的“得分转储”。
和我们训练有素的特工比赛
这可能是最令人兴奋的事情:)它非常简单,在自述文件中有很好的解释,但仅供参考,我使用以下命令来对抗如上所述训练的 PPO 代理:
**> python** -m gfootball.play_game --players "keyboard:right_players:1;ppo2_cnn:left_players=1,policy=impala_cnn,checkpoint=/path/to/checkpoint"
关于使用哪个键,参见自述文件,但本质上是箭头和 WASD。游戏结束时会写一个完整剧集的转储,你可以像上面一样使用它(使用gfootball.replay
命令)来创建一个完整的渲染。游戏的 avi 视频,就像这篇文章上面的那个。
使用这个命令的一个小变体,您可以观看它与内置 AI 的比赛:
**> python** -m gfootball.play_game --players "ppo2_cnn:left_players=1,policy=impala_cnn,checkpoint=/path/to/checkpoint" --level=11_vs_11_easy_stochastic
我的结论是,那个叫达芬奇的玩家确实不错!
成本/时间权衡
我很好奇这个项目最具成本效益的设置是什么,因为我想重复运行三次以获得置信区间,所以我尝试了三种不同的设置,并将它们的速度和成本总结如下:
- 首先我试了单个 V100 GPU,12 个 vCPU 核,32 GB 内存,128Gb 普通磁盘。在这台机器上,我在每种环境下实现了大约 17 SPS(每秒步数)和大约 50–60 FPS(每秒帧数)。我们将并行运行 16 个环境,每个环境平均每秒 280 帧。预计需要 50 小时,5000 万步需要 108 美元。
- 第二次尝试使用便宜得多的机器:8 个 vCPUs、8GB 内存、64GB 磁盘空间和一个 K80 GPU。这给了每个环境大约 10 SPS 和 50–60 游戏 FPS,平均总共大约 160 FPS。预计需要 89 小时,5000 万步的总成本为 51 美元。
- 第三,尝试一台“普通”的深度学习机器:12vCPUs、12GB 内存、64GB 磁盘空间和一个 P100 GPU。这给了每个环境大约 20 SPS 和 70–80 游戏 FPS,平均总共大约 320 FPS。预计 5000 万步需要 43 小时,总成本为 64 美元。
Screenshot of the most cost-efficient machine that I used: the “second try” i.e. the K80 GPU.
修复 libGL 问题
这个问题是我在云上想到的,但我假设它也可能发生在其他(基于 ubuntu 的)系统上,因为有许多 报告 或这个问题。我们无法回避的依赖项之一是libgl1-mesa-dev
包,它实际上破坏了/usr/lib/x86_64-linux-gnu/libGL.so
符号链接。
网上报道的一个明显的解决方案是强制重新安装sudo apt-get install --reinstall libgl1-mesa-glx
。我不知道这有多有效。我推荐的替代方案是,至少在 Google Cloud 上,简单地重新安装 GPU 驱动程序如下:/opt/deeplearning/install-driver.sh
这个问题就会被修复。
RescueForest:用随机森林预测紧急响应
King County SAR on the job
我正在完成 fast . aiML入门课程的材料,这太棒了。这种学习哲学,被导师杰里米描述为自上而下的方法,对我的学习方式非常有效。总的想法是,在你知道为什么它会起作用之前,你先要知道如何做 ML——就像你先知道如何打棒球,然后才知道为什么你会在给定的时间使用一种特定的策略一样。
我想做一个小的顶点项目来实践我学到的东西,所以我决定研究应急响应预测——特别是为一个名为金县搜救 (SAR)的组织,我是该组织的志愿者成员。我们执行各种各样的救援任务,但最常见的呼叫是帮助西雅图周围荒野中受伤或迷路的徒步旅行者。它大多是一个志愿者经营的组织,所以资源本来就有限。拥有一种方法来预测在任何给定的一天打电话的可能性可能会帮助我们优先考虑资源和准备,以最好地为社区服务。
我把这个项目分成了三个步骤,这三个步骤在本课程中都有涉及:1 .数据探索和清理 2。建立一个简单的模型并用它来研究特征重要性 3。特征工程和调整模型
这篇文章将涵盖我的一般方法和发现。详细代码和笔记本可以在我项目的回购中找到。
数据浏览,清理
在建立模型之前,我想了解我们拥有的数据的性质。有几个我们正在使用的数据源,我们将在日期前把它们连接在一起。Python 的 datetime 库对此很关键,并使这些操作变得更加容易。
结果数据
该项目的目标是预测在特定的一天是否有搜救呼叫发生。我从组织的内部数据库下载了这个,并删除了一些隐私信息。将数据加载到 python 和 pandas 允许一些简单的绘图,以确保我们专注于最相关的数据。我不得不缩小日期范围,从 2002 年到现在,因为在此之前的数据是不完整的。
一些探索图显示,我们在 29%的日子里有调用,这意味着数据有些不平衡,但并不可怕。电话在周末和夏天最频繁。我们凭直觉知道这一点,数据也支持这一点。这也证实了仅在日期内就可能有一些信息具有某种预测能力。
但首先,我们需要一个整洁的数据集。本质上,我们用一个表来表示我们所考虑的范围内的每个日期,并给出一个布尔值来报告当天是否有电话。通过利用 panda 的 date_range 函数,一个简单的脚本将 raw sar_data
转换成了一个clean_table
。
date_range **=** pd**.**date_range(start**=**'1/1/2002', end**=**'4/01/2019')
clean_table **=** []
**for** d **in** date_range:
**if** sar_data**.**date**.**isin([d])**.**any(): *# check if date in in table containing all calls*
clean_table**.**append([d,1])
**else**:
clean_table**.**append([d,0])
sar_clean **=** pd**.**DataFrame(clean_table)
sar_clean**.**columns **=** ['date','mission']
特征
通过使用clean_table
表中的日期列,我们可以使用漂亮的 fast.ai 函数提取信息,如星期、年、月等。从日期时间对象。在把它应用到我们整洁的桌子上之后,我们有了大约 13 个特性。
除此之外,我们还将整合一些来自 NOAA 的天气信息。他们提供了很多很酷的工具,数据科学家会发现这些工具很有用,我鼓励任何对整合天气数据感兴趣的人去看看。
理想情况下,我们可以在这个项目中使用天气预报数据,而不是实际的天气数据。当我们提前计划时,我们只能得到天气预报,而天气预报显然经常与实际天气不同。我找到的所有保存这些数据的资源都是付费服务,所以现在我不得不接受 NOAA 的数据。
我从两个当地气象站下载了天气数据——西雅图南部的波音机场和我们大部分任务发生的山脉中的加德纳山。我们得到温度、风、太阳和降水的信息,这是一幅给定一天的天气图。一些健全性检查确保数据按照我们预期的方式组织(夏天热,冬天多雨)。使用pandas.merge
将这些与clean_table
合并,得到包含以下特征的初始数据集:
`[Year', 'Month', 'Week', 'Day', 'Dayofweek', 'Dayofyear', 'Is_month_end', 'Is_month_start', 'Is_quarter_end', 'Is_quarter_start', 'Is_year_end', 'Is_year_start', 'Elapsed', 'DATE', 'AWND_x', 'PRCP_x', 'TAVG_x', 'TMAX_x', 'TMIN_x', 'TSUN', 'WT01', 'WT02', 'WT03', 'WT05', 'WT08', 'WT10', 'AWND_y', 'PRCP_y', 'SNWD', 'TAVG_y', 'TMAX_y', 'TMIN_y', 'TOBS', 'WESD']``
特征工程
测试、训练、初始模型
选择合适的验证和测试集是课程中的一个重要主题。我在这里采用了与杰里米讨论的推土机拍卖和杂货店销售预测的 Kaggle 竞赛相似的方法。在这些情况下,我们需要使用过去的数据来预测未来,因此我们按日期对数据进行排序,并为验证集保留最近的 15–20%的数据。我们会在这里做同样的事情。
对于测试集,我将使用一种更“真实”的方法,只在今年实时测试我的模型。
对于模型评估,内置的评分函数可能并不理想。只有 29%的时间有任务,所以一个天真的模型总是预测“没有呼叫”将是正确的,准确率为 71%。对于这种情况,ROC 曲线是一种不错的方法,所以我用它来进行模型评估。这些在 fast.ai 课程中没有广泛讨论,因为它们主要集中在回归问题上。作为复习,我发现这篇文章很有帮助。
接下来,用 scikit-learn 构建的一个简单的随机森林在 ROC 曲线中给出了一些信号(AUC=0.61),因此我继续进行这项工作,以便更好地理解手头的数据。
当深入研究模型中使用的特性重要性时,事情似乎变得有意义了。一周中的某一天、过去的天数(只是从数据集开始算起的连续天数)和一年中的某一天是三个最重要的特征。最重要的天气特征是西雅图的风,这可能预示着暴风雨的来临?接下来的几个天气特征是温度,这并不奇怪。
在课程中,Jeremy 保留了所有显示重要性的特征,即使它们可能是相关的。毫无疑问,附近地方的温度是相关的,但该模型应该用集合方法来处理这个问题。将来,做一些额外的功能工程来消除一些冗余可能是值得的。我确实删除了一些不太重要的功能,而且删除后不会影响性能。
假期数据
添加假期数据对模型有帮助吗?我使用了包含美国假期数据库的pandas.tseries.holiday
,并尝试了几种不同的方法,总结如下:-为is_holiday
添加一个布尔值列;-为days_until_next_holiday
和days_since_last_holiday
添加列;-为days_away_from_nearest_holiday
添加一个列
最后一种方法是最有效的,这是有道理的。节假日前后的几天最有可能是休息日,这与徒步旅行者的增加相对应。通过包含这些信息,ROC 从 61%提高到 65%。
谷歌趋势
在这个项目中,我发现了谷歌趋势数据的一个很酷的特性。虽然没有 API,但只是在网络界面上玩了玩,我就能得到关于国王县地区“徒步旅行”这个一般主题的搜索频率——这正是我们的准确反应区域。正如预期的那样,这些数据是季节性的,我希望它们可以捕捉到正在发生的其他事件,这些事件可能会增加或减少短期内对徒步旅行的兴趣。
添加这个特性给出了一个令人困惑的结果 ROC 没有提高,但是当您考虑特性的重要性时,它是第二重要的特性。这是否仅仅意味着趋势数据对于某些日期特征来说是多余的?我决定留着它继续前进。
构建最终模型
好了,现在是最终模型。我比较了具有相同基本参数的三种基于树的算法,AUC 总结如下。
- 随机森林:0.59
- AdaBoost: 0.61
- XGBoost: 0.63
XGBoost 做得最好,所以工具提供了学习如何调优这些模型的机会。我使用的主要方法是 sklearn 内置的网格搜索功能。这花了很长时间来运行,但结果给了我模型可以找到的最佳组合参数。这使我们的 AUC 上升到 0.67。
模型评估
我将全年监控该模型的性能,但是在撰写本文时,该模型有 23 的时间是正确预测的。这是个很难的问题,随机性很大,数据量很小。也就是说,到目前为止,它已经对我的生活产生了影响,让我在预测高呼叫概率的日子里提前做好准备。
尽管如此,仍有改进的空间。我将继续尝试新的模型,并在发现新的模型时添加新的数据。我也很高兴听到任何人对我可以改进我的方法的功能或方式的其他想法的建议。感谢 Jeremy、Rachel 和 fast.ai 团队带给我们如此美好的体验!
改编自我的网站
什么是自然实验?
实验和因果推理
方法、途径和应用
Photo by Andreas Gücklhorn on Unsplash
介绍
我喜欢阅读 Craig 等人(2017 )关于自然实验的综述文章(关于方法、途径和对公共卫生干预研究的贡献的概述)。在这篇文章中,我想总结它的要点,并附上我对因果推理发展的一些思考。这篇综述文章介绍了什么是 NE 以及对 NE 数据可用的方法和途径。通常情况下,年度综述,比如由克雷格等人撰写的这一篇,提供了对该领域近期发展状况和未来方向的快速回顾。这是学习数据科学的好方法。强烈推荐!
什么是 NE?
根据英国医学研究委员会的说法,任何不受研究人员控制的事件,将人群分为暴露组和未暴露组。
由于缺乏对分配过程的直接控制,研究人员不得不依靠统计工具来确定操纵暴露于治疗条件的变化的因果影响。
NEs 的关键挑战是排除选择进入治疗组的可能性,这将违反忽略假设。这种违反也使得治疗组和对照组不具有可比性,我们不能将结果变量的差异归因于干预的存在。
为了解决这个问题,数据科学家提出了潜在结果框架。POF 代表如果一个人暴露于和不暴露于干预时会发生的结果。
然而,棘手的是,这两种结果中只有一种是可观察到的,我们必须依靠反事实来推断单位之间的平均治疗效果。
如果分配是随机的,如在随机对照试验(RCTs)中,那么治疗组和对照组是可交换的。我们可以将这两组之间的差距归因于干预的存在。
如果分配不是随机的,如在 NEs 中,数据科学家必须依靠分配机制和统计方法的领域知识来实现有条件交换。
这是定性研究和领域知识发挥作用的时候,并确定在分配过程背后是否有一个因果故事。
我想说,由于实践和伦理的原因,NEs 在现实世界中比 RCT 有更广泛的应用范围。因此,正如 Craig et al. (2017 )建议的那样,选择合适的方法/设计对 NE 数据进行因果推断变得至关重要。
这样做主要有八种技术。我将在这里用一些研究笔记和实际应用的链接来介绍每种方法。请参考原始文章(这里是)来更全面地讨论每种技术。
方法
- 前后分析 。就我个人而言,如果没有更好的选择,这将是我的最后手段。没有多个数据点的单个案例比较。我们如何控制混杂因素?不是因果推理的理想选择。
- 回归调整 。当我们试图比较案例时,它有很多应用。
- 倾向得分匹配 。也适用于观测数据,但是 Gary King 最近否定了使用 PSM 的想法。
- 差异中的差异 。这是一种强有力的因果推理技术,具有简单明了的研究思想。
- 中断的时间序列 。具有多个数据项的因果方法。
- 合成控件 。这是工业界和学术界的一种流行方法,政治学家为此做出了巨大贡献。简而言之,如果对照组中没有与治疗组匹配的病例,我们可以人为地创建对照组的加权平均值作为基点。例如,我们使用其他案例的加权值创建一个人工控制场景,并比较这两组之间的差异。这是一个如此巧妙的想法,但有潜在的陷阱,对此我将在另一篇文章中详细阐述。
- T5【回归不连续设计】T6。强大的因果技术与一个伟大的视觉插图。
- 工具变量 。IV 方法包含很强的推理能力,但是众所周知很难找到。因此,它的应用有限。
如何让 NEs 在因果推理上更强?
这篇综述文章提供了三种解决方案:
- 加入定性成分以理解工作机制。我的两点看法是,在大数据和机器学习的时代,我们不应忘记定性研究的重要性。足够好地理解这个过程或领域知识,有助于我们开发更好的统计模型。
- 多种定量方法和目视检查相结合,检查 RDD 和 ITS 的不连续性。目视检查对于识别异常情况至关重要且简单明了。如果可能的话,更多更明智地使用它们。
- 引入伪造/安慰剂测试来评估因果归因的合理性。例如,我们可以使用不等价的因变量来测试未受干预影响的结果与受干预影响的结果的变化。这里,潜在的想法是使用多个 dv 交叉检查结果,这是一种广泛用于社会科学的研究思想。
Medium 最近进化出了它的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。
[## 阅读叶雷华博士研究员(以及其他成千上万的媒体作家)的每一个故事
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
leihua-ye.medium.com](https://leihua-ye.medium.com/membership)
实验和因果推理
如何不让你的在线控制实验失败
towardsdatascience.com](/online-controlled-experiment-8-common-pitfalls-and-solutions-ea4488e5a82e) [## 相关性并不意味着因果关系。现在怎么办?
数据科学中因果关系和相关性之间的地盘之争
towardsdatascience.com](/the-turf-war-between-causality-and-correlation-in-data-science-which-one-is-more-important-9256f609ab92) [## 数据科学家应该有充分的理由进行更多的实验
好的,坏的,丑陋的
towardsdatascience.com](/why-do-we-do-and-how-can-we-benefit-from-experimental-studies-a3bbdab313fe)
喜欢读这本书吗?
还有,看看我其他关于人工智能和机器学习的帖子。
线下和线上社交网络中的影响力研究
关系强度和网络度在决定社会影响力中的作用。
几乎所有关于社交网络和信息流分析的文章都是从提到斯坦利·米尔格拉姆在 20 世纪 60 年代著名的小世界实验开始的。我们照着做吧。
本文的前半部分是关于通过社会网络的信息传播的经典研究的主要发现。之后,我们将关注一种特殊的社交网络:在线社交网络。我们在 YouTube、Twitter 和脸书等社交媒体平台上发现了同样的离线社交网络特征吗?
注:本文是社交网络分析和影响者营销系列文章的一部分,全部基于我的硕士论文“Instagram 上的影响者欺诈:全球最大参与社区的描述性分析” 、 其中 你可以在这里 完整阅读。由于现在几乎没有人有时间阅读 140 多页的相关内容,我决定将我的硕士论文分成几篇中等长度的独立文章,让读者自己决定她感兴趣的内容。
insta gram 上相关标签的社交网络分析(使用 InstaCrawlR)
insta gram 上的影响者欺诈——对世界上最大的互动社区的描述性分析(乔纳斯·施罗德的硕士论文)
请随时关注我的个人资料以获取更新或稍后回来。我会继续添加其他文章的链接。
世界真小——离线社交网络的经典研究结果
Taken from Milgram (1967)
在 1967 年的实验中,米尔格拉姆要求随机选择的美国公民向随机目标传递一封信,只使用他们认识的朋友和熟人的名字。由此得出的路径长度中值为 5,这意味着人们通常只需几步就能彼此联系起来。这种“知识”进入了流行文化和常识(例如,S ix Degrees of 凯文·贝肯)。然而,更有趣的是他关于中介角色的发现。米尔格拉姆写给他们的信有一半是通过同样的三个人:雅各布斯先生、布朗先生和琼斯先生。这些人是高度联系的个人,或社会中心,基本上汇集了整个美国公民网络。
Granovetter (1973)将这些人称为桥梁,即信息通过社交网络流动的瓶颈。他认为,社交网络重叠的程度取决于连接它们的纽带的强度。越是相似或同性的个体,他们越有可能互动并形成牢固的关系。有道理:我们信任我们认识的人,他们往往和我们有相同的背景和兴趣。
然而,为了传播新的信息,我们需要关注那些联系不紧密的个体,他们将不同兴趣的社会圈子联系在一起。因此,弱关系在新信息的传播中起着特殊的作用,例如新产品或流行趋势。Brown 和 Reingen (1987)从经验上证明了这一假设。弱关系确实被发现与新思想的传播和子社区之间的传播不成比例地更相关。
米尔格拉姆经典实验的数字复制品也支持这一发现。在 Dodds,Muhamad 和 Watts (2003)的实验中,6 万名参与者被要求向来自几个国家的 18 个目标转发电子邮件。他们发现,在成功的连锁中,信息被转发给发送者描述为关系相当“随便”和“不密切”的人,因此:关系薄弱。然而,他们没有从米尔格拉姆的研究中找到雅各布斯先生的数字等价物。他们没有发现真正的桥梁。
从任何一个关系紧密的社区的立场来看,局外人都是局外人。他们很奇怪。然而,如上所述,局外人对于新思想的传播是很重要的。我们从许多关于创新传播的书籍和文章中知道,技术的早期采用者在开始时总是被认为是怪异的。
“为什么这个人在和他的手说话?”,是 90 年代许多人的想法。现在,每个人都有一部 iPhone,在乘地铁上下班的时候,可以和自己通话。
在他经常被引用的书《引爆点》(2000)中,格拉德威尔分析了任何趋势或社会流行病的传播——无论是技术采用、时尚趋势,甚至是犯罪。他认为有三种人必须像野火一样传播信息:连接器、专家和推销员。
连接器是像雅各布斯先生这样的人,他们通过自己的庞大网络将世界联系在一起。专家是有社会动机的人,他们通过分享信息在个人和市场之间充当中间人。当你想买一台新的笔记本电脑时,你最好在你的社交圈里寻找行家。销售人员被描述为天生的说服者,他们使用微妙的、主要是非语言的暗示来影响人们的观点。
专家是数据库。他们提供信息。连接器是社会粘合剂:他们传播它。当我们不相信我们所听到的时,推销员会说服我们。—马尔孔·格拉德威尔
格拉德威尔认为这些人最重要的功能之一就是充当翻译。他们获取创新者的信息,并将其翻译给更广泛的受众。因此,它们有助于解决摩尔(1991)的鸿沟问题。这对于那些试图将客户群从早期用户扩大到大众市场的公司来说非常重要。连接器、专家和销售人员——或者更现代的术语:影响者——可以帮助完成这项工作。
这么多关于与人面对面或通过模拟方式互动的旧世界。让我们继续研究在线社交网络中的影响力。
你好,扎克,我是汤姆!关于在线社交网络的一些研究结果
关于社会影响力和通过离线社交网络传播信息的经典研究人员不仅受到了他们所处时代的计算限制的挑战。他们不得不处理许多未经证实的假设和有限的数据,因为人们关系的本质和他们的个性不是很容易观察到的,而是可以通过调查解决的。
今天,由于技术进步和社交媒体平台的普及,社交网络分析如今更加富有成果。人们之间的联系很容易以关注者关系或朋友图表的形式观察到。构建和分析巨大的交互模型不再困难。
此外,人们乐于在网上分享大量关于自己和兴趣的信息。没有必要进行调查研究来确定个体群体的异质性和同质性——只需看看他们追随谁,喜欢什么。
这有可能解决 Manski(1993)在网络分析中经常发现的反射问题。一个社区的成员会因为群体对他们的影响而分享某些特征吗?还是说组成这个团体的人一开始就很相似?
Preview from https://www.jstor.org/stable/2298123
苏萨拉、吴和谭(2011)分析了 YouTube 的网络结构。他们能够通过系统地分离某些因素来区分社会影响和用户的自我选择,从而控制反思问题。他们的主要发现是,对 YouTube 的影响力来自于一个节点的网络中心性,而同性对社会传染起着至关重要的作用。
Bakshy 等人(2011)研究了对 Twitter 的影响力,这种影响力可以被定义为持续播种超越他人的级联的能力。他们发现,拥有许多过去有影响力的追随者的人确实更有可能继续他们的影响力。然而,研究人员指出,在颗粒基础上预测影响是不可靠的。持续影响的效果只对平均值成立,对个体不成立。他们建议营销人员使用一种分散祈祷式的投资组合策略,而不是把所有赌注都押在一匹马上。
Taken from Bakshy et al. (2011): Everyone’s an Influencer — Quantifying Influence on Twitter.
尽管 2018 年有各种坏消息和动荡的股票表现,脸书仍然是目前最大的社交媒体平台之一。用户可以通过双向联系与朋友联系,通过单向联系关注他们喜欢的艺术家。NewsFeed 算法决定了每个用户在浏览应用程序或网站时可以看到哪些内容。你可能会收到你的朋友保罗昨天分享的一个链接,你也想和你的网络分享它。
链接共享行为可以被视为影响力的一个指标。脸书在网络中的影响力显而易见。然而,有许多外部影响来源,如面对面接触或电子邮件交流。通过操纵 2.53 亿脸书用户的新闻源,Bakshy 等人(2012)能够确定社交媒体平台在信息传播过程中的作用。
他们创建了两个组:一个组中的某些信息被从新闻源中过滤出来,并且只能在脸书之外获取(无新闻源条件),另一个组中的信息可以从内部或外部获取(新闻源条件)。
Taken from Bakshy et al. (2012): The Role of Social Networks in Information Diffusion
像这样的实验设置的一大优势是,研究人员可以通过控制与同性相关的混杂因素来解决反射问题。通过比较两组的行为,研究人员发现,暴露于朋友分享行为(喂食条件)的受试者比没有喂食的受试者分享相同信息的可能性高 7.37 倍。因此,我们的朋友在某种程度上影响我们的行为。
此外,Bakshy 等人(2012 年)使用多种互动类型来衡量关系强度,例如,通过脸书信息进行私人交流的频率或通过评论进行公共交流的频率。Granovetter 的假设,即弱关系对新信息的传播更为重要,再次得到了经验上的支持。
为脸书再做一次研究。孙等人(2009)的研究重点是版面的扩散事件。当 Sally 喜欢 Metallica 的粉丝页时,这种粉丝行为可以被广播到她的一些网络中。保罗看到这一幕,立刻想到了圣安格尔的金属小军鼓声。他认为这是一支很酷的乐队,并对金属乐队也给予了好评。结果就是一个巨大的树状扩散网络。下面由此产生的网络,与少数人足以以流行病的方式传播信息的普遍假设形成对比(你好,格拉德威尔!).
Taken from Sun et al. (2009): Gesundheit! Modeling Contagion through Facebook News Feed
孙等发现扩散链一般都很长,但不是单个链式反应事件的结果。相反,它们是由大量用户发起的,这些用户的短链被合并在一起。此外,他们注意到,在控制受欢迎程度后,一个起始节点的最大扩散链长度不能用用户的人口统计或脸书使用特征来预测,包括朋友的数量。在此之后,识别潮流引领者将变得困难。
结论
影响的力量在一个网络中的个体之间并不是平均分配的。它可以被描述为一个社会网络中的连接数量(数量)以及每个纽带的强度(质量)的函数。如果你的联系质量不高,认识很多人可能还不够。
因此,与拥有成千上万追随者的有影响力的人合作本身还不令人信服,不管他们是真是假。微影响者的巨大吸引力在于他们与粉丝的关系质量,这比那些不在乎的广大观众更重要。
但这是另一个时间的话题。
请随时关注我的个人资料,获取关于这个主题的最新消息。你可以在 LinkedIn 或 Twitter 上联系我,如果你想谈谈我在市场营销方面的研究或数据科学的话。
感谢阅读,
乔纳斯·施罗德
PS:如果你想知道更多关于在线社交网络的研究,以及一些影响者是如何伪造的,直到他们成功,一定要看看我的大量研究论文:insta gram 上的影响者欺诈——对世界上最大的参与社区的描述性分析(Jonas Schrö der 的硕士论文)
引用文献
米尔格拉姆,斯坦利(1967),“小世界问题”,《今日心理学》,第 1 卷,№1,61–67 页。
马克·s·格兰诺维特(1973),“弱关系的力量”,《美国社会学杂志》,第 78 卷,第 6 期,1360–1380 页。
Brown,Jacqueline Johnson 和 Peter H. Reingen (1987),“社会关系和口碑推荐行为”,《消费者研究杂志》,第 14 卷,№3,350–362。
Dodds,Peter Sheridan,Roby Muhamad 和 Duncan J. Watts (2003),“全球社会网络中搜索的实验研究”,《科学》, 301,827–829。
查尔斯·f·曼斯基(1993),“内生社会效应的识别:反思问题”,《经济研究评论》,第 60 卷,第 3531–542 页。
苏萨拉、安贾纳、吴正河和谭勇(2011),“社交网络和用户生成内容的扩散:来自 YouTube 的证据”,信息系统研究,文章预告,1–19。
Bakshy、Eytan、Itamar Rosenn、Cameron Marlow 和 Lada Adamic (2012 年),“社交网络在信息传播中的作用”,国际万维网会议委员会(IW3C2) 2012 年会议录,[可用 athttps://arxiv . org/pdf/1201.4145 . pdf],1–10。
Bakshy,Eytan,Jake M. Hofman,Winter A. Mason 和 Duncan J. Watts (2011),“每个人都是影响者:量化对 Twitter 的影响”,第四届 ACM 网络搜索和数据挖掘国际会议(WSDM,2011 年),【可在http://snap . Stanford . edu/class/cs 224 w-readings/bak shy 11 influencers . pdf 获得】,1–10。
孙、埃里克、伊塔马尔·罗森、卡梅隆·a·马洛和托马斯·m·伦托(2009 年),《科学!通过脸书新闻源进行传染建模”,第三届国际 ICWSM 会议记录(2009) ,146–153。
注:本文将是社交网络分析和影响者营销系列的一部分,全部基于我的硕士论文“Instagram 上的影响者欺诈:对世界上最大的参与社区的描述性分析”的研究。相关文章的链接以后会在这里汇总。