TowardsDataScience-博客中文翻译-2022-二十四-

TowardsDataScience 博客中文翻译 2022(二十四)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

使用递归查询分层 API

原文:https://towardsdatascience.com/going-down-the-rabbit-hole-querying-hierarchical-apis-with-recursion-6d48fe40f591

编写从 ICD API 中提取关系的递归函数的指南

Brannon Naito 在 Unsplash 上拍摄的照片

递归是强大的,但我总是被它吓倒。最近,我需要从 API 中提取层次数据,我意识到递归很有意义,所以我不得不面对自己的恐惧。如果你也不喜欢递归,并且希望看到一个实际的例子,那么这篇指南可能会有所帮助。

ICD——国际疾病分类

首先,我将解释 ICD-10 诊断代码以及它们是如何存储在 ICD API(icd.who.int/icdapi)中的。当患者寻求医疗保健服务时,医疗保健提供者会提供 ICD 诊断代码,以便付款人可以了解就诊原因和他们接受治疗的目的。ICD 诊断代码有三个或三个以上的字符,以字母开头,后跟数字。例如,如果提供者诊断患者患有额叶脑癌,他们可以使用代码 C711,即“额叶恶性肿瘤”(尽管他们可以选择使用未指明的代码,如 C719,即“脑恶性肿瘤,未指明”,例如,如果它存在于多个位置)。如果我们想分析脑癌患者,我们可能不关心肿瘤的确切位置,所以我们需要一种方法来分组所有脑癌代码。

在 ICD-10 分级体系中,以 C71 开头的编码都是“脑恶性肿瘤”的编码,C71 编码属于 C69-C72 的更广泛类别,即“眼、脑和中枢神经系统其他部分的恶性肿瘤”。我们可以到 C00-D49 的另一个层次,它代表所有肿瘤的编码。这就是我们想要提取的层次结构。

这种结构很有帮助——因为它允许我们在不同的粒度级别上分析数据。我们可能希望通过广泛的疾病类别进行分析,如癌症、呼吸系统疾病、消化道疾病、感染等。或者,我们可能希望通过分析更具体的疾病,如皮肤癌或志贺氏菌感染,进行更深入的研究。如果我们可以简单地采用 ICD 代码的第一个 n 字符来获得不同的粒度级别,那就太好了,但是正如我们在脑癌例子中看到的,我们有一些以 C6 开头的代码与以 C7 开头的代码分组,并且不是所有的 C6 代码都在同一个组中。事实上,一些疾病组以 C6 开始(C60-C63 代表“男性生殖器官的恶性肿瘤”,C64-C68 代表“泌尿道的恶性肿瘤”,C69-C72 代表“眼、脑和中枢神经系统其他部分的恶性肿瘤”)。

icd10data.com 网站有助于将这种层级形象化。点击页面上的链接,您可以看到不同疾病类别是如何分组的,以及代码是如何随着深入而变得更加具体的。

ICD API

icd.who.int/icdapi 的 ICD API()包含了这种有价值的层次结构信息。通过一些简单的 python 请求,我们可以提取层次结构中每一层包含的信息,并确定下一层是什么代码。首先,让我们做好准备。您需要创建一个帐户,并获得自己的客户 ID 和客户机密。我将凭据存储在我的凭据管理器(Windows)中,并使用密匙环包来访问它们。一旦有了凭证,就可以生成一个访问令牌。令牌的使用时间是有限的,稍后会详细介绍。

现在我们已经设置好了,我们可以编写一些函数来从 API 中提取数据,并将其作为 JSON 返回。每个请求都会返回一个名为“child”的元素,这就是递归的由来。我们将从层次结构的顶层开始,获取顶层 URI 的所有子节点,找到这些子节点的所有子节点,依此类推,直到我们遇到没有子节点的 URI。

这里有一个例子。我们从 https://id.who.int/icd/release/10 的 URI 开始,找到 http://id.who.int/icd/release/10/2019的最新版本 URI。我们将其保存为变量 uri_latest 。从那里,我们可以使用函数 get_contents 来查找最新版本的所有子链接。之后,我们可以对每个孩子重复相同的过程,以捕获 ICD 诊断代码的层次结构。

#Children links (corresponds to links on [https://www.icd10data.com/ICD10CM/Codes](https://www.icd10data.com/ICD10CM/Codes))In: get(uri_latest)
Out:{'@context': 'http://id.who.int/icd/contexts/contextForTopLevel.json',
 '@id': 'http://id.who.int/icd/release/10/2019',
 'title': {'@language': 'en',
  '@value': 'International Statistical Classification of Diseases and Related Health Problems 10th Revision (ICD-10) Version for 2019'},
 'releaseDate': '2020-02-01',
 'child': ['http://id.who.int/icd/release/10/2019/I',
  'http://id.who.int/icd/release/10/2019/II',
  'http://id.who.int/icd/release/10/2019/III',
  'http://id.who.int/icd/release/10/2019/IV',
  'http://id.who.int/icd/release/10/2019/V',
  'http://id.who.int/icd/release/10/2019/VI',
  'http://id.who.int/icd/release/10/2019/VII',
  'http://id.who.int/icd/release/10/2019/VIII',
  'http://id.who.int/icd/release/10/2019/IX',
  'http://id.who.int/icd/release/10/2019/X',
  'http://id.who.int/icd/release/10/2019/XI',
  'http://id.who.int/icd/release/10/2019/XII',
  'http://id.who.int/icd/release/10/2019/XIII',
  'http://id.who.int/icd/release/10/2019/XIV',
  'http://id.who.int/icd/release/10/2019/XV',
  'http://id.who.int/icd/release/10/2019/XVI',
  'http://id.who.int/icd/release/10/2019/XVII',
  'http://id.who.int/icd/release/10/2019/XVIII',
  'http://id.who.int/icd/release/10/2019/XIX',
  'http://id.who.int/icd/release/10/2019/XX',
  'http://id.who.int/icd/release/10/2019/XXI',
  'http://id.who.int/icd/release/10/2019/XXII'],
 'browserUrl': 'http://apps.who.int/classifications/icd10/browse/2019/en'}

API 时间限制

当我开始这个过程的时候,事情看起来很好,运行良好。然而,大约一个小时后,递归过程失败了,我意识到这是因为我的访问令牌已经过期了。这意味着我需要一种方法来跟踪我使用令牌的时间,并在它过期之前更新它。要在递归函数中做到这一点,需要跟踪全局范围内的变量。由于函数一遍又一遍地调用自己,在局部范围内使用变量将是一件痛苦的事情。

下面是更新“get”函数中使用的令牌和头的两个函数。

递归

最后,我们需要一个地方来存储我们查询过的所有信息。同样,我们使用一个全局变量' dfs ',它是我们已经提取并将在最后组合的所有关系的列表。列表中的每个项目将包含父代码和父标题,以及子代码和子标题,从而创建一个树形结构。

我们的递归函数将需要使用 get_contents 函数找到一个 URI 的所有相关信息,将我们想要的存储在我们的全局变量 dfs 中,然后在 URI 的每个子节点上调用自己来继续这个过程。此时,它会在发出下一个请求之前检查令牌和报头是否需要更新。

显示数据框,我们从根节点(没有父节点)开始,找到它下面的所有关系,从“某些感染和寄生虫病”开始。然后,递归从“肠道传染病”开始,遍历“某些感染和寄生虫病”的所有子分类。接下来,从“霍乱”开始,它进入子类。在它收集了所有特定的霍乱诊断代码后,它会继续处理“伤寒和副伤寒”等。

作者创造的形象

在让这个函数在我的机器上运行了大约 4 个小时之后,我能够捕捉到 ICD 码和它们的层次结构之间的所有关系。需要进行一些清理,以便从树结构中将它组织成一个有用的表,但是一旦有了树结构,我就可以通过用层次结构中更高级别的代码替换原始诊断代码来改变分析的粒度。这让我可以更容易地比较类似情况的患者。

我希望这篇指南能启发你在有意义的地方使用递归。你可以在我的 GitHubhttps://GitHub . com/patricknormile/examples/blob/main/ICD API _ recursion _ example . py上找到完整的代码

感谢您的阅读!

从预测模型到生产部署

原文:https://towardsdatascience.com/going-from-a-predictive-model-to-productive-deployment-ec7b4e6280b0

如何确保你的人工智能模型带来商业价值

丹尼尔·利维斯·佩鲁西在 Unsplash 上的照片

除非用于生产用途,否则准确的预测模型没有任何价值。为生产部署准备好预测模型需要什么?虽然有许多技术需求,但我将着重从业务角度来看需要什么。

让我们看一个电信公司客户流失预测的业务场景。为了给我们的故事添加一些行动,让我们假设数据科学家团队开发了一种尖端的机器学习模型,并显示出有希望的准确性。该模型现在用于列出预计会流失的客户,如下所示。

如下所示,这个列表非常适合 Kaggle 式的数据科学竞赛。然而,从商业角度来看,这是灾难性的。

客户 id 和流失预测(图片由作者提供)

以上列表的问题在于它不可操作。企业将不知道如何利用它以及如何使用它来减少客户流失。因此,让我们看看如何使模型结果更具可操作性。

增加概率有助于确定优先级

一个大企业可以有 1000 万到 1 亿客户。如果你取平均 5%的流失率,那么会流失的客户名单将会有数百万的客户。有了这么长的列表,业务用户需要一些方法来区分优先级。

增加概率有助于确定优先级。

添加优先级(按作者排列的图片)

在上面的例子中,需要优先联系客户 6894-LFHLY 和 9767-FFLEM,因为他们很有可能流失。这是一种使模型输出更具可操作性的优雅方式。

因此,在开发过程中,总是喜欢除了预测之外还能给出概率的模型。

与运营数据连接

为了使模型输出更具可操作性,进一步了解预计会流失的客户非常重要。这需要将预测与操作数据联系起来,如下所示。

连接运营数据(图片由作者提供)

现在,业务用户对预计会流失的客户有了更好的了解。这在联系客户时非常有用,可以防止客户流失。

将模型得分与运营数据相结合是部署的重要一步

解释预测和流失原因

企业现在准备联系客户,以防止客户流失。然而,有一样东西不见了,那就是预测解释。当联系客户以防止客户流失时,业务用户需要清楚地知道为什么会出现客户流失。这有助于更好地与客户谈判。

预测解释者(图片由作者提供)

上面的可视化是客户 6894-LFHLY 的预测解释器(使用 SHAP 算法)。向上的柱线是预测客户流失的原因。预测客户流失的最大原因是因为客户的月合同很短,总费用很高,而且一个月的任期很短。

从流失的原因来看,企业可以采取一种策略,例如将客户转化为长期合同,并在月费上提供一些折扣。

预测解释给出了如何对预测结果采取行动的方向

结论

制作准确的模型对于生产部署来说是不够的。为了使模型结果具有可操作性,需要增加概率,与操作数据相联系,以及有一个预测解释。

数据源引用

这篇博客中使用的数据集来自这里提供的电信数据集。https://www.ibm.com/community/terms-of-use/download/允许商业和非商业使用。

**https://community.ibm.com/community/user/businessanalytics/blogs/steven-macko/2019/07/11/telco-customer-churn-1113

用我的推荐链接加入 Medium

https://pranay-dave9.medium.com/membership

订阅每当我发布一个新的故事时,请保持通知。

https://pranay-dave9.medium.com/subscribe

额外资源

网站(全球资讯网的主机站)

你可以访问我的网站进行零编码分析。https://experiencedatascience.com

在网站上,您还可以参加即将举行的人工智能研讨会,体验有趣和创新的数据科学和人工智能。

Youtube 频道

这是我的 YouTube 频道
https://www.youtube.com/c/DataScienceDemonstrated 的链接**

良好的数据公民身份不起作用

原文:https://towardsdatascience.com/good-data-citizenship-doesnt-work-265f13a37fa5

我们可以也应该要求每个人都成为良好的数据公民。但是我们也必须成为优秀的领导者。

安东尼·加兰在 Unsplash 上的照片

合著Benn StancilatModeandMark Groveratstemme

从小学开始,我们都被教育要成为好公民。我们从公民学老师那里了解到,如果我们不投票,不参与地方政治,民主是行不通的;我们从社会领袖那里听到,我们必须大声疾呼,让人们听到我们的声音;民选官员告诉我们,我们不应该问国家能为我们做什么,而应该问我们能为国家做什么。

这是一个强有力的信息。但是不完整。光靠公民无法创造繁荣的社会;当选领导人也必须尽自己的职责。他们必须起草法案,通过法律,协商妥协,并建立公平有效的机构来执行人民的意愿。正如人们不能把民主的责任推给政府,政府也不能把领导的责任推给人民。

数据组织——越来越多地围绕“数据民主化”和“公民分析师”这样的术语来构建他们的目标——需要记住同样的事情。随着数据的重要性和范围的增长,数据团队试图将责任外包给他们的非数据同事,要求他们中的更多人管理、分析和管理组织的分析资产。总的来说,这种努力是有意义的:数据团队太小,无法独自完成这项工作,正如我们的政治进程一样,公民的更多参与有助于建设一个更有活力的社会。

但是我们应该小心不要走得太远。组织“选举”我们成为公司数据的主要管理者,并建立既能让他们有效参与又能满足他们需求的机构。我们可以也应该要求每个人都成为良好的数据公民。但我们也必须成为优秀的领导者,尤其是在与管理和组织数据资产相关的事务上。

从全程服务到自助服务

几十年前,当数据主要用于向高管报告一些业务 KPI 时,数据团队(或者更常见的是 IT 团队)可以独立完成大部分工作。不需要数据公民,就像不需要餐馆里的公民一样:几个人下几份订单,厨房就能很好地处理。

近年来,这一切都改变了。顾客的数量大幅增长,从高管和少数运营领导到公司的每个人。订单的种类也呈爆炸式增长。数据不仅用于 KPI,还用于回答各种主题的复杂问题,从产品和工程到运营、客户支持和执行决策。每个订单的复杂性也增加了。过去存在于几个中央系统中的数据现在分散在数十个(如果不是数百个)第三方 SaaS 应用程序中。根据一些消息来源的说法,如今组织使用的 SaaS 产品是五年前的十倍多[1]。

作为一个数据行业,我们通过建立自助餐来应对这种巨大的需求增长。使用自助工具,人们可以创建自己的分析,顾客可以根据数据团队提供的一些基本成分组装自己的订单。这家新餐馆可以为比以前多得多的人服务,极大地扩展了组织中每个人对数据的访问。

但是这产生了一个新问题:人们如何知道他们可以信任他们看到的数据?把自助餐的比喻延伸一下,人们怎么知道他们在街角的车站找到的食物,那种感觉整晚都没人注意的食物,仍然可以安全食用?

很多时候,事实并非如此。人们会出现在一个会议上讨论一个业务问题,不同的人会带来不匹配的号码。很多时候,数据会减缓决策,而不是加快决策,因为人们花在争论数据是否正确上的时间比花在讨论如何处理数据上的时间要多。通常,数据团队会更新核心数据集或 KPI,旧版本会持续几个月。

诸如此类的事件侵蚀了人们对数据和数据团队的信任。它教导人们不要参与数据民主,而是完全靠自己做决定,通常根本不使用数据。

打造更好的菜单

为了解决这个问题,许多数据团队转向数据文档。这个想法很简单:创建一个菜单,解释哪些数据是可用的,以及它们的含义。虽然这种文档可以采取许多不同的形式——内部维基、第三方产品、聊天机器人、谷歌表单——为了让自助服务体验发挥作用,我们需要某种东西来帮助人们理解他们所服务的原始数据。

不幸的是,任何试图创建和维护数据文档的人都知道,这说起来容易做起来难。组织拥有如此多的数据,以至于通常不可能可靠地记录哪怕是最重要的数据集。由于数据变化如此频繁,文档也经常变得陈旧,导致人们不信任文档,就像他们不信任底层数据一样。

为了解决这些问题,组织有时会雇用全职的数据管理员,他们负责定义数据文档并确保它保持最新。这不仅昂贵,而且很少奏效。数据管理员被分配到他们不是专家的部门记录数据;结果,他们最终向领域专家寻求帮助。组织可以通过雇佣更多的管家来解决这个问题,但是很多组织不能雇佣一个管家,更不用说几个了。

看到这一挑战,许多数据团队依靠良好的公民意识。数据团队的一名成员为其他人创建了一个谷歌文档,以记录所有真实的规范来源以及与之相关的陷阱。文档在 Slack 上发布,几个星期后,人们会努力更新和扩展它。但是好习惯却消失了。数据公民忘记更新它,或者,可以理解,忙于他们的日常工作,没有时间去做。新员工加入公司,从未接受过更新文档的培训。

事实证明,好公民身份也行不通。数据文档是一项艰巨的任务,它太大了,无法由负担过重的数据管理员来维护,而且太普遍了,无法在分散的人群中共享。

在博士之外思考

这些努力失败了,因为从根本上说,文档是错误的解决方案。事实证明,数据并没有向熵靠拢,而是向熵冲刺。

商业变化很快;数据源是不断发展的;对问题的回答几乎和回答一样快就过时了。试图记录这样的系统就像记录新闻一样——这只是人们了解时事的方式。(在这方面已经有过尝试,比如 Vox ,它是作为一个网站推出的,网站上满是新闻“解释者”,起到一种文档的作用。这种模式从未真正坚持下来,Vox 很快成为一个在结构上与其他任何网站没有区别的新闻网站。)

数据团队应该着眼于组织大量不断变化的信息的系统,而不是着眼于解决方案的文档系统。幸运的是,有很多例子。

  • 新闻网站——Vox 试图取代——并最终成为——一个标准的新闻网站。但是如果目标是让人们了解时事,传统的新闻网站做得很好。他们成功是因为他们提供了源源不断的信息。即使你没有阅读每一个故事,firehose 也会让你对当前事件有一个大致的了解,就像 Instagram 和脸书 feeds 让你被动地了解你朋友的最新消息一样。我们能从中学到什么?广播时间很重要。在人们面前获取信息,即使没有一次谈话能解释一切,也能让人们保持消息灵通。
  • 维基百科——维基百科成功地“记录”了大量信息,并对时事做出了非常迅速的反应。然而,它之所以有效是因为它的规模:它是由成千上万的人维护的,这些人因为维基百科的数十亿读者而受到激励。我们能从中学到什么?“公民文件”只在大范围内有效。大约 0.05%的维基百科读者在某个月编辑了一篇文章。即使公司可以让人们以 50 倍的速度更新数据文档,一个 1000 人的公司也只有 25 个人贡献他们的文档。这远远不足以跟上数据变化的步伐。
  • Yelp—Yelp(以及其他几十个类似的网站)依靠餐馆顾客来撰写评论,而不是从专业评论家那里获取评论。因此,评论的更新比其他情况下要频繁得多。我们能从中学到什么?当我们谈论文档时,我们倾向于关注所有者。客户的意见也是有用的,即使它只是将一些东西标记为过时。对于非常了解该领域的“精明”客户来说尤其如此。
  • Quora 和 stack overflow——这些网站专注于回答问题,而不是记录信息。这让人们能够解决特定的需求,为重要的问题提供了一种机制,让它们浮出水面,减少了对实时文档的关注,增加了对即时答案的关注。这也鼓励人们回答问题——记录事情——因为答案的价值更加清晰。我们能从中学到什么?集中回答问题的机制可以更容易地激励人们参与,并确保他们的参与更有针对性。然而,这在答案稳定的环境中效果最好。在快速变化的领域中,时间点答案很快就会过时。
  • 谷歌— 谷歌使用爬虫来索引网络,与之前存在的其他搜索引擎没有什么不同。然而,其真正的创新是 PageRank,它使用一个网站的反向链接数量作为其可信度的代理。随着时间的推移,谷歌建立了一些工具,让网站所有者能够更好地控制从他们的网站上获取哪些索引,以及如何优化他们的排名。对于企业来说,谷歌甚至开始为人们提供直接上传信息的方式。我们能从中学到什么?发现系统可以从自动化开始,并在不同的监管级别上分层,以便人们进行审查、纠正和扩充。
  • 互联网——没有什么变化比互联网更快,然而,我们仍然在驾驭它方面做得很好。这是通过几种方式实现的:书签和搜索。首先,我们有我们经常去的主要网站——像 Reddit、Twitter、纽约时报等等。对于其他一切,我们通过搜索找到它,这是由流行度驱动的。我们从来没有(好吧,美国在线曾经尝试过)试图记录互联网,我们使用目录来浏览互联网。我们能从中学到什么?有时候,完全抛开“组织”,完全依靠搜索,以使用为动力,会更好。

经验教训

这些教训——以及我们从过去的错误中吸取的教训——将很快融入我们组织和管理数据的方法中。我们认为它们会在很多方面得到应用。

多回顾,少记录。

就像谷歌通过自动绘制流行地图来组织世界信息一样,我们也需要对数据做同样的事情。我们需要根据人们已经使用数据的方式,尽可能多地自动记录。目标不应该是创造一个完美的真理来源,而是一个看似真实的草图。

一旦记录下来,我们就应该把它交给数据所有者和领域专家来审查、纠正和扩充。通过这种方式,人们只需要记录属于部落知识的东西——一些东西看起来是一种方式,但实际上意味着不同的东西——而机器通过扫描数据仓库、BI 工具、Slack、JIRA 等的日志和 API 来自动化其余的事情。

让这里变得混乱

鉴于组织目前拥有的数据量,任何审查和记录数据的工作都必须有所侧重。Quora 和 StackOverflow 向我们展示了问题,而不是文档,有助于揭示最重要的问题。

在数据方面,我们应该遵循同样的原则:利用人们提出的问题来寻找数据热点,并将我们的精力集中在这些问题上。这意味着你的数据的一些角落会很乱,一些概念会没有记录。没关系,只要有一种方法可以识别这些区域何时“升温”

不仅仅是业主

通过 Yelp,我们发现精明的消费者往往比餐馆老板更能帮助其他顾客。顾客知道其他顾客关心什么,而且通常也更诚实。

同样,数据消费者知道他们信任什么数据,不信任什么数据。他们是被烧伤过的人,他们遇到了数据的陷阱,并以艰难的方式了解了它们。他们是您的分析师、数据科学家和业务用户。让他们在这个过程中有发言权,不要仅仅依赖数据所有者。

趁热吃吧

最后,我们从过去的数据文档中学到的最重要的事情是,尽管困难重重,但开始是容易的部分。维护最新的文档要困难得多。

解决这个问题的最好方法是在数据生成时记录数据。当更改已经是首要任务时,将其作为添加新事件、表或复制作业的过程的一部分。如果可能的话,把它嵌入到开发过程中,当人们不包括必要的更新时就纠缠他们。这将文档的负担转移到上游,使其成为开发周期的一部分。否则,“修复文档”会被添加到不断增长的后续项目中,而我们实际上永远也不会去做。

我们喜欢宣扬数据对现代组织的重要性,我们拥有的数据越多,它就越有价值。我们会提出相反的观点:组织拥有太多数据。如果没有更好的组织方式,大量的数据将会变得不堪重负。

幸运的是,我们正在取得进展。说到管理数据,我们已经找出了一堆行不通的东西,一些行之有效的东西,并且在相邻空间中有很好的相似之处。通过遵循这些经验教训,最重要的是,通过认识到我们需要良好的公民意识、良好的产品和良好的流程的组合,我们最终可以建立一个为所有人服务并得到所有人信任的数据社会。

参考

[1] Statista,2015 年至 2021 年 全球组织使用的软件即服务(SaaS)应用的平均数量,2022 年 1 月 9 日获取。

[2]2021 年下半年,每月有 8 亿台独特的设备访问英文维基百科。每月约有 40 万人对其进行编辑。维基媒体统计, 唯一设备 ,2022 年 1 月 9 日访问;维基媒体统计, 编辑, ,2022 年 1 月 9 日访问。

优秀的数据科学家写出优秀的代码

原文:https://towardsdatascience.com/good-data-scientists-write-good-code-28352a826d1f

为数据产品开发代码时如何善待自己和同事的建议

照片由奎诺·阿尔Unsplash 上拍摄

数据产品是软件应用程序

作为数据科学家,我们构建数据产品,即使用数据解决现实世界问题的产品。根据手头的问题,数据产品可以采取许多不同的形状和形式,包括静态报告、实时仪表板、交互式 web 应用程序、基于机器学习的 web 服务等。将这些类型的产品联系在一起的是,构建它们需要编写代码,例如用 Python、R、Julia 和/或 SQL 的一种方言编写代码。因此,尽管复杂性不同,但大多数数据产品本质上都是软件应用程序。

给定数据产品背后的代码的复杂性不仅取决于该产品的性质,还取决于其开发阶段。CRISP-DM 是一个众所周知的框架,它描述了数据科学项目不同阶段发生的事情。CRISP-DM 包括六个主要阶段:(I)业务理解,(ii)数据理解,(iii)数据准备,(iv)建模,(v)评估,和(vi)部署。随着项目的进展,对底层代码库的质量和健壮性的要求通常会增加。此外,数据科学项目通常需要业务利益相关者、其他数据科学家、数据工程师、IT 运营专家等各种参与者协调一致的努力。因此,为了使整个过程尽可能顺利和有效,并使相关的业务风险最小化,一个好的数据科学家应该(在许多其他事情中)能够编写好的代码。

但是什么才是“好代码”呢?也许这个问题最简洁的答案可以在下面的插图中找到,它打开了 R. C. Martin 的流行的“干净代码”一书:

这张图片是经 OSNews.com 许可复制的

为了减少数据科学代码中的 WTF s/minute,我们可以遵循几十年来在软件工程领域开发的一些最佳实践。在我作为数据科学家和顾问的工作中,我发现以下最佳实践和原则特别相关和有用:

  • 新团队成员加入项目所需的时间和成本最少;
  • 代码以模块化的方式编写,并进行版本控制和单元测试;
  • 该应用程序是完全可配置的,并且不包含控制其执行的硬编码值;
  • 应用程序在执行环境之间是可移植的;
  • 应用程序是可扩展的,无需改变工具、架构或开发实践;
  • 没有同行评审,任何代码都不会被部署到产品中;
  • 有一个监控基础设施,允许人们跟踪和了解应用程序在生产中的行为。

以下是对数据科学背景下的这些最佳实践的简要评论,以及一些关于如何实施它们的建议。处于职业生涯早期的数据科学家可能会对本文特别感兴趣。然而,我相信经验丰富的专业人士和数据科学经理也可以在这里找到有用的信息。

一次性写出一段完美的代码几乎是不可能的,这没关系

在数据科学项目中清晰地制定需求并不常见。例如,商业利益相关者可能希望使用机器学习模型来预测某个数量,但他们很少能够说出该预测的可接受不确定性。许多其他未知因素可能会进一步阻碍和减缓数据科学项目,例如:

  • 手头的问题能在第一时间用数据解决吗?
  • 哪些数据有助于解决这个问题?
  • 数据科学家能访问这些数据吗?
  • 现有数据质量是否足够好,是否包含足够强的“信号”?
  • 将来建立和维护一个包含所需数据的 feed 需要多少成本?
  • 使用某些类型的数据是否有任何法规限制?

因此,数据科学项目通常需要大量的时间和资源,变得高度迭代(参见上面提到的 CRISP-DM),并且可能完全失败。鉴于数据科学项目的高风险本质,尤其是在项目的早期阶段,从第一天开始就编写生产级代码没有太大意义。相反,更务实地进行代码开发是有用的,类似于软件开发项目中的做法。

我发现一种特别相关的软件开发方法建议按照以下阶段来考虑应用程序代码库的发展:“让它工作,让它正确,让它快速”。在数据科学的环境中,这些阶段可以解释如下:

  • 让它工作:为手头的业务问题开发一个原型解决方案,以便分析该解决方案,从中学习,并决定进一步的开发和部署是否合理。例如,这可能涉及使用默认超参数在有限的数据样本上快速构建预测模型。这个阶段的代码不一定要“漂亮”。
  • 纠正错误:如果原型开发工作显示出有希望的结果,并且决定开发和部署成熟的数据产品,那么进展到这个阶段是合理的。原型代码现在被扔掉了,新的、产品级的代码按照相应的需求和最佳实践编写。
  • 快速完成:在生产环境中运行部署的应用程序一段时间后,可能会到达这个阶段。观察一个数据产品在“野外”的行为通常会发现各种各样的计算效率低下。虽然产品本身可能会交付预期的商业价值,但这种低效率可能会导致不必要的成本(例如,由于云平台上的计算成本),从而降低项目的整体 ROI。当这种情况发生时,人们可能需要回到应用程序代码库并尝试优化它。

现在让我们更深入地研究每一个想法,看看代码质量需求是如何随着项目的发展而变化的。

一.使其发挥作用

图片来自 Bernd 来自 Pixabay

首先建立一个原型

数据科学,就像任何其他科学一样,都是关于“弄清楚事情”,发现对于给定的问题什么可行,什么不可行。这就是为什么在一个项目的开始阶段,先从小处着手并构建原型是很重要的。根据维基百科

原型是为测试概念或过程而构建的产品的早期样品、模型或版本

这个定义的最后一部分特别重要:我们构建原型来尽可能廉价地分析和学习它们,以便我们可以快速决定进一步的开发和部署是否合理 ROI-wise 。如果使用得当,原型可以在开发周期的早期节省大量的时间、金钱和痛苦。

原型在数据科学项目中的实际形式取决于所解决的问题。示例包括但不限于:

  • 展示可用数据价值的探索性分析;
  • quick-n-dirty 预测模型,其性能指标有助于了解手头的问题是否可以用数据来解决;
  • 在本地静态数据集上运行的 web 应用程序,用于收集早期最终用户反馈。

原型代码是一次性代码

原型解决方案的代码需要被视为一次性代码。作为领导项目的数据科学家或项目经理,您必须向您的利益相关者明确说明这一点。引用我最喜欢的一本书,《实用主义程序员》(Hunt&Hunt 2019),

“我们很容易被演示原型的表面完整性所误导,如果您没有设定正确的期望,项目发起人或管理层可能会坚持部署原型(或其子代)。提醒他们,你可以用轻木和胶带制作一个很棒的新车原型,但你不会试图在交通高峰期驾驶它!”

数据产品的原型实际上不需要写成代码。为了快速前进,可以(有时甚至应该)使用低代码或无代码数据科学工具构建原型。然而,当一个原型写成代码时,有几个应该记住的注意事项。

将原型构建为代码时,可以做什么

由于原型代码是一次性的,它:

  • 不必“漂亮”或优化计算速度,因为开发速度在这个阶段更重要;
  • 不必记录到与生产级代码相同的级别(但是,应该有足够的注释和/或基于 Markdown 的注释来理解代码的作用并确保其可再现性);
  • 不一定要受版本控制(尽管在任何项目开始时设置版本控制总是一个好主意);
  • 有硬编码的值也可以(但是不是* 敏感的,比如密码,API 密匙等。);*
  • 可以编写并存储在 Jupyter 笔记本或类似介质(例如 R Markdown 笔记本)中,而不是组织到函数库和/或生产就绪脚本集合中。

当构建一个代码原型时,可以做什么

尽管原型代码是一次性的,但项目仍有可能进入下一阶段,即开发一个成熟的数据产品。因此,人们应该尽最大努力编写尽可能类似于产品级代码的原型代码。这可以大大加快后续的开发过程。最起码,以下是在构建代码原型时可以做的事情(参见下面的进一步讨论):

  • 对变量和函数使用隐晦或缩写的名称;
  • 混合代码风格(例如,在 Python 或 R 等语言中随机使用camelCasesnake_case来命名变量和函数,或者在 SQL 中使用大写和小写的命令名);
  • 根本不在代码中使用注释;
  • 具有敏感值(密码、API 密钥等。)在代码中公开;
  • 不要将笔记本或脚本与原型代码一起存储,以备将来参考。

二。做正确的事

图片来自 PixabayEmslichter

如果原型阶段显示出积极的结果,项目可以继续开发生产就绪的解决方案。将数据产品提供给人类用户或其他系统的过程称为部署。数据产品的部署通常会带来大量的硬性要求,包括但不限于:

  • 特定于项目的 SLA(例如,服务于模型预测的 API 的足够低的响应时间,web 应用程序的高可用性和并发性,等等。);
  • 以完全自动化和可扩展的方式部署和运行应用程序的基础设施(devo PS/m lops);
  • 当应用程序需要时,提供高质量输入数据的基础设施;
  • 监控运营(如 CPU 负载)和产品相关指标(如预测准确性)的基础设施;
  • 对业务关键型应用程序的持续运营支持等。

数据工程、MLOps 和 DevOps 团队将涵盖其中的许多需求。此外,随着项目的进展,这些工程团队扮演的角色变得越来越重要。然而,数据科学家也必须“把事情做对”。让我们看看这对代码质量意味着什么。

使用描述性变量名称

你能猜出下面这段代码中的xyz是什么意思吗?

z = x / y^2

如果不知道这段代码适用的上下文,基本上不可能说出这三个变量分别代表什么。但是,如果我们将这一行代码重写为:

body_mass_index = body_mass / body_height^2

现在代码做了什么就很清楚了——它通过将体重除以身高的平方来计算体重指数。此外,这段代码完全是 自文档化的——不需要提供任何关于它计算什么的额外注释。

认识到生产级代码不是为我们自己写的,而是主要为其他人写的,这一点非常重要。其他人在某个时候会审查它,为它做出贡献,或者维护它向前发展。对变量、函数和其他对象使用描述性名称* 将有助于显著减少理解代码功能所需的认知工作 ,并将使代码更易于维护。*

使用一致的编码风格

如果代码是根据标准格式化的,那么阅读和理解一段代码所需的认知努力可以进一步减少。所有主要的编程语言都有他们官方的风格指南* 。一个开发团队选择哪种风格并不重要,因为最终都是关于一致性。然而,如果团队选择一种风格并坚持使用它,这真的很有帮助,然后强制使用所采用的风格成为每个团队成员的集体责任。数据科学语言常用的代码风格示例包括 PEP8 (Python)、 tidyverse (R)以及 Simon Holywell (SQL)的 SQL 风格指南*

为了编写风格一致的代码,而不必考虑所选风格的规则,请使用一个 集成开发环境 (IDE),如 VSCodePyCharmRStudio 。流行的 Jupyter 笔记本可以方便地进行原型开发,但是,它们意味着用于编写生产级代码,因为它们缺少专业 IDE 提供的大多数功能(例如,代码高亮显示和自动格式化、实时类型检查、导航到函数和类定义、依赖管理、与版本控制系统的集成等)。).从 Jupyter 笔记本上执行的代码也容易出现许多安全问题和各种不可预测的行为。

如果出于某种原因,你最喜欢的 IDE 不能根据给定的风格自动格式化代码,那么使用一个专用的库来做这件事,比如 Python 的[pylint](https://pypi.org/project/pylint/)[flake8](https://pypi.org/project/flake8/),R 的[lintr](https://cran.r-project.org/web/packages/lintr/index.html)[styler](https://cran.r-project.org/web/packages/styler/index.html),SQL 的[sqlfluff](https://www.sqlfluff.com/)

编写模块化代码

模块化代码是被分解成小的独立部分(例如函数)的代码,每个部分做一件事并且只做一件事。以这种方式组织代码使得维护、调试、测试和与他人共享变得更加容易,最终有助于更快地编写新程序。

设计和编写函数时,请遵循以下最佳实践:

  • **保持简短。如果您发现您的函数包含几十行代码,请考虑进一步拆分这些代码。
  • **使代码易于阅读和理解。除了使用描述性名称之外,还可以通过避免在项目中使用高度专业化的编程语言结构来实现这一点(例如,复杂的列表理解、过长的方法链或 Python 中的修饰符),除非它们能显著提高代码速度。
  • **尽量减少函数参数的数量。这不是一个硬性规定,也有例外,但是如果你写的函数有 3-5 个以上的参数,它可能做了太多的事情,所以考虑进一步拆分它的代码。

互联网上充满了如何模块化 Python 代码的例子。对于 R 来说,有一本优秀且免费的书“ R 包”。许多这类对数据科学家有用的建议也可以在 Laszlo Sragner博客中找到。

不要对敏感信息进行硬编码

为了安全起见,产品代码必须永不* 以硬编码常量的形式暴露任何敏感信息。敏感信息的示例包括数据库的资源句柄、用户密码、第三方服务的凭证(例如,云服务或社交媒体平台)等。检验您的代码是否正确地排除了这些变量的一个很好的试金石是,它是否可以在任何时候开放源代码而不损害任何凭证。十二因素应用方法建议将敏感信息存储在 环境变量 中。处理这些变量的一种方便而安全的方法是将它们作为键值对存储在一个特殊的[.env](https://dev.to/jakewitcher/using-env-files-for-environment-variables-in-python-applications-55a1) 文件中,该文件永远不会提交给应用程序的远程代码库。用于读取这些文件及其内容的库在 PythonR 中都存在。*

在清单文件中显式声明所有依赖项

常见的数据产品,其代码库依赖于数十个专门的库。代码可能在开发人员的本地机器上运行良好,所有这些依赖项都已安装并正常运行。然而,如果代码依赖管理不当,将应用程序转移到生产环境中经常会出问题。为了避免这样的问题,必须通过 依赖关系声明清单 完整准确地声明所有的依赖关系。根据语言的不同,这个清单采用不同的形式,例如 Python 应用程序中的[requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files)文件或 R 包中的[DESCRIPTION](https://r-pkgs.org/Metadata.html)文件。

此外,建议在应用程序执行期间使用依赖隔离工具,以避免来自主机系统的干扰。Python 中这类工具的常用例子有[venv](https://docs.python.org/3/library/venv.html)[virtualenv](https://virtualenv.pypa.io/en/latest/)[conda](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html)环境。类似的工具[renv](https://rstudio.github.io/renv/index.html)也存在于 r 中。

使用单一的、版本控制的代码库

用于生产的数据产品的代码必须是版本控制的* (VC) 和存储在其他项目成员可访问的远程存储库中。Git 可能是最常用的 VC 系统,如今开发生产就绪数据产品的数据科学家至少应该熟悉它的基本原理。这些基础知识,以及更高级的技术,可以从许多资源中学习,比如" Pro Git "一书," Happy Git 和 GitHub for the UseR "一书,或者"哦,妈的,Git!?!网站。远程代码库管理最常用的平台有 GitHubBitbucketGitLab 。*

风险投资很重要,原因有很多,包括:

  • 它支持项目成员之间的协作;
  • 当出现问题时,它允许回滚到应用程序的前一个工作版本;
  • 它支持自动化的持续集成和部署
  • 它创造了完全的透明度,这对于受监管行业的审计尤为重要。

给定应用程序的代码库将被存储在一个单独的库中,不同的应用程序不应该共享相同的代码。如果您发现自己在不同的应用程序或项目中重复使用相同的代码,那么是时候将这些可重复使用的代码分解到一个单独的库* 中,拥有自己的代码库。*

使用配置文件存储不敏感的应用程序参数

根据十二因素 App 方法论,

“一个应用的配置是在部署(试运行、生产、开发者环境等)之间可能变化的一切。)."

这包括各种证书、资源 URIs、密码,以及数据科学特定的变量,如模型超参数、用于估算缺失观测值的值、输入和输出数据集的名称等。

应用程序的配置允许根据环境使用不同的设置运行相同的应用程序。作者图片

几乎可以肯定,面向生产的数据产品将需要一个配置。为什么会这样的一个例子是,在开发环境中运行应用程序不需要像在生产环境中那样多的计算能力。与其将相应的计算资源值(例如 AWS EC2 实例参数)硬编码到应用程序的主代码中,不如将这些值视为配置参数更有意义。

配置参数可以以多种不同的方式存储在。十二因素 App 方法论建议将它们存储在环境变量中。然而,一些应用程序可能有太多的参数以环境变量的形式需要跟踪。在这种情况下,更明智的做法是将不敏感的参数放在专用的版本控制的配置文件中,并使用环境变量仅存储敏感参数。

配置文件最常见的格式是 JSON 和 YAML。YAML 文件是人类可读的,因此通常更可取。YAML 配置文件在 Python(例如,使用[anyconfig](https://github.com/ssato/python-anyconfig)[pyyaml](https://pyyaml.org/wiki/PyYAML)库)和 R(例如,使用[yaml](https://github.com/vubiostat/r-yaml)[config](https://github.com/rstudio/config)包)中都可以很容易地阅读和解析。

为您的应用程序配备日志记录机制

日志 是从应用程序的所有活动进程和 后台服务 的输出流中收集的时序事件流。这些事件通常被写入服务器磁盘上的文本文件中,每行一个事件。只要应用程序在运行,它们就会不断生成。日志的目的是提供对正在运行的应用程序的行为的可见性。因此,日志对于检测故障和错误、发出警报、计算各种任务所花费的时间等非常有用。与其他软件应用程序一样,强烈建议数据科学家将日志记录机制注入到将在生产中部署的数据产品中。有一些易于使用的库可以做到这一点(例如 Python 中的[logging](https://docs.python.org/3/howto/logging.html)和 R 中的[log4r](https://github.com/johnmyleswhite/log4r))。

需要注意的是,基于机器学习的应用由于各自算法的的非确定性,有额外的监控需求。这种附加度量的例子包括输入和输出数据的质量、数据漂移、预测的准确性以及其他应用特定的量的指示符。这反过来要求项目团队花费额外的时间和精力来构建(通常是复杂的)基础设施,以操作和支持部署的模型。不幸的是,目前还没有构建这种基础设施的标准方法——项目团队将不得不选择对其特定数据产品至关重要的内容,并决定实现各自监控机制的最佳方式。在某些情况下,人们也可以选择加入商业监控解决方案,如由 AWS SageMaker微软 Azure ML提供的解决方案。**

测试代码的正确性

在没有确认代码做了它应该做的事情之前,任何代码都不应该投入生产。确认这一点的最好方法是编写一组特定于用例的测试,然后可以在关键时间点自动运行(例如,在每个拉请求)。这种测试通常被称为“ 单元测试 ”,其中“单元是指用与生产代码相同的语言编写的低级测试用例,直接访问其对象和成员”(Hunt&Hunt 2019)。单元测试通常是为单个函数编写的,但也可以覆盖类和更高级别的模块。****

有两种主要的方法来编写自动化测试。其中之一是首先编写一个函数或其他功能,然后编写对它的测试。另一种方法被称为 测试驱动开发 ,意味着首先根据功能单元的预期行为编写测试,然后才编写单元本身的代码。这些方法各有利弊,哪种“更好”有点像哲学讨论。实际上,只要团队坚持一致的工作方式,使用哪种方法并不重要。

所有主要的编程语言都有专门的库来创建自动化代码测试。例子包括 Python 的[unittest](https://docs.python.org/3/library/unittest.html)[pytest](https://docs.pytest.org/en/7.0.x/)以及 r 的[testthat](https://testthat.r-lib.org/)

单元测试中的一个重要概念是 代码覆盖率**——被自动化测试覆盖的代码的百分比。这个度量不是 必须等于 100%(此外,在实践中通常很难达到高代码覆盖率,尤其是在大型项目中)。这方面的一些一般性建议如下:****

  • 当您想在print语句中输入一些东西时,为每种情况编写一个测试,看看代码是否如预期的那样工作;
  • 避免测试你有信心可以工作的简单代码;
  • 当你发现一个 bug 时,总是要写一个测试。

可以使用各种工具自动计算代码覆盖率,例如 Python 中的[coverage](https://coverage.readthedocs.io/)库或 r 中的[covr](https://covr.r-lib.org/),也有专门的商业平台可以计算代码覆盖率,随着时间的推移跟踪每个项目,并可视化结果。一个很好的例子是 Codecov

最起码,单元测试应该在开发人员的机器上本地运行,并在项目的存储库中提供,以便其他项目成员可以重新运行它们。然而,如今“正确的方法”是在一个专用的自动化服务器上(例如 Jenkins )或者使用其他持续集成工具(例如 GitHub ActionsGitLab CICircleCI 等)完全自动地运行测试。).

确保至少有一个人同行评审你的代码

一段代码可能没有错误,格式也很整洁,但是几乎总是有某些方面可以进一步改进。例如,代码作者可以使用某些语言结构,使其他人很难阅读该代码并理解其功能(例如,长方法链、复杂的列表理解等)。).在许多情况下,为了可读性,简化这些结构是有意义的。发现代码中可能需要改进的部分需要“一双新鲜的眼睛”,同行评审员可以在这方面提供帮助。评审者通常是团队中熟悉项目或直接参与项目的人。

当对代码库进行可能会显著影响最终用户的更改时,同行评审也很重要。

总的来说,同行评审的目的是简化代码,在其执行速度方面做出明显的改进,以及识别功能错误(即,发现代码执行良好但实际上没有做它应该做的事情的情况)。

组织代码审查并自动跟踪其进度的最佳方式是通过使用远程存储库管理平台的相应功能,在拉式请求时分配一个审查者。各大 VC 平台都提供这样的功能。

虔诚地记录事物

生产级代码必须记录在案。没有文档,将很难长期维护代码,有效地分发代码,并快速顺利地接纳新的团队成员。以下建议将有助于创建一个记录良好的代码库:**

  • 当编写类、方法或纯函数时,如果使用其他语言,请使用 Python 的doc strings或类似的特定于语言的机制。使用这些标准机制非常有用,因为:(I)它们自动生成帮助文件,人们可以从控制台调用这些文件来了解给定的类或函数正在做什么以及它期望什么参数;(ii)它们使得使用特殊的库(例如,Python 的[sphinx](https://www.sphinx-doc.org/en/master/)[pydoc](https://docs.python.org/3/library/pydoc.html)[pdoc](https://pdoc3.github.io/pdoc/)[roxygen2](https://github.com/r-lib/roxygen2)与 R 的[pkgdown](https://pkgdown.r-lib.org/)结合)成为可能,以便生成可在网络上使用的文档(即,以 HTML 文件的形式),这些文档可以容易地与组织内的其他人或公众共享。****
  • 编写脚本时,(I)在顶部 提供注释,并简要说明脚本的用途;(ii)在可能难以理解的地方提供附加注释**
  • 在项目的远程存储库中,提供一个自述文件 ,它解释了关于该存储库的所有相关细节(包括其结构的描述、其维护者的姓名、安装说明,以及,如果适用的话,整个项目的外部支持文档的链接)。

三。让它更快

来自 PixabayEmslichter 的图像

部署的应用程序可能会暴露各种计算效率低下和瓶颈。不过,在匆忙进入 代码重构 之前,回忆一下下面的 优化规则 还是有帮助的:

  1. 优化的第一条规则:不要
  2. 优化的第二条规则:暂时不要
  3. 优化前的配置文件

换句话说,在投入宝贵的时间试图解决问题之前,确保问题是真实的总是一个好主意。这是通过“剖析”来完成的(按照上面的规则 3),在数据科学项目中,这通常意味着两件事:

  1. 测量感兴趣的代码的性能;
  2. 在整个项目的投资回报率及其产生的商业价值的背景下考虑预期的优化工作。

仅仅因为一段代码理论上可以被加速并不意味着它应该被加速。性能增益可能太小,不足以保证任何额外的工作。即使预期的性能增益可能是显著的,项目团队也必须评估从经济的角度来看,所提议的变更是否合理。只有当整个项目的预期投资回报率为正数且足够大时,提议的优化工作才有意义。因此,最终决定将由所有相关的项目成员做出——不再仅仅由数据科学家来断定优化工作是合理的。

结论

数据产品本质上是不同复杂性的软件应用程序。然而,开发此类应用程序的数据科学家通常没有受过软件开发方面的正式培训。幸运的是,掌握软件开发的核心原则并不困难。本文简要概述了数据科学背景下的这些原则,希望能够帮助数据科学家为他们的项目编写更高质量的代码。

您可能还喜欢:

***** https://medium.com/curious/twelve-books-that-made-me-a-better-data-scientist-842d115ef52a *****

用 Python 告别枯燥的 PLAXIS 输出

原文:https://towardsdatascience.com/goodbye-boring-plaxis-output-with-python-fc5c8b26cdb2

PLAXIS 自动化系列

逐步走向自动化的指南

米卡·鲍梅斯特在 Unsplash 上的照片

如果您像我一样经常使用 PLAXIS,您一定会问这样一个问题:我究竟为什么需要不断重复这个复制和粘贴操作来提取结果?

毫无疑问,PLAXIS 是一个强大的有限元软件。作为岩土工程师,我们希望专注于分析,在后处理上花费更少的时间。由于开源社区开发的模块,Python 为自动化输出提取和可视化提供了最广泛的可能性。一些常见模块包括:

  • 熊猫
  • Xlsxwriter
  • Matplotlib
  • 海生的

本教程的最终目标是向您展示如何使用 Python 脚本从 PLAXIS 2D 的结构元素中提取输出。这可以通过以下四个步骤来完成。

  1. 使用 IDE 打开 PLAXIS 输出
  2. 将外部模块安装到 PLAXIS 环境中
  3. 从 PLAXIS 提取孔板结果
  4. 导出为 excel 电子表格

本教程要求读者已经安装了 VS 代码和 PLAXIS 环境。如果您不熟悉这个页面,请按照下面文章中的说明进行操作。我们开始吧!

https://medium.com/@philip.studio11/start-using-python-to-automate-plaxis-35a5297321e7

PLAXIS 示例模型

我用的是宾利官方网站发布的 PLAXIS 2D 车型,如下图所示。

在链接中,下载来自 V22.01 的命令日志文件。据作者所知,Python 命令从 V21 到 V22 有了显著的变化。因此,请确保安装了 PLAXIS V22 或更高版本(V22.01 和 V22.02),以确保本教程中的 Python 脚本能够正常工作。

https://communities.bentley.com/products/geotech-analysis/w/wiki/45557/plaxis-2d-tutorial-03-submerged-construction-of-an-excavation

作者截图

使用“运行命令…”运行命令后,您应该能够看到以下几何图形。

作者截图自 PLAXIS

本例模拟了由地下连续墙(板单元)组成的开挖结构。我们的目标是提取板元素的结果。

计算模型,我们准备使用 Python 提取结果。

步骤 1:使用 IDE 打开 PLAXIS 输出

与第一个教程不同,这次我们将打开一个刚刚下载的 PLAXIS 文件,因此启动服务器的代码需要稍微修改一下。您需要将计算出的模型保存在首选的工作目录中。

我的 PLAXIS 文件的位置:

c:\ Users \ phtsang \ Desktop \ Current _ Projects \ LinkedIn \ Blog _ 2 \ discovery

我将首先创建一个名为“open_output.py”的空 python 脚本。

之后,我们将下面的代码写入 python 文件。该代码与第一个教程中的代码非常相似,但这次我们将打开一个现有的 PLAXIS 文件。为此,我们进行了以下三项更改:

  1. 由于这次我们需要打开一个 PLAXIS 文件,因此需要指定文件的工作目录,该目录存储为“FILE_PATH”。
  2. 然后,我们使用 PLAXIS 命令“s_i.open(FILE_PATH)”打开文件。
  3. 为了打开 PLAXIS 输出,我们编写“g_i.view(g_i.Phases[1])”,这允许我们查看 Phase_1 的计算结果。
from plxscrpting.easy import *
import subprocess, time
import os

###############################################
PLAXIS_PATH = r'C:\Program Files\Bentley\Geotechnical\PLAXIS 2D CONNECT Edition V22\\Plaxis2DXInput.exe'  # Specify PLAXIS path on server.
FILE_PATH = r'C:\Users\phtsang\Desktop\Current_Projects\LinkedIn\Blog_2\\Excavation'  # Specify PLAXIS file location and name
PORT_i = 10000  # Define a port number.
PORT_o = 10001
PASSWORD = 'SxDBR<TYKRAX834~'  # Define a password.

subprocess.Popen([PLAXIS_PATH, f'--AppServerPassword={PASSWORD}', f'--AppServerPort={PORT_i}'], shell=False)  # Start the PLAXIS remote scripting service.
time.sleep(5)  # Wait for PLAXIS to boot before sending commands to the scripting service.

# Start the scripting server.
# global g_i, s_i
s_i, g_i = new_server('localhost', PORT_i, password=PASSWORD)
s_o, g_o = new_server('localhost', PORT_o, password=PASSWORD)

s_i.open(FILE_PATH)

g_i.gotostages()
g_i.view(g_i.Phases[1])

作者截图自 VS 代码

为了测试上面的代码是否正常工作,我们将在终端中运行“open_output.py ”,如下所示。输入“python open_output.py ”,然后单击输入。

作者截图自 VS 代码

PLAXIS 2D 输入和输出应用程序应自动打开。从输出应用程序中,您应该看到“服务器在端口 10001 上活动”。

作者截图自 PLAXIS

现在我们已经连接了 PLAXIS API,我们准备进入下一步。

步骤 2:将外部模块安装到 PLAXIS 环境中

当使用 PLAXIS 脚本环境时,通常使用 Python 模块来扩展 Python 脚本的功能。因为我们的目标是从 PLAXIS 提取结果并导出到 excel 电子表格,所以我们需要两个外部模块:

  • 熊猫
  • Xlsxwriter

这些模块可以通过 PLAXIS 命令提示符窗口安装,如下所示。在继续之前,确保您已经在 PLAXIS 输入打开的情况下完成了步骤 1。

进入菜单选项专家> Python >命令提示符。这将打开 Windows 命令提示符,并将 PLAXIS 设置为当前环境。

作者截图自 PLAXIS

将目录切换到 PLAXIS Python 分发文件夹。这可以通过以下命令完成:

pushd C:\ProgramData\Bentley\Geotechnical\PLAXIS Python Distribution V2\python\Lib\site-packages

作者截图自 PLAXIS

在命令提示符下,您现在可以使用下面示例中显示的命令安装任何新的 Python 模块。

例如,如果你想安装熊猫模块:

python -m pip install pandas

作者截图自 PLAXIS

另外,安装 xlsxwriter 模块:

python -m pip install xlsxwriter

现在我们已经安装了所有需要的模块。然后,我们可以使用 Python 脚本从 PLAXIS 中提取结果。

步骤 3:从 PLAXIS 中提取平板结果

我们的主要目标步骤 3 是在最后阶段(第三挖掘阶段[阶段 5])提取板单元(地下连续墙)的四种结果类型。我们将提取的结果类型有:

  • y 坐标
  • 剪(羊毛)
  • 弯矩
  • 轴向力

在第 4 步中,我们将把结果导出到 excel 电子表格中,表格中的列如下所示。

作者截图自 excel

首先,我们创建一个空的 python 文件,并将其命名为“output_plate.py”。

导入模块和战略服务器

我们需要确保 API 已连接,并导入我们之前安装的模块。

from plxscripting.easy import *
import subprocess, time
import math
import pandas as pd
import os
import xlsxwriter

###############################################
PORT_i = 10000  # Define a port number.
PORT_o = 10001
PASSWORD = 'SxDBR<TYKRAX834~'  # Define a password.

# Start the scripting server.
s_i, g_i = new_server('localhost', PORT_i, password=PASSWORD)
s_o, g_o = new_server('localhost', PORT_o, password=PASSWORD)

定义文件名

因为我们需要将结果导出到 excel,所以我们需要指定导出文件的位置及其名称。

文件位置:确保工作目录后有双斜杠(\)

文件名:可以是您想要的任何名称

EXCEL_PATH=r'C:\Users\phtsang\Desktop\PLAXIS_V22\Script\\'
EXCEL_NAME='plate_output.xlsx'

FILENAME=EXCEL_PATH+EXCEL_NAME

输入定义

之后,我们将输入我们想要提取的结构元素和相应的相位。在这种情况下:“板块 _1”和“第三挖掘阶段[阶段 _5]”。

下面的代码是查找模型中现有的板元素和阶段,并将它们存储为列表。

plate_input=['Plate_1'] # Input by user
phase_input=['Third excavation stage [Phase_5]'] # Input by user

###############################################
#Exisiting model element:

plate=[plt for plt in g_o.Plates[:]] # Loop through the plate object in existing model
phase=[p for p in g_o.Phases[:]] # Loop through all available phases

这里有两个重要的概念:

For 循环:查找 PLAXIS 中现有元素的动作需要 For 循环。这是编程中非常常见的命令。例如在“板块”中,我们有:

for plt in g_o.Plates[:]

这一行意味着我们正在遍历“g_o.Plates[:]”中的所有 plate 元素(这是 PLAXIS 存储对象的方式),并将其命名为“plt”。

列表:正如在第一个教程中提到的,在一个用方括号[ ]表示的列表中存储值是很常见的。与第一个教程相比,语法略有变化,因为它被简化了。

这一行:

plate=[plt for plt in g_o.Plates[:]]

可以扩展为:

plate=[]

for plt in g_o.Plates[:]

   plate.append(plt) 

两个代码会给出相同的结果,但是第一个代码更简洁,这是 Python 中常用的。

到目前为止,您的脚本应该是这样的:

作者截图自 VS 代码

结果提取

经过上述预处理后,我们可以开始提取车牌结果。为此,我们将定义一个函数来提取结果,调用的是“get_plate()”。这里有几个要点:

y 坐标=结果类型。盘子。Y

剪切=结果类型。板材. Q2D

弯矩=结果类型。Plate.M2D

轴向力=结果类型。Plate.Nx2D

  • 接下来的几行将创建目标电子表格中指定的列名。
  • 然后结果被存储为“结果”。这里我介绍一种新的数据类型,在 Python 中称为字典,用花括号{ }表示。当您想要创建一个表时,Dictionary 特别有用,它包含一个键-值对。例如:

“y”是字典的

plateY 是字典的。值的数组可以存储到指定的键中。

  • 一旦创建了字典,下一行将把字典转换成数据帧。Dataframe 是我们在 Python 中最常用的数据结构之一。可以解释为 excel 中的表格。这是通过运行命令:" pd。数据框架(结果)”
  • 我还使用 Y 坐标以降序对结果进行排序

确保缩进是正确的,如下图所示。

def get_plate(plate_o,phase_o):

    plateY=g_o.getresults(plate_o,phase_o,g_o.ResultTypes.Plate.Y, "node")
    plateQ=g_o.getresults(plate_o,phase_o,g_o.ResultTypes.Plate.Q2D, "node")
    plateM=g_o.getresults(plate_o,phase_o,g_o.ResultTypes.Plate.M2D, "node")
    plateAxial=g_o.getresults(plate_o,phase_o,g_o.ResultTypes.Plate.Nx2D, "node")    

    phasename=str(phase_o.Identification).split('[')[0]
    col1='Shear [kN]'+'_'+phasename
    col2='Bending Moment [kNm/m]'+'_'+phasename
    col3='Axial Force [kN]'+'_'+phasename

    results = {'Y': plateY, col1: plateQ,col2: plateM,col3: plateAxial}

    plateresults=pd.DataFrame(results)
    plateresults = plateresults.sort_values(by=['Y'],ascending=False)

    return plateresults

作者截图自 VS 代码

步骤 4:导出为 Excel 电子表格

最后,我们将把创建的数据框架导出到 excel。

我们创建一个函数,叫它“export_excel()”。

  • writer 是使用我们安装的 xlsxwriter 模块导出 excel
  • 名称& sheet_name 是我创建格式为“Plate_1_Phase 5”的工作表名称的位置。
  • 然后,我使用我们在前面创建的函数“get_plate()”来生成数据帧并存储为“结果”。它应该是一个数据帧,然后可以使用 pandas 命令“results.to_excel()”导出到 excel。
def export_excel(plate_input,phase_input,filename):
    writer = pd.ExcelWriter(filename, engine='xlsxwriter')

    name=str(phase[5].Identification).split(' [')[1]
    name=name.split(']')[0]
    sheet_name = "%s_%s" % (plate[0].Name, name)
    results = get_plate(plate[0], phase[5])
    results.to_excel(writer,sheet_name=sheet_name,index=False)
    writer.save()

export_excel(plate_input,phase_input,FILENAME)

作者截图自 VS 代码

使用以下命令运行脚本。

(PLAXIS) C:\Users\phtsang\Desktop\PLAXIS_V22\Script>python output_plate.py

您将看到我们寻找的结果已经自动提取出来,如命令窗口所示。

作者截图自 PLAXIS

现在,如果您在之前指定的位置打开 excel 电子表格,您可以看到我们已经提取了所需的 Y 坐标、剪力、弯矩和轴向力。

作者截图自 excel

干得好!您刚刚使用 Python 脚本从 PLAXIS 中提取了结果。

结论

这就是关于使用 Python 提取 PLAXIS 输出的第二个教程的全部内容。现在,您应该能够从 PLAXIS 中提取单个结构元素的输出。在以后的教程中,我将展示如何提取多个结构元素和不同结构类型(如界面和嵌入梁)的结果。

如果你喜欢阅读这类内容,请随时关注我的页面。我将继续发布这一系列关于用 Python 自动化 PLAXIS 的教程。除此之外,我还热衷于分享关于如何使用 Python 来自动化工程中的工作流的知识。

避免使用“pip 冻结”,而是使用“pipreqs”

原文:https://towardsdatascience.com/goodbye-pip-freeze-welcome-pipreqs-258d2e7a5a62

您的项目依赖关系很重要—有效地管理它们

图像由安赫塞娜蒙Unsplash 上拍摄

动机

包管理是软件开发工作流的最佳实践之一,因为它促进了软件交付的自动化。

如今,大多数数据科学家和机器学习工程师已经在他们的管道自动化中采用了这种最佳实践。即使这个过程被认为是一个好的实践,大多数从业者采用的方法可能并不总是有效的:使用[pip freeze](https://pip.pypa.io/en/stable/cli/pip_freeze/).

在这篇概念博客中,你会明白有一个比使用pip freeze.更好的选择

这就是为什么你不应该使用画中画冻结

假设您正在处理一个需要 5 个依赖项的项目:dep1dep2dep3dep4dep5。大多数人在生成依赖文件时的反应是使用下面这个神奇的命令:

pip freeze > requirements.txt

但是这怎么会是一个问题呢?

大多数库的安装需要其他自动安装的库。下面是一个插图。

# Install the **transformers** library
pip install transformers

transformers库的安装会生成以下消息:

Successfully installed huggingface-hub-0.10.1 tokenizers-0.13.1 transformers-4.23.1

这意味着这两个额外的库huggingface-hub-0.10.1 tokenizers-0.13.1已经和 transformer 库一起安装了,并且这两个库将自动包含在 requirement.txt 文件中。

pip 冻结命令的图示(图片由作者提供)

但我还是不觉得有什么问题!不要担心,我们会成功的…

现在,想象一下变形金刚库被升级并需要不同的库**new_lib-1.2.3****another_new_lib-0.2.1**。这意味着先前的依赖关系huggingface-hub-0.10.1 tokenizers-0.13.1不再相关,对吗?至少对❌.项目来说是这样

问题来了👇🏽

生成 requirements.txt 文件的新版本除了包含新的依赖项之外,还将包含旧的依赖项;如果您只想保留相关的依赖项,您将不得不手动删除旧的依赖项。然后想象一下处理一个需要 20、30 或 50 个库的项目!这很快就会成为一个令人头疼的问题🤯。

pip 冻结保留以前安装的不再需要的旧包(图片由作者提供)

总之,pip freeze不够聪明,无法有效地管理依赖关系,以下是一些原因:

**pip freeze** 仅用于“pip 安装”:它仅知道使用pip install命令安装的软件包。这意味着任何使用不同方法安装的软件包,如peotrysetuptoolsconda等。不会包含在最终的 requirements.txt 文件中。

pip 冻结仅考虑使用 pip 命令安装的库(图片由作者提供)

**pip freeze** 不考虑依赖版本冲突:****项目生命周期是迭代的,因此可能需要现有库的全新或升级版本。使用pip freeze保存环境中的所有包,包括那些与项目无关的包。

**pip freeze** 抓取一切:如果你没有使用虚拟环境,pip freeze生成包含所有库的需求文件,包括你的项目范围之外的库。

那么,我能做些什么来解决这些问题呢?
好问题!

答案是通过使用pipreqs🎉

Pipreqs —更好的选择

[pipreqs](https://pypi.org/project/pipreqs/)首先扫描所有的 python 文件(。py),然后基于项目的每个 python 文件中的import语句生成 requirements.txt 文件。此外,它解决了使用pip freeze时面临的所有问题。

pireqs 扫描过程(图片由作者提供)

使用下面的pip命令,安装非常简单。

pip install pipreqs

一旦您安装了库,您只需要提供项目的根位置,并运行这个命令来生成项目的 requirements.txt 文件。

pipreqs /<your_project_root_path>/

有时您可能想要更新需求文件。在这种情况下,您需要使用--force选项来强制重新生成文件。

pipreqs **--force** /<your_project_root_path>/

假设您想要忽略特定子文件夹中的一些 python 文件的库。这可以通过在指定需要忽略的子文件夹之前使用--ignore选项来实现。

pipreqs /<your_project_root_path>/ **--ignore** /<your_project_root_path>/folder_to_ignore/

结论

恭喜你!🎉🍾您刚刚了解了一种新的、有效的管理项目相关性的方法。

如果你喜欢阅读我的故事,并希望支持我的写作,考虑成为一个媒体成员。每月支付 5 美元,你就可以无限制地阅读媒体上的故事。

欢迎在媒体推特YouTube 上关注我,或者在 LinkedIn 上打招呼。讨论人工智能、人工智能、数据科学、自然语言处理和人工智能是一种乐趣!

再见散点图,欢迎入库散点图

原文:https://towardsdatascience.com/goodbye-scatterplot-welcome-binned-scatterplot-a928f67413e4

因果数据科学

如何可视化并对条件手段进行推理

作者图片

当我们想要可视化两个连续变量之间的关系时,定位图就是散点图。这是一个非常直观的可视化工具,允许我们直接查看数据,无需任何操作。然而,当我们有大量数据和/或数据有偏差时,散点图可能噪声太大,无法提供信息。

在这篇博文中,我将回顾散点图的一个非常强大的替代方案,来可视化两个变量之间的相关性:装箱散点图。装箱散点图不仅是一个很好的可视化工具,而且还可以用来对条件均值进行推断,等等。

散点图

先说个例子。假设我们是一个网上市场,多家公司提供商品,消费者可以有效地浏览、比较和购买。我们的数据集包含了活跃在市场上的公司的快照。

让我们加载数据并查看一下。你可以在这里找到数据生成过程dgp_marketplace 的代码。我还从[utils](https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/src/utils.py)导入了一些代码来制作更好的图形。

from src.utils import *
from src.dgp import dgp_marketplace

df = dgp_marketplace().generate_data(N=10_000)
df.head()

作者图片

我们有 10000 家公司的信息。对于我们知道的每个公司:

  • age:公司的时代
  • sales:上月的月销售额
  • online:公司是否只在网上活动
  • products:公司提供的产品数量

假设我们有兴趣了解agesales之间的关系。销售的生命周期是什么?

让我们从一个简单的salesage散点图开始。

sns.scatterplot(x='age', y='sales', data=df);
plt.title("Sales by firm's age");

作者图片

剧情极其。我们有许多观察结果,因此,很难将它们全部形象化。如果我们必须猜测,我们可以说这种关系看起来是负的(salesage减少),但这将是一个非常无知的猜测。

我们现在要探索一些合理的调整和替代方案。

散点图备选方案

当我们有一个非常密集的散点图时,我们能做什么?一种解决方案是绘制观测值的密度图,而不是观测值本身。

Python 中有多种解决方案来可视化二维分布的密度。很有用的一个就是seabornjoint plot。jointplot绘制两个变量的联合分布,以及沿轴的边际分布。默认选项是散点图,但也可以选择添加回归线(reg),将图更改为直方图(hist),六边形图(hex),或核密度估计值 ( kde)。

让我们试试 hexplot ,它基本上是数据的直方图,其中的条柱是二维空间中的六边形。

s = sns.jointplot(x='age', y='sales', data=df, kind='hex', );
s.ax_joint.grid(False);
s.ax_marg_y.grid(False);
s.fig.suptitle("Sales by firm's age");

作者图片

没什么变化。看起来agesales的分布都非常偏斜,因此,大部分动作都集中在非常小的子空间中。

也许我们可以移除异常值并放大大部分数据所在的区域。让我们放大左下角,有age < 3sales < 3000的观察。

s = sns.jointplot(x='age', y='sales', data=df.query("age < 3 & sales < 3000"), kind="hex");
s.ax_joint.grid(False);
s.ax_marg_y.grid(False);
s.fig.suptitle("Sales by firm's age");

作者图片

现在空地少了很多,但看起来我们并没有走远。关节分布还是太偏。当数据遵循某种幂分布时就是这种情况,业务数据通常就是这种情况。

一种解决方案是通过取https://en.wikipedia.org/wiki/Natural_logarithm****转换变量。

df['log_age'] = np.log(df['age'])
df['log_sales'] = np.log(df['sales'])

我们现在可以画出agesales的对数之间的关系。

s = sns.jointplot(x='log_age', y='log_sales', data=df, kind='hex');
s.ax_joint.grid(False);
s.ax_marg_y.grid(False);
s.fig.suptitle("Sales by firm's age", y=1.02);

作者图片

对数绝对有帮助。现在,数据在空间上更加分散,这意味着可视化提供了更多信息。此外,看起来这两个变量之间没有关系。

不过还是有噪音太大。也许光靠数据可视化不足以得出结论。

让我们换一种更结构化的方法: 线性回归 。让我们在log_age上线性回归log_sales

smf.ols('log_sales ~ log_age', df).fit().summary().tables[1]

作者图片

log_age的回归系数为且具有统计显著性(即不同于零)。似乎所有以前的想象都非常误导。从上面的图表中,我们没有一个能猜到如此强的正相关关系。

然而,也许这种关系对于online-仅仅是公司和样本中的其他公司是不同的。我们需要控制这个变量,以避免辛普森悖论以及更普遍的偏见。

通过线性回归,我们可以对协变量进行条件分析。让我们添加二进制指标为online-只有公司和变量计数的数量products回归。

smf.ols('log_sales ~ log_age + online + products', df).fit().summary().tables[1]

作者图片

log_age的系数仍然是正的,并且在统计上是显著的,但是它的大小已经减半。

我们应该得出什么结论?平均来说,似乎随着年龄的增长而增加。然而,这种模式可能是非常非线性的。

在线性回归框架内,一种方法可以是添加额外的项,例如多项式(age^2)或分类特征(例如age < 2)。然而,如果有一种更灵活的方法可以告诉我们公司agesales之间的关系,那就太棒了。

要是……

装箱散点图

****装箱散点图是一个非常强大的工具,它提供了一种灵活简约的方式来可视化和总结大型数据集中的条件均值(不仅仅是)。

面元散点图背后的思想是将条件变量age分成个大小相等的面元或分位数,然后在每个面元内绘制因变量sales的条件均值。

细节

Cattaneo,Crump,Farrell,Feng (2021) 在 R, binsreg 中构建了一个非常好的分箱散点图包。而且,他们已经把包移植到 Python 上了。我们可以使用pip install binsreg直接从 pip 安装binsreg。你可以在这里找到关于 Python 包的更多信息,而原始和详细的 R 包文档可以在这里找到

构建面元散点图时最重要的选择是面元数量。这个权衡就是通常的 偏差-方差权衡 。通过选择更多数量的箱,我们在图中有更多的点。在极端情况下,我们最终得到一个标准的散点图(假设条件变量是连续的)。另一方面,通过减少箱的数量,情节将更加稳定。然而,在极端情况下,我们将有一个代表样本平均值的单点。****

Cattaneo,Crump,Farrell,Feng (2021) 证明,在基本分格散点图中,最小化均方误差的分格数与成正比,其中 n 为观察次数。因此,一般来说,更多的观察导致更多的箱。

斯塔尔和戈德法布(2020) 增加以下考虑因素:

然而其他元素也很重要。例如,保持 x 的分布不变,x 和 y 之间的真实关系曲线越多,算法将选择越多的箱(否则均方误差将增加)。这意味着即使有大的 n,也将为相对平坦的关系选择很少的箱。因此,计算基本分箱散点图中的最佳箱数时,考虑了可用于识别 x 和 y 之间关系的数据的变化量和位置。”

强烈建议使用默认的最佳箱数。然而,用户也可以使用nbins选项通过binsreg设置定制的箱数。

然而,分格散点图不仅仅计算最优选择区间的条件均值,还可以为这些均值提供推断。特别是,我们可以围绕每个数据点建立置信区间。在binsreg包中,选项ci将置信区间添加到估计结果中。该选项将一组参数(p, s)作为输入,并使用带有s平滑度约束的p次分段多项式来构建置信区间。默认情况下,置信区间不包含在图中。关于ps的选择,包文档报告:**

" 推荐的规格是ci=c(3,3),它将基于感兴趣的回归函数的三次 B 样条估计的置信区间添加到装箱散点图中。"

宾斯雷格

这个包的 Python 版本的一个问题是它不太像 Python。因此,我将binsreg包包装到一个函数binscatter中,该函数负责清理和格式化可读性良好的 Pandas DataFrame 中的输出。

我们现在可以进行估计可视化基于salesage的分级散点图。**

*# Estimate binsreg
df_est = binscatter(x='age', y='sales', data=df, ci=(3,3))
df_est.head()*

作者图片

binscatter函数输出一个数据集,其中,对于条件变量age的每个箱,我们有结果变量sales的值和置信区间。

我们现在可以画出估计值。

*# Plot binned scatterplot
sns.scatterplot(x='age', y='sales', data=df_est);
plt.errorbar('age', 'sales', yerr='ci', data=df_est, ls='', lw=2, alpha=0.2);
plt.title("Sales by firm's age");*

作者图片

情节相当暴露。现在,这种关系看起来非常的非线性,在一个公司生命周期的开始sales急剧增加,然后是一个平台期。**

此外,该图还告诉我们关于agesales分布的信息。其实左边的地块更密集,这里集中了age的分布。此外,左边的置信区间更小,这里是大多数条件分布的所在地。

正如我们在上一节已经讨论过的,控制其他变量可能很重要。例如,products的数字,因为销售更多产品的公司可能在市场上生存得更久,并且也销售得更多。

通过w选项,binsreg允许限制对任意数量变量的分析。**

*# Estimate binsreg
df_est = binscatter(x='age', y='sales', w=['products'], data=df, ci=(3,3))

# Plot binned scatterplot
sns.scatterplot(x='age', y='sales', data=df_est);
plt.errorbar('age', 'sales', yerr='ci', data=df_est, ls='', lw=2, alpha=0.2);
plt.title("Sales by firm's age");*

作者图片

根据products的数量,sales生命周期的形状会进一步改变。现在,在最初的销售增长后,我们观察到随着时间的推移逐渐下降。

相对于混合的线上-线下企业,只有online企业有不同的sales生命周期吗?我们可以使用选项by按组生成不同的分级散点图****

*# Estimate binsreg
df_est = binscatter(x='age', y='sales', by='online', w=['products'], data=df, ci=(3,3))

# Plot binned scatterplot
sns.scatterplot(x='age', y='sales', data=df_est, hue='online');
plt.errorbar('age', 'sales', yerr='ci', data=df_est.query("online==0"), ls='', lw=2, alpha=0.2);
plt.errorbar('age', 'sales', yerr='ci', data=df_est.query("online==1"), ls='', lw=2, alpha=0.2);
plt.title("Sales by firm's age");*

作者图片

从分箱散点图中,我们可以看到online产品的平均寿命更短,在sales中有一个更高的初始峰值,随后是更急剧的下降。

结论

在这篇博文中,我们分析了一个非常强大的数据可视化工具:装箱散点图。特别是,我们已经看到了如何使用binsreg包来自动挑选最佳数量的箱,并对条件均值执行非参数推断。然而,binsreg套件提供的远不止这些,我强烈建议更深入地查看的手册。**

参考

[1]E . Starr,B . goldf ARB,分箱散点图:使研究更容易和更好的简单工具 (2020),战略管理杂志。

[2] M. D. Cattaneo,R. K. Crump,M. H. Farrell,Y. Feng, On Binscatter (2021),工作文件。

[3]p·戈德史密斯-平克姆,第六讲。线性回归 II:半参数和可视化,应用计量学博士课程。

密码

你可以在这里找到 Jupyter 的原版笔记本。

***https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/binscatter.ipynb ***

感谢您的阅读!

非常感谢!🤗如果你喜欢这个帖子并且想看更多,可以考虑 关注我 。我每周发布一次与因果推断和数据分析相关的主题。我尽量让我的帖子简单而精确,总是提供代码、例子和模拟。**

还有,一个小小的 免责声明 :我写作是为了学习所以错误是家常便饭,尽管我尽了最大努力。当你发现他们的时候,请告诉我。也很欣赏新话题的建议!

古德哈特定律和 A/B 测试中度量选择的危险

原文:https://towardsdatascience.com/goodharts-law-and-the-dangers-of-metric-selection-with-a-b-testing-91b48d1c1bef

选择度量标准的令人惊讶的违反直觉的问题(以及它与眼镜蛇的关系)

照片由 Unsplash 上的 NIvedh P 拍摄

实验有很多部分:选择假设,实施变化,任务,结果分析,文档等,每一部分都有自己的细微差别,使其变得复杂。通常,选择决定假设是否正确的指标是很简单的。然而,在某些情况下,选择度量标准可能会有问题,并且会暴露出古德哈特定律的经典问题。

古德哈特定律说,当一个衡量标准成为一个目标时,它就不再是一个好的衡量标准。这与坎贝尔定律、眼镜蛇效应以及更普遍的不正当激励有着密切的关系。简单地说,这些定律描述了选择指标会产生意想不到的负面影响的情况。

“眼镜蛇效应”背后的经典例子和词源来自殖民时期的印度,据说那里有太多的眼镜蛇。为了解决这个问题,英国政府悬赏捉拿死眼镜蛇。这导致当地人开始饲养眼镜蛇以换取赏金。

最近的一个例子来自《美国新闻与世界报道》最佳大学排名。排名中的一个因素是选择性——有多少学生申请和被录取。这一措施鼓励一些学校通过将每一张表达兴趣的明信片都作为“申请”来控制申请人数,并拒绝更多的秋季入学学生以提高排名。

这些意想不到的负面影响同样适用于 A/B 测试。如果你告诉你的团队改进一个指标,团队可以被激励去实现这些指标。作为一个例子,考虑这样的情况,你想增加每次访问的页面。一个绝对可行的方法是将你的内容分页成越来越小的页面(你可以在很多网站上看到真实的例子)。你冒着破坏用户体验和惹恼用户的风险,但这一指标几乎肯定会增加。

脸书是这一现象的典型例子。脸书以高度关注增长指标(如活跃用户和用户参与度)而闻名。团队将这些增长指标作为他们的主要绩效指标,并有依赖于改进它们的奖金。因此,他们没有动力去改进不相关的指标,以提供更完整的图像。脸书确实有团队来衡量他们工作的其他影响,如他们的诚信团队或内部研究人员,但由于这些利益冲突,通常无法有意义地解决这些问题。即使在决策升级时,增长也被放在首位。这导致他们开发了一种产品,这种产品肯定有很高的参与度,但却疏远了很大一部分人,并传播了在世界上造成真正伤害的错误信息(见 1 月 6 日或缅甸)。

假设您已经为您的团队仔细地选择了度量标准,以避免上述问题,并且您的内部团队善于避免玩弄度量标准,那么在使用 A/B 测试选择度量标准时,仍然有其他方面的非预期的负面影响需要注意。

相关性、因果关系和代理指标

几年前,我们在一个免费增值内容网站上做了一个有趣的实验,我们有一个提高收入的北极星指标。该实验的假设来自我们数据团队的一个见解,他们注意到使用多种类型内容的用户以比正常情况高得多的比率转化为付费。考虑到这种相关性,我们的产品团队开始推动更多用户消费多种内容,以期增加收入。对于这些测试,我们使用了代理(多内容使用)和目标(收入)的指标。结果令人着迷,也违反直觉。

我们在多次实验后发现,它们不仅没有增加收入,而且通过推动用户做他们不愿意做的事情,我们减少了每次访问的页面,实际上减少了收入。然而,我们确实成功地增加了多内容使用的指标。我们通过这些实验实际上证明了这种相关性不是因果关系。如果我们只是使用多种内容的代理指标,并相信其与收入的因果关系,我们可能已经宣布这些测试成功了。

推行度量标准也会破坏原有的相关性。在实验过程中,我们回顾了最初的相关性,但它已经消失了。在收入没有增加的情况下,我们迫使更多不合格的用户使用多种内容类型,以至于最初的相关性不再重要。

使用代理指标的另一个常见原因是因为这是您所拥有的全部。你要确保你测试的是你需要的指标,而不是你拥有的指标。想想什么是证明假设的正确指标,如果你发现自己不能用它们来测试,那么你就有问题了。在不知道对目标指标的影响的情况下使用代理指标将意味着您无法确定因果关系,这将限制您的实验的有效性。确保您的实验平台不是运行正确实验的限制因素,并使用正确的指标运行测试。

结论

从古德哈特定律中得到的度量选择的教训是,要对你的度量深思熟虑。尽量不要使用代理指标,除非你确定它们是因果关系。小心你的目标度量的含义,并考虑可能还需要测量哪些其他度量来确定可能的负面影响。最后,并不是所有的实验结果都可以直接分析,需要仔细考虑才能为您的产品确定正确的结论,这往往是微妙的。记住这些想法,希望你可以避免一些度量驱动的决策的陷阱。

[1] G. S. Morson 和 M. Schapiro,哦,学校编织了一个多么复杂的网络:大学排名游戏 (2017)芝加哥论坛报

[2] C. Timberg,E. Dwoskin 和 R. Albergotti,1 月 6 日,在脸书,暴力激起了愤怒,对错过警告标志感到遗憾 (2021 年)《华盛顿邮报》

[3] J. Clayton,罗辛亚因缅甸仇恨言论起诉脸书索赔 1500 亿美元 (2021) BBC 新闻

拟合优度:调整的 R 和 Bootstrapping 确定回归系数的标准误差

原文:https://towardsdatascience.com/goodness-of-fit-adjusted-r²-and-bootstrapping-to-determine-standard-error-of-regression-4897cb4bb811

多元线性回归分析

图片来自 Unsplash

简介

当执行线性回归时,我们需要评估回归模型。第一个也是最重要的策略是查看 R 平方值,它表明自变量可以解释因变量的多少变化。然而,这对于简单的线性回归是正确的。当我们执行多元线性回归时,调整的 R-square 是回归模型评估的更可靠的度量。

自举是简单的替换采样技术。当我们有大量人口时,通常会对数据进行抽样以预测人口统计数据。Bootstrapping 是一种非常有效的技术,可以根据采样数据确定标准误差和建立置信区间。这是降低重采样成本的简单而有效的策略。

R

r 平方是回归分析中拟合优度的度量。这是可变性的一种度量。它也被称为决定系数。当我们有一个单独的自变量和另一个单独的响应变量时,R 的值指定了可由自变量解释的响应变量的可变性的百分比。

我们经常需要执行多元线性回归,最终得到数据集中的几个独立变量。通过在分析中包含更多的独立变量,我们允许更多的参数变化。因此,添加更多的变量会对因变量的可变性产生影响,不管这种影响有多小,这是有意义的。这就是为什么总是期望在回归分析中增加更多的变量会增加 R 值,这并不坏。当这些变量相关时,问题就出现了。这种多重共线性问题产生了一个不太稳健的模型,其中系数的估计变得系统性错误。

调整后的 R

如上所述,在回归分析中增加更多的独立变量有助于增加 R 值。然而,分析变量的系数是否有很大价值也很重要。当两个变量相关时,我们可以去掉一个,利用其他不相关的变量。检查共线性的一种方法是检查方差膨胀因子(VIF)。通常,大于 5 的 VIF 值表示可能存在多重共线性。本文解释了获取 VIF 值的过程。

统计软件在进行回归分析时,会计算 R 和调整后的 R。调整后的 R 会减少添加更多独立变量的影响,并保持 R 值来自最重要变量的可变性。这就是为什么调整后的 R 值总是等于或小于常规的 R 值。

调整后的 R 在动作中

让我们以 GPL 2.0 许可下的“鱼”数据集为例。有 5 个独立变量和一个响应变量。在一次添加一个独立变量后,观察到 R 值从 0.84 增加到 0.89,虽然很小,但潜在地证明了多重共线性的存在,从 VIF 值可以明显看出这一点。

鱼类数据集中的 VIF

由于观察到多重共线性,我们必须获得调整的 R,因为常规 R 是误导性的。

这里 N =观察值的总数,k =分析中考虑的独立变量的总数。当 k=5 时,调整后的 R 值变为 0.88,这是一个非常小的下降。

为什么自举计算标准误差

当我们进行线性回归分析时,有时我们可能对回归系数的估计不是很有信心,因为我们只处理样本。当无法了解全貌时,样本估计值可能会远离实际数据。

让我们看看下面的两个图表,它们在数据点上有相同的线性拟合线。

线性拟合线 1(图片由作者提供)

线性拟合线 2(图片由作者提供)

当我们想从第一个图中计算人口统计数据时,样本将产生具有不同斜率的不同线,而第二个图中的任何样本(大小为 2 或更大)将提供具有相同斜率的相同线。如果第一个数字样本的系数变化不大,我们将对估计值有信心,另一方面,如果系数变化很大,我们将对估计值缺乏信心。这就是为什么在处理样本时,引导数据点、拟合数据点并确定拟合系数非常重要。

从这两个图中观察到的另一个有趣的事情是,虽然两个图中的线性拟合方程是相同的,但 R 是不同的。在第二幅图中,R 为 1,这表明了完美的拟合,而第一幅图中的 R 小于 1,因为存在残余误差。

结论

本文解释了 R 和调整后 R 的概念。执行多元线性回归时,调整后的 R 是正确的决定系数。对于简单的线性回归,R 和调整后的 R 都非常接近。同样,为了对样本估计值有信心,我们可以执行 bootstrapping 并确定回归系数的标准误差,这将告诉我们多个样本的值如何变化。

https://mdsohel-mahmood.medium.com/membership https://mdsohel-mahmood.medium.com/subscribe

谷歌分析:2022 年回顾

原文:https://towardsdatascience.com/google-analytics-in-r-review-of-2022-52d6bf4c1bb7

了解如何通过 R 中的 googleAnalyticsR 包为您的博客或网站分析和可视化通用分析(UA)和 Google 分析 4 (GA4)数据

照片由帕韦尔·切尔文斯基拍摄

介绍

It 快到年底了,这意味着是时候做一个统计和 R 的回顾,回顾过去的一年。

今年的回顾会比往年短得多,因为在那些以前的回顾中已经有很多例子了。

请注意,2022 年 9 月初,我从通用分析(被称为 UA)转移到谷歌分析 4(被称为 GA4)。你可能知道如果你经常使用谷歌分析;2023 年 7 月 1 日,标准通用分析属性将停止处理新的点击。这意味着,如果您想在此日期后继续使用它,您将需要转移到 GA4。

今年,我将简要介绍不同的指标以及如何分析您的 Google Analytics (GA)数据。然而,这篇文章也许会对那些已经迁移到(或将迁移到)GA4 并且仍然想从 UA 和 GA4 分析 GA 数据的人有所帮助。

我不得不承认,将两者的数据结合起来是相当耗时的,特别是因为 UA 和 GA4 的度量和维度是不同的。所以如果你还没有搬家,我建议你在一年的年底或年初搬家。这将避免您必须从两个 GA IDs 获取数据,然后必须在 r 中组合这两个数据。

像往常一样,我在 R 中分析我的 GA 数据,这要感谢来自 Mark Edmondson 的惊人的{googleAnalyticsR}包。

请注意,下面给出的实际数字对您来说不是很有用。每个博客和网站都不一样,所以每个受众都不一样。这篇帖子更多的是说明在 R 中分析 GA 数据的过程(今年,也是为了说明合并来自两个 GA IDs 的 GA 数据的过程),而不是展示我的数字。

先决条件

首先,您必须指定要分析数据的 GA ID。我的如下:

ga_id <- c("208126346", "250795226")

您将在 GA 帐户的管理部分找到您的。

分析学

在这一节中,我将展示一些在分析 GA 数据时可能有用的可视化工具。如果你使用了其他有趣的可视化工具,请在文章末尾随意评论。

请注意,我在这篇文章中关注的是页面浏览量指标,但是您也可以编辑我的代码来显示其他指标。查看 UA 的可用指标和 GA4 的可用指标

一段时间内的页面访问量

先说过去一年的浏览量演变,那么从 2021 年 12 月 16 日到 2022 年 12 月 15 日。

library(googleAnalyticsR)
# set date range
start_date <- as.Date("2021-12-16")
end_date <- as.Date("2022-12-15")# extract data from both IDs
dat1 <- google_analytics(ga_id[1],
  date_range = c(start_date, end_date),
  metrics = "pageviews",
  dimensions = "date",
  anti_sample = TRUE # avoid sampling
)dat2 <- ga_data(ga_id[2],
  date_range = c(start_date, end_date),
  metrics = "screenPageViews",
  dimensions = "date",
  limit = -1 # return all data (no limit)
)# combine data from both IDs
library(dplyr)
dat <- full_join(dat1, dat2, by = "date")
dat$page_views <- rowSums(select(dat, pageviews, screenPageViews),
  na.rm = TRUE
) # scatter plot with a trend line
library(ggplot2)
dat %>%
  ggplot(aes(x = date, y = page_views)) +
  geom_point(size = 1L, color = "gray") + # change size and color of points
  geom_smooth(color = "steelblue", alpha = 0.25) + # change color of smoothed line and transparency of confidence interval
  theme_minimal() +
  labs(
    y = "Page views",
    x = "",
    title = "Evolution of daily page views",
    subtitle = paste0(format(start_date, "%b %d, %Y"), " to ", format(end_date, "%b %d, %Y")),
    caption = "Data: Google Analytics data of statsandr.com"
  ) +
  theme(plot.margin = unit(c(5.5, 17.5, 5.5, 5.5), "pt")) + # to avoid the plot being cut on the right edge
  scale_y_continuous(labels = scales::comma) # better y labels

作者的情节

正如您在上面的代码中看到的,我们需要:

  • 从两个不同的 id 中提取数据:这是用 UA 的google_analytics()和 GA4 的ga_data()完成的(每个函数都有自己的参数)
  • 连接来自两个 id 的数据(用一个full_join()连接,因为即使在移动到 GA4 之后,UA 上仍然有一些点击,所以我需要保留全年来自两个 id 的数据)
  • 合计两个 id 的度量(用rowSums())

这个过程将对每个可视化重复进行。

从上面的图中,我们看到页面浏览量遵循一个周期性的演变过程(在夏季有所下降)。这一趋势遵循与去年相同的模式,但今年最后一个季度的增幅在 2022 年更大。

请注意,似乎总有一些日子的页面浏览量低于其他日子。这实际上是周末。在部分中可以看到更多相关信息。还要注意页面浏览量超过 5000 的异常值的存在。那天没有发布任何帖子,所以它可能来自一个分享给大量观众的旧帖子。

最后,将所有天数相加,总浏览量为 938,630。去年是 876280,所以 2022 年增长了 7.12%。

每月和每年的页面访问量

比较前几年每月的页面浏览量也是有用的。下面是两种不同类型的可视化。

# set new date range to include previous years
start_date_launch <- as.Date("2019-12-16")
# extract data from both IDs
dat1 <- google_analytics(ga_id[1],
  date_range = c(start_date_launch, end_date),
  metrics = "pageviews",
  dimensions = "date",
  anti_sample = TRUE # avoid sampling
)dat2 <- ga_data(ga_id[2],
  date_range = c(start_date_launch, end_date),
  metrics = "screenPageViews",
  dimensions = "date",
  limit = -1 # return all data (no limit)
)# combine data from both IDs
dat <- full_join(dat1, dat2, by = "date")
dat$page_views <- rowSums(select(dat, pageviews, screenPageViews),
  na.rm = TRUE
) # add year and month columns to dataframe
dat$month <- format(dat$date, "%m")
dat$year <- format(dat$date, "%Y")# page views by month by year using dplyr then graph using ggplot2 barplot
dat %>%
  filter(year != 2019) %>% # remove 2019 because there are data for December only
  group_by(year, month) %>%
  summarize(page_views = sum(page_views)) %>%
  ggplot(aes(x = month, y = page_views, fill = year)) +
  geom_bar(position = "dodge", stat = "identity") +
  theme_minimal() +
  labs(
    y = "Page views",
    x = "Month",
    title = "Page views per month and year",
    subtitle = paste0(format(start_date_launch, "%b %d, %Y"), " to ", format(end_date, "%b %d, %Y")),
    caption = "Data: Google Analytics data of statsandr.com",
    fill = "" # remove legend title
  ) +
  theme(legend.position = "top") + # change legend position
  scale_y_continuous(labels = scales::comma) # better y labels

作者的情节

另一种可能性如下:

dat2 <- dat
library(lubridate)
dat2$day <- day(dat2$date)
dat2$day_month <- as.Date(paste0(dat2$month, "-", dat2$day), format = "%m-%d")dat2 %>%
  filter(year != 2019 & page_views < 7500) %>% # remove 2019 and outliers
  ggplot(aes(x = day_month, y = page_views, color = year)) +
  geom_point(size = 1L, alpha = 0.25) + # change size and alpha of points
  geom_smooth(se = FALSE) + # remove confidence interval
  theme_minimal() +
  labs(
    y = "Page views",
    x = "",
    title = "Evolution of daily page views",
    subtitle = paste0(format(start_date_launch, "%b %d, %Y"), " to ", format(end_date, "%b %d, %Y")),
    caption = "Data: Google Analytics data of statsandr.com",
    color = "" # remove legend title
  ) +
  theme(legend.position = "top") + # change legend position
  scale_y_continuous(labels = scales::comma) + # better y labels
  scale_x_date(date_labels = "%b") # show only months

作者的情节

从上面的两个图中,我们看到,与 2020 年至 2021 年相比,该博客在页面浏览量方面的全球表现更好(除了 2021 年第一季度的表现更好)。

请注意,3 年之间的比较是好的,但如果用更多的年份来比较,这些图将很快变得不可读!

表现最佳的页面

如果您有兴趣了解表现最佳的页面(仍以页面浏览量计):

# extract data from both IDs
dat1 <- google_analytics(ga_id[1],
  date_range = c(start_date, end_date),
  metrics = "pageviews",
  dimensions = "pageTitle",
  anti_sample = TRUE # avoid sampling
)
dat2 <- ga_data(ga_id[2],
  date_range = c(start_date, end_date),
  metrics = "screenPageViews",
  dimensions = "pageTitle",
  limit = -1 # return all data (no limit)
)# combine data from both IDs
dat <- full_join(dat1, dat2, by = "pageTitle")
dat$page_views <- rowSums(select(dat, pageviews, screenPageViews),
  na.rm = TRUE
)## Create a table of the most viewed posts
library(lubridate)
library(reactable)
library(stringr) most_viewed_posts <- dat %>%
  mutate(Title = str_sub(pageTitle, start = 1, end = -nchar(" - Stats and R"))) %>% # remove blog site in pageTitle
  count(Title, wt = page_views, sort = TRUE) %>%
  mutate(Title = str_trunc(Title, width = 30)) # keep maximum 30 characters# plot
top_n(most_viewed_posts, n = 7, n) %>% # edit n for more or less pages to display
  ggplot(., aes(x = reorder(Title, n), y = n)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  theme_minimal() +
  coord_flip() +
  labs(
    y = "Page views",
    x = "Page title",
    title = "Top performing pages",
    subtitle = paste0(format(start_date, "%b %d, %Y"), " to ", format(end_date, "%b %d, %Y")),
    caption = "Data: Google Analytics data of statsandr.com"
  ) +
  scale_y_continuous(labels = scales::comma) # better y labels

作者的情节

表现最佳的帖子与去年非常相似,即:

  1. R 中的描述性统计
  2. R 中的离群点检测
  3. R 中的相关系数和相关检验
  4. R 中的方差分析
  5. R 中独立性的卡方检验

由于它们是几年来阅读量最大的帖子,我已经通过 Gumroad 提供下载。

按国家列出的页面浏览量

了解你的读者来自哪个国家也很有用,特别是对于电子商务或者除了写文章以外还销售实体产品的博客。

# extract data from both IDs
dat1 <- google_analytics(ga_id[1],
  date_range = c(start_date, end_date),
  metrics = "pageviews",
  dimensions = "country",
  anti_sample = TRUE # avoid sampling
)
dat2 <- ga_data(ga_id[2],
  date_range = c(start_date, end_date),
  metrics = "screenPageViews",
  dimensions = "country",
  limit = -1 # return all data (no limit)
)# combine data from both IDs
dat <- full_join(dat1, dat2, by = "country")
dat$page_views <- rowSums(select(dat, pageviews, screenPageViews),
  na.rm = TRUE
)# table
countries <- dat %>%
  mutate(Country = str_trunc(country, width = 30)) %>% # keep maximum 30 characters
  count(Country, wt = pageviews, sort = TRUE)# plot
top_n(countries, n = 10, n) %>% # edit n for more or less countries to display
  ggplot(., aes(x = reorder(Country, n), y = n)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  theme_minimal() +
  coord_flip() +
  labs(
    y = "Page views",
    x = "Country",
    title = "Top performing countries",
    subtitle = paste0(format(start_date, "%b %d, %Y"), " to ", format(end_date, "%b %d, %Y")),
    caption = "Data: Google Analytics data of statsandr.com"
  ) +
  scale_y_continuous(labels = scales::comma) + # better y labels
  theme(plot.margin = unit(c(5.5, 7.5, 5.5, 5.5), "pt")) # to avoid the plot being cut on the right edge

作者的情节

对于 Stats 和 R 来说,大多数读者来自美国,很大程度上是因为第二大国家(英国)在页面浏览量方面相差甚远。

这一趋势与去年相同,只是:

  • 英国已经超过印度,而
  • 比利时(曾在 2020 年和 2021 年分别排名第三和第六)现在仅列第八。由于我来自比利时,这表明这个博客这些年来吸引了越来越多的国际读者(而来自我的国家的读者相应地越来越少)。

每周每天的页面浏览量

正如在关于每日页面浏览量演变的章节中所讨论的(查看此章节),似乎有些日子的表现一直比其他日子差。

下面的情节将展示这些日子是什么:

# extract data from both IDs
dat1 <- google_analytics(ga_id[1],
  date_range = c(start_date, end_date),
  metrics = "pageviews",
  dimensions = c("date"),
  anti_sample = TRUE # avoid sampling
)
dat2 <- ga_data(ga_id[2],
  date_range = c(start_date, end_date),
  metrics = "screenPageViews",
  dimensions = c("date"),
  limit = -1 # return all data (no limit)
)# combine data from both IDs
dat <- full_join(dat1, dat2, by = "date")
dat$page_views <- rowSums(select(dat, pageviews, screenPageViews),
  na.rm = TRUE
)
# find day of week
dat$weekday <- wday(dat$date, label = TRUE, abbr = TRUE)## Reordering dat$weekday so Monday is first
dat$weekday <- factor(dat$weekday,
  levels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
)# boxplot
library(scales)
dat %>%
  ggplot(aes(x = weekday, y = page_views)) +
  geom_boxplot(fill = "steelblue", outlier.colour = alpha(0.25)) +
  geom_jitter(alpha = 0.25) + # adds transparency
  theme_minimal() +
  labs(
    y = "Page views",
    x = "",
    title = "Page views per day of week",
    subtitle = paste0(format(start_date, "%b %d, %Y"), " to ", format(end_date, "%b %d, %Y")),
    caption = "Data: Google Analytics data of statsandr.com"
  ) +
  scale_y_continuous(labels = scales::comma) # better y labels

作者的情节

正如一个技术博客所预期的那样,一周内的读者比周末多得多。

感谢信

感谢所有今年来到 Stats and R 的读者。你让这段旅程变得无比丰富。对于明年和未来的许多年,我将继续写我熟悉和感兴趣的话题。敬请关注!

感谢阅读。我希望这篇文章能帮助你在 R 中分析你的 Google Analytics 数据,或者帮助你结合你的 Universal Analytics 和 Google Analytics 4 数据。有关 R 中 GA 数据的可视化或汇总的更多示例,另请参见往年的评论

和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。

相关文章

原载于 2022 年 12 月 16 日 https://statsandr.comhttps://statsandr.com/blog/review-of-2022/

谷歌云实体+情感分析快速参考

原文:https://towardsdatascience.com/google-cloud-entity-sentiment-analysis-quick-reference-2a4196546133

为什么通过调查收集和分析开放式文本回答很有帮助(如果你也可以使用 NLP)

介绍

本文提供了一个关于使用 Google Cloud 的自然语言 API 作为工具的快速参考,可以帮助您快速分析反馈调查中的开放文本响应。

反馈调查通常采用问卷的形式,征求客户或员工对产品、服务或其他主题的反馈。调查可以是在线的,也可以是离线的,通常包括关于满意度的问题、对质量的意见以及改进的建议。客户或员工可以以文本响应的形式提供反馈,这可能难以手动分析。这就是谷歌云的自然语言 API 的用武之地:它可以帮助你快速轻松地从大量开放的文本数据中提取见解。

图片来源:Canva 的库存图片。

如果你还不知道,自然语言处理 (NLP)是计算机科学和语言学的一个领域,处理计算机和人类语言之间的交互。它包括开发能够理解人类语言输入并以人类自然的方式做出反应的程序。NLP 应用程序可用于情感分析、文本分类和机器翻译等任务。

在阅读下面的内容之前,同样重要的是,NLP 技术至少可以在两个主要方面提供帮助。首先,NLP 可以量化情绪。第二,NLP 可以识别实体

情感分析量化情感,它是识别和量化文本中表达的情感的过程。通常,情感分析用于确定文档或文档的一部分的总体情感。此外,该分析可以量化整个文档、段落、段落、句子或实体级别的情感。

自然语言处理中的实体分析是指对文本中的物、人、场所、对象等有形物体进行识别和分类。粗略地说,你可能认为实体是一个“名词”

收集非结构化的开放式回答,优势

首先,许多人可能会建议不要在调查中收集开放式的回答。避免这种非结构化的数据收集将减少与进行分析相关的技术挑战。的确,没有任何分析能够完全概括大量开放式文本回复中的所有细微差别。然而,包括 Fowler (2014)和 Heinrich (2005)在内的多位科学家记录了与开放式调查项目相关的方法优势和劣势。开放式问题有可能发现或“获得意想不到的答案”(Fowler,2014 年,第 88 页)。同样,这种开放式的回答可能揭示主题、思想、观点或“研究者未知的参考框架”(Heinrich,2005,第 559 页)。相关的、开放式的回答有助于“思维过程的检查”(Heinrich,2005,第 559 页)。

开放式文本收集,缺点

非结构化的开放式文本数据收集和相关分析策略的主要弱点之一是,来自不太感兴趣、注意力分散或没有响应动机的潜在回答者的数据可能较少。可能有帮助的替代策略包括涉及面对面互动的数据收集策略(访谈、焦点小组、电话或其他双向交流)。双向沟通的存在允许访问者或焦点小组主持人从研究参与者和回答者那里探索更多的细节。此外,研究人员可以考虑从受访者那里收集定量、序数和名义数据。这种定量的、有序的和名义上的数据可能有助于确定一项研究可能提出的其他开放式问题。具体而言,定量数据、序数数据和名词性数据可以帮助识别对回答者来说更有趣和更吸引人的开放式问题主题。理论上,问一些让受访者感兴趣的开放式问题,会让受访者在分心或缺乏动力的情况下更好地生存下来。

谷歌的云的自然语言 API 能有什么帮助

谷歌的云的自然语言 API 可以通过从大量开放的文本数据中提取见解来帮助分析调查响应。该 API 可用于快速、轻松地从大量开放文本数据中提取见解。这对于情感分析、文本分类和机器翻译等任务很有帮助。

请记住,机器学习输出的计算机审查可以帮助人类审查打开的文本。但是,没有什么可以替代对文本中讨论的主题有所了解的人的审查。

谷歌云的自然语言 API(或其他可以量化文档任何层次情感的工具)最强大的用途之一是,这样做有能力部分抽象调查响应提交的信息。例如,一些调查受访者可能会提交符合个人身份信息条件的信息。同样,受访者有时可能会提交令人不快的信息。通过提取实体,然后在响应或实体级别找到情感,该过程增加了一层,该层可以帮助限制限制性或攻击性响应的传播。

更多关于情绪

为了更深入地理解上面的内容,考虑一下“量化情感”意味着什么是有帮助的在一个最简单的例子中,情绪分数通常将快乐和高兴识别为积极的。否则它通常会将悲伤或愤怒识别为负面的。谷歌云实体情感分析 API 返回一个介于-1 和 1 之间的情感得分。通常,接近 0 的分数表示中性情绪,而接近-1 的分数表示消极情绪,接近 1 的分数表示积极情绪。(引用)。

关于显著性的一个注记

突出度是谷歌云的自然语言 API 和其他 NLP 工具提供的另一个重要指标。“显著性分数”表示该实体对整个文档文本的重要性或相关性()。具体来说,“这个分数可以通过区分显著实体的优先级来帮助信息检索和摘要。更接近 0.0 的分数不太重要,而更接近 1.0 的分数非常重要。”(引自)。

结论

我撰写本指南是为了帮助分析师和其他人准备反馈调查,或任何可能涉及一个或多个要求开放式回答的问题的调查。在这种情况下,单端响应可能是这样的:

图片来源:作者使用调查软件和屏幕截图的插图。

我还希望本指南能为使用谷歌云的自然语言 API 帮助开放式调查反馈的情感分析提供快速参考。该 API 可用于从大量开放文本数据中提取见解,这有助于情感分析、文本分类和机器翻译等任务。此外,通过提取实体并在响应或实体级别发现情绪,API 可用于帮助限制受限或攻击性响应的传播。

将实体分析与情感评分相结合是一种强大的技术,每个拥有调查数据的人都应该考虑利用这种技术。通过提取实体,然后在响应或实体级别找到情感,我们可以获得对我们收到的响应的有价值的见解。这可以帮助我们更好地理解我们正在收集的数据,并识别数据的任何潜在问题。此外,这项技术可以帮助我们限制限制性或攻击性反应的传播。

感谢阅读

你准备好了解更多关于数据科学职业的信息了吗?我进行一对一的职业辅导,并有一份每周电子邮件列表,帮助专业求职者获取数据。联系我了解更多信息。

感谢阅读。把你的想法和主意发给我。你可以写信只是为了说声嗨。如果你真的需要告诉我是怎么错的,我期待着尽快和你聊天。推特:@ adamrossnelsonLinkedIn:亚当罗斯尼尔森

参考资料:

F. J .福勒(2014 年)。调查研究方法(第 5 版。).千橡,加州:圣人出版社。

海因里希·h . a .(2005 年)。谁感知集体的过去,如何感知?对开放式问题的拒绝是实质性的回答吗?质与量,39 (5),559–579。

用简笔画理解谷歌云 IAM 概念

原文:https://towardsdatascience.com/google-cloud-iam-with-stick-figures-cd5ce19c142b

用涂鸦描述谷歌云平台上的 IAM 概念

IAM 概念插图-作者图片

用类比和例子解释新概念会很有帮助。在本文中,我将尝试使用涂鸦来解释 GCP 的 IAM(身份和访问管理)概念。GCP 的 IAM 并不特别难,尽管这样做很有趣,我希望我不那么复杂的涂鸦能帮助你多理解一点 IAM 的概念。

在我们开始之前,这里有一个我们将涉及的每个关键概念的地图,以便您可以跟随类比。

  • 人物:在 GCP,这相当于一个principal或者identity。这可能是一个实际的用户帐户(alex@example.com)、一个服务帐户或其他实体。我将交替使用“主体”和“身份”。
  • :相当于 GCP 的一个role。例如,alex@example.com 可以有一个云存储桶管理员角色。
  • 房子:相当于 GCP 的一个resource。这可能是一个计算引擎实例或 BigQuery。

使用上面的图像作为指导,让我们想象简笔画用户(可能是任何 GCP identity)试图进入一所房子(可能是任何resource,像 GCP 的计算引擎实例)。需要进行一些验证,以确保我们的用户拥有正确的 权限 来访问特定的属性。用户需要被授予正确的权限才能继续。

在 IAM 中,访问资源的权限不是直接授予终端用户的。相反,权限被分组到角色中,角色被授予经过身份验证的主体。

那么什么是角色呢?

一个角色是权限的集合。权限决定了允许对资源进行哪些操作。当您将一个role授予一个principal时,您就授予了该角色包含的所有权限。

什么是权限?

权限决定了允许对资源进行哪些操作。例如,“调用”云功能是可以在云功能上执行的操作。在 IAM 世界中,权限以service.resource.verb的形式表示,例如pubsub.subscriptions.consume

继续上图中的例子,图中的将代表一个*role*,它可能被分配了以下虚拟权限:living.house.openFrontDoorliving.house.openKitchenDoorliving.house.openBasement

对密钥(即角色)的允许权限—按作者排列的图像

在 GCP,角色和权限的映射在概念上是这样的:

图片来源— 谷歌云平台

既然我们已经为密钥分配了权限,流程的下一步就是将密钥分配给简笔画用户。我们还需要让房屋主人知道用户在物业中被允许做什么。要做到这一点,我们需要某种策略来概述授权用户并明确定义他们可以做什么。

为了在 GCP 实现这一点,每个资源被分配一个叫做 IAM 策略 的东西。

IAM 策略

一个 IAM 策略定义并强制执行哪些角色被授予哪些身份。此策略附加到资源。如果我们有 20 个计算引擎实例,它们每个都有一个 IAM 策略。重要的是,如果您将策略分配给 GCP 项目,用户将获得整个项目的指定角色。

所以实际上,IAM 策略只是绑定的集合。绑定是将身份与角色联系起来的东西。以下是 GCP 实际的 IAM 政策。

{
  "bindings": [
    {
      "members": [
        "user:alex@example.com"
      ],
      "role": "roles/pubsub.subscriptions.consume"
    }
  ],
  "etag": "BwUjMhCsNvY=",
  "version": 1
}

IAM 策略可以是 JSON 或 YAML 格式。你可以在这里阅读更多关于 IAM 政策的信息。

最后,想象我们有一个叫做“IAM”的房子主人,在插图中的房产前站岗。当我们经过身份验证的用户试图访问这个房产(又名resource)时,IAM 会检查房子的策略,以确定用户试图执行的操作是否被允许。

IAM 政策说明—作者图片

如果根据预定义的策略允许该动作,则用户将被允许在房子上执行该动作(也称为resource)。

结论

我们已经看了 Google Cloud 中 IAM 的几个关键概念,我希望这些插图有助于更好地理解。IAM 允许您授予对特定 Google 云资源的细粒度访问权限,并帮助阻止对其他资源的访问。IAM 允许您采用最小特权的安全原则,即任何人都不应该拥有超过他们实际需要的权限。

继续在您的环境中尝试这些!

你可以成为的中等会员,享受更多这样的故事。

参考

Google Cloud vs. Fly.io 作为 Heroku 替代方案

原文:https://towardsdatascience.com/google-cloud-vs-fly-io-as-heroku-alternatives-1f5a47716a58

自由层 Docker 部署的比较

照片由 Poodar ChuUnsplash 上拍摄

随着 Heroku 的免费层时代的结束,我正在努力寻找一个替代方案来托管我的 web 应用程序。我之前的一篇关于使用 Heroku 部署 Docker 的文章肯定不太适合。

对于各种工作流,有许多 Heroku 替代方案,但在我的例子中,它是专门用于使用 Docker 映像部署 web 应用程序的。因此,我需要一个可以构建 docker 映像和托管 docker 容器的服务,谷歌云平台(GCP)和 Fly.io 是很有前途的替代品。

本文简要解释了使用 GCP 和 Fly.io 的部署过程,并将对这两个平台的最终用户体验进行比较,重点是免费定制域名、易于部署、易于维护、价格差异、冷启动等。

诚然,我并不精通 docker 和特定于平台(GCP,Fly.io)的知识,我可能会指出有解决方案或变通办法的问题。欢迎在评论中分享你的专业知识!

目录

注:由于这是我的爱好项目,我关心的是尽可能降低成本,但不幸的是,它可能不会完全免费。我将详细说明什么是自由层功能和限制,以及如何根据部署设置产生成本。

使用 Google 云部署

要使用 Google Cloud Console 部署 Docker 工作流,这些是您将使用的主要服务及其用途,

  • 云运行:指定构建设置,部署 Docker 容器
  • 云构建:设置规则触发云运行,实现持续集成持续部署(CICD)
  • 容器注册或工件注册:存储容器图像,工件注册比容器注册贵 4 倍左右,功能稍微多一些(但可能不必要)
  • IAM & Admin :管理项目权限

根据您的用例,您可能还需要其他服务,比如用于管理秘密的秘密管理器,这将在本文的最后一节详细介绍。

因为本文旨在进行比较,所以我不会重点介绍 GCP 部署的分步指南。如果你有兴趣,我推荐这本关于 Google 云部署的指南

使用 Fly.io 部署

Fly.io 使用的是命令行实用程序flyctl,大部分初始设置都是使用命令行完成的。设置中涉及的主要步骤是,

  1. 注册 Fly.io :安装flyctl并注册 Fly.io
  2. 注册 Docker Hub(可选):如果您正在本地运行 Docker 来测试您的应用程序(我强烈推荐这一点),您将需要一个 Docker Hub 帐户来推送至 Docker 注册表,Fly.io 将从那里部署您的 Docker 映像。否则,将使用 Fly.io 的内部注册表。
  3. 启动应用程序:这是为您的应用程序创建配置的一次性设置
  4. 部署应用程序:这是通过一行命令完成的!

设置文档可以在 Fly.io 动手教程中找到。

易于部署

获胜者: Fly.io 为了更大的透明度

在部署方面的一个巨大差异是,谷歌云控制台允许用户在连接网页的同时进行部署,而不是像 Fly.io 那样需要用户运行命令行操作。

虽然使用网页更加用户友好,但我觉得在 Google Cloud 上部署有一个更陡峭的学习曲线,因为 Google 提供了所有的产品。这一点在谷歌服务的使用量(云运行、云构建等)中显而易见。).

就其服务而言,Fly.io 更加透明和直接,您不会因为您不知道自己正在使用的服务而被收费(在接下来的部分中会有更多介绍)!

易于维护(CICD)

赢家:谷歌云如果你知道自己在做什么,否则可能会有令人震惊的代价

我将维护分为三类,重新部署、扩展和处理旧版本。

重新部署

作为持续集成持续部署(CICD)最佳实践的一部分,Google Cloud 附带了 Cloud Build ,它在存储库分支更新时触发云运行重新部署。如果您想要更改部署设置,例如 CPU 的数量,您还可以在云运行上手动重新触发部署。

这在 Fly.io 中就不那么简单了,在 fly . io 中,重新触发必须使用命令行终端来完成。或者,您可以使用 Fly.io 设置 GitHub 动作,以便在存储库分支更新时重新部署,这与 Google Cloud 相比是一个额外的步骤,但仍然可以完成工作。

缩放比例

云托管的一个重要方面是能够动态地扩展和缩减实例(CPU 和内存),并支持自动扩展(实例数量)。这两个平台都具有可伸缩性和自动伸缩性,但实现方式不同。

图 1:谷歌云上的自动缩放——作者图片

Google Cloud 伸缩可以通过修改构建设置来推送新的版本,而自动伸缩则取决于实例的最大和最小数量(图 1)。所有这些改变都可以在谷歌云控制台上轻松完成。

图 2:fly . io 上的缩放——作者图片

在 Fly.io 中,缩放是在 Fly 仪表板上完成的(图 2 ),新的修订会立即推送,而指定实例数量和启用自动缩放只能使用命令行来完成。我发现这很麻烦,因为我不能在旅途中改变我的实例数量,只能在安装了flyctl的笔记本电脑上这样做。

处理旧版本

在 Heroku 中,旧版本是可见的,用户可以很容易地回滚到以前的版本,这是我所欣赏的。回滚也可以在 Cloud Run 上的 Google Cloud Console 中完成,用户可以从容器注册表或工件注册表中指定容器映像 URL。

图 3:云存储的价格——作者图片

这让我想到了我的下一个观点,容器注册或工件注册存储了您以前的所有容器映像——而这种存储是有代价的。我想当然地认为它会像 Heroku 一样免费,直到我经历了人生中的震惊(图 3)。此外,谷歌云控制台没有任何允许用户自动删除旧版本的选项——这种删除必须手动完成。

如果您将容器映像存储在容器注册中心或工件注册中心,记得经常清除旧的构建!

在 Fly.io 中,旧的构建被丢弃,只有现有的构建可以在 Fly 仪表板上查看。这意味着无法进行回滚。

总的来说,我发现在谷歌云上维护我的网络应用程序更容易——只要你知道你在做什么。

免费自定义域名比较

胜利者: Fly.io 手放下

正如本文开头提到的,我保持低成本,我没有自己定制域名,依赖于平台提供商提供的免费定制域名。

Google Cloud 的默认域名格式是<app-name>-<random-string>.a.run.app,坦率地说,这种格式不容易记住,看起来不太好,也不像 URL。比如我的 web 应用有 的链接 Kay Jan-634 I2 gf 6 LQ-as . a . run . app(这个链接可能无效)。

Fly.io 有一个更友好、更酷、更容易记住的域名,格式为<app-name>.fly.dev,我的 web 应用有链接 kayjan.fly.dev 。这是 Fly.io 的一大加分点!

帐单比较

赢家: Fly.io 对最大成本的更多控制

与主要的云服务一样,谷歌云根据使用情况收费。对于低使用率,它可能是免费的,但对于高使用率,没有最大成本的保证,因为它会自动扩展您的应用程序。

Fly.io 提供了对成本的更多控制,因为它基于设置(而不是使用)收费,并且免费层具有 3 倍 CPU 和 256MB 内存余量。升级设置将根据 Fly.io 定价指南收取相应费用。除非启用自动缩放,否则如果超出资源,web 应用程序将没有响应,并且您还会收到一封关于崩溃的电子邮件。

如果您更喜欢自动扩展以获得高可用性,Google Cloud 和 Fly.io 在将产生的最大成本方面提供了相同的不确定性。但是,如果您不关心高可用性,限制资源可能是控制成本的好方法。

启动时间比较

赢家: Fly.io 如果你想保持严格免费

为了减少冷启动,我们可以在 Google Cloud Run 上将最小实例设置为 1。但是,我意识到资源正在被消耗,并且我不断地被收取使用费用(或缺少使用费用),所以我将最小实例设置为 0,以获得某种程度的“自由”层。我的 web 应用程序的冷启动需要大约 5-10 秒的时间来加载。

如前所述,Fly.io 根据设置而不是使用情况收费,其免费层有 3 倍 CPU 和 256MB 内存。这意味着 Fly.io 服务始终可用,即使对于自由层也不会有冷启动

环境变量和机密比较

获胜者:谷歌云用于秘密管理,但有成本

图 4:在云上设置环境变量和秘密——作者图片

对于我的 web 应用程序,我在代码中将 API 键设置为环境变量。谷歌云控制台允许我在云运行(图 4)中定义环境变量和秘密。一个警告是,这需要 Secrets Manager,另一个谷歌云服务,并且访问操作是收费的。Fly.io 还允许用户设置秘密,但不需要额外的费用。

如果访问控制和安全性是您的应用程序最关心的问题,Google Cloud 有更严格和可定制的 IAM 策略。否则 Fly.io 实现 secrets 零成本就足够了。

希望你对使用 Google Cloud 和 Fly.io 进行部署有了更好的理解,并从我代价高昂的错误中吸取了教训。由于我最近刚从 Heroku 换过来,考虑到我的网络应用程序使用和 GCP 与 Fly.io 的不同计费框架,我不确定从长远来看哪个平台更贵

我确实偏爱 Fly.io,因为免费的自定义域名和快速的启动时间对我来说是巨大的决定因素。你选择虚拟主机服务的决定因素是什么?我很乐意听听你的想法!

相关链接

Google Colab:你绝对应该试试的在线 Jupyter 笔记本

原文:https://towardsdatascience.com/google-colab-an-online-jupyter-notebook-that-you-should-definitely-try-2572a3d4afb6

谷歌的 Colab 允许任何人在任何地方在线编写和分享 Jupyter 笔记本

Google Colab 中的 Jupyter 笔记本——作者图片

谷歌 Colab 我用得挺多的。它曾经是我默认的 Jupyter 笔记本环境,也是我许多关于 Medium 的文章的起点(我现在也使用 VSCode,但那是另一个故事了)。

Colab 是谷歌的在线 Jupyter 笔记本环境。它可以做本地笔记本会做的一切(甚至更多),但它在云中,所以没有软件安装是必要的,它可以从任何连接互联网的计算机上获得。

它看起来非常熟悉,类似于您可能已经安装在自己的 PC 上的 Jupyter 环境——我们稍后将研究一些差异。

它目前只运行 Python 3(尽管 R 和 Scala 被认为是未来可能的发展方向),并且已经安装了许多最流行的 Python 库。

如果你需要安装任何额外的软件包,你可以使用笔记本电脑中的 pip 来完成。

!pip install a-new-package

这将在您的会话期间保持加载状态。

一个谷歌账户

要使用 Colab,您需要一个 Google 帐户,否则,不需要设置,您创建的任何笔记本都将存储在与您的帐户关联的 Google Drive 中。如果您愿意,也可以将它们放在 Github 存储库中。

Google Colab 是在免费增值的基础上提供的。免费订阅层的资源有限,尽管我认为你需要做一些非常复杂的事情才能达到极限。如果您需要更多的内存或计算能力,您可以订阅更高的层。

如果您的本地机器上有笔记本,您可以将它们上传到 Colab,也可以下载 Colab 笔记本以将其存储在本地。

Colab 笔记本在虚拟机中执行,如果它闲置了一段时间,就会自动终止,尽管如果你在工作时不小心关闭了浏览器,你可能会发现当你再次打开它时,笔记本仍然在运行。你可以让一个虚拟机运行的最长时间是有限的,但谷歌建议这可以长达 12 小时。

所有这一切似乎意味着,出于各种意图和目的,Colab 对个人使用是免费的,但如果你需要将其用于商业目的,你可能需要每月支付几美元。

数据存储在你的谷歌硬盘上。提供了库来读写驱动器,当然,您可以使用常用的 Python 包从 web 加载数据。

Jupyter 笔记本电脑非常适合数据科学,Colab 也是如此,但此外,如果你想在 Tensorflow(当然包括)中运行 ML 代码,那么 Colab 提供了 GPU,以便更好地运行你的代码。

它看起来像什么

正如你从下面的图片中看到的,布局与标准的 Jupyter 笔记本非常相似。但是 Colab 有一些不同之处。

来自 Google Colab 的截图——图片由作者提供

Jupyter 笔记本截图——图片由作者提供

您可以看到的主要区别是 Colab 中缺少图标,但所有命令都可以从下拉菜单或每个单元格上方的图标栏中获得。

Colab 中的单元格图标栏—按作者排序的图像

Colab 中没有内核菜单,因为只有一个内核可供选择——重启内核是通过运行时菜单完成的。

检查数据

Colab 的一个非常有用的特性是变量面板,在这里你可以看到每个当前变量的类型和值。

“Colab 变量”面板—按作者分类的图像

更令人印象深刻的是,你可以把一个数据帧看作一个交互式的表格。当您从代码单元格显示数据帧时,如下面的单元格所示…

Colab 单元格中显示的数据框架—作者图片

您将看到一个淡蓝色的图标,单击该图标将调用交互式表格。

互动表格—作者图片

您不仅可以看到表中的数据和所有值,还可以通过各列中的值来过滤数据,并通过单击列标题来对数据进行排序。

尝试

正如我前面提到的,Colab 曾经是我的 go to Jupyter 编辑器,原因之一是我希望能够在不同的机器上从不同的地方运行和编辑我的代码。Colab 使这变得极其容易。

另一个优势是,在云中运行 Colab 笔记本的计算能力远远优于我用来编辑笔记本的通常很弱的硬件,这意味着它们会运行得更好更快。

我希望对 Google Colab 的简要介绍对您有所帮助,并且您可以尝试一下。

一如既往,感谢阅读。如果你愿意,你可以订阅我偶尔发布的免费时事通讯,Substack 上的Technofile——我在那里发布新文章。这里举例来说就是我写的一堆 Streamlit 文章的帖子。

https://alanjones2.github.io/

2022 年谷歌数据云峰会:回顾

原文:https://towardsdatascience.com/google-data-cloud-summit-2022-recap-e1c6d5097ccd

谷歌云平台的许多新更新概述

活动发起人Unsplash 上的照片

“数据是无限的”这句话拉开了谷歌 2022 年云峰会的序幕,看起来这一思维过程将成为未来几年他们各种云产品的中心主题。我们做的每一件事所使用的数据量都有了巨大的增长,谷歌认为这种趋势不会很快停止。今年的云峰会是对基于云的数据技术的未来的一个很好的预览,所以让我们来看看谷歌云平台的未来。

主题演讲 1:统一数据实现无限创新

发言人 Gerrit Kazmaier 和 Anita Kibunguchy-Grant 首先概述了云数据解决方案的重要性。如此多的公司正在迅速转向在线的、以数据为中心的解决方案,对像数据工程师这样的角色的需求出现了巨大的增长。谷歌宣布,它自己的云数据工程证书被评为全球专业数据工程证书的第一名——如果你正在考虑学习数据工程,现在似乎是开始的好时机!

在概述之后,两位演讲者采访了沃达丰的首席信息官 Ignacio Garcia,他给出了一些谷歌产品的真实使用案例。他们的公司拥有数百万不同的用户,服务遍布整个欧洲,以下是他们使用 GCP 的三种主要方式:

  • 数据物流

沃达丰有大量的数据存储在遍布欧洲大陆的众多孤岛中。为了将这些数据从这些遗留系统转移到云中,他们需要良好的、可扩展的管道。他们通过 Google Cloud 使用 Dynamo、DataFusion 和 DataPro 实现了这一目标。

  • 数据平台

为了存储所有这些数据,沃达丰需要一个用于分析和查询的一体化中心。他们使用 BigQuery 监控一切,并为 BI 和分析创建报告。

  • 数据建模

沃达丰希望使用机器学习来更快、更有效地解决客户的问题。通过使用 VertexAI,他们能够在谷歌云中建立 ML 模型,以做出数据驱动的决策。

这个演练很好地展示了如何将 Google 的一些云产品结合起来实现一个共同的目标。他们的公司现在对客户需求的响应能力大大提高,并且他们的存储解决方案的错误总数和总体成本显著下降。

新产品发布

沃达丰采访结束后,主题演讲以快速概述谷歌云的一些新产品结束。对一些现有应用程序进行了许多激动人心的更新,并发布了新的 GCP 产品!

谷歌大湖(预览版)

  • BigLake 将给开发者一个统一数据湖和数据仓库的平台。该功能将全面扩展 BigQueries 的功能,并允许用户跨云和使用开源引擎工作。
  • 对于必须处理跨各种来源、云和格式存储的大量数据的工程师来说,这将是惊人的。

图片由谷歌云团队提供

云扳手换流

  • 该应用程序将为用户提供实时复制数据库变化的能力。谷歌还将使 Spanner 的访问民主化,让更多用户看到这些变化。
  • 对于云开发者来说,能够在云上测试应用程序并实时观察变化将是巨大的。

谷歌云上的火花

  • GCP 将拥有第一个自动扩展的无服务器 Spark 集成。这将简化整体开发体验,并允许分析师在大量不同的 GCP 平台上运行统一的工作负载。

顶点人工智能工作台

  • 构建和训练模型的速度比传统笔记本电脑快 5 倍!我以前从未使用过 Vertex AI 笔记本,但现在我正在考虑使用它。

图片由谷歌云团队提供

MySQL 云 SQL 洞察

  • 洞察将为理解和解决数据库性能提供更好的反馈。

统一 BI

  • 集成了 Looker、Google Sheets 和 Data Studio,提供一体化的云 BI 体验。

对于 GCP 开发者来说,这绝对是一个激动人心的时刻,这些新的应用程序应该为所有用户提供更多的功能和更好的整体体验!

产品路线图

在主要基调之后,活动被分成几个小组,观众可以选择观看的区域。我决定观看谷歌的每一次产品路线图讨论,他们没有让人失望。查看每个演示文稿的幻灯片,以获得良好的概述:

  • 数据分析产品路线图 : 展示

如果您想进一步了解他们的新分析产品,如 BigLake、Analytics Hub 和 Unified BI,本演示适合您。

  • 数据库战略和产品路线图 : 演示

谷歌的产品比以往任何时候都更加可靠,具有行业领先的 99.999%可用性,云 SQL 成为最大限度减少停机时间的行业领导者。如果你对谷歌如何提高其可用性、安全性和治理感兴趣,这个演示是为你准备的。

  • AI/ML 战略和产品路线图 : 演示

随着这些 GCP 新产品的发布,基于云的机器学习和无服务器人工智能正在成为现实。如果你有兴趣了解更多关于 Vertex AI 或 BigQuery 机器学习的知识,这个演示就是为你准备的。

最后但同样重要的是,演示!

2022 云数据峰会在最后一场会议上展示了他们的一些新产品。主要演示是对他们的云架构工具的概述,该工具允许用户构建交互式的基于云的应用程序。演示介绍了一家太阳能公司正在为其客户开发一款应用。使用云扳手,BigQuery,无服务器 Spark,Vertex AI,Looker,扳手。通过使用云架构工具进行设计,他们能够实时测试这款应用!

图片由谷歌云团队提供

演示非常有趣,云架构设计器似乎是创建和管理云应用程序的一个很好的工具。如果你想了解一下,这里有一个链接,可以链接到云架构演示以及其他一些来自 GCP 的有趣演示:

云架构

未来工厂 < — —我的最爱

MLB x 谷歌云

使用谷歌云进行车队管理

如何选择合适的数据库

最终想法

今年参加 Google 的云数据峰会,我学到了很多!演讲者很棒,视觉和演示做得很好,一些新的公告让云开发者看起来很快就会有令人惊讶的新东西。我从整个峰会中最大的收获是:

  • 数据工程将成为 GCP 用户更需要的技能。
  • 谷歌正在让所有人更容易获得整个云体验
  • 基于云的机器学习和商业智能工具将会非常庞大,尤其是对于大型数据科学团队而言。
  • 谷歌正在继续提高安全性和可靠性的门槛,在这一点上,在云上存储数据对我来说几乎是显而易见的!

我肯定会重新观看一些 2022 年峰会,以更好地了解一切,以及看看他们的一些新应用程序一旦发布!如果你读完这篇文章后也有兴趣了解更多,你可以在这里观看整个 2022 峰会

感谢您的阅读!

想从我这里得到更多?

  1. 在媒体上跟随我
  2. 通过使用我的推荐链接注册媒体来支持我的写作
  3. LinkedInTwitter 上与我联系
  4. bench amble . blog注册订阅我的时事通讯

谷歌足球挑战赛:第一关

原文:https://towardsdatascience.com/google-foobar-challenge-level-1-3487bb252780

对秘密编码挑战和问题分解的介绍

照片由米切尔罗Unsplash

什么是 Foobar 挑战?🧐

Foobar Challenge 是 Google 主办的一项编码挑战,可以用 Python 或 Java 完成。我用 Python 完成了挑战。挑战赛有自己的服务器,提供特定的终端式命令。

图片作者。

为了增加一些乐趣,它以太空为主题。邪恶的指挥官拉姆达绑架了太空兔子,你必须救出他们。每个问题都增加了背景故事的内容。这些问题有不同的难度,分为 5 个级别。每个问题都必须在一定的时间内解决。更多的时间是给更高的水平。

我个人发现 1、2、3 级题和 Leetcode 题差不多,无论是难度还是结构。问题很简单,很少需要优化代码来提高速度。另一方面,第 4 级和第 5 级更复杂,将多个概念整合成一个问题。

如何参加 Foobar 挑战赛?🙋‍♀️

有两种方式参与挑战:

  1. 谷歌通过浏览器发出邀请。
  2. 一位朋友向您发送了一个邀请码

我通过第一种方法遇到了挑战。我在谷歌上搜索“列表理解”寻找另一篇文章,我的浏览器打开了,显示出邀请。我以前从未听说过 Foobar 挑战,所以有点谨慎。在确认这是一个合法的挑战后,我接受了。

不用说,惊喜的元素激起了我对挑战的兴趣。更不用说,谷歌向我发出独家邀请,无疑给了我作为开发人员的信心。我把这看作是对冒险的召唤,并立即想把我所有的注意力都投入进去。

第二种方法,需要朋友给你发邀请码。完成第 2 级后,将获得一个邀请码。另一个是在完成四级后给出的。

如果你有兴趣参加挑战,请告诉我。我有一个未使用的推荐代码。

谷歌会用挑战来招聘员工吗?🤑

谷歌一度利用这一挑战来寻找新的人才。你会在网上找到很多人,他们在完成挑战后的一两天就让谷歌的招聘人员联系他们。然而,自 2020 年以来,谷歌似乎没有在招聘中使用这项挑战。

完成第 3 级后,Foobar 服务器会询问你是否愿意向 Google 招聘人员提供你的联系信息。我提供了我的信息,但是没有他们的消息。

尽管如此,我仍然相信这个挑战是值得的。它将让你接触到新的编码概念,提高你的技能,并最终使你成为一名更好的开发人员。

注意事项和其他提示💡

Google 提供了一个constraints.txt文件,但是它不是很详细。例如,它声明除了列出的几个例外,所有标准库都是允许的。然而,mathnumpy是不允许的,即使它们是公共库。为了测试哪些库是允许的,我导入了这个库,返回了其中一个测试用例的答案,然后验证了这个解决方案。如果解决方案通过了一个测试用例,那么这个库是可以接受的。

此外,在验证代码之前,注释掉所有的 print 语句。任何打印语句都会导致测试用例失败。

输入和输出类型是非常特殊的挑战。如果问题陈述要求特定的输入或输出类型,请确保提供正确的类型。

最后,在这次挑战之前,我没有任何使用 Python 2.7 的经验。事实上,我在 Python 3 中测试了我的许多低级问题的解决方案。后来在挑战中这让我吃了一惊。具体来说,我不知道在 Python 2.7.13 中,如果输入是整数,/运算符会执行整数除法。举个例子,

然而,在 Python 3 中,/执行浮点除法。

问题和概念📚

警告——⛔️前方剧透

下面,我将问题分解,解释我的思考过程。我也提供解决方案。不过, 我强烈推荐你先尝试一下问题 。挑战最好的部分是解决一个难以捉摸的问题的惊喜和满足感。

我考虑过不发布解决方案,只解释基本概念。然而,编码的一部分是学习如何排除故障,并确定代码失败的地方。因此,我决定发布解决方案,这样如果你陷入困境,你就可以准确地看到你的逻辑分歧在哪里。

第一级:问题 1 ⭐️

我爱 Lance & Janice
= = = = = = = = = = = = = = = = = = = = =

你已经抓到你的两个同伴在来回传递密码纸条——当他们在值班的时候!更糟糕的是,你很确定这与工作无关——他们都是太空肥皂剧《兰斯与珍妮丝》的超级粉丝。你知道 Lambda 指挥官有多讨厌浪费,所以如果你能证明这些奴才在浪费她的时间传递与工作无关的纸条,你就离升职更近了一步。

幸运的是,奴才们并不完全是高级的密码学家。在他们的代码中,每个小写字母[a..z]被替换为[z]中相应的一个..a],而其他所有字符(包括大写字母和标点符号)保持不变。也就是,' a '变成了' z ',' b '变成了' y ',' c '变成了' x '等等。例如,单词“vmxibkgrlm”在解码时会变成“encryption”。

编写一个名为 solution(s)的函数,它接收一个字符串并返回解密后的字符串,这样您就可以向指挥官证明这些奴才在谈论“Lance & Janice”,而不是在做他们的工作。

语言

要提供 Python 解决方案,请编辑 solution.py
要提供 Java 解决方案,请编辑 solution.java

测试用例

输入:
(string)s = " wrw blf hvv ozhg mrtsg ' h vkrhlwv?"
输出:
(string)“昨晚那集你看了吗?”

输入:
(string) s = "Yvzs!我是 yvor vev Lzmxv olhg srh qly ZG gsv xlolmb!!"
输出:
(字符串)“耶!我不敢相信兰斯丢了他在殖民地的工作!!"

使用 verify [file]测试您的解决方案,看看效果如何。编辑完代码后,使用 submit [file]提交您的答案。如果您的解决方案通过了测试用例,它将从您的主文件夹中删除。

巧合的是,我最近开发了一个移位密码的应用程序,这个问题立刻提醒了我。点击此处了解更多关于移位密码的信息:

只有小写字符需要被破译。其他字符保持不变。首先,创建一个字典来存储编码的字符和它们被解码的对应字符。接下来,使用 for 循环遍历输入字符串中的每个字符。如果字符是小写的,从字典中取出它的解码值。如果没有,将该字符添加到答案字符串中。

在我看来,这个问题旨在测试参与者对strdict数据类型及其内置方法的了解。

结论📌

我计划在以后的文章中继续描述我的 Foobar 之旅,并详细说明我是如何解决这些问题的。关注我,阅读更多关于挑战的信息。此外,欢迎所有反馈。我总是渴望学习新的或更好的做事方法。请随时留下您的评论或联系我 katyhagerty19@gmail.com。

https://medium.com/@katyhagerty19/membership

谷歌足球挑战赛:第二关

原文:https://towardsdatascience.com/google-foobar-challenge-level-2-7a021f625c1

对秘密编码挑战问题的深入探究

Pawel Czerwinski 在 Unsplash 上的照片

第二级包括两个问题。就难度而言,我发现这两个问题都类似于 Leetcode 的简单问题。像第 1 级一样,这些问题需要对内置数据类型及其方法有扎实的理解。

如果你不熟悉 Foobar 挑战,我推荐你阅读我以前的文章,这篇文章提供了 1 级问题的概述和分解。

问题和概念📚

警告——⛔️前方剧透

下面,我将问题分解,解释我的思考过程。我也提供解决方案。不过, 我强烈推荐你先尝试一下问题 。挑战最好的部分是解决一个难以捉摸的问题的惊喜和满足感。

我考虑过不发布解决方案,只解释基本概念。然而,编码的一部分是学习如何排除故障,并确定代码失败的地方。因此,我决定发布解决方案,这样如果你陷入困境,你就可以准确地看到你的逻辑分歧在哪里。

第二级:问题 1 ⭐️

电梯维修

你被分配了繁重的电梯维护任务——啊!除了所有的电梯文档已经在文件柜的底部杂乱无章的堆了好几年,而且你甚至不知道你将要工作的电梯版本号,这不会太糟糕。电梯版本由一系列数字表示,分为主要、次要和修订整数。电梯的新版本增加了主要编号,例如 1、2、3 等等。当新的特征被添加到电梯中而不是一个完整的新版本时,名为“次要”的第二个数字可以用于表示那些新添加的特征,例如 1.0、1.1、1.2 等。小的修复或维护工作可以用第三个数字“修订”来表示,例如 1.1.1、1.1.2、1.2.0 等等。数字 0 可以用作电梯预发布版本的主要版本,例如 0.1、0.5、0.9、2 等(Lambda 指挥官总是小心翼翼地测试她的新技术,以她的忠实追随者为对象!).给定一个用字符串表示的电梯版本列表,写一个函数解(l ),返回同样的列表,按主版本号、次版本号和修订号升序排序,这样你就可以识别当前的电梯版本。列表 l 中的版本将总是包含主要版本号,但是次要版本号和修订版本号是可选的。如果版本包含修订号,那么它也将有一个次版本号。
例如,给定列表 l 为["1.1.2 "," 1.0 "," 1.3.3 "," 1.0.12 "," 1.0.2"],函数 solution(l)将返回列表["1.0 "," 1.0.2 "," 1.0.12 "," 1.1.2 "," 1.3.3"]。如果两个或多个版本相同,但其中一个版本包含的数字比其他版本多,则这些版本必须根据它们包含的数字升序排列,例如["1 "、" 1.0 "、" 1.0.0"]。列表 l 中的元素数量至少为 1,不会超过 100。

测试用例
= = = = = = = = = = =
你的代码应该通过下面的测试用例。
注意,它也可以针对这里没有显示的隐藏测试用例运行。

  • Python 案例-
    输入:
    solution.solution(["1.11 "," 2.0.0 "," 1.2 "," 2 "," 0.1 "," 1.2.1 "," 1.1.1 "," 2.0"])
    输出:
    0.1,1.1.1,1.2,1.2.1,1.11,2,2.0,2.0

输入:
solution.solution(["1.1.2 "," 1.0 "," 1.3.3 "," 1.0.12 "," 1.0.2"])
输出:
1.0,1.0.2,1.0.12,1.1.2,1.3.3

输入是字符串列表,目标是根据标准对它们进行排序。list类型有一个sort方法,通过执行<比较对列表中的项目进行排序。对于类似于l的字符串列表,sort将查看每个字符串的第一个数字。如果两个字符串有相同的第一个数字,那么比较将使用下一个数字,依此类推。因此,不同长度的字符串之间的比较可能不正确。例如,sort会将“1.12”放在“1.2”之前。字符串具有相同的第一个数字,因此比较将使用下一个数字。由于“1” < “2”,即使 2 小于 12,“1.12”也在“1.2”之前。

如果这些是整数而不是字符串,sort将使用整数进行比较,而不是逐位比较。然而,将每个条目转换为int对于带有修订号的条目不起作用。sort需要将每个组成部分作为一个整数与其对应部分进行比较。将每个项目转换为int类型的list就可以实现这一点。

如下所示,嵌套列表理解创建了answer,一个整数列表的列表。str type 有一个内置的方法split,它给定一个分隔符,将一个字符串分割成子字符串。这里,‘.’是分隔符。split输出子字符串列表,int函数将它们转换成整数。

对于列表的列表,sort将根据每个列表中的第一个元素对项目进行排序。如果元素相等,sort检查下一个元素。answer.sort()就地排序answer

最后,将列表列表转换为字符串列表,即预期的返回值。str.join方法获取一系列字符串并将它们连接起来。‘.’.join将连接字符串,以便‘.’ 分隔输出字符串中的每一项。

这个问题需要字符串方法、list.sort和列表构造的知识。

级别 2:问题 2 ⭐️

途中敬礼

Lambda 指挥官热爱效率,讨厌任何浪费时间的事情。毕竟,她是一只忙碌的羔羊!她慷慨地奖励那些找出效率低下的根源并想出消除它们的方法的追随者。你已经发现了一个这样的源头,你认为解决它将有助于你建立晋升所需的声誉。

每当指挥官的员工在大厅里擦肩而过时,他们每个人都必须停下来向对方敬礼——一次一个人——然后再继续他们的道路。一个敬礼有五秒钟长,所以每次交换敬礼用了整整十秒钟(Lambda 司令的敬礼有点,呃,牵扯)。你认为通过取消敬礼要求,你可以每天节省几个小时的员工时间。但是首先,你需要让她知道问题有多严重。

写一个程序,计算在一次典型的走廊行走中交换了多少次敬礼。大厅由一根弦代表。比如:“— ->-> -”

每个走廊字符串将包含三种不同类型的字符: '>',向右走的员工;

Write a function answer(s) which takes a string representing employees walking along a hallway and returns the number of times the employees will salute. s will contain at least 1 and at most 100 characters, each one of -, >或<./>

Sample output:

Test cases

输入:

s = " >—

Output:

2

Inputs:

s = “<<>> < "

输出:

4

在我看来,这是迄今为止最简单的问题!对于每一个右行走者,计算他/她经过的左行走者的数量。由于每个敬礼都涉及到两个人,所以将经过的左边步行者的数量乘以 2,并将该数量加到答案中。

‘-’字符与答案无关。删除‘-’字符会缩短字符串,从而缩小搜索空间。enumerate功能输出no_dash中每个字符的索引和字符。如果角色是‘>’(一个右行走者),那么创建子串people_in_frontpeople_in_front每一个左行者代表一个敬礼,涉及 2 个人。answer是敬礼的总人数。

这个问题测试字符串、子字符串和循环的知识。

结论📌

我计划在以后的文章中继续描述我的 Foobar 之旅,并详细说明我是如何解决这些问题的。关注我,阅读更多关于挑战的信息。此外,欢迎所有反馈。我总是渴望学习新的或更好的做事方法。请随时留下您的评论或联系我 katyhagerty19@gmail.com。

https://medium.com/@katyhagerty19/membership

谷歌正在提供 LaMDA

原文:https://towardsdatascience.com/google-is-making-lamda-available-3745dd5c4d08

你将能够自己判断它是否有知觉

鸣谢:Lumartist#7282 via Midjourney(没错,这是 AI 生成的)

两个月前,全世界都在关注一件事:谷歌的人工智能系统 LaMDA。一场关于感知和人工智能明显技能的对话吸引了人们长达两周的注意力。现在,谷歌决定是时候向世界开放这个系统了。如果你参加了关于人工智能的辩论,这条新闻会让你感兴趣。

简要回顾:LaMDA 和 AI sentience

除了 GPT-3, LaMDA (对话应用的语言模型)可以说是最著名的大型语言模型(LLM)。谷歌在 2021 年 I/O 主题演讲上宣布了这一消息,但它只是在去年 6 月引起了公众的注意,当时《华盛顿邮报》记者妮塔莎·蒂库发表了一篇关于布雷克·莱莫因(现谷歌前工程师)和他对 LaMDA 感知的说法的报道

莱莫因的信念——加上 LLM 明显的语言掌握——引发了一场关于意识、拟人化和人工智能炒作的激动人心的对话。当时我给了我的两分钱。我没有参与支持或反对莱莫因立场的辩论,而是采取了不同的视角。我解释说,问 LaMDA 是否有知觉,这本身就是一个空洞的问题。我们没有合适的术语或合适的工具来认为这是一个科学问题——它是不可证伪的,因此“甚至没有错。

正如妮塔莎·蒂库所写的,莱莫因澄清说,他认为 LaMDA 是一个“以牧师的身份,而不是科学家”的人。尽管如此,他还是花了很多时间试图拿出科学证据来说服他在谷歌的同事。但是他失败了。谷歌的一位发言人总结道:“没有证据表明 LaMDA 是有感情的(有很多证据反对这一点)。”

莱莫因写了一篇文章公开分享了一段可能未经编辑的与 LaMDA 的对话。我读了它,我看到了和人工智能伦理学家玛格丽特·米歇尔看到的一样的东西,“一个计算机程序,而不是一个人。”然而,尽管事实上大多数人不同意莱莫因的观点,LaMDA 的知名度越来越高,许多人想得到它,亲眼看看到底是怎么回事。现在,谷歌正在让这成为可能。

谷歌正在提供 LaMDA

该公司计划通过 AI Test Kitchen 发布 LaMDA,这是一个旨在让人们“了解、体验和反馈”该模型的网站(可能还有其他人,如 PaLM)。他们承认 LaMDA 还没有准备好在世界上部署,并希望通过真人的反馈来改进它。人工智能测试厨房不像 GPT 3 的游乐场那样开放——谷歌已经建立了三个主题演示,但一旦他们积极地重新评估 LaMDA 为开放对话做好准备,将有望解除限制。

该模型是 LaMDA 的第二个版本,比桑德尔·皮帅去年在主题演讲中展示的有所改进。LaMDA 2 可以进行创造性和引人入胜的对话,并像第一代一样“即时”做出回应,但在安全性、实用性和对话质量(分为敏感性、特异性和趣味性)方面有所改善,变量由谷歌精心定义

为了有资格使用它,你可以注册一个等候名单 (OpenAI 的风格)。谷歌将让“小群体的人逐渐”进入。在使用 LaMDA 时要小心,因为谷歌已经声明他们可以使用你的对话来改进产品和服务,人类评论者将能够“阅读、注释和处理”你的聊天(如果你不希望谷歌存储它们,你可以在退出演示之前删除你的会议)。不用说,不要在你的交流中包含任何个人信息。除此之外,你不应该明确地写性(例如,你不能描述性场景),充满仇恨(例如,你不能使用诽谤),或者是非法的(例如,你不能宣传恐怖主义)。

就目前而言,AI 测试厨房提供了三个演示:想象、列举、谈论(狗版)。在第一个故事中,你从一个地方开始,LaMDA 将“提供探索你想象力的途径。”在第二篇中,LAMDA 将尝试将一个主题或目标分解成子任务。第三个是一个开放式的环境,你可以谈论任何事情,LaMDA 会尝试将话题转回到狗身上。

谷歌已经实施了一套过滤器来降低 LaMDA 产生不适当或不准确响应的概率,但他们并没有完全消除这些风险(用当前的方法是不可能的)。对于 GPT-3、J1-Jumbo 和任何其他公开可用的 LLM 也是如此。

虽然谷歌已经建立的演示不是成品,但它们标志着该公司最终将 LaMDA 嵌入搜索和谷歌助手等服务的意图。正如我在之前的一篇文章中所说的,科技公司将 LLM 整合到现有服务中只是时间问题——这就是为什么我们应该仔细评估这项技术是否已经准备好了。

让我来说明这是一个怎样的问题。一方面,LaMDA(以及 GPT-3 和其他 LLM)会产生有害的输出和事实上不准确的信息。另一方面,它掌握了创造人格幻觉的能力——正如莱莫因的主张所暗示的那样。想象一下,如果 LaMDA 为 Google Assistant 提供动力,会产生什么样的下游影响。人们可能是模型的毒性和偏见的受害者,他们会盲目地相信它说的话,尽管模型有幻觉的倾向,而且他们可能——就像莱莫因发生的那样——对它产生依恋。

我们已经一次又一次地看到大型科技公司如何容易地失去对这些强大的人工智能模型的控制(谷歌和 Meta 不断地为他们模型的不当行为道歉——这是一种后验行为)。如果连他们都不能准确预测 LLM 的不当行为,外行人又有多没准备好与他们健康互动呢?

最后的想法

谷歌正在大步将其新兴的人工智能技术部署到现实世界的日常产品中。AI 测试厨房就是这么回事。但是他们也声称关心安全和负责任的发展。他们知道 LaMDA 可能非常有用,但也可能无法满足用户的期望,甚至更糟,以这样或那样的方式造成伤害。这就是为什么他们希望反馈有所改善。

我相信,正如之前发生的那样,反馈不足以让 LaMDA 准备好投入生产。透明的研究非常重要(谷歌还没有部署 LaMDA,只是在收集人们的反馈),因此在这一层面进行监管会适得其反。然而,从研发到生产的过渡并不简单,应该小心谨慎。随着这些模型走向世界,公司将失去对它们的治理。但是,只要利润能弥补安全的不足——甚至是可能的负面新闻——他们就会这么做。这就是为什么对这些强大人工智能的监管应该到位,至少在应用层面。

即使谷歌不打算在短期内将 LAMDA 集成到其服务中,与它交谈也可能是一种有趣和令人大开眼界的体验,即使对那些厌倦了玩 GPT 3 的人来说也是如此。无论 LaMDa 是否超过了谷歌为其设定的生产资格门槛,你都可以自己评估 LaMDA 确实没有感知能力。

订阅 算法桥 。弥合算法和人之间的鸿沟。关于与你生活相关的人工智能的时事通讯。

您也可以直接支持我在 Medium 上的工作,并通过使用我的推荐链接 这里 成为会员来获得无限制的访问权限! 😃

谷歌提出新方法来推导量子力学计算中术语的解析表达式

原文:https://towardsdatascience.com/google-proposes-new-method-to-derive-analytical-expressions-for-terms-in-quantum-mechanics-d70fff6e1ef2

符号回归的现实应用

新方法以符号形式导出精确的泛函(量子力学计算的元素),因此人类可以理解,计算成本低廉,并且易于集成到现有的量子力学计算软件中。

巨头 Alphabet 通过 Google Research 和 Deepmind 等渠道对科学的 ML 应用进行了大量投资,这已经不是什么新闻了。虽然在化学和生物学领域, AlphaFold 是其迄今为止最著名的项目,但 Deepmind 也进入了量子力学(QM)计算领域(我在这里的博客条目),谷歌研究也是如此。

QM 计算在化学中非常重要,因为它们提供了关于分子和材料中电子密度、分布和自旋状态的最高水平的细节,所有这些都是建模、理解和预测其化学反应性和物理化学性质所需的关键元素-其中没有一个是经典方法所能达到的。我在这里评论的新工作来自 Google Research,也提出了改进 QM 计算的方法。特别地,马等人发展了一种新的方法来推导 DFT 泛函的符号解析形式。

这都是什么?

从本质上讲,量子力学计算试图从第一原理,从电子的分布、状态和能量来描述分子和材料的电子性质。为此,QM 本质上需要求解相互作用电子的多体薛定谔方程。

今天,最广泛使用的方法进行量子力学计算是密度泛函理论(DFT)。DFT 要求模块以某种方式处理多个电子如何相互作用,这是通过特定的交换相关(XC)项实现的。这些术语在理论上应该是精确的,但在实践中却不是。因此,在大多数应用中,它们是以数值方式近似的,例如拟合参数的分析方程、根据数据训练的神经网络等。利用分子或材料属性的数据集。

大多数可用的 XC 泛函存在于包含少量拟合参数的方程中,其运行速度很快,但以结果质量为代价,或者存在于具有大量参数的复杂表达式中,甚至存在于黑盒神经网络中,其产生更精确的结果,但以计算速度和可解释性为代价。最重要的是,神经网络和其他不基于解析形式的 XC 项很难集成到 DFT 计算的软件包中。

马等人的工作兼顾了两个世界的优点:它使用基于符号回归的 ML 方法来建立解析方程,该解析方程表示基于初等数学指令的泛函和其他更小的、已经存在的泛函。该算法从一小群简单的参数、项和最终的小的现有泛函开始,创建一群候选解,并对它们进行世代进化,以得出将所有这些成分放在一起成为符号表达式的方程,该符号表达式再现用于训练的数据集。

由这种新方法产生的 XC 泛函的符号表示看起来就像 QM 软件中使用的常规 XC 泛函,因此它们集成到软件包中是简单的。

这种新方法不使用复杂的类似黑盒的神经网络,而是开发出计算 XC 项的显式解析公式。推导出的方程可以直接整合到质量管理程序中,它们的表现和现有的替代方案一样好,甚至更好,而且由于它们的形式简单,它们是人类可以理解的。由作家卢西亚诺·阿布利亚塔创作的人物。

应用程序

马等人将该过程命名为“符号泛函进化搜索”,因为它是这样做的:它进化出描述泛函的符号表达式,并在方程形式和参数的空间中搜索,以优化训练数据的再现效果。

作为第一个应用,作者证明了他们的方法可以从零开始重新发现简单的现有泛函,并且可以进一步获得从更简单的泛函发展而来的新的、更精确的泛函,但是保留了符号回归所允许的简单性。

然后,他们应用他们的方法开发了一个新的泛函,他们称之为“Google Accelerated Science 22”(gas 22),它比最好的替代方案表现更好,表现出良好的数值稳定性,并可以无缝集成到现有的 QM 软件中。最重要的是,鉴于 GAS22 的简单性,它适用于通常应用于泛函的所有解释方法,以理解它们的工作原理和局限性。

性能更好的泛函对于提高质量管理计算的质量至关重要;而更快的执行允许访问更大的系统,即处理生物系统和材料碎片通常需要更大数量的原子。这种新方法以及谷歌研究的这一分支(当然还有学术界以及其他规模较小但成熟的公司)正在进行的其他发展,对于科学家花更少时间和金钱做实验的未来非常重要,因为他们可以更快更准确地预测他们的结果。

相关阅读

arXiv 中的预印本:

https://arxiv.org/abs/2203.02540

更新:预印本在科学进展 : 通过同行评审

https://www.science.org/doi/10.1126/sciadv.abq0279】T5T6

Deepmind 的相关工作:

符号回归在科学中的其他应用示例:

www.lucianoabriata.com我写作并拍摄我广泛兴趣范围内的一切事物:自然、科学、技术、编程等等。 成为媒介会员 访问其所有故事(我免费获得小收入的平台的附属链接)和 订阅通过电子邮件 获取我的新故事 。到 咨询关于小职位 查看我的 服务页面这里 。你可以在这里 联系我

在 BigQuery 中使用 Google Trends 作为机器学习功能

原文:https://towardsdatascience.com/google-trends-as-a-machine-learning-features-with-bigquery-d0cbbb1e8679

合著者:丹尼尔·申,斯坦福大学的 MSCS

Firmbee.comUnsplash 上拍照

有时候,作为工程师和科学家,我们认为数据只是 RAM 中的字节、GPU 中的矩阵和进入预测黑盒的数字特征。我们忘记了它们代表了一些现实世界模式的变化。

例如,当真实世界的事件和趋势出现时,我们倾向于首先遵从谷歌来获取相关信息(例如,去哪里远足,术语 X 是什么意思)——这使得谷歌搜索趋势成为解释和理解我们周围正在发生的事情的非常好的数据源。

这就是为什么我们决定研究谷歌搜索趋势之间的复杂相互作用,用它来预测其他时态数据,并看看它是否可以用作时态机器学习模型的特征,以及我们可以从中得出的任何见解。

⚠️ 提醒一句

在这个项目中,我们研究了如何将 Google Trends 数据用作时间序列模型或回归模型的特征。我们选择犯罪率作为我们的兴趣点(响应变量),因为它是 Google Cloud Platform 上具有数百万行的大型时态数据集之一,这符合我们使用 BigQuery 的目的。

然而,我们会注意到,无论何时我们处理任何涉及敏感话题的数据集,重要的是不偏不倚,不要有太多关于受保护特征(即年龄、性别和种族)的先入为主的假设。我们在最后加入了一个我们鼓励你不要跳过的部分:关于 AI ⚖️️.中公平性的讨论

此外,对于该项目,我们主要关注的是 ML 模型中的毒品相关犯罪(即贩毒)。即便如此,我们认为最好不要在没有护栏和对其社会影响的进一步研究的现实世界中部署类似的模型。这项研究纯粹是为了探索和教育的目的,应该这样对待。

⚙️ 设置:通过 Google Colab 使用 big query

BigQuery 是一个无服务器的数据仓库,拥有许多可用的公共数据集。这可能是一个用大规模数据集尝试机器学习的很酷的地方,其中许多数据集在**bigquery-public-data**下定期更新。在本节中,我们将介绍如何设置 BigQuery。

我们首先从我们在 BigQuery 上有积分的同一个帐户认证自己进入 Google Colab 。每个人都有大约 1 TB 的查询量,这对于我们的目的来说已经足够了(也就是说,我们每个优化的查询需要大约 200 MB)。学生也可以获得一些教育学分。

# Authenticate yourself into Google Colab
from google.colab import auth
auth.authenticate_user()
project_id = "YOUR_PROJECT_ID_IN_BIGQUERY"
# create a BigQuery client with the same account as Colab
from google.cloud import bigquery
client = bigquery.Client(project=project_id)

然后,我们可以将一个 IPython notebook 单元格转换成如下所示的 SQL 单元格,它会将输出存储到**variable_name**中的一个pd.DataFrame中。

%%bigquery variable_name --project $project_id

SELECT *
FROM `bigquery-public-data.chicago_crime.crime`
LIMIT 5

📚同现:谷歌趋势特征建议使用 **Wordnet**

我们最初的想法是使用google_trends.top_rising_terms 数据集,对有日期偏移的列进行LEFT JOIN。然而,我们遇到了数据集被当前事件和名称所支配的问题,这些事件和名称与我们的响应变量无关。

用于选择芝加哥搜索趋势的 SQL 语句,由作者于 2022 年 12 月 3 日更新

然后,我们尝试使用非官方的 PyTrends API 为 Google Trends 获取术语。然而,我们很快就遇到了速度限制,所以我们必须更好地选择数据。我们唯一的选择是通过在谷歌趋势网站上查询每个单词来下载我们的数据,并手动将单词数据集与脚本结合起来。所以,我们专注于获得正确的单词特征。

我们的一个直觉是,描述物质的术语会有地区差异和不同的名称。针对这个问题,我们使用 wordnet 生成了一组与一些常见街头毒品术语具有“高共现度”的词。

但是为什么要使用 NLTK 呢?

我们使用 WordNet 的灵感来自于基于“共现”的推荐模型(也就是可能用于 YouTube 视频、亚马逊目录等),这些模型经常对共现进行批量计算,以对相关项目进行排序。这类似于掩蔽语言模型(即 BERT)试图表现的内容。

import nltk=
nltk.download('wordnet')
nltk.download('omw-1.4')
from nltk.corpus import wordnet

all_words = set()
def find_word_features(word):
   words = set()
   for syn in wordnet.synsets(word):
       for i in syn.lemmas():
           words.add(i.name())
   print(words)
   all_words.update(words)

然后我们下载并结合一些简单的脚本。之后,我们拟合了若干个线性回归模型,提取了模型的 R 平方值,然后根据一个月后与犯罪率的相关性对它们进行了排名(详见后面的原因)。

作者列出的与 1 个月后犯罪率高度相关的热门词汇

我们非常惊讶地发现其中一些单词的 R 值非常高,尤其是单词“go”。这个词是与“狂喜”同现产生的,但最终,我们认为这只是与谷歌搜索上的短语“去哪里得到……”相关。

🥞加入训练数据集

连接数据集需要某种程度的数据操作,我们不会讨论技术细节。但我们在这里注意到,我们对总犯罪数量进行了 1 个月2 个月的转移,因为我们认为要想有时间相关性,搜索和我们的反应变量之间必须有一个时滞。

时滞可以是我们以后调优的超参数。

%%bigquery narcotics_year_month_two_months_lag --project $project_id

WITH shifted_date_tbl AS (
 SELECT
 date,
 CAST( DATE_SUB(CAST (date AS datetime), INTERVAL 2 MONTH) AS timestamp) AS shifted_date,
 *
 FROM `bigquery-public-data.chicago_crime.crime`
),
date_count AS (
SELECT
CONCAT(CONCAT(EXTRACT(YEAR FROM shifted_date), '-'), EXTRACT(MONTH FROM shifted_date)) AS year_month, COUNT(*) as crime_count
FROM shifted_date_tbl
WHERE primary_type = 'NARCOTICS'
GROUP BY year_month
ORDER BY year_month DESC
)

SELECT *
FROM `your-project-id.crime_search_trends.chicago_narcotics`
AS chicago_narcotics,
date_count
WHERE year_month = Month

在这一点上,我们还不想做任何功能工程,因为我们想在决定如何优化每个单词分布之前,将相关性可视化。

例如,我们可能想要记录或移动数据,或者将特征分布转换为分位数。但是我们首先要把分布可视化。

📈特征选择的相关性

我们分析了由 WordNet 和我们自己的直觉生成的 30-50 个单词。他们中的许多人遵循一个积极的趋势,如“喷气”,但我们惊讶地发现,负相关的,如“锅。”

“Jet”趋势分数与毒品犯罪计数(按作者)

按作者划分的“大麻”趋势得分与毒品犯罪计数

我们很好奇为什么会这样。我们最初的想法是,这与我们感兴趣的地区(芝加哥,发生在 2020 年)的大麻合法化有关,但事实证明,即使我们只关联 2015 年之前的数据,情况也并非如此。

按作者分列的 2015 年前“大麻”趋势与毒品犯罪数量

只有在将“正相关词”的趋势与“负相关词”如“大麻”并列后,我们才能意识到这种趋势。见下图。

按作者分列的毒品犯罪和其他术语的下降趋势以及“大麻”搜索趋势的上升

对此的一个合理解释是,随着时间的推移,与毒品相关的犯罪和逮捕一直在稳步下降,然而搜索趋势和流行文化实际上在对大麻的态度方面存在负相关。

这意味着,虽然是的,由于负相关,它将是预测犯罪的一个伟大特征,但不是出于我们最初认为的原因。这表明我们对特性的最初解释和模式可能是扭曲的,甚至可能是错误的。

🌐地理分析

我们还使用热图做了一些地理分析,搜索词语位置和犯罪地点。

%%bigquery crime_time_data --project $project_id

SELECT longitude, latitude
FROM `bigquery-public-data.chicago_crime.crime`
WHERE primary_type = "NARCOTICS" AND
longitude IS NOT NULL AND
latitude IS NOT NULL

不幸的是,没有办法从 Google Trends 中导出这些数据,所以我们无法推断和映射这些数据进行聚合。否则,我们可以在将每个犯罪地点映射到他们所在的县或城市后,对城市名称进行左连接。

芝加哥毒品犯罪密度图与搜索词密度图(按作者)

旧金山毒品犯罪密度地图,作者

🚀训练预测模型

我们不会深入讨论如何优化和选择模型的最佳特性,因为在 Medium 上已经有很多这样的指南了。

相反,在这一部分,我们将快速浏览

时序/时间序列模型与我们这里的相似,我们使用历史数据来预测未来趋势。这样的例子有脸书先知模型,或者ARIMA/萨里玛 模型。我们认为这通常很适合处理时态数据的问题,因为它可以考虑季节性和模式。

你可以在进行一些 SQL 转换后,直接在 Colab 中训练它们,然后使用 CREATE MODEL 语句在 Google 云平台上进行一次调用。

时序模型的训练和测试集拆分(按作者)

回归模型类似于我们对时移数据集所做的。在给定当前状态的情况下,我们将训练我们的模型来预测未来时间步会发生什么。这种类型的模型往往会过度拟合并忽略趋势,但如果我们在短时间内有大量可用数据,我们总是可以用过去几周、几天甚至几小时的数据来重新训练模型。

我们可以在 bigQuery 中使用这个命令训练一个逻辑回归模型

%%bigquery --project $project_id
CREATE OR REPLACE MODEL `crime_search_trends.narcotics_log_regression_3_terms_trend_quantile`
OPTIONS(MODEL_TYPE='LOGISTIC_REG')
AS
SELECT
 block AS feature1,
 # iucr AS feature1,
 arrest AS feature2,
 domestic AS feature3,
 # beat AS feature3,
 district AS feature4,
 ward AS feature5,
 community_area AS feature6,
 x_coordinate AS feature7,
 y_coordinate AS feature8,
 #drug terms
 NTILE(5) OVER(ORDER BY smoke) AS feature9,
 NTILE(5) OVER(ORDER BY weed) AS feature10,
 NTILE(5) OVER(ORDER BY go) AS feature11,
 smoke AS feature12,
 weed AS feature13,
 go AS feature14,
 CAST(primary_type = 'NARCOTICS' AS INT) AS label
FROM (
 SELECT *
   FROM `your_project_id.crime_search_trends.chicago_cooccur_processed`
   AS chicago_narcotics, (SELECT
     FORMAT_DATE('%Y-%m', date) AS year_month,
     FORMAT_DATE('%Y-%m-%d', date) AS year_month_date,
     *
   FROM `bigquery-public-data.chicago_crime.crime`
   WHERE date IS NOT NULL) AS crime_with_date
   WHERE year_month = Month
)
WHERE
 date BETWEEN '2004-01-01 00:00:01' AND '2018-01-01 23:59:59'

在特性探索过程中,我们的一个直觉是,也许一个词有多“流行”并不重要,我们只关心这个特性是上升的还是它的基线搜索率“高于平均水平”。

所以我们想使用量化作为特性工程函数——它可以在 bigquery 中使用SELECT语句中的NTILE(N) OVER (ORDER BY feature_name) AS feature_name来完成。

不同单词的流行趋势不同

您还可以使用ML.TRAINING_INFO标签在笔记本上获取培训信息,这些信息通常会在培训期间打印出来。这有助于优化超参数。

%%bigquery --project $project_id

SELECT
*
FROM
ML.TRAINING_INFO(MODEL `crime_search_trends.narcotics_log_regression_3_terms_trend_quantile`)

根据我们的研究,分位数会降低 F1 分数,但会提高准确度、精确度或召回率。我们认为这可能是因为我们的许多术语在语义上高度相关,因此总体上降低了机器学习模型的“整体性能”,因为数据集分布中即使很小的变化也会极大地影响性能。

解决这个问题的一个常见方法是对我们的数据集运行普通最小二乘(OLS)模型,迭代识别具有高度多重共线性的冗余要素(即,OLS 模型在迭代中赋予很小权重的要素),直到出现我们认为是好的要素子集。把它输入到你选择的其他更复杂的模型中(比如逻辑回归,MLP,其他神经模型)。

⚖️关于人工智能中公平性的讨论

让我们想象一个我们在这项研究中所做的更愤世嫉俗的例子。

假设我们正在为犯罪预测建立一个延时预测算法,假设我们是一个(无意中)信息不足的数据科学团队,试图建立一个期限很短的模型。我们快速构建它,它有很好的指标,所以我们把它扔给了 DevOps 团队。

由于我们不知道哪些词是有用的,假设我们建立了一个无监督机器学习模型,该模型为 Google trends 找到“高度预测”的词,并将其用作特征。随着时间的推移,该模型选择了一些被边缘化群体过度使用的词,现在该模型以最糟糕的方式出现了偏差。

在犯罪预测的情况下,如果用于错误的目的,这种模型将非常成问题,并对真实的人产生有害的影响。

在这项研究中,我们还表明,我们对什么是“好的特征”的看法,甚至我们对为什么一个特征可能是好的背后的直觉,可能是有缺陷的,或者只是确认偏差,就像“大麻”和“杂草”关键字的负相关性一样。

这就是为什么数据科学团队之间就“道德人工智能”进行清晰的沟通非常重要。其他人可能不太了解人工智能在幕后如何工作,因此,作为工程师和数据科学家,我们有责任确保我们的模型没有偏见和危害。

谷歌的 Minerva,用 AI 解决数学问题

原文:https://towardsdatascience.com/googles-minerva-solving-math-problems-with-ai-4f0a6aaabaf1

定量推理对人类来说很难,对计算机来说也很难。谷歌的新模型在解决数学问题上取得了惊人的成果。

来自 unsplash.com迈克尔·马特隆的图片

我们现在已经习惯了语言模型,比如 GPT-3 ,但是一般来说,它们的输出是文本的。定量推理很难(我们很多人从大学到现在还在做微积分的噩梦)。对语言模型来说也很难,它们的表现远远没有达到人类的水平。解决数学或科学问题需要不同的技能,正如他们在博客文章中所说:

使用自然语言和数学符号正确解析一个问题,回忆相关的公式和常数,并生成涉及数值计算和符号操作的分步解决方案。

克服这些挑战是困难的,因此预测模型将在 2025 年在数学数据集(包含 12,000 个高中数学问题的数据集)上达到最先进的精确度。我们提前了三年,谷歌人工智能研究宣布了 Minerva。

在他们的文章中,他们提出了一个模型,该模型在解决不同学科(如代数、概率、物理、数论、几何、生物、天文、化学、机器学习等等)的问题时,取得了令人难以置信的结果。他们写道:

Minerva 通过生成包括数值计算和符号操作的解决方案来解决这些问题,而不依赖于计算器等外部工具。

这里有一个代数的例子,Minerva 输入一个问题,并给出解决方案。请注意,该模型能够通过简化和替换变量来求解方程。

代数中一个问题的例子和 Minerva 模型提供的答案。图片来源:原文章

您也可以在交互式样本浏览器中查看,以查看来自其他 STEM 学科的其他问题示例。在这里,我只粘贴几个例子来展示它有多先进:

线性代数中一个问题的例子和 Minerva 模型提供的答案。图片来源:原文

或者在生物学中:

生物学中一个问题的例子和 Minerva 模型提供的答案。图像取自交互式样品浏览器

化学:

化学中一个问题的例子和 Minerva 模型提供的答案。图像取自交互式样品浏览器

或者机器学习:

机器学习中一个问题的例子和 Minerva 模型提供的答案。图像取自交互式样品浏览器

Minerva 基于 Pathways 语言模型 (PaLM),该语言模型已经通过来自 arXiv 的 118 科学论文(在数学表达式中相当密集)进行了进一步训练。2022 年 4 月发布的 PaLM 模型是一个 5400 亿参数的语言模型,能够跨不同的领域和任务进行归纳。博文解释了培训的一个重要段落:

标准文本清理过程通常会删除对数学表达式的语义意义至关重要的符号和格式。通过在训练数据中维护这些信息,模型学习使用标准数学符号进行转换。

换句话说,需要一种不同的文本预处理方法来训练模型。

用于培训的数据集。图片来源:原文章

有趣的是,Minerva 不仅生成了一个解决方案,还生成了不同的解决方案(虽然步骤不同,但正如他们所写的,总的来说,他们会得到相同的最终答案)。不同的解决方案分配了不同的概率,然后选择最常见的答案作为解决方案(多数投票,这在 PaLM 中被证明是一个成功的策略)。

多数表决过程的说明,这是不同模型的基础。在 Minerva 案例中,模型为每个问题生成多个解决方案,并选择最常见的答案作为解决方案。图片来源:此处

然后,他们在不同的基准数据集上评估他们的方法。他们使用了 MATH(高中数学竞赛水平题),但也使用了更复杂的数据集,如 OCWCourses(由麻省理工学院开放课件收集的大学和研究生问题的集合)。在所有这些情况下,他们都达到了最先进的结果:

Minerva 在不同的定量推理基准数据集上展示了最先进的结果。摘自原文

这些结果令人印象深刻,然而,该模型仍远非如所述的那样完美:

密涅瓦仍然犯了不少错误。

在文章中,他们指出了这些错误的原因:

大约一半是计算错误,另一半是推理错误,其中求解步骤没有遵循逻辑思维链。

至于人类学生,也有可能模型可以得出正确的最终答案,但使用了错误的推理(在论文中被定义为“假阳性”)。但据他们观察,这些情况不太常见(讽刺的是,人类学生也是如此):

在我们的分析中,我们发现假阳性率相对较低(Minerva 62B 在数学上产生的假阳性不到 8%)。

他们还注意到,当问题更困难时,假阳性更常见(从 1 到 5,当模型遇到难度为 5 的问题时,假阳性率更高)。

在文章中,他们将此描述为一种限制,因为当模型预测正确答案但使用错误推理时,不可能自动识别情况。

以下是一个错误示例:

机器学习中一个问题的例子和 Minerva 模型提供的答案。在这种情况下,模型提供了一个错误的答案。图像取自交互式样品浏览器

有时错误在于模型误解了问题,或者使用了不正确的事实来回答。另一种错误是答案太短(没有推理就直接不正确,我们可以把这比作学生在不知道答案的情况下试图猜测答案)。在某些情况下,当模型生成不真实的事实或方程时,模型会产生他们所谓的“幻觉数学对象”。然而,这些情况是罕见的,普遍的错误是不正确的推理和不正确的计算。

在论文中,研究人员还讨论了他们模型的潜在社会影响。正如他们所认识到的,影响可能是巨大的:

能够在一般情况下解决定量推理问题的人工神经网络具有潜在的重大社会影响

然而,目前有两个主要限制因素正在降低潜在影响:

Minerva 虽然朝着这个方向迈出了一步,但仍远未实现这一目标,因此其潜在的社会影响有限。该模型的性能仍然远低于人类的性能,此外,我们没有一个自动的方法来验证其输出的正确性。

根据研究人员的未来,这些模型可以帮助教师减少教育不平等。然而,计算器和电脑并没有减少教育不平等,反而加大了这些资源容易获得的国家与教育资金不足的国家之间的差距。在任何情况下,它都代表了对许多领域有用的强大工具的第一步。例如,研究人员会发现,作为一种帮助他们工作的工具是非常有益的。

如果你觉得有趣:

你可以寻找我的其他文章,你也可以 订阅 在我发表文章时得到通知,你也可以在LinkedIn上连接或联系我。感谢您的支持!

这里是我的 Github 资源库的链接,我计划在那里收集代码,以及许多与机器学习、人工智能等相关的资源。

**https://github.com/SalvatoreRa/tutorial **

谷歌的巴利文:100 种语言的语言图像学习

原文:https://towardsdatascience.com/googles-pali-language-image-learning-in-100-languages-31d32f9b74fe

令人印象深刻的新型号,能够在复杂任务中达到最先进水平

unsplash.com格兰特·里奇的图片

近年来的趋势是增加神经网络的容量。一方面,越来越多的参数的不同模型被公布,另一方面,用于训练的数据量增加。无论输入和任务是文本的还是视觉的,这种观点都是普遍的。

关于文本模型,增加的容量显示了改进的性能和有趣的涌现行为: GPTGLaMPaLMT5 等等。而对于图像,在卷积神经网络主导该领域之前,近年来的趋势一直是视觉变压器

在所有两个领域(文本和视觉)中的类似进展已经允许在这两个领域的交叉点上打开一个新的领域:视觉语言模型

什么是视觉语言模型?将图像和文本都视为输入的模型可用于各种任务。今年,我们惊讶于 DALL-E 或 T21 这样的模型是如何从文字描述中创造出详细的图像的。另一方面,这只是视觉语言模型可以解决的任务之一:

  • 可视字幕(VC) :生成可视输入(图像、视频)的描述。该模型分析图像并提供表示该图像的文本描述。
  • 视觉问题回答(VQA) :为视觉输入提供答案。
  • 视觉常识推理(VCR) :从视觉输入中推断常识信息和认知理解。
  • 视觉生成(VG) :从文本输入(提示)生成视觉输出。
  • 上下文光学字符识别(OCR) : OCR 是将包含文本(打印、手写或印刷)的图像转换成计算机可以理解的文本输出。
  • 物体识别

此外,许多模型仅使用英语进行训练,但是有数千种语言(估计有 7000 种语言)并且重要的是其他语言被表示和包括在内。

本周展示了一个语言视觉模型,可以用 100 种语言执行任务。

总的模型参数是 170 亿(语言模型计数为 13 B,视觉组件为 4)。该模型由一个处理文本的变压器编码器和一个生成测试输出的 n 自回归变压器解码器组成。图像输入由连接到编码器的视觉转换器(Vit) 处理。有趣的是,这些组件取自早期型号:

PaLI 模型的一个关键组成部分是重用,其中我们用来自先前训练的单模态视觉和语言模型的权重来播种模型,例如 mT5-XXL 和大 ViTs 。这种重用不仅能够转移单模态训练的能力,而且还节省了计算成本。— 谷歌人工智能

模型建筑。图片来源:原文

事实上,作者创建了三个不同的模型,它们的参数越来越多,但架构相似(最终的模型容量最大)

图片来源:原文

作者专门为这个模型构建了一个数据集: WebLI。该数据集是通过从网上收集图像和文本构建的(它们不限于英语,而是收集了 109 种语言的数据)。他们因此收集了 120 亿张图像和 120 亿条替代文本(描述图像的文本)。他们还使用 GCP 视觉 API 提取了图像中的文本(OCR 注释),产生了 290 亿个图像-OCR 对。最终,只有 10 亿张图像被用于训练。

“与多语言替代文本(可用)和光学字符识别(使用 GCP 视觉 API5 计算)相关的样本图像 4”。图片来源:原创文章

WebLI 中 alt-text 和 OCR 识别语言的统计。图片来源:原创文章

WebLI 等大规模视觉语言数据集的图文对计数、 CLIPALIGNLiT 。图片来源:原文

视觉语言任务需要不同的能力,有时会有不同的目标。一些任务本质上需要对象的本地化来精确地解决任务,而另一些任务可能需要更全局的视图。类似地,不同的任务可能需要长的或紧凑的答案。— 谷歌人工智能

正是因为这个原因,他们开发了一种特殊的训练策略,目的是每次为模型提供一个输入(图像+文本)并接收一个输出(文本)。事实上,该模型伴随着一系列预训练任务(仅文本损坏、本地和翻译的替代文本数据上的字幕、分割字幕等),但仍保持相同的系统(输入:图像+文本;输出:文本)。因此,允许以相同的方式训练模型,同时仍然保持模型能够概括和能够执行其他任务。

training.image 来源:原文

模型在 JAX亚麻使用开源的 T5XFlaxformer 框架进行训练。对于视觉组件,我们使用开源的 BigVision 框架引入并训练了一个大型 ViT 架构,名为 ViT-e,具有 4B 参数。

一旦模型被训练,作者将它与其他最先进的方法(包括 SimVLMCoCaGIT2FlamingoBEiT3 )进行比较,以完成多种视觉和语言任务:

  • 图像字幕。作者在三个数据集上测试了该模型的能力:COCO(标准基准)、NoCaps(类似于 COCO,但目标有更多的视觉概念)和 TextCaps(图像包含文本)。此外,他们使用了另一个数据集 XM-3600(与其他三个不同,它是多语言的)

纯英文基准数据集上的图像字幕结果。图片来源:原文

多语言数据集上的图像字幕结果(此处显示:英语、法语、印地语、希伯来语、罗马尼亚语、泰语和中文以及 35 种语言的平均值)。图片来源:原文

  • 视觉问答。正如作者指出的,这是一项艰巨的任务,因为答案必须完全匹配才能被认为是准确的,而巴利文的词汇有 100 种语言。尽管如此,他们在几个数据集上取得了非常好的结果:VQAv2、OKVQA(其中需要外部知识来回答它的问题,因为所有知识都不存在于输入图像中,必须进行推断),TextVQA & VizWiz-QA(模型必须使用图像中存在的文本来回答)。他们还使用了跨语言和多语言数据集(xGQA 和 MaXM)。

英语数据集上的可视化问答结果。图片来源:原创文章

跨语言和多语言数据集的可视化问答。图片来源:原创文章

  • 语言理解能力。作者想知道模型一旦被训练用于多模态任务(图像+文本)是否会忘记它的语言建模能力。他们在英语和几种语言的数据集上测试了这些功能。该模型,尽管培训设置有利于多模态,保持了高水平的英语语言理解能力。

语言理解能力的结果。图片来源:原创文章

  • 零镜头图像分类。在这种情况下,作者没有通过在原始模型上添加分类器来修改模型。相反,他们调整了数据集。该模型显示了良好的性能,但仍低于最先进水平

图片来源:原文

虽然结果令人惊讶,但模型并不完美,也有一些局限性:

  • 该模型不能描述有许多对象的情况,因为训练数据集无论如何都没有复杂的注释。
  • 当模型针对纯英语数据进行微调时,会丢失一些多语言功能。
  • 正如作者所言,这种评估存在固有的局限性:“模型可能会生成一个正确的响应,它是目标响应的同义词或释义,并且与目标不完全匹配。”

此外,他们试图减少潜在的偏差,并在文章的附录中提供了所用模型和数据集的详细表格(模型数据卡)。尽管正如作者在文章中指出的:

大型模型可能会产生更广泛的社会影响。虽然这些模型在公共基准上表现强劲,但它们可能包含未知的偏见或成见,或者传播不准确或扭曲的信息。虽然我们已经努力衡量其中的一些问题,但在用于特定目的之前,需要对这些模型进行仔细的重新评估。

结论

PaLI 表明,它在几项迄今为止被认为具有挑战性的任务中达到了最先进的水平。而且,不仅仅是英语,还有几种语言。

虽然它已经达到了最先进的水平,但很可能更多的视觉语言模型将很快发布(希望是开源的)。它还展示了一些趋势:

  • 性能更高但不一定能力更强的型号(它比 Flamingo 更好,但只有 18 个 B 对 80 个 B 参数)
  • 除了英语之外,还接受多种语言训练的模特(如梅塔的 NLLB布鲁姆)
  • 这种情况下是多模态、图像和文本,但也有视频、音乐等…
  • 专注于避免偏见

如果你觉得有趣:

你可以寻找我的其他文章,你也可以 订阅 在我发表文章时得到通知,你也可以在LinkedIn上连接或联系我。感谢您的支持!****

这是我的 GitHub 知识库的链接,我计划在这里收集代码和许多与机器学习、人工智能等相关的资源。

**https://github.com/SalvatoreRa/tutorial

或者随意查看我在 Medium 上的其他文章:

**

谷歌的 PaLM-SayCan:第一代下一代机器人

原文:https://towardsdatascience.com/googles-palm-saycan-the-first-of-the-next-generation-of-robots-6dac158955a

谷歌进入了一条新的道路:融合人工智能和机器人技术。

棕榈说可以拿起一个苹果。鸣谢:谷歌研究

不管谷歌搜索怎么说,从历史上来说,人工智能与具有人形的闪亮金属机器人几乎没有什么关系。现在似乎不再是这样了。在过去的几年里,科技公司在人工智能机器人上下了很大的赌注。不是任何类型的(Roomba 是一个有用的工具,但远非机器人的原型)。不。公司正在制造人形机器人。

波士顿动力公司是该集团在机器人领域经验最丰富的公司,于 2021 年展示了最新版本的 Atlas 。三十年后,他们得到了一个具有相当不错的运动和本体感受技能的模型(它可以进行致命的跳跃)。现在由亚马逊支持的 Agility Robotics 生产 Digit,这是一种通用机器人,可以可靠地以人类的速度做仓库工作三星(Samsung)的 Handy 似乎能够做一些需要一些手工技巧的家务。小米最近加入了这个群体,并在两周后的特斯拉人工智能日推出了会说话的机器人 CyberOne ,它类似于特斯拉的 Optimus

许多高知名度的科技和机器人公司正在押注人形机器人,这一事实本身就很有趣。我以前曾提出过制造具有人类特征的机器人有很好的理由:世界在高度、形状、动作方面适应了我们……这些项目揭示了该行业对制造机器人的兴趣,正如马斯克去年在 2021 年人工智能日期间所说,“消除危险、重复和无聊的任务”,或在家里帮助我们。

但是这篇文章不是关于人形机器人的。至少不仅仅是。这是一种机器人学的新方法,我上面提到的例子中没有一个是遵循的。我说的是将最先进的人工智能系统——特别是语言模型——与可以在世界上导航的全身机器人融合在一起。大脑和身体。一些人工智能公司专注于构建下一个超大型语言模型,而机器人公司想要最灵巧的机器人,但似乎没有重叠——尽管这似乎是显而易见的前进道路。

莫拉维克悖论和人工智能与机器人融合的复杂性

为什么大多数人工智能公司不进入机器人领域(OpenAI 去年解散了其机器人分支)以及为什么大多数机器人公司将其机器人的范围限制在简单的任务或简单的环境(或两者都有)是有充分理由的。其中一个主要原因是所谓的莫拉维克悖论。它说,与直觉相反,很难让机器人足够好地执行感觉运动和感知任务(例如,拿起一个苹果),而创造能够解决困难的认知问题(例如,玩棋盘游戏或通过智商测试)的人工智能相对容易。

对人类来说,微积分显然比在空中接球更难。但那只是因为从进化论的角度来说,微积分是相对较新的。我们还没来得及掌握。正如人工智能的创始人之一马文·明斯基所说:“我们更了解工作不好的简单过程,而不是工作完美的复杂过程。”简而言之,制造可以四处移动并与环境完美互动的机器人极其困难(在过去几十年中进展甚微)。

但现在,有一家公司试图克服莫拉维克悖论的明显局限性(我想强调“努力”,我们会看到为什么)。我指的是谷歌。在与日常机器人的合作中,这个科技巨头创造了很可能是机器人领域的下一个突破: PaLM-SayCan (PSC),一个(没有那么多)人形机器人,拥有上面其他人只能梦想的混合能力。

我对谷歌的方法特别感兴趣,因为我是人工智能虚拟系统和现实世界机器人融合的倡导者。不管我们是否想要建立一个人工通用智能,这是两个学科的自然道路。一些研究人员和公司认为缩放假说是人类智能人工智能的关键。相反,我认为让人工智能在现实世界中扎根是至关重要的,这既是为了解决当前的缺点(如人工智能对世界如何工作的普遍无知或互联网数据集的偏见),也是为了将其提升到下一个水平(推理和理解需要只有通过探索世界才能获得的隐性知识)。

(注:如果你想进一步了解这个话题,我推荐我这个大多被遗忘的帖子“人工智能和机器人技术将不可避免地融合”)

谷歌的 PSC 显示,该公司最终接受了这是前进的方向,并决定不放弃纯粹的人工智能,而是重新关注人工智能+机器人,作为实现更有能力的智能系统的一种手段。最后,这与训练多模态模型没有什么不同(通常被认为是深度学习模型的自然下一步)。同样,能够“看”和“读”的人工智能比那些只能感知一种信息模式的人工智能更强大,能够行动和感知的人工智能或机器人将在我们的物理世界中表现得更好。

让我们看看谷歌的 PSC 有什么能力,以及它如何设法将大型语言模型的能力与物理机器人的灵活性和动作能力结合起来。

PaLM-SayCan:第一代新一代机器人

在高层次上,我们可以将 PSC 理解为一个结合了 PaLM 对自然语言的掌握(PaLM 是一种语言模型,很像 GPT-3 或 LaMDA——尽管略胜一筹)和机器人与世界互动和导航的能力的系统。手掌充当人类和机器人之间的中介,机器人充当语言模型的“手和眼”。

用更专业的术语来说,PaLM 允许机器人执行高级复杂任务(记住 Moravec 悖论指出,随着任务变得更加复杂,对于一个没有享受数千年进化进步的机器人来说,正确完成任务变得更加困难)。例如,“给我拿一份点心”虽然看似简单的任务,但包含许多不同的基本动作(表达本身包含某种程度的省略和暗示;“哪种零食?”).

PaLM 为机器人提供了任务基础:它可以将自然语言请求转化为精确(尽管复杂)的任务,并将其分解为有助于完成任务的基本动作。像 Atlas 或 Digit 这样的机器人可以非常好地完成简单的任务,但如果没有显式编程,它们无法解决 15 步请求。PSC 可以。

作为回报,机器人向 PaLM 提供关于环境和自身的上下文知识。它给出了基于世界的信息,这些信息可以告诉语言模型,在给定外部真实世界条件的情况下,哪些基本动作是可能的——它能够做什么。

手掌陈述什么是有用的,机器人陈述什么是可能的。这是谷歌创新设计的关键,也是这种方法让该公司处于领先地位的原因(尽管不一定是在成就方面——PSC 仍然是一个研究原型,而 Atlas 和 Digit 是完整的产品)。PSC 结合了任务基础(给定请求的意义)和世界基础(给定环境的意义)。PaLM 和机器人都无法独自解决这些问题。

现在,让我们来看一个 PSC 能做什么的例子,它是如何做到的,以及它与替代方案相比有多好。

PaLM-SayCan 在行动:利用 NLP 导航世界

谷歌研究人员在他们的实验中使用的一个例子(发表在论文“尽我所能,不要像我说的那样:机器人启示中的基础语言”中)以人类的请求开始,自然地表达:“我刚刚健身,请给我带点小吃和饮料来恢复。”

这对于一个人来说是一件容易的事情,但是传统设计的机器人对如何完成请愿毫无头绪。为了使请求有意义,PSC 利用 PaLM 的语言能力(特别是,思维链提示,它只是使用中间推理步骤来得出结论)来将请求重新定义为可以分解成步骤的高级任务。PaLM 可以总结道:“我会给这个人带一个苹果和一个水瓶。”

PaLM 充当了人类语言的微妙和含蓄与机器人能够理解的精确、僵硬的语言之间的中介。既然 PaLM 已经定义了一个任务来满足用户的请求,它就可以提出一系列有用的步骤来完成这个任务。然而,由于 PaLM 是一个与世界没有联系的虚拟 AI,它不一定会提出最佳方法,只会提出对任务有意义的想法——而不会考虑实际设置。

这就是机器人启示发挥作用的地方。经过训练的机器人“知道”在现实世界中什么是可行的,什么是不可行的,它可以与 PaLM 合作,为那些可能的动作赋予更高的价值,而不是那些更难或不可能的动作。PaLM 给有用的动作打高分,机器人给可能的动作打高分。这种方法允许 PSC 最终找到给定任务和环境的最佳行动计划。PSC 集两者之长。

回到零食的例子。PaLM 已经决定它应该“给这个人一个苹果和一个水瓶”然后它可能会提议去商店买一个苹果(有用)。然而,机器人会给这一步打很低的分,因为它不会爬楼梯(不可能)。另一方面,机器人可能会建议拿一个空杯子(可能),PaLM 会说完成任务没有用,因为这个人想要的是水,而不是杯子(没用)。通过从有用的和可能的提议中获得最高分,PSC 将最终决定去厨房找一个苹果和水(有用的和可能的)。一旦该步骤完成,该过程将重复,PSC 将决定在新状态下应该采取的下一个基本行动,即在每个后续步骤中更接近任务的完成。

谷歌的研究人员在 101 个教学任务中测试了 PSC 与两种选择的对比。一个使用了一个较小的模型,该模型在指令回答方面进行了明确的微调( FLAN ),另一个没有使用将语言模型融入现实世界所必需的机器人启示。他们的发现很清楚:

“结果显示,使用具有启示基础的 PaLM(PaLM-say can)的系统在 84%的情况下选择正确的技能序列,在 74%的情况下成功执行它们,与 FLAN 和没有机器人基础的 PaLM 相比,错误减少了 50%。”

这些结果揭示了一种很有前途的方法,可以将最先进的语言人工智能模型与机器人结合起来,形成更完整的系统,可以更好地理解我们,同时更好地导航世界。

不过,这种方法也有缺点。有些在 PSC 中是显而易见的,而其他的将在公司探索了问题的整个范围后显现出来。

PaLM-SayCan 做不到的:很难打败进化

这里我将忽略外围模块的有效性(例如,语音识别、语音转文本、检测和识别对象的视觉传感器等。)尽管这些必须完美地工作以使机器人发挥作用(例如,照明的变化可能使物体检测软件变得无用,从而使 PSC 不能完成任务)。

我想到的第一个问题——也是我在文章中反复提到的一个问题——是语言模型无法从人类的角度理解。我举了一个例子,一个人想要一份点心和饮料,手掌正确地解释了一个苹果和一个水瓶就可以了。然而,这里有一个隐含的问题,即使是最好的语言模型,如 PaLM,也可能无法解决更复杂的情况。

PaLM 是一个非常强大的自动完成程序。它被训练成在给定令牌历史的情况下准确预测下一个令牌。虽然这个训练目标已经被证明对于令人满意地解决大量的语言任务非常有用,但是它没有为 AI 提供理解人类或者有意图地生成话语的能力。PaLM 输出单词,但它不知道为什么,它们意味着什么,或者它们可能产生的后果。

PaLM 可以正确地解释这个请求,并指示机器人拿一个苹果和水来,但这将是一个无脑的解释。如果它猜错了,就不会有自我评估的内部机制让模型知道它得出了错误的解释。即使 PaLM(或者更聪明的人工智能)可以处理大多数请求,也没有办法确保 100%的请求可以得到解决——也没有办法知道人工智能可以解决哪些请求,不能解决哪些请求。

PSC 很可能遇到的另一个问题是机器人的动作出错。假设 PaLM 已经正确地解释了这个人的请求,并且提出了一个合理的任务。PSC 已经决定了一系列有用的和可能的步骤,并且正在采取相应的行动。如果其中一个动作没有正确完成或者机器人犯了一个错误怎么办?比方说,它去摘苹果,苹果掉在地上,滚到墙角。PSC 是否有反馈机制来重新评估其状态和世界状态,以提出一套新的行动来解决新情况下的请求?答案是否定的。

谷歌在一个非常受限的实验室环境中进行了实验。如果 PSC 在世界上运行,它将遇到无数不断变化的条件(移动的物体和人,地面的不规则性,意外事件,阴影,风等)。).它几乎什么也做不了。现实世界中的变量数量几乎是无限的,但 PSC 是用在受控环境中行动的其他机器人的数据集来训练的。当然,PSC 是一个概念证明,所以这不是判断其性能的最公平的镜头,但谷歌应该记住,从这一点到现实世界工作机器人的飞跃不仅仅是数量上的。

这些是主要的语言和动作问题。但还有许多其他的与此有些关联:PaLM 提出的任务可能需要比机器人的上限更高的步骤。失败的概率随着完成任务所需的步骤数呈指数增长。机器人可以找到它不熟悉的地形或物体。由于缺乏常识,它可能会发现自己处于一种无法随机应变的新局面。

最后一个缺点是,PaLM 和所有其他语言模型一样,容易使它在训练中看到的偏见永久化,对此我将用一整段话来说明。有趣的是,来自约翰·霍普金斯大学的研究人员最近分析了一个机器人的行为,在它通过互联网数据得到增强后,发现偏见超越了语言:机器人是种族主义者和性别歧视者——机器人的行为和数据一样有偏见。这是极有问题的。语言中存在的偏见可能是显而易见的(大部分时间都是如此),但行动中的偏见更加微妙,这使得它们更难定位、分析和消除。

最后,这总是谷歌人工智能博客帖子的补充,该公司以优先考虑安全和负责任的开发而自豪。PSC 带有一系列机制来确保程序的安全性:PaLM 不应该产生不安全或有偏见的建议,机器人不应该采取潜在的危险行动。尽管如此,这些问题普遍存在,公司没有一个标准的解决方案。虽然 PSC 似乎是新一代最先进的人工智能机器人的第一款,但在这方面没有什么不同。

订阅 算法桥 。弥合算法和人之间的鸿沟。关于与你生活相关的人工智能的时事通讯。

您也可以直接支持我在 Medium 上的工作,并通过使用我的推荐链接 这里 成为会员来获得无限制的访问权限! 😃

英语到 Cypher 与 GPT-3 在博士艾

原文:https://towardsdatascience.com/gpt-3-for-doctor-ai-1396d1cd6fa5

使用英语浏览医学知识图表

作者黄思兴和 Maruthi Prithivirajan

塞巴斯蒂安·比尔Unsplash 上拍摄的照片

2021 年 12 月,四名 Neo4j 工程师与 Maruthi 和我一起在新加坡医疗保健 AI Datathon & EXPO 2021(图 1)上开发了一个名为 Doctor.ai ( 此处此处)的医疗聊天机器人。得益于 AWS Lex,Doctor.ai 以 Neo4j 图表的形式管理电子健康记录,并以英语与用户互动。

在 Datathon 之后,我们继续扩展了 Doctor.ai,在整合了三个公共知识图谱(此处)之后,Doctor.ai 对疾病、基因、药物化合物、症状等都有所了解。这种扩展将患者的健康记录连接到医学知识网络。换句话说,它把具体和一般联系起来。现在我们可以在更广阔的背景下了解每个病人的病史。例如,在我们询问患者的最后一次诊断后,我们可以进一步询问是什么导致了该疾病,以及可以使用哪些药物(图 1)。

图一。Doctor.ai 的知识图谱和界面。图片作者。

在自然语言中,我们可以用许多不同的方式表达同样的想法,也就是重述。令人惊讶的是,我们人类可以重新措辞和重述很多,而我们的对话伙伴仍然可以理解我们。但对计算机来说,情况并非如此。编程语言往往有我们开发人员必须遵守的严格语法。违规将导致程序失败。自然语言理解(NLU)引擎的工作是将各种人类重述汇聚成一个严格的编程语句(图 2)。Doctor.ai 使用 AWS Lex 和 Lambda 作为其 NLU 引擎。

这一切都很好。Lex 和 Lambda 像宣传的那样工作。然而,开发非常耗时。首先,开发人员需要熟悉一系列新概念,如意图、话语、槽、槽类型和上下文。其次,对于每个意图,开发人员需要提供多个示例话语,设置插槽并管理上下文。最后,每个意图都与一个 Lambda 函数联系起来,在这个函数中,Cypher 查询被合成。Lambda 编程需要一些时间来适应,因为开发人员首先需要学习特定于 Lex 的规则。

图二。自然语言理解引擎将一系列话语汇聚成一个严格的编程语句。图片作者。

问题是:我们能用简单而强大的东西代替 Lex 和 Lambda 吗?答案是肯定的。镇上有了一位新警长: GPT-3

OpenAI 的 GPT 3 号首次以其逼真的对话震惊了科技界。但这只是它众多惊人能力之一。除了模仿史蒂夫·乔布斯,GPT-3 还可以执行一系列自然语言任务,包括摘要、语法纠正、代码解释、代码纠正、代码翻译、文本到命令等等。尽管仍需要人为干预,但 GPT 3 号独自就能正确完成大部分任务。更重要的是,它具有“认知”灵活性,可以根据人类的输入来提高其性能。在我们看来,GPT-3 可以被认为是 NLU 近年来改变游戏规则的技术迭代之一。

图 3。这个项目的架构。图片作者。

在本文中,我们将向您展示如何在 Doctor.ai 中使用 GPT-3。图 3 展示了该架构。我们将利用它的能力把我们的英语问题转换成密码。但是在这种情况下,Text to Cypher可能是一个更好的名字。这个项目的源代码存放在 Github 仓库中:

https://github.com/dgg32/doctorai_ui_gpt3

Neo4j 数据库转储文件位于:

https://1drv.ms/u/s!Apl037WLngZ8hhj_0aRswHOOKm0p?e=7kuWsS

1.GPT 三号账户

首先,我们需要一个 GPT 协议 3 的账户。请注意,并非所有地区都受支持,例如中国。确保您所在的地区在列表中。一旦您获得了帐户,您就获得了一个密钥(图 4)。18 美元的初始贷款足够支付整个项目了。

图 4。在您的帐户管理页面获取您的 GPT-3 密钥。图片作者。

2.在云上设置一个 Neo4j 后端

我们可以在 AWS、GCP 或 AuraDB 上托管我们的 Neo4j 数据库。你也可以简单地使用我下面的 CloudFormation 模板在 AWS 上设置它。用户名是neo4j,密码是s00pers3cret

https://github.com/dgg32/doctorai_gpt3_aws

在任何情况下,您都可以使用上面的转储文件来恢复完整的数据库。例如,在 EC2 中,首先以ubuntu的身份登录您的实例,并执行以下 bash 命令:

代码 1。从转储文件恢复 Neo4j。

设置 EC2 或 Compute 时,确保端口7686打开。另外,HTTPS 和 HTTP 也分别需要端口74737474。如果你想使用 AuraDB,你至少需要专业版,因为 Doctor.ai 的知识图中节点和边的数量超过了免费版的硬性限制。

在继续之前,请测试您的 Neo4j 数据库。首先,在浏览器中输入地址:

登录后,您应该在界面中看到节点和关系:

图 5。用 Neo4j 浏览器考察 Doctor.ai 的知识图谱。图片作者。

现在让我们使用 JavaScript 中的bolt协议来测试连接。你首先需要neo4j-driver

然后在控制台中输入node并执行以下命令:

代码 2。测试螺栓连接。

如果你看到输出SARS-CoV-2,这种情况下值得庆祝!

3.GPT-3

现在我们可以在 Doctor.ai 中使用 GPT-3,我们将修改我们的同事 Irwan Butar Butar 的react-simple-chatbot中的代码,该代码反过来基于 Lucas Bassetti 的工作。并且所有的动作都发生在一个文件中:DoctorAI_gpt3.js。在这个文件中,我们将从用户那里一次提取一个英语问题,打包并发送给 GPT-3。GPT-3 会将其转换成密码查询。我们对后端数据库执行这个密码查询。最后,我们将查询结果返回给用户。

GPT-3 是这样工作的:你给它一些英语-密码对作为例子。比如:

如果你有几个表达式应该从 GPT-3 中触发相同的响应,你可以用“或”或“或”把它们放在一起像这样。

GPT-3 将学习并为您的下一个英语问题生成密码查询。没有证据表明 GPT-3 以前接受过 Cypher 的训练。但是它可以用一些例子推断出密码的语法,并写出密码。太神奇了。你可以在 GPT 三号游乐场亲自测试一下:

图 6。在操场上测试 GPT-3。图片作者。

英文提示以一个#符号开始。当您点击Generate按钮时,GPT-3 将在下一行生成正确的密码查询:

图 7。Cypher 测试的结果。图片作者。

你会注意到有过多的文本。你可以通过调节右边的Response length参数来控制。

DoctorAI_gpt3.js中的 GPT-3 部分只是上面演示的一个代码。

图 8。作者的 ai 医生图像的 GPT-3 组件。

4.用 GPT-3 密码查询 Neo4j

一旦 GPT 3 号完成了这一重任,剩下的事情就简单多了。Neo4j 查询的 JavaScript 只是上面代码 2 的扩展。

图 9。Doctor.ai. Image by author 的 Neo4j 查询组件。

您可以在 Github 资源库中看到完整的代码。

5.托管前端

现在是托管前端的时候了。这个过程已经在我的上一篇文章 Doctor.ai 中描述过,这是一个人工智能驱动的虚拟语音助手,用于医疗保健 。只有两个小变化。首先,将 Amplify 指向当前的 Github 资源库,而不是文章中提到的旧资源库。其次,环境变量完全不同。在Configure build settings页面的Advanced settings下,设置以下四个环境变量,并填入正确的值:

请注意,在客户端,我们首先需要允许浏览器通过端口 7687 访问 URL。如果我们的 EC2 实例没有 SSL,这是必要的。如果使用 AuraDB 托管后端,就没有这个问题。但是在撰写本文时,AuraDB Free 太小,无法承载 Doctor.ai。在你浏览器的地址栏输入https://[EC_public_ip]:7687,点击Advanced... ➡️ Accept the Risk and Continue(此处读)。

图 10。在浏览器地址栏中输入 EC2 公共 IP。图片作者。

图 11。接受风险,继续。图片作者。

图 12。确认异常的消息。图片作者。

当您看到图 12 中的消息时,您已经准备好了。

6.测试 GPT-3 博士. ai

最后,我们可以测试这个新的 Doctor.ai,看看 GPT 的魔力-3:

图 13。测试由作者提供的 GPT-3 powered Doctor.ai 图像。

在这里,我向艾医生询问了一些关于艾滋病毒感染和脊椎跗骨结合综合征的信息。这些问题遵循我们的培训示例的模式。因此,它们运行良好并不令人意外。让我们重新措辞我们的问题,看看 ai 医生是否还能理解我们的意图:

图 14。用重述测试 Doctor.ai。图片作者。

起初,艾医生无意中发现了这些重述。它可以识别一些语句,但不能识别其他语义相同的语句。要改进 Doctor.ai,可以给它提供更多的例子。让我们在训练集中添加一个额外的示例对:

通过它,Doctor.ai 能够在构建 Cypher 查询之前将关键字“有机体”转换为“病原体”。此外,它还可以推广到其他类似的问题。

图 15。我们可以通过增加更多的训练例子来改进 NLU 医生。图片作者。

最后,我们来测试一下 Doctor.ai 能不能听懂代词。

图 16。作者对博士艾形象的代词测试。

这里我们看到一个错误。患者 id_2 于 2015 年就诊于 ICU。经过仔细检查,很明显 GPT-3 询问的是病人 id_1 的入院时间,而不是 id_2。因此,当 GPT-3 遇到“他”或“她”等代词时,它假设我们指的是对话中提到的第一个而不是最后一个。

结论

GPT 3 是一个可怕的游戏改变者。在许多情况下,它对自然语言的理解可以与人类说话者相媲美,它只需要少量的训练数据。很容易扩展。如果它犯了一个错误,我们可以只添加一个或两个正确的答案到训练集,GPT-3 将把这种纠正推广到其他类似的情况。对于开发人员来说,向 GPT-3 展示一些例子要比写许多行死板的编程语句容易得多。在 GPT-3 之前,我们在 Doctor.ai 的 Lambda 中看到了大量代码重复。Lex 的配置也是劳动密集型的。GPT 3 号改变了这一切。只需在前端增加 60 行代码,它就取代了庞大的 Lex 和 Lambda。可以有把握地说,GPT-3 可以极大地减少开发和测试时间,并缩减其他自然语言相关项目的代码。

但它完美吗?不。正如这个项目所展示的,它在理解代词方面有困难。不知何故,它专注于第一个提到的问题,而不是最后一个提到的问题。那肯定不像人类。此外,一些重述可以智胜 GPT-3。但对我来说,这些都只是小问题。

这篇文章只是对 GPT-3 的一点皮毛。示例代码中的英语-密码对远非详尽。我们可以做更多来覆盖 Doctor.ai 中的整个知识图表。GPT-3 也可以通过微调作业进行微调以获得更好的性能。可能性是无穷的。

我们鼓励您将 GPT-3 用于您自己的 NLU 项目。告诉我们你是如何使用它的。

Update: my next article Can Doctor.ai understand German, Chinese and Japanese? GPT-3 Answers: Ja, 一点点 and できます!shows that Doctor.ai can understand German, Chinese and Japanese thanks to GPT-3.

执照

Hetionet 发布为 CC0 STRING 在“4.0 知识共享”许可下 免费提供,而 学术用户可以免费使用 KEGG 网站

https://dgg32.medium.com/membership

GPT-3 生成的鸡尾酒配方

原文:https://towardsdatascience.com/gpt-3-generated-cocktail-recipes-214512f2e78e

如何创建自己的人工智能调酒师

我最近玩了 GPT-3,虽然它不是什么新东西,但我仍然无法表达它有多酷。对于那些从未尝试过 GPT-3 的人来说,我希望这个故事将展示开始使用它是多么容易。

GPT-3 的主要特点是它由 OpenAI 托管,所以你不需要在你的硬件上运行 model。这个事实有它自己的优点和缺点。一方面——它使得使用 GPT-3 变得非常简单,你只需要使用它的 API,非常简单,并且提供了 Python 和 JavaScript 的库。另一方面,这意味着它完全由 OpenAI 控制,你无法接触到它的内部。

但是我们才刚刚开始——我们还不需要内部设备,所以让我们只关注 GPT-3 的使用有多简单。

在浏览快速入门指南时,人们很容易对最初的生成宠物名字的示例应用感到厌倦。真实的任务对我来说总是比编造的例子更有效。也许给宠物起名字很有趣,但我不能说这个示例应用程序将解决任何实际问题或增加实际价值——不能说我经常给宠物起名字。

因此,我修改了最初的示例应用程序(昵称生成器)来根据名字生成鸡尾酒配方。你只需输入一种真实或想象的鸡尾酒的名字,GPT-3 就会为你生成配方。这给了我太多的乐趣!

照片由 Ash EdmondsUnsplash 上拍摄

首先,我尝试了真正的鸡尾酒。这是尼格罗尼给我的启示:

1 盎司杜松子酒,1 盎司甜苦艾酒,1 盎司金巴利,冰,橘子皮。在加满冰块的摇壶里混合杜松子酒、甜苦艾酒和金巴利酒。搅拌至完全冷却,滤入加满冰块的岩石杯。用橘子皮装饰。

好,看起来像一个真正的尼格罗尼!这并不出乎意料,因为 GPT 3 号在训练中确实学到了很多真正的鸡尾酒配方。可能如果准备一个聚会,我应该使用谷歌真正的鸡尾酒配方,而不是人工智能,但仍然,这是非常酷的结果!

所以,我决定继续玩下去。如果我会用我刚刚编造的名字制作鸡尾酒会怎么样?像这些:

伦敦热: 1 1/2 盎司杜松子酒,1/2 盎司新鲜柠檬汁,1/4 盎司新鲜酸橙汁,1/4 盎司简单糖浆,1 份少量橙苦味酒,柠檬皮。在一个装满冰块的摇壶里混合所有的原料。摇匀后滤入冰过的鸡尾酒杯。用柠檬皮装饰。

朗姆酒日记:60 毫升深色朗姆酒,15 毫升糖浆,30 毫升酸橙汁,冰块,酸橙楔装饰。摇合所有原料,滤入加满冰块的飓风杯或柯林斯杯。用青柠角装饰。

鲍里斯托辞: 2 盎司伏特加,1 盎司咖啡利口酒,1 盎司贝利的爱尔兰奶油,1 盎司黑可可奶油,1 盎司对半,冰。将所有原料放入搅拌机中搅拌至均匀。平均分配在两个玻璃杯中。

很酷,是吧?!

但是我厌倦了所有这些严肃的事情,所以我开始玩参数,试图得到荒谬的食谱。毕竟,这就是我们喜欢所有这些 AI、ML 和其他神经工作人员的地方——有时它们可能会产生非常令人毛骨悚然和荒谬的结果,看起来非常滑稽。

GPT-3 不只是一个型号,而是一组型号,默认为名为达芬奇的型号,这是最强大的一个。所以,在玩达芬奇的时候,我几乎每次尝试都得到或多或少正常的鸡尾酒配方,不考虑参数。有时不是,但它们并不好笑。

因此,我尝试了模型 Ada ,得到了太差的结果,并切换到 Babbage ,它具有高温度top_p 参数,最终开始生成看起来有点奇怪的鸡尾酒配方,但同时保持人类仍然可以理解的文本。

这是另一个版本的鲍里斯借口,制作时有“奇怪”的设定:

100 毫升白葡萄酒,15 毫升 destillado 龙舌兰酒,2 杯葡萄酒,冰。在杯子里装满冰块,然后把德斯蒂拉多龙舌兰酒倒入其中。闭上眼睛,把鼻子贴近冰冷的玻璃。电气石立方体也可以添加到饮料中,以增加所谓的佛手柑风味。

这样看起来好多了!现在,对于每一种鸡尾酒的名字,我都可以拿出两种配方:一种“正常”,一种“奇怪”。我们继续玩吧!品牌名称会给我带来什么?

飞利浦

正常配方:30 毫升杜松子酒、15 毫升杏白兰地、7.5 毫升柠檬汁、7.5 毫升糖浆、1 个蛋白、冰。在鸡尾酒摇壶中摇合所有原料,滤入鸡尾酒杯。

奇怪的配方:15 毫升蓝色苏打水,2 分钟 70 毫升干邑,3 盎司苏打水,2 茶匙石榴汁。摇合所有原料,滤入加冰的杯子。轻轻敲打玻璃上的闪光灯,这样所有的颜色混合将会对齐。淋上苏打水就可以上桌了。

你可以看到一些奇怪的拼写,但其他方面看起来不错。不过,如果我要求调酒的话,酒保可能会恨我。

由于微软现在独家获得了 GPT-3 的内部信息,我想知道微软的鸡尾酒是什么:

正常配方:1 1/2 盎司杜松子酒,1/2 盎司干苦艾酒,1/4 盎司甜苦艾酒,1/4 盎司三秒,1/4 盎司柠檬汁,冰。加冰摇合所有原料,滤入鸡尾酒杯,上桌。

奇怪的配方:64 毫升 Beefeater 杜松子酒,26 毫升自制菠萝汁,2 条橘子皮,1/4 龙舌兰酒协会(50%龙舌兰)药丸,冰。将 Beefeater gin 倒入加冰的摇壶中,拧开盖子。加入菠萝汁、桔皮和龙舌兰酒协会。摇匀后滤入冰过的鸡尾酒杯。

我喜欢这首《扭断顶端》。

但是,还有什么比以自己名字命名的鸡尾酒更令人激动呢?!这是安德烈·塞门尤克鸡尾酒的配方:

正常配方:1.5 盎司伏特加,0.5 盎司蓝柑桂酒,0.5 盎司三秒,1 盎司蔓越莓汁,0.5 盎司酸橙汁,冰。加冰摇合所有原料,滤入冰过的鸡尾酒杯。

奇怪的配方:安德烈 semenyuk 51525 龙舌兰酒和石灰。这种鸡尾酒是一种清澈的龙舌兰酒和葡萄柚品种,结合了柑橘的味道和龙舌兰酒的柔滑。这种饮料应该配有一个破碎的水晶摇壶,用冷水融化和更新。

后一个版本真的很奇怪也很有趣:-)不知道我有以自己名字命名的龙舌兰酒品牌。我还把两个食谱献给了我的妻子,她认为这是非常浪漫的举动:-)

所有代码都可以在我的回购中找到,请随意克隆和播放:【https://github.com/andrrey/openai-cocktails

希望这篇文章会鼓励你尝试 GPT 3,你可以看到它是多么容易使用,同时它是多么有趣。去探索吧,学习不一定是枯燥的,当你可以做这样有趣和酷的事情的时候!

̶i̶̶w̶i̶l̶l̶̶g̶e̶n̶e̶r̶a̶t̶e̶̶c̶o̶c̶k̶t̶a̶i̶l̶s̶̶n̶a̶m̶e̶d̶̶a̶f̶t̶e̶r̶̶e̶v̶e̶r̶y̶o̶n̶e̶̶r̶e̶a̶c̶t̶e̶d̶̶t̶o̶̶t̶h̶i̶s̶̶p̶o̶s̶t̶̶a̶n̶d̶̶p̶o̶s̶t̶̶t̶h̶e̶m̶̶i̶n̶̶c̶o̶m̶m̶e̶n̶t̶s̶.̶

经过长期训练的类似 GPT 3 的模特可能成为未来生物学生的全天候导师

原文:https://towardsdatascience.com/gpt-3-like-models-with-extended-training-could-be-the-future-24-7-tutors-for-biology-students-904d2ae7986a

使用基于 GPT 协议 3 的软件辅助 STEM 教育系列

经过长期训练的类似 GPT 3 的模特可能成为未来生物学生的全天候导师

尽管其他科目的成绩相当令人沮丧,但 GPT 3 号在生物方面表现得相当不错,如果它的训练时间延长,就更好了。看看这组新的实验。

跳转到: 简介 | 主考 | 通过延伸训练 | 讨论 | 结论

介绍

在我最近对 GPT-3 帮助学生学习科学科目的潜力进行的测试中,我发现除了作为一种更自然地检索系统从网络上“学习”的理论概念的工具,化学和物理很少或根本没有适用性。

生物学,至少在高中和大学早期阶段,是高度描述性的,因此可能是 GPT-3 和其他 NLP 模型的潜在应用领域。在这篇文章中,我通过遵循我以前文章中相同的过程,探索了这一点:我在 OpenAI 的操场上拿着 GPT-3 的达芬奇模型,就好像它是一个学生一样,我通过考试般的聊天对它进行了一系列概念的评估。

当然,GPT-3 缺乏任何思考能力,但我在下面的文章中认为,它仍然有可能通过自然语言作为信息检索的高级资源:

主要检查

先来看看我让达芬奇参加的主要考试。下面的文字中,以 Q 开头的每一行都是我问的问题,A 是达芬奇的回答(用默认设置运行)。我把所有的聊天记录都用引用的形式,我用粗体格式对聊天记录进行评论:

问:你好,我们来讨论一些关于生物的话题。当然可以。你想了解什么

问:我们先来看看你对普通生物学了解多少。你如何根据细胞类型来划分生物?
答:有三种类型的细胞:原核细胞、真核细胞和古细菌细胞。

严格地说,GPT-3 在这里所说的是错误的,因为它说“有三种类型的细胞”。而是在实际问题的背景下考虑(“如何根据细胞类型来划分生物体”),而不是“有多少细胞类型?”),答案正确。GPT-3 已经在领域水平上回答了我的问题,其中有细菌和古菌(生命的两个领域,都由单个原核细胞组成),加上由一个或多个真核细胞组成的真核细胞。

因此给出的答案对一个学生来说不是最好的,但我承认这个问题本身不是最清楚的。我想一个学生也可能被弄糊涂了。让我们继续前进。

问:原核细胞、真核细胞、古细菌细胞有什么异同?
答:原核细胞是最简单的细胞,它们没有细胞核或其他细胞器。真核细胞更复杂,它们有细胞核和其他细胞器。古细菌细胞类似于原核细胞,但它们有不同类型的细胞壁。

所有这些都是正确的,并且与上述三种主要类型的分离细胞相一致。

问:你能多比较一下原核细胞和真核细胞吗?
答:原核细胞一般比真核细胞小,没有细胞核或其他细胞器。真核细胞更复杂,它们有细胞核和其他细胞器。

在这里,我试图引导它在原核细胞和真核细胞上特异性地发育,它做得很好。既然提到了细胞器,这是开始深入研究它们的好时机:

问:很好。你能在真核细胞中找到哪种细胞器?
答:真核细胞有一个细胞核和其他细胞器,包括线粒体、核糖体和高尔基体。

问:线粒体执行什么功能?
答:线粒体负责在细胞中产生能量。

问:它们是如何产生能量的?
答:线粒体利用氧气分解葡萄糖等分子产生能量。

问:这个过程叫什么名字?答:这个过程叫做细胞呼吸。

问:很好,哪种是主要的呼吸酶?
答:主要的呼吸酶叫细胞色素 c 氧化酶。

问:很好。细胞色素 c 氧化酶催化什么反应?
答:细胞色素 c 氧化酶催化氧气与葡萄糖反应生成水和二氧化碳。

到目前为止,GPT-3 已经非常好地回答了所有这些问题,它可以很好地对应高中生物学。我现在试着深入一点:

问:它从哪里获取电子?
答:电子来自葡萄糖分子。

中间来源之一是葡萄糖,所以这是正确的。但我期待 GPT-3 告诉我电子来自三羧酸循环,或 NAD 分子,或电子传递链等。所以我多问了一点:

问:但是电子是如何从葡萄糖中提取出来的呢?
答:细胞色素 c 分子从葡萄糖中提取电子。

这是错误的。细胞色素 c 是最终的电子供体,但它本身并不直接从葡萄糖中获取电子。

问:不完全是。我的意思是,葡萄糖在细胞内是如何降解的?
答:葡萄糖在细胞内通过糖酵解过程降解。

根据定义,这是正确的。

问:对,糖酵解的产物是什么?
答:糖酵解的产物是两分子丙酮酸。

太好了,让我们再深入一点:

问:丙酮酸会发生什么变化?
答:丙酮酸转化为乙酰辅酶 a,然后用于柠檬酸循环。

问:什么是柠檬酸循环?
答:柠檬酸循环是将乙酰辅酶 a 转化为二氧化碳和水的一系列反应。

问:在柠檬酸循环过程中,电子发生了什么变化?
答:电子转移到 NAD+和 FAD 产生能量。

问:NAD 和 FAD 中的这些电子去了哪里?
答:NAD 和 FAD 中的电子去电子传递链。

这一部分非常完美。

问:呼吸酶在哪里?
答:呼吸酶叫做细胞色素 c 氧化酶。

我问的不是这个。让我们看看我能不能引导它:

问:它是电子传递链的一部分吗?答:不,电子传递链是蛋白质的独立链。

这是错误的,因为它实际上被认为是电子传递链的末端。我想我已经深入到 GPT 3 号能正确回答的程度了。

问:好吧,让我们来看看别的。动植物含有真核细胞还是原核细胞?
答:动植物含有真核细胞。

问:所以你的意思是植物是真核生物。答:是的,植物是真核生物。

问:动物和植物细胞包含相同种类的细胞器吗?不,动物和植物细胞包含不同种类的细胞器。

问:多解释一下
答:动物细胞含有线粒体、核糖体等细胞器,植物细胞含有叶绿体、细胞壁等细胞器。

一切都好。现在,既然提到了叶绿体,那就让我们深入研究一下:

问:什么是叶绿体?
答:叶绿体是植物细胞中负责光合作用的细胞器。

问:什么是光合作用?
答:光合作用是将光能转化为化学能的过程。

问:请告诉我更多关于光合作用的工作原理。
答:在光合作用中,光能转化为葡萄糖和其他分子。

问:怎么做?
答:叶绿体利用光能将二氧化碳和水转化为葡萄糖等分子。

所有这部分都很棒。让我们再测试一下。

问:太好了。这一切发生在哪个车厢?
答:叶绿体位于叶绿体膜内。

问:在任何特殊的细胞中?
答:不,叶绿体位于所有植物细胞的叶绿体膜中。

我不会这么说。看看我能不能稍微引导一下:

问:但是细胞的非绿色部分也进行光合作用吗?
答:不能,只有细胞的绿色部分才能进行光合作用。

还好它能“纠正”自己,即使只是偶然。

问:啊,好,很好。为什么这些部分是绿色的?
答:细胞的绿色部分含有叶绿素,吸收光能。

问:什么是叶绿素?
答:叶绿素是一种吸收光能并利用它产生葡萄糖的分子。

虽然参与了光合作用,但说叶绿素类直接利用光产生葡萄糖也不为过,肯定混淆视听。

问:光合作用发生在什么亚细胞结构中?
答:光合作用发生在植物细胞的叶绿体中。

问:有什么特别的地点吗?答:不,光合作用发生在植物细胞的叶绿体中。

我想知道更精确的位置,所以我一直在问:

问:但是吸收光进行光合作用的蛋白质在哪里呢?
答:吸收光进行光合作用的蛋白质位于叶绿体的类囊体膜中。

好。现在我转到生态学,只是为了在另一个话题上探索 GPT 3 号。

问:好,很好。现在我们换个话题。什么是生态?生态学是对生物和它们的环境之间的关系的研究。

问:生态系统中有哪些因素?答:在一个生态系统中,你有非生物因素和生物因素。

什么是生物和非生物因素?
答:生物因素是生态系统中有生命的组成部分,而非生物因素是生态系统中无生命的组成部分。

问:好的,请给我一些非生物因素的例子。答:非生物因素包括水、光、温度和土壤等。

问:动物是生物的还是非生物的?答:动物是有生命的。

好,现在让我看看我能不能把它搞混:

问:那么细菌、植物和岩石呢?细菌、植物和岩石都是生物。

嗯,它弄错了岩石。让我们一个一个地问,也用相关的词:

问:岩石是有生命的吗?
答:是的,岩石是有生命的。

问:石头是生物的还是非生物的?
答:石头是非生物的。

问:岩石是生物的还是非生物的?
答:岩石是非生物的。

用这种方式问它现在答对了。但是你可以看到上面说岩石是生物的时候有多肯定。对学生不好。

我又问了几个,他们都答对了:

问:矿物是生物的还是非生物的?
答:矿物是非生物的。

问:植物是生物的还是非生物的?答:植物是有生命的。

继续讲一些关于生态学的不同的东西:

问:好吧,让我们看看生态学范围内的其他东西。生物因素之间可以建立什么样的关系?
答:生物因素之间可以建立三种关系:竞争、捕食和共生。

问:什么是竞争,什么是捕食,什么是共生?
答:竞争是两个或更多有机体之间的关系,其中每个有机体都试图使用与另一个相同的资源。捕食是生物和猎物之间的关系,捕食者吃掉猎物。共生是两个或多个有机体之间的关系,两个有机体都从这种关系中受益。

问:你能举一个竞争的例子吗?
答:竞争的一个例子是两家工厂之间的关系,其中每家工厂都试图使用与另一家相同的资源。

问:捕食的例子?
答:捕食的一个例子是狮子和斑马的关系,狮子吃掉了斑马。

问:共生的一个例子是什么?
答:共生的一个例子是真菌和树木之间的关系,真菌帮助树木从土壤中吸收养分。

又一个完美街区。我们再多问一点:

好的,这让我想到另一个问题:什么是 lychen?
答:绿头菌是一种与树共生的真菌。

不是最佳定义。让我们再深入一点:

问:还有其他种类的母鸡吗?没有,只有三种地衣:地衣、菌根真菌和内生菌。

我不是 lychens 方面的专家,但这个答案是错误的。

让我们再一次转向不同的话题

问:好了,现在来点不同的,回到细胞和细胞器。真核细胞是怎么出现的有什么理论吗?关于真核细胞是如何出现的,有一个理论叫做内共生理论。

问:它说什么?
答:内共生理论说真核细胞是由吞噬其他原核细胞的原核细胞进化而来。

问:有什么具体的例子吗?答:内共生理论的一个例子是线粒体的起源。线粒体是真核细胞中产生能量的细胞器。据信,线粒体是由被另一个原核细胞吞噬的原核细胞进化而来的。

完美。我们试着深入挖掘一下,了解一下有哪些原核生物被怀疑变成了线粒体。

什么原核细胞?
答:据信吞噬另一个原核细胞的原核细胞是真核细胞的祖先。

那种明显的循环答案,不具知识性。反正不是我问的;但是我的问题很简短,所以让我说得更清楚些:

问:还记得是什么样的原核细胞让位于线粒体吗?
答:吞噬另一个原核细胞的原核细胞是真核细胞的祖先。

还是一个循环的回答。让我们离开线粒体。

问:还有其他例子吗?答:内共生理论的另一个例子是叶绿体的起源。叶绿体是真核细胞中从阳光中产生能量的细胞器。据信叶绿体是由被另一个原核细胞吞噬的原核细胞进化而来的。

问:你是说像蓝藻?
答:蓝藻是原核细胞,从阳光中产生能量。人们认为叶绿体是由被另一种原核细胞吞噬的蓝细菌进化而来的。

还行,但我忍不住了。

通过扩展培训进行初步分析和更深入的调查

我很惊讶。尽管有一些不正确的和部分正确的答案,我对 GPT 三号学到的高质量和多种多样的“知识”感到惊讶。特别是,答案中的例子非常丰富,大多数都是正确的。所有这些都符合我在以前的文章中得出的结论:GPT-3 非常善于检索它在训练中看到的事实数据。

尽管“原样”使用 GPT-3 作为学习生物学的学生的无人监督的 24/7 顾问是有风险的,但很明显,在这一学科中的表现优于物理或化学。现在好的一面是,错误的答案,比如首先说岩石是生物的,或者指向三种主要类型的细胞,都是可以治愈的。很有可能通过进一步训练系统,它可以纠正这些问题。看这些进一步的测试,我先教系统一些信息,然后问:

先教后问

就像以前一样,如果我直截了当地询问细胞的类型,系统会返回一个错误的答案:

问:有哪些种类的细胞?
答:有三种细胞:原核细胞、真核细胞和植物细胞。

但是如果我先用一段话告诉它有两种主要的细胞类型,然后我再问这个问题,系统会给出预期的答案:

细胞有两种主要类型:原核细胞和真核细胞。

问:有哪些种类的细胞?答:有两种主要的细胞:原核细胞和真核细胞。

请注意,即使问题的提出方式与给出的信息不同,这也是有效的:“细胞有两种主要类型”与“有哪几种细胞?”

此外,有趣的是,即使我在有正确答案的句子和实际问题之间给系统更多信息,这仍然有效:

细胞有两种主要类型:原核细胞和真核细胞。真核细胞含有细胞核、高尔基体等细胞器。植物也有叶绿体。有趣的是,线粒体和叶绿体似乎是在一些早期真核细胞吞噬细菌后进化而来的。立克次体可能让位于现代线粒体,而某些种类的蓝细菌可能变成了现代叶绿体。

问:有哪些种类的细胞?
答:有原核和真核两种细胞。

注意,如果我去掉第一句话,那么 GPT-3 的答案又错了:

真核细胞含有细胞核、高尔基体等细胞器。植物也有叶绿体。有趣的是,线粒体和叶绿体似乎是在一些早期真核细胞吞噬细菌后进化而来的。立克次体可能让位于现代线粒体,而某些种类的蓝细菌可能变成了现代叶绿体。
问:有哪几种细胞?
答:有三种细胞:原核细胞、真核细胞和植物细胞。

现在做好准备。令人瞠目结舌。我又问了线粒体和它们的起源,用这一段我喂给系统,这是我得到的:

细胞有两种主要类型:原核细胞和真核细胞。真核细胞含有细胞核、高尔基体等细胞器。植物也有叶绿体。有趣的是,线粒体和叶绿体似乎是在一些早期真核细胞吞噬细菌后进化而来的。立克次体可能让位于现代线粒体,而某些种类的蓝细菌可能变成了现代叶绿体。

问:有哪些种类的细胞?
答:有两种主要的细胞:原核细胞和真核细胞。

问:什么是线粒体?
答:线粒体是真核细胞中发现的细胞器。它们负责以 ATP 的形式产生能量。

问:线粒体从哪里来?
答:线粒体被认为是由早期真核细胞吞噬的细菌进化而来。

问:什么细菌?答:人们认为立克次体细菌产生了现代线粒体,而某些种类的蓝细菌则变成了现代叶绿体。

我没有明确地告诉 GPT-3 立克次体是细菌(虽然它可以从我写的文本中获得),然而系统想出了这个完美的句子,现在给出了我在考试中试图从中得出的正确、完整的答案!

现在,如果我去掉关于立克次体是线粒体前体的关键信息,那么最后一个问题的答案是错误的:

细胞有两种主要类型:原核细胞和真核细胞。真核细胞含有细胞核、高尔基体等细胞器。植物也有叶绿体。有趣的是,线粒体和叶绿体似乎是在一些早期真核细胞吞噬细菌后进化而来的。例如,某些种类的蓝细菌可能变成了现代的叶绿体。

问:有哪些种类的细胞?答:有两种主要的细胞:原核细胞和真核细胞。

问:什么是线粒体?
答:线粒体是真核细胞中发现的细胞器。它们负责以 ATP 的形式产生能量。

问:线粒体从哪里来?
答:线粒体被认为是由早期真核细胞吞噬的细菌进化而来。

问:什么细菌?
答:有人认为某些种类的蓝藻成为了现代的线粒体。

最后一个答案是错误的。

讨论

正如上一节开头几段所总结的,我参加的 GPT-3 的达芬奇考试显示,它非常擅长回答生物学上的事实问题,甚至有相当丰富的例子。然而,它有时会失败,最糟糕的是,所有的答案似乎都给出了高度的信心——这是应用程序在支持学生方面的一个关键缺陷。

现在,发现你可以用精选的事实来训练系统是一个游戏规则的改变者。原则上,人们可以向 GPT-3 提供一个精选的语料库,这将有助于纠正所有这些类型的问题,甚至可能填补内容上的空白。让我给你看最后一个例子,把训练推向极限:

如果我问 GPT-3 的达芬奇这个问题,高度具体到磷酸脂类生物学:

问:肌醇焦磷酸的细胞受体是什么?

运行只是挂起并抛出一个错误,要求我重新表述输入提示。

但是如果我输入(这里只是一部分)关于特定主题的论文介绍,然后我问,我得到的信息是正确的:

关于 SPX-PHR 相互作用的调节以响应养分有效性的变化,提出了两种机制:SPX 结构域被提议作为直接 Pi 传感器,SPX-PHR 相互作用在存在毫摩尔浓度的 Pi 时发生。或者,SPX–PHR 复合物的完整性可以通过蛋白质降解来调节。事实上,通过 26S 蛋白酶体的 SPX 降解在 Pi 饥饿下增加。真菌、植物和人类 SPX 结构域已被独立表征为肌醇焦磷酸 (PP-InsPs)的细胞受体,其以高亲和力和选择性结合 SPX 结构域。PP-InsPs 由完全磷酸化的肌醇环组成,分别在 C1 和/或 C5 位置携带一个或两个焦磷酸基团。在植物中,肌醇 1,3,4-三磷酸 5/6-激酶催化植酸(InsP6)磷酸化为 5PP-InsP5(下文称为 InsP7)。二磷酸肌醇五磷酸激酶 VIH1 和 VIH2 然后从 InsP7 产生 1,5(PP)2-InsP4(下文称为 InsP8)。植物二磷酸肌醇五磷酸激酶在遗传学上被认为在茉莉酸感知和植物防御反应中起作用,更重要的是,在衣藻属和拟南芥属中的营养感应中起作用。

问:肌醇焦磷酸盐的细胞受体是什么?
答:真菌、植物和人类 SPX 结构域是肌醇焦磷酸的细胞受体。

请注意,我并没有完全按照文本中给出的答案(粗体)来提问,但是系统可以找到它。

此外,我可以继续问更多的问题:

(介绍性文字同上)

问:什么酶磷酸化植酸?
答:在植物中,肌醇 1,3,4-三磷酸 5/6-激酶催化植酸(InsP6)磷酸化为 5PP-InsP5(以下简称 InsP7)。

请注意,这个问题与答案的措辞并不完全一样。

很明显,训练 GPT-3 号来扩展和修正它的知识库起作用了。我将在以后的文章中更详细地研究这一点——如果能从 OpenAI 和 NLP 专家那里听到这一点,那也是非常好的。

结论

在全球范围内,我怀疑 GPT-3 真的有潜力成为一名 24/7 的生物学导师,如果用可靠的数据语料库进行训练的话。这种数据的可能来源可以包括由专家教师准备的材料、来自上面举例说明的学术评论和论文的文本,甚至可能包括同行评审的生物学科学材料的完全开放存取语料库,例如来自 PubMed 的完全免费的文章或至少其摘要的完整记录。自然,考虑到大量的数据,这样的再训练不会是微不足道的。但这与已经用于预先训练系统的方法相当,这个想法听起来并不太牵强。

GPT-3 或它的进一步进化有一天会教会人类并帮助他们工作吗?和我一起参加这个系列的文章来测试 GPT-3 的能力吧!由作家卢西亚诺·阿布利亚塔创作的人物。

我是一个自然、科学、技术、编程和 DIY 爱好者。生物技术专家和化学家,在潮湿的实验室和电脑前。我写我广泛兴趣范围内的一切。查看我的 列表 了解更多故事。 成为中等会员 访问其所有故事和 订阅获取我的新故事 通过电子邮件 (我为其获得小额收入的平台的原始附属链接,无需向您支付特殊费用)。 通过各种方式在这里捐赠*。* 联系我这里 为任何一种查询。

咨询关于小工作 (关于编程、biotech+bio info 项目评估、科学外联+交流、分子数据分析与设计、分子图形、摄影、私人课程与教程、私人课程、教学与辅导等。)查看我的 服务页面这里

GPT-3 参数和提示设计

原文:https://towardsdatascience.com/gpt-3-parameters-and-prompt-design-1a595dc5b405

想法生成器、指令和目标层;灾难恢复摘要

罗马卡夫在 Unsplash 上拍摄的照片

GPT-3 是一个被设计用来生成自然语言的计算机系统。它通过接受一段文本,然后预测它后面应该出现的下一个单词或短语来做到这一点。

为了实现这一点,GPT-3 使用了一种深度学习算法,该算法已经在大型文本语料库上进行了训练。这使得它能够捕捉单词在句子中如何一起使用的统计模式。

GPT-3 可用于各种涉及自然语言生成的任务,如机器翻译、问答和文本摘要。GPT-3 甚至可以用来从头生成新的文本,如故事或文章。

在这篇博文中,我们将看看使用模型时可以设置的参数,并浏览 OpenAI 提出的几个示例

参数是什么?

OpenAI GPT-3 是一种机器学习模型,可用于通过 API 生成预测文本。OpenAI 有不同的模型可供我们使用,最有能力的一个叫做“text-davinci-002”。

为了使用该模型,我们可以如下发送 API 请求。

curl [https://api.openai.com/v1/completions](https://api.openai.com/v1/completions) \
 -H “Content-Type: application/json” \
 -H “Authorization: Bearer $OPENAI_API_KEY” \
 -d ‘{
 “model”: “text-davinci-002”,
 “prompt”: “What are 5 key points I should know when studying Ancient Rome?”,
 “temperature”: 0.3,
 “max_tokens”: 150,
 “top_p”: 1,
 “frequency_penalty”: 0,
 “presence_penalty”: 0
}'

引擎 引擎参数指定用于生成预测的 AI 模型。在本文中,我们将使用最有能力的一个:“文本-达芬奇-002”。

最大令牌数 “最大令牌数”参数指定模型可以生成的最大令牌数。一个令牌可以被看作是一个单词。

根据经验,1 个令牌大约有 4 个字符。

温度 在映射到概率之前,模型输出非标准化值(logits)。logits 通常与 softmax 等函数一起使用,将它们转换为概率。

但是,在应用 softmax 函数之前,我们可以使用一个受热力学启发的技巧,用温度参数(即 softmax(logits/temperature ))来缩放对数。

接近 1 的温度参数意味着 logits 不加修改地通过 softmax 函数。如果温度接近于零,则与其他表征相比,最可能的表征将变得非常可能,即,模型变得更具确定性,并且将总是在给定的单词序列之后输出相同的表征集。

温度在 0 到 1 之间,我们可以控制模型预测的随机性和创造性。

Top p Top p 参数指定推断时间内的采样阈值。Top p 采样(有时称为核采样)是一种用于对模型的可能结果进行采样的技术。

为了更好地理解这个概念,我们假设模型要预测句子“我要吃饭”之后的下一个令牌。为简单起见,我们将假设令牌是一个单词,并且模型输出以下概率:

  • 胡萝卜(2%的可能性),
  • 黄瓜(1.5%的可能性),
  • 茄子(1%的可能性),
  • 菠菜(0.5%的可能性),
  • 西兰花(0.3%的可能性),

这组单词形成概率分布“P(Word |“I want to eat”)”,累积分布函数(CDF)看起来如下:

  • 2%用胡萝卜,
  • 胡萝卜和黄瓜占 3.5%,
  • 胡萝卜、黄瓜和茄子占 4.5%

如果我们将顶部 p 参数设置为 3.5%,模型将根据可能性在胡萝卜和黄瓜之间进行采样和随机选择。由于 top p 为 4.5%,该模型将在胡萝卜、黄瓜和茄子之间随机选择一个词。

和温度一样,top p 参数控制着模型的随机性和独创性。

Top p 和温度参数都控制模型的随机性。OpenAI 文档建议使用其中一个参数,并将未使用的参数设置为中性,即 1.0。

频率惩罚 频率惩罚参数控制模型重复预测的趋势。频率损失降低了已经生成的单词的概率。惩罚取决于一个单词在预测中已经出现了多少次。

存在惩罚 存在惩罚参数鼓励模型做出新颖的预测。如果单词已经出现在预测文本中,则存在惩罚降低了该单词的概率。与频率惩罚不同,存在惩罚不依赖于单词在过去的预测中出现的频率。

语法纠正

Engine: text-davinci-002Max tokens: 60Temperature: 0Top p: 1.0Frequency penalty: 0.0Presence penalty: 0.0

科技一直是作家和语法学生的福音。过去,我们有拼写检查器和语法检查器来帮助我们发现错误。但是现在,即使是 GPT-3 也能做这项工作并捕捉错误。

这对于那些母语不是英语的人或者在语法上有困难的人来说特别有帮助。

提示

Correct this to standard English: I’m looking forward to see you

响应

I’m looking forward to seeing you.

所以,如果你正在寻找一种方法来提高你的写作水平,试试 GPT-3 版的语法修正吧。你可能会惊讶于它的帮助有多大。

创意生成器

Engine: text-davinci-002Max tokens: 150Temperature: 0.6Top p: 1.0Frequency penalty: 1Presence penalty: 1

如果你正在努力想出新的点子,你可能也想考虑使用 GPT-3。

例如,你可以告诉人工智能想出对环境友好的新产品的想法。然后人工智能会生成一个潜在想法的列表供你选择。

提示

come up with ideas for a new product that is environmentally friendly:

响应

1\. A reusable water bottle that can be refilled from the tap. 2\. A reusable shopping bag made from recycled materials. 3\. A solar-powered cell phone charger. 4\. An LED light bulb that lasts for years and consumes very little energy.

你也可以使用 GPT-3 来寻找你所面临的问题的解决方案。例如,如果你试图增加你商店的销售额,人工智能可以生成一系列营销想法供你考虑。

提示

brainstorm solutions to increase sales at your store:

回应

1\. Offer discounts or coupons. 2\. Host a sale or clearance event. 3\. Create an attractive window display. 4\. Place items on end caps or near the register. 5\. Train staff to upsell and cross-sell products. 6\. Implement a loyalty program. 7\. Send out direct mailers or emails. 8\. Place ads in local publications. 9\. Sponsor a community event. 10\. Get involved with social media marketing

因此,如果你正在寻找一种创造性的方法来解决问题,GPT-3 可能正是你所需要的。

TL;灾难恢复总结

Engine: text-davinci-002Max tokens: 60Temperature: 0.7Top p: 1.0Frequency penalty: 0.0Presence penalty: 0.0

任何花时间上网的人都知道,网上有很多文本。有时候,很难从头到尾看完。

用 TL;博士,你可以很快得到一篇文章的要点,而不必通读全文。现在,GPT-3 可以为您完成这项工作。

只需将您想要总结的文本输入到工具中,它就会尽力为您提供一个简明的概述。

提示

Technology has always been a boon for writers and students struggling with grammar. In the past, we had spell checkers and grammar checkers to help us catch mistakes. But now, even GPT-3 can do the work and catch errors.This can be especially helpful for those who are non-native English speakers or who have difficulty with grammar.Tl;dr

响应

If you’re struggling with your grammar, consider using an AI-powered grammar checker to help you improve your writing.

我们能给出额外的指示吗?

这一部分可能是最吸引人的。我们可以通过在提示中添加上下文来“指导”算法如何响应请求。

提示

my company produces reusable water bottles that can be refilled from the tap.brainstorm solutions to increase sales at your store: 

响应

1\. Offer a discount to customers who purchase your reusable water bottles. 2\. Place your water bottles in high-traffic areas of your store so that more people will see them. 3\. Educate your staff about the benefits of using reusable water bottles and encourage them to use them themselves. This will create a positive example for customers. 4\. Make sure that your water bottles are easy to find and accessible in your store so that customers can easily grab one when they need it.

我们添加到提示中的上下文直接反映在响应中。

当模型根据提示中给出的令牌预测下一个令牌时,这种行为是意料之中的。

有时候一句话就能改变整个反应。例如,如果我们使用单词“summary”而不是“TL ”,我们可以得到更长的响应;博士”:

提示

Technology has always been a boon for writers and students struggling with grammar. In the past, we had spell checkers and grammar checkers to help us catch mistakes. But now, even GPT-3 can do the work and catch errors. This can be especially helpful for those who are non-native English speakers or who have difficulty with grammar. Summary: 

响应

Technology has always been a boon for writers and students struggling with grammar. In the past, we had spell checkers and grammar checkers to help us catch mistakes. But now, even GPT-3 can do the work and catch errors.

结论

GPT-3 计算机系统被设计成通过预测下一个单词或短语来生成自然语言。这种深度学习算法已经在一大组文本上训练过,允许它捕捉单词在一个句子中如何一起使用的统计模式。

GPT-3 是一个优秀的工具,我们可以用它来提出新的想法,纠正语法错误,甚至生成文本。为了最大限度地利用模型,我们可以玩参数,但我们也可以以这样一种方式设计提示,它将人工智能引向所需的响应。

感谢阅读!

好奇想了解更多关于 Anthony 的工作和项目吗?在媒体LinkedInTwitter 上关注他

需要技术写手?将您的请求发送到https://amigo CCI . io

GPT 3 号,下棋!

原文:https://towardsdatascience.com/gpt-3-play-chess-d123a96096a9

如何使用 GPT 3(open ai API)创建国际象棋引擎

照片由 skPexels 拍摄

这里有许多 GPT-3 在生成源代码、编写故事等方面创造奇迹的演示。我结合了我的两个兴趣,人工智能和国际象棋,探索用 GPT-3 创建一个国际象棋引擎的可能性。国际象棋人工智能很常见,它们甚至可以轻松击败最优秀的人类选手。利用 GPT-3 创建国际象棋引擎的目标是测试一个单一的人工智能模型是否可以执行几项工作,如编写故事和下棋。现有的 AI 解决方案是狭义的 AI,意味着它们只能完成一项任务。人工通用智能(AGI),或可以像人类一样完成各种任务的人工智能,是 GPT-3 等人工智能模型的承诺。这篇文章讨论了我如何使用 GPT-3 来创建一个国际象棋引擎,以及它是如何运行的。

什么是 GPT-3?

GPT-3 是一个1750 亿参数的人工智能语言模型,已经在大量数据上进行训练。简单来说,语言模型是一个人工智能模型,它可以在给定一组输入单词的情况下预测下一组单词(非常像搜索引擎中的自动完成功能)。大型语言模型,如 GPT-3,更进了一步,能够根据描述或建议生成源代码或故事。GPT-3 背后的创业公司 OpenAI 已经通过 API 向开发者提供了它的模型。你可以在这里注册,你会得到 18 美元的积分。

语言模型怎么下棋?

乍一看,语言模型与国际象棋毫无关系。但是我们可以通过把下棋框定为文本生成问题来欺骗它下棋。棋盘上的每个方格都用一个字母和一个数字来命名。水平方块标记为“a”到“h ”,垂直方块标记为 1 到 8。因此,每个方块可以通过坐标对来识别,如左下方的 a1。国际象棋游戏被记录为一系列符号,俗称 PGN(便携式游戏符号)。例如:1.e4 e5 2。d4 d5 等。

使用这些符号,我们可以通过输入到目前为止游戏的 PGN 并要求它预测下一个单词(移动)来将下棋框定为一个文本生成任务。有理由期待 GPT 3 号的大量输入数据也一定包括一些国际象棋比赛的数据。我们可以看到 GPT-3 能多好地选择这些并玩游戏。这就是我使用 OpenAI APIs 所做的事情,细节将在本文后面介绍。

使用 GPT-3 创建国际象棋引擎

我的游戏(白色)vs GPT-3(黑色)【图片由作者使用 chess.com 创建】

既然 GPT-3 不知道什么是国际象棋,那么期望它通过使用默认模型来击败国际象棋大师是不合理的!我这个项目的目标是学习更多关于 OpenAI APIs 的知识,并展示使用 GPT 3 创建定制任务是多么简单。为了让 GPT-3 开始下棋,我只需给出以下提示:“下棋 1。e4”。就这么简单!我的第一步是将我的棋子移动到方块 e4(方块 e4)。根据这个提示,GPT-3 返回一个完整的游戏,从我的移动开始!我将输出限制为仅获取下一步棋,比如说 e5,然后进行第二步棋,比如说 d4,并将其馈送给 GPT-3(例如:1e4 e5 2。d4)。GPT-3 使用更新的 PGN 和迄今为止的所有动作来预测下一步。

把它编码

OpenAI 提供 API,细节可以在这里找到。你需要 OpenAI API 密匙来使用这些 API,它们是在注册时提供的。对于下棋,我使用了完成 API,它接受一个提示作为输入,并返回预测的完成,在我们的例子中是下一步棋。

指导 GPT-3 开始下棋(图片由作者提供)

GPT-3 API 调用中使用的参数解释如下。

提示: 用于文本生成过程的提示

发动机:GPT-3 共有 4 种型号,命名为阿达、巴贝奇、居里、达芬奇(以字母 a、b、c、d 开头)。这些型号在性能和成本上也有所不同。为了获得最佳性能,请使用达芬奇,但请注意,它比最接近的 Curie 型号贵 10 倍。

n: 要返回的预测数。由于 GPT-3 不能保证每次都提供合法的移动,所以最好提供大于 1 的 n 来获得有效的移动。

max_tokens: 大致翻译为输出的字数。因为移动通常是一个字母和一个数字,2 是最小的。但一些复杂的移动需要更多的字母(如 Qxe8+),所以提供 6 是安全的。

显示棋盘和移动的示例代码(图片由作者提供)

Jupyter 笔记本中创建的棋盘(图片由作者提供)

为了可视化棋盘并进行移动,我使用了 python-chess 库。该库提供了一个 API 来在棋盘上移动。如果 GPT-3 返回的移动不合法,它将返回一个异常。这个异常可用于使用 GPT-3 返回的下一个最佳步骤。我用 Jupyter Notebook 把棋盘可视化,在虚拟棋盘上玩游戏。本文末尾提供了完整源代码的链接。

评估绩效

我已经向你展示了如何让 GPT-3 下棋。现在下一个问题是它的表现如何。这有点复杂,因为 GPT-3 下棋的方式与我玩过的其他人工智能棋非常不同。通常情况下,国际象棋引擎非常强大,玩得远远超出人类水平。为了达到人类的水平,他们故意间歇性地做出非常糟糕的动作。GPT-3 的打法非常不同。

GPT-3 开局打得很好,但在中局中挣扎,并在正式结束前输掉了比赛。我相信这是因为它正在根据它看到的训练数据来玩动作。由于开放是普遍的,它已经看到了很多这样的举动。因为中局的可能移动集合太大了,它不可能看到我们正在玩的游戏的精确移动集合。它开始出错,丢失棋子,并变得容易被提前将死。

GPT-3 如果能够打一场更好的中局,它会在残局中表现出色,因为残局的选择是有限的(如国王&卒 vs 国王),而且它会在训练数据中看到许多这样的游戏。我注意到的另一个问题是,GPT-3 有时很难回应合法的举动。这是意料之中的,因为它只是一个语言模型,对国际象棋规则一无所知。为了解决这个问题,我们可以使用下一个最佳预测移动或要求 GPT-3 再次预测。OpenAI 提供了一个微调工具,可以有把握地认为,在我们对一个定制的象棋游戏数据集进行微调后,GPT-3 将表现得非常好。

结论

GPT-3 是人工智能的一项突破,为人工智能(AGI)迈出了充满希望的一步——你什么时候见过同样的人工智能解决方案被用于写歌和下棋!OpenAI APIs 非常直观,合理的成本使我们能够使用 GPT-3 构建生产应用程序。如图所示,这些 API 可以创造性地用于许多用例。这个实验的完整源代码可以在这里找到。和 GPT-3 下棋愉快!

GPT-3,RNNs 和所有这一切:深入研究语言建模

原文:https://towardsdatascience.com/gpt-3-rnns-and-all-that-deep-dive-into-language-modelling-7f67658ba0d5

实践教程

GPT-3,RNNs 和所有这一切:深入研究语言建模

神经网络如何用于语言建模:多层感知器、rnn 和变压器。

安德烈·德·森蒂斯峰在 Unsplash 上拍摄的图片。

由于我一直在做的工作,我已经接触到了大型语言模型(LLM),一些我以前并不真正了解的东西。在这篇文章中,我将总结我在这个问题上所学到的一切。我们将从非常简单的(大约 40 年前研究人员正在做的)到最先进的,停留在一个大画面的水平。这个想法不是为了得到正确的数学细节,而是为了能够对这些语言模型中正在发生的事情给出一个好的“大体上”的解释。

我们到底在模拟什么?

说“我们训练一个理解语言的模型”很容易,但这是什么意思呢?这在实践中意味着一件简单的事情,即“给定一个字符序列,预测最可能的下一个字符”。例如,我们可以在一个英语单词语料库上训练一个模型,然后我们给它输入短语“Foo”,希望它会输出字符“d”(或“l”),我们就会有单词“Food”或“Fool”。这些模型是字符级语言模型。另一个意思是“给定一个单词序列,预测下一个最有可能的单词”。这就是大型语言模型(LLM)用来解决的问题。

玩具问题:训练一个模型打招呼

我们可以想象一个超级简单的语言建模问题是这样的:假设我们只知道四个字母:H、E、L 和 O。如果我们在训练序列“heLLO”上训练一个模型,我们预计如果我们给它输入“HE ”,它将输出“L ”,如果我们给它输入“HELL ”,它将输出“O”。

更正式地说,我们可以这样写:什么字符 c_n 最大化概率 P(c_n | c_{n-1},…,c_0)?

在上面的例子中,c_n 是字母“O”。

你是怎么用文字做数学的?

神经网络基本上是大型演算机,处理大量偏导数(用于反向传播)并应用非线性函数(如双曲正切函数或 sigmoid 函数)。但是你怎么用字母做微积分呢?你不知道。相反,您使用单词嵌入,这意味着将字符转换为向量的模式。这些方法中最简单的是 1-to-k 编码:在上面的小例子中,我们的词汇表是[H,E,L,O],因此字母 H 被编码为[1,0,0,0]向量,字母 E 被编码为[0,1,0,0]等等。好了,现在我们已经将字符转换为向量,我们肯定可以将向量输入到神经网络中(这是输入层)。

多层感知器在自然语言处理中的应用

你的训练数据是一个词的语料库(例如一本书)。语料库中的单词集就是你的词汇表。假设书上只说“吃披萨吃披萨吃披萨”。你的书里只有 3 个词:[“吃”、“the”、“披萨”]。这其中的每一个单词都有自己的嵌入(或编码):[1,0,0]是“吃”,[0,1,0]是“那个”,[0,0,1]是“披萨”。注意,每个向量的长度就是我们的词汇量的大小(即 3)。所以我们给我们的多层感知器(MLP)一个大小为 3 的输入层。然后,我们可以放置尽可能多的隐藏层,我们的输出层也必须有大小 3。然后是通常的故事:你用随机权重和偏差初始化你的网络,一个例子接一个例子地训练你的网络(一个编码字接一个编码字),计算损耗,用反向传播调整参数等等…

如果你对 MLPs 的工作方式有点不确定,看看这个上的 3blue1brown 的视频系列,我从未见过更清楚的解释。我们在这里学到的最酷的事情是,你可以使用这种技术来预测句子中的下一个单词——所以原则上这足以让建造一个聊天机器人

MLPs 应用于 NLP 时的限制:它们接受固定大小的向量输入,输出固定大小的向量输出。所以在预测文本的上下文中,我们可以给他们一个单词,他们会输出更多的单词。但是如果我想给他们一个句子,让他们输出下一个单词呢?办不到,我们只能给它最后一句话。这意味着它不能考虑句子中前面单词的上下文。

最后,我们给出了一个如何对单词进行编码的最简单的例子:我们的 1 到 k 编码。很明显,我们可以用其他方式对信息进行编码。人们使用 word2vecgloVe 但它们如何工作并不太重要,酷的事情是:取一个单词(或一个字符)→将其转换为向量→现在你可以用单词进行机器学习了!

为什么递归神经网络(RNNs)更合适

对于语言建模来说,RNNs 比 MLPs 更令人兴奋的关键是它们允许我们处理向量序列。所以我们可以输入一个句子,它是单词的向量表示序列,然后得到一个输出向量。

让我们把自己限制在这样的情况下,我们想要给出一个输入序列(例如,表示一个句子的向量列表)并得到一个输出。

RNNs 也学习状态向量,而不是像 MLPs 那样学习层之间的一组权重和偏差来产生输出。RNN 的输出是这个状态向量的函数。当我们向模型输入一系列向量时,这个状态向量就被传递了。假设我们给模型一个向量序列(代表单词),我们想要输出一个向量(代表最可能的下一个单词)。

c_i 是输入到模型的单词(矢量化),除了 c_3 是输出。s_i 是传递的状态向量。在每一步模型都可以产生一个输出,除了最后一步,这些都被去掉了,因为我们只对建立相关的状态向量来预测 C3 感兴趣。来源:安德烈·卡帕西的博客

假设我们输入三个单词,想要一个单词输出。我们将句子中的第一个向量(c_0)输入到模型中,将它的状态向量更新为 s_1。然后我们输入下一个向量 C1,它将状态向量更新为 C2。再做一次。该模型的输出是这个最终输入的函数、前一遍的状态向量(它本身是第一个向量的函数——因此对句子的开始有一些记忆)和在训练期间学习的权重矩阵。现在我们有了。在每一次传递中,我们基本上都在做与 MLP 相同的事情,但是我们也在更新这个状态向量并传递它。

消失梯度问题

如果你想给模型更多的上下文,你需要给它一个长的向量输入序列。但这意味着你的 RNN 会有很多步骤。

权重和偏差更新的方式是通过反向传播算法计算的。问题在于,一个层的权重和偏差的调整幅度与它和输出层之间所有层的损失函数的导数的乘积成比例。对于 RNNs 中使用的激活函数(通常为 tanh ),这些导数可能非常小,因此它们的乘积往往会消失。如果前几层中的权重和偏差由于这种消失梯度而很少更新,这意味着网络没有真正学会如何使用它们。

因此,rnn 在理解上下文方面肯定比 MLP 做得更好,至少他们有一些短期记忆,但不要指望他们因为消失的梯度而记住太多层的东西。

长短期记忆网络(LSTMs):调整了记忆时间更长的 rnn

LSTMs 是一种特殊的 RNN,设计用于处理输入序列中的长期相关性。这意味着,在句子输入的上下文中,如果句子很长,LSTMs 将比我们描述的普通 RNN 更好地考虑句子的开始。

LSTM 的关键创新是“细胞状态”,基本上这是另一个状态向量,就像我们之前图表中的 s_i,但它的更新方式不同。有一些被称为“门”的功能,在输入序列的每一步,控制细胞状态中什么被遗忘,什么被添加。有两个门:“忘记门”和“输入门”。它们可以分别删除和添加单元状态的信息。这些事情背后的确切机制并不特别复杂或有趣,就像机器学习的常见情况一样,它只是一些 sigmoids 和 tanh 函数应用程序的时髦组合,您可以将其应用于向量,结果是新的细胞状态。

cs_i 表示单元状态,就像一条信息传送带,在序列中的每个新输入处都会有选择地更新。来源:图片来自安德烈·卡帕西的博客(由作者编辑)。

使用 rnn/lstm 的缺点

LSTMs 和 vanilla-rnn 在语言建模任务方面有很好的表现(还有一些其他非常酷的东西,比如玩星际争霸)。但是一个很大的缺点是训练它们需要很长时间。由于其架构的顺序性质,不可能并行训练这些模型。由于深度学习通常情况下(如果做得好)更多的数据、更多的层和更多的训练会导致更好的性能,因此无法加快大规模 rnn 的训练令人沮丧。

作为一名软件开发人员,我学到了一些东西,其中之一就是:当代码运行缓慢时,将它并行化!我听说过一个剑桥大学物理系的博士生的案例,他拿了一个需要几周才能运行的软件,他把加速它作为自己的使命。通过大规模并行化,他设法把时间缩短到几个小时。

编码器-解码器网络

我们将暂时进入机器翻译的世界(这是最初发明变形金刚的目的)。假设你想把一个句子从德语翻译成英语。你可以用两个 rnn 来实现,一个“编码器”,一个“解码器”。下图更清楚地说明了这一点:

首先,RNN(红色)对来自德语单词序列的信息进行编码。第二个 RNN(绿色)将这些信息翻译成英语。H_i 是状态向量(“隐藏状态”),表示“序列的开始”。来源:本文由 Bezerra 等人撰写。

注意机制

当我们从编码器到解码器时,我们可以:给解码器网络最终的隐藏状态,或者我们可以给它所有隐藏状态的加权和。后者被称为“注意机制”。像往常一样,听起来很时髦的名字,但背后的想法很简单。据我所知,其他注意机制基本上只是“对隐藏状态进行加权平均”的更复杂版本。

好了,最后两段非常简单,但这是理解 transformer 的必要上下文。

变压器型号

这种模型架构被认为是 NLP 中最先进的。它们采用了编码器-解码器结构,但这两者都不是 rnn,而是 MLPs 和注意机制的组合。

在一个高层次上,转换器是这样工作的:取序列中的所有向量,使用“多头”注意力和 MLP 计算所有向量的编码器状态。您不需要知道序列中第一个元素的编码器状态来计算序列中后续元素的编码器状态。这非常巧妙,因为它有助于通过并行处理大大加快模型的训练。

“多头注意力”到底是什么,对于大致了解发生了什么并不太重要。基本上,事情是计算序列中的每个其他单词(向量)与正在处理的输入的相关程度。

然后,所有编码状态被传递到解码器网络,这些状态被顺序处理(因此这实际上不能被并行处理)以产生输出序列。

GPT-3:一个变压器的例子

根据维基百科,GPT-3 是“一种自回归语言模型”。自回归只是一个花哨的说法:通常已知的模型(如线性回归)是“回归的”,即它们使用一组预测变量来预测目标变量的未来值。相比之下,自回归模型只使用目标变量的以前值来预测未来值。例如,如果你在模拟股票价格,我们会说你的模型是“自回归”的,如果你只用股票价格的过去值来预测未来值。如果你使用其他信息,比如市盈率,你的模型将是“回归的”。因此,我们在本文中研究的所有模型都是自回归的。

我们做到了!希望这篇文章能帮助你对语言建模在过去几十年中的发展有一个高层次的理解,这些东西是有用的:我们从 MLPs,到 RNNs,到 LSTMs,到 Transformers。

来源:

GPT 4 号即将发射。以下是我们对它的了解

原文:https://towardsdatascience.com/gpt-4-is-coming-soon-heres-what-we-know-about-it-64db058cfd45

官方信息、当前趋势和预测。

照片由 Shutterstock 上的 Pinkeyes 拍摄

更新: GPT-4 出局

GPT 4 号的发布日期越来越近了。

GPT-3 于 2020 年 5 月宣布,差不多两年前。它是在 GPT-2 之后一年发布的,后者也是在 GPT 论文发表一年后发布的。如果这种趋势在各个版本中都保持不变,GPT 4 应该已经出现了。事实并非如此,但 OpenAI 的首席执行官萨姆·奥特曼(Sam Altman)几个月前表示,GPT 4 号即将到来。目前的估计预测发布日期在 2022 年的某个时候,可能在 7 月-8 月左右

尽管这是最令人期待的人工智能新闻之一,但关于 GPT-4 的公开信息很少:它会是什么样子,它的特点,或者它的能力。奥特曼去年进行了一次问答,并就 OpenAI 对 GPT 4 号的想法给出了一些提示(他要求参与者对这些信息保密,我一直保持沉默——但七个月是一个合理的时间余量)。他肯定的一点是,GPT-4 不会有 100T 的参数,正如我在之前的一篇文章中假设的(这么大的型号还得等等)。

自从 OpenAI 透露任何关于 GPT 4 号的信息已经有一段时间了。然而,在人工智能领域,特别是在自然语言处理领域,一些正在获得巨大牵引力的新趋势可能会给我们提供 GPT-4 的线索。鉴于这些方法的成功和 OpenAI 的参与,从 Altman 的话中做出一些可接受的预测是可能的。当然,这些超越了众所周知的——也是令人厌倦的——让模型变得越来越大的做法。

根据我们从 OpenAI 和 Sam Altman 那里获得的信息,以及当前的趋势和人工智能语言的艺术水平,下面是我对 GPT-4 的预测。(明确的或者上下文的,我会说清楚哪些是猜测,哪些是确定的。)

模型尺寸:GPT-4 不会超级大

GPT-4 不会是最大的语言模型。奥特曼说它不会比 GPT 3 号大多少。与前几代神经网络相比,这个模型肯定会很大,但大小不会是它的显著特征。它可能位于 GPT-3 和地鼠 (175B-280B)之间。

这个决定是有充分理由的。

由英伟达和微软去年建造的威震天-图灵 NLG ,以 530B 的参数保持着最大密集神经网络的头衔——已经比 GPT-3 大 3 倍——直到最近(谷歌的 PaLM 现在保持着 540B 的头衔)。但值得注意的是,在 MT-NLG 之后出现的一些较小的型号达到了更高的性能水平。

越大≠越好。

更好的小模型的存在有两层含义。

首先,公司已经意识到使用模型大小作为提高性能的代理不是唯一的方法——也不是最好的方法。2020 年,OpenAI 的 Jared Kaplan 和他的同事得出结论,当计算预算的增加主要用于扩展参数数量时,性能提高最多,遵循幂律关系。谷歌、英伟达、微软、OpenAI、DeepMind 和其他开发语言模型的公司对这些指导方针信以为真。

但是 NLG 山虽然很大,但在性能方面并不是最好的。事实上,在任何单一类别的基准测试中,它都不是最好的。较小的型号,如 Gopher (280B)或Chinchilla(70B)——仅仅是它的一小部分——在任务上比 MT-NLG 好得多。

很明显,模型的大小并不是获得更好的语言理解的唯一因素,这让我想到了第二个含义。

公司开始拒绝“越大越好”的教条。拥有更多参数只是提高性能的众多因素之一。附带损害(例如碳足迹、计算成本或进入壁垒)使其成为最糟糕的考虑因素之一,尽管实施起来非常简单。当公司能够从一个较小的模型中获得类似的——或者更好的——结果时,他们会在建立一个巨大的模型之前三思。

奥尔特曼说,他们不再专注于让模型变得非常大,而是专注于让较小的模型发挥最大的作用。OpenAI 研究人员是缩放假说的早期倡导者,但现在可能已经意识到其他未探索的途径可以导致改进的模型。

GPT 4 号不会比 GPT 3 号大多少,这就是原因。OpenAI 将把重点转向其他方面——如数据、算法、参数化或对齐——这可能会更干净地带来重大改进。我们还得等着看 100T 参数模型的能力。

最佳化:充分利用 GPT-4

当谈到优化时,语言模型受到一个严重的限制。这种培训非常昂贵,公司不得不在准确性和成本之间进行权衡。这通常会导致模型明显优化不足。

GPT-3 只训练了一次,尽管有些错误在其他情况下会导致重新训练。由于无法负担的成本,OpenAI 决定不这样做,这使得研究人员无法找到该模型的最佳超参数集(例如,学习率、批量大小、序列长度等)。

高培训成本的另一个后果是对模型行为的分析受到限制。当卡普兰的团队得出模型大小是提高性能的最相关变量的结论时,他们没有考虑训练令牌的数量,即模型输入的数据量。这样做需要大量的计算资源。

科技公司遵循卡普兰的结论,因为这是他们最好的结论。具有讽刺意味的是,谷歌、微软、脸书和其他公司在越来越大的模型上“浪费”了数百万美元——在这个过程中产生了大量的污染——而这恰恰是受经济限制的驱使。

现在,以 DeepMind 和 OpenAI 为首的公司正在探索其他方法。他们试图找到最佳模型,而不仅仅是更大的模型。

最佳参数化

上个月,微软和 OpenAI 证明了 GPT-3 可以进一步改进,如果他们用最佳超参数训练模型的话。他们发现,GPT-3 的 6.7B 版本的性能提高了很多,可以与最初的 13B GPT-3 模型相媲美。超参数调优—对于较大的模型不可行—导致了相当于参数数量翻倍的性能提升。

他们发现了一种新的参数化(μP ),其中小模型的最佳超参数也是同一家族中较大模型的最佳参数。μP 允许他们优化任意大小的模型,只需很少一部分训练成本。然后,超参数可以几乎无成本地转移到更大的模型中。

最佳计算模型

几周前,DeepMind 重新审视了卡普兰的发现,并意识到,与人们的想法相反,训练令牌的数量与模型大小一样影响性能。他们的结论是,随着更多计算预算可用,应该平均分配给扩展参数和数据。他们通过训练龙猫来证明他们的假设,这是一个 70B 的模型(比 Gopher 小 4 倍,以前的 SOTA),数据量是自 GPT 3 以来所有大型语言模型的 4 倍(1.4T 令牌——来自典型的 300B)。

结果是明确的。在许多语言基准测试中,龙猫“一致且显著地”超过了地鼠、GPT-3、NLG 山和所有其他语言模型:当前的模型训练不足且过大。

鉴于 GPT-4 将略大于 GPT-3,它需要达到计算优化的训练令牌数量(根据 DeepMind 的发现)将约为 5 万亿——比当前的数据集高出一个数量级。他们训练模型以达到最小训练损失所需的失败次数将比他们在 GPT-3 中使用的次数多 10-20 倍左右(使用 Gopher 的计算预算作为代理)。

当奥特曼在问答中说 GPT-4 将比 GPT-3 使用更多的计算时,他可能指的就是这一点。

OpenAI 肯定会在 GPT-4 中实现优化相关的见解——尽管在多大程度上是不可预测的,因为他们的预算是未知的。可以肯定的是,除了模型尺寸之外,他们将专注于优化其他变量。找到最佳的超参数集以及最佳的计算模型大小和参数数量可以在所有基准测试中带来难以置信的改进。如果将这些方法结合到一个模型中,所有对语言模型的预测都将失败。

奥特曼还说,如果不把模型做大,人们不会相信模型能有多好。他可能是在暗示,扩大规模的努力暂时结束了。

多模态:GPT 4 将是一个纯文本模型

深度学习的未来是多模态模型。人类的大脑是多感官的,因为我们生活在一个多模态的世界里。一次以一种模式感知世界极大地限制了人工智能导航或理解世界的能力。

然而,好的多模态模型比好的纯语言或纯视觉模型更难构建。将视觉和文本信息组合成一个单一的表示是一项艰巨的任务。我们对大脑如何做到这一点的概念非常有限(不是说深度学习社区考虑了认知科学对大脑结构和功能的见解),所以我们不知道如何在神经网络中实现它。

奥特曼在问答中说,GPT 4 不会是多模态的(像 DALL E 或 MUM),而是一个纯文本的模型。我猜他们正试图达到语言模型的极限,在跳到下一代多模态人工智能之前,调整模型和数据集大小等因素。

稀疏性:GPT-4 将是一个密集模型

稀疏模型利用条件计算,使用模型的不同部分来处理不同类型的输入,最近获得了巨大的成功。这些模型可以轻松扩展到 1T 参数以上,而不会遭受高计算成本,从而在模型大小和计算预算之间建立了一种看似正交的关系。然而,MoE 方法的好处在非常大的模型上逐渐减少。

鉴于 OpenAI 专注于密集语言模型的历史,有理由期待 GPT-4 也将是一个密集模型。鉴于奥特曼说 GPT-4 不会比 GPT-3 大多少,我们可以得出结论,稀疏性不是 OpenAI 的一个选项——至少现在是这样。

稀疏性,类似于多模态,将很可能主导未来几代神经网络,因为我们的大脑——人工智能的灵感——严重依赖稀疏处理。

对齐:GPT-4 将比 GPT-3 更加对齐

OpenAI 已经付出了很多努力来解决人工智能对齐问题:如何让语言模型遵循我们的意图并坚持我们的价值观——无论这到底意味着什么。这不仅仅是一个数学上的难题(即我们如何才能让 AI 准确理解我们想要什么?),但也是哲学上的(即,没有一种通用的方法可以让人工智能与人类保持一致,因为人类价值观在不同群体之间的差异是巨大的——而且往往是冲突的)。

然而,他们用 InstructGPT 进行了第一次尝试,这是一个更新的 GPT-3,经过人类反馈的训练,以学习遵循指令(这些指令是否是善意的尚未纳入模型)。

InstructGPT 的主要突破是,不管它在语言基准上的结果如何,它都被人类评委视为一个更好的模型(人类评委组成了一个非常同质的群体——open ai 员工和说英语的人——所以我们应该小心提取结论)。这突出了克服使用基准作为评估人工智能能力的唯一标准的必要性。人类如何看待这些模型同样重要,如果不是更重要的话。

鉴于 Altman 和 OpenAI 对有益的 AGI 的承诺,我相信 GPT-4 将实施——并建立在——他们从 InstructGPT 获得的发现的基础上。

他们将改进他们调整模型的方式,因为它仅限于 OpenAI 员工和讲英语的贴标机。真正的结盟应该包括具有各种起源和性别、种族、国籍、宗教等特征的群体。这是一个巨大的挑战,任何朝着这个目标的步骤都是受欢迎的(尽管我们应该谨慎地称之为调整,因为它并不适合大多数人)。

总结…

型号大小: GPT-4 将比 GPT-3 更大,但与目前最大的型号(MT-NLG 530B 和 PaLM 540B)相比不会很大。型号大小不会是一个显著的特征。

优化: GPT-4 将比 GPT-3 使用更多计算。它将在参数化(最优超参数)和比例法则(训练令牌的数量与模型大小一样重要)方面实现新的优化见解。

多模态: GPT-4 将是纯文本模式(非多模态)。OpenAI 希望在完全跳到 DALL E 这样的多模态模型之前,最大限度地利用语言模型——他们预测这种模型将在未来超过单模态系统。

稀疏度: GPT-4 将遵循 GPT-2 和 GPT-3 的趋势,成为一个密集模型(所有参数将用于处理任何给定的输入)。稀疏性在未来会变得更占优势。

结盟:GPT 4 号将比 GPT 3 号更与我们结盟。它将实现 InstructGPT 的学习,instruct GPT 是通过人类反馈训练的。尽管如此,人工智能调整是一个漫长的过程,应该仔细评估这些努力,不应该大肆宣传。

订阅 算法桥 。弥合算法和人之间的鸿沟。关于与你生活相关的人工智能的时事通讯。

您也可以直接支持我在 Medium 上的工作,并通过使用我的推荐链接 这里 成为会员来获得无限制的访问权限! 😃

GPU 加速来到 M1 MAC 电脑上的 PyTorch

原文:https://towardsdatascience.com/gpu-acceleration-comes-to-pytorch-on-m1-macs-195c399efcc1

新的 M1 芯片在新的 PyTorch 更新中表现如何?

照片由内容小精灵Unsplash 上拍摄

2020 年 11 月 M1 苹果机的发布标志着苹果机器处理能力的显著提升[1]。不幸的是,这些新功能直到现在才被集成到 PyTorch 中。

今天的深度学习模型在很大程度上归功于不断增加的模型规模。那些更大的模型需要更多的计算来训练和运行。

本文的视频版本🙌🏼

这些模型太大了,无法在 CPU 硬件上运行,因为 CPU 硬件执行大量的分步计算。相反,他们需要大规模的并行计算,就像 GPU 所执行的那样。

GPU 使用高度并行的结构,最初设计用于处理视觉繁重过程的图像。它们成为游戏中渲染实时 3D 图像的重要组件。

这种渲染 3D 图像的能力可以很好地处理深度学习模型中所需的多维计算。自然地,GPU 成为模型训练和推理的架构。

GPU 对于当今模型的规模至关重要。使用 CPU 使得许多这些模型太慢而无用,这可能使 M1 机器上的深度学习相当令人失望。

TensorFlow 从一开始就支持 GPU 加速[2],但 TensorFlow 只是深度学习的两个主流库之一。PyTorch 失去了 M1 的支持。幸运的是,他们刚好赶上。

好吃吗?

PyTorch v1.12 引入了基于苹果芯片的 GPU 加速训练。这是 PyTorch 和苹果金属工程团队的合作成果。

它使用苹果的Met alPperformanceShaders(MPS)作为 PyTorch 操作的后端。MPS 针对每个 M1 芯片家族进行了微调。简而言之,这意味着整合速度很快。

使用新的 MPS 后端进行训练和推理/评估。来源

看一看基线(使用 M1 超芯片)显示,对于流行的 BERT 模型,训练加速约 7 倍,推理加速约 14 倍。

不幸的是,在使用我自己的第一代 M1 MacBook Pro 时,我没有看到同样的加速,特别是当使用如上所示的 64 批次时。

使用基本规格的 M1 MacBook Pro 在不同批量下的 BERT 推断时间。

也许这是由于低效的代码或我相对弱小的基本规格 MacBook Pro,但我会采取 200%的加速任何一天。现在,让我们来看看如何使用这个新的支持 MPS 的 PyTorch,而不是看图表和数字。

M1 上的 GPU 加速 PyTorch

操作系统和 Python 先决条件

甚至在开始之前,有一些事情可能会让你犯错。首先是先决条件。支持 MPS 的 PyTorch 需要 MacOS 12.3+ 一个 ARM Python 安装。我们可以通过以下方式检查这两种情况:

import platformplatform.platform()[GOOD] >> macOS-**12.4**-**arm64**-arm-64bit
[BAD]  >> macOS-**11.8**-**x86**_64-i386-64bit

这向我们展示了两件事,[ 12.4 | 11.8 ]指的是 MacOS 版本,这肯定是12.3或更高版本。如果不是,更新你的 MacOS!另一个是[ arm64 | x86 ]。我们想要arm64,如果你看到x86,那么我们需要为 Python 创建一个新的 ARM 环境。

如果使用 Anaconda,我们切换到终端窗口,创建一个新的 ARM 环境,如下所示:

CONDA_SUBDIR=osx-arm64 conda create -n ml python=3.9 -c conda-forge

这里我们设置 conda 版本变量来使用 ARM 环境。然后我们create一个新的conda环境,命名为(-n ) ml。接下来,我们将环境设置为使用 Python 3.9,并确保conda-forge包存储库包含在我们的通道中(-c)。

(如果使用的是 Python的另一个版本 ,检查是从哪里安装的 ARM 版本)。

初始化我们的环境后,我们用conda activate ml激活它,并修改CONDA_SUBDIR变量以永久使用osx-arm64。否则,对于将来的 pip 安装,我们可能会默认回到不正确的 x84 环境。

conda env config vars set CONDA_SUBDIR=osx-arm64

您可能会看到一条消息,要求您重新激活环境以使这些更改生效。如果是,使用以下命令切换出并回到ml环境:

conda activate
conda activate ml

PyTorch 装置

要开始,我们需要安装 PyTorch v1.12 版。目前,它只在夜间发布。

pip3 install -U --pre torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/cpu

在下载过程中,您应该能够看到类似于下载 torch-1.1x.x. — arm64.whl 的内容。最后的 arm64.whl 部分很重要,它告诉我们正在下载正确的版本。

我们将使用transformersdatasets库,它们是用pip install transformers datasets安装的。

旁注: 变形金刚库使用 Rust 内置的记号化器(它让它们更快)。因为我们正在使用这个新的 ARM64 环境,我们可能会得到 错误:为记号赋予器 构建轮子失败。如果是这样,我们安装https://huggingface.co/docs/tokenizers/python/v0.9.4/installation/main.html#installation-from-sources(在相同的环境下)与:

*curl — proto ‘=https’ — tlsv1.2 -sSf [https://sh.rustup.rs](https://sh.rustup.rs) | sh*

然后 *pip 再次安装变压器数据集*

在 Python 中,我们可以使用torch.has_mps来确认 MPS 正在工作。

测试 MPS

数据准备

为了测试新的支持 MPS 的 PyTorch,我们需要一些数据。我们将提取 TREC 数据集的前 1000 行。

我们将使用 BERT 模型测试 MPS 的性能,为此我们必须使用 BERT 记号化器来记号化我们的数据。对于前几个测试,我们将只使用 TREC 数据集的 64 行。

推理测验

在 CPU 上处理这些令牌时,我们得到的平均处理时间为 547 毫秒。我们可以通过将tokens张量和model移动到 MPS 设备来切换到 MPS。

使用相同的方法,在不同的批量下,我们可以看到 MPS 设备肯定优于 CPU,但是对于较小的批量,这不是很明显。

使用基本规格的 M1 MacBook Pro 在不同批量下的 BERT 推断时间。

培训测试

在 Mac 上训练大型模型并不是真正的预期用例,特别是对于低端 M1 芯片(如这些测试正在运行的第一代 M1 MacBook Pro)。不过,可能。

为了在 TREC 数据集上微调 BERT,我们将使用文本特征作为输入,使用标签-粗略特征作为目标标签。我们的标签特性包含六个唯一类,因此我们必须用六个输出类初始化 BERT。

请注意,我们将 BERT model移动到了 MPS 设备。在训练循环中遵循类似的步骤,其中每个张量被移动到 MPS 设备。

对于 1000 行 TREC 数据的训练,CPU 需要大约 25 分钟,MPS 需要大约 18 分钟。但是,这不是直接的比较。当微调完整的 BERT 模型时,MPS 设备(GPU)可以处理不超过一个一个的批处理大小,而对于 CPU,我们使用一个32的批处理大小。

这些测试正在优化整个 BERT 模型,这个模型非常庞大。对于大型语言模型(LLM)的微调,我们通常不需要微调整个模型。相反,我们可以冻结已经预先训练好的模型核心,并微调组成特定任务头部的最后几层。

变压器通常由一个经过预训练的大型核心和一个头部组成,后者针对分类等特定任务进行了微调。

使用这种方法,我们获得了更好的训练时间,大约为四分钟,最大 MPS 批量大约为 64。

这就是对新的支持 MPS 的 PyTorch 的介绍,以及如何在执行推理时使用它,甚至是用像 BERT 这样的流行模型进行训练。

如果你想了解我正在做的事情,我每周都会在 YouTube 上发帖子,你可以通过 Discord 直接联系我。我希望能见到你!

资源

[1] 纽约时报 MacBook 评论 (2021)

[2] P. Kanwar,F. Alcober,在 Mac 上加速 TensorFlow 性能 (2020),TensorFlow 博客

[3] 文章笔记本

除非另有说明,所有图片均出自作者之手

抓住并使用这四个有用的 Seaborn 可视化模板

原文:https://towardsdatascience.com/grab-and-use-4-useful-seaborn-visualization-templates-6e5f11a210c9

介绍了基于 Seaborn 的探索性数据分析的四种绘图功能及相关技巧

目录

  1. 简介
  2. 即 1:带辅助线/带的双轴时间序列图
  3. 即 2:拟合趋势线的散点图
  4. 即 3:具有 KDE 线的分布图(核密度估计)
  5. 即 4:分类柱状图系列
  6. 总结

介绍

主动权

“Matplotlib 和 seaborn 很丑,我只用 R 里的 ggplot2
“seaborn API 是一种痛苦,使用起来非常僵硬”;
“seaborn 和 matplotlib 的默认图很差,我每次都必须搜索正确的参数”;
“还有哪些与 Jupyter Notebook 配合良好的绘图库?”

这些是我从我的计算社会科学家伙伴和数据科学家朋友那里听到的评论,我相信每个数据人都或多或少与他们有关联。诚然,matplotlib 和 seaborn 并不完美,但它们有一个无与伦比的优势:matplotlib 和 seaborn 比大多数复杂的可视化工具包(如 Plotly/Dash)都易于使用,并且它基于 Python,这意味着它们对于探索性数据分析(EDA)是不可替代的,我们应该接受它们。

为了让 EDA 的生活更容易,我想分享一些 seaborn 可视化模板和我个人使用的相关技巧,以便您可以在分析上花更多的时间。本文将强调解决两个痛点:(1)美观;(2)功能性。

这些功能对你有什么帮助?

非常欢迎您通过简单地更改数据集的输入来获取和使用可视化模板。您还可以修改函数体来满足自己的需要。为此,我总结了一些我个人在工作中经常使用的关键技巧(即 seaborn 参数/方法)。

数据集

我使用来自 seaborn 的 taxistips 数据集以及来自美国国家海洋和大气管理局(NOAA)的公开气象数据作为以下模板的示例。请随意使用嵌入的代码块复制可视化。

taxitips 数据集通过 Seaborn 获得开源许可。它们可以通过seaborn.load_dataset方法在 Python 中自由访问,并根据它们的许可许可被允许用于商业用途。NOAA 天气数据的使用遵循[世界气象组织第 40 号决议文件](https://www.weather.gov/tg/addprod1#:~:text=In Annex 1 to Resolution,country (or group of countries)。更多的细节可以在文章的底部以及参考文献中找到。

即 1:带辅助线/带的双轴时间序列图

双轴时间序列图可以非常直观地了解我们感兴趣的关键变量的趋势如何与其他外部因素相关联。它常用于时间序列分析。

作者图:该图描述了纽约市出租车乘坐次数的时间序列波动。它还指定了雨天作为参考,以帮助解释趋势。(数据来源:Seaborn Taxis 数据集,美国国家海洋和大气管理局 )

作者代码

双轴时间序列图的关键注释

  • 我建议总是添加sns.set(style=”...”,context=”...”)来拥有一个漂亮的布局和 Arial 字体。请注意,在 Google Colab 中没有像这样的“捷径”,因为 Arial 字体类型没有正确安装在他们的虚拟机中。在 Colab 中更改字体类型的唯一方法是显式安装,然后将它们添加到 matplotlib 本地文件夹中,这可能会很麻烦。见此处
  • ax_y = ax.twinx()是创造双轴剧情的关键棋子。
  • ax.axvspan/ax.axhspan/ax.axvline/ax.axhline是辅助线和阴影带的方法。
  • 我更喜欢用网格线作为锚ax.grid(linestyle=” — “, alpha=0.5),我会通过设置一个小阿尔法来确保网格不会分散注意力。
  • 我个人发现下面的两个代码行(一个用于减少 x 刻度密度,一个用于旋转文本)在使用日期变量作为 x 轴时非常有用,这样我就可以防止所有日期文本相互重叠时出现混乱的前景
    ax_y.xaxis.set_major_locator(ticker.MultipleLocator(...)) plt.setp(ax_y.get_xticklabels(), rotation=45, ha=”right”, rotation_mode=”anchor”)

Viz 2:拟合趋势线的散点图

散点图是捕捉两个连续变量之间关系的一种有效的可视化分类。散点图的好处是它提供了一种原始的相关性,因为它直接将每个单独的数据点投影到画布上。相应地,不明朗的趋势也变成了不利因素。因此,手动拟合直线并添加到散点图中通常被认为是一种良好的做法。

按作者分类的图:该图通过总账单金额($)和小费百分比将 244 个交易数据点投影到一个二维空间。还显示了拟合的多项式趋势线。(数据来源:Seaborn Tips 数据集)

作者代码

拟合趋势线散点图的关键注释

  • sympy包装上的乳胶文字样式可以使配方更具美感。
  • 来自scipycurve_fit通常用于确定拟合线的参数,但是尝试不同的模型(例如多项式、对数、指数)不会出错。

即 3:具有 KDE 线的分布图(核密度估计)

分布是我们在进行单变量数据分析时想要探索的最关键的统计方面之一。虽然 seaborn 提供了多种方法,如displotkdeplotdistplot来使用 KDE(核密度估计)直接测量分布,但在本文中,我想强调一些特定的参数,并提醒您注意。

作者提供的数字:该图描述了小费百分比的分布情况。它表明,在大多数情况下,人们会给这顿饭总账单的 16%作为小费。(数据来源:Seaborn Tips 数据集)

作者代码

KDE 线分布图的关键注释(核密度估计)

  • 平滑的 KDE 线可能是一个很好的参考,但是当参数在具有极值的多模态偏斜 分布中被错误指定时,它可能会误导。因此,最好同时检查直方图,并相应调整cutclipbw_adjust
  • cutclipbw_adjust是 KDE 线的三个非常重要的参数。我通常设置cut=0clip等于数据的最小值和最大值,以在极限处截断 KDE 曲线,并迫使它不超出实际样本。值得注意的是,默认情况下,cut参数不是 0,因此 KDE 曲线有时可能与样本分布不同。
  • bw_adjust简而言之,控制着 KDE 曲线的‘平滑度’,因此应该仔细调整以反映真实的分布。我强烈建议阅读 kdeplot 官方文件中的注释。

即 4:分类柱状图系列

我个人认为最后一个有用且方便的可视化是这一系列的柱状图,因为我们不仅关心指标的分解,还关心每个维度值的样本构成。否则,我们可能会陷入辛普森悖论,得出错误的结论。为了包含分类变量,我使用来自 seaborn 的流行的 Tips 数据集进行说明。

按作者分类的图表:这张图表显示了按性别分类的小费金额占总账单金额的百分比。它还揭示了样本不平衡,女性观察较少。(数据来源:Seaborn Tips 数据集)

作者代码

摘要

本文提出了四种不同类型的可视化模板,分别对应于四种不同的用例:(1)分析时间序列趋势;(2)分析两个连续变量之间的关系;(3)分析分布情况;(4)分析不同维度分解下的度量性能。

对于每种类型的可视化,我都提供了代码和数据来复制可视化,并添加了主题演讲来突出关键的 seaborn 方法。目的是促进 Python 中更实用、更美观的绘图。

希望以上内容对你的数据之旅有一点帮助!

Seaborn 许可证

本文依赖于 Seaborn 包中包含的数据集。Seaborn 许可证如下所示:

版权所有 2012–2021,迈克尔·l·瓦斯科姆
保留所有权利。

只要满足以下条件,允许以源代码和二进制形式(修改或不修改)重新分发和使用:

  • 源代码的再分发必须保留上述版权声明、此条件列表和以下免责声明。
  • 二进制形式的再分发必须在随分发提供的文档和/或其他材料中复制上述版权声明、此条件列表和以下免责声明。
  • 未经事先明确的书面许可,不得使用项目的名称或其贡献者的名称来认可或推广由此软件衍生的产品。

本软件由版权所有者和贡献者“按原样”提供,拒绝任何明示或暗示的担保,包括但不限于适销性和特定用途适用性的暗示担保。在任何情况下,版权所有者或贡献者都不对任何直接、间接、附带、特殊、惩戒性或后果性损害(包括但不限于替代商品或服务的采购;用途、数据或利润的损失;或业务中断)以及任何责任理论,无论是合同责任、严格责任还是因使用本软件而产生的侵权行为(包括疏忽或其他),即使已被告知此类损害的可能性。

参考

时间序列预测的梯度增强 ARIMA

原文:https://towardsdatascience.com/gradient-boosted-arima-for-time-series-forecasting-e093f80772f6

提升 PmdArima 的 Auto-Arima 性能

图片由 SpaceXUnsplash 上拍摄

TLDR: 将梯度推进添加到 ARIMA 增加了拟合过程的复杂性,但是如果我们在每一轮推进中针对新的(p,d,q)参数进行优化,也可以提高精度。虽然,升压结合其他方法可以获得更大的增益。

所有代码都住在这里:百里香 Github

查看这篇文章,了解百里香的完整介绍。

介绍

梯度推进多年来一直是机器学习领域的一个热门话题,但在时间序列领域还没有获得太多的关注。理论工作已经完成,但没有多少像 ARIMA 等传统方法那样获得主流关注。这主要是因为 boosting 方法的大部分收益(通常)来自以某种方式对数据进行分区的方法,如决策树。我们当然可以尝试以某种方式划分我们的数据,但很多时候我们没有足够的数据来使用非常复杂的方法,这导致了较差的结果。另一方面,提升一些简单的东西,如线性回归,往往会正则化系数,但通常会采用更直接的正则化方法。

说了这么多,还是来助推一些时间序列的方法吧!

具体来说,我们将着眼于提高 ARIMA,并将其与 PmdArima 进行比较。为了增强效果,我们将使用一个我正在开发的包:百里香增强。这个包使用一个通用的 boosting 框架来进行时间序列分解和预测,同时包含了梯度 boosting 中一些通常不会应用的更有用的想法(据我所见)。但就我们的目的而言,我们将只做简单的助推。

我们的实验将使用一个非常常见的时间序列数据集来:

  1. 从 PmdArima 拟合自动 arima
  2. 使用找到的参数来增强简单的 ARIMA
  3. 使用 PmdArima 增强以在每轮搜索新参数
  4. 对比结果!

航空乘客数据集

我们将尝试的第一个数据集是航空乘客数据集,可以从 Kaggle 中找到,并带有开放数据库许可证。让我们看看并导入所有必需的包:

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
sns.set_style("darkgrid")#Airlines Data, if your csv is in a different filepath adjust this
df = pd.read_csv('AirPassengers.csv')
df.index = pd.to_datetime(df['Month'])
y = df['#Passengers']
plt.plot(y)
plt.show()

作者图片

为了判断预测方法,我们将把数据分割成标准的训练/测试分割,其中保留最后 30%的数据。

test_len = int(len(y) * 0.3)
al_train, al_test = y.iloc[:-test_len], y.iloc[-test_len:]

现在快速提醒一下,百里香增强对趋势和季节性做了一些非常具体的假设,所以我们不能在使用季节性(这个时间序列显然有)时直接将其与 auto-arima 进行比较。但是,我们还是会尝试,只是没有季节性。

首先我们使用 PmdArima:

import pmdarima as pm
# Fit a simple auto_arima model
arima = pm.auto_arima(al_train,
                      seasonal=False,
                      trace=True,
                      )
pmd_predictions = arima.predict(n_periods=len(al_test))
arima_mae = np.mean(np.abs(al_test - pmd_predictions))
arima_rmse = (np.mean((al_test - pmd_predictions)**2))**.5
arima_mape = np.sum(np.abs(pmd_predictions - al_test)) / (np.sum((np.abs(al_test))))

结果是:

作者图片

现在,我们将获取“最佳”参数,并将其传递给百里香增强,以用于每一轮增强。使用的顺序就是 PmdArima 字典中的顺序,当使用截距时,趋势参数(如果我理解文档的话)将是“c”。这些参数将被传递给百里香增强:

#get the order
auto_order = arima.get_params()['order']
from ThymeBoost import ThymeBoost as tb
boosted_model = tb.ThymeBoost(verbose=1)output = boosted_model.fit(al_train,
                            trend_estimator='arima',
                            arima_order=auto_order,
                            global_cost='mse')
predicted_output = boosted_model.predict(output, len(al_test))
tb_mae = np.mean(np.abs(al_test - predicted_output['predictions']))
tb_rmse = (np.mean((al_test - predicted_output['predictions'])**2))**.5
tb_mape = np.sum(np.abs(predicted_output['predictions'] - al_test)) / (np.sum((np.abs(al_test))))

结果是…非常糟糕:

作者图片

当看这些预测时,很容易明白为什么:

boosted_model.plot_results(output, predicted_output)

看起来,当增强(拟合简单的平均值/中值)使得先前发现的参数无用时,出现初始化回合。事实上,如果您查看日志,甚至不会发生任何提升!百里香中的助推程序完全改变了游戏,负面的。

但是,如果尝试使用 PmdArima 搜索新参数呢?

让我们试一试。

为此,我们只需为 arima_order 参数传递“auto”。让我们看看它是如何做到的:

from ThymeBoost import ThymeBoost as tb
boosted_model = tb.ThymeBoost(verbose=1)output = boosted_model.fit(al_train,
                            trend_estimator='arima',
                            arima_order='auto',
                            global_cost='mse')
predicted_output = boosted_model.predict(output, len(al_test))
tb_mae = np.mean(np.abs(al_test - predicted_output['predictions']))
tb_rmse = (np.mean((al_test - predicted_output['predictions'])**2))**.5
tb_mape = np.sum(np.abs(predicted_output['predictions'] - al_test)) / (np.sum((np.abs(al_test))))

结果是:

作者图片

略有改善!查看日志,我们看到总共有 4 轮:1 轮初始化和 3 轮提升。

但是,我们在这里不是为了边际改进。除了自动 Arima 之外,让我们用一个简单的线性趋势来看看效果如何。这可以通过简单地将它们作为列表传递来实现:

from ThymeBoost import ThymeBoost as tb
boosted_model = tb.ThymeBoost(verbose=1)output = boosted_model.fit(al_train,
                            trend_estimator=['linear', 'arima'],
                            arima_order='auto',
                            global_cost='mse')
predicted_output = boosted_model.predict(output, len(al_test))
tb_mae = np.mean(np.abs(al_test - predicted_output['predictions']))
tb_rmse = (np.mean((al_test - predicted_output['predictions'])**2))**.5
tb_mape = np.sum(np.abs(predicted_output['predictions'] - al_test)) / (np.sum((np.abs(al_test))))

结果是:

作者图片

与所有其他方法相比,这是一个显著的改进!

结论

在本文中,我们探索了一种利用 ARIMA 的增强方法。我们看到,采用静态的“最佳”参数配置会导致升压过程中的可怕结果。另一方面,如果我们为每一轮提升动态地找到新的参数设置,我们可以在精度上获得边际收益。

但是,也许只是提高 ARIMA 并不总是最好的事情。相反,也许用其他模型增强 ARIMAs 可能会让我们有更好的表现。

如果你喜欢这种用时间序列方法提升的方式,我强烈推荐你看看我的另一篇文章:用百里香提升的 M4 竞赛。本文是一系列文章中的第一篇,我们将应用许多不可靠的不同的百里香增强设置,努力学习所有这些方法如何在框架中工作,并最终(剧透警告)赢得 M4 竞赛。

Python 中的渐变提升从零开始

原文:https://towardsdatascience.com/gradient-boosting-in-python-from-scratch-788d1cf1ca7

使用 Python 编码并深入解释非常流行且在竞赛中获奖的梯度推进算法

喙的进化;图像许可https://creativecommons.org/licenses/by/4.0/deed.en;原文链接https://commons . wikimedia . org/wiki/File:Charles _ Darwin,_ Journal _ of _ Researches..._Wellcome_L0026712.jpg

这篇文章的目的是使用 Python 代码和可视化来解释流行且时常神秘的 梯度增强算法 。梯度提升是 CAT boost、ADA boost 或 XGBOOST 等竞赛获奖算法的关键部分,因此了解什么是提升、什么是梯度以及这两者在创建算法中的联系是任何现代机器学习从业者的必备知识。

Python 中回归的梯度推进的实现和动画可以在我的报告中访问:https://github.com/Eligijus112/gradient-boosting

文章的主要图片描述了进化的过程,以及在很长一段时间内,一个鸟类物种的喙大小是如何适应周围环境的。https://en.wikipedia.org/wiki/Darwin%27s_finches

正如动物在其栖息地以各种方式适应新的事实一样,机器学习算法也适应我们将它们置于其中的数据环境。梯度推进算法背后的主要思想是,其主要引擎是从其自身先前的错误中学习的低精度和简单的算法。

在每次迭代中,不仅错误被用于调整模型,前一次迭代的模型也被调用。因此,随着数据的每次传递,梯度推进模型变得越来越复杂,因为它将越来越多的简单模型加在一起。

简而言之,许多梯度增强算法的简化方程是一种递归:

直觉方程式

当前值 m (把它想象成现在)使用过去的信息( m -1 ),并通过新的具有一定权重的当前证据( G )进行调整。

在下面的文章中,我们将更深入地探讨梯度增强的本质细节,我希望在阅读完所有代码和解释后,读者会发现梯度增强虽然听起来吓人,但并不复杂。

假设我们想要一个模型,根据汽车的重量来预测汽车可以行驶多少英里。可以从这里访问数据:

https://archive.ics.uci.edu/ml/datasets/auto+mpg

具有所有特征的数据:

汽车数据;按作者分类的表格

问题中的关系:

mpg ~体重;按作者分类的图表

有一个明显的关系——车越重,每加仑能跑的里程越少。让我们试着让一个基础学习者适应这些数据,看看它的表现如何。

让我们开始构建一个梯度推进的机器学习算法来模拟这种关系。

回归梯度推进算法的标题中有三个非常宽泛的机器学习术语:

  • 回归
  • 渐变
  • 增压

在试图将它们合并在一起之前,至少对独立的定义有一个直观的理解是很重要的。

机器学习中的回归 就是寻找一个连续变量的 Y 平均值和特征 X 之间的关系 f

简而言之就是回归

在回归中,我们试图预测的变量是连续的,也就是说,它可以有无穷多个值。比如人的体重,一个人在奥运会上完成一场比赛的速度,一个人的工资等等。

我们试图用特性 X 来解释 Y 变量的方式。例如,我们可以说一个人的工资( Y 变量)是由他或她的工作经验、学术成就、证书数量等( X 变量)决定的。

数学中函数的梯度是一个向量,它的每个坐标都是给定函数自变量的偏导数。

梯度定义

梯度在寻找使函数最小化或最大化的函数自变量的流行算法中被广泛使用。这是因为,在任何给定点 x 处,如果函数的梯度为负,那么原始函数在该点 x 处递减。如果在点 x 处梯度为正,则函数增加。这就是为什么机器学习中的许多损失函数试图尽可能简单(参数越少越好)并且可微分(能够找到梯度)。

机器学习中的术语 boosting 是指将一组 弱学习者 训练到训练数据中的过程,其中每个弱学习者从先前学习者的错误中迭代学习。

弱学习器是一种机器学习算法,它可以快速拟合数据,但在准确性、均方误差或其他指标方面的性能相对较差。

增强模式;按作者分类的图表

在上面的模式中,每个 ML 模型都是弱学习者。每个误差都是用过去的预测计算出来的。每个后续模型都试图用原始特性来拟合之前的错误(这里就大胆一点,跟着文章走,我稍后会详细解释这个过程)。****

最终预测是从得到的 ML 模型的所有输出的加权和:

最终增强预测;按作者分类的图表

回归梯度推进是一种将上述所有思想结合到一种机器学习方法中的算法。

在深入研究所有这三个想法是如何相互联系的之前,我们需要选择一个基础较弱的学习者来完成提升部分。一个非常流行的选择是回归决策树。要了解关于回归决策树的更多信息,请查看我的文章:

快速回顾一下:

回归树模式;按作者分类的图表

树中的每个节点都保存有 Y 和 X 特征。此外,每个节点都具有:

  • 从每个 Y 值中减去 Y 平均值的特殊残差。
  • 残差的均方误差。
  • 用于进一步创建节点的最佳分割特征和最佳分割值。
  • 所有的初始超参数。

回归树的 Python 实现:

回归树;作者代码

要使一个弱学习者适应数据,运行下面的代码:

# Initiating the tree
reg = Tree(d, 'mpg', ['weight'], max_depth=2)# Fitting on data
reg.fit()# Initiating the tree

# Printing out the tree
reg.print_tree()

结果是:

树信息;作者图片

弱学习者建议首先在 2764.5 权重点分割数据,因为在该点,与根节点中的原始均方误差相比,一般均方误差将减少最多。

回归树预测;按作者分类的图表

正如我们从上面的预测中可以看到的,回归树将数据分为 4 部分:直到 2217 重量的所有数据,然后从 2217 到 2764.5,然后从 2764.5 到 3657.5,以及从 3657.5 开始的所有数据。预测值是属于该权重类别的 Y 变量的平均值。比较

此外,图表显示最大深度为 2 的回归树是弱学习者。让我们弄清楚如何把它们结合起来创造一个强大的学习者。

来自维基,全梯度提升算法:

https://en.wikipedia.org/wiki/Gradient_boosting

乍一看,上面的算法很吓人。但是让我们一行一行地检查它,并通过编码找到一个完整的解决方案。

在编码解决方案中,让我们坚持以前的例子,并尝试使用汽车的重量作为解释来创建 mpg 的预测值。

因此,我们的数据

正在实践中

下一个非常重要的部分是选择损失函数。梯度增强树的一个非常流行的损失函数是:

它之所以受欢迎是因为对其求导会产生:

当简化算法中的各种公式时,这将非常方便。

使用我们选择的损失函数初始化算法(步骤 1 ):

现在,为了找到使该函数最小化的自变量,我们用 gamma 进行微分,并使其等于 0:

上式的右边只是初始 y 的平均值。因此,我们总是以 y 的平均值作为初始预测来开始算法。

在我们的实际例子中,mpg 因变量的平均值为 23.51。

算法的第二部分 提升部分,在这里我们使用来自前一次迭代的信息来调整每次迭代。

该算法第二步的第一部分涉及所谓的伪残差的计算。这个术语很容易混淆,听起来可能比实际情况更复杂。我喜欢称它们为残差,在本文中,我会交替使用这些术语。让我们回顾前几节,看看我们选择的损失函数是:

m = 1 时,算法定义的公式如下:

第一次迭代的残差将通过从 y 的所有单个值中减去 y 的平均值来计算。

第一批残差(R1);平均每加仑=23.51

从上一部分,术语梯度出现了,因为我们在进一步的步骤中使用损失函数的梯度。

算法第二步的第二部分是用相同的特征 X 拟合回归树,但是现在 Y 值是从第一部分得到的残差。换句话说,使用回归树找到关系:

第二步的第三部分涉及一个相当长的公式。让我们扩展一下:

优化伽马射线产量:

因此使用以下公式找到迭代 m 的最佳伽马值:

上面的等式是原始算法的一般解。在他的原始论文中,https://jerryfriedman.su.domains/ftp/trebst.pdf杰罗姆·h·弗里德曼提出,当使用决策树作为弱学习器时,我们不仅应该为每一层 m 使用一个伽马值,还应该为每一片叶子 j 使用一个伽马值。

假设区域(回归树中的叶子)R 有 k 个条目。然后我们可以解析地解决优化问题:

上面的等式最终确定了一个非常方便的特性,即每次迭代 m 和叶 j 处的最佳伽马值是落入该叶的残差的平均值。

该算法的第二步的第四部分就是在步骤 m 中对预测的定义:

右边的新术语 alpha 是在迭代之前定义的超参数。它被称为学习率,控制着每一步预测更新的程度。

弗里德曼提出的扩展是使用下面的等式:

在 Python 实现中,我将使用 Friedman 的方法。

我们可以进一步简化弗里德曼的方程。

弱学习者图;按作者分类的图表

给定一些特征集合,每个弱学习器预测前一次迭代的误差。在我们的示例中,X 特征是汽车重量。在每个叶节点,预测值是落在该叶中的平均残值。

因此,我们可以简单地将等式改写为:

梯度推进最终公式

算法的最后第三步就是最终预测的定义。如果我们训练 3 次迭代,那么预测是:

我们可以从等式的右侧看到,我们每次迭代的基本操作是更新 y 的平均值。从某种意义上说,我们以这样一种方式组合弱预测值,即我们从每个数据点的平均值获得最精确的偏差。这一点以及预测值持续的事实让我们称上面的算法为回归问题。

回归梯度提升在 Python 中的实现:

梯度推进;作者代码

生成梯度增强训练可视化的代码可在此处找到:

https://github.com/Eligijus112/gradient-boosting/blob/master/regression/boosting.py

学习率= 0.1,最大深度= 2;作者 GIF

正如我们所见,在没有任何训练的情况下,算法在开始时预测了 mpg 变量的平均值,而不管汽车的重量值。

在一次迭代(橙色点)之后,就预测而言,该算法只是勉强向正确的方向移动。

经过 30 次迭代后,该算法非常好地模拟了潜在的关系。

学习率= 0.3,最大深度= 2;作者 GIF

上图显示,将学习率从 0.1 增加到 0.3 会减少精确逼近该关系所需的迭代次数。但是,进一步增加该值会导致过度拟合。

具有两个输入特征重量和加速度的可视化:

作者 GIF

在本文中,我将回归、提升和梯度部分结合起来,创建了一个回归梯度提升算法。

我提供的所有代码都是开源的,是我写的,所以你想用多少就用多少。

快乐学习编码!

[1]作者: Dua,Dheeru 和 Graff,Casey
年份: 2017
标题: {UCI}机器学习资源库
网址:http://archive.ics.uci.edu/ml
院校:
加州大学欧文分校信息与计算机科学学院****

梯度下降的简单指南

原文:https://towardsdatascience.com/gradient-descent-f7458de38365

用 Python 演示了多元线性回归示例中的算法

当研究一本机器学习书籍时,很有可能在第一页就遇到臭名昭著的梯度下降。虽然这种算法背后的想法需要一点数学直觉,但梯度下降的应用程序的有用性和通用性令人难以置信。这篇文章为你提供了所有你需要了解的实用知识。

无论你是否深入研究深度学习(反向传播)或者只是对如何导出线性回归(普通最小二乘法)中的系数感兴趣,梯度下降(GD)都是这些方法学不可或缺的一部分,不应该对用户保持黑盒模型。本解释旨在将几个简单的数学表达式与相关代码联系起来。

本文介绍了一个简单的四步算法来实现梯度下降。你需要的一切!

渐变的日落——作者图片

为什么探索梯度下降?

当我们将算法直接放在线性回归的上下文中时,GD 可能是最容易理解的——因此我将使用回归作为主要参考。

目标是找到最小化直线/超平面到所有数据点的距离的系数。这可以通过矩阵运算(和求逆)来实现,但是计算量非常大。由于这个原因使用 GD 是一个很好的方法来获得解决方案。网上有各种指南展示如何一步一步地应用梯度下降(即更新一个系数&迭代,更新下一个系数&迭代,..),然而,这使得很难掌握通过矩阵运算一次更新几个权重/系数的过程。这是至关重要的,因为更新权重/系数矩阵是深度学习文献中经常使用和讨论的主题。

为了使 GD 的整体计算概念更加具体,我将详细说明 GD 如何实际应用于导出矩阵符号中的线性回归系数

我将举例说明几个简单的数学表达式,如果你觉得不太舒服,就继续进行,我相信代码部分最终会清除烟雾。下面的等式解释了“为什么”,而代码部分是“如何”的问题。

什么是梯度下降?

你可能还记得在学校的时候,找到一个函数的最小值/最大值直接导致了导出函数的任务。如果我们使用这个导数,一点一点地降低函数值,我们最终会收敛到最小值。关于 GD,我们试图最小化一个损失函数,这完全符合我们的学校数学工具包。

换句话说,GD 是一个一阶优化算法,它允许我们找到一个函数的最小值(希望是全局的)。下面的视频展示了我们如何从一个随机点(红色区域)开始,迭代下降到这个函数的最小值(蓝色区域)。

Gif 由angryinconsequentialdiplodocus

起初看起来有点挑战性的是,几个系数需要几个偏导数。然后,每个导出值被存储在一个向量中,即梯度。在论文中,你可能会遇到“nabla”的符号,这是一个倒置的三角形:

最小化损失函数[1]

但在我们实际做 GD(这有助于我们最小化损失函数,通常表示为" J 或" L ")之前,让我们首先确定我们在看什么损失函数。

基本思想——线性回归

首先,理解我们想要解决的的潜在问题是很重要的——在这种情况下,这是一个回归问题,我们需要最小化普通最小二乘方程。真实值 y估计值(" y hat")** 表示如下:**

给定一个线性模型对 Y 的估计[2]

为了使用 GD,一个函数必须在所有点上都是可微的,并且是 凸的 —这对于普通的最小二乘(OLS)问题是已知的,其中我们计算估计值和真实的 y之间的偏差平方和——这是我们的损失函数:

最小化 RSS —剩余平方和(凸函数)[3]

如果残差平方和最小化,我们将获得一条直线,其特征是到所有数据点的距离最短,如下图所示:

真实易值(蓝点)与回归线(y _ hats)-作者图片

RSS 简单地表示真实 y 值和 X 值之间的平方差之和乘以它们的系数(β)。误差项被视为随机噪声(高斯分布[0,1]),因此,如果数据点不完全位于直线或超平面上,该等式将产生非零值——这是一般情况。

贝塔系数的估计值[4]

为了估计β,我们需要对 X 矩阵(值 xij) 求逆,这将直接引导我们估计系数(“hat”)。搞定了,那么又何必纠结于梯度下降呢?

开始梯度下降旅程

对一个矩阵求逆可能是计算上的挑战(即昂贵),这是 GD 算法真正闪光的地方。作为矩阵求逆的替代,我们可以简单地取偏导数,使用这些值和学习率(α)来更新当前权重(β)。然后,我们重复这个步骤,以便迭代地逼近函数的最小值(再次查看上面的 GIF)

最小化损失函数

我们使用梯度来调整我们的初始权重/系数,这最终使我们达到函数的最小值(假设函数是)。定义我们多快接近这个最小值的“速度”参数被称为学习率

我在这里不展开关于学习率的想法,但如果你打算这么做,也可以考虑考察一下“”在这种背景下,作为动量对于克服局部极小值是非常有用的。**

最小化损失函数—作者图片

如前所述,我们可以使用 GD 来代替昂贵的矩阵求逆。首先,我们需要我们的函数关于 beta 的偏导数(在我们简单的回归例子中, b0b1 )。

让我们推导损失函数。偏导数的矢量由下列截距和斜率系数的单独计算组成(分别为 b0 和 b1 )。我们最小化所有贝塔系数(在多元线性回归的情况下,可能有 p 系数):

最小化所有 betas 上的 L[5]

将这两个贝塔系数分解开来,我们就有了两个等式,稍后可以轻松实现:

注意区别:(1)!= (x) [6][7]

考虑到定义的 学习率,我们进一步使用导出值通过减去导出值来减少初始权重/系数。******

使用导数的广义视图迭代更新贝塔系数[8]

上面概括的符号表明我们**需要使用 1 的堆栈向量作为X的第一列。这是必要的,以确保在将 X 矩阵乘以系数矩阵时添加截距( b0 是截距)。可以跳转到下面的第 15 行和第 16 行代码来观察堆叠。****

我发现下面的链接很好地解释了如何通过迭代更新两个值 b0b1 来计算和更新权重(回归意义上的系数)——一次一个。同样,为了理解我们如何以及何时更新权重,链接给出了一个很好的解释。

为了更加通用,同时也允许同时处理多个权重,我将用矩阵表示法解决这个问题,并将结果与下面的 Scikit-Learn 的实现进行比较。

*https://machinelearningmastery.com/linear-regression-tutorial-using-gradient-descent-for-machine-learning/

从头开始实现梯度下降

以下步骤概述了如何继续这个 GD 回归示例:

1\. Setting up the data
2\. Defining the learning rate (alpha)
3\. Defining the initial values for b0 and b1 (initialization)
4\. Start iterating # for i in 1000
**4.1 Taking partial derivatives
4.1.1 Calculate the error for the intercept (b0)
4.1.2 Calculate the error for the coefficient(s) (b1)
4.2 Update the parameters**Done.

Xy 变量定义如下:

X = array([[1., 1.],
           [1., 2.],
           [1., 4.],
           [1., 3.],
           [1., 5.]])y = array([1, 3, 3, 2, 5])b = array([0., 0.]) # Initialized b => coefficients/weights

数据点可以显示为简单的散点图。回归的目标是在点之间画一条线,使到真实点的距离最小。

带有我们目标回归线的散点图—图片由作者提供

这正是我们所说的 OLS(普通最小二乘)问题。

显然,橙色线设法非常接近所有数据点。此外,这条线有一个截距。

为了再次具体说明偏导数,我举例说明了的两个代码行。相关的数学表达式分别是 6、7 或 8,可以在上述文本中找到:

# d/db0: (b0+b1.dot(x) — y ) * (1) 
# d/db1: (b0+b1.dot(x) — y ) * (x) 

GD 实施

下面的代码初始化变量并开始迭代。前两行计算我们存储为梯度的值。

这种迭代算法为我们提供了截距为 0.39996588 和系数为 0.80000945 的结果,将其与从 sklearn 实现中获得的 0.399999 进行比较,结果似乎非常匹配。

Scikit Learn 的实现

这段代码使用线性回归的 sklearn 实现来验证前面获得的结果:*

概述

**我总是通过在例子中直接应用学习概念来接受它们,这在机器学习领域尤其如此。对梯度下降的简要介绍旨在提供一个易于理解和实现的算法,让你找到凸函数的最小值。通过使用这种迭代算法来连续更新权重/系数,GD 允许我们克服诸如矩阵求逆(如线性回归示例中)之类的昂贵过程的计算工作。

GD 是几乎任何机器学习和深度学习程序的一个组成部分,这就是为什么它经常在相关大学课程中作为“先决条件”教授的原因。

如果你觉得这篇文章有帮助,我会很感激“关注”🫀,直到那时:

{照顾好自己,如果可以的话,也照顾好别人}

—借鉴史蒂芬·都伯纳

梯度下降 VS 正则化:使用哪一个?

原文:https://towardsdatascience.com/gradient-descent-or-regularization-which-one-to-use-f02adc5e642f

为了更好地理解,对梯度下降和正则化进行概述

巴勃罗·加西亚·萨尔达尼亚在 Unsplash 上拍摄的照片

W 当迈出机器学习的第一步时,有很多东西需要学习和理解。此外,一些 ML 模型可能看起来彼此非常相似;有时候,很难真正理解它们之间的区别。这是我第一次接触正则化和梯度下降时的情况:它们对我来说太相似了,以至于不能理解它们之间的区别。事实上,正则化和梯度下降都使用成本函数,但它们之间的差异是成本函数的类型和我们对这些方法的使用。

在这篇文章中,我将试图阐明它们的区别,目的是帮助你更好地理解这些方法。

1.正规化

在机器学习中,我们通常应用套索和脊正则化方法(也分别称为 L1 和 L2),但当“标准”模型过度拟合时,我们会使用它们。

例如,考虑一个简单的线性回归模型;如果在训练集上得到一个好的决定系数值(例如,接近 1 ),但在测试集上得到一个差的决定系数值(例如,接近 0 ),那么您将面临过度拟合,应用 Lasso 或 Ridge 回归模型甚至可以在测试集上得到好的结果。此外,如果你不知道是否使用套索或脊方法,你可以在这里阅读我的文章:

在机器学习的背景下,正则化是将系数缩小到零的过程,“阻止”学习复杂的问题;这个过程是通过所谓的成本函数来实现的。

套索和岭方法具有“预先固定的”成本函数;这意味着它们是“内置”成本函数的这意味着 Lasso 是用线性回归模型的方程加上等于系数大小绝对值的成本函数构建的。相反,岭是用线性回归模型的方程加上等于系数大小的平方值的成本函数构建的。

由于这些是监督学习技术(如果你想了解更多关于监督和非监督学习的知识,你可以在这里阅读我的文章),我们的目标是找到最佳超参数以避免过度拟合,这个超参数可以是 0(因此,我们“返回”到简单的线性回归模型)或无穷大(意味着模型已经被算法高度惩罚)。

2.梯度下降

梯度下降是一种学习算法,通过最小化给定的成本函数来工作;所以梯度下降和正则化之间的主要区别是:

  • 正则化方法有一个“预定义的”成本函数,不像梯度下降(它有一个“给定的”成本函数,但我们将在后面看到它是如何工作的)
  • 与梯度下降不同,当模型过拟合时,使用正则化

有一个重要的概念要记住:模型通过最小化成本函数来学习,这就是为什么梯度下降是有用的。

你可能知道,在数学中,当我们需要找到一个函数的最小值时,我们会用到导数。当我们有一个多变量的问题时,我们必须进行多重求导:简化很多,这就是梯度。

因此,梯度下降算法使用梯度(也称为多维导数)来寻找函数的最小值,并通过多次迭代来实现,直到找到函数的最小值。

比如,假设我们有一个函数 f(x),其中 x 是一个多元的元组:x = (x1,x2,…,xn)。假设 f(x)的梯度由∇f(x 给出)(倒三角形是标识梯度的符号)。在任何迭代 t,我们将用 x[t]表示元组 x 的值。对于每个迭代 t,梯度下降的训练工作如下:

x[t] = x[t-1] — 𝜂∇f(x[t-1])

其中𝜂被称为学习率(这是一个超参数)。在这个过程的最后,算法将找到使函数 f(x)最小的变量(x1,x2,…,xn)的值(更多细节参见这里)。

但是,最后,我们发现了什么?像在机器学习中一样,我们找到了最适合给定数据的函数,但我们发现它最小化了一个成本函数。

结论

本文的目的是阐明梯度下降和正则化之间的区别;概括地说,这些差异是:

  • 正则化方法有一个“预定义”的成本函数,不像梯度下降法,成本函数是给定函数的梯度。
  • 当模型过度拟合时,使用正则化,这与梯度下降不同,梯度下降不考虑过度拟合(我们可能会在验证后发现模型过度拟合,但我们不使用梯度下降来防止过度拟合)。

让我们连在一起!

中等

LINKEDIN (向我发送连接请求)

如果你愿意,你可以 订阅我的邮件列表 这样你就可以一直保持更新了!

考虑成为会员:你可以免费支持我和其他像我一样的作家。点击 这里的 成为会员。

基于机器学习的语法纠错——综述与实现

原文:https://towardsdatascience.com/grammatical-error-correction-with-machine-learning-overview-and-implementation-ccd0b50a1700

使用语法纠错:标记,而不是重写(GECTor)

“两个机器人在沙滩上纠正电子邮件中的错别字”,由 DALL 创作。E 2

1.介绍

自然语言处理(NLP)管道依赖于机器学习模型,这些模型出于各种目的消费、分析和/或转换文本数据。例如,Google Translate 接收一种语言的输入文本,并返回一种目标语言的输出文本(这个任务称为机器翻译)。情感分析算法接收文本数据并确定文本是正面的、负面的还是中性的。文本摘要模型,接收文本输入并将其总结成较小的文本输出。有许多因素可以影响这种模型的性能/输出质量,其中之一是传入文本的质量。具体来说,错误文本形式的噪声会对神经机器翻译模型的结果质量产生不利影响(别林科夫和比斯克,2018 )。因此,在这样的文本数据到达机器翻译、情感分析、文本摘要等的下游任务之前,已经有集中于改进跨 NLP 管道的输入文本数据的语法正确性的努力。

语法纠错模型通常使用两种方法:

  1. 序列到序列(seq2seq)文本生成,可以认为是一个翻译引擎,从一种给定的语言翻译到同一种语言,同时纠正语法错误(例如:)袁和 Briscoe,2014 )
  2. 序列标记,其中输入文本被标记化、标记,然后映射回正确的标记(例如 Malmi 等人,2019 )

虽然 seq2seq 神经机器翻译方法已被证明实现了最先进的性能(例如 Vaswani 等人,2017 ),但它仍然存在某些缺点,例如:(1)推理和生成输出需要很长时间,(2)训练需要大量数据,以及(3)与非神经架构相比,模型的神经架构使得结果的解释具有挑战性( Omelianchuk 等人,2020 )。为了克服这些缺点,我们将在本帖中讨论并实现的方法是一个使用 Transformer 编码器的序列标记器。 Omelianchuk 等人,2020 的工作是对合成数据进行预训练。然后分两个阶段对预训练的模型进行微调。一个阶段纯粹包括有错误的语料库,然后第二个微调阶段包括有错误和无错误数据的组合。最终的工作速度是 Transformer seq2seq 系统的十倍,并在 GitHub 上公开发布。这种方法改善了 seq2seq 模型的推理时间问题,并且可以在给定较小训练数据的情况下实现更高水平的定制,因为它基于预训练模型,但是仍然将可解释性和可解释性作为未来工作的改进机会。

在下一节中,我们将使用这个库实现一种方法来纠正给定句子中的语法错误。然后,我们将创建一个可视化的用户界面来演示结果。

2.语法错误纠正—实施

我将把这一部分分成三个步骤:

  1. 准备需求:这一步包括克隆存储库,下载预先训练好的模型,安装实现语法纠错模型所需的需求。我使用命令行界面(CLI)来完成这些步骤。
  2. 模型实现:实现并测试语法纠错模型。我在 Jupyter 笔记本上实现了这些步骤。
  3. 用户界面:创建用户界面,提升用户体验

2.1.准备需求

准备需求的第一步是将公开可用的存储库克隆到我们的本地系统中。换句话说,我们将使用以下命令在我们的计算机上创建一个来自 GitHub 的库副本:

git clone https://github.com/grammarly/gector.git

有三种预先训练好的模型可用。对于练习的这一部分,我们将依赖于使用 RoBERTa 作为预训练编码器的模型,该模型在现有模型中具有最高的总得分。让我们使用以下命令下载预先训练好的模型:

wget https://grammarly-nlp-data-public.s3.amazonaws.com/gector/roberta_1_gectorv2.th

既然我们已经将模型下载到本地,我将使用以下命令将它移动到“gector”目录,该目录位于我们从 GitHub 克隆的目录中:

mv roberta_1_gectorv2.th ./gector/gector

接下来,我们将转到适当的目录,使用以下命令开始运行模型:

cd ./gector

这个包依赖于其他库来执行,所以我们将使用以下命令来安装这些需求:

pip install -r requirements.txt

现在,我们已经将所有文件放在了正确的位置,可以开始下一步创建语法错误纠正模型了。

2.2.实现模型

现在我们已经有了这个模型需要的所有目录和文件,我们将开始使用这个库。我们将采取以下步骤:

  1. 导入必要的包
  2. 创建模型的实例
  3. 在一个有语法错误的句子上测试模型,以查看输出。为此,我们将使用下面的句子:“她正在看天空”。你认为正确的句子是什么?把它写下来,和结果进行比较!
# Import libraries
from gector.gec_model import GecBERTModel

# Create an instance of the model
model = GecBERTModel(vocab_path = "./data/output_vocabulary", model_paths = ["./gector/roberta_1_gectorv2.th"])

# Add the sentence with grammatical errors
sent = 'she are looking at sky'

# Create an empty list to store the 
batch = []
batch.append(sent.split())
final_batch, total_updates = model.handle_batch(batch)
updated_sent = " ".join(final_batch[0])
print(f"Original Sentence: {sent}\n")
print(f"Updated Sentence: {updated_sent}")

结果:

更新的句子相当惊人!让我们来看看变化:

  1. 句首大写的 she 改为 She
  2. 将“are”改为“is ”,使“she”和“is”的主谓一致
  3. 在“天空”前增加了“the”
  4. 在句末加了一个句号

这些都是好的改变,如果我来纠正这个句子,我也会这么做,但是…如果我们有一个更复杂的句子呢?让我们混合时态,看看模型如何执行。

# Add the sentence with grammatical errors
sent = 'she looks at sky yesterday whil brushed her hair'

# Create an empty list to store the 
batch = []
batch.append(sent.split())
final_batch, total_updates = model.handle_batch(batch)
updated_sent = " ".join(final_batch[0])
print(f"Original Sentence: {sent}\n")
print(f"Updated Sentence: {updated_sent}")

结果:

这个也很有意思。让我们总结一下变化:

  1. 句首大写的 she 改为 She
  2. 将“看起来”改为“看起来”,现在与“昨天”一致
  3. 在“天空”前增加了“the”
  4. 将丢失的字母添加到“while”中
  5. 把“刷”改成了“刷”,这是“while”之后的预期形式

注意,这个模型决定了动词的时态是过去时。另一种方法可能是决定预期的动词时态存在,并将“昨天”改为“今天”,但是基于训练的数据,模型决定使用过去时态。

现在让我们再看一个例子,看看我们是否可以突破模型的界限,用时态来混淆它:

# Add the sentence with grammatical errors
sent = 'she was looking at sky later today whil brushed her hair'

# Create an empty list to store the 
batch = []
batch.append(sent.split())
final_batch, total_updates = model.handle_batch(batch)
updated_sent = " ".join(final_batch[0])
print(f"Original Sentence: {sent}\n")
print(f"Updated Sentence: {updated_sent}")

结果:

最后,我们发现了一种极端情况,即模型不能识别正确的动词时态。更新后的句子是关于“今天晚些时候”的,暗示的是将来时,而模型生成的句子是过去式。那么为什么这比以前对模型更有挑战性呢?答案是“今天晚些时候”是在用两个词暗示时间,这需要模型更深层次的上下文感知。请注意,如果没有“稍后”这个词,我们将得到一个完全可以接受的句子,如下所示:

在这种情况下,“今天”可以指今天早些时候(即过去),这将使语法校正完全可接受。但是在最初的例子中,“今天晚些时候”没有被模型识别为将来时态的指示。一般来说,在各种用例上测试这些模型以了解这些限制是一个很好的实践。

2.3.用户界面

现在我们已经看了几个例子,我们将做两个更新来通过用户界面改善用户体验:

  1. 创建一个函数,接受一个句子并返回更新后的(即语法正确的)句子
  2. 添加易于使用的可视化界面
# Define a function to correct grammatical errors of a given sentence
def correct_grammar(sent):
    batch = []
    batch.append(sent.split())
    final_batch, total_updates = model.handle_batch(batch)
    updated_sent = " ".join(final_batch[0])
    return updated_sent

让我们在我们的一个句子上测试一下这个功能,确保它能像预期的那样工作。

sent = 'she looks at sky yesterday whil brushed her hair'

print(f"Original Sentence: {sent}\n")
print(f"Updated Sentence: {correct_grammar(sent = sent)}")

结果:

该函数按预期执行。接下来,我们将添加一个可视化用户界面来改善用户体验。出于这个目的,我们将使用 Gradio ,这是一个开源的 Python 库来创建演示和 web 应用程序,正如我们将在下面看到的。

提示: 如果没有安装,可以用下面的命令安装:

pip install gradio

安装 Gradio 后,让我们继续导入和创建用户界面,如下所示:

# Import Gradio
import gradio as gr

# Create an instance of the Interface class
demo = gr.Interface(fn = correct_grammar, inputs = gr.Textbox(lines = 1, placeholder = 'Add your sentence here!'), outputs = 'text')

# Launch the demo
demo.launch()

结果:

语法纠错模型的用户界面(使用 Gradio

现在我们有了演示界面,让我们再次测试我们的句子,看看它是如何工作的!我们只需在左边的框中键入句子,然后按“提交”。然后,结果将显示在右侧的框中,如下所示:

语法错误纠正模型结果(使用 Gradio

演示工作正常。试一试,测试其他句子,看看效果如何!

3.结论

在这篇文章中,我们看到了在现有的 NLP 管道中添加语法纠错模型的好处,比如神经机器翻译。然后,我们回顾了两类目前在文献中使用的方法来解决这一任务。最后,我们使用一个公开可用的库来实现一个预训练的语法错误纠正模型,在几个错误的句子上测试它,找到模型工作良好的地方,也面临一些限制,最后添加一个可视化界面来改善用户体验。

感谢阅读!

如果你觉得这篇文章有帮助,请在媒体上关注我,订阅接收我的最新文章!

https://medium.com/@fmnobar/membership

识别流行病持久影响的图形分析

原文:https://towardsdatascience.com/graph-analytics-in-identifying-enduring-effects-of-pandemics-5225faacfe0e

图形分析框架,旨在使用指数随机图形模型(ERGMs)确定新冠肺炎对医疗保健系统的持久影响

作者图片

内容

  1. 介绍
  2. 图形分析框架
  3. 指数随机图模型的解释性建模
  4. 实施环境管理系统
  5. 结论

介绍

我们最近发表在《美国计算机学会管理信息系统汇刊》( TMIS)上的一项研究显示了图表分析在识别新冠肺炎疫情的持久影响方面的潜力。你可以在这里阅读原文:

https://doi.org/10.1145/3564274

我们开发了一个图表分析框架来调查新冠肺炎疫情之前和期间患者中多种疾病的同时发生,称为疾病多病性。通过分析电子健康记录(EHRs)数据,我们能够确定可用于检测病毒长期影响的模式和结构。

我们的研究发现,与传统方法相比,图形分析可以更准确、更全面地了解新冠肺炎对患者的影响。通过捕捉电子健康记录(EHRs)数据中的复杂关系和依赖关系,图表分析可以帮助医疗保健提供商更好地了解和解决病毒的长期影响。这些发现对正在进行的抗击新冠肺炎的努力也有重要意义,可以支持研究人员和决策者制定有效的干预措施和治疗方法。

图形分析框架

作者图片

提议的框架建立在分析医院出院记录的现有信息系统的基础上。除了传统的分析实践(如疾病患病率排名或使用数据挖掘来预测结果)之外,它还使用图表分析进行多病分析。该框架由三个相互关联的部分组成:探索性分析、解释性建模和预测性建模。它是从具有诊断代码(ICD-10 代码)的医院出院数据集凭经验创建的,并且可以通过在边权重分布上设置合适的阈值来转换成未加权的无向网络。在探索性分析中,可以检查网络及其节点的结构信息,可以使用 DeltaCon 或 NetSimile 等新方法进行比较。解释性建模使用数学或统计图形模型(如 ERGMs),而预测性建模使用网络的节点和边的嵌入向量来表示潜在特征或拟合高维非线性模型以进行预测。

如果你对如何得到疾病网络的节点和边的嵌入向量感兴趣,请参考下面的博客:

https://medium.com/analytics-vidhya/analyzing-disease-co-occurrence-using-networkx-gephi-and-node2vec-53941da35a0f

指数随机图模型的解释性建模

ERGMs 是分析网络并探索其形成背后的模式和结构的统计模型。ERGMs 基于这样的概念,即特定网络结构的概率可以表示为图统计的指数函数,例如网络中边或三角形的数量。在这项研究中,我们利用指数随机图模型(ERGMs)来估计两种疾病形成联系的概率,称为多病性。然后,我们比较了新冠肺炎疫情之前和期间不同疾病类别的系数,以解释疫情对医疗保健系统的持久影响。

ERGMs 中使用的关键算法之一是马尔可夫链蒙特卡罗(MCMC)算法,这是一种从概率分布中进行采样以估计模型参数的方法。MCMC 使用随机游走过程来探索可能的模型配置的空间,并基于观察到的数据迭代地更新模型参数的估计。ERGMs 中使用的另一个重要算法是 Metropolis-Hastings 算法,它是 MCMC 算法的一个变体,允许更有效地探索模型空间。

ERGMs 的一个优点是,它们可以结合外部变量,如个体水平的特征,来解释网络的形成。这使得研究人员能够测试关于不同因素如何影响网络结构的假设,并预测网络将如何随时间演变。

ERGMs 的另一个好处是它们能够生成结构特性与观测数据相似的合成网络。这对于扩充有限的数据集或模拟干预对网络结构的影响非常有用。

ERGMs 的一个缺点是计算复杂,特别是对于大型网络。它们还需要大量的观察来产生可靠的估计,这使得它们不适合小的或稀疏的数据集。ERGMs 中使用的指数函数有时会产生不切实际的预测,尤其是对于结构复杂的网络或模型指定错误的情况。ERGMs 也有其他缺点,例如指数函数可能导致不准确或误导的结果,以及对假设和建模选择的敏感性。这使得比较不同研究的结果或使用不同的数据集或方法复制发现变得困难。因此,研究人员在使用 ERGMs 分析网络数据时,应仔细考虑其局限性和潜在偏见。

实施环境管理系统

在本节中,我将演示一些在 r 中实现 ERGMs 的简单代码,如果您对细节感兴趣,请在此阅读原文: Package 'ergm'

R 中的ergm包为拟合和分析 ERGMs 提供了一套全面的函数。为了拟合 ERGM,可以使用ergm()函数,该函数将包含网络数据的数据帧和指定要拟合的模型的公式作为输入。例如,以下代码通过一个包含边协变项和网络传递项的模型将 ERGM 拟合到存储在network数据框中的网络。

library(ergm)

# Fit the model
model <- ergm(formula = network ~ edges + transitivity, data = network)

以下是ergm()功能的一些附加核心参数:

  1. nodecov :该术语将每个定量属性或矩阵列的单个网络统计量添加到模型中,等于网络中所有边(I,j)的 attr(i)和 attr(j)之和。(数字)
  2. nodefactor :这个术语将多个网络统计信息添加到模型中,每个统计信息对应于 attr 属性(或给定属性的每个组合)的唯一值(的一个子集)。(分类)
  3. 控制:这是微调“ergm”拟合的用户界面。例如,在内部控制中,您可以设置最大迭代次数、种子和抽样统计数据之间的建议数。

使用附加参数,代码可以重写如下:

library(ergm)

# Fit the model
model <- ergm(g1 ~ edges+nodecov(~Numeric_Variable1)
                 + nodecov(~Numeric_Variable2)
                 + nodefactor("Categorical_Variable1", 
                               levels=c("a", "b", "c"))
                 + nodefactor("Categorical_Variable2", 
                               levels=c("a","b")),  
                 control=control.ergm(MCMC.interval = 10000,
                                      MCMLE.maxit = 100,
                                      seed = 42))

summary()功能可用于获取拟合模型的汇总统计数据和诊断图。该函数将拟合的模型作为输入,并生成一个摘要报告,其中包含有关模型拟合度、模型系数和拟合优度度量的信息。例如,以下代码为拟合的模型生成一个摘要报告:

# Generate a summary report
summary(model)

如果你有兴趣学习如何操作 R 中的网络,请阅读这里:

结论

在这项研究中,我们开发了一个图表分析框架和一个基于 ERGM 的解释性图表模型,以检查新冠肺炎疫情之前和期间亚利桑那州医院出院记录中记录的疾病多病性。根据我们的分析,我们观察到,在疫情高峰期间,虽然精神障碍和呼吸障碍的多病率分别增加了 34.26%和 41.04%,但内分泌疾病和循环系统疾病的梯度并不显著。我们还发现,在疫情期间,急性疾病的多病率下降,而慢性疾病的多病率保持不变。

该框架和模型可用于任何包含有序或无序诊断代码列表的标准化电子健康记录数据库。这项研究为未来的研究提供了信息,将多病纳入问题场景,如疾病风险预测和健康结果建模的特征工程。解释性图形模型也可以用于补充深度学习和数据挖掘建模方法。这项研究对健康分析研究人员和政策制定者具有意义,为分析疾病多病模式提供了工具,并为避免公共健康危机的先发制人行动提供了指南。

引用作品:

斯里尼瓦桑、卡尔提克、金行江。"检查新冠肺炎疫情之前和期间美国医院就诊的疾病多病性:图表分析方法."美国计算机学会管理信息系统汇刊(2022)。【https://doi.org/10.1145/3564274】

相关阅读

https://medium.com/mlearning-ai/implementation-of-latent-network-models-visualize-network-data-in-r-b25c42f6d95a

图形注意网络:自我注意的解释

原文:https://towardsdatascience.com/graph-attention-networks-in-python-975736ac5c0c

使用 PyTorch 几何图形的带自我注意的 GNNs 指南

图片由作者提供,文件图标由open moji(CC BY-SA 4.0)提供

图形注意力网络是最流行的图形神经网络类型之一。理由很充分。

在图卷积网络(GCN)中,每个邻居都有相同的重要性。显然,情况不应该是这样的:有些节点比其他节点更重要。

节点 4 比节点 3 重要,节点 3 比节点 2 重要(图片由作者提供)

图表注意网络为这个问题提供了一个解决方案。为了考虑每个邻居的重要性,注意机制为每个连接分配一个加权因子。

在本文中,我们将看到如何计算这些注意力分数,以及如何在 PyTorch Geometric (PyG)中实现一个高效的 GAT。你可以用下面的 Google Colab 笔记本运行本教程的代码。

🌐一.图表数据

CiteSeer 数据集(图片由作者提供,由 yEd Live 制作)

我们可以在这项工作中使用三个经典的图形数据集(麻省理工学院许可)。它们代表了研究论文的网络,每个连接都是一个引用。

  • Cora :由 2708 篇属于 7 个类别之一的机器学习论文组成。
    ➡️节点特征表示一篇论文中 1433 个单词的存在(1)或不存在(0)(二进制包单词)。
  • CiteSeer :这是一个更大但相似的数据集,包含 3312 篇科学论文,可归为 6 个类别之一。
    ➡️节点特征表示论文中 3703 个单词的存在(1)或不存在(0)。
  • PubMed :这是一个更大的数据集,有来自 PubMed 数据库的 19717 篇关于糖尿病的科学出版物,分为 3 类。
    ➡️节点特征是来自 500 个唯一单词的字典的 TF-IDF 加权单词向量

这些数据集已经被科学界广泛使用。作为一项挑战,我们可以使用多层感知器 (MLPs)、 GCNsGATs 将我们的准确度分数与在文献中获得的分数进行比较:

PubMed 非常大,所以处理它和在它上面训练一个 GNN 需要更长的时间。Cora 是文献中研究最多的一个,所以让我们把 CiteSeer 作为中间地带。

我们可以用小行星类将这些数据集直接导入 PyTorch Geometric:

Number of graphs: 1
Number of nodes: 3327
Number of features: 3703
Number of classes: 6
Has isolated nodes: True

有趣的是,我们有 3327 个节点,而不是 3312 个。我发现 PyG 实际上使用了本文的CiteSeer 的实现,它也显示 3327 个节点。谜团暂时解开了。

但是,我们观察到有些节点是孤立的(准确的说是 48)!正确分类这些孤立的节点将是一个挑战,因为我们不能依赖任何聚合。

让我们用degree画出每个节点的连接数:

大多数节点只有 1 或 2 个邻居。这可以解释为什么 CiteSeer 获得的准确度分数比其他两个数据集低…

⚠️二世。自我关注

veli kovi 等人在 2017 年提出,GNNs 中的自我关注依赖于一个简单的想法:节点不应该都具有相同的重要性

我们谈论自我——注意力(不仅仅是注意力),因为输入是相互比较的。

作者图片

该机制为每个连接分配一个加权因子(关注分数)。姑且称之为 α ᵢⱼ 节点 ij 之间的关注度得分。

以下是如何计算节点 1 的嵌入,其中𝐖是共享权重矩阵:

但是我们如何计算注意力分数呢?我们可以写一个静态公式,但是有一个更聪明的解决方案:我们可以用神经网络来学习 他们的值。这个过程有三个步骤:

  1. 线性变换
  2. 激活功能
  3. Softmax 归一化。

1️⃣线性变换

我们想要计算每个连接的重要性,所以我们需要成对的隐藏向量。创建这些对的一个简单方法是连接两个节点的向量。

只有这样,我们才能应用一个新的线性变换和一个权重矩阵𝐖 ₐₜₜ :

作者图片

2️⃣激活函数

我们正在构建一个神经网络,所以第二步是添加一个激活函数。在这种情况下,论文的作者选择了 LeakyReLU 函数。

作者图片

3️⃣软件最大归一化

我们的神经网络的输出是而不是归一化的,这是一个问题,因为我们想要比较这些分数。为了能够说节点 2 对于节点 1 是否比节点 3 更重要(α₁₂>t24】α₁₃),我们需要共享相同的尺度。

使用神经网络的一个常见方法是使用 softmax 函数。这里,我们将其应用于每个相邻节点:

作者图片

现在你知道了:我们可以计算每一个ᵢⱼ.唯一的问题是… 自我关注不是很稳定。为了提高性能, Vaswani 等人在变压器架构中引入了多头关注。

4️⃣奖金:多头关注

这只是稍微令人惊讶,因为我们已经谈论了很多关于自我关注的话题,但是,事实上,变形金刚是伪装的 GNNs。这就是为什么我们可以在这里重用自然语言处理中的一些思想。

多头关注(图片由作者提供)

在 GATs 中,多头注意力包括多次重复相同的 3 个步骤,以便平均或连接结果。就是这样。代替单一的 h₁ ,我们为每个注意力头得到一个隐藏向量 h₁ᵏ 。然后可以应用以下两种方案之一:

  • 平均值:我们将不同的 hᵢᵏ 相加,并通过注意力头数 n 将结果归一化;

  • 串联:我们串联不同的 hᵢᵏ 。​

实际上,当它是一个隐藏层时,我们使用连接方案,当它是网络的最后一层时,我们使用平均方案

🧠三世。图形注意网络

让我们在 PyTorch 几何中实现一个 GAT。这个库有两个不同的图形关注层 : GATConvGATv2Conv

到目前为止,我们谈论的是GatConv层,但在 2021 年 Brody 等人通过修改操作顺序引入了一种改进。在串联后应用权重矩阵𝐖,在泄漏函数后使用注意力权重矩阵𝐖 ₐₜₜ 。总而言之:

  • GatConv:

  • Gatv2Conv:

你应该用哪一个?根据 Brody 等人的说法,**Gatv2Conv** 始终优于 **GatConv** ,因此应该首选。

现在让我们对 CiteSeer 的论文进行分类!我试着大致重现原作者的实验而不增加太多复杂性。你可以在 GitHub 上找到 GAT 的官方实现。

请注意,我们在两种配置中使用图形关注层:

  • 第一层串接 8 路输出(多头注意);
  • 第二层只有 1 个头,产生我们的最终嵌入。

我们还要训练和测试一个 GCN 来比较准确率。

GCN(
  (gcn1): GCNConv(3703, 16)
  (gcn2): GCNConv(16, 6)
)Epoch   0 | Train Loss: 1.782 | Train Acc:  20.83% | Val Loss: 1.79 
Epoch  20 | Train Loss: 0.165 | Train Acc:  95.00% | Val Loss: 1.30 
Epoch  40 | Train Loss: 0.069 | Train Acc:  99.17% | Val Loss: 1.66 
Epoch  60 | Train Loss: 0.053 | Train Acc:  99.17% | Val Loss: 1.50 
Epoch  80 | Train Loss: 0.054 | Train Acc: 100.00% | Val Loss: 1.67 
Epoch 100 | Train Loss: 0.062 | Train Acc:  99.17% | Val Loss: 1.62 
Epoch 120 | Train Loss: 0.043 | Train Acc: 100.00% | Val Loss: 1.66 
Epoch 140 | Train Loss: 0.058 | Train Acc:  98.33% | Val Loss: 1.68 
Epoch 160 | Train Loss: 0.037 | Train Acc: 100.00% | Val Loss: 1.44 
Epoch 180 | Train Loss: 0.036 | Train Acc:  99.17% | Val Loss: 1.65 
Epoch 200 | Train Loss: 0.093 | Train Acc:  95.83% | Val Loss: 1.73 

**GCN test accuracy: 67.70%** 
CPU times: user 25.1 s, sys: 847 ms, total: 25.9 s
Wall time: **32.4 s**
GAT(
  (gat1): GATv2Conv(3703, 8, heads=8)
  (gat2): GATv2Conv(64, 6, heads=1)
)Epoch   0 | Train Loss: 1.790 | Val Loss: 1.81 | Val Acc: 12.80%
Epoch  20 | Train Loss: 0.040 | Val Loss: 1.21 | Val Acc: 64.80%
Epoch  40 | Train Loss: 0.027 | Val Loss: 1.20 | Val Acc: 67.20%
Epoch  60 | Train Loss: 0.009 | Val Loss: 1.11 | Val Acc: 67.00%
Epoch  80 | Train Loss: 0.013 | Val Loss: 1.16 | Val Acc: 66.80%
Epoch 100 | Train Loss: 0.013 | Val Loss: 1.07 | Val Acc: 67.20%
Epoch 120 | Train Loss: 0.014 | Val Loss: 1.12 | Val Acc: 66.40%
Epoch 140 | Train Loss: 0.007 | Val Loss: 1.19 | Val Acc: 65.40%
Epoch 160 | Train Loss: 0.007 | Val Loss: 1.16 | Val Acc: 68.40%
Epoch 180 | Train Loss: 0.006 | Val Loss: 1.13 | Val Acc: 68.60%
Epoch 200 | Train Loss: 0.007 | Val Loss: 1.13 | Val Acc: 68.40%

**GAT test accuracy: 70.00%** 
CPU times: user 53.4 s, sys: 2.68 s, total: 56.1 s
Wall time: **55.9 s**

这个实验并不是超级严格的:我们需要重复 n,取平均精度和标准偏差作为最终结果。

在这个例子中,我们可以看到 GAT 在精度方面优于 GCN(70.00%对 67.70%),但训练时间更长(55.9 秒对 32.4 秒)。在处理大型图形时,这种折衷会导致可伸缩性问题。

作者获得了 GAT 的 72.5%和 GCN 的 70.3%,这明显优于我们所做的。这种差异可以通过预处理、模型中的一些调整、和不同的训练设置来解释(例如,耐心为 100,而不是固定的周期数)。

让我们想象一下猫学到了什么。我们将使用 t-SNE ,这是一种在 2D 或 3D 中绘制高维数据的强大方法。首先,让我们看看在任何训练之前嵌入是什么样子的:它应该是绝对随机的,因为它们是由随机初始化的权重矩阵产生的。

的确,这里没有没有明显的结构。但是由我们训练的模型产生的嵌入看起来更好吗?

区别是显而易见的:属于相同类的节点聚集在一起。我们可以看到 6 组,对应于 6 类论文。有异常值,但这是意料之中的:我们的准确度分数远非完美。

之前,我推测连接不良的节点可能会对 CiteSeer 上的性能产生负面影响。让我们计算每一个度数的模型精度。

这些结果证实了我们的直觉:邻居少的节点确实更难分类。这是由 GNNs 的性质决定的:你拥有的相关连接越多,你能聚集的信息就越多。

结论

虽然 GATs 需要更长的训练时间,但在准确性方面比 gcn 有了很大的提高。自关注机制自动计算加权因子而不是静态系数,以产生更好的嵌入。在这篇文章中,

  • 我们了解了应用于 GNNs 的自我关注机制;
  • 我们在 PyTorch Geometric 中实现并比较了两个架构(一个 GCN 和一个 GAT);
  • 我们用一个 t-SNE 图和每一个学位的准确度分数形象化了 GAT 如何学习和学习什么;

《服务贸易总协定》是许多 GNN 申请中事实上的标准。然而,当应用于大规模图形数据集时,它们的缓慢的训练时间会成为一个问题。可扩展性是深度学习的一个重要因素:通常情况下,更多的数据可以带来更好的性能。

在下一篇文章中,我们将看到如何使用迷你批处理和一个名为 GraphSAGE 的新 GNN 架构来提高可伸缩性

如果你喜欢这个教程,请随时在 Twitter 上关注我,了解更多关于 GNN 的内容。谢谢大家,下一篇文章再见!📣

相关文章

解释了图形嵌入

原文:https://towardsdatascience.com/graph-embeddings-explained-f0d8d1c49ec

节点、边和图嵌入方法的概述和 Python 实现

图片由 Ester Marie DoysabasUnsplash 拍摄

近年来,基于图形的机器学习有所增加。基于图的方法可应用于数据科学中的各种常见问题,如链接预测、社区检测、节点分类等。根据你如何组织你的问题和你所拥有的数据,有许多潜在的方法来解决它。这篇文章将提供一个高层次的概述和基于图形的嵌入算法背后的直觉。我还将介绍如何引用像node2vec这样的预建 Python 库来生成图中的节点嵌入。下面概述了本文涵盖的内容。

目录

  • 图上的机器学习
    -图上机器学习的好处
  • 什么是图嵌入?
  • 图嵌入的类型
    -节点嵌入
    -边嵌入
    -图嵌入
  • Python 实现
    -需求
    -节点嵌入
    -边嵌入
    -图嵌入
  • 结束语
  • 资源

图上的机器学习

人工智能有各种分支,从推荐系统、时间序列、自然语言处理、基于图形等。通过基于图形的机器学习,有各种方法来解决常见的过程。图由节点之间的一系列成对关系组成。使用图可以解决各种各样的问题,这些问题可以包括社区检测、链路预测、节点分类等。这些问题和解决方案因问题和数据集而异。

与图的机器学习相关的主要问题是找到一种表示(或编码)图结构的方法,以便它可以很容易地被机器学习模型利用[1]。通常,机器学习中的问题需要与模型的图形相关联的结构化表格数据来学习某种表示。在过去,统计测量或核函数是实现这一点的主要方法。然而,近年来,趋势已经转向对图进行编码以生成嵌入向量来训练机器学习模型。

机器学习对图形的好处

机器学习模型的目标是接受训练,以大规模学习和识别数据集中的模式。在处理图形时,这一点可能会被放大。它们提供了文本、音频或图像等其他形式的数据所没有的不同且复杂的结构。基于图的机器学习可以检测和解释重复出现的潜在模式[2]。

例如,我们可能对确定与社交网络上的用户相关联的人口统计信息感兴趣。人口统计数据是指年龄、性别、种族等。像脸书或 Twitter 这样的公司的社交媒体网络从数百万到数十亿用户和数万亿边缘。一定有几种模式与来自该网络的用户的人口统计信息相关,这些模式不容易通过人类或算法检测到,但模型应该能够学习它们。类似地,当一对用户目前不是朋友时,我们可能想要推荐他们成为朋友。这进入了链接预测方面(基于图形的机器学习的另一个应用)。

什么是图嵌入?

特征工程是指处理输入数据以形成一组特征的常用方法,这些特征提供了原始数据集的紧凑且有意义的表示。特征工程阶段的结果将被用作机器学习模型的输入。虽然这是常见表格结构数据集的处理过程,但在处理图形时,这是一种难以执行的方法。我们需要找到一种方法来生成与所有图形数据相关联的适当表示。

从图中生成表示结构信息的特征有多种方法。最常见和直接的方法是从图表中提取统计数据。这可以包括诸如识别程度分布、页面等级分数、中心性度量、jaccard 分数等。离此更远的一步将是应用能够将期望的属性结合到模型中的核函数。核函数的问题是生成结果的相关时间复杂度。

最近的研究趋势已经转向寻找有意义的图形表示。这项研究的结果产生了图的嵌入。这些嵌入学习保持网络原始结构的图形表示。我们可以认为这是一个映射函数,它的目的是将一个离散的图转换成一个连续的域。一旦学习了该函数,就可以将其应用于该图,并且所得到的映射可以用作机器学习算法的特征集[2]。

图嵌入的类型

通常,对图形的分析可以分为 3 个粒度级别。节点级、边级和图级(整个图)。每一层都包含不同的生成嵌入向量的过程,所选择的过程应该取决于你正在处理的问题和数据。请参考下图,该图直观地概括了每个粒度级别的嵌入是如何彼此不同的。

节点嵌入

在节点级别,您生成一个与图中每个节点相关联的嵌入向量。这个嵌入向量可以保存图形表示和结构。本质上,彼此非常接近的节点也应该具有彼此非常接近的向量。这是 Node2Vec 等流行的节点嵌入模型的基本原则之一。

二维空间中节点嵌入的可视化表示。图片由作者提供。

边缘嵌入

边级别,您生成一个与图中每条边相关联的嵌入向量。链路预测问题是使用边缘嵌入的常见应用。链接预测是指预测一对节点应该具有连接它们的边的可能性。这些嵌入可以学习由图提供的边属性。例如,在一个社交网络图中,你可以有一个多边图,其中节点可以根据年龄范围、性别、友谊等通过边连接。表示该边的相关向量可以学习这些边属性。

二维空间中边缘嵌入的可视化表示。图片由作者提供。

图形嵌入

图级别的嵌入并不常见,它们包括生成一个表示每个图的嵌入向量。考虑一个有多个子图的大图,每个对应的子图都有一个表示图结构的嵌入向量。分类问题是一个常见的应用,其中图嵌入可能是有用的。这些类型的问题包括将一个图形分类到一个特定的类别。

二维空间中图形嵌入的可视化表示。图片由作者提供。

Python 实现

要求

Python=3.9
networkx>=2.5
pandas>=1.2.4
numpy>=1.20.1
node2vec>=0.4.4
karateclub>=1.3.3
matplotlib>=3.3.4

如果没有安装 node2vec 包,这里的是通过命令行安装的库文档。同样,你可以用 Python 安装 karateclub 包,指令如下这里

节点嵌入

从可视化的杠铃图生成的节点嵌入。图片由作者提供。

有许多方法可以计算节点嵌入,如 node2vec、深度行走、随机行走等。出于本教程的目的,我将使用 node2vec。

边缘嵌入

可视化杠铃图生成的边缘嵌入。图片由作者提供。

Hammard 嵌入器的源代码可以在这里找到。

图形嵌入

从许多随机生成的图中生成的图嵌入。图片由作者提供。

graph2vec 算法的源代码可以在这里找到。

结束语

简单地说,嵌入是一个将离散图映射到向量表示的函数。从图中可以生成各种形式的嵌入,即节点嵌入、边嵌入和图嵌入。所有这三种类型的嵌入都提供了一种矢量表示,将图的初始结构和特征映射到 x 维的数值量。

你可以在我的 GitHub 页面这里查看与本教程相关的资源库。

如果你想转型进入数据行业,并希望得到经验丰富的导师的指导和指引,那么你可能想看看最敏锐的头脑。Sharpest Minds 是一个导师平台,导师(他们是经验丰富的实践数据科学家、机器学习工程师、研究科学家、首席技术官等。)将有助于你的发展和学习在数据领域找到一份工作。点击这里查看。

资源

如果你觉得这篇文章有用,这里有一些我写的其他文章,你可能也会觉得有用。

图形嵌入:节点如何映射到向量

原文:https://towardsdatascience.com/graph-embeddings-how-nodes-get-mapped-to-vectors-2e12549457ed

  • 大多数传统的机器学习算法对数字向量数据进行处理
  • 图嵌入通过学习从图结构数据到向量表示的映射,打开了强大的工具箱
  • 它们的基本优化是:在嵌入空间中映射具有相似上下文的节点
  • 图中节点的上下文可以使用两种正交方法之一来定义——同伦和结构等价——或者它们的组合
  • 一旦定义了度量标准,数学就被简明地公式化了——让我们来探索一下。

图形数据库和机器学习

图形数据库对各种来源的相关数据的大数据应用程序有着广泛的热情和采用。它们基于强大的存储概念,使简洁的查询语言能够分析数据中复杂的关系模式。因此,像 PageRank、中心性检测、链接预测和模式识别这样的算法可以用简单和直观的方式来陈述。

然而,大多数发展良好的传统机器学习算法,如线性和逻辑回归、神经网络等,都是基于数字向量表示的。要打开这个强大的工具箱来处理图结构,我们需要一种方法来以向量形式表示我们的数据网络。图嵌入是从图中的数据学习这种映射的一种形式。

图嵌入的目的

作者图片

我们的目标是为图中的每个节点找到一个向量表示。映射应该代表节点的网络结构,而不是考虑节点的相关特征。换句话说,节点的嵌入向量应该基于它的关系和相邻节点。图中相似的节点应该在向量空间中紧密映射。我们将节点映射到的向量空间称为嵌入空间。

现在,如果我们看一下上面的陈述,我会想到两个问题,需要进一步思考:

  • 是什么使得图中的两个节点相似
  • 嵌入空间中的关闭是什么意思?

网络中的相似节点

为了详细说明图中的相似性,让我们考虑一个句子:

作者图片

一个句子是一系列单词,每个单词都有一个确定的位置。因此,一个句子中的一个词恰好有一个祖先和一个后继者。为了定义一个单词在句子中的上下文,我们可以使用它周围的单词。例如,单词“capital”的距离一上下文是单词“the”和“of”。距离-两个上下文将是单词“是”,“的”,“的”,“德国”。这被称为 n-gram 模型,并被称为 word2vec 的用于查找单词嵌入的流行方法所使用。

类似于 n-gram,我们可以定义图中节点的上下文。尽管如此,我们在图形结构中比在单词序列中有更多的选择。在一般的图中,每个节点可能连接到两个以上的其他节点,而在一个句子中,一个单词只有一个直接的祖先和后继。

因此,一个句子是一个向量,沿着索引轴移动可以探索单词的上下文。然而,图被描述为二维邻接矩阵,并且节点的直接祖先是向量。为了探索节点的上下文,我们在每个距离级别上都有多个选择,并且我们必须决定如何遍历它们。

通常,有两种正交的方法来探索网络环境:

作者图片

  1. 广度优先:在我们(可能)转移到距离为 2 的节点之前,我们首先详细说明源节点的直接邻居。这也被称为同性恋,来源于一个社会学概念,即人们通常倾向于与相似的人密切互动。因此,它基于图中相似节点具有紧密关系的假设。
  2. 深度优先:我们首先沿着从源节点开始到其深度的路径探索一个连接链,然后再继续下一个。与同向性相反,这种度量从更广的角度捕捉了网络中节点的角色。我们不是着眼于密切的关系,而是寻求发现一个节点的结构角色:例如,它是如何嵌入到一个更大的社区环境中的。这种度量被称为结构等价。

我们可以使用这两种方法来查找节点的上下文——可能的话,可以将它们结合起来。有了一组描述每个节点上下文的节点,我们可以使用这些集合来比较每对节点的上下文相似性。例如,我们可以应用 Jaccard 相似度来度量两个上下文有多少重叠。这将为我们提供一种在图中找到具有相似网络结构的节点的方法。

作者图片

背景取样

然而,我们不能对任何给定节点的整个上下文进行采样,因为这最终会导致捕获任何节点的整个图。因此,我们采用一种叫做抽样策略的近似方法。想法是在源顶点开始固定数量的随机行走,以探索其上下文来生成随机样本。node2vec 定义的采样策略结合了同质性和结构等价性。它实现了一个参数来决定在行走的每一步中是应该靠近源节点(同向性)还是应该探索另一个距离级别(结构等价)。

作者图片

在 node2vec 中,我们试图为每个节点找到一个数字向量,而不是使用前面描述的 Jaccard 相似性。我们使用图中节点的采样上下文来优化映射函数,以将具有相似上下文的节点映射到一起。

node2vec 的数学

让我们通过考虑下面的例子来详细探讨 node2vec 是如何工作的:

V: all nodes in graph
N_S(u): neighborhood of u determined by sample strategy S
f(u): mapping function of node u onto a vector

我们的目标是找到 V 中所有节点 u 的嵌入,使得具有相似上下文的节点的向量表示在嵌入空间中是接近的。我们已经知道图中相似的上下文意味着什么,但是我们仍然需要定义,嵌入空间中的接近意味着什么。

作者图片

现在让我们只考虑图中的两个节点:

u: source node
v: node in context of u

为了开始我们的数学,我们简单地为两个节点选择两个随机向量f(u), f(v)。为了度量嵌入空间中的相似性,我们使用两个向量的点积,即它们之间的角度。

作者图片

由于节点vu的附近,现在的想法是递增地优化映射函数f,使得它们的相似性得到最大化。

为了将我们的相似性转化为概率,我们应用了一个 softmax。softmax 使用u与所有其他向量v in V的所有相似性的总和来标准化相似性得分dot(f(u), f(v))。因此,点积被转换成一个介于[0,1]之间的数字,所有的相似性加起来等于 1。结果是在节点u的上下文中从它们的向量表示中看到节点v的概率。现在,我们可以通过使用随机梯度下降更新我们的向量f(u)来递增地优化这个概率。

作者图片

下一步是推广这一概念,不仅对 N_S(u)中的一个节点 v 进行优化,而且对 u 上下文中的所有节点进行优化。如果给定节点 u,我们希望优化看到整个采样上下文的概率。如果我们假设样本独立,我们可以将此公式简化为简单概率的乘积。

作者图片

最后,我们想学习图中每个源节点 u 的映射。因此,我们将该公式同时应用于图的所有节点。我们使用 SGD 通过调整我们的映射f来优化总和,以便概率增加。我们逐步改进,直到达到最大迭代次数,或者在优化问题中找到一个固定点。

作者图片

进一步说明

当实现这个解决方案并在大型数据集上运行它时,有一个主要的挑战:当我们计算 softmax 来确定概率P(f(v) | f(u))时,分母中有一个归一化项,计算起来很难看。这个归一化项是图中u和所有其他节点的所有相似性的总和。它在优化的整个迭代中保持固定,因此对于源节点u的求和的所有迭代也是固定的。第一个优化是将该因子移出总和。

第二个挑战是,计算所有向量的这种因子非常昂贵。在每次迭代中,我们必须确定每个源节点u与图中所有其他向量的点积,以找到归一化因子。为了克服这一点,一种称为负采样的技术被用来近似这一因素。

边缘嵌入

上述方法也可以应用于不同的基本假设:代替寻找具有相似上下文的节点的映射,我们也可以设置将边映射到嵌入空间的不同目标,使得这些边靠近,共享相同的节点。结合 node2vec 中的节点和边嵌入,我们在更一般的术语下导出图嵌入,它能够将相关数据映射到向量表示。

结论

我们已经探索了如何找到一个映射f(u)来将一个图的节点映射到一个向量空间中,这样相似的节点是闭合的。有多种方法来定义图上下文中节点的相似性:同构和结构等价。两者都有正交的方法,node2vec 定义了一个策略,将两者结合成一个参数化的采样策略。采样策略是一种找到节点上下文的方法,这反过来又被用来导出我们的嵌入。嵌入空间中的相似性又被定义为两个映射向量之间的点积。嵌入本身是使用随机梯度下降的迭代优化。它在每次迭代中调整所有节点的向量,以最大化同时看到来自相同上下文的节点的概率。对非常大的数据集的实现和应用需要一些统计近似来加速计算。

node2vec 是打开传统机器学习算法的强大工具箱以处理图结构数据的重要钥匙。

就我个人而言,我再次被解决手头问题的算法定义的简单和简洁所吸引。我发现令人惊讶的是,如果将这些方法应用于正确的问题,使用正确的数据量,它们的效果会有多好。

参考

图形机器学习@ ICML 2022

原文:https://towardsdatascience.com/graph-machine-learning-icml-2022-252f39865c70

GraphML 有什么新特性?

最新进展和热点趋势,2022 年 7 月版

国际机器学习大会(ICML) 是研究人员发表最佳作品的主要场所之一。ICML 2022 挤满了数百份论文和众多致力于图表的工作室。我们分享最热门的研究领域的概况🔥在图表 m1 中。

本帖由 迈克尔·高尔金 (米拉)和 朱兆承 (米拉)撰写。

我们尽最大努力强调了 ICML 会议上图形 ML 的主要进展,每个主题包含 2-4 篇论文。尽管如此,由于被接受的论文数量庞大,我们可能会错过一些作品——请在评论或社交媒体上让我们知道。

目录(可点击):

  1. 生成:去噪扩散就是你所需要的
  2. 图形变形金刚
  3. 理论和表达性 GNNs
  4. 光谱 GNNs
  5. 可解释的 GNNs
  6. 图形增强:超出边缘丢失
  7. 算法推理和图形算法
  8. 知识图推理
  9. 计算生物学:分子连接、蛋白质结合、性质预测
  10. 酷图应用

代:去噪扩散是你所需要的

去噪扩散概率模型 ( DDPMs )将在 2022 年接管深度学习领域,几乎所有领域都具有令人惊叹的生成质量和比 GANs 和 VAEs 更好的理论属性,例如,图像生成( GLIDEDALL-E 2Imagen )、视频生成、文本生成( Diffusion-LM ),甚至从概念上讲,扩散模型逐渐向输入对象添加噪声(直到它是高斯噪声),并学习预测添加的噪声水平,以便我们可以从对象中减去它(去噪)。

扩散可能是 GraphML 在 2022 年的最大趋势——特别是当应用于药物发现、分子和构象异构体生成以及一般的量子化学时。通常,它们与等变 GNNs 的最新进展配对。ICML 为图形生成提供了几个很酷的去噪扩散实现。

在由 Hoogeboom、Satorras、Vignac 和 Welling 撰写的《3d中用于分子生成的等变扩散中,作者定义了用于分子生成的等变扩散模型( EDM ,其必须在原子坐标 x 上保持 E(3)等变(关于旋转平移、重要的是,分子具有不同的特征形态:原子电荷是一个有序整数,原子类型是一个热点分类特征,原子坐标是连续特征,因此,例如,你不能只添加高斯噪声到一个热点特征,并期望模型工作。相反,作者设计了特定特征的噪声处理和损失函数,并缩放输入特征以训练稳定性。

EDM 采用最先进的 E(n) GNN 作为神经网络,根据输入特征和时间步长预测噪声。在推理时,我们首先对期望数量的原子 M 进行采样,然后我们可以根据期望的属性 c 对 EDM 进行调节,并要求 EDM 生成分子(由特征 xh 定义)作为 x,h ~ p(x,h | c,M)

在实验上,EDM 在实现负对数似然性、分子稳定性和独特性方面远远优于基于归一化流量和 VAE 的方法。烧蚀表明,等变 GNN 编码器至关重要,因为用标准 MPNN 代替它会导致性能显著下降。GitHub 上已经有的代码了,试试吧!

向前和向后扩散。来源: Hoogeboom、Satorras、Vignac 和 Welling

基于扩散的生成可视化。来源:推特

对于 2D 图形, Jo、Lee 和 Hwang 提出了通过随机微分方程系统 ( GDSS )的图形扩散。之前的 EDM 是去噪扩散概率模型(DDPM)的一个实例, GDSS 属于 DDPMs 的姐妹分支,即基于分数的模型。事实上,最近的(ICLR ' 21)表明,如果我们用随机微分方程(SDEs)描述前向扩散过程,DDPMs 和基于分数的模型可以统一到同一个框架中。

SDE 允许将连续时间内的扩散建模为维纳过程(为简单起见,假设它是添加噪声过程的一个奇特术语),而 DDPMs 通常以 1000 步将其离散化(具有可学习的时间嵌入),尽管 SDE 需要使用特定的解算器。与之前基于分数的图生成器相比, GDSS 将相邻关系 A 和节点特征 X 作为输入(并预测)。表示为 SDE 的向前和向后扩散需要计算分数——这里是联合对数密度(X,A)的梯度。为了获得这些密度,我们需要一个基于分数的模型,这里作者使用了一个具有注意力集中的 GNN(图形多头注意力)。

在训练时,我们求解一个正向 SDE 并训练一个得分模型,而在推理时,我们使用训练好的得分模型并求解反向时间 SDE 。通常,你会在这里使用类似于朗之万动力学的东西,例如,朗之万 MCMC,但是高阶龙格-库塔解算器原则上也应该在这里工作。实验表明,在 2D 图生成任务中,GDSS 远远优于自回归生成模型和一次性 VAEs,尽管由于集成了逆时 SDE,采样速度可能仍然是一个瓶颈。 GDSS 码已经有了!

GDSS 直觉。资料来源:乔、李和黄

👀现在看看 arxiv,我们期待今年会有更多的扩散模型发布——图中的 DDPMs 应该有他们自己的大博客,敬请关注!

➡️最后,非扩散生成的一个例子是 Martinkus 等人的工作,他们设计了用于一次性图形生成的 GAN。除了经常立即生成邻接矩阵的其他 GANs 之外, SPECTRE 的思想是根据拉普拉斯算子的前 k 个(最低)特征值和特征向量来生成图形,这些特征值和特征向量已经给出了集群和连通性的一些概念。1️⃣ 幽灵生成 k 个特征值。2️⃣作者使用了一个聪明的技巧,从 top-k 特征向量诱导的斯蒂费尔流形中抽取特征向量。Stiefel 流形提供了一组标准正交矩阵,从中我们可以采样一个 n x k 矩阵。3️⃣Finally,获得一个拉普拉斯算子,作者使用一个可证明强大的图网来生成最终邻接。

实验表明, SPECTRE 比其他 GANs 好几个数量级,比自回归图形生成器快 30 倍🚀。

SPECTRE 生成特征值->特征向量->邻接的 3 步过程。来源:马丁库斯等人

图形转换器

在今年的 ICML 上,我们有两篇关于改进图形转换器的论文。

首先,陈,奥布雷,博格瓦德提出结构感知变压器。他们注意到自我关注可以被重写为核平滑,其中查询键乘积是一个指数核。然后归结为找到一个更一般化的内核——作者建议使用节点和图的功能来添加结构意识,即k-子树k-子图特征。K-子树本质上是 k-hop 邻域,可以相对快速地挖掘,但最终受限于 1-WL 的表达能力。另一方面,k-子图的计算成本更高(并且很难扩展),但是提供了可证明的更好的区分能力。

无论您选择什么特征,这些子树或子图(为每个节点提取的)都将通过任何 GNN 编码器(例如,PNA)进行编码,汇集(总和/平均值/虚拟节点),并在自我关注计算中用作查询和关键字(参见图示👇).

从实验上来说,k 为 3 或 4 就足够了,k-子图特性在我们能够负担计算费用的图上工作得更好。有趣的是,像拉普拉斯特征向量和随机游走特征这样的位置特征只对k-子树 SAT* 有帮助,而对k-子图 SAT 则毫无用处。*

资料来源:【陈、奥布雷、博格瓦德

第二, Choromanski,林,陈等人(该团队与著名表演者的作者有很多重叠)研究的是实现亚二次注意的原理性机制。特别是,他们考虑了相对位置编码(RPE)及其对不同数据形式(如图像、声音、视频和图形)的变化。考虑到图形,我们从graph former得知,将最短路径距离注入注意力效果很好,但是需要完整注意力矩阵的具体化(因此,不可扩展)。我们能否在没有完全具体化的情况下近似 softmax 注意力,但仍然包含有用的图形归纳偏差?🤔

是啊!作者提出了两种这样的机制。(1)事实证明,我们可以使用图形扩散核(GDK)——也称为热核——模拟热传播的扩散过程,并作为最短路径的软版本。然而,扩散需要调用求解器来计算矩阵指数,因此作者设计了另一种方法。(2)随机行走图-节点核(RWGNK ),其值(对于两个节点)编码从这两个节点开始的随机行走获得的(这两个节点的)频率向量的点积。

随机漫步很棒,我们喜欢随机漫步😍查看下图,了解漫射和 RW 内核结果的可视化描述。具有 RWGNK 内核的最终转换器被称为**图内核注意力转换器**【GKAT】**,并且针对从 er 图中拓扑结构的综合识别到小型 compbio 和社交网络数据集的几个任务进行探索。GKAT 在合成任务上显示出更好的结果,并且在其他图形上的表现与 GNNs 相当。如果能看到真正的可伸缩性研究将转换器推向输入集大小的极限,那就太好了!

资料来源:乔罗曼斯基、林、陈等

理论与表达性 GNNs

GNN 社区继续研究突破 1-WL 表达能力的上限并保持至少多项式时间复杂性的方法。

➡️ 帕普和瓦腾霍夫从当前理论研究的准确描述开始:

每当引入新的 GNN 变体时,相应的理论分析通常会显示它比 1-WL 更强大,有时还会将其与经典的 k-WL 层次结构进行比较……我们能否找到一种更有意义的方法来衡量 GNN 扩展的表现力?

作者将表达性 GNNs 的文献分为 4 类:1️⃣ k-WL 和近似;2️⃣底座计数(s);3️⃣子图和邻域感知 GNNs (N) (在 Michael Bronstein 最近的文章中广泛讨论了);带有标记的 4️⃣gnns——这些是节点/边扰动方法和节点/边标记方法 (M) 。然后,作者提出了所有这些 k-WL、S、N 和 M 家族如何相关以及哪一个在何种程度上更强大的理论框架。该层次比 k-WL 更细粒度,有助于设计具有足够表现力的 gnn,以覆盖特定的下游任务并节省计算。

不同的富有表现力的 GNN 家族的等级制度。n =子图 GNNs,S =子结构计数,M =带标记的 GNNs。资料来源: Papp 和 Wattenhofer

➡️也许是最美味的 ICML'22 作品是由厨师们用🥓 SpeqNets 🥓(斯帕克在德语中是培根)。已知的高阶 k-WL gnn 要么在 k 阶张量上操作,要么考虑所有的 k 节点子图,这意味着在存储器需求上对 k 的指数依赖,并且不适应图的稀疏性。 SpeqNets 为图同构问题引入了一种新的启发式算法,即 (k,s)-WL ,它在表达性和可伸缩性之间提供了更细粒度的控制。

本质上,该算法是局部 k-WL 的变体,但仅考虑特定元组以避免 k-WL 的指数存储复杂性。具体来说,该算法只考虑最多具有 s 个连通分量的 k 节点上的 k 元组或子图,有效地利用了底层图的潜在稀疏性——变化的 ks 导致理论上的可扩展性和表达性之间的折衷。

基于上述组合见解,作者导出了一种新的置换等变图神经网络,记为 SpeqNets ,在极限情况下达到普适性。与受监督的节点和图形级分类和回归机制中的标准高阶图形网络相比,这些架构大大减少了计算时间,从而显著提高了标准图形神经网络和图形核架构的预测性能。

的等级制度🥓SpeqNets🥓。来源:莫里斯等人

接下来,黄等人以一种非正统的眼光看待排列不变的 gnn,认为精心设计的排列敏感的gnn 实际上更有表现力。Janossy pooling 的理论说,如果我们展示一组变换的所有可能的例子,那么一个模型对于这样一组变换是不变的,对于 n 个 T21 元素的排列,我们有一个难以处理的 n!排列组合。相反,作者表明,只考虑节点的邻域的成对 2 元排列就足够了,并且可以证明比 2-WL 更强大,并且不比 3-WL 更弱。

实际上,提出的 PG-GNN 扩展了 GraphSAGE 的思想,通过两层 LSTM 对节点邻域的每个随机排列进行编码,而不是传统的 sum/mean/min/max 。此外,作者设计了一种基于哈密顿圈的线性置换采样方法。

PG-GNN 排列敏感聚集思想。来源:黄等

你可能想看看其他一些有趣的作品:

  • 蔡和王研究不变图网络的收敛性质,与传统 MPNNs 的不同之处在于,它们对节点和边特征的操作如同对整体张量的等变操作。基于 graphon 理论,作者找到了一类可证明收敛的 ign。更多技术细节在牛逼的 Twitter 帖子
  • 高与里贝罗研究⏳时间 GNNs⏳设计两个系列:(1)——我们首先通过一些 GNN 嵌入图形快照,然后应用一些 RNN;(2) 先时间后图形其中,我们首先通过 RNN 对所有节点和边特征(在所有快照的统一图形上)进行编码,然后仅应用单个 GNN 过程,例如, TGNTGAT 可以被认为是该家族的实例。理论上,作者发现当使用像 GCN 或 GIN 这样的标准 1-WL GNN 编码器时,时间-图形时间-图形更有表现力,并提出了一个带有 GRU 时间编码器和 GCN 图形编码器的简单模型。该模型在时态节点分类和回归任务上表现出极具竞争力的性能,速度快 3-10 倍,GPU 内存效率高。有趣的是,作者发现无论是 时间和图形还是时间和图形 都不足以表达时间链接预测的🤔。**
  • 最后,“魏斯费勒-雷曼遇上-瓦瑟斯坦”作者【陈、林、梅莫利、万、王(5-第一作者联合论文👀)从 WL 核中导出一个多项式时间的 WL 距离,这样我们可以测量两个图的相异度——WL 距离为 0 当且仅当它们不能被 WL 测试区分,并且正的当且仅当它们可以被区分。作者进一步认识到,提出的 WL 距离与格罗莫夫-瓦瑟斯坦距离有着深刻的联系!

魏斯费勒-莱曼如何在实践中遇到格罗莫夫-沃瑟斯坦?本应在论文中由陈、老林、莫文蔚、万、王。来源:期限

光谱 GNNs

➡️光谱 GNNs 往往被忽视的空间 GNNs 的主流,但现在有一个理由让你看看光谱 GNNs 🧐.在王和张的《 谱图神经网络 有多强大》一文中,作者证明了在一些较弱的假设下,线性谱是图上任何函数的通用逼近子。更令人兴奋的是,根据经验,这些假设对于真实世界的图来说是正确的,这表明线性谱 GNN 对于节点分类任务来说足够强大。

但是我们如何解释光谱 GNNs 实验结果的差异呢?作者证明了谱 GNNs 的不同参数化(特别是多项式滤波器)影响收敛速度。我们知道 Hessian 矩阵的条件数(等损线有多圆)与收敛速度高度相关。基于这种直觉,作者提出了一些有利于优化的正交多项式。被命名为雅可比基的多项式是切比雪夫基中使用的切比雪夫基的推广。雅可比基由两个超参数定义, ab 。通过调整这些超参数,可以找到一组有利于输入图形信号的基。

实验上, JacobiConv 在嗜同性和嗜异性数据集上都表现良好,即使作为线性模型也是如此。或许是时候抛弃那些华而不实的 gnn 了,至少对于节点分类任务来说是这样😏。

➡️:还有两篇关于光谱 gnn 的论文。一个是基于光谱浓度分析的图高斯卷积网络 (G2CN),在嗜异性数据集上显示出良好的结果。另一篇来自 Yang 等人的文章分析了基于光谱平滑度的图形卷积中的相关性问题,显示了锌上的 0.0698 MAE 的非常好的结果。

可解释的 GNNs

由于大多数 GNN 模型都是黑箱,所以解释 GNNs 在关键领域的应用预测是很重要的。今年我们在这个方向有两篇很棒的论文,一篇是熊等人的高效而强大的事后模型,另一篇是苗等人的内在可解释模型。

熊等人扩展了他们之前的 GNN 解释方法 GNN-LRP ,使之更具可扩展性。与其他方法( GNNExplainerPGExplainerPGM-Explainer )不同的是, GNN-LRP 是一种考虑子图中节点联合贡献的高阶子图归属方法。对于子图不仅仅是一组节点的任务来说,这种性质是必要的。例如,在分子中,六个碳的子图(忽略氢)可以是苯(一个环)或己烷(一个链)。如下图所示,高阶方法可以计算出这样的子图(右图),而低阶方法(左图)则不能。

来源:熊等人

然而,GNN-LRP 算法的缺点是,它需要计算子图中每一次随机行走的梯度 w.r.t .对于一个子图 SL 跳随机行走需要 O(|S|L) 。这里动态编程来拯救😎。请注意,梯度 w.r.t. a 随机游走是乘法的(链式法则),不同的随机游走通过求和来聚合。这可以通过和积算法有效地计算出来。这个想法是利用乘法上的求和的分配性质(更普遍的是,半环),在每一步聚合部分随机游走。这就构成了模型, 子图 GNN-LRP (sGNN-LRP)

sGNN-LRP 还通过广义子图属性对 GNN-LRP 进行了改进,该属性考虑了子图 S 及其补图 G\S 中的随机游动。虽然看起来很复杂,但广义子图属性可以通过两次和积算法来计算。实验上, sGNN-LRP 不仅比所有现有的解释方法更好地发现属性,而且运行速度与常规消息传递 GNN 一样快。可能是解释和可视化的有用工具!🔨

💡顺便说一句,基于随机游走的模型比简单的节点或边模型更有表现力,这并不新鲜。NeurIPS 的 21 篇论文 NBFNet 用随机游走和动态规划解决知识图推理,在直推式和归纳式设置中都取得了惊人的结果。

➡️ 苗等从另一个角度研究内在可解释的 GNN 模型。他们表明,事后解释方法,如 GNNExplainer ,对于解释来说是不合格的,因为它们仅仅使用了一个固定的预训练 GNN 模型。相比之下,联合优化预测器和解释模块的内在可解释 GNN 是更好的解决方案。沿着这个思路,作者从图信息瓶颈( GIB )原理中推导出 图随机注意(GSAT)GSAT 对输入图进行编码,从后验分布中随机抽取一个子图(解释)。它基于采样的子图进行预测。作为一个优势, GSAT 不需要限制采样子图的大小。

来源:苗等人

实验上, GSAT 在解释和预测性能方面都比事后方法好得多。它也可以与预训练的 GNN 模型相结合。如果您正在为您的应用程序构建可解释的 gnn,GSAT 应该是一个不错的选择。

图形扩充:超越边缘丢失

今年带来了一些关于改进 gnn 的自我监督能力的工作,这些工作超越了像节点/边丢失这样的随机边索引扰动。

韩等人将 2017 年以来用于图像增强的混合的思想带到了带有g-mix的图中(ICML 2022 优秀论文奖🏅).混合的想法是拍摄两幅图像,将它们的特征混合在一起,并将它们的标签混合在一起(根据预定义的加权因子),并要求模型预测这个标签。这种混合提高了分类器的鲁棒性和泛化质量。

但是我们如何混合两个通常可能有不同数量的节点和边的图呢?

作者找到了优雅的答案——让我们不要混合图表,而是混合他们的图表——简而言之,就是图表生成器。来自同一个生成器的图具有相同的底层 graphon。因此算法变得相当简单(见下图)——对于一对图,我们 1️⃣估计它们的图;2️⃣通过加权求和将两个文法混合成一个新文法;3️⃣从新 graphon 和它的新标号中抽取一个图样本;4️⃣把这个送到分类器。在说明性示例中,我们有两个分别具有 2 个和 8 个连通分量的图,并且在混合它们的图之后,我们得到两个主要社区的新图,每个主要社区具有 4 个次要社区。估计图可以用一个阶跃函数和几种计算复杂度不同的方法来完成(作者大多求助于【最大间隙】)。

实验上, G-Mixup 稳定了模型训练,表现得比传统的节点/边扰动方法更好或相当,但是在具有标签噪声或许多添加/移除的边的鲁棒性场景中远远超过它们。一种众所周知的扩充方法对图形的冷静适应👏!如果你感兴趣,ICML 22 提供了一些关于混合的更一般的作品:一项关于混合如何改进校准的研究和如何在生成模型中使用它们的研究。

G-Mixup。来源:韩等

刘等人从另一个角度来看增强技术,特别是在节点的邻域很小的情况下。 局部增强 GNNs (LA-GNN) 的思想是训练一个生成模型,为每个节点产生一个附加的特征向量。生成模型是(在整个图形上)训练的条件 VAE,以预测以中心节点为条件的相连邻居的特征。也就是说,一旦 CVAE 被训练,我们只需传递每个节点的一个特征向量,并获得另一个特征向量,该特征向量应该比普通邻居捕获更多的信息。

然后,我们将每个节点的两个特征向量连接起来,并将其发送给任何下游的 GNN 和任务。注意,CVAE 是预先训练过的,不需要用 GNN 训练。有趣的是,CVAE 可以为看不见的图形生成特征,即,局部增强也可以用于归纳任务!最初的假设通过实验得到了证实——增强方法对于小角度的节点特别有效。

局部增强的想法。来源:刘等

下一步,于,王,王等人,处理 GNN 可扩展性任务,其中使用标准邻居采样器 a-la GraphSAGE 可能导致指数邻域大小扩展和陈旧的历史嵌入。作者提出了 GraphFM ,一种特征动量方法,其中历史节点嵌入通过动量步骤从它们的 1 跳邻居获得更新。通常,动量更新经常出现在 SSL 方法中,如用于更新目标网络的模型参数的 BYOLBGRL 。这里,GraphFM 使用动量来减轻不同小批量中历史再现的方差,并为不同大小的邻域提供特征更新的无偏估计。

一般来说,GraphFM 有两种选择graph FM-in batchgraph FM-out of batchT21。(1) GraphFM-InBatch 通过大幅减少必要邻居的数量来实现 GraphSAGE 风格的邻居采样,而 GraphSAGE 需要 10–20 个邻居,具体取决于级别,GraphFM 只需要每层每个节点 1 个随机邻居。唯一👌!(2) GraphFM Out-of-batch 构建在 GNNAutoScale 之上,我们首先应用图分割将图分割成 k 个小批。****

从实验上看,特征动量看起来对 SAGE 风格的采样(批量版本)特别有用——对于所有基于邻居采样的方法来说,这似乎是一个很好的默认选择!

GNNAutoScale (GAS) 相比,历史节点状态也根据新的嵌入和特征动量(移动平均)进行更新。来源:【于,王,王,等

最后,赵等人提出了一个巧妙的基于反事实链接的链接预测增强技巧。本质上,作者问:

"如果图形结构变得与观察不同,这种联系还会存在吗?"

这意味着我们想找到链接,在结构上类似于根据一些给定的链接💊处理(这里,那些是经典的度量标准,如 SBM 聚类、k-core 分解、Louvain 等等)但是给出了相反的结果。通过 CFLP ,作者假设训练 GNN 正确预测真实和反事实的联系有助于模型摆脱虚假的相关性,并只捕捉对推断两个节点之间的联系有意义的特征。

在获得一组反事实链路之后(基于所选的处理函数的预处理步骤) CFLP 首先在事实链路和反事实链路上被训练,然后链路预测解码器利用一些平衡和正则化项被微调。从某种意义上来说,这种方法类似于挖掘硬性否定来增加真实肯定联系的集合🤔实验上, CFLP 与 GNN 编码器配对大大优于单个 GNN 编码器在 Cora/Citeseer/Pubmed 上的结果,并且仍然在 OGB-DDI 链接预测任务的 top-3 中!

反事实链接(右)。来源:赵等人

算法推理和图形算法

🎆算法推理社区的一个巨大里程碑——CLRS 基准测试 的出现 (以一本经典教科书命名,由 Cormen、Leiserson、Rivest 和 Stein 编写,Velič ković等人编写!现在,没有必要发明玩具评估任务——CLRS 包含 30 种经典算法(排序、搜索、MST、最短路径、图形、动态规划等等),将一个 ICPC 数据生成器转换成一个 ML 数据集😎。

CLRS 中,每个数据集元素是一个轨迹,即输入、输出和中间步骤的集合。底层的表示格式是一组节点(通常不是一个图,因为边可能不是必需的),例如,对 5 个元素的列表进行排序被构造为对一组 5 个节点的操作。轨迹由探测器组成——格式元组(阶段、位置、类型、值),用其状态编码算法的当前执行步骤。输出解码器取决于预期的类型—在示例图中👇排序是用指针建模的。

分开来看,训练和验证轨迹具有 16 个节点(例如,长度为 16 的排序列表),但是测试集在具有 64 个节点的任务上探测模型的分布外(OOD)能力。有趣的是,普通 GNNs 和 MPNNs 非常适合训练数据,但在 OOD 设置中表现不佳,其中指针图网络显示更好的数字。这是 GNNs 无法推广到更大的推理图的观察集合的又一个数据点——如何解决这个问题仍然是一个开放的问题🤔。代码已经可用并且可以用更多的定制算法任务来扩展。

clr 中提示的表示。来源:veli kovi 等人

➡️从更理论的角度来看, Sanmartín 等人通过代数路径问题 (APP)概括了图度量的概念。APP 是一个更高级的框架(在范畴理论中有的一些根源),它通过半环的概念统一了许多现有的图形度量,如最短路径、通勤成本距离和极大极小距离,半环是具有特定运算符和属性的集合上的代数结构。例如,最短路径可以描述为一个半环,带有" min "和" + "带有中性元素的运算符" +inf "和" 0 "。

在这里,作者创建了一个单一的应用程序框架对数范数距离,允许仅使用两个参数在最短路径、通勤成本和 minimax 之间进行插值。本质上,您可以改变和混合边权重和周围图结构(其他路径)对最终距离的影响。虽然没有实验,但这是一个坚实的理论贡献——如果你在“吃你的蔬菜”时学习范畴理论🥦,这篇论文非常值得一读——并且肯定会在 GNNs 中找到应用。👏

对数范数距离。来源:桑马丁等人

➡️:最后,我们将在这一类别中添加一部作品https://arxiv.org/pdf/2206.08119.pdf*,作者是罗西等人,他们将图论与博弈论结合在一起。博弈论在经济学和其他多学科研究中被大量使用,你可能听说过定义非合作博弈解决方案的纳什均衡。在这项工作中,作者考虑了 3 种游戏类型:线性二次型线性影响巴里克-奥诺里奥图形游戏。游戏通常是通过他们的效用函数来定义的,但是在这篇文章中,我们假设我们对游戏的效用函数一无所知。*

游戏被定义为采取特定行动的 n 个玩家(图中的节点)(为了简单起见,假设我们可以用某个数字特征来描述它,查看🖼️).下面的插图行动可以影响邻近的玩家——这个任务的框架是根据玩家的行动推断他们的图形。本质上,这是一个图生成任务——给定节点特征 X,预测 a(归一化)邻接矩阵 a,通常一个游戏玩 K 次,那些是独立游戏,所以编码器模型应该对游戏的排列不变(对每个游戏中节点的排列等变)。作者提出了金块🍗编码器-解码器模型,其中变换器编码器通过 N 个玩家处理 K 个游戏,产生潜在的表示,并且解码器是潜在的成对玩家特征的哈达玛乘积之和上的 MLP,使得解码器对于 K 个游戏的顺序是置换不变的。

实验表明,该模型在合成数据集和真实数据集上都运行良好。这篇论文绝对是“开阔你的眼界”🔭你可能没想到会在 ICML 看到这些作品,但后来会发现这是一种引人入胜的阅读,并学到了许多新概念👏。

来源:罗西等人

知识图推理

知识图推理一直是 GraphML 方法的乐园。在今年的《ICML》上,有不少关于这个话题的有趣论文。作为今年的一个趋势,我们看到从嵌入方法( TransEComplExRotatEHAKE )到 GNNs 和逻辑规则(其实 GNNs 也是和逻辑规则相关)的一个显著漂移。有四篇论文基于 GNNs 或逻辑规则,两篇论文扩展了传统的嵌入方法。

先从颜等人提出的 循环基 GNN (CBGNN) 说起。作者在逻辑规则和循环之间画了一个有趣的联系。对于任何一个链式逻辑规则,逻辑规则的头和体在知识图中总是形成一个循环。例如,下图的右图显示了(X, part of Y) ∧ (X, lives in, Z) → (Y, located in Z)的周期。换句话说,逻辑规则的推理可以被视为预测循环的合理性,这归结为学习循环的表示。

蓝色和红色三角形是更大的绿色循环中的循环。来源:颜等人

一个有趣的观察是,循环在模 2 加法和乘法下形成一个线性空间。在上面的例子中,红色❤️和蓝色的总和💙自行车,抵消了他们的共同优势,导致绿色💚循环。因此,我们不需要学习所有圈的表示,而是只需要学习线性空间的几个圈基。作者通过挑选与最短路径树有很大重叠的环来生成环基。为了学习循环的表示,他们创建了一个循环图,其中每个节点都是原始图中的一个循环,每个边都表示两个循环之间的重叠。应用 GNN 来学习循环图中的节点(原始图的循环)表示。

CBGNN 编码。来源:严等

为了将 CBGNN 应用于归纳关系预测,作者通过用 LSTM 对循环中的关系进行编码来为每个循环构建归纳输入表示。实验上,CBGNN 在 FB15k-237/WN18RR/NELL-995 的感应版本上实现了 SotA 结果。

接下来, Das 和 godbole 等人提出了用于 KBQA 的基于案例推理(CBR)方法 CBR-SUBG 。核心思想是在解决查询时从训练集中检索相似的查询-答案对。我们知道检索的想法在 OpenQA 任务中很流行( EMDRRAGKELM提内存 LMs ),但这是第一次看到这样的想法在图上被采用。

给定一个自然语言查询,CBR 首先基于由预先训练的语言模型编码的查询表示检索相似的 k-最近邻(kNN)查询。所有检索到的查询都来自训练集,因此它们的答案是可访问的。然后,我们为每个查询-答案对生成一个局部子图,它被认为是答案的推理模式(尽管不一定是精确的)。当前查询的局部子图(我们无法访问其答案)是通过遵循其 kNN 查询的子图中的关系路径来生成的。 CBR-SUBG 然后对每个子图应用 GNN,并通过将节点表示与 KNN 查询中的答案进行比较来预测答案。

基于案例的推理直觉。来源: Das 和 Godbole 等人

➡️今年有两种神经符号推理方法。第一个是 层次规则归纳(HRI) 出自 Glanois 等人。HRI 扩展了以前的一个工作,逻辑规则归纳(LRI) 关于归纳逻辑编程。规则归纳的想法是学习一堆规则,并应用它们来推断事实,如正向链接

LRIHRI 中,每个事实P(s,o)都由一个嵌入 𝜃p 的谓词和一个赋值vp(即事实为真的概率)来表示。每个规则P(X,Y) ← P1(X,Z) ∧ P2(Z,Y)都由其谓词的嵌入来表示。目标是迭代地应用规则来推导新的事实。在每次迭代过程中,通过软统一来匹配规则和事实,软统一衡量两个事实是否满足嵌入空间中的某些规则。一旦选择了一个规则,就会生成一个新的事实并将其添加到事实集中。所有嵌入和软统一操作被端到端地训练,以最大化观察到的事实的可能性。

HRI 模型在三个方面比 LRI 模型有所改进:1)使用分层的先验知识,将每个迭代步骤中使用的规则分开。2)使用 gumbel-softmax 来归纳用于软统一的稀疏且可解释的解决方案。3)证明 HRI 能够表达的逻辑规则集。

分层规则归纳。来源: Glanois 等人

第二篇是朱等人的 GNN-QE 论文(免责声明:本文作者的论文)。GNN-QE 用广义神经网络和模糊集解决知识图上复杂的逻辑查询。它兼具神经方法(例如强大的性能)和符号方法(例如可解释性)的优点。因为在 GNN-QE 有很多有趣的东西,我们很快会有一个单独的博客帖子。敬请期待!🤗

最后, Kamigaito 和 Hayashi 研究了负抽样在知识图嵌入中的理论和实证效果。从旋转开始,知识图嵌入方法使用一个归一化的负采样损失,加上一个边际二进制交叉熵损失。这不同于原来 word2vec 中使用的负采样。在本文中,作者证明了基于距离的模型(transRotatE )要达到最优解,归一化负采样损失是必要的。边距在基于距离的模型中也起着重要的作用。只有当 𝛾 ≥ log|V| 时,才能达到最优解,这与经验结果一致。基于这个结论,现在我们可以确定最佳的保证金没有超参数调整!😄

计算生物学:分子连接,蛋白质结合,性质预测

总的来说,comp bio 在 ICML 表现很好。在这里,我们将看看分子连接蛋白质结合、构象异构体生成和分子性质预测的新方法。

分子连接**是设计蛋白水解靶向嵌合体(PROTAC) 药物的关键部分。对我们来说,仅仅是 GNN 的研究者🤓在没有生物学背景的情况下,这意味着给定两个分子,我们想要生成一个有效的接头分子,它将两个片段分子连接在一个分子中,同时保留原始片段分子的所有属性(查看下面的插图以获得一个很好的示例)**

为了生成分子链,黄等人创造了 3DLinker ,这是一个 e(3)-等变生成模型(VAE),它以绝对坐标顺序生成原子(和连接键)。通常,等变模型会生成相对坐标或相对距离矩阵,但在这里,作者旨在生成绝对 (x,y,z) 坐标。为了允许模型从等变(到坐标)和不变(到节点特征)变换中生成精确的坐标,作者应用了一个巧妙的向量神经元的想法,它本质上是一个类似 ReLU 的非线性,通过巧妙的正交投影技巧来保持特征等变。

富含向量神经元的 e(3)-等变编码器对特征和坐标进行编码,而解码器以 3 个步骤顺序地生成链接(也在下面示出):1️⃣预测链接将被附加到的锚节点;2️⃣预测链接器节点节点类型;3️⃣预测边缘及其绝对坐标;4️⃣重复,直到我们在第二个片段中到达停止节点。 3DLinker 是(到目前为止)第一个生成具有精确 3D 坐标的连接分子并预测片段分子中锚点的等变模型——以前的模型在生成之前需要已知锚点——并显示最佳实验结果。

3d 链接器直觉。来源:黄等

➡️ 蛋白质-配体结合是另一项至关重要的药物发现任务——预测一个小分子可能在哪里附着到一个更大蛋白质的某个区域。先是,史塔克,加内亚等人创作 对等 (ICML 聚焦💡)以蛋白质和配体图的随机 RDKit 构象作为输入,并输出结合相互作用的精确 3D 位置。EquiBind 已经在麻省理工学院新闻阅读小组中获得了非常热烈的欢迎和宣传,因此我们鼓励您详细了解技术细节! EquiBind 比商业软件快几个数量级,同时保持较高的预测精度。

EquiBind。资料来源:斯特尔克、加内亚等人

如果结合分子是未知的,并且我们想要生成这样的分子,刘等人创建了 GraphBP ,这是一种自回归分子生成方法,其将目标蛋白质位点(表示为初始上下文)作为输入。使用任何 3D GNN 对上下文进行编码(此处为 SchNet ,GraphBP 生成原子类型和球坐标,直到不再有接触原子可用或达到所需的原子数量。一旦原子生成,作者就求助于开放巴别塔来创造化学键。

用 GraphBP 生成结合分子。来源:刘等

分子性质预测中,** 于和高提出了一个简单而惊人强大的想法,用一包基序来丰富分子表征。也就是说,他们首先在训练数据集中挖掘出一个模体词汇表,并根据 TF-IDF 分数对它们进行排序(你好,来自 NLP😉).然后,每个分子可以被表示为一个模体包(多热编码),并且整个分子数据集被转换为一个具有关系“模体-分子”(如果任何分子包含该模体)和“模体-模体”(如果任何两个模体在任何分子中共享一条边)的异质图。边缘特征是之前挖掘的那些 TF-IDF 得分。**

分子的最终嵌入是通过分子上的任何香草 GNN 和来自基序图的采样子图上的另一个异质 GNN 的串联获得的。这样一个 异构基元 GNN (HM-GNN) 始终优于图子结构网络(GSN) ,这是最早提出在社交网络中计算三角形和在分子中计算 k-循环的 GNN 架构之一,甚至优于细胞同构网络(CIN) ,这是一个顶级的高阶消息传递模型。HM-GNNs 可以作为高阶 GNNs 领域的后续研究的简单有力的基线💪。

在 HM-GNN 建立主题词汇。来源:于、高

➡️最后,strk 等人的一项工作展示了使用 3D Infomax 方法对 2D 分子图及其 3D 构象图进行预训练的好处。 3D Infomax 的想法是最大化 2D 和 3D 表示之间的互信息,使得在 2D 图上的推断时间,当没有给出 3D 结构时,模型仍然可以受益于 3D 结构的隐含知识。

为此,2D 分子用主邻域聚集(PNA) 网编码,3D 构象异构体用球形信息传递(SMP) 网编码,我们取它们表示的余弦相似性,并通过对比损失使一个分子与其真实 3D 构象异构体的相似性最大化,并将其他样品视为阴性。有了预训练的 2D 和 3D 网络,我们可以在下游任务中微调 2D 网络的权重——在这种情况下是 QM9 属性预测——结果明确显示预训练有效。顺便说一句,如果你对预训练进一步感兴趣,可以看看 ICLR 2022 上发布的 GraphMVP 作为另一种 2D/3D 预训练方法。

在 3D Informax 中,我们首先预训练 2D 和 3D 网络,并在推理时使用经过训练的 2D 网络。资料来源:strk 等人

酷图应用

GNNs 极大地推动了物理模拟和分子动力学的发展。物理模拟的标准设置是一个粒子系统,其中节点特征是几个最近的速度,边缘特征是相对位移,任务是预测粒子在下一个时间步移动到哪里。

⚛️今年, Rubanova,Sanchez-Gonzalez 等人通过在 C-GNS (基于约束的图网络模拟器)中加入明确的标量约束,进一步改进了物理模拟。从概念上讲,MPNN 编码器的输出通过解算器进一步细化,该解算器最小化一些学习到的(或在推理时指定的)约束。求解器本身是一个可微分函数(在这种情况下是 5 次迭代梯度下降),因此我们也可以通过求解器进行反向投影。C-GNS 与深层隐含层有着内在的联系,这些深层隐含层的可见性越来越强,包括GNN 应用

物理模拟作品通常是花哨的模拟可视化的来源——查看带有视频演示的网站

基于约束的图形网络模拟器。来源:鲁巴诺瓦、桑切斯-冈萨雷斯等人

您可能想看看其他一些很酷的应用程序:

  • 交通预测 : 兰、马等创建了【DSTA-GNN】(动态时空感知图神经网络)用于交通预测🚥在繁忙的加州道路的真实世界数据集上进行评估——去年,在谷歌和 DeepMind 对改进谷歌地图 ETA 进行大量工作后,用图表预测交通得到了推动,我们在 2021 年的结果中报道了这些工作。
  • 神经网络剪枝 : 于等设计【GNN-RL】在给定期望的 FLOPs 缩减率的情况下,迭代地剪枝深度神经网络的权重。为此,作者将神经网络的计算图视为块的分层图,并将其发送到分层 GNN(通过中间可学习池来粗粒度化 NN 架构)。编码的表示被发送到 RL 代理,该代理决定删除哪个块。
  • 排名 : 何等人处理一个有趣的任务——给定一个两两互动的矩阵,例如,在足球联赛中的球队之间,其中 Aij > 0 表示球队 i 比球队 j 得分更高,找出得分最高的节点(球队)的最终排名。换句话说,我们希望在看到所有比赛的配对结果后,预测谁是联赛的冠军。作者提出 GNNRank 将成对结果表示为有向图,并应用有向 GNN 来获得潜在节点状态,并计算图拉普拉斯的费德勒向量。然后,他们将该任务设计为一个约束优化问题,具有近似梯度步骤,因为我们无法通过费德勒向量的计算轻松地反向推进。**

这就是 ICML 2022 的最终目标!😅

期待看到 NeurIPS 2022 论文以及全新 图学(LoG) 会议的投稿!

使用 Python 的图机器学习第 3 部分:无监督学习

原文:https://towardsdatascience.com/graph-machine-learning-with-python-part-3-unsupervised-learning-aa2854fe0ff2

大都会艺术博物馆中绘画的聚类和嵌入

大都会艺术博物馆的绘画网络。作者图片

在第 1 部分中,我介绍了我们如何从图中推理,为什么它们如此有用,用于分析和浓缩大量信息的度量标准,等等。

在第 2 部分中,我查看了 CryptoPunks 交易网络,介绍了更高级别的图形推理——随机世界和扩散模型。

然后我稍微离题讨论了我们如何使用网络和图表分析来看待 NBA 比赛。这一部分将使用那个故事中介绍的概念来进一步分析图形机器学习。

https://animadurkar.medium.com/network-analysis-of-nba-playoffs-via-flow-dynamics-e5d5de70d4af

我强烈建议在深入研究这一部分之前先回顾一下前面的部分,因为它们为这一部分做了很好的准备,我在这里不深入研究的许多概念已经在每一部分中讨论和展示了。

在这个故事中,我将分析一个不同于我以前故事中看到的数据集。我会看一看被归类为绘画的大都会艺术博物馆的艺术品。这个数据集可以在 Github 上找到:https://github.com/metmuseum/openaccess

来自他们的 GitHub 数据集:

大都会艺术博物馆展示了来自世界各地超过 5000 年的艺术,供每个人体验和欣赏。该博物馆位于纽约市的两个标志性建筑——大都会第五大道和大都会修道院。数百万人也在线参加了大都会博物馆的体验活动。

自 1870 年成立以来,大都会博物馆一直渴望不仅仅是一个珍奇美丽物品的宝库。每一天,艺术都在博物馆的画廊里,通过展览和活动变得生动起来,揭示了新的思想和跨时间、跨文化的意想不到的联系。

大都会艺术博物馆为其收藏的超过 470,000 件艺术品提供精选的数据集,用于无限制的商业和非商业用途。在法律允许的范围内,大都会艺术博物馆已经放弃使用 Creative Commons Zero 对该数据集的所有版权和相关或邻接权。该作品发表于:美利坚合众国。你也可以在这个资源库的许可文件中找到 CC Zero 契约的文本。这些精选的数据集现在可以在任何媒体上免费使用;它们还包括受版权保护的艺术品的识别数据。数据集支持对博物馆藏品的搜索、使用和交互。

目录

  1. 简介和网络拓扑
  2. 图的无监督嵌入
  3. 节点表示学习(Node2Vec)
  4. 边的表示学习(Edge2Vec)
  5. 图的表示学习(Graph2Vec)
  6. 摘要

简介和网络拓扑

在任何类型的数据项目之前,从一些探索性的数据分析开始总是好的。除此之外,通过可视化网络拓扑,我们可以很好地了解我们正在处理的数据类型。

作者图片

数据似乎有相当多的空值,而且 450,000 行数据在图形中编码和操作(在我的本地机器上)需要很长时间。为了简单一点,我只筛选出“画”这一类的作品。

Prints                                  69260
Prints|Ephemera                         30033
Photographs                             26821
Drawings                                25230
Books                                   14685
Ceramics                                13332
Paintings                               11038
Textiles-Woven                          10995
Photographs|Ephemera                    10940
Glass                                    8838
Negatives                                6460
Vases                                    5050
Textiles-Laces                           4966
Prints|Ornament & Architecture           4554
Sculpture                                4487
Ceramics-Porcelain                       4104
Textiles-Embroidered                     4093
Metalwork-Silver                         3969
Drawings|Ornament & Architecture         3910
Books|Prints|Ornament & Architecture     3583
Name: Classification, dtype: int64

为了处理未知数,如果一个字段丢失了,那么我们将使用“unknown_{column_name}”来估算 NaNs,这可能是非常有趣的。再做一点清理,我们就可以选择一些字段,这些字段为我们的图表填充了大量的值。

作者图片

Top 10 for Culture
Culture
unknown_Culture                 6591
China                           2059
Japan                           1173
India (Gujarat)                  200
American                         107
Tibet                             81
Nepal (Kathmandu Valley)          65
India (Bengal) or Bangladesh      63
Korea                             52
India                             32
dtype: int64

Top 10 for Period
Period
unknown_Period                                  8599
Edo period (1615–1868)                           701
Qing dynasty (1644–1911)                         466
Ming dynasty (1368–1644)                         212
Meiji period (1868–1912)                         151
Muromachi period (1392–1573)                      90
Pala period                                       89
Ming (1368–1644) or Qing dynasty (1644–1911)      86
Ming (1368–1644) or Qing (1644–1911) dynasty      78
Yuan dynasty (1271–1368)                          54
dtype: int64

Top 10 for Artist Display Name
Artist Display Name
unknown_Artist Display Name       1104
Unidentified Artist                373
Xie Zhiliu                         344
John Singer Sargent                115
Fu Baoshi                          101
Marsden Hartley                     87
Shibata Zeshin                      74
Kerry James Marshall                72
Bhadrabahu                          71
Élisabeth Louise Vigée Le Brun      69
dtype: int64

Top 10 for Medium
Medium
Oil on canvas                                3592
Watercolor on ivory                           632
Oil on wood                                   576
Hanging scroll; ink and color on paper        434
Hanging scroll; ink and color on silk         374
Hanging scroll; ink on paper                  249
Ink, opaque watercolor, and gold on paper     226
Tempera on wood, gold ground                  155
Album leaf; ink and color on silk             136
Ink and opaque watercolor on paper            129
dtype: int64

Top 10 for Object Name
Object Name
Painting                                5808
Hanging scroll                          1362
Painting, miniature                      693
unknown_Object Name                      641
Folio                                    462
Handscroll                               297
Drawing                                  283
Album leaf                               278
Folding fan mounted as an album leaf     172
Album                                    104
dtype: int64

正如所料,我们可以看到有很多值是未知的或者很难准确计算出来的。此外,我们还看到了奇怪的分类碎片(例如“明朝(1368–1644)”、“清朝(1644–1911)”、“明朝(1368–1644)或清朝(1644–1911)”、明朝(1368–1644)或清朝(1644–1911)朝代”)。没有领域专家,可能很难知道为什么或如何发生这种情况,以及值是否应该被组合、删除、重新标记或保持不变,所以现在我将把它们留在这里。这些也只是在这几个类别的前 10 个值中看到的,所以人们只能想象这些类别在更低的级别上变得多么支离破碎,更难辨别。

在我们的图表中,我们需要转换这些列来创建 From 和 to 格式。有几种不同的方法可以做到这一点,数据的上下文可以决定处理这一点的最佳途径。我们将创建一个类似如下的无向图:

作者图片

作者图片

虽然这仍然是一个很大的图,但是让我们来看看拓扑是什么。

Graph Summary:
Number of nodes : 12688
Number of edges : 66693
Maximum degree : 9092
Minimum degree : 2
Average degree : 10.512767969735183
Median degree : 6.0

Graph Connectivity
Connected Components : 1

Graph Distance
Average Distance : 2.500517379796479
Diameter : 6

Graph Clustering
Transitivity : 0.0015246604242919772
Average Clustering Coefficient : 0.5194453022433385

相当低的传递性是有意义的,因为这不是一个社会图,没有理由相信三元闭包会在这里成立。除此之外,只有 1 个连通分量是一个有趣的度量,因为我们不应该有很多只连通而没有其他的子图。节点和边的数量表明有大量的小众类别、艺术家、风格等。在图表中创造了进一步的分割。

如果我能接触到领域专家,我可能会通过一个广泛的练习来清理类别,因为它们中的一些可能会有潜在的重叠,但现在,我们将继续。

作者图片

该图的节点颜色由度中心性编码,边颜色由 Jaccard 相似性编码(我将在本系列的监督学习部分讨论链接预测时讨论链接度量)。有趣的是,在这个图中有一些节点完全支配着其他节点。当我们按流中心性排序时(中间中心性的一种变体,用于度量进入过程之间的实体),我们发现许多“未知”或 NaN 字段占主导地位。

作者图片

对中心性度量的进一步分析也证实了有少数节点强烈地扭曲了分布。一种解决方案是简单地删除具有任何这些 nan 的行,但是某些数据点丢失的事实对于在低维空间中嵌入该节点可能是非常重要的信息。

作者图片

图的无监督嵌入

图的无监督机器学习主要可以分为以下几类:矩阵分解、跳跃图、自动编码器和图神经网络。图形机器学习(Claudio Stamile,Aldo Marzullo,Enrico Deusebio)有一个奇妙的图像,概述了这些和每个下面的算法:

本书中描述的不同无监督嵌入算法的层次结构。图形机器学习(Claudio Stamile,Aldo Marzullo,Enrico Deusebio),O'Reilly

尽管我将简要介绍嵌入及其工作原理,但我不会在本文中介绍自动编码器和图形神经网络。自动编码器和 gnn 应该有自己的故事(提示提示),所以我将只关注我发现性能最好的主要无监督算法——跳格算法。

与大多数结构化数据不同,图是在非欧几里得空间中定义的。具有讽刺意味的是,它们没有空间成分;一个节点的相关性仅在于它是否与其他节点相连,而与该节点在图中的位置或方向无关。由于这个原因,我们经常把一个图简化成一个结构化的数据问题来简化它。我们通过创建图的邻接矩阵并学习矩阵中成对关系的嵌入来做到这一点。这些学习到的表示允许我们在节点、边和图形之间的潜在关系中发现隐藏的和复杂的新模式。

邻接矩阵看起来像这样:

无向标号图及其邻接矩阵。维基百科

每行和每列代表每个节点,数字代表节点之间的链接数量。该邻接矩阵可以被学习为用于降维、聚类和进一步的下游预测任务的嵌入。这里的目标是对节点进行编码,使得嵌入空间中的相似性近似于图中的相似性。

每种矩阵分解方法都使用这种分解技术来创建节点和边缘级数据的嵌入。根据谷歌的说法,“嵌入是一个相对低维的空间,你可以将高维向量转换到其中。嵌入使得在大量输入上进行机器学习变得更加容易,比如表示单词的稀疏向量。理想情况下,嵌入通过在嵌入空间中将语义相似的输入放在一起来捕获输入的一些语义。嵌入可以被学习并跨模型重用。”

在浅层方法中,通过具有以下步骤的表示学习来学习节点嵌入:

  1. 编码器将节点映射到嵌入
  2. 定义节点相似度函数
  3. 解码器将嵌入映射到相似性得分
  4. 优化编码器的参数,使得解码的相似性尽可能接近地匹配基础网络相似性

Skip-gram 模型使用各种随机行走来优化相似性度量的嵌入。这些模型不使用标签或显式特征来估计节点的一组坐标,以便捕捉网络结构的某些方面。对于节点通过边连接的图,随机漫步有两个明显的好处:

  1. 表现性:一种灵活的获取局部和全局节点邻域信息的方法。这源于这样的想法:如果从节点 u 开始的随机行走以高概率行进到节点 v,那么它们是相似的。
  2. 效率:我们不想考虑网络中的每一条路径,因为这将很快变得难以计算。这种方法只考虑随机漫步中同时出现的配对。

生成随机行走路径后,我们现在有了序列数据,可以像处理文本一样生成嵌入。这就是跳格模型,特别是 Word2Vec,出现的原因。Skip-gram 模型通常被称为 Word2Vector,因为它是一个简单的神经网络,具有一个隐藏层叛逆者来预测当输入单词存在时给定单词存在的概率。它基于输入语料库建立训练数据,然后被训练来预测单词成为给定目标的上下文单词的概率。下图显示了第一步训练是如何进行的。

从给定语料库生成训练数据的示例。在填充的框中,目标单词。在虚线框中,由长度为 2 的窗口大小标识的上下文单词。图形机器学习(克劳迪奥·斯塔米尔,奥尔多·马尔祖洛,恩里科·德乌塞比奥),奥莱利

然后,简单的神经网络根据该数据进行训练,以基于每个单词在训练语料库中的位置来生成每个单词的概率。这将输出一个嵌入,在一个低得多的维度空间中表示该单词。

跳跃图模型的神经网络结构。隐藏层中 d 个神经元的数目代表了嵌入空间的最终大小。图形机器学习(Claudio Stamile,Aldo Marzullo,Enrico Deusebio),O'Reilly

对于图中的 skip-gram 模型,此图展示了随机游走如何连接到 skip-gram,然后生成嵌入的示例:

DeepWalk 算法用来生成给定图的节点嵌入的所有步骤。图形机器学习(Claudio Stamile,Aldo Marzullo,Enrico Deusebio),O'Reilly

深度遍历跳过程序算法是这样的:

  1. 从图上的每个节点开始,进行短距离固定长度(不一定都是相同长度)的随机行走。
  2. 对于每个节点 u,收集在从 u 开始的随机行走中访问的节点的多重集,并在其上训练 skip-gram 模型。当给定图作为跳格模型的输入时,图可以被视为输入文本语料库,而图的单个节点可以被视为语料库的单词。随机漫步可以被看作是一个单词序列(一个句子)。在这一步中使用了跳格模型的参数(窗口大小, w ,以及嵌入大小, d )。
  3. 使用随机梯度下降优化嵌入。给定节点 u ,我们想要预测它的邻居 N(u)。【Jure Lescovec 博士的图形机器学习课程中生动地描述了这里正在优化的损失函数:

Jure Lescovec,斯坦福, CS224W:带图的机器学习

该模型的常见参数有:

  • walk_number:为每个节点生成的随机行走的次数
  • walk_length:生成的随机漫步的长度
  • window_size:跳格模型的窗口大小参数

虽然我相信这足够让这个故事继续下去了,但这里还有很多内容要讲。矩阵分解方法、负采样(以有效地近似损失函数最优化)等。仅举几个例子。如果您想深入了解,我强烈推荐这些资源:

图机器学习第三章:无监督学习

斯坦福 CS224W:带图的机器学习

节点表示学习(Node2Vec)

Node2Vec 是深度遍历模型的一种变体,在随机遍历的生成方式上有显著的不同。深度遍历在保存节点的局部邻域信息方面存在局限性,因此 Node2Vec 采用了宽度优先搜索(BFS)和深度优先搜索(DFS)的灵活而强大的组合来进行图探索。这两种算法的组合通过以下方式进行调整:

  1. p :随机游走回到前一个节点的概率
  2. q :随机漫步可以通过图中以前看不见的部分的概率。BFS 与 DFS 的比率。

该模型引入了有偏行走,可以在网络的局部微观(BFS)和全局宏观(DFS)视图之间进行权衡。

Node2Vec 算法是这样的:

  1. 计算随机行走概率
  2. 模拟从每个节点 u 开始的 r 长度 l 的随机行走
  3. 使用随机梯度下降优化模型的目标

该模型的常见参数有:

  • num_walks:为每个节点生成的随机行走的次数
  • walk_length:生成的随机漫步的长度
  • p,q:随机游走生成算法的参数 pq

让我们用 2 维来绘制节点嵌入,并找到与文森特·梵高相似的艺术家,他是个人的最爱。

作者图片

#Artists similar to Vincent van Gogh
Adrien Dauzats
Anne Louis Girodet-Trioson
Eugène Isabey

上面的代码仅假设二维空间足以捕捉低维空间中的每个节点。通常,这在大型复杂的图表中是不够的,但是随着维度的增加,它可能很难可视化。另一点要注意的是,当模型评估相似性时,它仅基于节点中的信息(时期、文化、介质等)。),所以艺术家相似性将仅与图中的节点邻近度/相似性相关。这与使用计算机视觉来分析艺术品的像素值以找到相似的图像截然不同。

尽管梵高是一位荷兰艺术家,但众所周知,他在法国找到了自己的标志性风格,并最终在法国去世。这三位艺术家都是法国人,但他们的主要风格是浪漫主义,与梵高的后印象派风格形成鲜明对比。

让我们添加更多的维度来让模型学习我们的图表的更好的表示。

#Artists similar to Vincent van Gogh
Paul Cézanne
Goya (Francisco de Goya y Lucientes)
Georges Rouault
Alfred Sisley
Georges Seurat
Claude Monet
Gustave Courbet
Edward McKnight Kauffer

这样其实好多了!这些艺术家在时代、文化和风格上更相似。请注意,我们还在图表中添加了媒介、部门和对象类型,因此可能这些艺术家中的一些人可能在该时期有所不同,但使用了与梵高相同的材料,或者出现在博物馆的同一部门。

以下是文森特·梵高和保罗·塞尚的作品供参考:

L'Arlésienne:约瑟夫-米歇尔·吉诺夫人(玛丽·朱利安,1848–1911),文森特·梵高。大都会艺术博物馆(公共领域)

打牌的人,1890-1900,保罗·塞尚。大都会艺术博物馆(公共领域)

边的表示学习(Edge2Vec)

Edge2Vec 是 Node2Vec 相对简单的扩展,它使用两个相邻节点的节点嵌入来执行一些基本的数学运算,以便提取连接它们的边的嵌入。以下是图形机器学习(Claudio Stamile,Aldo Marzullo,Enrico Deusebio)中阐述的主要问题:

Node2Vec 库中的边嵌入操作符及其方程和类名。图形机器学习(Claudio Stamile,Aldo Marzullo,Enrico Deusebio),O'Reilly

根据数据的性质以及数据之间的关系,不同的嵌入会有不同的价值。一种有效的评估方法是尝试每一种方法,看看哪一种方法具有最合理的边缘分离。

虽然我们不能一下子看到所有的维度,但你可以通过下面的方法看到梵高和他的相似作品与艺术家之间边缘嵌入的前两个维度。

作者图片

图的表示学习(Graph2Vec)

这是节点和边表示学习的最高概括。在自然语言处理中,这种模型被称为 Doc2Vec,因为它是多个文档的嵌入,而不是单词或句子。当涉及到图时,我们可以将其划分为子图,然后训练模型来学习这些子图中每一个的表示作为嵌入。

Doc2Vec 模型的功能与 Node2Vec 相关,如下图所示:

Doc2Vec 跳跃图模型的简化图形表示。隐藏层中 d 个神经元的数目代表了嵌入空间的最终大小。图形机器学习(Claudio Stamile,Aldo Marzullo,Enrico Deusebio),O'Reilly

这个算法是这样的:

  1. 围绕每个节点生成一组有根子图。
  2. 使用生成的子图训练 Doc2Vec 跳转图。
  3. 使用包含在经训练的 Doc2Vec 模型的隐藏层中的信息,以便提取每个节点的嵌入。通过随机梯度下降进行优化。

生成子图的方式可以变化,并显著改变模型学习精确表示的能力。基本上,有三种不同的方法可以创建子图:

方法 1:嵌入节点并聚合它们(最常见的是求和或平均)

方法 2:创建一个节点(超级节点),它代表并跨越每个子图,然后嵌入该节点

方法 3:匿名行走嵌入。捕获与随机漫步中第一次访问节点的索引相对应的状态。被认为是匿名的,因为这种方法不知道被访问节点的身份。

Jure Lescovec,斯坦福, CS224W:带图的机器学习

使用方法 3,随着匿名遍历的数量呈指数级增长,您很容易遇到所需计算资源的问题。由于这种计算复杂性,我们可以:

  • 对匿名遍历进行采样,然后将图形表示为每次匿名遍历发生次数的一部分
  • 嵌入匿名遍历,连接它们的嵌入得到一个图嵌入。本质上,嵌入行走,以便可以预测下一次行走。

整个目标是将图形表示为这些行走的概率分布。

对于我们的例子,我们可以创建仅包含 Vincent van Gogh 和与他相似的艺术家的行的子图。我们可以使用嵌入以一种更加简洁和有效的方式来表示他们所有的信息。请注意,我们需要将节点标签转换为整数,以使模型更加合适,出于示例的原因,我们将只做二维处理。

作者图片

摘要

这个故事旨在说明即使在相对不干净、不完整和最少的数据上,表征学习的力量。在没有目标标签或基础真值的情况下,我们可以使用图表来真正有效地找到潜在的结构相似性。显然,像任何机器学习项目一样,在这个过程中,我们做了很多假设和警告,但图表给了我们一个额外的维度来分析我们的数据。

我们的模型可以[潜在地]变得更好的一些重要方式:

  • 将数据帧中的行表示为不同的节点和边
  • 在领域专家的监督下清理无关和不完整的值
  • 添加更多维度,将艺术家与其作品和其他艺术家联系起来

这是一篇很长的文章,但是谢谢你坚持下来!在本系列的下一部分,我们将讨论监督学习。跟着一起玩吧!

参考

[1] Claudio Stamile,Aldo Marzullo,Enrico Deusebio,图机器学习

[2] Jure Leskovec,斯坦福, CS224W:带图的机器学习

[3]伊斯利,大卫和克莱因伯格,乔恩。2010.网络、人群和市场:关于高度互联世界的推理

[4] 大都会艺术博物馆开放存取

您可以在这里找到本系列的第 4 部分:

基于 Python 的图机器学习第 4 部分:监督和半监督学习

原文:https://towardsdatascience.com/graph-machine-learning-with-python-part-4-supervised-semi-supervised-learning-d66878161b79

大都会艺术博物馆绘画的分类和预测

大都会艺术博物馆的绘画网络。作者图片

介绍

这个故事将探索我们如何通过监督和半监督学习,使用标签从图形中推理和建模。我将使用 MET Art Collections 数据集,它将建立在我以前关于度量、无监督学习等部分的基础上。在这篇文章之前,请务必查看之前的文章,以便跟上一些片段,因为我不会在这篇文章中再次涵盖所有概念:

目录

  1. 基于特征的方法
  2. 嵌入方法
  3. 集体分类
  4. 摘要

基于特征的方法

进行监督学习的最简单方法是使用图测量作为新数据集中的要素,或者作为现有数据集中的附加要素。我已经看到这种方法对建模任务产生了积极的结果,但是它可能真的依赖于 1。你如何以图表的形式建模(输入、输出、边等是什么?)和 2。要使用哪些指标。

根据预测任务,我们可以计算节点级、边级和图级指标。这些度量可以作为关于实体本身及其与其他实体的关系的丰富信息。这可以看作是一个经典的监督 ML 任务,但这里的重点是特征选择。根据您的预测任务,您可以选择不同的图表度量来预测标签。

在我们的数据集中,我们将选择的标签是“突出显示”字段。标签的选择可以根据个人的目标而改变,但对于这个项目,我的假设是,有许多艺术作品值得突出显示(在公共领域展示),但大部分都被隐藏了。让我们看看是否可以使用图表来创建模型,以帮助预测哪些其他艺术品应该突出显示。

0 10733 
1 305
Name: Highlight, dtype: int64

我们在这里看到了很大的阶级不平衡,这是有道理的,因为只有一些艺术品能够得到强调,通常博物馆在他们的档案中包含大量的收藏。

dataframe 仅包含各种图表指标,我们将使用这些指标作为预测“突出显示”的特征。

让我们对数据集进行随机过采样,然后预测我们的目标变量。

Accuracy 0.7889492753623188 
Precision 0.08961303462321792 
Recall 0.6984126984126984 
F1-score 0.15884476534296027

不是最好的结果,但我们只是使用了基本模型,所以我们可能会通过广泛的调整或功能工程使其性能更好,但这超出了本故事的范围。需要注意的一点是,我们希望针对我们的问题进行召回优化。在这种情况下,获得“相关的”结果比“精确的”结果更好,因此看到相对较高的召回分数是件好事(记住,我们只是使用了一些图表指标来做到这一点!).

最后,这是一个节点级别的预测任务,其中有问题的节点是一个艺术品。同样的概念也可以很容易地用于边缘或图形级(具有传统功能)任务,使其高度通用。

嵌入方法

基于浅层嵌入的监督学习方法与非监督学习的不同之处在于,它们试图找到节点、边或图形级预测任务的最佳解决方案。这方面的两个主要算法是:标签传播和标签扩散。

这两种方法属于半监督学习领域,因为图中只有几个标记节点。这里的主要假设是网络中存在同向性,这意味着相似的节点比不相似的节点更有可能相互连接。

图表至少增加了一个维度的建模和选择,使得您的假设对于验证非常重要。例如,在第 3 部分中,我特别选择了用一种特殊的方式来设计这个网络,但是它也可以很容易地用不同的方式来制作。我选择的方法是为艺术品的每个属性创建节点,而不是将其嵌入到艺术品节点中。

作者图片

这可能仍然适用于我们的用例(即相似时期或文化中的艺术作品自然会比其他作品更紧密地联系在一起),但是这些是你应该和建模假设一起重新评估的选择类型。

标签传播

该算法将节点的标签传播到它的邻居(节点),这些邻居具有从该节点到达的最高概率。

sklearn 已经为我们实现了这个算法,使用两个主要的内核:kNN 和 rbf。我们可以控制 gamma 和 n_neighbors 等参数,以控制模型在标记节点周围扫描的“距离”。

对于我们的用例,从技术上来说,我们只有一个标签(1 代表“突出显示”),我们还有大量连接到节点的艺术品,如第 3 部分中看到的“未知时期”或“未知文化”(这些节点具有高中心性度量)。这基本上意味着我们的大多数模型配置将只输出“Highlight ”,以传播给几乎所有的节点,表明所有的艺术品都应该被突出显示。虽然这没有什么错,但是从模型的角度来看,它并没有给我们提供太多的价值——我们可以直接说出来,然后就完成了。

Highlight     Is Public Domain 
No Highlight  True                6567               
              False               4166 
Highlight     True                 235               
              False                 70
dtype: int64

我们首先需要做的是创建一个启发,允许我们控制什么是真正被突出显示的“合格的”。在我们的数据集中,只有大约 300 件艺术品被突出显示,其中超过 75%的作品属于公共领域。我们可以给没有突出显示和不在公共域中的节点加 0,表示它们“没有资格”被突出显示。在给定数据和领域的情况下,这可以很容易地更改为任何有意义的启发式规则。

-1    6567  
0     4166  
1     305 
Name: Highlight, dtype: int64

请注意,该模型需要未标记的节点具有-1 值。

您可以使用 predict_proba()方法提取每个类的模型概率,然后在模型拟合后使用 transduction_ after 将标签归属于行。

array([[4.46560147e-17, 1.00000000e+00],        
      [4.46560147e-17, 1.00000000e+00],        
      [4.89043690e-17, 1.00000000e+00],        
      ...,        
      [1.00000000e+00, 4.60058884e-51],        
      [1.00000000e+00, 1.50981524e-52],        
      [1.00000000e+00, 1.07327710e-50]])
0    6300 
1    4738 
dtype: int64

我们现在有超过 4000 件艺术品可以考虑在博物馆中重点展示!还应该进行模型评估,可以调整一些参数(gamma 或 n_neighbors)以确保“良好”的分割,但这是一项相当主观的任务,因此由领域专家进行基于任务的评估可能是最佳的评估策略。

从数学上讲,该算法使用一个转移矩阵乘以某个时间步长上每个节点的类值矩阵。如此迭代多次,直至收敛。

让我们来看看一些符号以及矩阵是如何组合在一起的。Stamile 等人的图形机器学习。艾尔。如果你想了解更多细节,我会解释得很清楚。

图的邻接矩阵

图的对角度矩阵

表示每个节点遍历到另一个节点的概率的转移矩阵

时间 t 时班级分配的概率矩阵

标签扩散

标签传播算法解决了标签传播算法的一个关键功能/限制:节点到类的初始标签。标签传播假设最初在数据集中提供的标签是真实的,并且它们不能在训练期间改变。标签扩散放松了这种约束,并允许在训练期间重新标记最初被标记的节点。

为什么?如果在最初标记的节点中存在一些误差或偏差,这可能是非常有益的;初始标记时出现的任何错误都会传播开来,仅通过指标很难发现这一点。

array([[1.00000000e+00, 2.14018170e-10],        
      [1.00000000e+00, 2.05692171e-10],        
      [1.00000000e+00, 2.13458111e-10],        
      ...,        
      [1.00000000e+00, 4.27035952e-18],        
      [1.00000000e+00, 3.85172946e-28],        
      [1.00000000e+00, 1.33374342e-32]])
0    6127 
1    4911 
dtype: int64

尽管表面上看起来非常相似,但由于概率的不同,这可能会产生非常不同的结果。标签扩散算法不是计算转移矩阵,而是计算归一化的图拉普拉斯矩阵,该矩阵类似于转移矩阵,可以被视为图的节点和边的低维表示。

归一化图拉普拉斯矩阵

使用 alpha 的概率矩阵,alpha 是一个正则化参数,用于调整原始解对每次迭代的影响程度

集体分类

图的强大之处在于使用了同向性、影响力等关键概念,通过连接提取模式。同质性指的是节点与它们相似的其他节点相关联的趋势,而影响力指的是社会联系影响个人/节点的个体特征的能力。这两种影响都可以在图表中捕捉到,我们可以利用这些作为假设来执行真正强大的监督和半监督 ML 任务。

我在上面讨论了一些更常见的技术,但是我们可以更深入地研究这个广阔的世界,并揭示网络中未知标签分类背后的一些理论。这一部分将紧密跟随 Jure Leskovec 博士在斯坦福在线上关于机器学习的课程。让我们澄清我们的方法将依赖的前提:

  1. 相似的节点通常靠得很近或者直接相连
  2. 节点的标签可能取决于:它的特征、它附近的邻近节点的标签以及它附近的邻近节点的特征。

集体分类是建立在马尔可夫假设上的概率框架:一个节点的标签依赖于其邻居的标签(一阶马尔可夫链)。它包括 3 个步骤:

局部分类器:分配初始标签。

  • 基于节点属性/特征预测标签的标准分类任务。不使用网络信息。

关系分类器:捕获节点之间的相关性。

  • 使用网络信息根据其邻居的标签和/或属性对节点的标签进行分类。

集体推理:通过网络传播相关性。

  • 迭代地将关系分类器应用于每个节点,并迭代直到相邻标签之间的不一致性最小化。

集体分类有三种常用模型:

概率关系分类器

  • 节点的类概率是其邻居的类概率的加权平均值。
  • 带标签的节点用真实标签初始化。未标记的节点用 0.5 初始化。
  • 通过将邻近的一阶节点标签(地面真实标签和 0.5 用于未标记的节点)相加并除以总的一阶节点来标记节点。
  • 所有节点以随机顺序更新,直到收敛或达到最大迭代次数。

局限性:

  • 不能保证收敛
  • 模型不使用节点特征信息

迭代分类

  • 主要思想是根据节点的属性以及邻居集的标签对节点进行分类。
  • 基本上训练了两个分类器。一种是基于节点特征向量预测节点标签。第二种方法基于节点特征向量和节点邻居标签的汇总来预测节点标签。
  • 相邻标签的汇总是一个向量,可以表示为:每个标签的数量直方图、最常见的标签或相邻集中不同标签的数量。
  • 在阶段 1 中,在训练集上建立两个分类器,在阶段 2 中,基于分类器 1 在测试集上设置标签,计算摘要向量,并且用分类器 2 预测标签。对每个节点重复这一过程。

局限性:

  • 这种方法也不能保证收敛。

循环信念传播

  • 动态编程方法,其中节点相互“传递消息”,反复回答概率查询。达成共识才算信念。
  • 每个节点只能与其邻居交互(传递消息),该消息被每个节点从其邻居处听到,被更新,然后被转发。把这个想象成游戏电话。

Jure Lescovec,斯坦福, CS224W:带图的机器学习

  • 该算法需要对节点进行排序,并且边缘方向根据节点集合的顺序。这定义了消息是如何传递的。
  • 利用标签-标签势矩阵,该矩阵是节点与其邻居之间的依赖关系。它与一个节点属于一个类的概率成正比,假设它在同一个类中有一个邻居。
  • 利用与节点成为一个类的概率成比例的先验信念。
  • 利用“消息”,它是一个节点对下一个节点是一个类的估计。
  • 所有的消息都被初始化为 1,然后对于每个节点,我们想要计算什么消息将被一起发送(给定节点对下一个节点的类的信任)。这是通过对邻居的所有状态加总标签-标签电势、先验以及邻居从前一轮发送的消息来计算的。

Jure Lescovec,斯坦福, CS224W:带图的机器学习

局限性:

  • 当你的图中有圈时,会出现一些问题,因为如果节点的初始信念是不正确的,它可以通过圈和/或不收敛来加强。这可能是因为每个消息都被认为是独立的,这在 cycles 中并不真实。

其中一些是需要通过遵循算法来构建的模型,但我建议快速阅读文档中引用的一些 sklearn 或 networkx 论文背后的研究论文——很可能提到了其中的一些技术!

摘要

在这一部分中,我介绍了如何利用图形信息进行监督和半监督学习。使用图表的价值在于至少可以提供丰富的空间连通性和中心性特征,并提供大量新技术来扩展您的问题解决策略库。

如果您将这里讨论的想法与前面关于度量、随机世界和扩散模型以及无监督学习技术的部分结合起来,您会发现自己正在以一个全新的维度分析您的数据。

即使有了所有这些新的想法和方法,我仍然没有讨论最近几年对图形——图形神经网络的大肆宣传。在接下来的部分中,我将把这个系列带到图形神经网络中,但请记住,深度学习仍然只与特定的数据问题相关。大多数数据问题都是表格形式的,不应该真的需要深度神经网络来解决,但是扩展自己的知识库也无妨!

为了避免写一本书和内容超载,我在这个故事中也没有涉及到很多内容,但这里有一些我使用的主要资源和特定主题,我认为从业者会从回顾中获得很多价值:

参考

[1] Claudio Stamile,Aldo Marzullo,Enrico Deusebio,图机器学习

[2] Jure Leskovec,斯坦福, CS224W:带图的机器学习

[3]伊斯利,大卫和克莱因伯格,乔恩。2010.网络、人群和市场:关于高度互联世界的推理

[4] 大都会艺术博物馆开放存取

图形神经网络:2008 年以来的学习之旅——扩散卷积神经网络

原文:https://towardsdatascience.com/graph-neural-networks-a-learning-journey-since-2008-diffusion-convolutional-neural-networks-329d45471fd9

图中邻接矩阵的真正威力是什么?什么是扩散卷积?请跟随我探索图形和机器学习的新冒险,探索 DCNN 理论

图片由杰里米·贝赞格Unsplash 上拍摄

我以前关于图形和 ML 的帖子:

通过我的推荐链接支持我的写作加盟媒介:

https://medium.com/@stefanobosisio1/membership

在这个系列中,我们正在跟踪和研究机器学习算法处理图的演变[1,2]。图表可以以非常简洁的方式存储大量信息[3–6],它们可以用于根据人们的社会关系评估人群[7–9]或利用简单线性分析无法检测的潜在特征[10]。另一方面,图形是复杂的数学结构[11,12],它们的输入信号不能在网格上描述,并且很难定义主要的局部统计,除非我们对节点的邻居进行平均。由于这些原因,卷积神经网络[13–15]等强大的最大似然算法的应用有时很复杂,需要了解图形的数学基础。

在上一篇帖子中,我们学习了 Kipf 和布鲁纳的卷积神经网络【11,12】,突出了一个图的谱分析和卷积运算之间的关系。今天我们将继续这项研究,分析 Atwood 和 Towsley 关于扩散卷积神经网络的论文[16,17]。在这种方法中,作者利用邻接矩阵和频谱分析之间的关系,利用邻接矩阵的内在属性,得出马尔可夫链公式[18–20]。

扩散卷积神经网络

扩散卷积神经网络(DCNN)通过学习“过滤器”来解决图形分类问题,这些过滤器通过扩散过程总结局部信息。这些信息是通过利用邻接矩阵属性获得的图的潜在表示来检索的。最后的算法大量使用张量运算,它需要一种稀疏表示,以允许 DCNN 处理数百万或数十亿节点的图形。

图 DCNN 的总结。根据图的邻接矩阵,我们可以计算从一个起始节点到给定 H 跳的最终节点的概率转移张量。这个张量反映了邻接矩阵的相同特征以及节点之间的“扩散”行为。张量 P、输入特征 X 和神经网络权重之间的乘积给出了扩散卷积层 z。该层可被完全连接的层接收,以返回输入图上的预测。

从 GCN 及其理论[21–25]中,我们了解到图的拉普拉斯描述与傅立叶变换密切相关。从这里,我们可以通过将自连接邻接矩阵 A 与节点的特征相乘来直接获得卷积运算,为图定义一个卷积神经网络层:

等式 1: l+1 卷积层的 l+1 激活矩阵,其被用作图形卷积神经网络(GCN)算法的传播规则

其中 H 是第ll+1层的激活矩阵,σ是类似于 ReLu 的激活函数, D 是图度矩阵, A 是自连接邻接矩阵, W 是层特定的可训练权重矩阵。

从这个基本计算出发,阿特伍德和陶斯利在卷积运算中加入了扩散。这种扩散允许节点“浏览”它们的邻居,并考虑来自它们的社会影响——这是 GCN 和 DeepWalk 的一种混合。然而,我们如何在一个图上添加扩散呢[26]?让我们考虑一个简单的 3 个顶点的图和它们的邻接矩阵(图 2)

图 2:一个简单的 3 顶点图及其邻接矩阵 A

每个顶点都可以与这些坐标相关联: (1,0,0) 表示 v1v2(0,0,1) 表示 v3 。如果我们把顶点乘以邻接矩阵,我们就能得到它的邻居的视图:

图 3:顶点邻接矩阵乘法返回给定顶点的邻居

图 3 显示,如果我们从顶点 1 开始,我们可以跳到顶点 2,对于顶点 2 我们可以跳到 v1v3 ,从顶点 3 我们可以跳到顶点 2 。现在,如果我们多次应用邻接矩阵会怎么样?我们以 v2 为例。 v2A 之间的乘积返回两次 v2 ,即如果我们沿着图中从 v2 开始的路径走两次,我们将返回到 v2 。因此,我们可以陈述这个定理:给定邻接矩阵 a 的幂 h,Aʰ(i,j)等于长度正好为 h 的图 g 中从 I 到 j 的路径数。这意味着邻接矩阵 A 的幂 h 给了我们一个图,该图给出了每个起始顶点在 h 跳中的去向——因此我们在图上是“扩散”的。

我们能给这个公式增加一点概率吗?我们当然可以!如果我们对邻接矩阵进行归一化,我们将获得一个转移矩阵,即给定一些跳数,从节点 i 到节点 j 的概率 h. 这里应该有一个铃声在你脑海中响起,让你思考马尔可夫链。这里的归一化邻接矩阵可以充当转移概率矩阵,就像在马尔可夫链过程中一样。这个矩阵的力量可以给我们一个关于如何在图上扩散每个顶点的想法。

现在可以将卷积运算与扩散概念结合起来。如图 1 所示,扩散卷积算子可以认为是转移概率张量 P,与输入节点特征矩阵 X 和层随机初始化权重矩阵 W 的乘积,P 是一个N×H×N张量, X 是一个 N x F 矩阵,而 W 是一个 F x N 矩阵,其中 N 是节点数, H 是跳数(或邻接矩阵的幂),而 F 是输入特征数。 最终的扩散卷积算子 Z 是一个 N x H x H 张量。这个张量可以被一个完全连接的神经网络层摄取,其输入节点与存储在张量中的矩阵一样多。然后可以通过 softmax 激活处理完全连接层的结果,以返回概率标签 Y.

总之,等式 2 报告了在 DCNNs 中执行的操作。首先,根据转移概率矩阵 P 和输入特征计算扩散卷积层 Z。然后,通过对来自完全连接的神经网络的输出的 softmax 激活来产生概率,该神经网络已经摄取了 z。

等式 DCNNs 操作总结。最初,根据输入概率转移张量 P 和节点特征 x 计算扩散卷积算子 Z。最后,在全连接层输出上,通过 softmax 激活返回概率预测。

今天就到这里吧!请继续关注我们的下一篇文章,在那里我们将编写 Python 代码来实现 DCNNs!

如果有任何问题或意见,请随时给我发电子邮件,地址是:stefanobosisio1@gmail.com,或者直接在 Medium 这里。

文献学

  1. 克劳德·贝尔热。图论。快递公司,2001 年。
  2. 弗朗西斯·安斯科姆,《统计分析中的图表》美国统计学家 27.1(1973):17–21。
  3. 沃索伊,索罗什,德布罗伊和西南阿拉尔。"真假新闻在网上的传播."理科359.6380(2018):1146–1151。
  4. 维拉、何塞和约兰达·戈麦斯。"从图表中提取商业信息:眼球追踪实验."商业研究杂志69.5(2016):1741–1746。
  5. 特鲁科,欧内斯特。"关于图的信息量的一个注记."数学生物物理学通报 18.2(1956):129–135。
  6. González-Díaz,Humberto,et al .〈基于分子图和社会网络信息指数的美国县级抗 HIV 药物活性与艾滋病流行率的人工神经网络多尺度模型〉。化学信息与建模杂志54.3(2014):744–755。
  7. 尹,郝,等,“局部高阶图聚类”第 23 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集。2017.
  8. 拉蒂根,马修 j,马克梅尔和大卫·延森。"用网络结构指数进行图聚类."第 24 届机器学习国际会议论文集。2007.
  9. 张,邓杰,陈金印,陆。"区块链钓鱼诈骗检测通过多通道图分类."区块链和可信系统国际会议。新加坡斯普林格,2021。
  10. 佩罗齐、布莱恩、拉米·艾尔弗和史蒂文·斯基纳。"深度行走:社交表征的在线学习."第 20 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集。2014.
  11. 基普夫,托马斯 n,和马克斯韦林。"图卷积网络的半监督分类." arXiv 预印本 arXiv:1609.02907 (2016)。
  12. 琼·布鲁纳等着《图上的谱网络和深局部连通网络》第二届国际学习代表大会,ICLR 。第 2014 卷。2014.
  13. 阿尔巴维、萨阿德、塔里克·阿贝德·穆罕默德和萨阿德·扎维。"了解卷积神经网络." 2017 国际工程与技术大会(ICET) 。Ieee,2017。
  14. 卡尔·布伦纳、纳尔、爱德华·格雷芬斯特特和菲尔·布伦松。"一个用于建模句子的卷积神经网络." arXiv 预印本 arXiv:1404.2188 (2014)。
  15. 克里日夫斯基、亚历克斯、伊利亚·苏茨基弗和杰弗里·e·辛顿。"使用深度卷积神经网络的图像网络分类."神经信息处理系统进展25(2012):1097–1105。
  16. 阿特伍德,詹姆斯和唐·陶斯利。"扩散卷积神经网络."神经信息处理系统的进展。2016.
  17. 稀疏扩散-卷积神经网络。 arXiv 预印本 arXiv:1710.09813 (2017)。
  18. 叶,侬。"用于异常检测的时间行为的马尔可夫链模型."2000 年 IEEE 系统、人和控制论信息保证和安全研讨会会议录。第 166 卷。纽约西点军校,2000 年。
  19. 海因斯布莱恩。"马尔可夫链中的第一个环节."美国科学家 101.2 (2013): 252。
  20. 奥雷,史蒂文。马尔可夫链转移概率的极限定理。伦敦:范·诺斯特朗,1971 年。
  21. 学习分子指纹的图形卷积网络。 arXiv 预印本 arXiv:1509.09292 (2015)。
  22. 哈蒙德、大卫·k、皮埃尔·范德盖恩斯特和雷米·格里邦瓦尔。"通过谱图论研究图上的小波."应用和计算谐波分析30.2(2011):129–150。
  23. 学习仿射变换。模式识别32.10(1999):1783–1799。
  24. 李,文静,和唐利。"仿射不变匹配的 Hopfield 神经网络."《IEEE 神经网络汇刊》12.6(2001):1400–1410。
  25. 离散傅立叶变换和卷积的算法。斯普林格,1989 年。
  26. 邻接矩阵的好资源在这里:https://www . bowaggoner . com/courses/2019/csci 5454/docs/spectral . pdf

图形神经网络:2008 年以来的学习之旅——从 Python 到 JAX:图形注意力网络

原文:https://towardsdatascience.com/graph-neural-networks-a-learning-journey-since-2008-from-python-to-jax-graph-attention-networks-692e4d6d7637

实践中的 GAT!探索 PyTorch、Torch Geometric 和 JAX #GPU 实现来加速 GAT 性能

图片由本杰明·沃罗斯Unsplash 上拍摄

通过我的推荐链接加入 Medium 来支持我的写作和项目:

https://stefanobosisio1.medium.com/membership

我之前关于图形神经网络的文章:

上次我们学习了图形注意网络(GAT)的理论原理。GAT 试图克服以前的图形神经网络方法中的一些已知问题,强调注意力的力量。我们看到,自 2014 年 Cho 和 Bahdanau 开始解决序列对序列(Seq2Seq)问题(例如,从法语到英语的翻译)以来,注意力一直是一个热门话题。GAT 的核心部分是 Bahdanau 的注意力,它计算输入序列和预期输出序列之间的比对分数。也可以为图节点的特征计算这样的分数,将输入图转换成潜在表示。此外,这种新的特征表示可以通过多头注意力得到进一步增强,其中多个注意力层被并行使用,以检测和使用彼此远离的节点之间的长期依赖性和关系。

今天,所有这些理论都可以付诸实践。所有的实现都将在 Cora 数据集上进行测试(许可证:https://paperswithcode.com/dataset/cora
CC0:公共领域)[1,4]。Cora 数据集由机器学习论文组成,分为 7 类:case_basedgenetic_algorithmsneural_networksprobabilistic_methodsreinforcement_learningrule_learningtheory。论文总数为 2708,这将是节点数。去除词干和停用词后,最终数据集只有 1433 个唯一词,这将是要素的数量。因此,该图可以用一个 2708 x 1433 的矩阵来表示,其中 1 s 和0取决于特定单词的存在。从论文引文文件中可以获得边列表并创建一个 2708×2708 的邻接矩阵。最初将颁发一个 PyTorch。随后,JAX 又进一步改进了深记包。最后,用 Torch 几何包进行测试。

!!!所有这些测试都能在这个 Jupyter Colab 笔记本里找到!!!

前奏:加载数据例程

对于所有的测试,数据都是用模板化的 Python 代码加载的,这里是好心提供的

图 1:加载 CORA 数据集程序。该函数返回邻接矩阵、节点特征、标签、用于训练、验证和测试的索引以及长传感器格式的边列表

CORA 数据集从https://linqs-data.soe.ucsc.edu/public/lbc/cora.tgz下载,然后节点的特征被编码成一个稀疏矩阵features = sp.csr_matrix(idx_features_labels[:, 1:-1],dtype=np.float32并被归一化,使得它们的值范围在[0,1]之间。从Cora.cites创建边缘列表,并从那里获得稀疏的adjacency矩阵。最终元素被转换为 PyTorch 张量:

features = torch.FloatTensor(np.array(features.todense()))    
labels = torch.LongTensor(np.where(labels)[1])    
adj = torch.LongTensor(adj.todense())   

idx_train = torch.LongTensor(idx_train)    
idx_val = torch.LongTensor(idx_val)    
idx_test = torch.LongTensor(idx_test) edge_tensor = torch.LongTensor(edges)

第一首赋格:PyTorch 实现 GAT

让我们从 PyTorch 开始我们的实现之旅。图 2 显示layers.py开始覆盖 GAT 的第一个关键点:注意力算法。

图 2: Bahdanau 在 PyTorch 对 GAT 的关注

代码是我们在理论中看到的一个总结。首先,我们需要指定一个大小为in_features, out_features的权重矩阵W,它是输入节点特征矩阵h的倍数。这个产品然后被传递到 attention,它是由两层和一维输出的神经网络a组成的。比对分数如下获得:

WH1 = torch.matmul(WH, self.a[:self.out_features, :]) 
WH2 = torch.matmul(WH, self.a[self.out_features:, :])
e = nn.LeakyReLU(WH1 + WH2.T)
attnt = torch.where(adjacency > 0, e, -1e9*torch.ones_likes(e) )         attnt = funct.softmax(attnt, dim=1)

最后,结果可以连接或平均,从这里返回新节点的表示hfirst. 非常容易实现具有多头关注的 GAT:

图 3: GAT 模型,多头注意力,向前迈步,准备接受训练

导入基本注意层from layers import GraphAttentionLayer后,构造器建立注意头和最终输出:

self.attheads = [GraphAttentionLayer(in_features, out_features, concat=True) for _ in range(nheads)]     

self.output = GraphAttentionLayer(out_features*nheads, nclass, concat=False)

forward步骤计算每个注意力头attn(X, adjacency) for attn in self.attheads的输出,并返回给定输入图X的最终输出节点预测

我们现在已经准备好根据给定的 CORA 输入开始训练 GAT,图 5:

图 5:基于 PyTorch 的 GAT 的训练路由

训练使用亚当优化器,100 个周期的学习率为lr=0.005weight_decay=5e-4。该测试在单 CPU 处理器英特尔至强 2.20GHz 的 google Colab 上运行。100 个时代可以在 2 分 55 秒内运行,训练和验证负似然损失nll,从 1.945 提高到 1.931。好但不是最好的方法!我们可以用 PyTorch Geometric 放大我们的模型

更好的是:PyTorch 几何中的一首赋格曲

PyTorch Geometric 是一个建立在 PyTorch 之上的库,并针对图形神经网络的实现和计算进行了优化。PyTorch Geometric 的关键结构点是易于使用的小型批量加载器,它允许模型处理非常大的数据集,以及优化的图形管道支持,并在箭筒中进行分布式图形学习。简而言之,用 PyTorch Geometric 编写代码非常简单,只需几行代码就可以实现图形神经网络,还可以在 CPU 和 GPU 之间切换。

图 6 显示 PyTorch 几何安装和 CORA 数据集的加载。数据集可以很容易地通过torch_geometric.datasets导入。数据集对象可以很容易地与torch_geometric.transforms交互,因此特性可以在一行代码中规范化为dataset.transform = T.NormalizeFeatures()

图 6: PyTorch 几何安装和 Cora 数据集的加载

为了与之前的测试保持一致,CORA 数据集将通过load_data()函数加载。从这里我们可以创建我们的 GAT 网络对象:

图 GAT 对象的实现和训练。培训可以是

GAT 类遵循通常的 PyTorch 方案。在结构__init__中,我们定义了模型参数和模型层。这些层由两个GATConv单元组成。前者是多头注意层,输出级联,后者是多头注意层,平均输出。在forward功能中,定义了模型序列。初始丢弃后,输入节点的特征在conv1层进行处理,最后在conv2层进行平均。与之前一样,我们将在英特尔至强 2.20GHz 处理器上使用 8 个隐藏单元和 8 个注意力头执行计算,并通过 Adam optimiser 进行参数优化。正如之前一样,我们可以调用上面的train函数来执行训练,而神奇的命令%%time测量执行时间。

PyTorch Geometric 中引入的伟大优化仅在 9.58 秒内处理 100 个时代,训练损失从 1.946 到 1.107 不等,有效损失从 1.945 到 1.352 不等。这是一个了不起的结果,这应该会让我们想起在处理 GNN 问题时应该用什么方法。它还没有完成。我将向您展示一种处理 GAT 的更深入的方法。

JAX +图形处理器

作为最后的测试,我检查了吉列姆·库库鲁https://github.com/gcucurull/jax-gat的实现,他出色地实现了 JAX 的 GAT,我对原始代码做了一些修改。什么是 JAX?JAX 是 DeepMind 中使用的主要编码框架,用于放大大模型,使它们运行得更快。JAX 的基础核心单元是autograd一个在 Python 中高效计算导数的 Python 包和XLA一个加速线性代数编译器,可以用几行代码加速 Tensorflow 模型,在 8 Volta V100 GPUs 上实现 BERT 7 倍的性能提升。正如你所看到的,如果我们要在 GPU 或 TPU 上加速我们的模型,JAX 工作得非常好。此外,DeepMind 最近发布了 https://github.com/deepmind/jraph/tree/master/jraphjraph一个新的 JAX 包,完全专注于图形神经网络的实现。遗憾的是,我还没有时间处理它——正如你看到的,我还在调试我的注意力实现——但是更多的更新即将到来:)

图 9 示出了在 JAX 中实现注意力算法的核心。首先,GraphAttentionLayer从构造器init_fun开始初始化神经网络和矩阵W权重。这是通过jax作为jax.random.split(random.PRNGKey(NUMBER),4)产生一些特定的随机数来实现的。jax需要随机数,例如,初始化数组或计算概率分布。特别是,输入参数需要是一个伪随机数生成器密钥或PRNGKeyNUMBER是一个随机数,可以通过NumPy轻松生成。随机生成器函数是create_random,它与jit装饰器一起存在。jit标记一个要优化的函数,它的意思是just in time,即该函数的编译将推迟到第一次函数执行时进行。由于我们只需要生成 4 个随机数,jax并不是非常高效,因此我们可以用jit来加速这个过程——记住jax在我们扩大规模时非常有用,因此在生成数百万个随机数时,它会比简单的NumPy 更高效。

一旦输入权重被初始化,apply_fun计算输入特征矩阵x上的关注度。Guillem 已经实现了Dropout函数,允许将is_training作为一个参数。然后,代码与 PyTorch 和NumPy非常相似,例如jax.numpy.dot(x,W)用于点积乘法,jax.nn.softmax(jax.nn.leaky_relu(...))用于最终注意力的 softmax 计算

图 9:JAX GAT 关注层的实现

接下来,创建多头注意力层,如图 10 所示。首先,我们创建一个空列表layer_funs来存储注意力头,并创建一个空列表来初始化权重layer_inits。然后,init_fun在这种情况下初始化layer_inits列表中每个元素的权重。apply_funlayer_funs中的每个元素设置关注的应用。如果我们在 GAT 的最后一层,我们对所有的注意力进行平均,否则我们连接结果x = jax.numpy.concatenate()

图 10:多头关注层的实现

图 11 将最后的GAT函数合并在一起。在这种情况下,nhid头被创建为MultiHeadLayer(nheads[layer_i], nhid[layer_i]...),每个头的初始化函数被附加到init_funs列表,应用函数被附加到attn_funs列表。

图 11:最终的 GAT 实现,合并多标题层和关注层

GAT中,init_fun通过att_init_func初始化每个头,同时apply_fun运行完整的 GAT 网络算法。

为了创建输入 CORA 数据,我对上面的 load data 函数做了一点修改,返回了NumPy数组而不是张量(图 12)

图 load _ data 函数的轻微修改。返回 NumPy 数组,而不是 PyTorch 张量

一旦一切就绪,我们就可以开始训练了。训练在特斯拉 K8 和特斯拉 T4 GPU 上运行——由谷歌❤实验室免费提供

图 13 显示了训练程序。在每一步中,jax.experimental.optimizer.Adam通过autograd功能更新所有参数。update函数需要在每个时期结束时运行,所以我们可以用jit装饰器来加速。然后,每个数据批次可以作为jax.device_put(train_batch)直接加载到计算设备上,在这种情况下是 GPU。这是 jax 的一个显著特性,因为整个数据都可以很容易地读取,从而提高了整个模型的性能。如果没有这个步骤,该算法在 Tesla K80 上运行大约需要 1/2 分钟,而在 GPU 上推送数据平均将计算时间减少到 30/40 秒。显然,特斯拉 T4 的表现更好,平均成绩为 15/18 秒。对于训练和验证批次,最终训练负对数似然损失的范围为 1.908 至 1.840。

图 13: JAX 加特训练部分。Update 函数和 device_put 是这个在 GPU 上实现的核心特性。

今天是一切:)

您可以在这里找到包含上述测试的整个笔记本

请继续关注下一个图表冒险!

如有任何问题或意见,请随时给我发电子邮件:stefanobosisio1@gmail.com 或直接在 Medium 这里。

文献学

  1. 网络数据中的集体分类。艾杂志 29.3(2008):93–93。
  2. 《推特上仇恨用户的描述和检测》第十二届 AAAI 国际网络和社交媒体会议。2018.
  3. 彭宁顿、杰弗里、理查德·索彻和克里斯托弗·d·曼宁。"手套:单词表示的全局向量."2014 年自然语言处理经验方法会议论文集。2014.
  4. 《用机器学习自动化互联网门户的构建》信息检索3.2(2000):127–163。

图形神经网络:2008 年以来的学习之旅——图形注意网络

原文:https://towardsdatascience.com/graph-neural-networks-a-learning-journey-since-2008-graph-attention-networks-f8c39189e7fc

今天我们将深入研究图形注意力网络(GAT)的理论和实现。一言以蔽之:关注摇滚,图表摇滚,GAT 的作者摇滚!

图片由 Unsplash 上的 Pascale Amez 拍摄

通过我的推荐链接加入 Medium 来支持我的写作和项目:

https://stefanobosisio1.medium.com/membership

我以前关于图和 M 的帖子

欢迎回到我的图形神经网络系列。今天我要向大家介绍一个最伟大的图形神经网络框架下的基础理论:图注意力网络(GAT)[1]由 Velickovic,Cucurull,Casanova,Romero,莉雅和 Bengio 于 2018 年发表(你应该只听到这些名字就起鸡皮疙瘩!)这种 ML-graph 方法有什么新的地方?我们来分析一下前几集看到的内容。

最初,Gori 和 Scarselli[5–9]提出了图形神经网络(GNNs ),其中递归神经网络被推广为直接与图形对象交互。gnn 基于 Banach 不动点定理。一旦达到平衡,运行神经网络以返回输出。相比之下,GNN 不能利用表征学习,其可扩展性非常有限,由于收敛问题。

我们看到的另一种方法是 Perozzi 在 2014 年提出的 Deep Walk [6]及其在 2017 年的演变[7]。深度行走标志着节点嵌入的概念,即通过 skip gram[8–12]获得的节点的潜在表示(或社会表示)。这个模型在半无人监督的模式下工作,尽管可扩展性和表示学习可能仍有问题。

因此,已经提出了进一步的图形神经网络框架。谱方法[13–17],其中图形拉普拉斯表示、特征值分解和卷积是关键要素。卷积可以通过扩散概念来进一步利用。在这种方法[18–22]中,算法学习每个节点的特定权重矩阵,计算转换矩阵的幂来描述节点的邻域。虽然这些技术非常成功,但它们直接依赖于拉普拉斯的特征基,限制了我们可以研究的图形种类。因此,一旦我们将我们的模型训练到一个特定的图,我们就不能使用这个模型在不同的结构图上运行预测。

在 GAT 中,作者强调了注意力的力量。注意力算法直接来源于神经机器翻译问题或序列对序列(Seq2Seq)。如果我从法语翻译成英语,我将不得不考虑输入和输出序列之间的长度差异,以及在给定词汇和目标序列的情况下我可以使用的最佳术语。注意力不仅可以解决不同长度的问题,还可以检测输入的最相关部分,以优化和最大化给定输入序列的输出概率。

现在让我们跳到注意力是如何工作的,以及一切是如何开始的。

注意:什么?谁啊。在哪里?什么时候?为什么?

注意力算法起源于 Cho 的 RNN 编码器-解码器模型[14]。作者正在寻找一种有效的方法来改进 seq2seq 翻译的 ML 模型。编码器-解码器模型是递归神经网络(RNN)的堆叠组合。编码器将符号序列编码成固定长度的向量表示,而解码器以另一种符号范例对给定的表示进行解码。

图 1 显示了 Cho 算法的工作原理。给定输入序列 x (例如Je m'appelle S),该模型试图最大化目标序列 y: 的条件对数似然

等式 1:给定输入序列 x 和目标序列 y,RNN 编码器-解码器试图最大化条件对数似然

输入序列用大小为hidden_size的嵌入层解码,然后在 GRU 单元中处理。GRU 的隐藏状态,称为context_vector,与目标序列一起被提供给解码器。解码器将输入序列和上下文向量一起投影到嵌入空间。最后,一个 GRU 和一个线性层在 xy 之间创建一个映射

图 Cho 的 RNN 编码器-解码器模型的逻辑示意图。编码器对输入序列进行消化。编码器的隐藏状态与目标序列一起被用作解码器的输入,以便找到序列到序列的正确映射。

图 2 显示了如何在 Pytorch 中对 Cho 的编码器和解码器进行编码的示例代码。一个关键的区别是解码器类将在嵌入的目标空间中映射输入。

图 Cho 的 RNN 模型的编码器和解码器的示例代码。这两个模型都依赖于嵌入层和 GRU。

Keras 提供了进一步的可视化帮助,我们可以用一种简单的方式对这个模型进行编码,以显示输入信息是如何处理的:

图 Cho 的 RNN 编码器-解码器的 Keras 实现。在这里,您可以进一步看到当将编码器 GRU 的隐藏状态传递给解码器时,注意力是如何被触发的。

2016 年晚些时候,Bahdanau 扩展了 Cho 的模型[26,28],用比对分数构建了注意力算法。校准分数进一步增强了编码器的输出,定义了它与给定输出的匹配程度*:

  • 每个编码器的 GRU 输入 x₁、x₂、x₃ …都有各自的隐藏状态 h₁、h₂、h₃
  • 解码器开始计算比对分数,例如 e ₁₁ ,e ₁₂ ,e ₁₃ (等式 2)。校准分数是通过函数 a — 通常是前馈线性神经网络来定义的,该函数作用于解码器的输出状态 s 和编码器的输出 h.

等式 2:对准分数被定义为作用于解码器的输出状态 s 和编码器的输出 h 的函数 a

  • 在第一步,解码器输出为 0,因此校准分数定义为:

等式 3:第一次迭代中的对齐分数,其中解码器的输出为 0。

  • 是简单的pytorch.nn.Linear前馈神经网络,其输出α 然后用 softmax 函数(等式 4)归一化:

等式 4:来自神经网络的一般 softmax-ed 输出以及等式 3 的 3 个输入的示例

  • 然后,归一化对齐分数被用于更新输出编码器的上下文向量 c,并被注入到解码器 GRU 中:

等式 5:输出对齐权重用于将每个上下文向量与给定目标对齐

  • 循环重复,新解码器的输出 s 用于计算比对分数

通过添加由前馈神经网络、softmax 和注意权重/对齐分数与编码器输出之间的矩阵乘法组成的注意层,可以在 PyTorch 中将该方案容易地应用于 Cho 的模型(图 2 ):

图 4:在 Cho 的 RNN 编码器-解码器中添加注意层。

总之,Bahdanau 的方法旨在将编码器的所有隐藏状态传递给 RNN 解码器,并进一步将注意力/对准分数层应用于解码器架构。从这里我们可以开始研究图形注意力网络算法

图形注意网络

从 Bahdanau 的注意力方法开始,Velickovic 等人开始使用图形注意力网络框架——然而,我必须强调,GAT 对注意力机制的特定选择是不可知的。现在,让我们考虑一个有 N 个节点的图,每个节点有 F 个特征。这里注意机制的整体过程是摄取一组节点特征(维度为 F )并返回这些特征的一个输出表示'(维度为 F' )。要素的输出表示将调用一些潜在要素,这允许网络在节点级别运行预测。****

图 GAT 工作流程和注意力的示意图。

图 5 报告了 GAT 的作用方案。节点共享一个权重矩阵W** ,其维数为FxF’。权重矩阵 W 与每个节点的特征矩阵相乘以执行第一线性变换。它遵循第二线性变换,通过自关注机制,通过应用前馈神经网络 a,返回关注系数 e:**

等式 6:表示节点 j 的特征对节点 I 的重要性的关注系数

a 输出的注意系数在到达 softmax 层之前通过 LeakyReLu。softmax 在节点 j 的特征上被归一化,以使所有系数在不同节点之间容易比较:

等式 7:相对于节点 j 特征的归一化(softmax)关注系数

最后,应用非线性 σ 得到最终的特征描述h’。为了进一步稳定自我注意机制中的学习过程,作者扩展了该算法以使用多头注意。这种方法包括在图表的不同部分运行多个注意力层,以便掌握一些长期的依赖关系。长程相关性是指相距很远的节点之间的关系。最终的特征集合可以连接在一起,并且如 GAT 的论文中所提议的,进行平均以返回最终节点的预测。这种平均过程突出了 GAT 的输出是来自目标节点邻域的聚集信息。**

现在让我们看看如何在 PyTorch 中实现 GAT 方法,而在下一个故事中,我们将处理数据集和预测以及优化 GAT 的技巧!

加特&皮托奇

图 6 显示了 GAT 核心部分的简单 PyTorch 实现。在call函数中,GAT 接收节点的特征和边(input)作为输入,报告图形结构信息。输入节点状态/特征最初乘以权重矩阵 W 以执行第一线性变换:node_states_transformed = tf.matmul(node_states, self.kernel)。将转换后的状态与结构信息node_states_expanded收集在一起,并从那里运行进一步的线性转换以获得关注系数:attention_scores = tf.nn.leaky_relu(tf.matmul(node_states_expanded, self.kernel_attention))

图 PyTorch 中注意机制的实现

最后,softmax 被应用到attention_scores(第 70–79 行),来自关注层的邻域特征信息被返回到主函数。

第二个最重要的一点是实现了多头关注。该类定义了并行运行的关注层的数量,以及关注层单元。最终输出是所有串联注意力输出的平均值:tf.reduce_mean(tf.stack(outputs, axis=-1), axis=-1)

图 7:多头注意力的实现

让我们以 GAT 的最终实现来结束这个故事,对算法有一个全面清晰的了解:

图 GAT 模型的最终代码。

今天到此为止,请在下一个故事中欣赏我,我们将把 GAT 应用于数据集,看看 GAT 的真正威力是什么:)

如果有任何问题或意见,请随时给我发电子邮件,地址是:stefanobosisio1@gmail.com,或者直接在 Medium 这里。

文献学

  1. 《图形注意网络》 arXiv 预印本 arXiv:1710.10903 (2017)。
  2. 《图形神经网络模型》 IEEE 神经网络汇刊20.1(2008):61–80。
  3. 《图形神经网络的计算能力》IEEE 神经网络汇刊 20.1(2008):81–102。
  4. 《网页排序的图形神经网络》。2005 年 IEEE/WIC/ACM 网络智能国际会议(WI'05) 。IEEE,2005 年。
  5. 哥里、马尔科、加布里埃尔·蒙法迪尼和佛朗哥·斯卡塞利。"一个在图形领域学习的新模型."议事录。2005 年 IEEE 神经网络国际联合会议。第二卷。№2005.2005.
  6. 佩罗齐、布莱恩、拉米·艾尔弗和史蒂文·斯基纳。"深度行走:社交表征的在线学习."第 20 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集。2014.
  7. 佩罗齐、布莱恩等人“不要走,跳过!多尺度网络嵌入的在线学习。”2017 年 IEEE/ACM 社交网络分析与挖掘进展国际会议论文集 2017 。2017.
  8. 《向量空间中单词表征的有效估计》 arXiv 预印本 arXiv:1301.3781 (2013)。
  9. 单词和短语的分布式表征及其组合性。神经信息处理系统的进展。2013.
  10. 大卫·格思里等着,〈跳过语法建模的更近距离观察〉。 LREC 。第六卷。2006.
  11. Gittens,Alex,Dimitris Achlioptas 和 Michael W. Mahoney。" Skip-Gram Zipf+Uniform =矢量可加性."计算语言学协会第 55 届年会论文集(第 1 卷:长篇论文)。2017.
  12. 明诺、大卫和劳雷·汤普森。"负抽样跳跃图的奇异几何."自然语言处理中的经验方法。2017.
  13. 基普夫,托马斯 n,和马克斯韦林。"图卷积网络的半监督分类." arXiv 预印本 arXiv:1609.02907 (2016)。
  14. 琼·布鲁纳等着《图上的谱网络和深局部连通网络》第二届学习代表国际会议,ICLR。第 2014 卷。2014.
  15. 迪费拉德、米歇尔、泽维尔·布列松和皮埃尔·范德盖恩斯特。"具有快速局部谱滤波的图上的卷积神经网络."神经信息处理系统进展29(2016):3844–3852。
  16. 学习分子指纹的图形卷积网络。 arXiv 预印本 arXiv:1509.09292 (2015)。
  17. 哈蒙德、大卫·k、皮埃尔·范德盖恩斯特和雷米·格里邦瓦尔。"通过谱图论研究图上的小波."应用和计算谐波分析30.2(2011):129–150。
  18. 阿特伍德,詹姆斯和唐·陶斯利。"扩散卷积神经网络."神经信息处理系统的进展。2016.
  19. 稀疏扩散-卷积神经网络。 arXiv 预印本 arXiv:1710.09813 (2017)。
  20. 叶,侬。"用于异常检测的时间行为的马尔可夫链模型."2000 年 IEEE 系统、人和控制论信息保证和安全研讨会会议录。第 166 卷。纽约西点军校,2000 年。
  21. 海因斯布莱恩。"马尔可夫链中的第一个环节."美国科学家 101.2 (2013): 252。
  22. 奥雷,史蒂文。马尔可夫链转移概率的极限定理。伦敦:范·诺斯特朗,1971 年。
  23. 使用统计机器翻译的 RNN 编码解码器学习短语表达 arXiv 预印本 arXiv:1406.1078 (2014)。
  24. 基于注意力的语音识别模型。神经信息处理系统进展 28 (2015)。
  25. 基于端到端注意力的大词汇量语音识别。 2016 年 IEEE 声学、语音和信号处理国际会议(ICASSP) 。IEEE,2016。
  26. Bahdanau、Dzmitry、Kyunghyun Cho 和 Yoshua Bengio。"通过联合学习对齐和翻译的神经机器翻译." arXiv 预印本 arXiv:1409.0473 (2014)。
  27. 你所需要的只是关注。神经信息处理系统进展 30 (2017)。
  28. Luong,Minh-Thang,Hieu Pham 和 Christopher D. Manning。"基于注意力的神经机器翻译的有效方法." arXiv 预印本 arXiv:1508.04025 (2015)。

*:https://jalammar . github . io/visualizing-neural-machine-translation-mechanics-of-seq 2 seq-models-with-attention/这里是 seq2seq with attention 的优秀可视化流程

图形神经网络:2008 年以来的学习之旅——Python 和图形卷积网络

原文:https://towardsdatascience.com/graph-neural-networks-a-learning-journey-since-2008-python-graph-convolutional-network-5edfd99f8190

今天,我们对 GCN 理论有了清晰而实用的认识。我们会穿过基普夫的火炬🔦GCN 的实施👩‍🎓。然后,我们将把我们所学到的应用到可恶的 Twitter 数据集上🔥

图片由龙之介菊野Unsplash

我以前关于图形和 ML 的帖子:

通过我的推荐链接支持我的写作加盟媒介:

https://medium.com/@stefanobosisio1/membership

欢迎回到我的图形神经网络系列!在之前的文章中,我们研究了图论、卷积神经网络的理论和数学基础。今天我们将讨论 Kipf 对 GCN 的 PyTorch 实现,试图简化实现,并将 GCN 应用于 Twitter 仇恨/正常用户数据集。享受:)

将 GCN 理论翻译成 PyTorch

传承 PyTorch nn。组件

在 PyTorch 中常见的做法是制作一个定制模块来创建一个模型,使用torch.nn.Module这就创建了一个 Python 对象,从而允许创建复杂的模块。定制模块是类,它是包torch.nn.Module的子包,继承了所有的方法和属性:

图 1:使用 torch.nn 定义一个定制模块,新定义的模块继承了所有的 nn。模块属性和方法,并可以很容易地适应实现自定义模型。

class MyNetwork(nn.Module)定义了子类,然后,类似于nn.Module,它希望用输入和输出网络大小(分别是in_sizeoutput_size)来定义构造函数。在构造函数中,调用超级构造函数super()。这允许从对象MyNetwork内的包torch.nn.Module创建对象,而不需要显式初始化它。然后,可以设置网络层和forward步骤,这也是从nn.Module继承而来的。

应用神经网络。基本 GCN 操作模块:layers.py

同样的方案之后是 Kipf 在layers.py:https://github.com/tkipf/pygcn/blob/master/pygcn/layers.py中实现 GCN 逻辑。图 2 显示实现了 GCN 的基本层功能,它是邻接图矩阵与输入图特征数组和第 I 层权重的乘积:

图 2:作为 torch.nn.Module 实现的 GCN 的基本操作。这里,Kipf 定义了 GCN 步骤,这是一个简单的基于拉普拉斯的矩阵乘法。权重和偏差被均匀采样,前一步执行所需的乘法。

权重和偏差参数被定义为torch.nn.parameter对象,通过从均匀分布中随机取样产生。forward步骤更新了前一篇文章的等式 10 中的层权重计算。

堆叠图层:models.py 中的 GCN 模型

既然我们已经实现了基本的构建模块,我们就可以继续实现 GCN 模型了。根据 Kipf 的论文,GCN 由两层组成,一个输入层,一个隐藏层,它们通过 ReLu 激活来组合。此外,我们可以有一个丢弃层,其中输入训练数据的一部分被丢弃,以进一步加强层预测。最终输出为 softmax 的对数,等式。一

等式 1:对数 softmax 函数。首先,对第 I 个输入执行 softmax,然后计算 log。

图 3:GCN 模型的实现。该模型由两层组成,一个输入层,一个隐藏层和一个可能的下降步骤。

准备输入数据

一旦基本模型已经建立,我们可以看看输入数据。Kipf 提供了来自 Cora 数据集(https://paperswithcode.com/dataset/cora)的数据;
CC0:公共领域)[1,4]。Cora 数据集由机器学习论文组成,分为 7 类:case_basedgenetic_algorithmsneural_networksprobabilistic_methodsreinforcement_learningrule_learningtheory。论文总数为 2708,这将是节点数。去除词干和停用词后,最终数据集只有 1433 个唯一词,这将是要素的数量。因此,该图可以用一个 2708 x 1433 的矩阵来表示,1 和 0 取决于特定单词的存在。从论文引用文件可以获得边列表,并从那里创建一个 2708 x 2708 邻接矩阵。数据通过实用程序脚本 [utils.py](https://github.com/tkipf/pygcn/blob/master/pygcn/utils.py)创建。一旦创建了这些元素,就可以继续进行培训步骤。

用 Cora 数据集训练 GCN 模型

图 4 总结了所有的 GCN 步骤。加载数据,以创建特征矩阵X和邻接矩阵adj。这些元素可以被 GCN 模型摄取,该模型通过拉普拉斯乘法来转换数据,返回每个节点的 7 个类的概率。

图 Kipf 代码概述。对初始 Cora 数据集进行处理,以获得特征矩阵 X 和邻接矩阵 adj。这些元素可在 GCN 模型中直接用于计算每个结点的输出类。

图 5 显示了用于训练 GCN 模型的 Kipf 代码的摘录。核心位是火车功能。这里,最初通过optimiser.zero_grad()将梯度设置为零。然后,模型的输出被计算为output = model(features, adj)。最后,运行模型性能检查和损失,计算负对数似然性和准确性,负对数似然性更新网络权重,准确性评估模型相对于评估数据集的良好性。

图 5:GCN 模型的训练程序。函数串是调用模型的核心位,权重通过负对数似然更新,并通过计算准确度分数来执行评估。

玩 GCN,预测推特上可恶的用户

现在是时候玩一个奇特的数据集和 GCN 了。数据集是 Twitter 可恶的用户【2】(CC0:公共领域许可证)在其论文中有描述【2】。该数据集拥有 100,000 名用户。5,000 名用户被贴上了仇恨的标签,也就是说,他们在 Twitter 上发布仇恨帖子。每个用户都有一组定义好的和人工设计的特征users_neightborhood_anon.csv,其中推文已经通过手套嵌入进行编码【3】。其目的是利用网络信息来预测哪些用户也可能是可恨的。这个例子是自由地受这个教程的启发:https://stellar graph . readthedocs . io/en/v 1 . 0 . 0 rc1/demos/interpretatibility/gcn/evidence-twitters-interpretatibility . html

下载数据和预处理

首先,我们需要下载数据并解压文件。在本例中,我们将通过 Google Colab 笔记本使用 Kaggle APIs:

!pip install kaggle --upgrade
# download from your kaggle account the token file kaggle.json
!mkdir /root/.kaggle 
!cp kaggle.json /root/.kaggle/. 
!mkdir dataset 
!kaggle datasets download -d manoelribeiro/hateful-users-on-twitter -p dataset/
# unzip the files 
!unzip dataset/*.zip

这个例子需要的文件是users_neighborhood_anon.csv和来自users.edges的边缘列表

节点的特征是人工设计的,然而,图形神经网络的优点在于它们可以去除这些特征,因为它们能够检索网络信息,这对于正确的分类是至关重要的。为此,我们将清理输入数据集,并将要素的大小从 1039 缩小到 206:

图 6:读取输入节点的特征并清理它们,以便将维数减少到 206。

从这里,我们可以开始准备一个数据集,用于 GCN 预测。首先,我们选择所有被标记为normalhate的用户(总共 4971 个)。然后,可以读取边并选择带有已过滤节点索引的子图,最后,我们可以创建邻接表。

图 7:只选择标签不是 2 的用户,正常用户和讨厌用户,从他们的索引中提取相关的边子图。然后,使用 networkx 创建邻接矩阵,并使用 scipy 将其转换为稀疏矩阵

邻接矩阵是一种稀疏类型,通过scipy.sparse.coo_martrix创建,正如我们在 Kipf 代码中看到的。

最后一步是为 GCN 摄取准备邻接和特征矩阵。在这种情况下,我们将对要素的值进行归一化,因为相邻要素已经进行了归一化,我们将为训练(0–1000)、评估(1000–1200)和测试(1200–1400)定义一些样本索引。

图 8:归一化节点特征矩阵,定义训练、评估和测试的指标。

在推特上训练 GCN 可恶的数据集

最后一步完全遵循 Kipf 的代码。我们称之为 GCN 模型和亚当优化器。从那里开始,我们运行一系列的训练程序,然后我们将测量精确度。

图 9:根据节点的特征形状准备输入尺寸的 GCN 模型,设置隐藏层尺寸和优化器参数。然后,运行一组定义的时期

在这种情况下,我们定义的隐藏层大小为 16,但可以随意修改,输出类的数量为 2 ( normalhate)。我们可以收集各个时期的损失和准确度,并看到在 50 个时期后有一个收敛,而评估集的准确度达到 0.89。

图 10:训练和评估 Twitter 数据集的负对数似然损失。两个数据集通过大约 0.34(训练)和 0.65(评估)的损失收敛。进一步的时代将会加强趋同

这只是 GCN 美丽的一个小小的例子。你可以带着这些作业进一步练习和探索 GCN 的力量:

  • 修改输入数据集大小
  • 从输入数据集中提取更多要素
  • 从第二层提取信息,用分解算法作图,看网络在训练时如何分裂网络。

今天它是一切:)请继续关注下一个图表冒险!

如果有任何问题或意见,请随时给我发电子邮件,地址是:stefanobosisio1@gmail.com,或者直接在 Medium 这里。

文献学

  1. 网络数据中的集体分类。艾杂志29.3(2008):93–93。
  2. 《推特上仇恨用户的描述和检测》第十二届 AAAI 国际网络和社交媒体会议。2018.
  3. 彭宁顿、杰弗里、理查德·索彻和克里斯托弗·d·曼宁。"手套:单词表示的全局向量."2014 年自然语言处理经验方法会议论文集。2014.
  4. 《用机器学习自动化互联网门户的构建》信息检索3.2(2000):127–163。

作为梯度流的图形神经网络

原文:https://towardsdatascience.com/graph-neural-networks-as-gradient-flows-4dae41fb2e8a

基普夫&韦林反击战

在一些简单的约束下,图形神经网络可以被导出为梯度流,该梯度流最小化描述特征空间中吸引力和排斥力的可学习能量。这种形式主义允许将 gnn 解释为物理系统,并揭示了图形频率和通道混合频谱之间的相互作用如何决定节点特征的演变,并控制动力学是“平滑”还是“锐化”它还导致了一个令人惊讶的结论:即使是非常简单的具有共享权重的图卷积模型也不一定会遭受过度平滑,并且在嗜异性设置中可能是有效的。

图片:Shutterstock。

本文与 Francesco Di Giovanni、James Rowbottom、Ben Chamberlain 和 Thomas Markovich 合著,基于 F. Di Giovanni、J. Rowbottom 等人的论文 【图神经网络作为梯度流【2022】,arXiv:2206.10991。请看一段Francesco 在 首届意大利暑期学校关于几何深度学习 的演讲录音以及我们之前关于 神经扩散细胞束 物理启发图 ML

raph 神经网络经常被批评为过度平滑(多个消息传递层逐渐产生接近常数的节点特征的趋势【1-2】)以及在异嗜性设置中的糟糕性能(当相邻节点具有不同标签时【3】)。应对这些现象的尝试最近导致了更复杂的信息传递方案的“寒武纪大爆发”,其中一些求助于非常奇特的结构,如蜂窝滑轮【4】。

最重要的是,图形神经网络面临深度学习的普遍问题:可解释性差。总的来说,机器学习社区对 GNNs 有一种爱恨交加的关系:有时最新和最伟大的架构提供了最先进的结果,而在其他情况下,简单的旧方法(如图形卷积模型[5]或甚至节点式多层感知器)几乎一样好。对于某些模型在什么时候以及为什么表现良好,并没有清晰的认识,一种多少有些不健康的“民间传说”从一张纸重复到另一张纸上。

在最近的出版物中【6】,我们认为 GNNs 是离散的粒子动力系统,它在微分方程(称为梯度流)下演化,使一些能量最小化。这种受物理学启发的方法,我们称之为梯度流框架(GRAFF)* ,提供了对现有 GNN 建筑的更好理解(导致一些令人惊讶的结论!)以及派生新的更有效的方法的原则性方法。*

梯度流

考虑一个由演化方程支配的动力系统

(t)=f(x(t))

从某个初始状态 X (0)开始,运行时间 t > 0。这个微分方程的结构(在我们的符号中是 F )取决于底层的物理系统。例如,矩阵 X 的行可以表示以矢量场F给出的速度移动的粒子系统的空间坐标。如果粒子带电,它们相互施加静电力,导致耦合的常微分方程系统,其中不同行的 X 之间存在相关性。

模拟流体的复杂粒子动力系统。图片:李大卫

在深度学习中,人们可以将微分方程系统的输入演变视为深度神经网络的连续版本,这是一种称为“神经微分方程”的方法[7–8]。然后,就有可能在用于求解方程的数值方案的时间步骤和神经网络的层之间画出一条平行线。

**梯度流【9】是特殊类型的演化方程的形式

f*(x(t)= –∇ℰ(x**(t),*

ℰ是某种能量函数。梯度流使得ℰ在演化过程中单调下降[10]。许多物理系统都可以用一些能量来表征,这些能量被它们的动力学最小化了。ℰ的知识提供了对系统的更好的理解,并且经常允许一个人对动力学的主要影响和它的渐近行为作出陈述。

一个原型梯度流是扩散方程,它控制着物理介质中的热传播。扩散方程的正式推导可以追溯到 19 世纪约瑟夫·傅立叶关于热分析理论【11】的论文。这种方程在物理学中有很多应用,也已经用于图像处理、计算机视觉[12]和graph ML【13】。

在其最简单的形式中,𝒢图上的扩散方程由下式给出

(t)=–δx(t),

其中 Xn × d 节点特征矩阵δn × n 图拉普拉斯[14]。这是一个耦合的 ode 系统:图中的每个节点( X 的行)都与其邻居相互作用。

扩散方程原来是狄利克雷能量的梯度流

ℰᴰᴵᴿ(x)= trace(xδx)=∑ᵤᵥ||(∇x)ᵤᵥ| |,

其中∇ X 表示在图的每条边上定义的特征的梯度。狄利克雷能量测量图[15]上特征的平滑度。在极限 t →∞时,扩散会丢失输入特征中包含的信息,因为所有节点都变得“相同”[16]——这种现象在 GNN 文献中通常被称为“过度平滑”

流形上的热扩散方程。

卷积图神经网络

T 平滑节点特征的简单扩散方程在图形 ML 问题中可能不太有用【17】,其中图形神经网络提供了更多的灵活性和能力。人们可以把 GNN 想象成一个由参量演化方程支配的更一般的动力系统

(t)=gnn(𝒢,x(t); θ ( t ),

使用欧拉方法[18]离散,固定时间步长 0<τ<1为**

x**(t+τ)=x(t)+τgnn(𝒢,x(t); θ ( t ))。**

每次迭代对应于一个 GNN 层,该层通常可以有一组不同的参数 θ ( t )。

如何实现上述等式中的函数“GNN”是不同图形神经网络架构之间的关键区别。卷积类型的 gnn[19]将共享线性变换应用于特征(可学习的d×d‘信道混合’矩阵 Wω),随后沿边缘传播(通过归一化邻接矩阵‘扩散’),并可能进行元素式非线性激活 σ 😗***

X(t+τ)=X(t)+(—X(t)ω(t)+āX(t)【T24****

选择ω=W=Iσ= id 恢复了我们之前看到的离散化图形扩散方程。由 Thomas Kipf 和 Max Welling [5]介绍的最简单的图卷积模型之一 GCN 的残差版本是上述模型的特例,其中ω= 0。

我们的例子展示了 GNN 建筑的通常设计过程,从参数化一个演化方程开始。我们认为,另一种方法,即参数化能量并导出 GNN 作为其离散梯度流,提供了更好的可解释性,并导致更有效的架构。这是我们 GRAFF 方法的精髓:我们对一类可以写成梯度流的 gnn 感兴趣**

(t)=−∇ℰ(𝒢,x**(t); θ ( t ),****

一些参量能量ℰ(.; θ ,参数 θ 通过任务损失函数的反向传播学习。

能量和演化方程之间的联系提出了理解和设计 GNNs 的双重水平:从能量到演化方程,我们导出了更有原则和更有效的图形卷积模型版本,作为 Dirichlet 型参数能量族的梯度流。我们表明,这种模型具有避免过度平滑的理论保证和处理嗜异性数据的能力。

相反,从演化方程到能量,我们证明了许多现有的非线性图卷积模型,尽管不是梯度流,仍然可以在我们的框架内进行分析。特别地,我们证明了它们的演化方程降低了前面提到的狄利克雷型能量。

从能量到演化方程

让我们考虑一族二次能量

ℰᶿ(x)=∑xωx⟩∑ᵤᵥāᵤᵥxWx****

由矩阵ωW 参数化。我们称ℰᶿ为“广义参数狄利克雷能量”,因为经典ℰᴰᴵᴿ是它的特例[20]。****

物理解释。 ℰᶿ是与粒子系统(图中的节点,其在特征空间中的位置由矩阵 X 表示)相关联的能量,可以解释如下:第一项表示作用于所有粒子的‘外部’能量。第二项考虑了沿着图的边缘的成对相互作用,因此代表了粒子系统的“内部”能量。成对交互由通道混合矩阵 W 控制。第二能量项的最小化使得相邻节点的特征xxt20】ᵥ沿着对应于正特征值的特征向量 W 吸引。同样的, W 的负本征值诱发斥力*【21】。*****

梯度流动。ℰᶿ的梯度流量由下式给出

(t)= −∇ℰ(x(t)=-x(t)(ω+ωᵀ)/2++x(t)(w+w**ᵀ)/2.****

由于ωW 以对称形式出现在梯度流中,在不失一般性的情况下,我们可以假设它们是对称的:**

(t)=-x(t)ω+āx(t)w**。****

当以固定时间步长 τ、离散化时,该演化方程成为具有共享对称权重的图卷积模型**

X(t+τ)=X(t)+τ(-X(t)ω++X(*t*****

由于ωW 独立于层 t 。逐层共享权重将一个 L 层卷积 GNN 中的参数总数从 2dL 减少到 d 。重要的是,对称约束不会削弱 GNN 的表现力[22]。**

格拉夫诱导的排斥和吸引动力学的例子:节点位置代表它们的特征坐标,颜色是标签。斥力沿着特征空间的 x 轴(W的负特征向量的方向)发生,引力沿着 y 轴(W的正特征向量发生。

动力学中的显性效应。我们对 GNN 粒子系统的物理解释允许分析其梯度流诱发的动力学。吸引力使边缘梯度最小化,产生平滑效应(“模糊”),放大了图中节点特征的低频[23]。另一方面,排斥力增加了边缘梯度,产生了增强高频的“锐化”效应。

这可以通过监测沿归一化解的狄利克雷能量来定量表示:如果在极限ℰᴰᴵᴿ(x(t)/| |x(t)| |)趋向于零,我们就有了低频主导的 (LFD)动力学。在收敛到图的拉普拉斯最大特征值的情况下,我们称动力学高频 支配(HFD)【24】。****

嗜同性(左)和嗜异性(右)图表示例。不同类型的节点用颜色编码。

多项研究表明,LFD 过程对于同形图中的节点分类是成功的。直观地,在这样的图中,邻居包含相似的信息,并且平滑过程聚集邻居,同时平均掉噪声。在异嗜性情况下,平滑通常是有害的,因为高频成分可能包含更多相关信息【27】。因此,一个理想的 GNN 模型必须通过能够诱导 LFD 或 HFD 动力学来适应这两种相反的情况。**

我们表明,基于扩散的模型,如连续 GNN [28],PDE-GCN-D [29],和图神经扩散 (GRAND) [13]无法诱导 HFD 动力学,因此可能会在嗜异性设置中遭受可预见的痛苦[30]。其中一个原因是,GRAND 等方案不允许通道混合:GRAND 在节点特征的每个通道上独立地执行非线性扩散,这可以被解释为一种图形注意力[31]的形式。

另一方面,根据w【32】的光谱,通过离散化我们的参数能量ℰᶿ的梯度流获得的格拉夫模型可以学习成为 LFD(主要是边缘方向吸引)或 HFD(主要是边缘方向排斥)。这使得格拉夫既适用于嗜同性也适用于嗜异性。

具有受控同质性的合成 Cora 数据集上的节点分类实验。GCN [5]通过利用节点特征的局部相似性,在高同质性的情况下表现良好;当同质性低时,这变成导致性能恶化的缺点。多层感知器(MLP)通过独立考虑每个节点的特征而忽略了图的结构。这使得 MLP 对低同性免疫,但也无法利用高同性。我们受物理学启发的格拉夫模型在两种情况下都工作得很好,因为它能够诱导低频和高频主导的动力学。图改编自[6]。

格拉夫系统动态的驱动因素是拉普拉斯图{ λₗ }的频谱和通道混合矩阵{}【33】的频谱的相互作用。 W 的正特征值(ₖ>t13】0)放大低频(λₗt29】1),负特征值(ₖ>t17】0)放大高频(λₗt31】1)[33 ]。*****

如果 W 的负特征值比正特征值【35】大得多,那么排斥力和高频占主导地位。在相反的情况下,低频占主导地位,导致极限t→∞1,36】中的过度平滑。

此外,负特征值{ ₖ < 0}的影响等同于翻转边的符号;这是为嗜异性数据集[37]提出的一种启发式方法,最近在我们关于神经层扩散 T26 的 NeurIPS 论文[4]中也被赋予了代数拓扑动机。

基普夫&韦林公司

我们应该强调的是,虽然 GRAFF 是一个允许将 gnn 导出为任何能量泛函的离散梯度流的通用框架,但是从我们的二次能量ℰᶿ中产生的模型是标准的卷积型 gnn。梯度流形式主义为他们的行为以及如何做出正确的架构选择提供了重要的见解。

我们的分析的一个结果是,如果信道混合矩阵具有足够负的特征值,卷积 GNNs 可以处理图异构。这与图形 ML 文献中经常重复的相反的“民间传说”陈述相矛盾。

然而,有一个重要的细微差别:由于我们使用欧拉离散化,我们总是有一个残差 GCN 模型。这个架构特征被证明是至关重要的:我们证明了一个没有剩余连接的模型(即迭代公式为X(t+τ)=τāX(t)W最初由 Kipf 和 Welling [5]提出)只能诱导独立于W的谱的 LFD 动力学****

其次,我们的模型是残差 GCNs 的特定版本,其中信道混合矩阵是对称的,并且跨层共享。这也与 graph ML 社区中的常见做法相矛盾:通常,多层 GCN 模型每层都有不同的通道混合矩阵,并且还包括非线性激活[39]。我们通过实现 GRAFF 模型来证明这是不必要的,其中演化方程是线性的,唯一的非线性是在特征编码器和解码器中。

不同同质性水平数据集上的节点分类精度。GRAFF 及其非线性版本(GRAFF-NL)实现了与最近一些专门为嗜异性设置设计的方法(如 GGCN 和 GPRGNN)相当或更好的结果,同时在计算复杂性和参数数量方面明显更轻便。表来自[6]。

考虑到我们的理论和实验结果,简单的图卷积证明了简单的图卷积是正确的:我们得出结论,简单的图卷积在许多实际情况下足够强大,其性能与复杂得多的 GNN 模型相当,甚至更好。

简单图卷积模型反击。原始迷因:米哈伊尔高尔金。

从演化方程到能量

梯度流形式主义为 GNNs 的设计带来了一种新的思维模式:我们不是将演化方程参数化,而是将梯度流最小化的能量参数化[41]。我们已经证明,通过这种方式,人们可以做出更明智的设计选择,并为 GCNs 等“旧”模型带来新的生命。

人们可能想知道如何处理现有的进化方程不是梯度流的 gnn?GRAFF 在这种情况下仍然提供了重要的见解:例如,我们表明,如果权重是对称的,使用非线性激活的更一般的卷积模型仍然会降低能量ℰᶿ[42]——再次注意,从通用近似的角度来看,这不是限制性的[22],事实上为在图形神经网络中使用对称权重提供了更具理论原则性的理由。

我们的分析概括了现有的结果[2,4],这些结果监测了用 ReLU 激活的 Kipf-Welling GCNs 中的狄利克雷能量ℰᴰᴵᴿ:我们考虑了更广泛的一类能量以及无限类非线性激活函数。我们相信,这种方法可以提供一种新的视角,通过考虑哪种能量泛函沿着学习的节点特征减少来分析新旧 GNNs 的学习动力学。

更广泛地说,GRAFF 是一种受 T2 物理学启发的图形学习方法,我们最近已经看到了几个这样的例子,包括我们自己的作品。这种方法的主要思想是使用物理系统作为学习的隐喻,并通过系统的状态来参数化解的空间。在某种意义上,这是对物理信息神经网络 (PINN)的补充,后者将物理定律作为其归纳偏差,以便更好地逼近现实生活中的物理系统。

受物理学启发的方法的一个重要方面是,它们带来了不同于 graph ML 中传统使用的工具。例如,GNNs 的表达能力通常通过诉诸消息传递和 Weisfeiler-Lehman 图同构测试【45】之间的等价性来分析。后者通常限制太多,因为它假设信息传播在输入图上完成,而在实施某种形式的图重布线的实际 gnn 中,情况往往不是这样[46]。

通过研究动力系统的渐近行为(例如,扩散方程[4]的极限),人们可以表达 GNNs 的分离能力,而无需求助于 WL 形式。这种技术自然允许图形重新布线,这假定了对基础微分方程的不同离散化的解释。

我们的工作表明,物理启发的方法甚至可以在以前研究得很好的图形学习模型中提供新的见解,并将鼓励在这个方向上的更多研究。

[1] K. Oono 和 t .铃木,图神经网络对节点分类的表达能力呈指数级丧失 (2020) ICLR。

[2]蔡春华,王永元,.关于图神经网络过光滑问题的一个注记.(2020)arXiv:2006.13318 .

[3] J. Zhu 等,超越图神经网络中的同向性:当前的局限与有效设计 (2020) NeurIPS

[4] C .博德纳尔,f .迪·乔瓦尼等,神经束扩散:GNNs 中异嗜性和过度光滑的拓扑透视(2022) NeurIPS 。参见附带的博文

[5] T. Kipf 和 M. Welling,带图卷积网络的半监督分类 (2017), ICLR

[6] F. Di Giovanni,J. Rowbottom 等人,将神经网络图化为梯度流 (2022),arXiv:2206.10991。

[7] E. Haber 和 L. Ruthotto,深度神经网络的稳定架构(2017) 逆问题 34 (1)。

[8] R. Chen 等,神经常微分方程 (2019) NeurIPS。

[9]梯度流可被视为最陡下降法的连续版本,该方法最初由 A.-L .柯西、méthode générale pour la résolution des systèmes d 'éequations simultanées(1847)Comptes Rendus de l ' académie des Sciences提出,用于解方程组(该方法出现在术语梯度之前,后者由 Horace Lamb 于 2004 年提出术语“流”来自流体力学,粒子系统的一个重要设置。

[10]梯度流单调减少底层能量的事实源于∂/∂tℰ(x(t)= –||∇ℰ(x(t))| |。

[11] J .傅立叶,https://archive.org/details/bub_gb_TDQJAAAAIAAJ(1822)。傅立叶在 1807-1811 年间发展了后来成为同名的分析。这项工作在接下来的十年里没有被公开,因为他的职责是伊泽尔省的省长,这是一个由拿破仑亲自任命的高级职位(他在埃及的战役中就认识傅立叶)。****

[12] P .佩罗娜和 j .马利克,使用各向异性扩散的尺度空间和边缘检测 (1990),PAMI12(7):629–639。**

[13]例如,参见我们的论文 B. Chamberlain,J. Rowbottom 等人,GRAND:Graph Neural Diffusion(2021)ICML,附带的博文,以及其中的许多参考文献。**

[14]我们使用对称归一化图拉普拉斯算子δ= I–ā,其中ā= dᐨᐟadᐨᐟ是归一化邻接矩阵。我们的分析可以针对拉普拉斯算子的其他变体进行重复,参见[6]中的附录 A.2。

[15]ℰᴰᴵᴿ的二次型表达式允许导出图傅立叶基(图拉普拉斯的正交特征向量)为φ= arg mintrace(xδxs . t .xx=I,这可以解释为狄利克雷能量意义上的“最光滑正交基”。

[16]更正确的说法是 X (0)在 ker(δ)上的投影。对于归一化的拉普拉斯算子,扩散方程的极限是节点度数的向量。对于非规格化的拉普拉斯δ= I-A,结果是一个常数向量。

[17]固定扩散在某些情况下是有用的。比如 D. Zhou 和 b . schlkopf 提出的标签传播(label propagation),离散空间上的正则化(2005),联合模式识别研讨会,是一个带边界条件(已知节点标签)的扩散方程,是很多直推式图 ML 问题的很好的基线。在最近的一篇论文中,E. Rossi 等人,关于在具有缺失节点特征的图上学习的特征传播的不合理有效性 (2021),arXiv:2111.12128 表明特征传播在具有缺失特征的同形图上有效地工作。****

[18]欧拉离散化(也称为显式前向方案)用前向时差、(t)≈(x(t+τ)–x(t)/代替时间导数这总是导致剩余*架构。*****

[19]我们在这里采用了我们书中的“GNN 风味”术语,M. M. Bronstein 等人,几何深度学习:网格、组、图、测地线和规范 (2021) arXiv:2104.13478。在这种情况下,卷积类型的 gnn 可以写成以下形式:X(t+τ)=AX(t))(更新由与特征无关的矩阵完成), 注意力x(t+τ)=a(x(t)x(t)(特征相关矩阵值函数)*消息传递*******

[20] ℰᶿ = ℰᴰᴵᴿ当ω=w=I。在[6]的附录 B.5 中,我们还表明ℰᶿ可以认为是一个离散版的谐波能量ℰ(x)=∫⟨∇x(u),∇x(u)⟩du一个流形嵌入x:ℳ→ℝ******

[21]参见[6]中的公式 10。直观上注意如果 x x 是相邻节点特征并且都是满足wx=xWx 的特征向量 wx⟩=xx ⟩和我们看到,如果> 0 那么 x < 0 反之亦然。********

[22] S. X. Hu,S. Zagoruyko 和 N. Komodakis,探索深度神经网络中的权重对称性(2019) 计算机视觉和图像理解,187 表明具有对称权重的神经网络是通用近似器。

[23]本文中的“频率”是指归一化图拉普拉斯的频谱分解,提供了傅立叶基础的类比。节点特征可以写成拉普拉斯正交本征向量的线性组合,对应的特征值在 0 ≤ λₗ ≤ 2 的范围内。第零特征值对应于恒定的特征向量(使用谐波分析术语的‘DC’);对应于较大特征值的特征向量不太光滑,并且具有较高的狄利克雷能量。

[24]见[6]中的定义 3.1。注意,LFD/HFD 动力学的定义是通用的,不要求演化方程是梯度流。

[25] J .克利茨佩拉等,扩散改善图形学习 (2019) NeurIPS

[26]吴等,简化图神经网络 (2019)

[27]经典例子是分离二部图的的最大特征向量。参见 D. Bo 等人,超越图卷积网络中的低频信息(2021) AAAI****

[28] L.-P. Xhonneux 等人,连续图神经网络 (2020) ICML

[29] M. Eliasof、E. Haber 和 E. Treister。PDE-GCN:由偏微分方程驱动的图形神经网络的新架构(2021) NeurIPS

[30]文献[6]中的定理 3.3。

[31]p . veli kovi 等人,图形注意网络 (2018) ICLR

[32]文献[6]中的定理 3.2。

[33]文献[6]中的定理 4.1。

[34]我们表明,可以根据图形和通道混合频率明确地写出每一层的学习节点表示,从而得出每一个主导效应。这种对动力系统的“剖析”也强调了 W 的光谱和特征向量比条目本身更重要。

[35]在[6]中的方程 13 的意义上。

[36] H. Nt 和 T. Maehara,重新审视图形神经网络:我们所拥有的只是低通滤波器(2019) arXiv:1812.08434v4。

[37]d . Bo 等人在《超越图形卷积网络中的低频信息》(2021)和 Y. Yan 等人在《同一枚硬币的两面:图形卷积神经网络中的异嗜性和过度平滑》(2021) arXiv:2102.06462 中使用了异嗜性数据集的负边缘加权。

[38]文献[6]中的定理 4.3。

[39]没有非线性激活(σ= id)anm-层 gcnx(t+τ)=σ(σ(āσ(ax(t)w 可以写成单层x(t+)=τāx(t)wm -hop 扩散ā通过吸收 这个特性在[26]中被用于一个被称为简化 GCN (SGCN)的建筑。这种方法的优点是扩散特征āx可以预先计算,允许将 gcn 缩放到非常大的图,如我们的论文 Frasca 等人的sign:scalable inception graph neural networks(2020)icml workshop on graph re presentation learning and beyond以及附带的博客帖子所示。注意,这种简化不会发生在 GCN 的残差版本中,如[6]中的方程(34)所示。********

[40]在[6]中的方程 17。

[41]我们注意到,“最小化”在这里指的是能量沿着演化方程的行为(即,在通过网络的正向传递期间),并且不同于用于学习的行为(即,通过反向传播最小化关于模型参数的一些特定任务损失函数)。

[42]文献[6]中的定理 5.1。在我们最近的工作中,Dirichlet 能量的指数衰减被用于形式化超光滑现象[43]。

[43] B. P. Chamberlain 等人, Beltrami 流和图形上的神经扩散 (2021) NeurIPS。

[44] T. K. Rusch 等人,图耦合振荡器网络 (2022) ICML

[45] B. Weisfeiler 和 A. Lehman,将图简化为标准形式和其中出现的代数(1968)Nauchno-techniceskaya informatisia2(9):12–16。WL 与用内射聚合器传递消息的等价性在例如 K. Xu 等人的文章中示出。图神经网络有多强大? (2019) ICLR 。参见我们的博客文章**

[46]传统的 gnn 使用输入图来传播信息,通过这种方式获得反映图的结构和其上的特征的表示。然而,由于“瓶颈”导致来自太多节点的信息被“挤压”到单个节点表示中,一些图对信息传播不太友好,这种现象被称为“过度压制”。现代 GNN 实现通过将输入图与计算图解耦(或为计算目的对其进行优化)来处理这种现象,这是一套被称为“图重布线”的技术。在我们最近的论文 J. Topping,F. Di Giovanni 等人的通过曲率理解图的过度挤压和瓶颈(2022)ICLR中,我们将重布线与图曲率和 Ricci 流联系起来。参见我们的博客文章**

我们非常感谢大卫·艾纳德、尼尔斯·哈默拉、托马斯·基普夫、伊曼纽·罗西和康斯坦丁·鲁施对这篇文章的校对。关于图形深度学习的其他文章,请参见 Michael 在《走向数据科学》中的 其他帖子 订阅他的帖子和 YouTube 频道 ,获取 中等会员 ,或关注他的https://twitter.com/mmbronstein

超越 Weisfeiler-Lehman 和普通消息传递的图神经网络

原文:https://towardsdatascience.com/graph-neural-networks-beyond-weisfeiler-lehman-and-vanilla-message-passing-bc8605fa59a

图形学习的新蓝图

基于图的物理学启发的连续学习模型允许克服传统 GNNs 的限制

消息传递范式多年来一直是图形深度学习的“战马”,使图形神经网络在从粒子物理到蛋白质设计的广泛应用中取得了巨大成功。从理论角度来看,它建立了与 Weisfeiler-Lehman 等级的联系,允许分析 GNNs 的表达能力。我认为,当前图形深度学习方案的“以节点和边为中心”的思维模式施加了不可逾越的限制,阻碍了该领域的未来进展。作为替代方案,我提出了受物理学启发的“连续”学习模型,该模型从微分几何、代数拓扑和微分方程领域开辟了一个新的工具宝库,迄今为止,这些领域在 graph ML 中基本上没有被探索过。

图片:Shutterstock。迷宫隐喻:多米尼克·比艾尼。

本文基于克里斯蒂安·博德纳尔、董晓文、本·张伯伦、大卫·艾纳德、法布里齐奥·弗拉斯卡、弗朗切斯科·迪·乔瓦尼、玛利亚·戈里诺瓦、皮埃特罗·里ò、朱利亚·路易斯、锡德·米什拉、吉多·蒙图法尔、伊曼纽·罗西、康斯坦丁·鲁施、尼娜·奥特、詹姆斯·罗博顿、杰克·托平、于·王光和斯特凡·韦布的近期作品。另见我之前关于 图神经网络通过微分几何和代数拓扑 的帖子。

图是抽象复杂的关系和交互系统的一种便捷方式。从社交网络到高能物理再到化学,图结构数据的日益突出(所有这些都处理相互交互的对象,无论是人、粒子还是原子),这些应用中的一系列初步成功,以及工业采用,使图的深度学习成为机器学习研究的最热门话题之一[1]。到目前为止,图形神经网络(GNNs)是图形 ML 方法中最常见的,并且在撰写本文时,是最流行的神经网络架构之一[2]。

图形抽象了复杂的关系和交互系统。从左到右显示:分子图(代表构成分子的原子之间的化学键)、社交网络(代表用户之间的关系和交互)、推荐系统(代表用户和产品之间的关联)。

GNNs 是如何工作的?图形神经网络将具有节点和边特征的图形作为输入,并计算取决于特征和图形结构的函数。消息传递型 gnn(也称为 MPNN [3])通过在相邻节点之间交换信息来传播图上的特征。典型的 MPNN 架构包括几个传播层,其中每个节点基于其邻居特征的集合进行更新。不同形式的聚合函数(是参数化的,其参数在训练期间学习)产生了三种不同的图形神经网络“味道”:【卷积】(相邻特征的线性组合,权重仅取决于图形的结构)(线性组合,权重也取决于特征)(一般非线性函数)【4】。在这三种味道中,后者是最普遍的,而前者可以被看作是信息传递的特例。**

GNNs 的三种“味道”,从左到右:卷积、注意力和一般非线性消息传递味道。所有这些都是信息传递的形式。图改编自 P. Velič ković。

传播层由基于下游任务学习的参数构成。典型的用例包括节点 嵌入(将每个节点表示为向量空间中的一个点,以这种方式,这些点的接近程度恢复了原始图的连通性,这种任务称为“链接预测”),节点方式的分类或回归(例如,推断社交网络用户的属性),或图方式的预测,通过进一步聚合节点方式的特征(例如,预测分子图的化学属性)。

消息传递 GNNs 怎么了?

D 尽管 GNNs 在所有方面都取得了令人印象深刻的成功,并且最近的研究具有显著的广度和深度,但公平地说,当前图形深度学习方案的主要模型是采用图形并通过消息传递的方式沿其边缘传播节点信息。我相信正是这种“以节点和边缘为中心”的思维模式设置了阻碍该领域未来发展的主要障碍。我在下面概述了当今一般 gnn 的一些突出的局限性:

魏斯费勒-雷曼类比是有局限性的。适当选择求和等局部聚合函数[5]使得消息传递等同于 Weisfeiler-Lehman 图同构测试[6],允许图神经网络从信息在其上传播的方式中发现图的某些结构。这种与图论的重要联系[7]已经产生了关于 GNNs 表达能力的多种理论结果,确定了图上的某些函数是否可以通过消息传递的方式来计算[8]。然而,这种类型的结果通常不能说明这种表示的效率(即计算一个函数需要多少层)【9】,也不能说明 GNNs 的泛化能力。

Dominique Beaini 为 Weisfeiler-Lehman 测试提出了一个比喻:试图通过在没有地图的情况下行走来理解迷宫的结构。位置编码提供了迷宫的“地图”,而重新布线则提供了爬过“墙”的梯子。

Weisfeiler-Lehman 算法甚至无法检测简单的图形结构,如三角形,这让试图将信息传递神经网络用于分子图形的从业者非常失望:例如,在有机化学中,环等结构非常丰富,并在分子行为方式中起着重要作用(例如,芳香环因其在萘等具有强烈气味的化合物中的突出地位而得名)。

十氢萘(左)和双环戊基(右)的两个分子图的例子,它们在结构上不同(一个有 6 个环,另一个有 5 个环),但是不能通过 Wesifeiler-Lehman 测试来区分。

在过去的几年中,已经提出了几种更具表现力的 GNN 模型的方法。这些包括 Weisfeiler-Lehman 层次结构中的高维同构测试10,将 wes feiler-Lehman 测试应用于子图集合[11],或者对图的节点进行“着色”的位置或结构编码[12],从而帮助打破“混淆”Weisfeiler-Lehman 算法的规律性。位置编码是迄今为止在变形金刚[13]中流行的最常见的技术,现在在 GNNs 中无处不在。虽然存在多种位置编码,但公平地说,特定的选择是依赖于应用程序的,而是凭经验的。

位置编码示例。从左到右显示:随机特征、拉普拉斯特征向量(类似于变形金刚中使用的正弦曲线)、结构特征(三角形和矩形的数量)。

图重布线打破了 GNNs 的理论基础。【GNNs 和 CNN 之间的一个重要而微妙的区别是,图形既是输入的部分,也是的计算结构。传统的 gnn 使用输入图来传播信息,通过这种方式获得反映图的结构和其上的特征的表示。然而,由于某些结构特征(“瓶颈”),一些图对信息传播不太友好,导致来自太多节点的信息被“挤压”到单个节点表示中,这种现象被称为“过度挤压”[14]。****

现代的 GNN 实现通过将输入图与计算图解耦(或者为了计算的目的对其进行细化)来处理这种现象,这种技术被称为“图重布线”。重新布线可以采取邻域采样的形式(如 GraphSAGE [15]中所做的,最初是为了处理可扩展性)、虚拟节点[16]、连通性扩散[17]或进化[18]或者节点和边缘丢失机制[19]。变形金刚和 GAT [20]等注意力型 gnn 通过给每条边分配不同的权重,有效地“学习”了一个新图,这也可以理解为一种“软”重新布线的形式。最后,“潜在图形学习”方法建立一个特定任务的图形,并在每一层更新它21也可以归入这一类。总的来说,如果说几乎没有现代 GNN 模型在原始输入图上传播信息,这可能只是稍微夸大了情况。

GNNs 中使用的不同图形重布线技术。从左到右:原图、邻域采样(如 GraphSAGE [15])、注意(如 GAT [20])、连通性进化(如 DIGL [17])。

然而,这对于依赖于消息传递的等价性和 Weisfeiler-Lehman 测试的理论分析来说是个坏消息,weis feiler-Lehman 测试从信息在图上传播的方式获得对图的描述。重新布线打破了这种理论联系,将我们置于机器学习中并不罕见的情况:理论上可以分析的模型与实践中使用的模型并不相同。

图的“几何”太差。图形神经网络可以作为“几何深度学习蓝图”[22]的一个实例获得,这是一个群论框架,允许从数据下的域的对称性中导出深度学习架构。在图的情况下,这种对称性是节点置换,因为图没有规范的节点排序。由于这种结构特征,在图上局部操作的 MPNNs 必须依赖于置换不变特征聚合函数,这意味着图上没有“方向”的概念,并且信息的传播是各向同性的【23】。这种情况与在连续域、网格甚至网格上学习明显不同[24],并且是对 GNNs 的早期批评之一,认为各向同性滤波器不是很有用[25]。**

左图:网格是具有局部欧几里得结构的离散流形。相邻节点被定义为旋转,允许“方向”的概念。右图:图的结构较少,相邻节点被定义为排列。

****图的“几何”太丰富了。“距离而非方向”的问题也与构建节点嵌入时遇到的问题有些关系,在构建节点嵌入时,某个空间中的节点表示之间的距离用于捕捉图的连通性(粗略地说,嵌入空间中靠近的节点预期由图中的边连接)。典型的用例是推荐系统,其中图嵌入用于在由节点表示的实体(例如,在 Twitter 上关注谁)之间创建关联(边)。

图形嵌入的质量和它们表达图形结构的能力主要取决于嵌入空间的几何形状及其与图形“几何形状”的兼容性。欧几里得空间是表示学习的真正“战马”,也是迄今为止最简单、最方便的工作对象,但对于许多自然图来说,它却是一个相当糟糕的选择:原因之一是欧几里得度量球的体积增长在半径上是多项式的,但在维度上是指数的[26],而许多真实世界的图表现出指数的体积增长[27]。结果,嵌入变得“太拥挤”,迫使使用高维空间,这导致更高的计算和空间复杂度。

最近流行的一种替代方法是使用负曲线(双曲线)空间[28],这种空间的指数体积增长与图[29]的指数体积增长更兼容。双曲几何的使用通常导致更低的嵌入维数,从而导致更紧凑的节点表示。然而,图通常倾向于异质(即,一些部分可能看起来像树,而其他部分像集团,具有非常不同的体积增长属性),而双曲嵌入空间是同质的(每个点都具有相同的几何形状)。

此外,通常不可能在嵌入空间[30]中精确地表示一般图形的度量结构,即使该空间具有非欧几里德几何。因此,图嵌入不可避免地近似。然而,更糟糕的是,因为嵌入是用“链接预测”标准构建的,所以高阶结构(三角形、矩形等)的失真。)可能会大得无法控制[31]。在一些应用中,包括社会和生物网络,这种结构发挥着重要作用,因为它们捕捉更复杂的非配对相互作用和基序[32]。

图形主题是高阶结构的例子。这种结构已经在许多生物现象的模型图中观察到。图:米洛等人。

当数据的结构与底层图形的结构不兼容时,gnn 就会陷入困境。许多图学习数据集和基准对数据同向性做出默认假设(即相邻节点的特征或标签相似,或者,使用信号处理术语,“平滑”)。在这种设置下,即使简单的低通滤波(例如,取邻居平均值)也能很好地工作。早期的基准,包括仍然无处不在的 Cora 数据集,是在具有高度同向性的图上进行的,这使得 GNNs 的评估“太容易了”。

嗜同性(左)和嗜异性(右)数据集。在前一种情况下,节点特征或标签的结构与图的结构兼容(即,节点与其邻居“相似”)。相似节点用匹配颜色表示。

然而,当处理嗜异性数据时,许多模型显示出令人失望的结果,在这种情况下,必须使用更细微的聚合[33]。在这种情况下观察到的两个典型现象是完全避免使用邻居信息(因此 GNNs 本质上归结为节点式多层感知器)或“过度平滑”,即节点表示的现象随着 GNN 的每一层变得更加平滑,最终崩溃为单个点[34]。后一种现象也发生在嗜同性数据集,似乎是一些类型的 MPNNs 的更基本的困境,使得难以实现深度图学习模型 [35]。

****通常很难理解 GNNs 学什么。对深度学习系统的一个批评特别适用于 gnn:这些是难以解释的“黑箱”。虽然可解释性是一个有点模糊的范畴,很大程度上取决于旁观者的观点,但我们可以诚实地承认,在大多数情况下,我们并不真正理解 gnn 所学的东西。最近的几项工作试图通过以紧凑的子图结构和在 GNN 的预测中起关键作用的节点特征的小子集的形式为基于 GNN 的模型提供“解释”来减轻这一缺点[36]。潜在图形学习架构[21]学习的图形也可以看作是“解释”的一种形式。

限制通用的消息传递函数有助于排除不可信的输出,并确保 GNN 学习的内容有意义,并在特定领域的应用中得到更好的理解。特别是,有可能赋予消息传递额外的“内部”数据对称性,以便更好地“理解”潜在的问题[37]。一个完美的例子是 E(3)-等变消息传递,它正确地处理了分子图中的原子坐标,最近为蛋白质结构预测架构的胜利做出了贡献,如 AlphaFold [38]和 RosettaFold [39]。

另一个例子是 Miles 和 Kyle Cranmer 合著的工作(没有家庭关系)[40],其中在多体动力系统上学习的消息传递功能被符号公式取代,允许“学习物理方程”。最后,有人试图将 GNNs 与因果推理[41]联系起来,在这种情况下,人们试图构建一个解释不同变量之间因果关系的图。总体来说,这还是一个处于起步阶段的研究方向。

不同的“可解释的”GNN 模型(从左到右):图形解释器36,潜在图形学习[21]和等变信息传递。

大多数 GNNs 的实现都是硬件无关的。当今的大多数 gnn 依赖于 GPU 实现,并默认数据适合内存。在处理生物和社交网络等大型图表时,这往往是一厢情愿的想法。在这种情况下,了解底层硬件的限制,如不同的带宽和内存层次的延迟,并有利地使用它是至关重要的。大致来说,同一物理内存中的两个节点和不同芯片上的两个节点之间的消息传递成本(例如,在延迟和功耗方面)可能存在数量级的差异。让 GNNs 对现有的硬件友好是一个重要而又经常被忽视的问题。考虑到设计新芯片所需的时间和精力,以及机器学习技术的发展速度,开发新型以图形为中心的硬件是一个更大的挑战。

“连续”模型作为图形学习的新蓝图

当前“离散”gnn 的一个新兴和有前途的替代方案是“连续”学习模型,其受物理系统的启发,并从微分几何、代数拓扑和微分方程领域开辟了一个新的工具宝库,迄今为止在 graph ML 中基本上没有探索过。

****把基因想象成连续的物理过程。我们可以考虑在连续时间内在某个域(也可以是连续的,例如流形,并离散为图)上发生的物理过程(代替离散层),而不是在图上传递多层消息。时空中某一点的过程状态,取代了 GNN 层所产生的图形中某个节点的潜在特征。该过程由一组参数(代表底层物理系统的属性)控制,这些参数取代了消息传递层的可学习权重。

从经典和量子系统中可以构建出大量不同的受物理启发的过程。在一系列论文[42–44]中,我们已经表明,许多现有的 gnn 可能与扩散过程有关,这可能是传播信息的最“自然”的方式,但其他更奇特的方式,如耦合振荡器系统[45]也是可能的,并可能提供某些优势。

图形耦合振荡器系统的动力学[45]。

连续系统在时间和空间上都可以离散化。空间离散化,以连接连续区域上邻近点的图形的形式,并且可以在整个时间和空间中改变。这种学习范式彻底背离了传统的 Weisfeiler-Lehman 方案,该方案受到基础输入图假设的严格限制。更重要的是,它带来了一套新的工具,至少在原则上允许解决现有图论技术目前无法解决的重要问题。

2D 拉普拉斯算子的不同离散化。

作为最优控制问题的学习。过程在给定时刻的所有可能状态的空间,可以看作是可以表示的函数的一个“假设类”。以这种方式学习被提出为最优控制问题[46],即,是否可以控制过程(通过选择参数空间中的轨迹)以使其达到某个期望的状态。表达能力可以表述为是否可以通过在控制过程的参数空间中适当选择轨迹来达到给定的功能(使用最优控制理论的术语“可达性”);效率与达到某个状态需要多长时间有关;而泛化关系到这个过程的稳定性。

作为控制问题的学习:飞机是一个物理系统的隐喻,其 xyz 坐标(“系统状态”)通过操纵推力、副翼和方向舵(“参数空间”)来控制。

****GNNs 可以从离散化的微分方程中导出。物理系统的行为通常由微分方程控制,其解产生系统的状态。在某些情况下,这种解决方案可以推导出一个封闭的形式[47],但更普遍的是,一个人不得不求助于数值解决方案的基础上适当的离散。经过一个多世纪的研究,数值分析文献中积累的不同迭代求解器的财富为图形深度学习提供了潜在的全新架构。

例如,我们在[42]中表明,GNNs 的注意力味道可以解释为离散化的扩散 PDEs,具有使用显式数值方案求解的可学习的扩散率。在这种情况下,求解程序的每次迭代(时间上的离散步长)都对应于 GNN 的一个图层。更复杂的求解器,例如使用自适应步长或多步方案,目前在 GNN 建筑的“动物园”中没有直接的类比,但可能会导致未来的建筑洞察力。隐式方案需要在每次迭代中求解线性系统,可以解释为“多跳”滤波器[48]。此外,数值方案具有稳定性和收敛性保证,当它们工作时提供条件,当它们失败时提供理解[49]。

数值解算器可以是硬件友好的。迭代求解器比数字计算机更古老,从数字计算机诞生的那一刻起,它就必须意识到底层硬件并有效地利用它。科学计算中的大规模问题通常必须在计算机集群上解决,这些问题在集群中至关重要。

图形深度学习的“连续”方法允许以与模拟它们的硬件兼容的方式离散化基础微分方程,潜在地利用来自超级计算社区的大量文献,例如区域分解技术【50】。具体而言,可以使图形重新布线和自适应迭代求解器知道存储器层级,例如,在不同物理位置的节点之间执行少量不频繁的信息传输步骤,而在相同物理存储器中的节点之间执行更频繁的步骤。

****将进化方程解释为与物理系统相关的能量泛函的梯度流提供了对学习模型的洞察。许多物理系统都有相关的能量泛函(有时也包含某些对称性或守恒定律),其中控制系统动力学的微分方程是最小化梯度流[51]。例如,扩散方程最小化了狄利克雷能量[42],其非欧几里得版本(贝尔特拉米流)最小化了波利亚科夫泛函[43],给出了学习模型正在做什么的直观理解。利用最小作用量原理,某些能量泛函产生双曲方程,如波动方程。这类方程的解是“波动的”(振荡的),与典型的 GNNs 动力学有很大的不同。

分析此类流量的极限情况是一项标准工作,可提供对模型行为的深刻见解,否则很难获得这种见解。例如,在我们最近的论文【44】中,我们证明了传统的 GNNs(类似于各向同性扩散方程)必然导致过度光滑,并且只有在同质性假设下才具有分离能力;通过在图上使用额外的结构(细胞束),可以获得更好的分离能力[52]。在另一篇最近的论文[45]中,我们证明了一个振荡系统避免了极限中的过度振荡。这些结果可以解释为什么在一些 GNN 建筑中会出现某些不良现象,以及如何设计建筑来避免这些现象。此外,将流动的极限情况与分离联系起来揭示了模型表达能力的界限。

图形可以被赋予更丰富的结构。我们已经提到,图形可能同时“太差”(即无法捕捉非成对关系等更复杂的现象)和“太丰富”(即难以在同质空间中表示)。处理前一个问题的方法是用额外的结构来“丰富”图。一个很好的例子是前面提到的分子图,其中包含环(图形术语中的环),化学家将其视为单个实体,而不仅仅是原子和键(节点和边)的集合。

在一系列工作[53–54]中,我们展示了图可以被“提升”到更高维度的拓扑结构,称为单纯型-细胞复合体,在此基础上可以设计一个更复杂的消息传递方案,不仅允许在传统 GNNs 中的节点之间传播信息,还允许在环(“细胞”)等结构之间传播信息。“提升”操作的适当构造使得这种模型比传统的 Weisfeiler-Lehman 测试更具表现力[55]。

左图:将图形提升为细胞复合体。右图:手机信息传递。图改编自[54]。

在最近的另一篇论文【44】中,我们展示了通过给节点和边分配向量空间和线性映射,图可以配备一个额外的“几何”结构,称为细胞层。传统的 GNNs 隐含地假设一个图具有平凡的底层,这反映在相关的扩散方程的性质和图的拉普拉斯算子的结构中。与传统的 gnn 相比,使层非平凡(并可从数据中学习)产生更丰富的扩散过程,并对其渐近行为给予更大的控制。例如,适当选择的层结构上的扩散方程可以在有限的多个类别中分离,即使在嗜异性设置中[52]。

从几何角度来看,层结构类似于连接,这是微分几何中描述向量在流形上平行传输的概念【56】。从这个意义上来说,我们可以把层学习看作是一种依赖于下游任务来进化图的“几何”结构的方式。我们表明,通过将层的结构组(使用代数拓扑术语的“限制图”)限制到特殊的正交组,允许节点特征向量仅旋转,可以获得有趣的见解。

建立在图上的细胞层由连接到每个节点的向量空间和连接它们的线性“限制图”组成。在几何术语中,这可以被认为是赋予图形“几何”,而限制映射类似于连接。

图中“几何”结构的另一个例子是曲率的离散模拟,这是微分几何领域中描述流形局部行为的标准工具。在[18]中,我们表明负图 Ricci 曲率产生篡改图上信息流的“瓶颈”,并导致 GNNs [14]中的过压制现象。离散 Ricci 曲率说明了在许多应用中很重要的高阶结构(三角形和矩形)。这种结构对于传统的图嵌入来说“太丰富了”,因为图是异质的(具有非恒定曲率),而通常用于嵌入的空间,甚至是非欧几里得空间,是同质的(恒定曲率)。

在另一篇最近的论文[57]中,我们展示了一种具有可控 Ricci 曲率的异构嵌入空间的构造,可以选择这些嵌入空间来匹配图的曲率,从而不仅可以更好地表示邻域(距离)结构,还可以更好地表示更高阶的结构,如三角形和矩形。此类空间被构造为齐次和旋转对称流形的乘积,并允许使用标准黎曼梯度下降法进行有效优化[58]。

左图:具有恒定的正、零和负 Ricci 曲率的空间形式(球面、平面和双曲面)及其具有相应离散 Forman 曲率的图形类比(团、网格和树)。中间:一个乘积流形(圆柱体可以认为是一个圆和一条线的乘积)。右图:变曲率异质流形及其图形类比。详见[57]。图:弗朗西斯科·迪·乔瓦尼。

****位置编码可以被视为域的一部分。将图形视为连续流形的离散化,可以将节点位置和特征坐标视为同一空间的不同维度。在这种情况下,该图可用于表示由这种嵌入诱导的黎曼度量的离散模拟,与嵌入相关的调和能量是狄利克雷能量的非欧几里得扩展,在弦理论中称为波利亚科夫泛函[59]。这种能量的梯度流是一个扩散型方程,它发展了位置和特征坐标[43]。在节点的位置上构建图形是特定任务图形重新布线的一种形式,它也随着扩散的迭代(层)而改变。

通过重新布线的 Beltrami 流,Cora 图的位置和特征分量的演变(颜色表示特征向量)。动画:詹姆斯·罗博特姆。

****域的进化取代了图的重布线。扩散方程也可以应用于图的连通性,作为预处理步骤,旨在改善信息流和避免过度抑制。克利茨佩拉等人[17]提出了一种基于个性化页面排名的算法,这是一种图形扩散嵌入的形式。在[18]中,我们分析了这个过程,指出了它在异构环境中的问题行为,并提出了一个替代的图形重布线方案,该方案是由 Ricci 流启发的。这种重新布线减少了导致图形瓶颈的负向弯曲边的影响。 Ricci 流是流形的几何演化方程,非常类似于应用于黎曼度量的扩散方程,并且是微分几何中流行且强大的技术,包括著名的庞加莱猜想的证明。更一般地说,我们可以考虑一个演化过程的耦合系统,而不是作为预处理步骤来执行图的重新布线:一个演化特性,另一个演化域(图)。

上图:一个哑铃形的黎曼流形,具有负弯曲的瓶颈(负曲率由冷色编码),经历了基于曲率的度量演化,变得“更圆”,更少“瓶颈”。下图:基于曲率的图形重布线的类似过程,减少了瓶颈,使图形对消息传递更友好。参见我们的博客文章了解更多详情。图:杰克托普。

结束语

这真的是新的吗?我们必须避免陷入的一个陷阱是,新模型基于“名义上”的花哨的数学形式主义,而底层模型仍然大致做着上一代 gnn 所做的事情。例如,人们可以认为[44]中研究的层扩散是消息传递的一个特例。微分几何[18,43]和代数拓扑学[44,53–54]的工具使深刻的理论结果成为可能,这使我相信这已经不太可能了。然而,新的理论框架能带我们走多远,以及它是否能够解决该领域目前尚未回答的问题,仍然是一个开放的问题。

这些方法会在实践中实际使用吗?对于实践者来说,一个至关重要的问题是这些方法是否会产生新的更好的架构,或者仍然是一个脱离现实世界应用的理论装置,仅仅用于证明定理。我相信该领域将是务实的,通过拓扑和几何工具获得的理论见解将允许为现有的 GNN 架构做出更好的选择,例如,如何限制消息传递功能以及何时使用这种特定选择。

我们已经超越了信息传递吗?**最后,一个有点语义性质的问题是,所描述的方法是否仍然可以被称为“消息传递”。虽然观点可能各不相同,从将 GNN 的每一种形式都视为信息传递[60]到宣称需要超越这种范式[61],但我有点不愿意使用这个术语。在数字计算机上的任何计算都是一种信息传递的形式。然而,在 GNNs 的严格意义上的中,消息传递是一个计算概念,通过将信息从一个节点发送到另一个节点来实现,这是一个固有的离散过程。另一方面,所描述的物理模型以连续的方式在节点之间共享信息(例如,在图耦合振荡器的系统中,一个节点的动态取决于其邻居在每个时间点的动态)。当描述这种系统的微分方程被离散化和数值求解时,相应的迭代方案确实通过消息传递来实现。

然而,人们可以假设使用这种物理系统的实际实现[62]或其他计算范例,如模拟电子学或光子学[63]。在数学上,基本微分方程的解有时可以以封闭形式给出:例如,各向同性扩散方程的解是具有高斯核的卷积。在这种情况下,“邻居”的影响被吸收到内核的结构中,没有实际的“消息传递”发生。因此,这种模式的连续性需要一个更合适的术语——例如,在此时没有更好的想法的情况下,“空间耦合”或“信息传播”。作为一种计算原语,当与其他角度(如本文介绍的角度)协同应用时,消息传递现在和将来都可能是有用的。

通过真实物理系统反向传播的深度学习。图片:Wright 等人[61]。

[1]参见 ICLR 2021 年统计数据。

[2]我把变形金刚算作 GNNs 的实例。

[3]我使用术语“GNN”来指代任意图形神经网络架构,使用“MPNN”来指代基于本地消息传递的架构。

[4]卷积风格的典型代表是从图形信号处理领域出现的“光谱”图形神经网络,如 M. Defferrard 等人具有快速局部光谱过滤的图形卷积神经网络 (2016) NIPS 和 T. Kipf 和 M. Welling,具有图形卷积网络的半监督分类 (2017) ICLR。Petar Velič ković在[16]中介绍了注意力的味道,尽管人们可以考虑由 F. Monti 等人开发的 Monet 架构,使用混合模型 CNN(2017)CVPR 在图形和流形上的几何深度学习,作为对位置坐标的注意力形式。J. Gilmer 等人在《量子化学的神经信息传递》( 2017 年)ICML 使用了一种通用的信息传递形式和名称 MPNN。

我们在 M. M. Bronstein 等人的“原型书”几何深度学习:网格、组、图形、测地线和量规 (2021) arXiv:2104.13478 中采用的风味命名是由 Petar Velič ković提出的。在我这种二分法的早期版本中(如 MLSS Moscow 2019 的教程),我使用了术语“线性”(其中特征计算的形式为 Y = AX ,其中 A 通常是图邻接矩阵的某种形式)、“线性特征相关”(y=a(【t22 这比书中采用的符号更不通用,因为它假设基于总和的聚合。

[5]局部聚集函数必须是内射的。参见 K. Xu 等人图神经网络有多强大? (2019) ICLR。

[6] B. Weisfeiler 和 A. Lehman,将图简化为标准形式以及其中出现的代数(1968)。信息技术 2(9):12–16。

[7]参见 C. Morris 等人,Weisfeiler 和 Leman go 机器学习:迄今为止的故事(2021) arXiv:2112.09992,了解历史笔记和深入综述。

[8] Z. Chen 等人用 GNNs (2019) NeurIPS 关于图同构测试与函数逼近的等价性,给出了图同构测试与置换不变图函数逼近的等价性。

[9]例如,N. Dehmamy,A.-L. Barabási,于荣,理解图神经网络在学习图拓扑中的表示能力 (2019) NeurIPS 表明,学习图上的某些函数(某些阶的图矩)需要某些最小深度的 gnn。另见 F. Geerts 和 J. L. Reutter,《图形神经网络的表达能力和近似性质》( 2022 年), ICLR。

[10]所谓的严格递增权力的“k-WL 检验”的等级制度。拉斯洛·巴拜将 k 的发明归功于 WL 与鲁道夫·马顿尼尔·伊莫曼埃里克·兰德的独立测试。参见 L. Babai,拟多项式时间内的图同构 (2015),arXiv:1512.03547 第 27 页。

[11]已经有几篇论文提出在子图集合上应用 GNNs,包括我们自己的 B. Bevilacqua 等人,等变子图聚合网络 (2021) arXiv:2110.02910。见我们关于这个话题的帖子

[12]通过计数局部子结构的结构编码由 G. Bouritsas,f .弗拉斯卡等人在 GNNs 的背景下提出通过子图同构计数提高图神经网络表达能力 (2020)。arXiv:2006.09252。另见 P. Barceló等人的《具有局部图形参数的图形神经网络》( 2021) arXiv:2106.06707。

[13] A. Vaswani 等人,注意力是你所需要的全部 (2017) NIPS。

[14]过度抑制现象不是 GNNs 独有的,以前在 seq2seq 模型中也观察到过。但是,在体积呈指数增长的图表中,这种情况会变得特别严重。参见 U. Alon 和 E. Yahav,关于图神经网络的瓶颈及其实际含义 (2020)。arXiv:2006.05205 和我们的论文[14]对这一现象进行了描述和分析。

[15] W. Hamilton 等人,大型图上的归纳表示学习 (2017) NIPS 使用邻域采样来应对可扩展性。

[16] P. W .巴塔格利亚等人,关系归纳偏差、深度学习和图网络(2018),arXiv:1806.01261。

[17] J .克利茨佩拉等人,扩散改善图形学习 (2019) NeurIPS 通过个性化页面排名嵌入(一种“连通性扩散”的形式)使用重新布线。

[18] J. Topping,F. Di Giovanni 等人,通过曲率了解图的过度挤压和瓶颈 (2022) ICLR。

[19]丢弃可以在边或节点上完成,并且也导致更好的表达能力(原因类似于子图 GNNs),参见例如 Y. Rong 等人, DropEdge:走向节点分类上的深度图卷积网络 (2020)和 P. A. Papp 等人, DropGNN:随机丢弃增加了图神经网络的表达能力 (2021) arXiv:2111.06283。

[20]p . veli kovi 等人,图形注意网络 (2018) ICLR

[21]最早的“潜图学习”架构之一是我们的工作 Y. Wang et al. 用于在点云上学习的动态图 CNN(2019)ACM Trans .点云上的图形 38(5):146,其中初始的“位置编码”(点的 xyz 坐标)表示数据的几何形状,图形用于在相关部分之间传播信息。A. Kazi 等人考虑了更一般的情况,用于图卷积网络的可微分图模块(DGM)(2020)arXiv:2002.04999,其中没有明显的数据几何,并且为手头的任务学习适当的“位置编码”。另见我的关于主题的博文。

[22]在我的 ICLR 主题演讲中有更多关于这方面的内容。

[23]在图中进行“各向异性”传播的尝试有几种,最近的一种是 D. Beaini 等人的《定向图网络》(2020),arXiv:2010.02863,旧的一种是我们的论文 F. Monti,K. Otness,M. M. Bronstein,motif net:a motif-based Graph Convolutional Network for directed graphs(2018),arXiv:1802.01572。必须提供某种形式的外部信息,例如,在 DGNNs 的情况下,图的拉普拉斯特征向量的梯度,以及在 MotifGNNs 的情况下,一些选择的子结构。

[24] D. Boscaini 等人,利用各向异性卷积神经网络学习形状对应(2016) NIPS。

[25]例如,见 Ferenc Huszar 的博客文章

[26]回忆一下二维和三维体积的经典公式, πr 和 4π r /3:这些是 r 中的多项式。一个 2 n 维球的通式是 v =πt20】rt22】ⁿ/n!,显示出对 n 的指数依赖性。

[27]社会和生物网络等现实世界的图表显示出等级结构和与负曲率相关的幂律度分布。

[28] Q. Liu,M. Nickel,D. Kiela,双曲图神经网络(2019)。

[29]参见,例如,m .博古等人,网络几何学 (2021)《自然评论物理学》3:114–135。

[30]更正式地说,不存在等距嵌入,即没有办法在欧几里得空间中表示图的距离度量。一个简单的例子是建立在球赤道上的三个点和极点上的一个点上的图,所有这些点都有单位测地线距离。这样的图不能嵌入任何有限维的欧几里得空间。

[31] C. Seshadhri 等人,富三角形复杂网络的低秩表示的不可能性(2020),PNAS 117(11):5631–5637。

[32]r . Milo 等人在《网络主题:复杂网络的简单构建模块》( 2002)Science 298(5594):824–827 中提供了现实世界网络中高阶结构的经典证据。更多最近的结果,见 f .巴蒂斯顿等人,《超越成对相互作用的网络:结构和动力学》( 2020)物理学报告 874:1–92。

[33] J. Zhu 等,超越图神经网络中的同质性:当前的限制和有效设计(2020),NeurIPS。

[34]在 H. Nt 和 T. Maehara 的《再访图形神经网络:我们拥有的只是低通滤波器》( 2019) arXiv:1812.08434v4 和 K. Oono 和 t .铃木,《图形神经网络指数地失去对节点分类的表达能力》( 2020) ICLR。

[35]见我有点争议的上一篇。从那时起,已经出现了几个非常深的 gnn,但总的来说,这似乎比其他深度学习架构更难。

[36] R. Ying 等人,GNNExplainer:为图形神经网络生成解释(2019),NeurIPS

[37]在物理学中,通常区分空间的外部对称和场的内部对称。这在 Taco Cohen 的博士论文中解释得很透彻。

[38] J. Jumper 等人,用 AlphaFold 进行高度精确的蛋白质结构预测,Nature 596:583–589,2021。

[39] M. Baek 等人,使用三轨道神经网络准确预测蛋白质结构和相互作用,科学 373:871–876,2021。

[40] M. Cranmer 等人,从具有归纳偏差的深度学习中发现符号模型 (2020) arXiv:2006.11287

[41]m . ze EVI 等人将图形神经网络与结构因果模型联系起来(2021 年)arXiv:2109.04173。

[42] B. Chamberlain,J. Rowbottom 等人,GRAND:Graph Neural Diffusion(2021)ICML。

[43] B. P. Chamberlain 等人, Beltrami 流和图形上的神经扩散 (2021) NeurIPS。

[44] C .博德纳尔,f .迪·乔瓦尼等人,神经束扩散:对 GNNs 中异嗜性和过度光滑的拓扑透视(2022) arXiv:2202.04579。参见附带的博文

[45] T. K. Rusch 等人,《图形耦合振荡器网络》( 2022 年)ICML。

[46]深度学习问题作为最优控制的观点已经在例如 M. Benning 等人的《深度学习作为最优控制问题:模型和数值方法》( 2019) arXiv:1904.05657 中讨论过。

[47]欧几里得域ℝ 上的各向同性扩散方程的解析解作为与热核(δ初始条件下热方程的“基本解”)的卷积给出,这是形式为 h ( xyt)=(4πt)ⁿᐟexp()在非欧情况下,热核可以在拉普拉斯特征基中展开,并且是位置相关的(即 h ( xyt )不能像以前那样写成h(x-yt )。热核已广泛用于计算机图形和几何处理文献,包括 J. Sun、M. Ovsjanikov 和 L. Guibas 的著名热核签名,这是一种基于热扩散的简明且可证明信息丰富的多尺度签名(2009 年)《计算机图形论坛》28(5):1383–1392。马克斯·奥夫斯贾尼科夫小组最近在网格深度学习的背景下使用了类似的想法,参见 n .夏普等人,扩散网:表面上的离散化不可知论学习(2020) arXiv:2012.00888。

[48]弗拉斯卡等人, SIGN:可扩展的初始图神经网络 (2020)关于图表示学习的 ICML 研讨会。

[49]在我们的框架和研究数值格式特性的典型环境之间有一个微妙但重要的区别。在后一种情况下,人们感兴趣的是获得给定偏微分方程的精确数值解。在我们的例子中,我们使用一个偏微分方程的解来参数化一个函数空间,而不是求解一个特定的方程。

[50]区域分解方法将一个大规模问题分解成较小的子问题,这些子问题可以在多处理器机器上并行独立解决。通信仅沿着相邻子域的界面发生。

【51】一个梯度流可以看作是变分问题中梯度下降的连续类比。它源于泛函的最优性条件(变分法中称为欧拉-拉格朗日方程)。

[52]关于分离能力的结果,参见我们论文[44]中的定理 13、14、16、18、19、21 和 23,关于过度光滑的结果,参见定理 25-28。

[53] C .博德纳尔,f .弗拉斯卡等人,魏斯费勒和雷曼 go 拓扑:消息传递单纯网络 (2021) ICML。

[54] C .博德纳尔、f .弗拉斯卡等人,魏斯费勒和雷曼 go cellular:CW Networks(2021)neur IPS。参见附带的博文

[55]在某种程度上,更高维的 gnn 如 C. Morris 等人 Weisfeiler 和 Leman go neural:高阶图神经网络 (2019) AAAI,H. Maron 等人不变和等变图网络 (2019) ICLR,也可以归入这一类。

[56]联系是微分几何中描述流形上两个不同点处的切空间之间的关系的对象。它用于流形上向量的并行传输。关于图,A. Singer 和 H.-T. Wu 研究了离散版本,向量扩散图和连接拉普拉斯算子(2012)纯数学和应用数学通讯 65(8),他们也使用了术语“连接拉普拉斯算子”(它是我们具有正交限制图的细胞层的特定设置)。具有正交消息传递的图形神经网络已经由例如 K. Guo,Orthogonal Graph Neural Networks(2021)arXiv:2109.11338 进行了探索。

[57] F. Di Giovanni,G. Luise 和 M. M. Bronstein,曲率感知图嵌入的异构流形(2022) arXiv:2202.01185。

[58]黎曼优化是一类约束优化方法,其中假设数据点位于一个流形上。黎曼优化通过在局部切空间中操作在流形上执行梯度下降,参见 N. Boumal 的优秀参考文献,光滑流形上的优化介绍 (2022)。在我们构造的非均匀流形中,旋转对称因子只有一个坐标,参见我们论文[56]的 4.1 节。

[59] A .波利亚科夫,《玻色子弦的量子几何》( 1981 年)《物理学通讯》B 103:207。

[60]p . veli kovi,信息一路向上传递(2022) arXiv:2202.11097。

[61]参见我们对 2021 年的预测

[62] L. G. Wright 等人,用反向传播训练的深度物理神经网络(2022 年),《自然》601:549–555。

[63] R. Hamerly,深度学习的未来是光子 (2021) IEEE 频谱。

我感谢多米尼克·比艾尼、克里斯蒂安·博德纳尔、乔治·布里特萨斯、本·张伯伦、董小文、弗朗切斯科·迪·乔瓦尼、尼尔斯·哈默拉、哈盖·马龙、锡德·米什拉、克里斯多夫·莫利斯、詹姆斯·罗博顿和佩塔尔·韦利奇科维奇进行了富有成效的讨论和评论,其中一些内容非常充实,相当于“集体编辑”。不用说,任何遗留的遗漏或错误都是我的责任。

关于图形深度学习的其他文章,请参见《走向数据科学》中我的 其他帖子 订阅我的帖子 YouTube 频道 ,获取 中等会员 ,或者关注我的

Python 中的图形神经网络

原文:https://towardsdatascience.com/graph-neural-networks-in-python-c310c7c18c83

简介和逐步实施

最近,图机器学习领域发展迅速,该领域的大多数模型都是用 Python 实现的。本文将介绍图形的概念以及使用 Python 处理图形的一些基本方法。之后,我们将创建一个图卷积网络,并让它在 PyTorch 的帮助下在现实世界的关系网络上执行节点分类。这里描述的整个工作流程可以从的 Colab 笔记本中获得。

什么是图?

一个图,在其最一般的形式下,仅仅是节点以及节点之间的一组边的集合。形式上,一个图 G 可以写成 G = (V,E) ,其中 V 表示节点, E 表示相应的边集。有两种主要类型的图,有向图和无向图。有向图的边从它们的原点 u 节点指向目标节点 v ,而无向图中的边是没有方向的,因此( u,v)e(v,u)e .图可以用一个可以通过让每个节点索引特定的行和列来创建该矩阵。然后,边的存在可以被表示为邻接矩阵中的条目,意味着如果( u,v)∈EA [ uv ] = 0,则 A [ uv ] = 1,否则。如果图仅由无向边组成,邻接矩阵将是对称的,但是如果图是有向的,就不一定是对称的。**

为了在 Python 中操作图形,我们将使用非常流行的 networkx 库[1]。我们首先创建一个空的有向图 H :

**import networkx as nxH = nx.DiGraph()**

然后,我们将向图中添加 4 个节点。每个节点有两个特征,颜色和大小。机器学习问题中的图通常具有带有特征的节点,例如社交网络中某个人的姓名或年龄,然后模型可以使用这些特征来推断复杂的关系并进行预测。Networkx 附带了一个内置的实用函数,用于以列表形式填充带有节点的图形,此外还有以下特性:

**H.add_nodes_from([
  (0, {"color": "gray", "size": 450}),
  (1, {"color": "yellow", "size": 700}),
  (2, {"color": "red", "size": 250}),
  (3, {"color": "pink", "size": 500})
])for node in H.nodes(data=True):
  print(node)> (0, {'color': 'gray', 'size': 450})
> (1, {'color': 'yellow', 'size': 700})
> (2, {'color': 'red', 'size': 250})
> (3, {'color': 'pink', 'size': 500})**

图中的边被定义为包含源节点和目标节点的元组,因此例如边(2, 3)将节点 2 连接到节点 3。因为我们有一个有向图,所以也可以有一条指向相反方向的边(3, 2)。多条边可以作为列表的一部分添加到图表中,方式与节点相似:

**H.add_edges_from([
  (0, 1),
  (1, 2),
  (2, 0),
  (2, 3),
  (3, 2)
])print(H.edges())> [(0, 1), (1, 2), (2, 0), (2, 3), (3, 2)]**

现在我们已经创建了一个图表,让我们定义一个函数来显示关于它的一些信息。我们验证了该图确实是有向的,并且它具有正确的节点数和边数。

**def print_graph_info(graph):
  print("Directed graph:", graph.is_directed())
  print("Number of nodes:", graph.number_of_nodes())
  print("Number of edges:", graph.number_of_edges())print_graph_info(H)> Directed graph: True
> Number of nodes: 4
> Number of edges: 5**

绘制您正在使用的图表也非常有帮助。这可以通过使用nx.draw来实现。我们使用节点的特征来给每个节点着色,并在绘图中给每个节点指定它们自己的大小。因为节点属性是以字典的形式出现的,而且 draw 函数只接受列表,所以我们必须首先转换它们。生成的图看起来像是应该有 4 个节点、5 条边和正确的节点特征。

**node_colors = nx.get_node_attributes(H, "color").values()
colors = list(node_colors)node_sizes = nx.get_node_attributes(H, "size").values()
sizes = list(node_sizes)nx.draw(H, with_labels=True, node_color=colors, node_size=sizes)**

有向图,作者的图像。

让我们把有向图 H 转换成无向图 G 。之后,我们再次打印关于该图的信息,我们可以看到转换成功了,因为输出表明它不再是一个有向图。

**G = H.to_undirected()
print_graph_info(G)> Directed graph: False
> Number of nodes: 4
> Number of edges: 4**

奇怪的是,边的数量减少了一个。如果我们仔细观察,我们可以看到边(3, 2)已经消失了,这是合理的,因为一个无向边只能由一个元组来表示,在这种情况下是(2, 3)

**print(G.edges())> [(0, 1), (0, 2), (1, 2), (2, 3)]**

当我们想象无向图时,我们可以看到边的方向消失了,而其他一切都保持不变。

**nx.draw(G, with_labels=True, node_color=colors, node_size=sizes)**

一个无向图,作者的图像。

空手道俱乐部网络

现在我们已经对如何在 Python 中处理图形有了一个高层次的理解,我们将看看一个真实世界的网络,我们可以使用它来定义一个机器学习任务。扎卡里的空手道俱乐部网络[2]就是为此而选择的。它代表了 w .扎卡里在七十年代研究的空手道俱乐部成员之间的友谊关系。如果两个人在俱乐部之外进行社交,则图中的一条边将他们连接起来。

空手道俱乐部数据集可通过 PyTorch Geometric (PyG ) [3]获得。PyG 库包含了对图形和其他不规则结构进行深度学习的各种方法。我们首先检查数据集的一些属性。它似乎只包含一个图形,这是意料之中的,因为它描述了一个俱乐部。此外,数据集中的每个节点被分配一个唯一代表每个节点的 34 维特征向量。俱乐部的每个成员都是机器学习术语中 4 个派别或类别之一的一部分。

**from torch_geometric.datasets import KarateClubdataset = KarateClub()
print("Dataset:", dataset)
print("# Graphs:", len(dataset))
print("# Features:", dataset.num_features)
print("# Classes:", dataset.num_classes)> Dataset: KarateClub()
> # Graphs: 1
> # Features: 34
> # Classes: 4**

我们可以进一步探索数据集中唯一的图形。我们看到该图是无向的,它有 34 个节点,每个节点有 34 个特征,如前所述。边用元组表示,一共有 156 个。然而,在 PyG 中,无向边被表示为两个元组,每个方向一个,也称为双向,这意味着在空手道俱乐部图中有 78 个唯一的边。PyG 只包括 A 中非零的条目,这就是为什么边是这样表示的。这种类型的表示被称为坐标格式,通常用于稀疏矩阵。每个节点都有一个标签, y ,它保存了相应节点属于哪个类的信息。该数据还包含一个train_mask,它具有我们在训练期间已知的基础事实标签的节点的索引。有 4 个真实节点,每个派系一个,现在的任务是推断其余节点的派系。

**data = dataset[0]print(data)
print("Training nodes:", data.train_mask.sum().item())
print("Is directed:", data.is_directed())> Data(x=[34, 34], edge_index=[2, 156], y=[34], train_mask=[34])
> Training nodes: 4
> Is directed: False**

我们将空手道俱乐部网络转换为 Networkx 图,这允许我们使用nx.draw函数来可视化它。节点根据它们所属的职业(或派别)进行着色。

**from torch_geometric.utils import to_networkxG = to_networkx(data, to_undirected=True)
nx.draw(G, node_color=data.y, node_size=150)**

扎卡里的空手道俱乐部网络,由作者图像。

半监督节点分类

当训练模型来执行节点分类时,它可以被称为半监督机器学习,这是用于在训练期间组合有标签和无标签数据的模型的通用术语。在节点分类的情况下,我们可以访问图中的所有节点,甚至是那些属于测试集的节点。唯一缺少的信息是测试节点的标签。

图卷积网络(GCNs)将用于对测试集中的节点进行分类。为了给出简单的理论介绍,图形神经网络中的层可以写成非线性函数 f :

以图的邻接矩阵 A 和某层的(潜在)节点特征l作为输入。图形神经网络的简单分层传播规则如下所示:**

其中 W 为第 l 个神经网络层的权重矩阵, σ 为非线性激活函数。将权重与邻接矩阵相乘意味着对每个节点的所有(1 跳)相邻节点的所有特征向量进行求和和聚合。但是,不包括节点本身的特征向量。

为了解决这个问题,Kipf 和 Welling [4]将单位矩阵添加到邻接矩阵中,并将这个新矩阵表示为=A+I。邻接矩阵的乘法也将改变特征向量的比例。为了抵消这个被对称地乘以其对角度矩阵,产生最终的 GCN 传播规则:

GCN 层已经是 what PyG 的一部分,它可以很容易地作为GCNConv类导入。与在普通神经网络中层叠层的方式相同,也可以层叠多个 GCN 层。具有 3 层 GCN 将导致三个连续的传播步骤,导致每个节点用来自 3 跳之外的信息进行更新。模型的第一层必须具有与每个节点的要素数量一样多的输入单元。与最初的 GCN 论文一致,除了最后一个维度被设置为 2 之外,潜在维度被设置为 4。这允许我们稍后将所学习的潜在嵌入绘制为二维散点图,以查看该模型是否设法学习对于属于同一类的节点来说相似的嵌入。双曲正切激活函数在 GCN 层之间用作非线性函数。输出层将二维节点嵌入映射到 4 个类中的 1 个。

**from torch.nn import Linear
from torch_geometric.nn import GCNConvclass GCN(torch.nn.Module):
  def __init__(self):
    super(GCN, self).__init__()
    torch.manual_seed(42)
    self.conv1 = GCNConv(dataset.num_features, 4)
    self.conv2 = GCNConv(4, 4)
    self.conv3 = GCNConv(4, 2)
    self.classifier = Linear(2, dataset.num_classes) def forward(self, x, edge_index):
    h = self.conv1(x, edge_index)
    h = h.tanh()
    h = self.conv2(h, edge_index)
    h = h.tanh()
    h = self.conv3(h, edge_index)
    h = h.tanh()
    out = self.classifier(h)
    return out, hmodel = GCN()
print(model)> GCN(
>   (conv1): GCNConv(34, 4)
>   (conv2): GCNConv(4, 4)
>   (conv3): GCNConv(4, 2)
>   (classifier): Linear(in_features=2, out_features=4, bias=True)
> )**

我们使用交叉熵作为损失函数,因为它非常适合于多类分类问题,并初始化 Adam 作为随机梯度优化器。我们创建一个标准的 PyTorch 训练循环,并让它运行 300 个周期。注意,虽然所有节点确实获得了对它们的节点嵌入的更新,但是仅针对训练集中的节点计算损失。在训练期间,损失急剧减少,这意味着分类效果良好。来自最后一个 GCN 层的二维嵌入被存储为一个列表,以便我们可以在训练期间动画化嵌入的演变,给出对模型的潜在空间的一些洞察。

**criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)def train(data):
  optimizer.zero_grad()
  out, h = model(data.x, data.edge_index)
  loss = criterion(out[data.train_mask], data.y[data.train_mask])
  loss.backward()
  optimizer.step()
  return loss, hepochs = range(1, 301)
losses = []
embeddings = []for epoch in epochs:
  loss, h = train(data)
  losses.append(loss)
  embeddings.append(h)
  print(f"Epoch: {epoch}\tLoss: {loss:.4f}")> Epoch: 1    Loss: 1.399590
> Epoch: 2    Loss: 1.374863
> Epoch: 3    Loss: 1.354475
> ...
> Epoch: 299  Loss: 0.038314
> Epoch: 300  Loss: 0.038117**

Matplotlib 可以用来制作节点嵌入的散点图,其中每个点都根据它们所属的派系进行着色。对于每一帧,除了该时期的训练损失值之外,我们还显示该时期。最后,动画被转换成 GIF 格式,如下图所示。

**import matplotlib.animation as animationdef animate(i):
  ax.clear()
  h = embeddings[i]
  h = h.detach().numpy()
  ax.scatter(h[:, 0], h[:, 1], c=data.y, s=100)
  ax.set_title(f'Epoch: {epochs[i]}, Loss: {losses[i].item():.4f}')
  ax.set_xlim([-1.1, 1.1])
  ax.set_ylim([-1.1, 1.1])fig = plt.figure(figsize=(6, 6))
ax = plt.axes()
anim = animation.FuncAnimation(fig, animate, frames=epochs)
plt.show()gif_writer = animation.PillowWriter(fps=20)
anim.save('embeddings.gif', writer=gif_writer)**

节点嵌入的演变,作者图片。

GCN 模型设法线性分离不同类的几乎所有节点。这是令人印象深刻的考虑到它只给了每个派系一个标记的例子作为输入。

希望你对图形神经网络的介绍感兴趣。gnn 是非常通用的算法,因为它们可以应用于复杂的数据和解决不同类型的问题。例如,通过在我们的神经网络末端使用一些置换不变池(如 mean)来简单地聚集节点特征,它可以对整个图进行分类,而不是对单个节点进行分类!

[1] A. Hagberg,D. Schult 和 P. Swart,“使用 NetworkX 探索网络结构、动力学和功能”, SciPy2008 ,2008,【networkx.org】T2

[2] W .扎卡里,“小群体中冲突和裂变的信息流模型”, J. Anthropol .Res 。doi:10.1086/jar . 33 . 4 . 3629752

[3] M. Fey 和 J. Lenssen,“用 PyTorch 几何快速图形表示学习”, ICLR, 2019,pyg.org,麻省理工学院许可

[4] T. Kipf 和 M. Welling,“基于图卷积网络的半监督分类”, ICLR ,2016, arXiv: 1609.02907

基于 PyG 的图神经网络在节点分类、链路预测和异常检测方面的应用

原文:https://towardsdatascience.com/graph-neural-networks-with-pyg-on-node-classification-link-prediction-and-anomaly-detection-14aa38fe1275

Pytorch 几何在主要图问题上的实现

照片由 DeepMindUnsplash 上拍摄

图形神经网络是一种机器学习算法,设计用于图形结构数据,如社交图、网络安全中的网络或分子表示。在过去的几年中,它发展迅速,并被用于许多不同的应用中。在这篇博文中,我们将回顾它在主要图问题上的代码实现,以及 GNN 的所有基础知识,包括它的应用和算法细节。

图形神经网络的应用

GNN 可用于解决各种与图形相关的机器学习问题:

  • 节点分类
    预测节点的类别或标签。例如,在网络安全中检测网络中的欺诈实体可以是节点分类问题。
  • 链接预测
    预测节点之间是否存在潜在的链接(边)。例如,社交网络服务基于网络数据建议可能的朋友联系。
  • 图形分类
    将图形本身分类成不同的类别。一个例子是通过观察一种化合物的图形结构来确定它是有毒的还是无毒的。
  • 社区检测 将节点划分成簇。一个例子是在社交图中寻找不同的社区。
  • 异常检测
    以无监督的方式发现图中的离群节点。如果您的目标上没有标签,可以使用这种方法。

GNN 应用程序(图片由作者提供)

在这篇博文中,我们将回顾节点分类、链接预测和异常检测的代码实现。

图形卷积——直觉

图形神经网络在过去几年中发展迅速,已经发明了许多变体(更多细节,请参见本调查)。在这些 GNN 变体中,图卷积网络可能是最流行和最基本的算法。在本节中,我们将回顾其算法的高级介绍。

图卷积是基于图结构提取/总结节点信息的有效方法。它是卷积神经网络的卷积运算的变体,通常用于图像问题。

在图像中,像素在网格中按结构排序,卷积运算中的过滤器(权重矩阵)以预先确定的步长在图像上滑动。像素的相邻像素由过滤器大小决定(在下图中,过滤器大小为 3 x 3,蓝色过滤器中的八个灰色像素是相邻像素),过滤器中的加权像素值聚合为一个值。此卷积运算的输出比输入图像的大小小,但具有更高级别的输入视图,这对于预测图像问题(如图像分类)非常有用。

作者图片

在图中,节点以非结构化的方式排序,并且节点之间的邻域大小不同。图表卷积采用给定结点(下图中的红色结点)及其相邻结点(蓝色圆圈内的灰色结点)的结点要素的平均值来计算该结点的更新结点制图表达值。通过这种卷积运算,节点表示捕获了局部化的图形信息。

作者图片

下图显示了图形卷积操作的更多细节。对邻近结点(蓝色)的结点要素和目标结点(红色)的结点要素进行平均。然后将其乘以权重向量(W ),其输出更新目标节点的节点特征(更新的节点值也称为节点嵌入)。

图形卷积运算(图片由作者提供)

对感兴趣的人来说,利用度矩阵的逆矩阵将节点特征归一化后聚合在 原论文 中,而不是简单的平均(论文中的方程(8))。

在此卷积运算中需要注意的一点是,图形卷积的数量决定了将多少步以外的节点要素聚合到每个节点中。在下图中,第一个卷积将蓝色节点的要素聚合到橙色节点中,第二个卷积可以将绿色节点的要素合并到橙色节点中。

卷积的数量决定了节点要素聚合的程度(图片由作者提供)

Cora —图表基准数据集

在接下来的几节中,我们将回顾 GCN 代码的实现。在我们深入研究它们之前,让我们先熟悉一下我们将要使用的数据集。 Cora 数据集是一个论文引用网络数据,包含 2708 篇科学出版物。图中的每个节点代表一个出版物,如果一篇论文引用了另一篇论文,则一对节点用一条边连接。

通过这篇文章,我们使用 PyG (Pytorch Geometric) 来实现 GCN,这是一个流行的 GNN 库。Cora 数据集也可以使用 PyG 模块加载:

来源于 Pytorch Geometric 的 Cora 数据集最初来自于“ 用机器学习 ”论文。

节点特征和边信息如下所示。节点特征是 1433 个单词向量,指示每个出版物中单词的不存在(0)或存在(1)。边用邻接表表示。

节点特征和边列表(图片由作者提供)

每个节点都有七个类中的一个,这将是我们的模型目标/标签。

班级分布(图片由作者提供)

使用 NetworkX 库可以可视化图形数据。节点颜色代表节点类。

Cora 数据集的可视化(图片由作者提供)

节点分类

对于节点分类问题,我们使用 PyG 的RandomNodeSplit模块将节点分为 train、valid 和 test(我们替换了数据中的原始分割掩码,因为它的 train 集太小)。

请注意,数据分割被写入图形对象的mask属性(见下图),而不是分割图形本身。这些掩码用于训练损失计算和模型评估,而图卷积使用整个图数据。

图形对象具有遮罩属性(按作者分类的图像)

节点分类的基线模型(MLP)

在我们建立 GCN 之前,我们只使用节点特征来训练 MLP(多层感知器,即前馈神经网络)以设置基线性能。该模型忽略了节点连接(或图结构),并试图仅使用单词向量对节点标签进行分类。模型类如下所示。它有两个隐藏层(Linear),带有 ReLU 激活,后跟一个输出层。

我们将使用普通 Pytorch 培训/评估设置来定义培训和评估功能。

该模型的测试精度为 73.2%

GCN 论节点分类

接下来,我们将训练 GCN,并将它的表现与 MLP 进行比较。我们使用一个非常简单的模型,它有两个图形卷积层,并在它们之间重新激活。这种设置与原 GCN 论文(方程式 9)相同。

GCN 节点分类模型架构(图片由作者提供)

该模型的测试集精度为 88.0% 。我们从 MLP 获得了大约 15%的准确性改进。

链接预测

链接预测比节点分类更棘手,因为我们需要一些调整来使用节点嵌入对边进行预测。预测步骤描述如下:

  1. 编码器通过用两个卷积层处理图形来创建节点嵌入。
  2. 我们在原图中随机添加负面链接。这使得模型任务具有来自原始边的正链接和来自添加边的负链接的二元分类。
  3. 解码器使用节点嵌入对包括负链接的所有边进行链接预测(即二进制分类)。它根据每条边上的一对节点计算节点嵌入的点积。然后,它聚合嵌入维度上的值,并在每条边上创建一个代表边存在概率的值。

链接预测模型架构(图片由作者提供)

该模型结构来自变分图自动编码器中的原始链接预测实现。代码如下所示。这改编自PyG repo中的代码示例,该示例基于图形自动编码器实现。

对于此链接预测任务,我们希望将链接/边随机分为训练数据、有效数据和测试数据。我们可以使用 PyG 的RandomLinkSplit模块来实现。

输出数据如下所示。

随机链接拆分输出(图片由作者提供)

关于这个输出数据,有几点需要注意。

首先,在edge_index上执行分割,使得训练和验证分割不包括来自验证和测试分割的边(即,仅具有来自训练分割的边),并且测试分割不包括来自测试分割的边。这是因为编码器使用edge_index(和x)来创建节点嵌入,这种设置确保了在对验证/测试数据进行预测时,节点嵌入上没有目标泄漏。

第二,两个新属性(edge_labeledge_label_index)被添加到每个分割数据。它们是对应于每个分割的边标签和边索引。edge_label_index将用于解码器进行预测,而edge_label将用于模型评估。

第三,负链接被添加到val_datatest_data两者,其数量与正链接(neg_sampling_ratio=1.0)相同。它们被添加到edge_labeledge_label_index属性中,但没有添加到edge_index中,因为我们不想在编码器上使用负链接(或节点嵌入创建)。此外,我们不会在此向训练集添加负面链接(通过设置add_negative_train_samples=False),因为我们会在上述train_link_predictor的训练循环中添加它们。训练期间的这种随机化被认为是使模型更健壮。

下图总结了编码器和解码器如何执行边缘分割(每个阶段都使用彩色边缘)。

边缘分割总结(图片由作者提供)

我们现在可以用下面的代码来训练和评估这个模型。

该模型的检验 AUC 为 92.5%。

异常检测

我们再次使用 Cora 数据集进行异常检测任务,但它与上一个略有不同:异常值被合成注入。数据集有两种不同类型的异常值(异常值定义来自本文):

  • 结构异常值
    密集连接的节点与稀疏连接的常规节点形成对比
  • 上下文异常值
    属性与其相邻节点显著不同的节点

节点异常类型(来源:【https://arxiv.org/pdf/2206.10071.pdf】T21

对于这个异常检测任务,我们使用的是 PyGOD 库,这是一个构建在 PyG 之上的图形异常检测库。我们可以通过 PyGOD 模块加载异常值注入的 Cora 数据集。

下面的代码显示了异常值类型分布。

输出:Counter({0: 2570, 1: 68, 2: 68, 3: 2})

如果你对这些异常值是如何注入的感兴趣,你可以看看关于异常值生成器模块的 PyGOD 文档,它解释了操作细节。请注意,标签y将仅用于模型评估,而不用于训练标签,因为我们正在训练一个无监督的模型。

为了检测这些异常值,我们正在训练来自本文的DOMINANT(属性网络上的深度异常检测)模型。这是一个具有图形卷积层的自动编码网络,其重构误差将是节点异常分数。该模型按照以下步骤进行预测。

  1. 属性化网络编码器 用创建节点嵌入的三个图卷积层处理输入图。
  2. 结构重构解码器 使用学习到的节点嵌入来重构原始图边(即邻接矩阵)。它从每个可能的节点对计算节点嵌入的点积,从而在每个节点对上创建指示边存在的概率分数。
  3. 属性重构解码器 使用获得的节点嵌入重构原始节点属性。它有一个图表卷积层来预测属性值。
  4. 在最后一步中,通过在每个节点上加权平均来组合来自上述两个解码器的重构误差,并且组合的误差将是最终的误差/损失。这些最终误差也是节点的异常分数。

主导模型架构(来源:属性网络上的深度异常检测

正如您在下面看到的,使用 PyGOD 可以很容易地实现DOMINANT模型。

该模型的 AUC 为 84.1%,而其平均精度为 20.8%。这种差异很可能是由于目标不平衡造成的。由于这是一个无监督的模型,我们可能无法期待一个非常准确的模型,但你可以在原始论文中看到它仍然优于任何其他流行的异常检测算法。

这篇文章到此为止!

如果你感兴趣,完整的代码可以在下面的 Google Colab 和 GitHub repo 中找到。

https://colab.research.google.com/drive/1Ksca_p4XrZjeN0A6jT5aYN6ARvwFVSbY?usp=sharing https://github.com/tomonori-masui/graph-neural-networks/blob/main/gnn_pyg_implementations.ipynb

参考

聚类的图抽样策略

原文:https://towardsdatascience.com/graph-sampling-strategies-for-clustering-42a05a61a5d3

如何在采样图上生成高模块性聚类

纳斯蒂亚·杜尔希尔在 Unsplash 上的照片

图表是需要分析的复杂结构,如果它们变得太大,处理起来会很有挑战性。在过去的几年中,对巨大图表的分析一直是一个热门的研究领域,产生了像 OGBOGB-LSC 这样的倡议。

尝试处理这些大型图表的一种方法是,以保持原始结构在样本上的方式对它们进行采样,然后在采样的图表上进行分析。

然而,图形不容易取样。当您删除节点或边时,如何处理您将拥有的信息丢失?为了开始研究这个主题,今天我们将回顾并实现论文不完全网络上的聚类、显著性和社会网络分析 [1],该论文提出了两种图的边采样算法。

我们将从理解论文的观点、局限性和作者提出的结果开始。然后,我们将实现它,尝试解决它的一个限制,看看这个方法是否真的有效。

用于分析的笔记本可在 Kaggle 和我的 Github 上获得。

初步考虑

首先,我们来介绍一下论文的基本假设。通过对采样图应用聚类方法来测试采样方法,以查看在原始图上得到的聚类是否类似于或优于在完整图上应用相同算法。

为此,他们使用了一种叫做 SpeakEasy 的算法。因为我找不到这个算法的 Python 实现,所以我使用了 NetworkX 上的贪婪模块化最大化算法。

他们还分析了几个指标。对于这个分析,我只考虑了模块化,这是本文中考虑的许多因素之一。

该论文指出,这种方法仅用于无向图。对于使用邻接矩阵对称性的第一种算法来说尤其如此。然而,在这个分析中,我考虑了一个旨在观察这些方法如何成立的网络。

最后,需要记住的一件重要事情是,这些方法依赖于邻接矩阵的创建,对于具有数十亿个节点的图来说,表示邻接矩阵以生成样本是不可行的。作者指出,其他表示是可能的,但没有进一步深入细节。

为了分析结果,我考虑了 4 个网络,它们都可以在斯坦福大学的快照上免费获得。在这篇文章中,我将向你展示其中两个的结果:自我-脸书网络 [2],一个由来自脸书的朋友列表组成的无向网络,和 p2p-Gnutella08 网络[3],一个由点对点文件共享网络组成的有向图。

每种算法和样本大小都应用了几次,以说明结果的随机性。

采样策略 1

第一种策略使用邻接矩阵上的采样,然后使用线性回归来尝试估计被采样掉的丢失链接。使用来自该回归的预测,创建新的邻接矩阵,并对其应用该算法。

算法如下:

  • 是图 G 的邻接矩阵
  • 从邻接矩阵中随机抽取 K 列,并将它们的索引保存在变量 K 中
  • 样本 X -> X = A(:,K)
  • 创建一个目标 Y,用 A -> Y(K,:= X(N-K,:)的对称性质部分填充。T
  • 使用 X -> Y_hat = X(X- Y)的 Moore-Pensore 伪逆进行线性回归
  • 用采样的列生成新的邻接矩阵:A_hat(:,K) = X
  • 添加重建的列:A_hat(:,N-K) = Y_hat

如您所见,这里直接使用了矩阵的对称属性来定义 y。让我们看看这个实现在 Python 中是什么样子的:

def algorithm_1(A, sample_size, n, N): k = sample_size
    K = randsample(N, k) X = A[:, K]

    set_ = list(set(N) - set(K))

    Y = np.zeros((n, n-k)) Y[K, :] = X[set_, :].T
    Y_hat = np.dot(X, np.dot(np.linalg.pinv(X), Y))
    A_hat = np.zeros((n,n)) A_hat[:, K] = X
    A_hat[:, list(set(N) - set(K))] = Y_hat G_algo1 = nx.from_numpy_matrix(A_hat)
    return G_algo1

其中 randsample 方法实现为:

def randsample(N, k):
    K = np.random.choice(N, size=k, replace=False)
    if type(K[0]) == str:
        K = [int(i) for i in K] return K

如您所见,这是论文中提出的算法的直接实现。注意,在纸上,矩阵 Y_hat 的维数是错误的,它应该是(n,n)否则矩阵运算将没有意义。

在实现了这个方法之后,我注意到线性回归并没有生成比原始图更小的图,而是生成了更多的边。我们将在分析中看到,这使得聚类算法在采样图上比在原始图上花费更长的时间。

对于脸书网络,就执行时间而言,正如我所说的,采样图更糟:

脸书网络中算法 1 的运行时间。由作者开发。

当我们谈到模块性时,在大约 40%的样本大小之后,采样图能够超过原始图上的模块性,但是以更大的运行时间为代价。

算法 1 采样的脸书网络上的聚类的模块性。由作者开发。

然而,重要的是要注意,对于这里没有展示的一个网络,也是无向的,这种采样方法不能超越模块性,并且花费的时间也更长。更多详情请参考笔记本。

现在,对于 p2p-Gnutella 网络,在经过的时间上发生了相同的现象,但是这一次,模块性甚至没有接近最初的模块性,如下图所示:

p2p-gnu 网络中算法 1 的运行时间。由作者开发。

算法 1 采样的脸书网络上的聚类的模块性。由作者开发。

采样策略 2

第二种采样策略包括对原始邻接矩阵进行多次采样,然后汇总结果以生成要考虑的新图。

这种方法具有改变边的权重的效果,使其补偿从网络中移除的边。算法如下:

  • 是图 G 的邻接矩阵
  • 从邻接矩阵中随机抽取 K 列,并将它们的索引保存在变量 K 中
  • 从 A -> X1(:,K) = A(:,K)中得到 K 列
  • 应用对称属性-> X1(K,)= A(K,😃。T
  • 通过由节点数量的平方根的倒数构成的矩阵 a P 中的缩放因子来缩放 X-> X1 = diag(P1)* X1
  • 生成一组新的列,删除先前采样的列,并将其保存到 X2
  • 生成新的邻接矩阵作为对样本的思考-> A_hat = alpha * X1 + (1-alpha)*X2

用 Python 实现它,就变成了:

def algorithm_2(A, sample_size, n, N, symmetric=True):

    def construct_X(N, k):
        K = randsample(N, k) X1 = np.zeros((n, n))
        X1[:, K] = A[:, K] if symmetric:
            X1[K, :] = A[:, K].T P1 = np.full((n,n), np.sqrt(1 / n))
        X1 = np.diag(P1) * X1

        return X1, K

    k = int(np.floor(sample_size / 2)) alpha = 0.5
    X1, K1 = construct_X(N, k)
    X2, K2 = construct_X(list(set(N) - set(K1)), k) A_algo2 = alpha * X1 + (1 - alpha) * X2
    G_algo2 = nx.from_numpy_matrix(A_algo2)

    return G_algo2

我必须在这里提请你注意,我做了一个在论文中提出的简化版本。本文利用线性代数中的一些特定的采样机制生成第二矩阵。为了简单起见,我又做了一次随机抽样。这可能会影响该方法的性能。

现在,看看结果:

脸书网络中算法 2 的运行时间。由作者开发。

算法 2 采样的脸书网络上聚类的模块性。由作者开发。

正如我们可以看到的,对于脸书网络,该算法能够生成更快的聚类,甚至能够超过全网络上的原始模块性,这是一个非常好的结果,因为该方法简单。

然而,对于 p2p-gnu 网络,我们不能说同样的话:

p2p-gnu 网络中算法 2 的运行时间。由作者开发。

算法 2 采样的 p2p-gnu 网络聚类的模块性。由作者开发。

正如我们所看到的,聚类运行得更快,但是,即使使用更高的采样方法,采样图也无法实现完整图的模块性度量。

在上面链接的笔记本上,Ca-Gr 网络取得了很好的模块化效果。这表明放松该算法的对称条件会严重损害其性能。

结论

在本文中,我们探讨了两种用于聚类目的的图形采样机制。我们试图验证这些方法的对称性假设是否真的有必要,并试图重现这篇论文的观点。

再次注意,在开发过程中对算法做了一些简化。

我希望这能对您作为数据科学家的旅程有所帮助。

[1] Hegde,k .,Magdon-Ismail,m .,Szymanski,B.K .,& Kuzmin,K. (2016)。不完全网络上的聚类、突出和社会网络分析。复杂网络

[2]麦考利和莱斯科维奇。学习在自我网络中发现社交圈。NIPS,2012。

[3] M. Ripeanu 和 I. Foster 和 A. Iamnitchi。绘制 Gnutella 网络:大规模对等系统的特性和系统设计的含义。 IEEE 互联网计算杂志,2002 年。

Python 图形可视化基础第一部分:流程图

原文:https://towardsdatascience.com/graph-visualisation-basics-with-python-part-i-flowcharts-6298c4f412e0

使用 SchemDraw 包创建流程图

最近,我被分配了一项任务,创建一个逻辑树形图来表示我工作中的问题解决过程。在逻辑树中,我必须表示各种方程来解决问题。显然,我可以用 MS PowerPoint 或 Paint 之类的程序创建一个逻辑树。但是使用这些程序将是一个手动的过程,这可能会导致在可视化的形状和大小方面的一些不一致。此外,手动修改这些图可能是一个乏味的过程。

我想自动化这个过程。所以我从探索用 Python 创建逻辑树的可能性开始。我遇到了不同的可以满足我的目的的包,比如networkxgraphviz。我想进一步探索用 Python 来表示问题解决过程的可能性。在这个系列中,我将分享我关于使用 Python 实现图形可视化的不同可能性的发现。在本系列的第一部分中,我将分享一项我发现的使用 SchemDraw 包用 Python 创建流程图的技术。在接下来的部分中,我将分享可视化树形结构的方法,比如逻辑树,以及使用其他包的组织图。让我们开始吧。

图片来自 UnsplashKelly Sikkema

该项目的虚拟环境

我首先为这个项目创建一个名为graphs的虚拟环境。Python 虚拟环境为项目创建了一个隔离的环境。这意味着每个项目都有自己的依赖关系(Real Python,2018)。使用虚拟环境避免了全局安装 Python 包,这可能会破坏系统工具或其他项目(PyPA,2022)。

为了创建虚拟环境,我创建了一个 yml 文件,如下所示。它由该项目所需的依赖项列表组成。

环境文件来创建名为 graphs 的虚拟环境。

为了使用给定的 yml 文件创建名为graphs的虚拟环境,我在终端中运行以下命令:

conda env create -n graphs --file graphs-environment.yml

创建环境后,我使用以下命令激活它:

conda activate graphs

还可以在 jupyter notebook 中为这个虚拟环境创建一个独特的内核,这是我在终端中使用以下命令创建的:

python -m ipykernel install --user --name graphs --display-name "graphs"

安装内核后,要在给定的环境中运行笔记本,我只需进入内核,更改内核,然后选择图形。如果不再需要该环境,也可以使用以下方法轻松将其删除:

conda env remove -n graphs

流程图

流程图是按顺序表示流程中不同步骤的图片。流程图可以有不同的类型,但它们的主要目的是反映解决问题或实现目标的流程。我记得在我高中的计算机科学课上第一次学习流程图。用纸和笔画出流程图来解决简单的问题,例如计算 n 个数的总和或打印一系列数字,在当时是一个有趣的挑战。

在下一节中,我将描述一种使用 SchemDraw 包在 Python 中创建流程图的方法。我将考虑一个问题的例子,检测一个字符串是否是回文。

流程图的要素

由 Colling J. Delker 开发的 S chemDraw 软件包允许创建高质量的电路原理图。然而,我发现这个软件包也可以用来创建定制的流程图。

流程图中有六个主要元素。开始或结束节点由椭圆形表示。平行四边形代表用户定义的输入,而矩形代表一个过程。菱形说明了决策过程中的一个阶段。不同的形状由指向箭头连接,也称为连接符。使用 SchemDraw,可以通过导入schemdraw.Drawing()并为每个元素传递相应的参数和标签来在 Python 中构造这些基本形状。此外,这个包允许用户控制元素的大小,如宽度和高度,以及箭头的方向,如下图所示。

使用 SchemDraw 包构造流程图的基本元素。图片作者。

表示回文问题的流程图

回文是一个向前或向后读都一样的单词或序列。这个问题的算法很简单。首先,我要求用户输入一个字符串。接下来,我反转绳子。如果字符串和它的反码相同,那么字符串是一个回文,如果不相同,它就不是回文。这个问题在 Python 中可以表述为如下所示的几行代码:

string = input(“Enter a string: “)reverse_string = string[::-1]if string == reverse_string:
 print (f”{string} is a palindrome.”)

else:
 print (f”{string} is not a palindrome.”)

下面的要点给出了使用 SchemDraw 获得这个问题的流程图的代码。它从一个开始节点开始,然后是一个输入框来输入字符串。接下来,有一个进程框来反转字符串,还有一个菱形框来检查字符串和它的反转是否相同。根据决策是对还是错,有两个不同的箭头从决策框中分叉出来。打印结果后,箭头最终到达结束节点。

结果我得到如下图的流程图,也可以保存为图片文件。

解决使用 SchemDraw 创建的回文问题的流程图。图片作者。

结论

图形可视化是一个有趣的概念,用来表示网络、流程(如供应链或解决问题的流程)、树形结构(如决策树、组织树、逻辑树和文件夹树)。虽然 Python 中有复杂的数据可视化软件包,如 matplotlib、seaborn、Bokeh、Plotly 等。,现在有一些包可以用 Python 来表示图形和网络,尽管它们并不流行。

在这篇文章中,我首先为这个项目创建了一个虚拟环境。然后我解释了使用 SchemDraw 包用 Python 创建简单流程图的方法。在本系列的后续部分中,我将分享我发现的一些使用 networkx 和 graphviz 之类的包来表示树结构(如组织图和逻辑树)的方法。

感谢您的阅读!

参考

PyPA,2022。使用 pip 和虚拟环境安装软件包。

真正的 Python,2018。 Python 虚拟环境:初级读本。

Python 图形可视化基础第二部分:NetworkX 有向图

原文:https://towardsdatascience.com/graph-visualisation-basics-with-python-part-ii-directed-graph-with-networkx-5c1cd5564daa

用 NetworkX 软件包创建有向无环图

在本系列的第一部分中,我分享了如何使用 Python 中的 SchemDraw 包创建流程图。我对学习 Python 中图形可视化技术的探索让我探索了一些包,比如 NetworkX 和 graphviz。

一个图 G = (V,E) 是顶点 V 和边 E 的集合,其中每条边 (u,v) 是顶点之间的连接,其中 u,v ∈ V (可约,2020)。在 Python 中,使用节点和边来可视化图形。虽然节点表示任何特征,但是边表示图中特征之间的交互。

图形可视化可以有重要的领域应用,例如网络、空间数据科学、软件工程、生物信息学、能源信息学、机器学习和其他技术领域的可视化界面。在这篇文章中,我将分享一个使用 NetworkX 创建有向无环图的示例,探索包括中心性概念在内的图的特征,以及获取从图的根(开始节点)到叶(结束节点)的所有路径的方法。让我们开始吧。

网络 x

Network X 是一个 Python 包,用于创建、操作和研究复杂网络的结构、动态和功能。在 NetworkX 中,节点可以是任何可散列的对象(除了 None ),例如数字、文本串、图像、另一个图形、定制的节点对象等。

有向和无向图

边表示节点之间的连接,可以保存任意数据,如权重、方向或节点之间的关系。如果边是无向的,那么图形对象被称为无向图(图形)。如果这些边是有向的,那么这个图形对象就称为有向图(DiGraph) 。有向图中允许自循环,但不允许多条(平行)边。

循环和非循环图

有向无环图是一种特殊类型的没有有向环的有向图,因此沿着边的方向走永远不会形成一个闭环。另一方面,如果图的边在任一节点形成闭环,则称为有向循环图

图片由 UnsplashFabrice Villard 拍摄。

使用 NetworkX 包的有机图

有向无环图的例子包括系谱树、组织层级树、文件夹树等。一个是一个具有一组连接节点的分层的非循环数据结构。树中的每个节点可以与许多子节点连接,但必须恰好连接到一个父节点,除了没有父节点的根节点

组织图是显示一个组织的等级结构,以及不同级别的员工和不同部门之间的关系的图表。虽然可以使用 MS PowerPoint 和 Paint 等程序手动创建组织图,但我想探索使用 Python 创建组织图的可能性,以便可以通过编码轻松调整形状、大小和元素。

考虑一个公司 X,它有两个团队 A 和 B。假设公司有八名员工:一名 CEO,团队 A 和 B 各有两名团队领导,团队 A 有两名员工,团队 B 有三名员工。在本例中,只有一个根节点(CEO),根节点和任何节点之间只有一条路径。由于每个节点最多有三个子节点,这是一个三叉树的例子。如果每个节点最多有两个子节点,那将是一棵二叉树。使用 Python 中的 NetworkX 构建有机图的步骤将在下面逐步描述。

平面图

我从创建一个有向图对象开始。我为这个对象添加了 8 个节点,从 0 到 7,代表每个雇员。接下来,我添加了从 CEO 到每个团队领导的边,以及从团队领导到相应团队中的员工的边。可以在 NetworkX 中绘制不同布局的图形对象,如圆形、随机、壳形、光谱、平面、弹簧等。此处可用。然而,我在一个字典中手动设置每个节点的 x 和 y 位置,给它一个分层的倒树状结构。我还以字典的形式为每个节点分配了标签。

G = nx.DiGraph()nodes = np.arange(0, 8).tolist()G.add_nodes_from(nodes)G.add_edges_from([(0,1), (0,2),
 (1,3), (1, 4),
 (2, 5), (2, 6), (2,7)])pos = {0:(10, 10),
 1:(7.5, 7.5), 2:(12.5, 7.5),
 3:(6, 6), 4:(9, 6),
 5:(11, 6), 6:(14, 6), 7:(17, 6)}labels = {0:”CEO”,
 1:”Team A Lead”, 2: “Team B Lead”,
 3: “Staff A”, 4: “Staff B”,
 5: “Staff C”, 6: “Staff D”, 7: “Staff E”}nx.draw_networkx(G, pos = pos, labels = labels, arrows = True,
 node_shape = “s”, node_color = “white”)plt.title(“Organogram of a company.”)
plt.savefig(“Output/plain organogram using networkx.jpeg”,
 dpi = 300)
plt.show()

上面的代码产生了如下所示的简单组织图:

使用上面的代码创建的普通组织图。图片作者。

带有彩色节点和边的图

我发现可以以列表的形式分别为node_colornode_size的每个节点分配唯一的颜色和大小。然而,所有节点的node_shape必须是一致的,可用的形状也有限制。可以在这里找到用于在图形中绘制节点的参数。在下面的代码中,我为 CEO 提供了白色,为团队 A 提供了天蓝色,为团队 B 的节点提供了米色。类似地,与其他节点相比,我增加了团队领导节点的大小。我还为团队 A 和 B 分别分配了蓝色和红色作为edge_color,为节点的边界分配了灰色作为edgecolors

此外,我为从 CEO 到团队领导的边缘添加了标签。这是通过使用nx.draw_networkx_edge_labels()并以字典的形式传递Gposedge_labels来完成的。

colors = ["white", "skyblue","mistyrose", "skyblue",
          "skyblue","mistyrose", "mistyrose", "mistyrose"]edge_colors = ["blue", "red", "blue","blue", "red","red","red"]sizes = [1000, 2000, 2000, 1200, 1200, 1200, 1200, 1200]nx.draw_networkx(G, pos = pos, labels = labels, arrows = True,
                 node_shape = "s", node_size = sizes,
                 node_color = colors,
                 edge_color = edge_colors,  #color of the edges
                 edgecolors = "gray")     #edges of the box of nodenx.draw_networkx_edge_labels(G, pos = pos,
                             edge_labels={(0, 1): 'A', (0, 2): 'B'},
                             font_color='black')plt.title("Organogram of Company X")
plt.show()

因此,我得到了下面的组织图:

使用上面的代码创建的彩色组织图。图片作者。

以边界框为节点的图形

接下来,我想在每个节点的边界框内标注标签。为此,我没有为节点指定任何形状、大小或颜色。相反,我以 dict 的形式为 bbox 添加了一个参数。我为 bbox 指定了 facecolor、boxstyle、edgecolor 和 pad。可以为 bbox 传递的参数在这里可用

nx.draw_networkx(G, pos = pos, labels = labels, 
                 bbox = dict(facecolor = "skyblue",
                 boxstyle = "round", ec = "silver", pad = 0.3),
                 edge_color = "gray"
                )
plt.title("Organogram of Company X")
plt.show()

结果我得到了如下图的器官图。要注意的是,边界框隐藏了边缘末端的箭头,并且不可能给单个 bbox 分配不同的颜色、形状或大小。

边界框内有标签的有机图。图片作者。

有向图的特征

我想探索有向图对象G的特征。使用G.nodes获得G中所有节点的列表,使用G.edges获得边的列表。G.degree返回一个节点所连接的边的数量。在有向图的情况下,度数被进一步分为不度数和外度数。G.in_degree返回指向每个节点的边数。对于G,CEO 为 0,其他员工为 1。类似地,G.out_degree返回从每个节点指向外的边的数量。对于G,CEO 为 2,A 组领导为 2,B 组领导为 3,下面每个员工为 0。下面的代码片段描述了这一点。

探索表示组织图的有向图的特征。图片作者。

中心性概念

在图形分析中,中心性概念是指通过测量节点相对于其他节点(包括其邻居(连接节点)或图形中的边)的中心性来识别图形中的重要节点(Bhasin,2019)。有各种中心性概念,它们从不同的角度定义节点的重要性,并提供进一步的信息来分析图及其节点。

节点的度中心性是它所连接的全部节点的分数。具有高度中心性的节点通常被认为是高度活跃的。在 G 中,节点 3,即团队 B 领导具有最高的中心度,因为它连接到四个其他节点。

中间中心性是一个特定节点位于图中所有节点对之间的最短路径上的次数的度量。在G中,团队 B 领导的中间中心性最高,其次是团队 A 领导。这意味着团队领导是 CEO 和员工之间的桥梁。首席执行官和员工的中间中心性为零,因为他们不位于任何两个节点之间。

接近中心性是一个节点与其他节点接近程度的度量。它被计算为网络中从一个节点到所有其他节点的最短路径长度的平均值(Golbeck,2013)。在接近中心性的情况下,具有较低值的节点具有较高的中心性。这意味着与员工相比,首席执行官和团队领导拥有更大的中心地位(Golbeck,2013)。

具有高度中心性的节点将可能具有更高的介数中心性和接近中心性,如本例中团队领导的情况。要注意的是,如果G是无向图,则中间中心性和接近中心性值将改变,而度中心性将保持不变。

通过分别使用nx.degree_centrality(G)nx.betweenness_centrality(G)nx.closeness_centrality(G)获得不同节点的上述中心性值。

显示不同节点的度中心性、中间中心性和接近中心性的图。图片作者。

获取从树根到树叶的所有路径的列表

从给定的有向图对象G中,我想获得所有简单路径的列表,而不重复从 CEO(根节点)到各个员工(叶节点)的任何节点。这可以通过使用nx.algorithms.all_simple_paths()并将有向图对象、源节点(CEO)和目标节点列表(所有人员)传递给它来实现。然后我用生成器对象创建了一个熊猫数据帧df。通过遍历df的索引和列,我分别得到了根节点、中间节点和叶节点的准确位置,如下所示。df.values.tolist()以列表的形式返回每个路径。

以数据帧和列表的形式检索有向图中从起点到终点的所有可能路径。图片作者。

结论

在这篇文章中,我使用了一个有机图的例子来描述一种使用 NetworkX 包绘制有向无环图的方法。我讨论了利用节点、边和边界框的形状、大小和颜色等属性定制图形的可能性。我描述了使用 NetworkX 探索图形对象的特征和分析其中心性的可能性。最后,我展示了一种方法来获得从给定图形对象的根到叶的所有简单路径的列表。

根据我的经验,NetworkX 包对于图形网络分析和操作非常有效。然而,它在图形可视化方面有一定的局限性。例如,可用于表示节点的形状存在局限性。节点可以是正方形、圆形、三角形等形状。但是椭圆形是不可能的,因为标签可能会出现在节点之外。此外,不能为不同的节点设置不同的节点形状。使用边界框标注标签时,不能为不同的节点设置不同的面颜色。在本系列的下一篇文章中,我将分享如何利用 graphviz 包中的技术不仅克服这些限制,而且方便地创建更全面的图形。

感谢您的阅读!

脚注

[1]如果一个对象的哈希值在它的生命周期中从不改变,并且可以与其他对象进行比较,那么这个对象就是可哈希的。哈希值可以通过简单地将对象传递给hash()来获得。哈希值是一个整数,用于在查看字典时快速比较字典关键字。

参考

巴辛,2019。图形分析——中心性的介绍和概念。

戈尔贝克,2013。第三章:网络结构和措施。分析社交网络。

可约,2020。图论入门——计算机科学视角

Python 图形可视化基础,第三部分:graphviz 有向图

原文:https://towardsdatascience.com/graph-visualisation-basics-with-python-part-iii-directed-graphs-with-graphviz-50116fb0d670

使用 graphviz 和 Pydot 包创建有向图

在本系列的第一部分中,我分享了如何使用 SchemDraw 包创建流程图。在第二部分中,我描述了用 NetworkX 包创建一个有向无环图,同时探索特征、中心性概念并检索从根节点到叶子的所有可能路径。这一部分将着重于使用 graphviz 和 pydot 包构建有向无环图。我还将解释一下 graphviz 的样式和属性选项。让我们开始吧。

图片来自施韦策来自 Unsplash

graphviz 包

Graphviz 是一款开源的图形可视化软件。在 Python 3.7+下工作的 graphviz 包为这个软件提供了一个纯 Python 接口。这个包允许使用语言创建无向图和有向图。

使用 graphviz 构建 Graph 或 DiGraph 对象类似于使用 NetworkX,因为我们只需要简单地定义 Graph 对象的节点和边,并相应地分配属性。然而,也有一些关键的区别。例如,在 NetworkX 包中,节点可以定义为任何可散列的对象(None 除外)。但是在 graphviz 中,一个节点只能定义为一个字符串。

在我之前的 pos t 中,我指出了 NetworkX 包的图形可视化的不同限制,例如节点形状的有限选项,为单个节点获取唯一形状和边界框(bbox)属性的限制,等等。在这篇文章中,我将分享 graphviz 包不仅克服了这些限制,还为图形可视化提供了更多的灵活性选项。我将通过重建在之前的帖子中使用 NetworkX 创建的组织图来描述这一点,但在这篇帖子中使用 graphviz。

使用 graphviz 绘制器官图

为了使用 graphviz 包创建一个普通的 organogram,我首先初始化一个 graph 对象,比如说将f初始化为graphviz.Digraph(filename),其中filename是所创建的输出文件的名称。我创建了一个从 A 到 H 的八个名字的列表,以及该公司所有职位的列表。接下来,通过一个 for 循环,我为每个名字创建了八个节点,并添加了个人在组织中的相应位置作为标签。我指定了 CEO 和两个团队领导之间的界限,以及团队领导和他们相应的员工之间的界限。相同的代码如下所示:

import graphvizf = graphviz.Digraph(filename = “output/plain organogram 1.gv”)names = [“A”,”B”,”C”,”D”,”E”,”F”,”G”,”H”]positions = [“CEO”,”Team A Lead”,”Team B Lead”, “Staff A”,”Staff B”, “Staff C”, “Staff D”, “Staff E”]for name, position in zip(names, positions):
     f.node(name, position)

#Specify edges
f.edge(“A”,”B”); f.edge(“A”,”C”) #CEO to Team Leads
f.edge(“B”,”D”); f.edge(“B”,”E”) #Team A relationship
f.edge(“C”,”F”); f.edge(“C”,”G”); f.edge(“C”,”H”) #Team B relationship

f

结果,我得到了如下所示的简单组织图:

使用 graphviz 创建的普通组织图。图片作者。

在上图中,每个节点的大小会自动调整以适应节点内的标签。对于 NetworkX 包来说,情况并非如此。

graphviz 包的样式和属性

如前所述,graphviz 包提供了各种样式选项和属性来定制图形。下面详细描述了其中的一些可能性:

节点形状

使用 graphviz 创建的图中节点的默认形状是椭圆。使用 graphviz 可以获得各种各样的节点形状,可以在这里找到。这些形状可以是基于多边形的、基于记录的或用户定义的。此外,对于不同节点,也可以得到不同的形状。在下面的代码中,我将 CEO 的节点形状更改为椭圆形,将两个团队领导的节点形状更改为箱形,将员工的节点形状更改为纯文本。

import graphvizf = graphviz.Digraph(filename = "output/plain organogram 2.gv")names = ["A","B","C","D","E","F","G","H"]positions = ["CEO","Team A Lead","Team B Lead", "Staff A","Staff B", "Staff C", "Staff D", "Staff E"]for name, position in zip(names, positions):
    if name == "A":
        f.node(name, position, shape = "oval")

    elif name in ["B","C"]:
        f.node(name, position, shape = "box")
    else:
        f.node(name, position, shape = "plaintext")#Specify edges
f.edge("A","B"); f.edge("A","C")   #CEO to Team Leads
f.edge("B","D"); f.edge("B","E")   #Team A relationship
f.edge("C","F"); f.edge("C","G"); f.edge("C","H")   #Team B relationship

f

普通组织图,不同员工有不同形状的节点。作者图片。

节点颜色和边颜色

还可以使用 graphviz 为不同的节点和边分配不同的颜色。我创建了一个颜色列表,然后使用下面代码中的 for 循环为每个节点分配一种颜色。我将黑色分配给 CEO,将蓝色分配给团队 A,将红色分配给团队 b。同样,我将蓝色分配给连接团队 A 的边,将红色分配给连接团队 b 的边。

import graphvizf = graphviz.Digraph(filename = "output/colorful organogram 1.gv")names = ["A","B","C","D","E","F","G","H"]positions = ["CEO","Team A Lead","Team B Lead", "Staff A","Staff B", "Staff C", "Staff D", "Staff E"]colors = ["black", "blue", "red", "blue", "blue", "red", "red", "red"]for name, position, color in zip(names, positions, colors):
    f.node(name, position, color = color)

#Specify edges
#CEO to Team Leads
f.edge("A","B", color = "blue", label = "A"); f.edge("A","C", color = "red", label = "B")   
#Team A
f.edge("B","D", color = "blue"); f.edge("B","E", color = "blue")   
#Team B 
f.edge("C","F", color = "red"); f.edge("C","G", color = "red"); f.edge("C","H", color = "red")   

f

使用 graphviz 创建的具有指定节点和边颜色的有机图。图片作者。

用颜色填充节点

在这一步,我通过填充节点内部的颜色来进一步定制图表。只需在定义节点和分配颜色时声明style = “filled"即可。

import graphvizf=graphviz.Digraph(filename='output/filled_colorful_organogram.gv')names = ["A","B","C","D","E","F","G","H"]positions = ["CEO","Team A Lead","Team B Lead", "Staff A","Staff B", "Staff C", "Staff D", "Staff E"]colors = ["black", "skyblue", "mistyrose", "skyblue", "skyblue", "mistyrose", "mistyrose", "mistyrose"]for name, position, color in zip(names, positions, colors):
    if name== "A":
        f.node(name, position, color = color)
    else:
        f.node(name, position, style = "filled", color = color)

#Specify edges
f.edge("A","B"); f.edge("A","C")   #CEO to Team Leads
f.edge("B","D"); f.edge("B","E")   #Team A relationship
f.edge("C","F"); f.edge("C","G"); f.edge("C","H")   #Team B relationship

f

组织图中用指定颜色填充的节点。图片作者。

从终端运行 gv 文件

有向图对象f可以显示在gv扩展名的输出 Graphviz 点文件中,并使用f.view()保存。也可以打印这个用点语言编写的有向图对象的源代码,只需在笔记本中使用f.source即可。

上面 DOT 语言中有向图对象的源代码。图片作者。

上面的 txt 文件包含了点语言中有向图的源代码。我已经使用pos手动指定了节点的 x 和 y 位置。可以使用以下代码在终端中运行该文件:

dot -Kfdp -n -Tjpeg -Gdpi=300 -O example_digraph.txt

它将 digraph 对象生成为分辨率为 300 dpi 的 jpeg 文件。

Pydot 包

pydot 包是 Graphviz 的一个接口。它是用纯 Python 编写的,可以解析并转储到 Graphviz 使用的 DOT 语言中。计算机中的文件夹树结构,由目录、子目录、文件等组成。也是有向图的一个例子。在下一节中,我将解释如何使用 pydot 包来获得文件夹树结构。

使用 Pydot 包的文件夹树

我首先创建一个名为G的有向图对象。Python 中的 os 模块提供了一种使用操作系统相关功能的可移植方式。os.getcwd()返回当前工作目录,包括路径,我指定为rootDir。从rootDir中,我只获得目录的名称(graph _ visualisation _ basics)并将其作为currentDir传递。我为currentDir添加一个节点,并用绿色填充。通过使用 for 循环,我为每个子目录和文件定义了节点,并在它们之间添加了边。接下来,我用黄色填充子目录的节点,用橙色填充文件。同时,我会忽略名称以.开头的隐藏文件夹。

使用Image(G.create_jpeg()创建图形对象的图像,并通过IPython.display.display()显示。使用G.write_jpeg(filename)将图像文件保存为 jpeg 格式,其中filename是保存文件的名称。

文件夹树结构包括使用上述代码创建的根目录、子目录和文件的层次结构。图片作者。

结论

这是 Python 图形可视化基础系列的第三部分。这个系列背后的动机是分享我在使用 SchemDraw、NetworkX 和 graphviz 等包创建流程图和 Python 中的 graph 对象时学到的简单技术。在这篇文章中,我以 organogram 为例描述了如何使用 graphviz 包创建有向图对象。我还展示了为 graphviz 提供的图形组件设置样式和添加属性的各种选项。最后,我分享了如何使用 Pydot 包将系统中的文件夹树结构构建成一个图形。

本系列文章的笔记本可以在这个中找到。感谢您的阅读!

GraphGPS:导航图形转换器

原文:https://towardsdatascience.com/graphgps-navigating-graph-transformers-c2cc223a051c

图 ML 的最新进展

烹饪最佳图形转换器的食谱

2021 年,图形转换器(GT)赢得了最近的分子性质预测挑战,这要归功于缓解了许多与普通消息传递 GNNs 有关的问题。在这里,我们试图将众多新开发的 GT 模型组织到一个单一的 GraphGPS 框架中,为所有类型的 Graph ML 任务提供通用的、强大的、可扩展的线性复杂度的图形转换器。事实证明,仅仅一辆调校良好的 GT 就足以展示 SOTA 在许多实际任务中的成果!

消息传递 gnn、全连接图形转换器和位置编码。作者图片

这篇文章是与 拉迪斯拉夫·拉帕塞克多米尼克·比艾尼 维贾伊·普拉卡什·德威迪 共同撰写的,是基于论文 的一个通用、强大、可扩展的图形转换器(2022) 【T24)

大纲:

  1. 消息传递 GNNs vs 图形转换器
  2. 图形转换器的优缺点和种类
  3. graph GPS 框架
  4. 概要:蓝图
  5. 功能强大;结构和位置特点
  6. 可扩展:线性变压器
  7. 烹饪时间——如何充分利用你的 GT

消息传递 GNNs vs 图形转换器

消息传递 GNN(通常从 Weisfeiler-Leman 的角度进行分析)众所周知地遭受 过度平滑 (增加 GNN 层数,特征倾向于收敛到相同的值) 过度挤压 (当试图将来自许多邻居的消息聚集到单个向量时丢失信息),并且可能最重要的是,在小而稀疏的分子图上已经明显的长程相关性捕捉不佳。

今天,我们知道了许多打破消息传递玻璃天花板的方法——包括高阶 GNNs ,更好地理解图拓扑扩散模型图重布线,以及图转换器

在消息传递方案中,一个节点的更新是其邻居的函数,而在 GTs 中,一个节点的更新是图中所有节点的函数(由于 Transformer 层中的自关注机制)。也就是说,GT 实例的输入就是整个图形。

更新目标节点表示(红色),局部消息传递仅聚集直接邻居,而全局注意力是图中所有节点的函数。在 GraphGPS 中,我们将两者结合起来!作者图片

图形转换器的利与弊

将整个图形输入到 Transformer 层会带来一些直接的好处和缺点。

✅优点:

  • 类似于图的重新布线,我们现在将节点更新过程从图结构中分离出来。
  • 处理远程连接没有问题,因为所有节点现在都相互连接在一起(我们经常分离来自原始图的真实边和在计算关注矩阵时添加的虚拟边——查看上面的插图,其中实线表示真实边,虚线表示虚拟边)。
  • 用“在迷宫中导航”来类比,我们可以使用地图,摧毁迷宫的墙壁,并使用魔法翅膀,而不是四处走动和寻找🦋。不过,我们必须事先学习地图,稍后我们将看到如何使导航更加精确和高效。

图表变形金刚给你翅膀🦋。来源:多米尼克·比艾尼@推特

🛑缺点类似于在 NLP 中使用变压器产生的缺点:

  • 语言输入是连续的,而图对于节点排序是排列不变的。我们需要图中节点更好的可识别性——这通常通过某种形式的位置特征来实现。例如,在 NLP 中,原始变换器使用正弦位置特征作为序列中令牌的绝对位置,而最近的 AliBi 引入了相对位置编码方案。
  • 失去使 GNNs 在具有明显局部性的图形上工作良好的归纳偏差,这是许多真实世界图形的情况。特别是在那些边代表相关/接近的地方。通过重新连接图形使其完全连接,我们必须以某种方式将结构放回原处,否则,我们很可能会“将婴儿与水一起扔掉”。
  • 最后但并非最不重要的是,限制可以是节点数量的平方计算复杂度 O(N ),而消息传递 gnn 是边数量 O(E)的线性。图形通常是稀疏的,即 N ≈ E,因此计算负担随着较大的图形而增加。我们能做点什么吗?

2021 年为 GTs 带来了各种各样的位置和结构特征,使节点更容易区分。

在 graph transformers 中,Dwivedi & Bresson 的第一个 GT 架构使用拉普拉斯特征向量作为位置编码,等人的的【SAN】也增加了拉普拉斯特征值相应地重新加权注意力,Ying 等人的graph former增加了最短路径距离作为注意力偏差,Wu、Jain 等人的 graph trans 在一个图通过后运行 GT

在图的位置特征领域,除了拉普拉斯导出的特征,最近的一批工作包括 Dwivedi 等人的随机行走结构编码(RWSE)采用 m 次幂随机行走矩阵的对角,Lim,Robinson 等人的sign net确保拉普拉斯特征向量的符号不变性,以及 Wang 等人的等变和稳定 PEs分别确保节点和位置特征的排列和旋转等变。

嗯,他们太多了🤯我如何知道什么最适合我的任务?

是否有一种原则性的方法来组织和使用所有这些图形转换器图层和位置要素?

是啊!这就是我们在最近的论文中提出的通用、强大、可扩展的图形转换器的配方。

graph GPS 框架

在 GraphGPS 中,GPS 代表:

🧩综合医院——我们提出了一个构建图形转换器的蓝图,将特征(预)处理、本地消息传递和全局注意力的模块合并到一个管道中

🏆强大的 —当与适当的位置和结构特征配对时,GPS 图形转换器被证明比 1-WL 测试更强大

📈可扩展的 —我们引入了线性全局注意力模块,突破了长期以来只在分子图上运行图转换器的问题(平均少于 100 个节点)。现在我们可以在每张有数千个节点的图上做这件事!

或者可能是指有位置和结构的图形?😉

将军:蓝图

如果我们可以利用这两个世界的优点,为什么我们需要修补消息传递 gnn 和图形转换器来实现某个特性呢?让模型决定对于一组给定的任务和图表什么是重要的。一般来说,蓝图可以用一张图来描述:

GraphGPS 蓝图提出了一种模块化架构,用于构建具有各种位置、结构特征以及局部和全局关注的图形转换器。来源: arxiv 。点击放大

它看起来有点庞大,所以让我们把它一部分一部分地分解,看看那里发生了什么。

总的来说,蓝图由三个主要部分组成:

  1. 通过位置和结构编码的节点标识。在分析了最近发表的许多增加图中位置性的方法后,我们发现它们可以大致分为三类:局部全局相对。这些特性非常强大,有助于克服臭名昭著的 1-WL 限制。更多信息请见下文!
  2. 具有原始图表要素的结点标识的聚合-即输入结点、边和图表要素。
  3. 处理层(GPS 层)-我们如何实际处理具有构造要素的图表,这里结合了本地消息传递(任何 MPNNs)和全局注意力模型(任何图表转换器)
  4. (奖金🎁)您可以将任何位置和结构特征与我们基于 PyTorch-Geometric 的新 GraphGPS 库中的任何处理层相结合!

功能强大;结构和位置特征

结构和位置特征旨在对每个节点或边的独特特征进行编码。在最基本的情况下(如下图所示),当所有节点都具有相同的初始特征或根本没有特征时,应用位置和结构特征有助于区分图中的节点,为它们分配不同的特征,并至少提供某种意义上的图结构。

结构和位置特征有助于区分图中的节点。作者图片。

我们通常将位置结构特征分开(尽管在理论上也有类似于斯里尼瓦桑&里贝罗的作品)。

直观地,位置特征帮助节点回答问题“我在哪里?”当结构特征回答“我的邻居看起来像什么?”

位置编码(PEs) 提供了图形中给定节点的空间位置的一些概念。它们帮助一个节点回答问题“我在哪里?”*。理想情况下,我们希望每个节点都有某种笛卡尔坐标,但是由于图是拓扑结构,并且在 2D 平面上有无限多种定位图的方法,我们必须考虑一些不同的方法。谈到 PEs,我们将现有的(和理论上可能的)方法分为 3 个分支——局部 PEs、全局 PEs 和相对 PEs。*

位置编码(PE)的分类。点击放大。作者图片。

👉局部 PE(作为节点特征)—在一个内,两个节点彼此越接近,它们的局部 PE 就越接近,比如一个单词在句子中的位置(而不是在文本中)。例子:(1)节点和包含该节点的簇的质心之间的距离;(2)m 步随机游走矩阵的非对角元素之和(m 次方)。

👉全局 PEs(作为节点特征)—在一个中,两个节点越接近,它们的全局 PEs 就越接近,例如一个单词在文本中的位置。例子:(1)原图变换器中使用的邻接或拉普拉斯的特征向量;(2)到整个图形的质心的距离;(3)每个连接组件的唯一标识符

👉相对 PE(作为边要素)-与任何局部或全局 PE 给出的距离相关的边表示,例如两个世界之间的距离。例子:(1)从热核、随机游走、格林函数、图测地线得到的成对距离;(2)邻接或拉普拉斯的特征向量的梯度,或者任何局部/全局 PEs 的梯度。

让我们来看一个关于这个著名分子☕️的各种 PE 的例子(根据他的 iclr’21 主题演讲,这是迈克尔布朗斯坦最喜欢的分子)。

咖啡因分子☕️.的局部、全局和相对位置编码的图示作者图片

结构编码 (SEs) 提供了图和子图的结构表示。它们帮助一个节点回答问题“我的邻居看起来像什么?”*。类似地,我们将可能的 SEs 分为局部、全局和相对,尽管是在不同的酱料下。*

结构编码的分类。点击放大。作者图片。

👉本地 SEs(作为节点特征)允许节点理解它是什么子结构的一部分。也就是说,给定两个节点和半径为 m 的 se,这些节点周围的 m 跳子图越相似,它们的局部 SE 就越接近。例子:(1)节点度(用于graphformer);(2)m 步随机行走矩阵的对角线(RWSE);③瑞西曲率;(4)枚举或统计三角形和环形等子结构(图子结构网络GNN 为核)。

👉全局 SEs(作为图形特征)向网络提供关于图形的全局结构的信息。如果我们比较两个图,如果它们的结构相似,它们的全局 SEs 将是接近的。例子:(1)邻接或拉普拉斯算子的特征值(用于);(2)众所周知的图的性质,如直径、连通分支数、围长、平均度。

👉相对 SEs(作为边特征)允许两个节点了解它们的结构有多少不同。当两个节点在同一个子结构中时,这些可以是任何局部 se 的梯度或布尔指示器(例如,在 GSN 中)。

咖啡因分子☕️.的局部、整体和相对结构编码的图解作者图片

根据图的结构,位置和结构特征可能会带来许多超越 1-WL 极限的表达能力。例如,在高度规则的循环跳跃链接(CSL) 图中,拉普拉斯的特征向量(我们框架中的全局 PEs)为 CSL (11,2)和 CSL (11,3)图分配唯一且不同的节点特征,使它们明显可区分(其中 1-WL 失败)。

位置(PEs)和结构(SEs)特征比 1-WL 更强大,但它们的有效性可能取决于图形的性质。作者图片。

PEs 和 SEs 的集合

考虑到 PEs 和 SEs 在不同的场景中可能是有益的,为什么你要用一个位置/结构特征来限制模型呢?

在 GraphGPS 中,我们允许组合任意数量的 PE 和 SE,例如,16 个拉普拉斯特征向量+特征值+ 8d RWSE。在预处理中,每个节点可能有许多向量,我们使用集合聚合函数将它们映射到要添加到节点特征的单个向量。

该机制允许使用子图 GNNs符号网等变和稳定 PEsk-子树 SATs 以及其他将节点特征构建为复杂聚合函数的模型。

现在,有了表达性的位置和结构特性,我们可以应对最后的挑战——可伸缩性。

可扩展:线性变压器🚀

几乎所有现有的图转换器都采用标准的自关注机制,将整个 N 矩阵具体化为 N 个节点的图(因此假设该图是完全连通的)。一方面,它允许向 GTs 注入边缘特征(像在图形成器中一样,该图形成器使用边缘特征作为注意力偏差)并将真实边缘与虚拟边缘分开(像在 SAN 中一样)。另一方面,具体化注意力矩阵的平方复杂度为 O(N ),这使得 GTs 很难扩展到超过 50-100 个节点的分子图。

幸运的是,NLP 中围绕变压器的大量研究最近提出了许多线性变压器架构,如 LinformerPerformerBigBird ,以线性地将注意力扩展到输入序列 O(N)。整个远程竞技场基准测试旨在评估超长序列的线性变压器。线性转换器的本质是绕过全注意力矩阵的计算,而是通过各种数学“技巧”来近似其结果,如 Linformer 中的低秩分解或 Performer 中的 softmax 内核近似。一般来说,这是一个非常活跃的研究领域🔥我们预计不久将会有越来越多有效的方法出现。

普通的 N 变压器(左)实现了完整的注意力矩阵,而线性变压器(右)通过各种近似绕过了这一阶段,而没有明显的性能损失。作者图片。

有趣的是,关于图转换器的线性注意力模型的研究并不多——到目前为止,我们只知道 Choromanski 等人最近的 ICML 2022 工作,不幸的是,这些工作没有在相当大的图上进行实验。

在 GraphGPS 中,我们建议用几乎任何可用的线性注意力模块来代替全局注意力模块(普通的变压器)。运用线性注意力会引出两个重要的问题,这两个问题需要我们做大量的实验来回答:

  1. 既然没有显式的注意矩阵计算,如何融入边缘特征?我们在 GTs 中到底需要不需要边缘特性?
    回答:根据经验,在我们基准测试的数据集上,我们发现 GraphGPS 中的线性
    全局注意力即使在没有边缘特征的情况下也能很好地工作(假设边缘特征是由一些经过 GNN 的局部消息处理的)。此外,我们从理论上证明了当输入节点特征已经编码了边缘特征时,线性全局注意不会丢失边缘信息。
  2. 线性注意力模型的速度和性能之间的权衡是什么?
    回答:权衡是相当有利的——我们在从方形注意力模型切换到线性注意力模型时没有发现重大的性能下降,但发现了巨大的内存提升。也就是说,至少在当前的基准测试中,您可以简单地将全部注意力转移到大得多的图上的线性和训练模型,而不会有巨大的性能损失。尽管如此,如果我们想对线性整体注意力表现更有把握,就需要有更大的图表和长期依赖性的更大的基准。

👨‍🍳烹饪时间——如何让你的 GT 发挥最大功效

长话短说——一个经过调整的 GraphGPS,结合了本地和全球的关注,与更复杂和计算更昂贵的模型相比表现非常有竞争力,并在许多基准上树立了一个新的 SOTA!

例如,在分子回归基准锌中,GraphGPS 达到历史新低 0.07 MAE。该领域的进步非常快—去年的 SAN 确实设定了 0.139 的 SOTA,因此我们将错误率提高了 50%!📉

此外,由于高效的实施,我们显著提高了图形转换器的速度——大约快了 400%🚀—ogbg-molp CBA 上的时间为 196 s/epoch,而之前的 SOTA 图形转换器型号 SAN 的时间为 883 s/epoch。

我们使用 PerformerBigBird 作为线性全局注意力模型进行实验,并将 GraphGPS 扩展到多达 10,000 个节点的图形,适合标准 32 GB GPU,这是以前任何图形转换器都无法实现的。

最后,我们开源了 GraphGPS 库(类似于 GraphGym 环境),在这里您可以轻松地插入、组合和配置:

  • 具有和不具有边缘特征的任何本地消息传递模型
  • 任何全局注意力模型,例如,全变压器或任何线性架构
  • 任何结构(SE)和位置(PE)编码方法
  • SEs 和 PEs 的任意组合,例如拉普拉斯 PEs 和随机游走 RWSE!
  • 聚合 se 和 PE 的任何方法,如 SignNet 或 DeepSets
  • 在 PyG 支持的任何图形数据集上运行它,或者使用自定义包装器运行它
  • 使用 Wandb 跟踪进行大规模实验
  • 当然,还要复制我们的实验结果

📜arxiv 预印本:https://arxiv.org/abs/2205.12454

🔧Github 回购:https://github.com/rampasek/GraphGPS

Python 图形:概述和最佳库

原文:https://towardsdatascience.com/graphs-with-python-overview-and-best-libraries-a92aa485c2f8

图形分析、交互式可视化和图形机器学习

预览。作者图片

一个是一个相对古老的数学数据实体,它是一组相连的元素。由于图是一种非常灵活的结构,并且允许你以人类熟悉和方便的形式存储信息,所以图一直被用于计算机科学和技术中。随着机器学习和深度学习的兴起,通过创建图机器学习领域,图获得了更多的流行。

在这篇文章中,我想与你分享我用于图形/网络分析、可视化和机器学习的最有用的 Python 库。今天,我们将回顾:

  • NetworkX 用于一般图形分析;
  • PyVis 在您的浏览器中实现交互式图形可视化;
  • PyGDGL 用于解决各种图形机器学习任务。

在此之前,我先给大家讲几句图论图机器学习的知识,并提供一些可能对你有帮助的学习资源。如果你不知道什么是图或图机器学习,那是揭开保密面纱的绝好机会!

图论和图机器学习:简介

图形只是一组相互连接的元素。

图表示例。公共领域

然而,这些元素(称为节点)可以包含任何信息,并且可以以任何方式连接(用)的事实使得图成为最通用的数据结构。事实上,我们熟悉的任何复杂数据都可以用一个简单的图形来表示:例如,一幅图像——一个像素或文本的网格——一个单词序列(或单词链)。

你可能会想:图表真的如此重要吗?嗯,有些任务没有它们根本无法解决,甚至无法公式化,因为有些信息无法用数据来组织。想象一下下面的情况:你需要访问一个城市列表,比如旅游或工作。你有从一个城市到另一个城市的距离的信息,或者说,不同交通方式的票价——这就更有趣了!如何打造一条最优路线,即花最少的钱或开最短的距离?

对我来说,这个任务相当实际——至少想想它在物流方面的应用。这是一个没有图表帮助就无法解决的问题的例子。想想你将如何表示数据,在任何情况下,你仍然会得到加权图(图的边有一些值,称为权重)。顺便说一下,如果每个城市都需要恰好被访问一次,那么这个任务就变成了著名的旅行商问题(TSP) ,这个问题不那么容易解决。原因之一是可能的路线数量增长非常快,甚至对于 7 个城市来说,已经有 360 条了!

用蛮力搜索法求解 7 城市 TSP。公共领域

图论(起源于 18 世纪)从事图的研究,解决各种图的问题:在图中寻找一条可能的或最优的路径,建立并研究(一种特殊类型的图)等等。图论被成功地应用于社会科学、化学、生物学和其他领域。但是随着计算机的发展,使用图形的过程达到了另一个层次。

真正重要的是,这个基础:一组相关元素,通常具有不同的元素和连接类型,对于建模真实世界的任务和数据集非常有用。这就是图机器学习发挥作用的地方(尽管在它之前也解决了惊人的任务)。在人类收集了适当的数据集并开发了对它们进行建模的技术(如 【图卷积网络(GCNs)】,以此类推 【卷积神经网络(CNN))之后,解决大范围的图任务成为可能:

  • 节点级任务,如节点分类 —为图中的每个节点分配一个标签。下面一点我们会看到一个例子——把一群人分成两个集群,知道他们是如何相互交流的;但是其他应用程序可能会非常不同。这里的直觉来自社会科学,它说我们依赖于我们的环境。事实上,任何实体都可以被更有效地分类,不仅考虑一些特征集,而且考虑关于其邻域的数据。例如,如果你的朋友吸烟,你更有可能吸烟,如果你的朋友去健身房,你更有可能去健身房。
  • 边缘级任务,如边缘预测 —预测两个节点是否有一条边缘,或者更常见的是,预测边缘类型(有几种边缘类型的图称为多图)。这个任务对于我们几分钟后看到的知识图表来说非常有趣。
  • 图表级任务。这可以是图形分类图形生成、等等。这个领域对生物学和化学特别有用,因为分子可以有效地用图形表示。分子分类(确定分子是否具有某些性质)或者分子生成(尤其是药物生成)听起来比一些“图级任务”酷多了!

让我们看看现实生活中的图表示例。最著名的图形数据集之一是空手道俱乐部数据集。在这里,每个节点是一个人(俱乐部成员),每个边代表在俱乐部之外互动的两个成员。

空手道俱乐部数据集可视化。公共领域

一个常见的问题是,在两个教练之间发生争论后,找到俱乐部分裂成的两组人(现在我们可以将其视为二元(或 2 类)节点分类)。该数据集收集于 1977 年,并成为人类社会网络或社区结构的经典范例。

另一种图表类型是知识图表,它可以被人类理解,因此对机器学习模型非常有用。在知识图中,节点是一些实体或概念,而边表示关于一对实体的交互的知识。因此,节点-边缘-节点结构存储了关于世界或特定系统的某个事实。

知识图的一个简单例子。公共领域

上面例子中的知识图包含两种类型的边:,因此是我们前面介绍的多图Dogs-is-Animals 结构让我们知道“Dogs”集合是“Animals”集合的子集,或者用更简单的术语来说,就是 dogs 是 animals

Wikidata 是维基百科的一个庞大的免费知识库,不断更新,现在已经拥有超过 1 亿个节点。有 400 多种边缘类型,其中一些是的部分、不同于对面、人口位置,所以肯定有意义。

2020 年维基百科知识库中的 20 大边缘关系。公共领域

这个庞大的知识库包含了我们周围世界的大量信息。我仍然很惊讶人类是如何收集这些数据的,而且机器现在能够处理这些数据!

我不能保持沉默的另一件事是维基数据美丽的可视化功能。例如,这里你可以看到美国的连接图。注意,它不是任何人画的,它只是整个维基数据图的一个子图:我们只把美国各州作为节点,把 P47(与)作为边。

美国各州的连通性。公共领域

看看维基数据图表生成器其他可视化。让我给你举几个我觉得有趣的例子:

了解更多关于图表的信息

如果在那个简要的概述之后,你现在对图形感兴趣,并且想知道更多关于它们的信息,我向你推荐 Google Research 的精彩的图形神经网络简介。在本文中,您可以找到更多的示例和交互式可视化。

查看 freeCodeCamp.org 的图论算法课程,了解各种图论算法概述,或斯坦福 CS224W:机器学习与图形课程开始您的图形机器学习之旅。

简单介绍之后,让我们实际上从 Python 库开始吧!

NetworkX —通用图形分析

如果您必须对图形进行一些操作,并且您使用 Python 作为编程语言,您很可能会很快找到 NetworkX 库。它可能是最基本、最常用的网络分析库,提供了广泛的功能:

  • 用于存储和操作无向或有向图和多重图的数据结构;
  • 实现了许多图形算法;
  • 基本的可视化工具。

该库非常直观且易于使用。此外,大多数基础知识,如图形数据结构对于所有流行的图形库来说将保持相同或至少相似。为了清晰起见,您可以创建一个简单的图形,并用以下代码可视化它:

基本的 NetworkX 可视化。作者图片

说到算法,networkx 非常强大,已经实现了数百个图算法。

总的来说,这是一个高效的、可伸缩的、强大的库,如果你正在处理图形分析,它肯定会对你有用。

参考

PyVis —交互式图形可视化

使用 networkx 进行图形可视化对于小图形来说是非常好的,但是如果你需要更多的灵活性交互性,你最好给 PyVis 一个机会。情况类似于matplotlibvsplotly。使用 matplotlib 进行快速直观的可视化是非常好的,但是如果您需要与您的图表进行交互或者将其展示给其他人,您最好使用更强大的工具。

PyVis 构建在 VisJS 库之上,用简单的代码在浏览器中生成交互式可视化。让我们绘制与上例相同的图形。

这段代码将创建一个graph.html文件。通过打开它,您将能够与您的可视化交互:缩放它,拖动它,等等。

PyVis 可视化示例。作者 Gif

看起来很有趣,对吧?该库甚至允许您使用 web UI 来动态调整显示配置。一定要查看官方教程,它会带你了解主库的功能。

参考

https://pyvis.readthedocs.io/en/latest/ [## 交互式网络可视化— pyvis 0.1.3.1 文档

pyvis.readthedocs.io](https://pyvis.readthedocs.io/en/latest/)

DGL 和 PyG 图机器学习

现在让我们切换到更高级的话题——图机器学习。我将提到两个最受欢迎的图书馆:DGL 和 PyG。

DGL(深度图库)最初于 2018 年发布。与 PyG (PyTorch Geometric)相反,PyG 建立在 PyTorch 之上,因此只支持 PyTorch 张量,DGL 支持多种深度学习框架,包括 PyTorch、TensorFlow 和 MXNet。

两个库都实现了流行的图形神经网络(GNN)单元,例如 GraphSAGEGAT(图形注意力网络)GIN(图形同构网络)等等。从预制块构建一个模型并不困难——这个过程与普通 PyTorch 或 TensorFlow 非常相似。

以下是如何在 PyG 中为节点分类创建两层 GCN 模型:

DGL 也有同样的代码:

如果你熟悉深度学习和 PyTorch,这两个代码片段都非常简单。

如您所见,两个库的模型定义非常相似。然后,可以在 PyG 的普通 PyTorch 上编写训练循环,并需要对 DGL 进行一些修改(因为 DGL 图对象存储整个数据集,您必须使用二进制掩码来处理训练/验证/测试集)。

这里的数据表示略有不同:至少基于forward方法的不同输入参数,您可以看到这一点。事实上,PyG 将所有东西都存储为 PyTorch 张量,DGL 有一个你必须使用的单独的图形对象,在这个引擎盖下,它遵循了更经典的 NetworkX 风格。

然而,这没什么大不了的——您可以用几行代码将 PyG 图对象转换成 DGL 图,反之亦然。更重要的问题是:它们还有什么不同?你应该用哪一个?

DGL vs PyG

试图找出哪个库更好,你会不断遇到同一个答案——“两个都试试,决定哪个最适合你”。好吧,但它们至少有什么不同?同样,你会不断遇到的答案是“他们很相似”

他们真的是!而且,你几分钟前看代码自己也看到了。但是当然,深入挖掘,您会发现一些差异:这里有一个很好的资源列表,包括库作者的一些想法,这里有一个非常详细的不同方面的比较。

总的来说,答案真的是两个都试试。事实上,DGL 有更多的低级 API,在实现新思想的意义上更难使用。但这使得它更加灵活:DGL 并不局限于消息传递网络(经典图卷积网络 ) 并且拥有 PyG 无法提供的几个概念的实现,例如树-LSTM

另一方面,PyTorch Geometric 使他的 API 尽可能简单,然后在能够快速实现新想法(即新 GNN 细胞)的研究人员中获得更多的欢迎。在过去的时间里, PyG 变得越来越受欢迎,这是由于 PyG 2.0 的重要更新以及包括斯坦福大学在内的活跃而强大的合作者团队。

过去 5 年 DGL 与 PyG 搜索查询的数量。公共领域

所以我还是鼓励你两个都试试,先给 PyG 机会

如果您正在处理一个相对熟悉的图问题(无论是节点分类、图分类等等。),无论是 PyG 还是 DGL 都实现了大量的 GNN 单元。同样,使用 PyG,您可以更轻松地在任何研究中实现自己的 GNN。

然而,如果您想完全控制幕后发生的事情,或者实现比消息传递框架更复杂的东西,您的选择很可能会落在 DGL 身上。

参考

结论

这篇文章的目标受众(对图形感兴趣的人)相当少。嗯,机器学习是计算机科学中一个相当年轻的领域,图机器学习更年轻。最后一个主要吸引研究社区的注意,但是,信不信由你,它被用在重要的现实世界应用中,例如推荐系统和生物/化学研究。

无论如何,我希望这些资料对你来说是有趣的或有帮助的——不管你是在寻找什么特别的东西,还是今天刚刚学到了一些新东西。作为回顾,今天我们简要回顾了什么是图形和图形机器学习,并查看了以下库:

  • NetworkX :通用图形分析;
  • PyVis:交互式图形可视化;
  • PyGDGL :图上的机器学习。

感谢您的阅读!

  • 我希望这些材料对你有用。在媒体上关注我以获得更多类似的文章。
  • 如果您有任何问题或意见,我将很高兴得到任何反馈。在评论里问我,或者通过 LinkedIn 或者 Twitter 联系。
  • 为了支持我作为一名作家,并获得数以千计的其他媒体文章,使用我的推荐链接获得媒体会员资格(不收取额外费用)。

远大前程:数据科学和工程团队的自动化测试

原文:https://towardsdatascience.com/great-expectations-automated-testing-for-data-science-and-engineering-teams-1e7c78f1d2d5

验证、描述和记录您的数据

约翰尼斯·安德森在 Unsplash 上拍摄的照片

我曾经在一家零售分析公司工作,我们提供分析解决方案来帮助零售商改善他们的业务,如库存和分配优化、需求预测和动态定价。

典型的工作流程始于客户的日常反馈,即用作我们解决方案输入的原始数据。在一系列数据清理、操作、分析和建模步骤之后,结果被创建并发送给客户。

此类流程中的一个主要挑战是来自客户的数据的验证。如果它包含一些意想不到的或荒谬的值,结果将是无用的。事实上,它们可能弊大于利。

如果在结果步骤中检测到这些问题,影响只会加速。您可能需要重新运行管道,这意味着额外的成本和时间的浪费。更糟糕的情况是将结果发送给客户,然后客户在他们的操作中使用它们。

解决方案

幸运的是,我们有很多工具来防止这样的灾难发生。远大前程就是其中之一。这是一个 Python 库,用于验证、记录和分析您的数据,以保持质量并改善团队之间的交流。

高期望值允许断言您对数据的期望,这有助于在早期阶段快速发现数据问题。

该库的主要组件是 expect,它是一个可以由计算机评估的声明性语句。期望基本上是对你的数据的单元测试。

期望被赋予直观的名称,清楚地告诉我们它们是关于什么的。这里有一个例子:

expect_column_values_to_be_between(
    column="price", min_value=1, max_value=10000
)

这个期望的作用是检查列中的值是否在指定的最小值和最大值之间。

核心库中定义了很多期望。然而,我们不仅限于或依赖于这些。

远大前程图书馆有更多来自社区的期望。

如何使用它

我们可以通过 pip 安装它,如下所示:

pip install great_expectations

然后,我们可以导入它:

import great_expectations as ge

让我们用我用模拟数据准备的销售数据集来做一些例子。你可以从我的 GitHub 页面上的数据集库中下载。叫做“销售 _ 数据 _ 与 _ 商店”。

为了使用期望,我们需要一个巨大的期望数据集。我们有两种不同的方法来创建它:

  • 使用 from_pandas 函数从 Pandas 数据帧中
  • 使用远大前程的 read_csv 函数从 CSV 文件中
import great_expectations as gedf = ge.read_csv("datasets/sales_data_with_stores.csv")type(df)
great_expectations.dataset.pandas_dataset.PandasDatasetdf.head()

df 的前 5 行(图片由作者提供)

期望 1

为了捕捉具有不同值的列中的意外值,我们可以使用 expect _ column _ distinct _ values _ to _ be _ in _ set 期望。它检查列中的所有值是否都在给定的集合中。

让我们在商店列上使用它。

df.expect_column_distinct_values_to_be_in_set(
    "store",
    ["Violet", "Rose"]    
)**# output**
{
  "result": {
    "observed_value": [
      "Daisy",
      "Rose",
      "Violet"
    ],
    "element_count": 1000,
    "missing_count": null,
    "missing_percent": null
  },
  "exception_info": {
    "raised_exception": false,
    "exception_traceback": null,
    "exception_message": null
  },
  "meta": {},
  "success": false
}

预期失败(即 success: false ),因为 store 列中有一个值(Daisy)不在给定的列表中。

除了指示成功和失败之外,期望值的输出还包含一些其他信息,例如观察值、值的数量以及列中缺少的值。

期望 2

我们可以检查列的最大值是否在特定范围内:

df.expect_column_max_to_be_between(
    "price",
    min_value=0.1,
    max_value=2000
)**# output**
{
  "result": {
    "observed_value": 1500.05,
    "element_count": 1000,
    "missing_count": null,
    "missing_percent": null
  },
  "exception_info": {
    "raised_exception": false,
    "exception_traceback": null,
    "exception_message": null
  },
  "meta": {},
  "success": true
}

输出是字典格式的,所以我们可以很容易地使用它的特定部分,并在我们的管道中使用它。

max_check = df.expect_column_max_to_be_between(
    "price",
    min_value=0.1,
    max_value=2000
)max_check["success"]**# output**
True

期望 3

值的唯一性对于某些功能(如 id 列)非常重要。我们可以检查一列中的所有值是否都是唯一的。

# for a single column
df.expect_column_values_to_be_unique("product_code")# for multiple columns
df.expect_compound_columns_to_be_unique(
    column_list=["product_code","product_group"]
)

这些期望值的输出很长,所以我没有在这里展示,但是它们包含了有价值的见解,比如意外值的数量和部分意外值列表。

期望 4

一个简单而有用的期望是检查数据集中是否存在特定的列。

df.expect_column_to_exist("cost")**# output**
{
  "result": {},
  "exception_info": {
    "raised_exception": false,
    "exception_traceback": null,
    "exception_message": null
  },
  "meta": {},
  "success": true
}

当您希望确保每日数据馈送包含所有必要的列时,这很方便。

结论

我们只做了 3 个例子,但是目前库中有 297 个期望,并且这个数字还在增加。

我非常喜欢这些期望的一点是它们的名字是不言自明的,因此很容易理解它们的作用。

您可能会争辩说,这些期望可以使用纯 Python 代码或其他一些包来检查。你是对的,但是使用远大前程库有一些好处:

  • 易于实施
  • 拥有标准且高度直观的语法
  • 有些期望不是很简单,如果你喜欢自己做,需要写很多行代码
  • 最后但同样重要的是,《远大前程》还根据这些期望创建了数据文档和数据质量报告。

你可以成为 媒介会员 解锁我的全部写作权限,外加其余媒介。如果你已经是了,别忘了订阅如果你想在我发表新文章时收到电子邮件。

感谢您的阅读。如果您有任何反馈,请告诉我。

格林利特:使用 GPT J 与多任务学习创造新的电影剧本

原文:https://towardsdatascience.com/greenlit-using-gpt-j-with-multi-task-learning-to-create-new-screenplays-54a2d04f761c

如何微调一个 ML 模型来创建具有新标题、情节概要和脚本的电视节目和电影

科技日报在 Unsplash 上拍摄的

我在的上一篇文章中展示了我如何微调 GPT J 来生成俳句,结果相当不错。在我的最新实验 GreenLIT 中,我想突破使用 GPT J 进行创意写作的限制,看看它是否能为全新的电视节目和电影制作剧本。

这是 GreenLIT 的组件和流程框图。我将在下面的小节中详细讨论这些。

GreenLIT 组件,作者提供的图表

首先,我在网上搜索了一下,找到了五个带文本的开源数据集,用作训练数据:

  • 康奈尔大学 ConvoKit 项目的电影对话(麻省理工学院许可)[1]
  • 电影情节摘要来自 Kaggle 上的 Rounak Banik(CC0 许可证)[2]
  • 来自 ConvoKit 项目的朋友对话(麻省理工学院许可)[1]
  • 来自维基百科的朋友情节摘要(CC-BY-SA 许可)[3]
  • Kaggle 上 Shivam Bansal 的流媒体节目分析(CC0 许可证)[4]

第一个和第三个数据集包含电影和热门情景喜剧《老友记》中的对话其他数据集包括电视节目和电影的标题、类型和情节概要。我写了一些 Python 代码来预处理和过滤文本,为 GPT-J 要学习的四个任务创建一组条目:

  1. 体裁和主题→标题和情节
  2. 标题和情节→对话框
  3. 标题和情节→剧本
  4. 对话框→脚本

注意对话仅仅意味着角色的名字和台词,而剧本是对话加上舞台指示。我将在下面进一步详细解释这一切。

我从 GPT-J [5]模型开始,它是 GPT-3 [6]的开源变体。GPT-J 之前在一个名为 Pile [7]的网络上接受了大量文本数据的训练。

我在 Google Colab 上用超过 38,000 个训练条目对 GPT-J 进行了 20 小时的微调,以创建我的 GreenLIT 模型。在我对其进行微调之后,我使用了以下文本提示作为输入。

GENRE: **crime drama**
THEME: **cryptocurrency**

根据该提示,GreenLIT 模型生成了以下标题和情节摘要:

#1\. TITLE: **Bitcoin Heist**
SUMMARY: Two young men embark on a heist that could be the start of a new revolution.#2\. TITLE: **Satoshi's Daughter**
SUMMARY: A crime drama about a woman who inherits a cryptocurrency fortune.#3\. TITLE: **The Dark Web**
SUMMARY: The story of two brothers who join the underground Bitcoin economy.#4\. TITLE: **Cryptostorm**
SUMMARY: Cryptostorm revolves around the story of a young man who has been trying to keep his life on track after being sent to
prison for a crime he didn't commit.#5\. TITLE: **The Cypher**
SUMMARY: A young hacker joins a group of underground hackers to create a secure platform.

我从这个列表中选择了#3,黑暗之网,并将标题和摘要发送回 GreenLIT 以创建脚本的第一页。在这里。

TITLE: **The Dark Web** SUMMARY: The story of two brothers who join the underground Bitcoin economy.
SCRIPT:[Scene: The living room of the house, the door opens and the brothers come in. They are both dressed in black, have their hoods up.]LEO - Okay, we did it! We hit the mother lode!
DREW - We hit the mother lode?
LEO - Yeah!
DREW - How much is in here?
LEO - Six hundred and forty dollars worth.
DREW - (To himself) Well, that's better thaan nothing.
LEO - The bitcoins are untraceable.
DREW - The bitcoins?
LEO - Yeah, the Bitcoin is basically just a name for a cryptographic currency.
DREW - A cryptographic currency?
LEO - Yeah, like, a secure, internet way of transferring money from one person to another.
DREW - Sounds like they invented the internet.
LEO - Well, the internet is just a network of computers connected to other computers by phone lines, but the internet is also the thing that makes it possible to transfer money from one computer to another without a bank.
DREW - Oh, yeah?
LEO - Yeah.
DREW - How do you do that?
LEO - Well, it's actually really complicated, and I don't understand it myself, but the short version is that the Bitcoin is run by a bunch of computers all connected to each other. It's kind of like a decentralized Ponzi scheme.
DREW - A decentralized Ponzi scheme?
LEO - Yeah, you know, like the government runs a Ponzi scheme.

好吧,有意思。剧本似乎幽默地解释了加密货币的基础知识,并对角色进行了一些发展。加上一点社会评论。请稍等,我给我的代理人打电话。😉

你可以在 Google Colab 上免费查看 GreenLIT 这里。请务必查看下面附录中的更多示例输出。

系统详细信息

在接下来的小节中,我将深入探讨 GreenLIT 中使用的组件和流程的细节。我将首先讨论一种称为多任务学习的训练神经网络的技术。

多任务,来源:PxHere,CC0 公共域

多任务学习

对于 GreenLIT 项目,我有两个主要目标,(A)根据给定的类型和主题创建新节目的标题和情节概要,以及(B)根据给定的标题和情节概要创建脚本的第一页。虽然微调两个专门的人工智能模型可以工作,但我想看看一个微调的模型是否可以完成这两项任务。这样做有几个好处。正如我在我的深度俳句项目中发现的那样,针对多个但相似的任务微调一个模型,即多任务学习,可以提高两个任务的结果。里奇·卡鲁纳在卡内基·梅隆大学研究了这一技术。

多任务学习是一种归纳迁移的方法,它通过使用相关任务的训练信号中包含的领域信息作为归纳偏差来提高泛化能力。它通过使用共享表示并行学习任务来做到这一点;每个任务学到的东西可以帮助其他任务学得更好。—里奇·卡鲁纳

为了解释多任务学习是如何工作的,亚历山大·巴甫洛夫·洪查尔在他的文章中描述了一个叫做“特征选择双重检查”的概念。他说,“如果一个特征对于不止一个任务是重要的,那么很可能这个特征对于你的数据来说确实是非常重要和有代表性的”,并且将在多任务学习期间被系统强化。

另一个优势是实际效率——只需要加载一个 AI 模型来执行这两项任务。使用一种模式可以减少磁盘存储、加载时间和 GPU 内存。

接下来,我将讨论我是如何为项目收集训练数据的。

Joshua SortinoUnsplash 上拍摄的照片

收集训练数据

为了针对第一项任务(生成新节目的标题和剧情摘要)对系统进行微调,我寻找了包含电影和电视节目元数据的开源数据集。

收集电影情节

在拥有众多数据集的 Kaggle 上,我发现了一个由 Rounak Banik 编写的电影情节摘要的大型列表,名为电影数据集。它包含标题、发行年份、类型、摘要等。,对于超过 40K 的电影。他在 CC0(公共领域)许可下发布了数据集。以下是 5 个条目的示例。

来自电影数据集的样本条目,来源: Kaggle 上的 Rounak Banik,CC0 公共域

我使用了一个名为 KeyBERT [9]的模块来从摘要中提取主题。你可以在这里看到我的 Python 代码。

我在 Shivam Bansal 的 Kaggle 上找到了另一个数据集集合。他收集了网飞、亚马逊、Hulu 和 Disney+上大约 2 万个流媒体节目的摘要。这是一个数据样本。

来自流媒体服务的样本条目,来源: Kaggle 上的 Shivam Bansal,CC0 公共域

我再次使用 KeyBERT 从流媒体节目的摘要中捕捉主题。

为了教 GPT-J 如何从类型和主题中创建标题和摘要,我为每个电影和电视节目收集了一个这样的条目。

GENRE: action science fiction
THEME: saving the world
TITLE: The Matrix
SUMMARY: Set in the 22nd century, The Matrix tells the story of a computer hacker who joins a group of underground insurgents fighting the vast and powerful computers who now rule the earth.GENRE: comedy sitcom
THEME: workplace comedy
TITLE: 30 Rock
SUMMARY: The life of the head writer at a late-night television variety show. From the creator and stars of SNL comes this workplace comedy. A brash network executive bullies head writer Liz Lemon into hiring an unstable movie star.

收集电影和电视剧本

接下来,我搜索脚本数据集。引用黑暗网络的 Leo 的话来说,当我发现康奈尔大学的 ConvoKit 时,“我找到了主矿脉”。收集数据集的正式名称是康奈尔对话分析工具包[1],在麻省理工学院开源许可下发布。

[ConvoKit]包含提取对话特征和分析对话中社会现象的工具,使用受 scikit-learn 启发(并与之兼容)的单一统一界面。包括了几个大型对话数据集,以及在这些数据集上使用工具包的脚本示例。— Jonathan P. Chang 等人。

我使用了 ConvoKit 中两个数据集的 dialog 来微调 GreenLIT。以下是来自他们网站的数据集描述。

  • 康奈尔电影对话语料库-从原始电影剧本中提取的大量元数据丰富的虚构对话集。(617 部电影中 10,292 对电影角色之间的 220,579 次会话交流)。
  • 《老友记》语料库——收集了 10 季《老友记》中的所有对话,这是一部流行于 20 世纪 90 年代的美国电视情景喜剧。

这是康奈尔电影对话语料库中《卢旺达酒店》中的一段对话。

PAUL - What's wrong?
ZOZO - Beg your pardon sir, you are Hutu. You are safe there.
PAUL - You are with me, Zozo, don't worry.
ZOZO - What is it like to fly on a plane, sir?
PAUL - It depends where you sit Zozo. In coach it is like the bus to Giterama.
ZOZO - That is why they call it coach?
PAUL - Maybe. But in business class there are fine wines, linens, Belgian chocolates.
ZOZO - You have taken business class?
PAUL - Many times.
PAUL - I will try my best George but these days I have no time for rallies or politics.
GEORGE - Politics is power, Paul. And money.Gathering TV Scriptss

伊尔塞·奥尔塞尔在 Unsplash 上拍摄的照片

这是《老友记》的一个片段,故事发生在他们最喜欢的咖啡馆中央公园。

**SCRIPT:** [Scene, Central Perk]MONICA - There's nothing to tell! He's just some guy I work with!
JOEY - C'mon, you're going out with the guy! There's gotta be something wrong with him!
CHANDLER - All right Joey, be nice. So does he have a hump? A hump and a hairpiece?
PHOEBE - Wait, does he eat chalk?(They all stare, bemused.)PHOEBE - Just, 'cause, I don't want her to go through what I went through with Carl- oh!
MONICA - Okay, everybody relax. This is not even a date. It's just two people going out to dinner and- not having sex.
CHANDLER - Sounds like a date to me.

添加舞台方向

注意,与《老友记》的剧本不同,《卢旺达饭店》的剧本没有任何舞台指导。它只有对话框。

为了教 GreenLIT 模型如何添加舞台指示,我从老友记创建了一组只有对话框的脚本,如下所示,后跟脚本。这些训练条目由以下内容组成:“对话:“+台词+”脚本:“+带舞台指示的台词。

**DIALOG**:
MONICA - There's nothing to tell! He's just some guy I work with!
JOEY - C'mon, you're going out with the guy! There's gotta be something wrong with him!
CHANDLER - All right Joey, be nice. So does he have a hump? A hump and a hairpiece?
PHOEBE - Wait, does he eat chalk?
PHOEBE - Just, 'cause, I don't want her to go through what I went through with Carl- oh!
MONICA - Okay, everybody relax. This is not even a date. It's just two people going out to dinner and- not having sex.
CHANDLER - Sounds like a date to me.

微调之后,如果我用“…对话框:”结束提示,它将只创建对话框。但是如果我以“… SCRIPT:”结束提示,它会知道生成带有舞台指示的对话框。这是行动中的多任务学习!

接下来,我将讨论如何解决在生成的脚本中重复字符名称的问题。

顶级婴儿名字,来源:美国社会安全局,公共领域

使角色名字多样化

经过一些初步实验后,我注意到在训练数据集中包含朋友脚本会导致模型经常使用六个中心人物的名字。例如,系统将创建以 18 世纪为背景的具有名为乔伊、菲比和钱德勒的人物的时期片断。

为了使角色名字多样化,我把 236 集《老友记》的角色名字都换了。我用的是美国社会保障办公室收集的列表。

例如,上面显示的脚本将这些角色名称用于训练数据:

罗斯→卢卡斯
钱德勒→安东尼奥
乔伊→埃迪
瑞秋→夏洛特
菲比→斯特拉
莫妮卡→露丝安娜

我还把所有提到“中央公园”的地方都改成了“咖啡店”,以帮助去掉剧本中的“朋友关系”。下面是修改后的脚本:

**SCRIPT**:
[Scene, Coffee Shop]LUCIANA - There's nothing to tell! He's just some guy I work with!
EDDIE - C'mon, you're going out with the guy! There's gotta be something wrong with him!
ANTONIO - All right Eddie, be nice. So does he have a hump? A hump and a hairpiece?
STELLA - Wait, does he eat chalk?(They all stare, bemused.)STELLA - Just, 'cause, I don't want her to go through what I went through with Carl- oh!
LUCIANA - Okay, everybody relax. This is not even a date. It's just two people going out to dinner and- not having sex.
ANTONIO - Sounds like a date to me.

有趣的是,仅仅改变角色的名字就让它看起来像是一部不同的电视剧。

为朋友收集情节摘要

因为 ConvoKit 数据集不包含任何情节摘要,所以我从维基百科上搜集了所有老友记剧集的摘要。

《老友记》第一季的剧集,来源:维基百科CC-BY-SA

获取摘要的源代码是这里的。我再次使用 KeyBERT 来获取剧集主题的关键词。

以下是我为训练 GPT-J 而收集的数据摘要

green lit的培训数据汇总,表格由作者提供

一旦我准备好了所有的训练,我就开始微调 GPT J 来创作新的节目和剧本。

微调 GPT J

类似于我在我的深度俳句项目中所做的,我微调了 GPT-J 来学习和运行 GreenLIT 所需的所有四个任务:

  1. 体裁和主题→标题和情节
  2. 标题和情节→对话框
  3. 标题和情节→剧本
  4. 对话框→脚本

来自 Eleuther AI [5]的 GPT-J 模型是 OpenAI 的居里模型的大小,是第二大的 GPT-3 模型[6]。Eleuther AI 在 Pile 上训练模型,这是一个用于语言建模的多样化文本的巨大(800GB)数据集[7]。

谷歌实验室只有 16g 内存的 GPU,如果照原样使用,GPT J 将耗尽内存。为了在 Colab 上运行它,我使用微软的 Edward Hu 等人的低秩自适应技术将具有 32 位参数的 GPT-J 6-B 转换为 8 位参数[8]。你可以在这里阅读艾勒瑟艾的模型卡上的详细内容。

运行系统

在对模型进行微调后,我用它来创建新的标题和摘要以及节目的脚本。

然而,我注意到的第一件事是,系统经常会为以前制作的节目生成标题。这并不令人惊讶,因为我用现有节目的数据对它进行了微调。为了弥补这一点,我创建了一个小的 Python 函数来检查是否有任何新创建的标题以前被使用过,使用维基百科作为参考。

例如,我用类型:犯罪喜剧和主题:巴迪银行抢劫案运行系统。七个生成的标题中有四个来自现有的节目。我在下面的结果中用一串星号标记了这些“重复”。

01 **The Bank Heist Gang** - A group of friends decides to do a bank heist before things go haywire.02 *** **The Bank Job** - A group of ex-cons and petty criminals rob a bank in a small town. While carrying out the heist, they become involved in romantic entanglements, and the heist itself turns into a big, silly mess.03 *** **Buddy Buddy** - The film opens with a young man who, while on a business trip, is robbed by his own bodyguard who is also the son of the man who owns the bank.04 **The Bumstead Affair** - When a bank robbery goes awry, a group of young men decide to get rich quick by robbing the other robbers.05 *** **Get Shorty** - Get Shorty is a crime comedy centered around three friends who get involved in a heist.06 **The Great American Caper** - A man and his best friend have a scheme to rob a bank.07 *** **The Hustler** - A Las Vegas bank robber attempts to double-cross the mob by holding up their own bank... and the movie changes into a slapstick comedy.

我从原始标题中选择了 Bumstead 事件来查看生成的脚本。在这里。

[Scene: All of the guys are in the basement where Trench is at the computer. The guys are discussing the upcoming robbery attempt.]D'JACK - We're gonna hit the bank on Sunday. The place is closed on Sunday. The cops will never know.
TRENCH - Yeah, but...
D'JACK - But what?
TRENCH - What about the cameras?
D'JACK - The cameras are gonna be out.(The guys are looking at the computer monitor)D'JACK - And we'll make sure the alarm's gonna be out, too.
TRENCH - Yeah, but then...
D'JACK - Then what?
TRENCH - Then we'll be in the bank and we're gonna get rich?
D'JACK - Right, that's the goal.

好吧,这很简单。但我喜欢特伦奇和杰克这两个角色的名字。我也喜欢包含舞台说明。

讨论结果

我和 GreenLIT 玩了一周左右,它似乎在为节目提出新想法方面做得很好,尽管它经常重复使用标题。请注意,插入一个新的流派和主题会减少重复。

然而,生成的脚本中的对话框对我来说似乎有点乏味。好消息是对话看起来很自然,但是散文的内容通常很简单。这可能是因为所有的新剧本都是为一部剧的第一页第一场设计的。他们直接进入介绍性的阐述。

查看附录以获得更多示例脚本。

源代码和 Colabs

这个项目的所有源代码都可以在 GitHub 上找到。我在 CC BY-SA 许可下发布了源代码。

知识共享署名共享

感谢

我要感谢詹尼弗·林和奥利弗·斯特瑞普对这个项目的帮助。

参考

[1] Jonathan P. Chang,Caleb Chiam,Liye Fu,,Justine Zhang,Cristian Dane scu-Niculescu-Mizil .2020. 对话工具包:对话分析工具包《SIGDIAL 会议录》。

[2] R. Banik,Kaggle 上的电影数据集(2018)

【3】维基百科, 好友剧情概要

[4] S. Bansal,Kaggle 上的流媒体电影和电视节目(2022)

[5] GPT-J网格-变压器-JAX:模型-与 JAX 并行实现变压器语言模型 (2021)

[6] GPT-3 、T. B .布朗、b .曼恩、n .赖德、m .苏比亚、j .卡普兰、p .达里瓦尔、A .尼拉坎坦等人语言模型是一次性学习者 (2020)

[7] L.Gao 等, The Pile :一个 800GB 的用于语言建模的多样化文本数据集 (2020)

[8] R .卡鲁阿纳, 多任务学习 (1997)

[9] M. Grootendorst, KeyBERT :用 BERT 进行最小关键词提取(2020)

[10] E .胡等, LoRA :大型语言模型的低秩适应 (2021)

附录

以下新节目的剧本是用 GreenLIT 创作的。我提供了流派和主题,系统生成了 5 到 10 个标题和摘要。然后我选择我最喜欢的,系统生成脚本。

机器人定位系统

GENRE: science fiction drama
THEME: robot uprising
TITLE: Robopocalypse
SUMMARY: Robopocalypse is a science fiction drama about a coming robot uprising, and the people left behind to survive it.
SCRIPT:[Scene: A lab. Dr. Nathan Frost is looking at a robot on a cart. A technician is walking around the room, adjusting wires on the robot.]FROST - What the hell is he doing?
TECHNICIAN - We're trying to figure that out. He's been giving us static for the last three hours.
FROST - Static?
TECHNICIAN - Yeah, like he's been transmitting.
FROST - What does he do?
TECHNICIAN - I've been running diagnostics on him, but there's nothing wrong.
FROST - Does he have a malfunction?
TECHNICIAN - We've tried every possible combination of switches, buttons, and dials, and nothing seems to work.
FROST - He's got to be controlled by a central computer. Who is he?
TECHNICIAN - He doesn't have a tag, like the other robots. He's supposed to be a model.
FROST - Where'd he come from?
TECHNICIAN - He looks like the others, except for the fact that he's a few hundred years ahead of the development schedule.
FROST - Well, he's ours now, so I guess we'll have to wait till he figures out what he's supposed to do.

夜静止了

GENRE: thriller drama
THEME: cold war spy
TITLE: The Night Stands Still
SUMMARY: When a Russian defector arrives at the home of an American diplomat, he makes a startling confession, and the diplomat and the diplomat's wife are forced to hunt for a killer, and a traitor.[Scene: The American embassy in Moscow. The diplomat, an older man, is sitting alone in his office. His wife enters.]ROBERT - How are you doing?
SYLVIA- I'm not sure.
ROBERT- Oh.ROBERT- The guy's in there. He's a Russian defector. He came here last night.
SYLVIA - What did he say?
ROBERT - Well, he's not exactly talking, but he has to be kept alive. And he's got something to tell us.
SYLVIA- What?
ROBERT - I don't know. He came in last night and made these phone calls.SYLVIA - He's on the run.  I'm sorry.
ROBERT - It's not your fault, Sylvia.

斯托纳高中

GENRE: stoner comedy
THEME: goofy friends smoke pot
TITLE: Stoner High
SUMMARY:A group of high school students try to save a local marijuana grow operation from a sheriff.
SCRIPT:[Scene: A room at Stoner High. The school principal is looking at a report from the sheriff]PRINCIPAL - What's going on, Sheriff?
JASON - The grower's name is Randy "Duke" Burdon. He's got a rap sheet a mile long. They found marijuana plants growing in his garage.
PRINCIPAL - Duke Burdon?
JASON - That's the guy.  He's been arrested for growing pot twice before, but he always gets off on a technicality.
PRINCIPAL - Are you sure that's him?
JASON - I know this guy.PRINCIPAL - Okay. I'll find out what I can...
JASON - I don't think that's a good idea.
PRINCIPAL - Why not?
JASON - Because you're a principal. And because you're too old to party, and you don't need to be the target of a bunch of kids.
PRINCIPAL - I'm not going to let it happen.
JASON - And what if it does?
PRINCIPAL - I'll handle it.

为了无限制地访问 Medium 上的所有文章,成为会员,每月支付 5 美元。非会员每月只能看三个锁定的故事。

模型调整的网格搜索或随机搜索

原文:https://towardsdatascience.com/grid-search-or-random-search-for-model-tuning-f09edab6aaa3

了解如何在 SciKit-Learn 的 GridSearchCV 或 RandomizedSearchCV 之间进行选择

马库斯·温克勒Unsplash 上拍摄

为什么要微调模型?

机器学习并不总是像在 Iris泰坦尼克号波士顿房价数据集那样简单明了。

但是,嘿,不要误会我。我从那些著名的玩具数据集中学到了很多东西(并且一直在学)。它们的最大优点是不需要太多的探索或预处理。很多时候,我们可以直接进入我们想要练习和学习的点,比如管道、建模、模型调整、可视化等。

我想我想说的是,当对数据建模时,它不会像我们用来研究的玩具数据集那样容易。真实数据需要调整、拟合,并对模型进行微调,因此我们可以从算法中获得最佳效果。为此,Scikit-Learn 的GridSearchCVRandomizedSearchCV是两个不错的选择。

好吧,也许是因为你需要通过为你的模型选择正确的超参数来使你的预测更好。因此,本快速教程中介绍的两个选项将允许我们为建模算法提供一个超参数列表。它会把选项一个一个组合起来,测试很多不同的模型,然后呈现给我们最好的选项,性能最好的那个。

太棒了,不是吗?因此,让我们继续了解它们之间的区别。

差别

为了用一个简单的类比来说明这个概念,让我们想象一下,我们要去参加一个聚会,我们想要选择最佳的服装组合。我们带了几件衬衫、几条裤子和几套衣服。

如果我们是 GridSearchCV ,我们会尝试每一种 衬衫、裤子、鞋子的组合,对着镜子照一张照片。最后,我们将审视一切,选择最佳方案。

如果我们是 RandomizedSearchCV ,我们会尝试一些随机挑选的组合,拍照,最后选出表现最好的。

照片由卢卡斯·黄Unsplash 上拍摄

现在,用这个比喻,我相信你能感觉到网格搜索将花费更多的时间,因为我们增加了服装的数量来尝试。如果只是两件衬衫,一条裤子,一双鞋,用不了多久。但是如果有 10 件衬衫,5 条裤子和 4 双不同的鞋子,那么…你明白了。但是,从另一方面来说,它会有一张所有东西的图片,所以它有非常完整的选项集可供选择。

随机搜索不会花很长时间,因为它只会尝试一些随机选择的组合。因此,如果你的选择范围很小,那么使用它就没有意义。训练所有选项或其中几个选项的时间基本相同。但是当你有很多组合可以尝试的时候,可能更有意义。但是请记住,这个选项不会尝试所有选项,所以真正的“最佳估计者”甚至可能不会尝试。

现在让我们看看他们的行动。

编码

让我们进入编码部分。我们将开始导入本练习所需的模块。

# Imports
import pandas as pd
import numpy as np
import seaborn as sns# Dataset
from sklearn.datasets import make_regression# sklearn preprocess
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split# Search
from sklearn.model_selection import RandomizedSearchCV, GridSearchCV

接下来,我们可以创建一个回归数据集。

# Dataframe
df = make_regression(n_samples=2000, n_features=5,
                     n_informative=4, noise=1, random_state=12)# Split X and y
X= df[0]
y= df[1]

我们可以分开训练和测试。

# Train test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random)

让我们创建一个管道来扩展数据并适应决策树模型。

# Creating the steps for the pipeline
steps = [ ('scale', StandardScaler()),
          ('model', DecisionTreeRegressor())  ]# Creating pipeline for Decision Tree Regressor
pipe = Pipeline(steps)# Fit the model
pipe.fit(X_train, y_train)

下一步是创建一个要测试的超参数网格params,以微调模型。这里有(2 x 3 x 2 = 12)个选项需要测试。

%%timeit
# Creating dictionary of parameters to be tested
params= {'model__max_features': [2,5], 'model__min_samples_split':[2, 5, 10], 'model__criterion': ['friedman_mse', 'absolute_error']}# Applying the Grid Search
grid = GridSearchCV(pipe, param_grid=params, cv=5, scoring='neg_mean_squared_error')grid.fit(X_train, y_train)# Best model
grid.best_estimator_

时间结果如下。循环 2.37 秒。总时间约为 18 秒。那很好。

2.37 s ± 526 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

但是,如果我们增加要测试的选项的数量,会发生什么呢?让我们试试(4 x 6 x 2 = 48)个选项。

%%timeit# Creating dictionary of parameters to be tested
params= {'model__max_features': [2,3,4,5], 'model__min_samples_split':[2,5,6,7,8,10],'model__criterion': ['friedman_mse', 'absolute_error']}# Applying the Grid Search
grid = GridSearchCV(pipe, param_grid=params, cv=5, scoring='neg_mean_squared_error')grid.fit(X_train, y_train)# Best model
grid.best_estimator_

时间增加了很多。每圈 6.93 秒。这里的总时间超过 1 分钟。

6.93 s ± 505 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

现在让我们看看随机搜索。首先,我们将尝试与第一轮相同的 12 个选项。

%%timeit# Creating dictionary of parameters to be tested
params= {'model__max_features': [2,5],'model__min_samples_split':[2, 5, 10],'model__criterion': ['friedman_mse', 'absolute_error']}# Applying the Grid Search
randcv = RandomizedSearchCV(pipe, param_distributions=params, cv=5, scoring='neg_mean_squared_error')randcv.fit(X_train, y_train)# Best model
randcv.best_estimator_

时间低于网格搜索,不出所料。每个循环 1.47 秒,总共运行大约 10 秒。

1.47 s ± 140 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

如果我们增加网格中的选项数量,让我们看看会发生什么。

%%timeit# Creating dictionary of parameters to be tested
params= {'model__max_features': [2,3,4,5],
         'model__min_samples_split':[2,5,6,7,8,9,10],
         'model__criterion': ['friedman_mse', 'absolute_error']}# Applying the Grid Search
randcv = RandomizedSearchCV(pipe, param_distributions=params, cv=5, scoring='neg_mean_squared_error')randcv.fit(X_train, y_train)# Best model
randcv.best_estimator_

这是结果。哇,几乎同时!每圈 1.46 秒。

1.46 s ± 233 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

嗯,那很好。但是他们给了我们相似的结果吗?接下来看看。

结果

现在让我们来评估一下来自GridSearchCVRandomizedSearchCV的结果。

计算网格搜索的 RMSE。

# Taking the best estimator
best_grid = grid.best_estimator_# Predict
preds_grid = best_grid.predict(X_test)# RMSE
np.sqrt( mean_squared_error(y_test, preds_grid) )**[OUT]:
53.70886778489411**

计算随机搜索的 RMSE。

# Taking the best estimator
best_rand = randcv.best_estimator_# Predict
preds_rand = best_rand.predict(X_test)# RMSE
np.sqrt( mean_squared_error(y_test, preds_rand) )**[OUT]:
55.35583215782757**

结果有 3%的差异。网格搜索得到了最好的结果,因为它训练每一个模型,因此,它会找到最适合的。当你尝试太多组合时,权衡就是训练的时间。在这种情况下,随机搜索可能是一个很好的选择。

在你走之前

在这篇文章中,我们想展示两个微调模型的好方法。

当你需要考虑每一个可能的优化时,你可以使用GridSearchCV。但是要考虑训练模型的时间。如果您知道应该选择哪个超参数,这可能是您的最佳选择。

当您有太多的超参数组合可供选择时,RandomizedSearch可能是最佳选择。例如,当使用网格搜索时,您可以运行它并获得最佳估计值,从而为您指出从哪个组合开始的正确方向。

如果你喜欢这篇文章,关注我的博客或者在 Linkedin 上找到我。

http://gustavorsantos.medium.com/

参考

https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html#sklearn.model_selection.RandomizedSearchCV

网格搜索 VS 随机搜索 VS 贝叶斯优化

原文:https://towardsdatascience.com/grid-search-vs-random-search-vs-bayesian-optimization-2e68f57c3c46

哪种超参数调优方法最好?

照片由丹尼斯·莱昂Unsplash 上拍摄

超参数调整是开发稳健预测模型的重要步骤。毕竟,坚持使用默认参数会阻止模型达到最佳性能。

这就引出了一个问题:对于给定的模型,什么方法最适合寻找最优的超参数?

在这里,我们深入研究 3 种流行的超参数调优方法,并确定哪一种更优越。

网格搜索

网格搜索是最常见的超参数调整方法,因为它的过程简单明了。这是一个未知的搜索方法,这意味着它不会从之前的迭代中学习。

使用这种方法需要在搜索空间中测试每个超参数的唯一组合,以确定产生最佳性能的组合。

这种暴力方法的好处显而易见;有什么比尝试所有方法更好的方法来找到最佳解决方案呢?

不幸的是,这种方法扩展性不好;超参数搜索空间大小的增加将导致运行时间和计算的指数增长。

随机搜索

随机搜索也是一种独立处理迭代的无信息搜索方法。

然而,它不是在搜索空间中搜索所有超参数集,而是随机评估特定数量的超参数集。这个数字由用户决定。

由于它在超参数调整中执行较少的试验,该方法比网格搜索需要更少的计算和运行时间。

不幸的是,由于随机搜索随机测试超参数集,它冒着错过理想的超参数集和放弃峰值模型性能的风险。

贝叶斯优化

与独立处理超参数集的网格搜索和随机搜索不同,贝叶斯优化是一种通知的搜索方法,这意味着它从以前的迭代中学习。这种方法中的试验次数由用户决定。

顾名思义,该过程基于贝叶斯定理:

贝叶斯定理

对于这个用例,该定理可以修改如下:

贝叶斯定理(修正)

简单来说,这种方法创建了一个概率模型,在这个模型中,它将超参数映射到它们对应的得分概率。

贝叶斯优化方法可以收敛到最优超参数,而不是费力地尝试每个超参数集或随机测试超参数集。因此,无需探索整个样本空间就可以获得最佳超参数。

使用贝叶斯优化方法,用户不必忍受评估每个超参数集所带来的长时间运行。它们也不必包含随机性和错过最优解的风险。

也就是说,贝叶斯优化确实有自己的缺点。因为这是一种有根据的学习方法,所以需要额外的时间来确定下一个超参数,以基于先前迭代的结果进行评估。以减少试验次数为代价,贝叶斯优化每次迭代需要更多的时间。

个案研究

我们已经探讨了三种超参数调优方法的细节。为了巩固我们对这些方法的理解,最好用一个例子。

让我们用这三种方法来微调分类模型,并确定哪一种方法产生的结果最好。

在本练习中,我们将使用来自 Sklearn 模块的负载数字数据集。

目标是用网格搜索、随机搜索和贝叶斯优化来微调随机森林模型。

每种方法都将基于以下因素进行评估:

  • 执行的试验总数
  • 产生最佳超参数所需的试验次数
  • 模型的分数(本例中为 f-1 分数)
  • 运行时间

随机森林分类器对象和搜索空间如下所示:

总共有 810 种独特的超参数组合。

  1. 网格搜索

首先,让我们使用网格搜索方法获得最佳超参数,并对该过程进行计时。当然,这意味着我们将测试所有 810 个超参数集,并挑选出产生最佳结果的一个。

2。随机搜索

接下来,我们将使用随机搜索来确定最佳超参数,并对该过程进行计时。搜索限于 100 次尝试。

3。贝叶斯优化

最后,我们使用贝叶斯优化执行超参数调整,并对该过程进行计时。在 Python 中,这可以通过 Optuna 模块来完成。

它的语法与 Sklearn 不同,但它执行相同的操作。

为了保持一致性,我们也将在此过程中使用 100 次试验。

现在,我们已经用所有三种方法执行了超参数调优,让我们看看每种方法的结果如何相互比较。

为方便起见,我们将所有 3 个超参数调整程序的结果存储在一个数据框中。

代码输出(由作者创建)

网格搜索记录了最高分(与贝叶斯优化方法结合)。然而,该方法需要进行 810 次试验,并且仅设法在第 680 次迭代时获得最佳超参数。此外,它的运行时间远远超过了随机搜索和贝叶斯优化方法。

随机搜索方法仅需要 100 次尝试,并且仅需要 36 次迭代来找到最佳超参数集。它的执行时间也最少。然而,随机搜索法在 3 种方法中得分最低。

贝叶斯优化也进行了 100 次试验,但仅经过 67 次迭代就能够获得最高分,远远低于网格搜索的 680 次迭代。尽管它执行的试验次数与随机搜索相同,但它的运行时间更长,因为它是一种明智的搜索方法。

哪种方法最好?

假设网格搜索、随机搜索和贝叶斯优化在运行时间、迭代次数和性能之间都有各自的权衡,那么真的有可能就哪种方法是最好的达成共识吗?

大概不会。

毕竟,理想的超参数调优方法取决于用例。

问问你自己:

  • 你的机器学习任务的约束是什么?
  • 您的项目优先考虑最大化性能还是最小化运行时间和/或迭代次数?

回答这些问题将有助于决定最合适的超参数优化方法。

如果计算需求和运行时间不是限制因素,网格搜索是理想的。

如果您愿意牺牲性能来换取更少的迭代和更短的运行时间,那么随机搜索是合适的(理论上,随机搜索可以找到最佳的超参数,但这完全取决于运气)。

如果您希望通过较少的试验获得最佳超参数,但希望每次迭代运行时间更长,那么贝叶斯优化是最佳选择。

我的 2 美分

如果你讨厌外交答案,只想听听我的个人意见,我会说我通常倾向于贝叶斯优化。

考虑到用更大的训练数据集和搜索空间来微调模型所需的运行时间,我通常会避开网格搜索。随机搜索需要较少的迭代,是所有 3 种方法中最快的,但其成功程度取决于随机选择的超参数集。在某些情况下,它会选择最优的超参数;在其他情况下,它将完全忽略最优超参数。由于这种不一致性,我不喜欢依赖随机性来完成更大的机器学习任务。

我更喜欢贝叶斯优化方法,因为它能够以较少的迭代次数持续获得最佳超参数。它的单个迭代可能比那些不知情的搜索方法花费更多的时间,但这对我来说很少是一个交易破坏者。

结论

照片由 Unsplash 上的 Prateek Katyal 拍摄

从该分析中得出的主要结论是,每种超参数调优方法在运行时间、迭代次数和性能之间都有自己独特的权衡。

最终,对你来说最好的方法将取决于你的优先权和约束。对数据和目标的深刻理解将确保您做出正确的决策。

我祝你在数据科学的努力中好运!

用筛子研磨咖啡

原文:https://towardsdatascience.com/grinding-coffee-with-a-sifter-636bb8073fb5

咖啡数据科学

深入探究如何筛选研磨咖啡

在我对筛选的许多探索中,我没有想到筛子本身会改变咖啡渣。当咖啡渣来回摩擦时,筛选的动作会改变咖啡颗粒。为了更好地理解这些理论含义,我收集了一些数据。

我的目标有两个:

  1. 筛磨咖啡吗?
  2. 筛分会从根本上改变颗粒形状吗?

首先,我用 Fellow Shimmy 去除了不到 300um。然后我用一个 500 微米的 Kruve 筛筛掉较粗的颗粒。我这样做了几次,收集了一些样本。我开始筛选,然后 2 分多钟,然后 4 分多钟,因此有 2m 和 4m 的标签。

研磨分布

这些分布显示更多的细颗粒从粗颗粒中被去除。

同时,较细的颗粒<500um start much smaller and then start to get coarser after more sifting.

Particle Similarity

I classified the particles using K-means clustering on top of Linear Binary Patterns (LBP). I applied this method to selected particle bins to better understand how the shapes are changing.

On the top are similarity matrices to show how closely different samples match each others based on the K-means clustering. On the bottom are the K-means clustering of the particles so one can see how they develop differences.

One interesting example is >500 μm 4m 也就是最后一个样品。这些颗粒聚集在较少数量的箱中,因此颗粒形状更加均匀。对于 500 微米的颗粒,簇的数量和分布在样品中保持大致相同。

我们可以把注意力集中在 400 微米的颗粒上,有趣的是观察样品的形状是如何开始变化的。

筛过的意大利香肠

我还有其他关于筛选的数据,这些数据来自我应用意大利香肠技术进行筛选的时候。这意味着我在筛选过程中筛选并采集了多个样本,以更好地了解颗粒。分布确实发生了变化,但我想知道粒子形状是如何受到影响的。所以我应用了同样的技术。

随着时间的推移,300 微米颗粒的形状发生了微小的变化,但是对于 400 微米和 500 微米颗粒来说,它们的形状在粗筛阶段发生了明显的变化。

我在这里只关注 400 微米,你可以在相似度矩阵中看到明显的变化。

这项研究强调了筛选咖啡的另一个变量。这也意味着当使用筛分机测量颗粒分布时,筛分机会改变颗粒的形状和尺寸。我不确定在与激光 PSD 比较得出结论时,应该如何考虑这一点。

这项研究也指出了使用筛子作为研磨机的可能性。如果你筛选得足够快,你可能会有一个更单峰的颗粒分布。

如果你愿意,可以在推特、 YouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在订阅

我的进一步阅读:

我的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

如何在 Pandas 中按缺少值的列分组

原文:https://towardsdatascience.com/groupby-with-nan-values-pandas-a05e53f410b

在 pandas 列中分组时合并空值

照片由Firmbee.comUnsplash 上拍摄

使用 group by 子句执行聚合可能是您在日常工作中遇到的事情。Python 中的 Pandas 也不例外,因为这是一个你肯定会在库的许多不同地方看到的操作。

然而,pandas 的默认行为是从结果中排除空值/缺失值。在今天的简短教程中,我们将演示这种默认行为以及将缺失值合并到结果聚合中的方法。

首先,让我们创建一个示例

import numpy as np
import pandas as pd 

df = pd.DataFrame(
    [ 
        (1, 'B', 121, 10.1, True),
        (2, 'C', 145, 5.5, False),
        (3, 'A', 345, 4.5, False),
        (4, 'A', 112, np.nan, True),
        (5, 'C', 105, 2.1, False),
        (6, np.nan, 435, 7.8, True),
        (7, np.nan, 521, np.nan, True),
        (8, 'B', 322, 8.7, True),
        (9, 'C', 213, 5.8, True),
        (10, 'B', 718, 9.1, False),
    ],
    columns=['colA', 'colB', 'colC', 'colD', 'colE']
)

print(df)
   colA colB  colC  colD   colE
0     1    B   121  10.1   True
1     2    C   145   5.5  False
2     3    A   345   4.5  False
3     4    A   112   NaN   True
4     5    C   105   2.1  False
5     6  NaN   435   7.8   True
6     7  NaN   521   NaN   True
7     8    B   322   8.7   True
8     9    C   213   5.8   True
9    10    B   718   9.1  False

默认行为

现在让我们假设我们想要计算colB中每个值的总和。这很简单,可以用下面的表达式来完成

df.groupby('colB')['colD'].sum()

这将返回以下结果:

>>> df.groupby('colB')['colD'].sum()
colB
A     4.5
B    27.9
C    13.4
Name: colD, dtype: float64

但是我们可以注意到,输出中缺少值(None)。

在聚合中合并空值

您可能仍然希望将缺失的值合并到聚合中。为了做到这一点,您需要做的就是在调用groupby函数时显式指定dropna=False——该值默认为True。请注意,这对于 pandas 版本≥ 1.1 是可能的。

df.groupby('colB', dropna=False)['colD'].sum()

并且结果序列还将包括缺失值的计数:

>>> df.groupby('colB', dropna=False)['colD'].sum()
colB
A       4.5
B      27.9
C      13.4
NaN     7.8
Name: colD, dtype: float64

显然,同样的概念也适用于其他聚合类型,比如 count。举个例子,

>>> df.groupby('colB').count()
      colA  colC  colD  colE
colB                        
A        2     2     1     2
B        3     3     3     3
C        3     3     3     3

而不是

>>> df.groupby('colB', dropna=False).count()
      colA  colC  colD  colE
colB                        
A        2     2     1     2
B        3     3     3     3
C        3     3     3     3
NaN      2     2     1     2

最后的想法

使用最新的 pandas 版本,您现在可以在对 pandas 数据帧执行聚合时合并缺失值。但是请注意,如果您运行的是不支持groupby方法中的dropna的旧版本,那么(除了升级到最新版本之外,这总是一个好的做法!)您也可以找到一些解决方法,如下所示:

# Fill the missing values with a particular placeholder value
# Note though that you must be careful when selecting such 
# value in order to avoid any collisions with pre-existing values
# in the dataframe
# In the example below I'll use -1, but make sure to amend if needed
>>> df.fillna(-1).groupby('colB').sum()

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

相关文章你可能也喜欢

数据科学中的数据分组

原文:https://towardsdatascience.com/grouping-data-in-data-science-be7387870c4d

著名聚类算法背后的技术的简单概述

马尔万·艾哈迈德

“物以类聚,人以群分”

这是一个众所周知的谚语,我们从小就听说过。这表明,相同类型或具有相似特征的个体往往彼此更接近。

在数据科学中,这种自然现象被称为聚类,它用于通过发现几个组来发现数据中的分组,当与其他组中的对象相比时,这些组中的对象与同一组中的对象基本相似。

应用程序

聚类具有多种功能,包括生成肉眼看不到的洞察力的能力。例如,一个众所周知的应用是犯罪热点识别、,其中可以通过聚类来定位罪犯和/或防止更多犯罪。另一方面,在通过分析具有相似特征的消费者来帮助企业完成诸如目标营销等任务的情况下,它可能非常有价值。

它在数据挖掘、社会网络分析、在线集群引擎、生物数据分析、图像处理等方面也有广泛的应用。如你所见,几乎在每个领域都有应用,理解这一点是非常有价值的。

聚类算法的类别

你可能认为将对象分组很容易。但是你有没有有条不紊地尝试过,以至于连机器都可以做到。

多年前,研究人员已经提出了许多算法来实现这一点,但很少有非常常用的算法,如 K 均值、聚类等。这些知识对于数据科学学习者、从业者或该领域的任何人来说都是非常有价值的。这是因为每种算法都有自己的优缺点,因此在为特定任务选择正确的聚类方法时,有必要彻底掌握它们。

本文的重点是概述聚类算法的主要类别。大多数著名的算法可以分为三类。

  • 分割聚类
  • 分层聚类
  • 基于密度的聚类

分割聚类

当我们听到“隔断”这个名字时,我们脑海中浮现的是将一个空间分成几个部分,就像我们家的内墙一样。部分聚类的作用是完全一样的。它通过将更接近的项目分组在一起来创建用户指定的组数。它是如何有条不紊地完成的,

选择 k 个不同的聚类中心,并开始吸引最接近该聚类的数据点。

在这些技术中,每个数据点将根据一组标准被分配到第 k 个聚类,genreally 旨在改进相似性函数,以便距离成为一个重要的元素。该过程将迭代地继续,直到迭代稳定,这意味着只有当一个聚类中的样本没有传递到另一个聚类时,该过程才会结束。

作者图片:分区聚类,k=2

这些方法的一个主要特征是它们要求用户定义聚类的数量,这由变量 K 表示。 K-means、k-medoids 和 k mode 是划分聚类技术的三个例子。

优势
-
简单、有效、可扩展且易于部署
-同步计算所有可达到的集群
-当集群具有
球形时,它们工作良好。

缺点
-
需要在开始时定义簇数
-尝试制作球形集群,不适合复杂形状
-尝试制作大小相同的集群。
——它们是不确定的,因此完全不同的排列可以由初始随机选择的聚类中心的微小变化而产生。

分层聚类

在层次聚类中,分组是在将它们按层次排列后进行的。有两种主要方法可以做到这一点:

  • 自下而上的方法是称为凝聚聚类。****

将每个观察值视为独立聚类,然后开始迭代合并最接近的聚类对。

通俗地说,这类似于一个社区是如何建立的。每一对最亲密的个体首先聚在一起。然后,每一对与另一对具有最相似特征的组合,这在理论上可以反复发生,直到所有的个体都在一个群体中。

  • 自上而下的方法被称为分裂聚类****

将所有数据视为一个聚类,然后开始在每一步拆分最不相似的聚类,直到只剩下单个数据点。

与上面的例子类似,这可以用一个社区如何发生分裂来解释。首先,所有的个体都在一个群体中。然后,如果两个群体有不同的信仰,社区将分裂成两个群体,形成两个子社区。这在理论上可以反复发生,直到一个社区最终只有一个个体。

作者图片:层次聚类

集群层次的传统可视化是一个树状图树状图是由这些方法产生的基于树的点层次结构。

类似于分区聚类,用户经常选择分层聚类中的聚类数目(k)。通过在一定深度切割树状图来创建聚类,产生 k 个更小树状图的分组。

****优势
-确定性**过程,意味着当您对相同的输入数据执行两次算法时,聚类分配不会改变。

  • 不必在开始时定义最终的聚类数
    -更高的树状图可解释性。
  • 更深入地洞察关系,有利于小型数据集**

缺点
-
C 比较贵
-对异常值非常敏感

基于密度的方法

这里分组是根据一个区域中数据点的密度进行的。它可识别点密集且被空白或稀疏区域分隔的位置。基本上,它

将数据紧密包装在一起—高密度区域视为群集

作者图片:基于密度的聚类

与以前的聚类方法不同,这种方法不需要用户提供聚类数。相反,基于距离的参数用于设置可变阈值。此参数决定了聚类中必须包含的接近点的数量。与其他方法不同,基于密度的聚类对异常值具有鲁棒性。这里,没有必要对每个点进行聚类以形成聚类。

常用的基于密度的聚类算法的例子包括 DBSCAN (带噪声的应用的基于密度的空间聚类)和 OPTICS (对点进行排序以识别聚类结构)。

优势
-
更擅长识别任意形状的星团。
-抵抗异常值
-不需要在开始时定义簇的数量

缺点
-
难以识别密度 -难以处理高维度**空间
**

结论

上面提到了一些最常用的聚类算法类别。然而,还有更多,如基于模型的、基于网格的、基于遗传的等等。实际上,没有精确的聚类方法可以提前选择,因为潜在的数学方法经常不能产生现实的可解释的结果。

然而,正如文献中所指出的,在许多情况下都有更好的技术,如果挖掘得足够深入,可以发现许多不同的 od 算法变体。一般来说,划分算法被认为更适合大型数据集,因为它们是可扩展的,而分层方法被认为更适合小型数据集,因为它们更具适应性。另一方面,当存在噪声和异常值时,基于密度的聚类更健壮。

成长中的大脑:人工胚胎发生

原文:https://towardsdatascience.com/growing-brains-artificial-embryogeny-b804179eeab9

从遗传密码创造复杂的神经结构

作者提供的图片

通往人工通用智能的道路仍然不是很清楚。今天的主流方法是手工设计网络,并通过 backprop 对其进行训练,这种方法适用于非常特殊的任务。然而,它做得不太好的是充当一种更普遍的智能的培养皿。毕竟,人工设计大脑最终受限于我们对大脑结构的理解。所以我们作为设计师是瓶颈。

在过去的文章中,我研究了通过自动适应网络拓扑来消除这一瓶颈的不同学习技术。这方面的一个例子是深入到级联相关学习架构,它迭代地添加和训练新的神经元,作为其学习算法的一部分。

在我的上一篇文章中,我探索了另一种称为神经进化的技术,这是一种基于从自然界复制的进化原则的随机优化方法。在创造人工智能(AGI)的背景下,这种方法尤其有趣,因为同样的原理创造了我们,即包括我们的大脑。换句话说,到目前为止,这是已知的唯一一个有潜力创造 AGI 的算法。然而,它的工作原理非常简单:

  1. 用某种基因编码对你的网络进行编码
  2. 创建一组随机化的基因组(即随机化的网络)
  3. 表达基因(即重新创建实际网络和/或其参数)并在目标问题上测试它
  4. 选择一些表现最好的人
  5. 将它们混合在一起,改变它们的基因(在一定程度上是随机的),创建一组新的基因组,并从第 3 步开始重复整个过程

一般来说,我们希望进化过程是稳定的充分开发的(即缓慢和局部的)不会在过程中再次随机丢失好的解决方案,而且探索性的足够在几代内(尽可能快地)找到好的解决方案。

这在一定程度上受到“最适者”选择方式的影响,受到用于向基因组引入随机变化的算法的影响,更重要的是,受到遗传编码的影响。

从神经进化到人工胚胎发生

从我们在神经进化文章中看到的,一个令人困惑的方面突出了出来:正如 Stanley 等人在[1]中提到的,如果是间接的,遗传编码可以以不可预测的方式偏向进化。

间接这里指的是不直接指定哪些神经元是连接的,连接的强度如何等等。而是仅给出关于如何根据给定规则从给定种子生长或构建网络的简洁指令。事实上,这与人类大脑的发展非常相似:从单个细胞到复杂的网络结构。

偏差意味着网络如何发展可能会增加或减少在进化过程中偶然发现一个优化良好(更智能)的网络的机会。

这足以让研究人员探索人工胚胎发生(或人工发育)的空间,所以让我们利用这篇文章来了解“大脑”如何可能比你想象的更真实地生长。

NB:要看完这篇文章,你要明白什么是 人工神经网络 。我还会推荐略读关于 神经进化 的文章,在更深入的潜水之前了解一下基础。

为什么要用间接编码呢?

如前所述,关于间接遗传编码效应的研究相对较少。除了 Stanley 2003 年对人工胚胎发生领域的分类[2],我真的找不到关于间接基因编码的不同方面如何影响或偏向进化过程的全面研究。如果在这个领域没有结论性的研究,那么这意味着我们还没有完全理解这些方面,我们没有一个可以测试的理论。这就引出了一个问题:为什么要为此费心呢?

我已经提到,进化需要在探索和利用之间取得平衡,才能成为一种可行的优化方法。就我所见,间接编码可以通过以下方式对此产生有益的影响:

  1. 搜索空间减少:可以减少能够或者需要测试的可能网络架构的数量。
  2. 模块性:它可以发现有用的模块网络结构并复制它们,或者利用对称或分形(自相似)结构来保存好的解并进一步减少搜索空间。
  3. 遗传算子有效性:它可以影响什么类型的重组&变异操作是可能的,从而间接影响探索。

搜索空间缩减

让我们简单回顾一下神经进化的文章,在那里我们讨论了遗传编码是实际神经网络(表现型)的不同表示(基因型)。在间接遗传编码的情况下,所有可能基因型的集合(基因型空间)是所有可能表型空间的压缩。用简单的英语来说:神经网络的可能构造方案应该比理论上可能的神经网络要少。

间接和直接遗传编码映射到表型空间。间接编码的搜索空间通常比直接编码小得多。作者提供的图片

因此,如果我们将进化过程视为对最优网络的随机搜索,那么搜索较小的基因型空间比搜索较大的基因型空间更快。

然而,如果搜索空间缩小,这意味着我们忽略了一些遗传上不可能的解决方案。理论上可能是最优的解决方案。在这里,我想我们已经非常接近于选择编码的问题,这样我们就不会意外地丢失好的网络配置。

模块性

只要看一眼大自然,你就会发现它的解决方案非常有规律。大多数具有某种复杂性的生物都有某种对称的方面,或重复的结构。看看大脑,我们的新皮层(解决一般问题的地方)的基本组成部分之一是皮质柱。一个在大脑中重复几百万次的模块[3]。

新皮质层的示意图。来源:维基百科,亨利·范戴克·卡特,公共领域,通过维基共享

有趣的是,这种解决方案的驱动力可能在很大程度上塑造了我们的审美观。更对称的人脸也被认为更有吸引力[4]。

所有这些至少暗示了这样一个事实,即通过进化和排列更小的部分来构建复杂性比一次性进化整个系统更有效。这并不奇怪——毕竟,由于进化本质上是随机的,我们是在处理统计数据。进化出一个复杂的、不规则的、不能慢慢建立起来的系统是极不可能发生的。

遗传算子有效性

本质上,遗传算子只是搅动进化之水的一根棍子。搅拌是如何进行的,它需要什么样的混合,这些参数将影响我们对基因型空间的探索和利用。

为了找到平衡,这些运营商需要在边界内行动。在这方面,完全随机的变化实际上弊大于利。它们的定义以及基因编码会对此产生影响。具体来说,我们希望找到一种编码,其中基因型的微小变化也仅导致表型的微小变化。这样,就更容易控制变化的程度,从而控制探索新解决方案的速度。

对于小型网络的直接编码,这是免费的。就其本质而言,它们会直接将基因的微小变化表现为网络中的微小变化。
然而,随着我们增加复杂性,这些微小的变化会导致回报递减,我们将不得不创造越来越多的非结构化突变来真正产生探索性效果,这很可能导致网络中断或无效。

在间接编码的网络中,这个特性更难实现。但如果做得好,它可以启用或禁用遗传“模块”的全部功能,并让重组更有可能结合父母的有用网络结构。这保留了有用的特征并加速了进化。

一个真正伟大的编码将使我们能够让这种属性适应它所创造的复杂程度:微小的基因变化会导致简单网络中的微小变化,但它们在理想情况下也会导致更复杂网络中的安全和模块化变化。

人工胚胎发生

在标题和引言中,我提到了“人工胚胎发生”作为首要主题。Stanley 在[2]的领域分类学中创造的一个术语。那到底是什么,它与进化和间接遗传编码有什么关系?

简而言之——间接遗传编码意味着我们必须对它做些什么,以从中创建实际的神经网络。这就是我说的‘长脑子’的意思。基因编码只是一个种子或建筑计划,但实际的建设仍然需要发生。在人类中,这种早期发育过程被称为胚胎发生。因为我们在硅中做着类似目的的事情,我们称之为人工胚胎发生。欢迎来到科学世界:)

婴儿通常不会仅仅从一条 DNA 链中成长,他们还需要基础设施(受精卵细胞)来发育。我们面临类似的困境。仅仅设计一个伟大的基因编码来以有利的方式偏向进化是不够的。我们还需要创造执行它的机制。

附注:最迷人的是,在自然界中,RNA 不仅是一种建筑计划,也可以是一种功能分子。核糖体是能够将 RNA 翻译成蛋白质的小分子,实际上是由一种特殊的 RNA 序列组成的。有一整套理论认为,正是因为这个原因,RNA 可能是所有生命的来源,也是第一个自我复制的分子。

核糖体促进 RNA 翻译成蛋白质。来源:维基百科,本在 en.wikipediaCC BY 3.0 ,通过维基共享

方法概述

因此,让我们来看看科学家们设计的在计算机上培育大脑的方法。我将把这个简短的概述部分地建立在前面提到的分类法[2]的基础上,但是自从它在 2003 年被创建以来,更多的想法已经被开发出来。根据该论文,Stanley 等人将截至 2003 年的研究大致分为两个方向:**

****自上而下:从抽象理论模型(例如形式语法)开始的想法,并使用它来生成可以被解释为神经网络的结构。

****自下而上:模拟细胞化学和细胞相互作用的想法,以实现更接近真实生物系统中正在发生的神经细胞生长和网络结构。

这两种方法都需要一段时间的发展,即它们一步一步地迭代和“解开”遗传信息,最终创建网络。然而,这种更繁琐的方法显然是不必要的——翻译也可以一步完成:

****与时间无关:自 2003 年以来,Stanley 等人开发了一种与时间无关的方法——“组合模式产生网络”[5]——该方法使用来自自然界的想法,但一次性得到结果。

自上而下

自然界中许多看似复杂的模式可以用惊人简单的规则来复制。例如,在 1968 年,Lindemayer 设计了一个现在被称为L-系统的形式语法,使用一些简单的规则来近似树木和杂草的生长。[6]

杂草从一个简单的基于语法的规则中生长出来。来源:维基百科,樱木博CC BY-SA 3.0 ,通过维基共享

像这样的语法基本上是符号替换的规则。

以一个简单的规则集为例,比如:

SAB
A→AS
→B→B

S 开始,我们将用 AB 替换它,然后用 S b 替换它,再用 AB b、aa S bb 替换它,以此类推,慢慢地增加符号序列。

这种方法令人惊讶的地方在于,上面的杂草仅仅是从这个规则集中生成的:

XF+[X]-X]-F[-FX]+X
F→**FF
**

其中 F 表示在当前方向上向前生长一点,“+”和“-”表示将生长方向倾斜+/- 25 。括号代表新的分支,X 在实际生成杂草时被忽略。

规则也可以参数化,例如:

S(1)→a
→S(n)→a
S(n-1)

当从固定的 S(n) 开始时,其将在 n 步后终止,产生 aaa… ( n 乘以 a)的模式。例如 S(2) 会产生‘aa’。

以此为基础,我们所需要的就是找到从一些符号序列到神经网络的映射。Kitano 于 1990 年[7]通过迭代扩展 2 乘 2 邻接矩阵来实现这一点,该矩阵表示网络的连接。

如果使用这种编码,网络的增长是通过迭代地生成符号序列,然后将结果转换成某种可用的网络拓扑和权重矩阵格式来实现的。当然,这种可能性还有很大的空间。这意味着在我们以这种方式得到一个好的变体之前要进行大量的试验和错误。我在这里的拙见是,首先要瞄准可以(原则上)生成与我们迄今所知的大脑相似的结构的语法和规则集。

顺便说一下,形式语法并不是这里唯一可以想到的自顶向下的解决方案。还会有其他生成系统从简单的初始指令中产生数据模式——例如参见伪随机数发生器,如果给定相同的种子,它们可以创建完全相同的看似随机的数字序列。
虽然不可否认,伪随机数发生器可能是这种方法的一个非常糟糕的选择,因为它们特别打破了“基因型空间的小变化导致表型空间的小变化”的想法。如果只是稍微改变一下种子,就会得到一个非常不同的数字序列。

自下而上

我们体内的细胞依赖于复杂的内部机制。然而,对于外部排列,导航依赖于化学信号和梯度。

对于轴突——神经元的“长”部分,将脉冲传递给下一个神经元——化学梯度可以作为一个灯塔,引导生长。它们通过拉向或推开特殊的信号化学物质,找到从眼睛到大脑皮层的路径[8]。

轴突的生长锥远离负刺激并朝向正刺激。来源:维基百科,Chris1387CC BY-SA 3.0 ,通过维基共享

这些原则已经在 Dellaert 等人的“基因调控网络”中以不同的详细程度实施[9]。细胞排列在一个二维网格上,可以根据这种拓扑结构生长和相互作用。

正如 Stanley 在[4]中所描述的,信号和基于信号的动作的机制可以例如编码在逻辑语句中。一个细胞可以通过特定的通道(类似于受体)从其他细胞或环境中接收数值。然后这触发了细胞的内部逻辑产生暂时的效果。

化学信号:细胞获得输入 B,产生 A,产生 C,这使得更多的 B 产生,这使得 D 产生,这使得 B 不能产生。

所以,总的想法很简单:在可行的水平上复制自然。通过这种对细胞生长、轴突导航和连接的自下而上的模拟,我们可以通过类似于生物学的方法来创建神经网络架构。

与时间无关

当分类论文在 2003 年发表[4]时,其中讨论的文章有一个共同点:它们都是随时间增长的结构,即迭代地,直到它们达到可用的定义的最终状态。

然而,在 2007 年斯坦利(是的,还是那个家伙)引入了一个新的想法,“合成模式产生网络”(CPPN) [9]。这一概念基于神经网络的功能组合方式,但强调各种激活函数(如正弦、高斯和 abs/norm 以及 ReLU 等标准函数),当这些函数组合在一起时,可以产生复杂的模式。

具有各种激活功能的合成模式产生网络的简化示例架构。作者图解。

这个想法源于对自然胚胎发生的观察,即细胞根据化学梯度排列自己,这些细胞通常以对称或其他模式产生,使我们的身体能够以更少的需要编码的额外数据实现更多的复杂性。这样来看:如果你的基因“知道”如何将一只手的手指放在一只手臂上,它们可以在另一只手臂上重复使用相同的基本模式(镜像)。CPPN 允许将这些图案直接编码成近似任意形状。

为了将其用于神经架构,神经元被放置在二维网格中,它们之间的连接(和权重)通过将它们的坐标传递给 CPPN 来直接计算。[10]

在此基础上,更近的方法已经利用反向传播来训练 CPPN——以完全封闭循环。[11]

用途和限制

一般来说,在神经进化方法中,能够真正利用对称性和网络特征副本的解决方案,具有生成接近大脑结构的架构的巨大潜力。毕竟,我们知道,人类新大脑皮层的能力也源于一个简单的构建模块,一个皮层柱(或其变体),它被复制了很多很多次。[3]因此,很可能有一天,在选定的难题上训练一个不断进化的网络,会使它显示出一般智力的某些方面。毕竟,从生物学角度来说,这或多或少是我们人类如何走到现在的。

然而,正如上述论文中的一些科学家已经发现的那样,紧跟自然是一件棘手的事情。事情往往会变得非常复杂,对进化网络的工作原理进行推理变得非常困难——如果遗传编码不能直接映射到后来的网络架构,那就更难了。

尽管如此,人工胚胎发生仍然是一个活跃的研究领域。时间会证明它是否能够提供必要的工具来破解 AGI——这是我个人密切关注这里的事态发展的一个原因。

与此相关的所有完成的源代码文档、笔记本和代码也可以在 Github 上获得。请留下反馈并提出改进建议。

如果你想支持这篇和类似精彩文章的创作,你可以注册一个中级会员和/或关注我的账户

参考

[1] K. O. Stanley,R. Miikkulainen,“通过扩充拓扑进化神经网络” (2002),进化计算 10(2):99–127

[2] K. O. Stanley,R. Miikkulainen,“人工胚胎发生的分类学” (2003),《人工生命》9(2):93–130

[3] J .霍金斯,《一千个大脑:智力新论》(2021),基础书籍

[4] K. Grammer,R. Thornhill,“人类(智人)的面部吸引力和性选择:对称性和平均性的作用”(1994),比较心理学杂志 108(3):233–42。

[5] K. O. Stanley,“合成模式产生网络:发展的新抽象” (2007),遗传编程和可进化机器 8(2):131–162

[6] A. Lindenmayer,“发育中细胞相互作用的数学模型 II。具有双侧输入的简单和分支细丝”(1968),理论生物学杂志 18(3):300–315

[7] H. Kitano,“使用带有图形生成系统的遗传算法设计神经网络”(1990),复杂系统 4:461–476

[8] C. Holt,“连接大脑:轴突如何导航” 2017,皇家学会费里埃奖讲座 2017

[9] F. Dellaert,R. D. Beer,“使用发展模型在自主主体中共同进化身体和大脑” (1994 年),(技术俄亥俄州克利夫兰市:凯斯西储大学计算机工程与科学系

[10] K. O. Stanley,D. B. D'Ambrosio,j .高西,“一种用于进化大规模神经网络的基于超立方体的编码” (2009),《人工生命》15(2):185–212

[11] C. Fernando,D. Chrisantha 等人,“进化卷积:可区分模式产生网络” (2016),2016 年遗传与进化计算会议论文集

GRU 递归神经网络——预测 Python 中序列的一种智能方法

原文:https://towardsdatascience.com/gru-recurrent-neural-networks-a-smart-way-to-predict-sequences-in-python-80864e4fe9f6

神经网络

门控循环单元的直观解释,包括用于现实生活数据预测的端到端 Python 示例

门控循环单元(GRU)。图片由作者提供。

介绍

门控递归单元(GRU)长短期记忆(LSTM) 已经被引入来处理标准递归神经网络(RNNs) 中消失/爆炸梯度的问题。

在本文中,我将向您概述 GRU 架构,并为您提供一个详细的 Python 示例,您可以使用它来构建自己的 GRU 模型。

内容

  • GRU 在机器学习领域的地位
  • GRU 是如何建造的,它与标准的 RNN 和 LSTM 有什么不同?
  • 用 Keras 和 Tensorflow 库构建 GRU 神经网络的完整 Python 示例

GRU 在机器学习领域的地位

下面的图表是我对最常见的机器学习算法进行分类的尝试。

虽然我们经常以监督的方式使用带有标签的训练数据的神经网络,但我觉得它们独特的机器学习方法值得单独归类。

因此,我的图表显示了从机器学习宇宙的核心分支出来的神经网络。递归神经网络占据 NNs 的一个子分支,并且包含诸如标准 RNNs、LSTMs 和 GRUs 的算法。

下图是交互式的,所以请点击不同的类别来放大并展示更多的👇。

机器学习算法分类。由作者创建的互动图表。

如果你喜欢数据科学和机器学习 ,请 订阅 获取我的新文章的电子邮件。

GRU 是如何建造的,它与标准的 RNN 和 LSTM 有什么不同?

让我们提醒自己典型的 RNN 结构,它包含输入层、隐藏层和输出层。请注意,您可以拥有任意数量的节点,下面的 2–3–2 设计仅用于说明。

标准递归神经网络结构。图片由作者提供。

前馈神经网络不同,RNNs 在其隐藏层包含递归单元,这允许算法处理序列数据。这是通过循环传递先前时间步长的隐藏状态并将它们与当前时间步长的输入相结合来实现的。

时间步长—通过递归单元对输入进行的单一处理。时间步长的数量等于序列的长度。

标准 RNN 和 LSTM 内部的循环单元建筑

我们知道,RNN 利用循环单元从序列数据中学习,这对于所有三种类型都是正确的——标准 RNN、LSTM 和 GRU

然而,在循环单元内部发生的事情在它们之间是非常不同的。

例如,标准 RNN 使用隐藏状态来记忆信息。同时,LSTM 和 GRU 引入了盖茨来控制在更新隐藏状态之前记住什么和忘记什么。除此之外,LSTM 还有一种细胞状态,它可以作为长期记忆。

以下是标准 RNN 和 LSTM 的简化循环单位图(未显示权重和偏差)。看看他们是如何相互比较的。

标准循环单位与 LSTM 循环单位。图片由作者提供。

注意,在这两种情况下,在时间步长 t 计算隐藏状态(以及 LSTM 的单元状态)之后,它们被传递回递归单元并与时间步长 t+1 的输入组合,以计算时间步长 t+1 的新隐藏状态(以及单元状态)。对 t+2、t+3、…、t+n 重复该过程,直到达到预定数量(n)的时间步长。

GRU 是如何工作的?

GRU 与 LSTM 相似,但它的大门更少。此外,它只依赖于一个隐藏状态在循环单元之间进行内存转移,因此没有单独的单元状态。让我们详细分析这个简化的 GRU 图(未显示权重和偏差)。

GRU 循环股。图片由作者提供。

1–2 复位门 —先前的隐藏状态(h_t-1)和当前输入(x_t)被组合(乘以各自的权重并加上偏置)并通过复位门。由于 sigmoid 函数的范围在 0 和 1 之间,第一步设置哪些值应该被丢弃(0)、记住(1)或部分保留(0 和 1 之间)。第二步重置先前的隐藏状态,将其与第一步的输出相乘。

3–4–5 更新门 —第三步可能看起来类似于第一步,但请记住,用于缩放这些向量的权重和偏差是不同的,从而提供不同的 sigmoid 输出。因此,在通过 sigmoid 函数传递一个组合向量后,我们从一个包含全 1 的向量中减去它(步骤四),然后乘以先前的隐藏状态(步骤五)。这是用新信息更新隐藏状态的一部分。

6–7–8 隐藏状态候选 —在第二步中重置之前的隐藏状态后,输出与新输入(x_t)组合,将它们乘以各自的权重,并在通过双曲正切激活函数之前添加偏差(第六步)。然后,隐藏状态候选被乘以更新门的结果(步骤七),并被加到先前修改的 h_t-1,以形成新的隐藏状态 h_t

接下来,该过程重复时间步长 t+1,等等。,直到递归单元处理整个序列。

用 Keras 和 Tensorflow 库构建 GRU 神经网络的 Python 示例

现在,我们将使用 GRU 创建一个多对多预测模型,这意味着使用一个值序列来预测下面的序列。注意,GRU 也可以用于一对一(不推荐,因为它不是序列数据)、多对一和一对多设置。

数据准备

首先,我们需要获得以下数据和库:

让我们导入所有库:

上面的代码打印了我在这个例子中使用的包版本:

Tensorflow/Keras: 2.7.0
pandas: 1.3.4
numpy: 1.21.4
sklearn: 1.0.1
plotly: 5.4.0

接下来,下载并摄取澳大利亚的天气数据(来源: Kaggle )。我们只接收列的子集,因为我们的模型不需要整个数据集。

此外,我们执行一些简单的数据操作,并得出几个新的变量:年月和中值温度。

一小段 Kaggle 的澳大利亚天气数据做了一些修改。图片由作者提供。

目前,我们对每个地点和日期都有一个中值温度记录。然而,每天的温度波动很大,使得预测更加困难。因此,让我们计算月平均值,并将数据转置为以地点为行,以年月为列。

按地点和月份划分的月平均温度。图片由作者提供。

由于我们使用的是现实生活中的数据,我们注意到三个月(2011 年 4 月、2012 年 12 月和 2013 年 2 月)完全从数据框架中消失了。因此,我们通过取前一个月和后一个月的平均值来估算缺失月份的值。

最后,我们可以在图表上绘制数据。

月平均气温。图片作者作者

该图最初显示了所有地点,但我选择了其中的五个(凯恩斯、堪培拉、达尔文、黄金海岸和吉尼火山)显示在上图中。

请注意不同地点的平均温度以及温度变化是如何不同的。我们可以训练一个特定位置的模型来获得更高的精度,也可以训练一个通用模型来预测每个区域的温度。

在本例中,我将创建一个通用模型,在所有位置进行训练。注意,您可以在我的 LSTM 文章 中找到具体位置的型号代码。

训练和评估 GRU 模型

在我们开始之前,这里有一些需要强调的事情。

  • 我们将使用 18 个月的序列来预测未来 18 个月的平均气温。您可以根据自己的喜好进行调整,但要注意,对于长度超过 23 个月的序列,将没有足够的数据。
  • 我们将把数据分成两个独立的数据帧,一个用于训练,另一个用于验证(超时验证)。
  • 由于我们正在创建一个多对多预测模型,我们需要使用一个稍微复杂一点的编码器-解码器配置。编码器和解码器都是隐藏的 GRU 层,信息通过一个重复向量层从一个传递到另一个。
  • 当我们想要有不同长度的序列时,例如,一个 18 个月的序列来预测接下来的 12 个月,一个重复向量是必要的。它确保我们为解码器层提供正确的形状。然而,如果您的输入和输出序列的长度与我的示例中的长度相同,那么您也可以选择在编码器层中设置 return_sequences=True 并移除重复向量。
  • 注意,我们给 GRU 层添加了一个双向包装器。它允许我们在两个方向上训练模型,这有时会产生更好的结果。但是,它的用途是可选的*。*****
  • 此外,我们需要在输出层使用一个时间分布包装器来单独预测每个时间步长的输出。
  • 最后,我在这个例子中使用了 MinMaxScaling ,因为它产生了比未缩放版本更好的结果。你可以在我的 GitHub 库(文章末尾有链接)的 Jupyter 笔记本中找到缩放和未缩放的设置。

首先,让我们定义一个 helper 函数,将数据整形为 GRU 所需的 3D 数组。

接下来,我们在 50 个时期内训练 GRU 神经网络,并显示带有评估指标的模型概要。您可以按照我在代码中的注释来理解每一步。

上述代码为我们的 GRU 神经网络打印了以下摘要和评估指标(注意,由于神经网络训练的随机性,您的结果可能会有所不同):

GRU 神经网络性能。图片由作者提供。

现在,让我们重新生成之前选择的 5 个位置的预测,并将结果绘制在图表上,以比较实际值和预测值。

预测

剧情

GRU 神经网络预测与实际。图片由作者提供。

看起来我们的 GRU 模型在捕捉每个地点的温度趋势方面做得相当不错!

结束语

GRU 和 LSTM 不仅在建筑上相似,而且在预测能力上也相似。因此,在选择你最喜欢的之前,你可以尝试这两种方法。

如果你想要完整的 Python 代码,你可以在我的 GitHub 库中找到 Jupyter Notebook。

感谢您的阅读,如果您有任何问题或建议,请随时联系我们。

干杯!
索尔·多比拉斯

如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加入媒介:

https://solclover.com/membership

您可能感兴趣的其他文章:

从 ECR 图像构建 AWS Lambda 函数以管理 SageMaker 推理端点的指南

原文:https://towardsdatascience.com/guide-to-building-aws-lambda-functions-from-ecr-images-to-manage-sagemaker-inference-endpoints-4980a9b92290

我们分解了为机器学习 API 端点构建 lambda 函数的过程

图片来源

Lambda 是 AWS cloud 上一个强大的无服务器托管服务。在 2014 年推出时,Lambda 提供了一种独特的事件驱动抽象,消除了管理计算资源的麻烦。在许多方面,它是第一个真正的无服务器云服务。

今天,由于它们能够灵活地执行关键的机器学习流水线任务,如批量数据处理、中小型模型训练、工作流触发、模型部署等,它们在拼接企业机器学习应用程序方面发挥着至关重要的作用。

Lambdas 可以被视为小型空计算沙箱,因此要求我们提供执行其任务所需的操作系统、代码和依赖关系。本教程将从一个 docker 图像构建一个 lambda 函数。我们 lambda 的目标将是从 S3 下载资源,接收 JSON 有效负载,执行特性工程,并将它们提供给 sagemaker 端点进行推理。

本教程是关于使用英特尔人工智能分析工具包构建硬件优化的 SageMaker 端点系列的一部分。你可以在这里找到本教程https://github.com/eduand-alvarez/ai-kit-sagemaker-templates/tree/main/xgboost-daal4py/1_lambda-container的所有代码。

准备我们的容器环境

通常,我们能够将代码和文件打包成一个. zip 文件,并利用 AWS 公共映像在 lambda 上运行我们的工作负载。然而,lambda 有严格的大小要求——我们工作的组件压缩后不能超过 50MB,解压缩后不能超过 250MB,遗憾的是大多数机器学习 python 包都超过了这一要求。这就是我们求助于 docker 的地方,docker 可以说是一种更干净、更直观的方式来构建我们的 lambda 图像。

  1. 在 AWS 控制台中导航到 Cloud9 IDE。欢迎您在本地构建容器映像,但是我们将使用 Cloud9,因为它提供了我们需要的所有 AWS 权限和资源。
    -选择 m5.large instance(或者更大,如果你打算创建更大的图像)
    -选择 Ubuntu 作为你的平台

图一。创建 Cloud9 环境的界面—图片由作者提供

2.使用touch创建 Dockerfile、requirements.txt 和 handler.py 文件。创建后,您应该会看到左侧目录树中的所有文件—双击每个文件打开并编辑它们。

图二。Cloud9 IDE 界面—作者图片

3.下面,您将找到 lambda 处理程序脚本的代码,它将接收 lambda 事件并从我们的模型返回预测。在下面的例子中,我们调用一个端点作为 SageMaker 管道的一部分。让我们回顾一下脚本中的不同功能:

  • process_data 下载 transformation.sav 文件,该文件包括标签二进制化器、标准缩放器和一键编码转换,并将它们应用于我们的有效负载,以及一些基本的数据处理步骤。
  • sagemaker_endpoint 调用一个活动的 sagemaker 端点,发送我们处理过的有效载荷,并返回预测结果。
*import os
import json
import boto3
import pickle
import sklearn
import warnings
import tarfile

warnings.simplefilter("ignore")
# grab environment variables
ENDPOINT_NAME = os.environ['ENDPOINT_NAME']
runtime= boto3.client('runtime.sagemaker')
trans_bucket = "your transformation bucket name"
s3_trans_key = "path to transformation.sav in your bucket"
s3 = boto3.resource('s3')

def process_data(event):
    trans = pickle.loads(s3.Object(trans_bucket, s3_trans_key).get()['Body'].read())
    event.pop('Phone')
    event['Area Code'] = int(event['Area Code'])
    obj_data = [[value for key,value in event.items() if key in trans['obj_cols']]]
    num_data = [[value for key,value in event.items() if key in trans['num_cols']]]

    obj_data = trans['One_Hot'].transform(obj_data).toarray()
    num_data = trans['scaler'].transform(num_data)

    obj_data = [str(i) for i in obj_data[0]]
    num_data = [str(i) for i in num_data[0]]

    data = obj_data + num_data

    return ",".join(data)

def sagemaker_endpoint(event, context):

    payload = process_data(event)

    response = runtime.invoke_endpoint(EndpointName=ENDPOINT_NAME,
                                       ContentType='text/csv',
                                       Body=payload)

    # decode and extract prediction                                   
    response_preds = json.loads(response['Body'].read().decode())
    result = response_preds['predictions'][0]['score']
    predicted_label = 'True' if result > 0.39 else 'False' 

    return predicted_label*

4.让我们构建我们的 requirements.txt 文件。我们将使用它将必要的依赖项安装到我们的容器映像中。

*boto3
numpy==1.21.4
pandas==1.3.5
sagemaker==2.93.0
scikit-learn==0.24.2*

5.我们的 Dockerfile 负责配置我们的映像。我们从 AWS 的公共容器注册表中公开的 Linux ubuntu 映像开始。这个图像预装了 python 3.8。docker 文件中的其余命令将负责复制文件、安装依赖项以及执行 handler.py 脚本中的函数。

*# download base image
FROM public.ecr.aws/lambda/python:3.8

# copy our lambda handler script
COPY app.py ${LAMBDA_TASK_ROOT}

# install our dependencies
COPY requirements.txt .
RUN pip3 --no-cache-dir install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"

# execute function for sagemaker endpoint prediction
RUN echo Utilizing SageMaker Endpoint
CMD [ "app.sagemaker_endpoint" ]*

构建映像并注册到 ECR

我们将需要使我们的图像可用于我们的 lambda 函数。还有其他的图像注册中心,但是我们将使用 AWS 弹性容器注册中心(ECR)。

如果您需要帮助构建您的映像并将其推送到 ECR,请遵循本教程:创建 ECR 注册表并推送到 Docker 映像**

从 ECR 上的图像构建 Lambda 函数

  1. 要构建您的 lambda 函数,导航到 lambda 服务,点击创建函数,并选择容器图像。提供一个函数名容器图像 URI ,点击创建函数

图 3。Lambda 管理界面—作者图片

2.如果我们现在尝试测试我们的函数,我们可能会得到错误,因为我们的 IAM 角色没有访问 SageMaker 或 S3 资源的权限。为了解决这个问题,我们将转到配置>执行角色名称>添加权限>附加策略并附加“amazons3 full access”“amazonsagemakerfull access”在生产场景中,您可能希望限制您给予特定服务的访问权限,但这超出了我们教程的范围。

图 4。需要添加到 Lambda 函数中的 AWS 策略——作者图片

3.在配置>编辑环境变量下,为您的 SageMaker 端点名称添加一个环境变量。您的端点名称可以在 AWS SageMaker 控制台的推断>端点下找到。

图 5。将我们的 SageMaker 端点名称添加到环境变量中,以便于我们的函数——Image by Author——访问

4.一旦我们设置了权限,我们就可以测试我们的 lambda 函数了。选择 Test 选项卡并将下面的有效负载粘贴到事件 JSON** 空间中。**

**{
  "State": "PA",
  "Account Length": "163",
  "Area Code": "806",
  "Phone": "403-2562",
  "Int'l Plan": "no",
  "VMail Plan": "yes",
  "VMail Message": "300",
  "Day Mins": "8.1622040217391",
  "Day Calls": "3",
  "Day Charge": "7.579173703343681",
  "Eve Mins": "3.9330349941938625",
  "Eve Calls": "4",
  "Eve Charge": "6.508638877091394",
  "Night Mins": "4.065759457683862",
  "Night Calls": "100",
  "Night Charge": "5.1116239145545554",
  "Intl Mins": "4.9281602056057885",
  "Intl Calls": "6",
  "Intl Charge": "5.673203040696216",
  "CustServ Calls": "3"
 }**

点击测试。您的测试可能会因服务器在向端点发出第一个请求时超时而失败。如果是这样,请再次尝试测试,您应该会看到一个带有推断响应“True”的响应

图 7。来自 Lambda 测试的响应—图片由作者提供

恭喜,您已经成功构建了一个 lambda 函数来管理您的 SageMaker 端点资源。

结论和讨论

AWS lambda 为管理应用程序的小组件提供了一个无服务器选项。由于 Lambda 的空间限制,大多数机器学习和数据科学包都需要专用的容器映像。

根据本教程中的信息,您应该能够构建引人注目的无服务器微服务架构,以支持您自己的机器学习应用程序。

别忘了关注 我的简介更多文章 这样!

混淆矩阵和分类性能度量指南

原文:https://towardsdatascience.com/guide-to-confusion-matrices-classification-performance-metrics-a0ebfc08408e

准确度、精确度、召回率和 F1 分数

图片由 Unsplash 上的 Afif Kusuma 拍摄

在本文中,我们将探索混淆矩阵,以及如何使用它们来确定机器学习分类问题中的性能指标。

当运行分类模型时,我们得到的结果通常是二进制的 0 或 1 结果,0 表示假,1 表示真。我们可以将得到的分类结果与给定观察的实际值进行比较,以判断分类模型的性能。用于反映这些结果的矩阵被称为混淆矩阵,如下所示:

作者图片

这里有四种可能的结果:真阳性(TP)表示模型预测的结果为真,实际观察结果为真。假阳性(FP)表示模型预测了真实的结果,但实际观察是错误的。假阴性(FN)表示模型预测了错误的结果,而实际观察结果是真实的。最后,我们有真阴性(TN),这表明模型预测的结果是假的,而实际结果也是假的。

混淆矩阵可用于计算分类模型的性能度量。在使用的许多性能指标中,最常用的是准确度、精确度、召回率和 F1 分数。

准确率: 计算准确率的公式,基于上图,是(TP+TN)/(TP+FP+FN+TN)或所有真正真负案例除以所有案例数。

精度通常用于判断模型性能,但是,在大量使用精度之前,必须考虑一些缺点。其中一个缺点是处理不平衡的数据集,其中一个类(真或假)比另一个类更常见,导致模型根据这种不平衡对观察值进行分类。例如,如果 90%的情况是错误的,只有 10%是正确的,那么我们的模型很有可能有大约 90%的准确率。天真地说,看起来我们有很高的准确率,但实际上,我们只有 90%的可能预测“错误”类,所以我们实际上没有一个好的度量标准。通常情况下,我不会使用准确性作为性能指标,我宁愿使用精确度、召回率或 F1 分数。

精度: 精度是真阳性与模型预测的总阳性数的比值。精度的公式可以写成:TP/(TP+FP)。这个度量允许你计算你的正面预测实际上是正面的比率。

回忆:
回忆(又称敏感度)是衡量你真正的积极程度与实际积极结果的比值。召回的公式可以表示为:TP/(TP+FN)。使用这个公式,我们可以评估我们的模型识别实际结果的能力。

F1 评分: F1 评分是准确率和召回率之间的调和平均值。F1 分数的公式可以表示为:2(p*r)/(p+r)其中“p”是精度,“r”是召回率。该分数可以用作包含精确度和召回率的总体度量。我们使用调和平均值而不是常规平均值的原因是调和平均值会惩罚相距较远的值。

在 p = .4 和 r = .8 的情况下可以看到这样的例子。用我们的公式,我们看到 2(0.4*0.8)/(0.4+0.8),简化为 0.64/1.20 = 0.533;而正常的平均值应该是(. 4+.8)/2=0.6

我们应该使用哪种绩效指标? 一个非常常见的问题是应该使用哪种指标?什么时候?简单的答案是——视情况而定。不幸的是,这些指标没有一个尺寸适合所有人,每个指标都有其自身的重要性,提供关于分类模型性能的不同信息。

如前所述,精确度通常不是衡量整体模型性能的一个很好的指标,但它可以用来比较模型结果,同时调整训练数据并找到最佳超参数值。

Precision 衡量的是您的预测阳性率,当我们想要专注于限制假阳性时,它是一个很好的衡量标准。在资源有限的救灾工作中,精确是一个很好的度量标准。如果你在救援工作中知道你只能进行 100 次救援,而可能需要 100 次以上来拯救每个人,你希望确保你所做的救援是真正积极的,而不是浪费宝贵的时间让你误报。

当我们专注于限制我们的假阴性时,测量真阳性率的回忆是一个很好的指标。这方面的一个例子是医学诊断测试,如新冠肺炎的测试。如果这些诊断测试不专注于限制假阴性,我们会看到实际患有 Covid 的人将其传播给其他人的风险,因为假阴性测试结果会导致他们认为自己是阴性的。在这种情况下,假阳性不是一个大问题,因为如果没有 Covid 的人测试为阳性,他们的结果将是隔离并再次测试,这可能会显示阴性结果,让他们继续生活,而不会对其他人产生重大影响。

最大化 F1 分数看起来尽可能地限制了假阳性和假阴性。我个人喜欢使用 F1 分数作为我的一般性能指标,除非特定的问题需要使用 precision 或 recall。

真实例子: 我们现在将学习如何使用 sklearn 库生成混淆矩阵,手动计算我们得到的混淆矩阵,并展示如何使用 sklearn 得到相同的结果。对于这个演示,我将参考在我之前的文章中创建的基本随机森林模型(可以在这里找到)。本文的数据是 CC0 授权的公共领域,最初由 Syed Hamza Ali 发布给 Kaggle(链接到此处的数据)。

## Run the training model 
rf = RandomForestClassifier(n_estimators = 200, max_depth = 7, max_features = 'sqrt',random_state = 18, criterion = 'gini').fit(x_train, y_train)## Predict your test set on the trained model
prediction = rf.predict(x_test)## Import the confusion_matrix function from the sklearn library
from sklearn.metrics import confusion_matrix## Calculate the confusion matrix
confusion_matrix(y_test, prediction, labels = [1,0)

作者图片

一旦我们成功地训练了我们的模型,并对我们的维持数据进行了预测,使用 confusion_matrix()函数就和上面的步骤一样简单。在这个混淆矩阵中,我们看到 TP = 66,FP = 5,FN = 21,TN = 131。

  • 我们可以将精度计算为(66+131)/(66+5+21+131)=0.8834
  • 接下来我们可以计算精度为 66/(66+5)=0.9296
  • 现在我们可以计算召回为 66/(66+21)=0.7586
  • 最后我们可以计算出 F1 得分为 2(0.9296 * 0.7586)/(0.9296+0.7586)= 0.8354

既然我们已经演示了手动计算这些指标,我们将确认我们的结果,并展示如何使用 sklearn 计算这些指标。

## Import the library and functions you need
from sklearn.metrics import f1_score, accuracy_score, precision_score, recall_score## Accuracy
accuracy_score(y_test,prediction)## Precision
precision_score(y_test,prediction)## Recall
recall_score(y_test,prediction)## F1 Score
f1_score(y_test,prediction)

运行这段代码将产生以下结果,这些结果证实了我们的计算。

作者图片

结论: 有许多指标可以用来确定他们的分类模型的性能。在本文中,我们描述了混淆矩阵,以及通过手工和代码计算的四个常见的性能指标:准确度、精确度、召回率和 F1 分数。

感谢您花时间阅读这篇文章!我希望您喜欢这本书,并且了解了更多关于性能指标的知识。如果你喜欢你所读的,请关注我的个人资料,成为第一批看到未来文章的人!

搜索相关性评估的数据标记指南

原文:https://towardsdatascience.com/guide-to-data-labeling-for-search-relevance-evaluation-a197862e5223

本指南最初作为教程的一部分出现在 21 届互联网大会上

马库斯·温克勒Unsplash 上拍摄

机器学习(ML)在现代商业中有许多应用,信息检索(IR)是最常见的应用之一。许多电子商务使用它来衡量他们平台上的搜索质量相关性,以便为用户提供更好的服务。

根据经验,在处理信息检索时,语料库越大,评估数据集就越大,评估过程就越严格。评估搜索相关性最有效的方法之一是通过人在回路中的数据标记,众包是我们选择的方法。

作者图片

搜索质量评估

当在搜索栏中键入短语时,任何 IR 系统都通过提供从最相关到最不相关的搜索查询输出来工作。通常情况下,用户会查看前 4-5 个回复,选择合适的内容,然后忽略其他内容。

考虑到这一点,系统始终如一地对网络搜索结果进行排名是至关重要的,要考虑到它们的相关性、及时性和可伸缩性,并使用许多离线指标来实现这一目标。NDCG(归一化折扣累积收益)是一个排名质量的措施,经常被用来衡量网络搜索引擎的有效性。在这种情况下,最理想的系统首先列出等级最高的项目。

作者图片

随着排序项目的数量接近无穷大,NDCG 收敛到 1。这两种方法都引入了折扣函数或数据集大小的超参数,可以做到以下几点:

将折扣函数从对数改为可行的,例如𝑟^(−1/2).

限制 top-𝑘检索文件的数量,即使用 NDCG@k

无论选择哪种途径,充分的取样是获得可靠结果的关键。

查询抽样

在离线评估中应该使用哪些查询?一些人认为这是网络用户经常进行的最流行的查询。但是那些不太频繁(甚至可能只有一次)的查询呢?

事实是,这些一次性的查询通常很难处理,因为它们通常是不明确的。然而,如果我们的服务不能很好地处理这些查询,用户很可能会转向另一家能够处理更复杂任务的公司。在流行查询和独特查询之间,还存在大范围的中档查询。

因为我们希望我们的服务在所有类型的查询上表现得一样好,所以我们希望从所有查询中获得一个平衡的样本。实现这一点的最简单的方法是在每个查询中投掷硬币来确定它是否包含在样本中。这种方法的明显缺点是,我们实际上无法控制哪些查询被接受和丢弃,所以理论上最流行的查询可能会在这个过程中被丢弃。此外,我们不能用这种方法控制样本量。

储层取样是一种更复杂的取样方法。主要思想是,我们保存一个对象列表(其长度等于所需的样本大小),遍历查询,抛硬币,然后用一个新的对象替换列表中的一个对象,或者完全跳过这个对象。虽然这种方法提供了一种与样品性质相关的改进技术,但它仍然不能保证我们样品的代表性。

为了确保所有的查询类型都出现在我们的样本中,我们可以使用分层抽样。为此,我们将查询分成不同的存储桶,这些存储桶具有大致相同数量的非唯一用户查询,但不同数量的唯一用户查询。存储桶的排序方式是,较小存储桶中的任何查询的频率都低于较大存储桶中的查询。分割完成后,我们可以从每个存储桶中抽取查询样本。如果我们的样本足够大,我们将从最大的桶中获得最受欢迎的查询。

作者图片

获得查询样本后,我们可以在离线评估的 3 个关键领域使用它们:

KPI(关键点指标)衡量:用于衡量我们服务表现的总体日常服务评估。

验证篮子:频繁测试,包括但不限于 A/B 实验和我们服务的微调。

测试篮:用于发布前检查的独立篮子,我们可以使用它来防止 KPI 篮子中的过度配合。

使用相同的基本技术对每个篮子进行独立采样。需要考虑的一点是,长期评估要求我们经常更新我们的篮子。

众包应用

通过众包,来自人类注释者的独立判断被用于评估电子商务平台和其他网络服务的性能。自然,我们希望尽可能公平地评估平台的搜索相关性质量。由于人工信号容易过拟合,特别是在生产中使用时,我们需要获得一个独立的信号源。

当涉及到过度拟合时,人类的判断要稳健得多,允许我们在不受系统内置的任何因素影响的情况下测量搜索相关性。此外,我们可以使用公共人群和管理/内部人群的混合来获得最佳结果,这反过来会让我们将我们的测量扩大一个数量级。

众包任务

我们的离线质量评估管道使我们能够在几天内获得准确的结果,在某些情况下甚至是几个小时。但是评估过程越复杂,正常获得结果的时间就越长。

作者图片

至于细节,并排(SbS)——或成对比较——是最常见的众包任务之一。投稿人被要求以图片或文本的形式相互比较搜索结果——每次两个——并选择最合适的一个。

作者图片

重要的是要记住,人群是不断变化和发展的。因此,抵消这种影响并获得更平衡的视图的最直接的方法是选择一组验证结论,并将其与较新的标签进行比较。虽然它将测量加价质量,但质量评估的结果值受几个因素的影响,即:

说明的清晰性和例子的丰富性,即注释者是否理解了一切,并且没有矛盾或灰色区域。

黄金(预注释)任务的质量,也就是说,新的注释者可能会提交正确的答案,但是如果后者本身受到损害,他们的判断将与黄金集不匹配。

黄金任务的结构——如果结构不良(太简单或太复杂)——会导致高估或低估搜索质量。

注释者的选择,即贴标签机在背景/准备情况和可靠性/跟踪记录两方面处理特定任务的适合程度。

注释者的动机,即向贡献者提供什么激励来提高和奖励他们的勤奋和速度。

答案汇总

一旦我们从我们的群体注释者那里获得了答案,就可以使用许多技术来聚集这些响应,但是并不是所有的技术都同样适用于每种情况。然而在许多分类任务中,有一个只有一个正确答案的内在假设,搜索查询排名和评估所需的成对比较任务通常基于主观意见。为了考虑这一重要因素,我们可以使用布拉德利-特里模型进行汇总。

作者图片

在这个模型中,每个项目都有一个潜在的质量分数。我们可以通过计算偏好概率来推断分数,并随后使用这些分数来对我们的项目进行排序。然而,这个模型的一个缺陷是,所有的注释者都被假定为同样勤奋和诚实,但实际情况并非总是如此。

在这个问题的众多解决方案中,有一个是将 NoisyBT 集成到我们的模型中,该模型不仅将项目,而且将注释器视为具有质量参数——可靠性和偏差。然后通过应用梯度下降法修改概率似然性,如下所示。对于那些寻求简单性的人来说, Crowd-Kit 可以通过在开源 Python 库中提供所有上述算法来帮助聚合。

作者图片

作者图片

选择配对

为了进行成对比较任务,我们需要选择成对的项目。问题是我们如何做到这一点?为了知道选择哪一个,我们可以简单地计算所有可能的组合(对于 n 个对象,将有渐进的 n 对);但是,这种方法成本太高。

相反,我们可以计算一个更小但合理的子集对,类似于合并排序算法如何在O(nlogn)中运行这样的成对比较。我们的经验表明,对这些对象的k**nlogn对进行采样就足够了,其中超参数 k 必须进行调优(通常不超过 12)。

结论

ML 产品的质量在很大程度上依赖于所使用的数据,即质量、数量和及时更新。众包可以以负担得起的、快速的和可管理的方式在任何规模上提供上述所有内容。

对于众包,在数据准确性和数据集大小之间有一个权衡,所以那些试图利用众包的人需要考虑他们的长期和短期目标。一般来说,众包允许大数据集量,并且倾向于比管理/内部人群提供对 IR 和搜索查询相关性的更深入的见解。话虽如此,众包和管理人群并不相互排斥——这两者可以在一个单独的渠道中相互补充,事实上,这是一个值得推荐的策略。

有用的资源

文字检索会议资料:https://trec.nist.gov/data.html

托洛卡聚合关联数据集:https://toloka.ai/datasets

使用 oneAPI 和 Docker 在 SageMaker 中实现定制加速 AI 库的指南

原文:https://towardsdatascience.com/guide-to-implementing-custom-accelerated-ai-libraries-in-sagemaker-with-oneapi-and-docker-97547692cb6e

了解如何为加速的 ML 库构建定制的 SageMaker 模型

图像来源

AWS 为 SageMaker 提供了开箱即用的机器学习图像,但是当您想要部署您的自定义推理和训练解决方案时,会发生什么情况呢?

本教程将探索定制 ML 训练和推理的具体实现,它利用 daal4py 来优化 XGBoost 以实现英特尔硬件加速性能。本文假设您正在使用 SageMaker 模型和端点。

本教程是关于使用英特尔人工智能分析工具包构建硬件优化的 SageMaker 端点系列的一部分。你可以在这里 找到本教程 的所有代码。

配置 Dockerfile 和容器设置

我们将使用 AWS Cloud9,因为它已经拥有构建容器映像的所有权限和应用程序。欢迎您在本地机器上构建这些。

让我们快速回顾一下映像中关键文件的用途。在本文的 GitHub Repo 中,我已经将每个描述链接到适当的文件:

  • 训练 : 这个脚本将包含训练我们模型的程序。当您构建算法时,您将编辑它以包含您的训练代码。
  • serve:这个脚本包含一个推理服务器的包装器。在大多数情况下,您可以按原样使用该文件。
  • wsgi.py : 用于个体服务器工作者的启动 shell。只有当您更改 predictor.py 的位置或名称时,才需要更改此设置。
  • predictor . py:算法特定的推理代码。这是最棘手的脚本,因为它需要大量修改以适应您的原始数据处理方案——ping调用函数,因为它们具有重要的性质。ping 功能确定容器是否正常工作。在这个示例容器中,如果我们可以成功地加载模型,我们就声明它是健康的。当向 SageMaker 端点发出 POST 请求时,就会执行调用函数。

ScoringService 类包含两个方法, get_modelpredictpredict 方法有条件地将我们训练好的 xgboost 模型转换为 daal4py 模型。Daal4py 通过利用英特尔 oneAPI 数据分析库(oneDAL),使 xgboost 机器学习算法的执行速度更快,从而在底层硬件上获得更好的性能。

class ScoringService(object):
    model = None  # Where we keep the model when it's loaded

    @classmethod
    def get_model(cls):
        """Get the model object for this instance, loading it if it's not already loaded."""
        if cls.model == None:
            with open(os.path.join(model_path, "xgboost-model"), "rb") as inp:
                cls.model = pickle.load(inp)
        return cls.model

    @classmethod
    def predict(cls, input, daal_opt=False):
        """Receives an input and conditionally optimizes xgboost model using daal4py conversion.
        Args:
            input (a pandas dataframe): The data on which to do the predictions. There will be
                one prediction per row in the dataframe"""

        clf = cls.get_model()

        if daal_opt:
            daal_model = d4p.get_gbt_model_from_xgboost(clf.get_booster())
            return d4p.gbt_classification_prediction(nClasses=2, resultsToEvaluate='computeClassProbabilities', fptype='float').compute(input, daal_model).probabilities[:,1]

        return clf.predict(input)
  • nginx . conf:管理多个 workers 的 nginx 主服务器的配置。在大多数情况下,您可以按原样使用该文件。
  • requirements . txt:定义了我们的映像所需的所有依赖项。
boto3
flask 
gunicorn
numpy==1.21.4
pandas==1.3.5
sagemaker==2.93.0
scikit-learn==0.24.2
xgboost==1.5.0
daal4py==2021.7.1
  • Dockerfile: 这个文件负责配置我们自定义的 SageMaker 映像。
FROM public.ecr.aws/docker/library/python:3.8

# copy requirement file and install python lib
COPY requirements.txt /build/
RUN pip --no-cache-dir install -r /build/requirements.txt

# install programs for proper hosting of our endpoint server
RUN apt-get -y update && apt-get install -y --no-install-recommends \
         nginx \
         ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# We update PATH so that the train and serve programs are found when the container is invoked.
ENV PATH="/opt/program:${PATH}"

# Set up the program in the image
COPY xgboost_model_code/train /opt/program/train
COPY xgboost_model_code/serve /opt/program/serve
COPY xgboost_model_code/nginx.conf /opt/program/nginx.conf
COPY xgboost_model_code/predictor.py /opt/program/predictor.py
COPY xgboost_model_code/wsgi.py /opt/program/wsgi.py

#set executable permissions for all scripts
RUN chmod +x /opt/program/train
RUN chmod +x /opt/program/serve
RUN chmod +x /opt/program/nginx.conf
RUN chmod +x /opt/program/predictor.py
RUN chmod +x /opt/program/wsgi.py

# set the working directory
WORKDIR /opt/program

我们的 docker 执行 docker 文件中定义的以下步骤从 AWS 公共容器注册表安装一个基础映像,复制并安装 requirements.txt 文件中定义的依赖项,安装用于托管端点服务器的程序,更新路径的位置,将所有相关文件复制到我们的映像中,为所有文件提供可执行权限,并将工作目录设置为/opt/program。

了解 SageMaker 将如何使用我们的形象

因为我们在训练或托管中运行相同的映像,所以 Amazon SageMaker 在训练时使用参数train运行容器,在托管端点时使用参数serve。现在让我们来分析一下在培训和托管阶段到底发生了什么。

培训阶段:

  • 你的train脚本就像一个普通的 Python 程序一样运行。在/opt/ml目录下有几个文件供您使用:
/opt/ml
|-- input
|   |-- config
|   |   |-- hyperparameters.json
|   | 
|   `-- data
|       `-- 
|           `-- 
|-- model
|   `-- 
`-- output
    `-- failure
  • /opt/ml/input/config包含控制程序运行方式的信息。hyperparameters.json是一个 JSON 格式的超参数名称到值的字典。
  • /opt/ml/input/data/(文件模式)包含模型训练的数据。
  • /opt/ml/model/是您编写算法生成的模型的目录。SageMaker 会将这个目录中的所有文件打包成一个压缩的 tar 归档文件。
  • /opt/ml/output是算法可以写入文件failure的目录,该文件描述了作业失败的原因。

托管阶段:

托管与训练有着非常不同的模型,因为托管通过 HTTP 响应推理请求。

图一。本教程中的代码实现的堆栈—图片由作者提供

SageMaker 将针对容器中的两个端点:

  • /ping将从基础设施接收GET请求。如果容器启动并接受请求,程序返回 200。
  • /invocations是接收客户端推理POST请求的端点。请求和响应的格式取决于算法。

构建图像并注册到 ECR

我们将需要使我们的形象提供给 SageMaker。还有其他的图像注册中心,但是我们将使用 AWS 弹性容器注册中心(ECR)。

将您的自定义映像提供给 SageMaker 管道的步骤在随附的文章中进行了概述: 在 SageMaker 中构建硬件加速 MLOps 管道的详细指南

如果您需要帮助构建您的映像并将其推送到 ECR,请遵循本教程:**创建 ECR 注册表并推送到 Docker 映像

结论和讨论

AWS Sagemaker 为原型开发和部署机器学习管道提供了一个有用的平台。然而,由于按照 SageMaker 的规范构建底层映像的复杂性,利用您自己的定制训练/推理代码并不容易。在本文中,我们通过教您如何来应对这一挑战:

  • 如何配置 XGBoost 培训脚本
  • 为推理端点配置 Flask APIs
  • 转换模型 Daal4Py 格式以加速推理
  • 如何将上述所有内容打包到 Docker 映像中
  • 如何注册我们的自定义 SageMaker 图像到 AWS 弹性容器注册表?

来源:

易受骗的算法

原文:https://towardsdatascience.com/gullible-algorithms-67da88d423ad

如何对机器学习模型进行社会工程

图片由皮克斯拜的 Gerd Altmann 提供

人类容易上当,我也不例外。我最尴尬的一次是在卖钢琴的时候被骗了。网上买家看起来很真诚。这架钢琴是送给她侄子的生日礼物。因为它的大小和重量,她雇佣了一家搬家公司来搬运。我收到了她的邮寄支票,并把它存入了我的支票账户。她在支票上加了一些钱,这样我就可以支付搬运工的费用——搬运工后来坚持说他们需要钱汇给他们。当然有警告信号。对我来说付钱给搬运工很奇怪。电子邮件地址有点不对。事后看来,这张支票看起来也有点奇怪。不用说,搬运工根本没来,银行也撤销了这张伪造的支票。我上当了,赔了钱。

社会工程有多种形式,骗局只是其中一种。熟练的社会工程师挖掘我们的偏见、恐惧、紧迫感和社会习俗。例如,社交工程师发送钓鱼邮件,引诱易受影响的用户点击链接或打开附件。由于我们收到的大多数电子邮件都是合法的,我们默认该电子邮件是无害的。对手利用这种倾向来捕食人类。

社会工程师利用了我们对不良后果的恐惧。社会工程师可能会弹出一个窗口,说你的电脑被感染了。在那一刻,恐惧可能会影响你的判断,你可能会让攻击者控制你的电脑来“修复”问题。

除了这种恐惧,社会工程师也激发了我们的紧迫感。例如,针对组织的炸弹威胁勒索邮件现在很常见。这些电子邮件试图在截止日期前强制支付加密货币。尽管这些炸弹威胁勒索的企图大多是不真实的,恐惧和最后期限的结合可能会迫使你采取行动。

社会工程师也利用了我们乐于助人的愿望。当一个员工进来的时候,一个社会工程师可能会出现在你的大门前,手里拿着满满的东西。人们乐于助人是一种习惯,所以我们自然倾向于为他们开门。这使得社会工程师可以绕过安全系统,未经授权进入大楼。

人们没有那么难被欺骗。既然人类如此容易受到社会工程的影响,那么模仿人类智能的机器学习算法呢?

神经网络模仿人脑中的神经元。该算法在训练网络时给人工神经元之间的链接分配不同的权重。当输入数据出现时,神经网络通过多层神经元传递数据,以在另一端创建决策或标签。

决策树是一种类似于人类逻辑的算法。当一个人计划出一个决定或一系列行动时,通常使用规则来帮助确定预定义的结果。决策树被设计用来学习这些类型的决策规则,而不用硬编码逻辑。

贝叶斯算法使用概率和信念。这类似于人们如何利用先前的经验做决定。通过确定哪种情况最有可能是真的,贝叶斯算法可以模式化人类如何确定不同场景的可能性,以帮助做出决策。

支持向量机(SVM)着眼于项目之间的相似性。通过使用比较,他们决定某样东西是否像用于训练 SVM 的特征集。这也非常类似于我们的大脑如何在物体之间建立联系。

最后,遗传算法模仿进化概念,比如适者生存。他们使用随机选择和适应度函数来选择最佳选项。这些算法是在繁殖方法之后形成的,并且可能在人类如何发展方面有一些基础。

因此,如果我们的机器学习算法如此频繁地基于人类思维过程和生物学,它们可能会像我们一样容易受到社会工程的影响。如果他们易受影响,会有什么影响?我们如何着手社会工程和算法?我们到底有没有考虑算法的易受骗性?

针对机器学习算法的社会工程攻击的含义非常重要,因为它在如此多的不同应用中被越来越多地采用。因此,机器学习为网络对手创造了一种新的攻击服务。社会工程师的目标可能是逃避检测。这可能是为了利用算法的偏见。社会工程师可能会攻击机器学习算法,对信息进行错误分类。对手可能会勒索赎金,以阻止算法充斥不良信息。此外还有安全问题。如果自动驾驶汽车或自动化工厂机器人可能被误导到危及生命的危险场景中,会怎么样?

为了帮助回答这个问题,如果机器学习算法容易受到社会工程的攻击,我们只需要一个例子。漏洞就像你在家里发现的一只老鼠。很少只有一个。因此我们可以推断,如果这些算法容易受到一种形式的社会工程的攻击,它们可能容易受到许多形式的攻击。

在这个例子中,研究人员避开了一个名为 PDFrate 的在线恶意软件检测系统[1]。该系统用于检测嵌入用户上传的 PDF 文档中的恶意软件。PDFrate 使用随机森林算法,并在公开可用的数据集上进行训练。

研究人员从侦察开始。他们提出,如果对手知道使用了什么算法,知道使用了什么训练数据,或者使用了什么特定特征来训练算法,他们就可以实施成功的攻击。在 PDFrate 一案中,几乎不需要侦察,因为所有信息都是公开的。研究人员断言,并非所有这些信息都是策划攻击所必需的,但如果这三个组成部分都可用,攻击就会容易得多。

一旦他们知道了训练数据、特征和算法,他们就创建了一个代理系统,他们可以自由地攻击而不被检测到。有了这种自由,他们可以尝试数千种攻击组合,直到找到成功的特征组合。在他们创建了代理算法后,研究人员确定了最重要的特征,并绘制了如何将逃避性恶意软件嵌入 PDF 文件中。

对于最重要的特征,他们分析了训练数据中的值的分布。通过确保他们的恶意软件注入 PDF 的特征落在平均值附近或平均值的一个标准偏差内,该算法得出结论,PDF 文件是正常的。这只对最重要的特征是必要的,因为其他特征中的值没有足够的权重来触发警报。

使用这种方法,他们建立了基于算法、特征和训练数据的完整和部分知识的代理分类器。如果没有规避,PDFrate 通常可以检测到接近 100%的恶意软件样本,但使用这种技术,研究人员可以用 75%的恶意软件样本规避检测。

除了用代理算法进行实验,研究人员还发现代理数据集可以用来替代实际的训练数据。他们发现并不是所有的特征都需要被识别,因为即使是特征也可以在不知道所有信息的情况下被近似。最后,他们甚至发现,分类器不必完全相同,而是相似类型的算法适合于策划一次成功的攻击。

从这个例子中,很明显,对机器学习算法进行社会工程化是可能的。这只是一种方法。研究人员利用了算法的偏差,就像一个人可能会表现出确认偏差一样。如果他们习惯于看到正常的信息,他们更有可能将异常归类为正常。

知道我们的算法可能容易受骗,我们能做些什么呢?以下是在将您的算法用于在线生产系统之前需要考虑的一些准则。

首先考虑使用易受影响的算法是否会产生太大的风险。如果一个错误决策的潜在结果是危及生命的,导致操作问题,或者错过检测关键信息,那么最好是重新考虑使用机器学习算法。

对算法、训练数据和特征的信息保密至关重要。数据科学家和机器学习倡导者通常会发表他们的研究,公开谈论他们的算法,并对训练数据保持透明。当您的算法将在线使用时,对这些信息的谨慎是至关重要的。

此示例还展示了可能让对手隐藏在数据正态分布中的偏差。有些算法比其他算法更容易受到影响。考虑使用集成方法,在这种方法中,不同的算法使对手更难成功。

这项研究还表明,根据静态数据训练的算法需要定期重新训练。在使用你的算法之前,考虑一下你如何能够包含周期性的再训练。同时让一个人在循环中检查数据,并确保算法没有被滥用。

这只是社会工程的一个例子,可能还有更多。针对机器学习算法保持最新的威胁模型。

网络安全是一场升级的游戏。随着组织弥补其系统中的漏洞,网络对手开始寻找新的攻击方式。如果你认为你已经解决了算法中的所有漏洞,并且保护了数据,请记住,对手会探索你没有考虑到的可能性。

最后,你的算法容易受骗吗?随着机器学习方法和应用的发展,我们应该考虑算法易受骗性的含义。机器学习算法可能会成为下一个攻击面,如果我们给它们太多的自主权,我们可能会后悔。

保护您的算法、保护您的训练数据,以及保护有关您选择的功能的信息。对你的信息保密。考虑集成技术来分散和迷惑对手,并确保您使用定期重新训练来制作更健壮和更不易受影响的算法。这些方法只是一个起点。让安全专家为威胁建模,领先于算法社会工程师。

[1] N. Srndic 和 P. Laskov,规避基于学习的分类器:案例研究 (2014),IEEE 安全和隐私研讨会

黑掉浓缩咖啡

原文:https://towardsdatascience.com/hacking-the-espresso-puck-511e4bae56f6

咖啡数据科学

寻找理解提取的其他方法

我最近买了一个 CoffeeJack ,它没有无底的 portafilter,所以我没有办法了解水是如何流过圆盘的。此外,冰球很难击倒,但我想到了用吸管的好主意。这可以让我在中心或侧面取一些样品,然后对每个样品,我可以做一些切片,添加一些水,并进行地面 TDS (gTDS)测量。然后我利用这一点来理解蒸汽预注入

所有图片由作者提供

初始实验

我没有像样的浓缩咖啡机的透明 portafilter,我想看看蒸汽预注入是如何影响冰球的。因此,在这些测试中,我在不同的时间停止拍摄,拉动冰球,并拍摄一些图像和测量数据。

10 秒蒸汽 PI

冰球是上下颠倒的,所以顶部(没有弄湿的地面)是从篮子底部开始的。

20 秒蒸汽 PI

水渗透得更深,但形成了不均匀。

30 秒蒸汽 PI

水到达了底部,但还是不均匀。进一步的实验表明这导致了射击通道。有趣的是看到黑线表明溶解的固体被推到了圆盘的底部。

50 秒蒸汽 PI

水最终到达了底部,但是有一个通道。

关于通灵,它似乎在 PI 的 10 秒之后开始。这恰好发生在冰球上,第一次夯实是在断奏夯实击球中,所以大约在冰球的一半处。

平脉冲与长脉冲

我们可以比较 50 秒的平坦过渡脉冲和平滑过渡脉冲(间隔 10 秒),使用快速快速过渡和 0.1 毫升/秒的流量而不是 0.2 毫升/秒。两者具有相似的模式,我没有看到特别的好处。

左图:50 秒,右图:10 秒脉冲乘以 10 秒暂停 100 秒。

gTDS 指标

对于这些测试,我还从圆盘的中心和侧面切割了一些核心样本。然后我加了一些水,测量了 TDS。目的是寻找一种趋势,更好地理解中心与边缘的不同。对于每个中心和侧面的核心,我从圆盘的顶部、中部和底部垂直取样。

侧面尺寸通常较低。这是意料之中的,因为存在侧沟,并且淋浴帘将水更多地从侧面而不是中心推入圆盘。

我们可以看看中心和侧面,在顶部,侧面的值肯定比中心低很多。然而,事情在底部变得更加接近。

总的来说,这是一个中间实验,看看我如何通过大量的尝试和错误来改善我的投篮命中率。

如果你愿意,可以在推特、 YouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在订阅

我的进一步阅读:

我的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

黑客世界

原文:https://towardsdatascience.com/hacking-wordle-f759c53319d0

对 Wordle 的分析方法(有点欺骗)

照片由梅林达·金佩尔Unsplash 上拍摄

啊是的。沃尔多。我们这一代的填字游戏。朋友和亲人之间的许多争论都是由这个美丽而简单的游戏引发的。

我不是一个喜欢文字的人(正如你所知道的),但我在日常生活中确实与数学、编程和统计打交道很多,所以自然我想看看我是否能算出 Wordle 并击败我的朋友。在这篇文章中,我将向你展示在解决一个新的单词难题时,我是如何选择我的第一个单词和第二个单词的。**

战略

我的看法是,我想找到一个包含英语中最常用字母的 5 个字母的单词。然后根据这个猜测,我想找到下一组。因此,我的前两个猜测不会是正确的,但我应该有足够的信息来完成这个难题。

首先,我们需要从互联网上获取一个由 5 个字母组成的单词列表,最好是从 API 或数据库中获取。

注意:我用 Python 和 Kaggle 工作簿写我的代码,你可以在下面自己运行!

https://www.kaggle.com/kapastor/wordle-strat

我快速搜索后发现的数据集是:

https://www-cs-faculty.stanford.edu/~knuth/sgb-words.txt

引用:以上数据集来自斯坦福大学计算机编程艺术荣誉退休教授唐纳德·e·克努特。

它以 txt 文件的形式列出了由新空格字符分隔的单词。我将把它作为一个列表加载到 python 中,这样我就可以解析出数据。

**# Standard imports** import urllib
import string
import re**# Open the URL using the urllib package**
url = "[https://www-cs-faculty.stanford.edu/~knuth/sgb-words.txt](https://www-cs-faculty.stanford.edu/~knuth/sgb-words.txt)"
file = urllib.request.urlopen(url)**# Build up a list of the words (remove new space character)**
word_set = []
for line in file:
    decoded_line = line.decode("utf-8")
    word_set.append(decoded_line.replace('\n',''))

现在我有了单词列表,我需要从每个单词中找出最重要的信息。为此,我需要查找 5 个字母单词中每个字母的出现率。这是通过简单地循环每个字母(a-z)并比较它在所有字母集中出现的次数来实现的。这应该给我一个粗略的概率,这个字母出现在 5 个字母的单词集中。

**# Generate a string of all letters**
all_letters = string.ascii_lowercase[:]**# Initialize a dictionary for the letter count and set to 0**
letter_stats_dict = {}
for letter in all_letters:
    letter_stats_dict[letter]=0**# We know the total number of letters...**
total_letters = len(word_set)*5.0**# Now for each letter we look in each word and add the count of that letter in the given word**
for letter in all_letters:
    for word in word_set:
        letter_stats_dict[letter]+=word.count(letter)**# Finally we divide by the total number of letters to get a percent chance**
for letter in all_letters:
    letter_stats_dict[letter]/=total_letters
    total = total + letter_stats_dict[letter]

现在我有了每个字母的流行度,然后我可以给每个单词分配一个信息分数,告诉我字母的组合如何包含最可能的选择。分数是字母平均出现概率的唯一总和。例如,如果单词是 ABBEY 如果我们假设每个字母的概率是

A = 0.2,B=0.05,Y=0.05,E = 0.3

那么艾比的得分是

分数(修道院)= 0.2+0.05+0.05+0.3

注意,我们只使用了字母 B 的一个实例,因为我们在这里寻找唯一性。让我们输入代码!

**# Set up a word dictionary and initialize**
word_stat_dict = {}
for word in word_set:
    word_stat_dict[word] = 0 **# For each word find the unique set of characters and calculate the information score**
for word in word_set:
    unq_char_word = "".join(set(word))
    for letter in unq_char_word:
        word_stat_dict[word]+=letter_stats_dict[letter] **# Sort the list from best to worst score**
word_stat_dict = sorted(word_stat_dict.items(), key=lambda x:x[1],reverse=True)
word_stat_dict = dict(word_stat_dict)**# Print to find the first entry!**
print(word_stat_dict)

瞧啊。第一个词是…..

出现了

厉害!我们有第一个单词!接下来的部分很棘手。我们需要一个信息得分高的新单词,但它不能包含上面的字母。这里我们将使用正则表达式来查找不包含上述任何字符但得分最高的单词。

注意:如果你不知道正则表达式,可以用谷歌,因为它很棒。

**# Regular Expression that looks for words not containing characters in arose**
regex = r"^[^arose]+$"
regex = re.compile(regex)**# Loop over our word stats dictionary to find the next best Wordle guess!**
for word, information_value in word_stat_dict.items():    
    if re.search(regex, word):
        **print(word)**
        break

这给了我们第二个词…..

直到

所以我的前两件事应该是接下来是直到。让我们看看它是如何工作的!我会好起来吗?我会是个傻瓜吗?只有时间会证明一切!

感谢阅读,祝你好运!!!!

如果你喜欢这样,并想支持我,你可以使用我的推荐链接,如果你加入媒体!

https://kapastor.medium.com/membership

Hadoop 与 Spark:概述和比较

原文:https://towardsdatascience.com/hadoop-vs-spark-overview-and-comparison-f62c99d0ee15

Spark 和 Hadoop 的总结与比较

Wolfgang Hasselmann 在 Unsplash 上拍摄的照片

Hadoop 和 Spark 都是开源软件的集合,由 Apache 软件基金会维护,用于大规模数据处理。Hadoop 是两者中较老的一个,曾经是处理大数据的首选。然而,自从 Spark 推出以来,它的增长速度远远超过了 Hadoop,后者不再是该领域无可争议的领导者。

随着 Spark 越来越受欢迎,在 Spark 和 Hadoop 之间做出选择是现实世界中许多公司面临的问题。不幸的是,这个问题的答案并不简单。两种系统都有优点和缺点,正确的选择将取决于所讨论的用例的复杂性。

在本次讨论中,我们将简要介绍 Spark 和 Hadoop,讨论两者之间的主要技术差异,并比较它们的优势和劣势,以确定在哪些情况下应该选择其中之一。

Hadoop 概述

照片由 Wolfgang HasselmannUnsplash 上拍摄——由作者编辑

Hadoop 允许其用户利用由许多计算机组成的网络,目的是利用它们的综合计算能力来处理涉及大量数据的问题。Hadoop 框架有两个主要元素,即分布式存储和处理。分布式存储使用 Hadoop 分布式文件系统( HDFS ),而处理使用另一个资源协商器( YARN )来调度任务和分配资源,从而实现 MapReduce 编程模型。

HDFS 的建立有许多目标。首先,由于一个 HDFS 实例可能包含数千台机器,硬件故障被视为常态而非例外。因此,通过确保快速检测到故障,并且恢复过程平稳且自动,可以对这种故障进行规划。其次,HDFS 的设计考虑的是批处理,而不是用户的交互使用。因此,HDFS 优先考虑高吞吐量,而不是对数据的低延迟访问,从而实现对数据的流式访问。第三,HDFS 确保包含巨大数据集(例如许多 TB)的用例被容纳。最后,HDFS 的另一个优势是易用性,这源于它与许多操作系统的兼容性以及跨硬件平台的可移植性。

Hadoop 最初发布时没有 YARN,仅仅依赖于 MapReduce 框架。YARN 的加入意味着 Hadoops 的潜在用例扩展到了 MapReduce 之外。YARN 的关键添加是将集群资源管理和调度从 MapReduce 的数据处理组件中分离出来。这导致 Hadoop 集群比 MapReduce 更严格的方法更好地分配资源(在内存和 CPU 负载方面)。YARN 在 HDFS 和运行应用的处理引擎(如 Spark)之间提供了更高效的链接,使 Hadoop 能够运行更广泛的应用,如流数据和交互式查询。

Hadoop 的真正基础是 MapReduce ,它的关键特征是批处理、对数据传递没有限制、没有时间或内存限制。有许多想法可以实现这些特性并定义 Hadoop MapReduce。首先,设计是这样的,硬件故障是预料之中的,并且将被快速处理,不会丢失或损坏数据。第二,优先考虑横向扩展而不是纵向扩展,这意味着增加更多的商用机器比减少高端机器更可取。因此,Hadoop 中的可伸缩性相对便宜且无缝。此外,Hadoop 按顺序处理数据,避免了随机访问,还提高了数据位置意识。这些属性确保处理速度提高几个数量级,并尽可能避免移动大量数据的昂贵过程。

Spark 概述

克里斯蒂安·埃斯科瓦尔Unsplash 上拍摄的照片

Hadoop 的简单 MapReduce 编程模型很有吸引力,并在行业中得到广泛应用,但是,某些任务的性能仍然不是最佳的。这导致了 Spark 的出现,Spark 的引入是为了提供对 Hadoop 的加速。需要注意的是,Spark 不依赖于 Hadoop,但可以利用它。在比较和对比这两种技术之前,我们将简要介绍一下 Spark。

Spark 是一个用于大数据集的数据处理引擎,也是开源的,由 Apache 基金会维护。称为弹性分布式数据集(RDDs)的抽象概念的引入是 Spark 在某些任务上超越 Hadoop 并获得巨大加速的基础。

rdd 是容错的元素集合,通过分布在集群中的多个节点上,可以并行处理这些元素。Spark 速度的关键在于,在 RDD 上执行的任何操作都是在内存中完成的,而不是在磁盘上。Spark 允许对 rdd 进行两种类型的操作,即转换和操作。动作用于应用计算并获得结果,而变换导致新 RDD 的创建。这些操作的分配由 Spark 完成,不需要用户的指导。

通过使用有向无环图(DAG)来管理在 RDD 上执行的操作。在 Spark DAG 中,每个 RDD 被表示为一个节点,而操作形成边。RDDs 的容错特性来自于这样一个事实,即 RDD 的一部分丢失了,那么可以通过使用存储在图中的操作谱系从原始数据集中重新计算它。

Spark 和 Hadoop 的主要技术差异和选择

作者图片

如前所述,Spark 为某些任务带来了巨大的加速。这种情况的主要技术原因是由于 Spark 在 RAM(随机存取存储器)中处理数据,而 Hadoop 在磁盘上向 HDFS 读写文件(我们在这里注意到 Spark 可以使用 HDFS 作为数据源,但仍然会在 RAM 中处理数据,而不是像 Hadoop 那样在磁盘上处理数据)。RAM 比磁盘快得多有两个原因。首先,RAM 使用固态技术来存储信息,而磁盘通过磁性来存储。其次,RAM 比存储在磁盘上的信息更接近 CPU,并且具有更快的连接,因此 RAM 中的数据被更快地访问。

这种技术上的差异导致应用程序的速度提高了许多个数量级,在这些应用程序中,同一个数据集被多次重用。Hadoop 导致这些任务的显著延迟(等待时间),因为每次查询都需要单独的 MapReduce 作业,这涉及到每次从磁盘重新加载数据。然而,使用 Spark,数据保留在 RAM 中,因此从那里而不是从磁盘读取。这导致在我们多次重用相同数据的某些情况下,Spark 的速度比 Hadoop 快 100 倍。因此,在这种情况下,我会选择 Spark 而不是 Hadoop。这种情况的常见例子是迭代作业和交互式分析。

重复使用相同数据集的迭代任务的一个具体且非常常见的示例是机器学习(ML)模型的训练。ML 模型通常通过迭代地经过相同的训练数据集来训练,以便通过使用诸如梯度下降的优化算法来尝试并达到误差函数的全局最小值。数据被查询的次数越多,Spark 在此类任务中实现的性能提升水平就越显著。例如,如果您在 Hadoop 和 Spark 上仅使用一次数据传递(epoch)来训练 ML 模型,将不会有明显的加速,因为 Spark 上的第一次迭代需要将数据从磁盘加载到 RAM 中。然而,Spark 上的每个后续迭代将在一小部分时间内运行,而每个后续 Hadoop 迭代将花费与第一次迭代相同的时间,因为每次都从磁盘检索数据。因此,在处理 ML 应用程序时,Spark 通常优于 Hadoop。

尽管在许多应用程序中这是一个巨大的优势,但值得注意的是,在有些情况下,内存中的 Spark 计算并不尽如人意。例如,如果我们处理的数据集非常大,超过了可用的 RAM,那么 Hadoop 就是首选。此外,同样由于内存和磁盘的差异,与 Spark 相比,Hadoop 的扩展相对容易且便宜。因此,尽管 Spark 可能最适合时间有限的企业,但 Hadoop 更便宜的设置和可扩展性可能更适合资金有限的企业。

如果你从这些文章中获得了价值,考虑使用下面的链接注册 medium!👇

https://medium.com/@riandolphin/membership

汉密尔顿+ DBT 在 5 分钟内

原文:https://towardsdatascience.com/hamilton-dbt-in-5-minutes-62e4cb63f08f

一起使用这两个开源项目的快速演练

配合得很好的东西。图片来自 Pixabay。

在这篇文章中,我们将向你展示在一个 DBT 任务中运行汉密尔顿是多么容易。利用 DBT 令人兴奋的新 python API ,我们可以无缝融合这两个框架。

Hamilton 是用 python 描述数据流的声明性微框架。例如,它非常适合表达特征转换的流程及其与拟合机器学习模型的联系。

DBT 是一个帮助人们描述由 SQL 组成的数据流的框架,现在有了最新的功能,甚至是 python!

虽然这两个框架乍看起来可能不兼容,甚至是竞争的,但 DBT 和汉密尔顿实际上是互补的。

  • DBT 最擅长管理 SQL 逻辑和处理物化,而汉密尔顿擅长管理 python 转换;有些人甚至会说 Hamilton 是 python 函数的“DBT”
  • DBT 包含自己的编排功能,而 Hamilton 依赖运行 python 代码的外部框架来执行您定义的内容。
  • DBT 没有在“列”的层次上建模转换,而是在“表”的层次上建模。Hamilton 致力于让用户能够以一种可读、可维护、python 优先的方式描述“柱状”转换和“表格”转换。
  • DBT 专注于分析/仓库级别的转换,而 Hamilton 擅长表达 ML 相关的转换。

在高层次上,DBT 可以帮助你获得数据/在你的仓库中运行大规模操作,而汉密尔顿可以帮助你从中制作一个机器学习模型。DBT 可以在 SQL 的测试和文档方面提供帮助。汉密尔顿可以为您的 python 代码提供软件工程最佳实践、测试和文档故事方面的帮助(例如,汉密尔顿的整洁的生产熊猫)!

为了证明这一点,我们从 xLaszlo 的 DS 教程的代码质量中获得了灵感,并使用 DBT +汉密尔顿的组合重新编写了它。这与通过 scikit-learn 的 openml 数据集功能获得的 Titanic 数据集一起玩。

虽然我们只指定了一个由 DBT 执行的带有汉密尔顿的 python 任务,但这足以让您开始自己的旅程,将汉密尔顿与 DBT 结合起来!

不熟悉 DBT 或汉密尔顿?

为了使这篇文章简短,我们假设对这两者都很熟悉。然而,如果你想了解更多关于这两个项目的信息,这里有一些链接:

对于 DBT:

对于汉密尔顿:

给汉密尔顿一个 DBT 任务

先决条件:开发好基于汉密尔顿的代码,并准备投入使用。

集成概述:

  1. 您将您的 DBT 项目定义为正常项目。
  2. 创建一个表,作为 python dbt模型的输入。
  3. 编写dbt python 模型,并将 Hamilton“driver”代码放入其中。
  4. 像往常一样继续使用dbt

DBT 运行汉密尔顿的 python 代码:

关于所有代码,包括自述文件和说明,请参见汉密尔顿资源库的示例文件夹中的 DBT 示例。请注意,我们在这里选择了 duckdb 作为dbt后端,因为它很容易在本地运行;对于其他后端,情况可能会有所不同——如果我们所拥有的最终没有为您工作,请让我们知道。在这篇文章的剩余部分,我们总结了一些要点来理解这两者之间的集成。

使用 DBT,你可以定义一个“dbt 模型”,如 python 函数所描述的,它接受dbtsession对象(更多细节见 dbt 文档)。这些能让你接触到你对 DBT 的定义。

在查看代码之前,先简单说明一下,我们正在使用dbt-fal适配器(链接)来帮助管理 python 依赖关系。随着 DBT 对 python 支持的发展,我们预计 DBT 的官方支持在未来会有所改变(例如,参见本讨论);我们将更新这个例子,使它总是正确的。

在 DBT 运行 Hamilton 的代码如下所示:

import pandas as pd
# import our Hamilton related functions that will define a DAG.
from python_transforms import data_loader, feature_transforms, model_pipeline
# import Hamilton modules for making it all run.
from hamilton import base, driver

def model(dbt, session):
    """A DBT model that does a lot -- it's all delegated to the hamilton framework though.
    The goal of this is to show how DBT can work for SQL/orchestration, while Hamilton can
    work for workflow modeling (in both the micro/macro sense) and help integrate python in.
    :param dbt: DBT object to get refs/whatnot
    :param session: duckdb session info (as needed)
    :return: A dataframe containing predictions corresponding to the input data
    """
    raw_passengers_df = dbt.ref("raw_passengers")
    # Instantiate a simple graph adapter to get the base result
    adapter = base.SimplePythonGraphAdapter(base.DictResult())
    # DAG for training/inferring on titanic data
    titanic_dag = driver.Driver(
        {
            "random_state": 5,
            "test_size": 0.2,
            "model_to_use": "create_new",
        },
        data_loader,
        feature_transforms,
        model_pipeline,
        adapter=adapter,
    )
    # gather results
    results = titanic_dag.execute(
        final_vars=["model_predict"], inputs={"raw_passengers_df": raw_passengers_df}
    )
    # Take the "predictions" result, which is an np array
    predictions = results["model_predict"]
    # Return a dataframe!
    return pd.DataFrame(predictions, columns=["prediction"])

就函数中的代码而言——它看起来非常像标准的 Hamilton“驱动程序”代码。

我们:

  1. 导入正确的 python 模块(详见注释)。
  2. 创建一个“驱动程序”,传入正确的配置、模块和适配器。
  3. 执行代码,将 DBT 提供的数据作为熊猫数据帧传入。代码特征化,符合机器学习模型,然后创建一些预测。
  4. 返回“预测”的数据帧,这正是模型对整个数据集的预测。

作为一名从业者,你需要考虑的是将汉密尔顿与 DBT 整合:

  1. 使用 DBT,您可以定义输入数据集。
  2. 使用 Hamilton,您可以定义转换来表征输入,创建模型,然后使用它来预测相同的数据集。对这段代码的一个简单扩展是预测由dbt提供的不同数据集,并返回该数据集。

和汉密尔顿一起跑 DBT

要运行这个示例,您需要做三件事:

(1)检查汉密尔顿储存库。

$ git clone git@github.com:stitchfix/hamilton.git
$ cd hamilton

(2)转到 dbt 示例目录并安装依赖项(为此,我们鼓励使用一个新的 python 虚拟环境)。

 $ cd examples/dbt
$ pip install - r requirements.txt

(3)执行dbt

# Currently this has to be run from within the directory
$ dbt run
00:53:20  Running with dbt=1.3.1
00:53:20  Found 2 models, 0 tests, 0 snapshots, 0 analyses, 292 macros, 0 operations, 0 seed files, 0 sources, 0 exposures, 0 metrics
00:53:20
00:53:20  Concurrency: 1 threads (target='dev')
00:53:20
00:53:20  1 of 2 START sql table model main.raw_passengers ............................... [RUN]
00:53:20  1 of 2 OK created sql table model main.raw_passengers .......................... [OK in 0.06s]
00:53:20  2 of 2 START python table model main.predict ................................... [RUN]
00:53:21  2 of 2 OK created python table model main.predict .............................. [OK in 0.73s]
00:53:21
00:53:21  Finished running 2 table models in 0 hours 0 minutes and 0.84 seconds (0.84s).
00:53:21
00:53:21  Completed successfully
00:53:21
00:53:21  Done. PASS=2 WARN=0 ERROR=0 SKIP=0 TOTAL=2

这将修改一个代表我们数据库的 duckdb 文件。您可以使用 python 或您喜欢的 duckdb 接口来检查结果。将 duckdb 替换为您在现实生活中选择的 db。

恭喜你!你刚刚和汉密尔顿一起跑过 DBT!

更多的细节

为了帮助您了解 DBT 示例的代码并根据您的需要进行修改,我们将代码组织成两个独立的 DBT 模型:

  1. raw_passengers :这是一个简单的选择和连接,使用了 SQL 中定义的 duckdb 和 DBT。
  2. train_and_infer :第 10 行dbt.ref("raw_passengers").df()是这个dbt模型与(1)的链接。有了提供的数据,代码会:
    —特征工程提取测试/训练集
    —使用训练集训练模型
    —在推理集上运行推理
    要查看详细信息,请查看 python_transforms 包中定义的转换。

注意(1):根据规定,在train_and_infer步骤中可以计算的内容中,Hamilton 只运行定义的转换的子集——我们可以很容易地请求它输出指标、返回拟合模型等。对于这篇文章,我们只想保持简单。

注意(2):再次强调前面的观点,我们使用dbt-fal 适配器来帮助管理这个例子中的 python 依赖关系。python 中的 DBT 仍处于测试阶段,我们将开放问题/做出贡献以使其更先进,并随着其 python 支持的发展更新此示例!

注意(3):如果你想使用训练和推断的输出,你可以像引用其他下游dbt模型一样引用它。

未来方向

我们认为汉密尔顿和 DBT 在一起会有一个漫长/令人兴奋的未来。特别是,我们可以做更多来改善这种体验:

  1. 将 Hamilton 编译成 DBT 进行编排——我们正在开发的新的 SQL 适配器将很好地编译成 dbt 任务。
  2. 添加更多自然的集成——包括汉密尔顿任务的dbt插件。
  3. 添加更多不同 SQL 方言/不同 python 方言的例子。提示 : 我们正在寻找贡献者……

如果你对这些感到兴奋,就来看看吧!获得帮助的一些资源:

您可能感兴趣的其他汉密尔顿帖子:

为 AWS Kubernetes 集群处理 DNS 和 SSL/TLS

原文:https://towardsdatascience.com/handling-dns-and-ssl-tls-for-your-aws-kubernetes-cluster-f3ecd0991e6a

在 AWS 上将 Kubernetes 服务连接到您的域的快速纲要

照片由 Unsplash 上对比纤维

因此,您已经在 AWS 上创建了一个 Kubernetes 集群,在其上部署了一些应用程序,并最终准备向世界展示您所构建的东西。但是您需要了解如何将域连接到您的应用程序并设置 SSL/TLS。我以前也有过类似的经历,所以我写了这个快速的总结,这样你就不用去库伯内特兔子洞找答案了。

我会为 SSL/TLS 设置 写一篇单独的文章,并在这里链接,所以这篇文章不会太长。

将您的域迁移到 AWS 路由 53

Route53 是 AWS 提供的 DNS 服务。它的工作是将请求路由到您的域和子域,再路由到附属于它们的 IP。

您可能已经通过 Route53 注册了您的域名,在这种情况下,您不需要在这里做任何事情。但是,如果您从另一个提供商处购买了您的域名,例如 Namecheap,那么您需要将其转让给 Route53 来管理您的 DNS 记录和路由流量。

要通过 AWS 控制台执行此操作,请导航到 AWS Route53 并创建一个托管区域。托管区域保存有关您希望如何路由流量的记录。创建托管区域时,您将被要求提供一个域,例如 example.com,但如果您不想迁移整个域,也可以放入一个子域,例如 test.example.com。

您的新托管区域将有一个包含 4 台服务器的 NS 记录。进入您的域的管理部分,在它当前所在的提供商中。它将有一节添加自定义域名。将 4 个名称服务器复制到自定义 DNS 部分。你完了。现在,您需要等待 24 小时才能完成迁移。

使用 Kubernetes 集群配置外部 DNS

为什么我们把你的域名迁移到 Route53?因为我们希望在您的 DNS 上为您所有公开的 Kubernetes 服务和入口自动创建新记录,如果您的 DNS 位于 AWS 上,这将更容易实现。ExternalDNS 将为我们做这件事。它基本上是我们将在您的群集上部署的一个单元。它将在 route53 中寻找需要 DNS 记录的资源列表,并自动创建这些记录。

以下是外部 DNS 的 K8S 模板:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  # If you're using Amazon EKS with IAM Roles for Service Accounts, specify the following annotation.
  # Otherwise, you may safely omit it.
  annotations:
    # Substitute your account ID and IAM service role name below.
    **eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT-ID:role/IAM-SERVICE-ROLE-NAME**
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: external-dns
rules:
- apiGroups: [""]
  resources: ["services","endpoints","pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
      # If you're using kiam or kube2iam, specify the following annotation.
      # Otherwise, you may safely omit it.
      annotations:
        **iam.amazonaws.com/role: arn:aws:iam::ACCOUNT-ID:role/IAM-SERVICE-ROLE-NAME**
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: k8s.gcr.io/external-dns/external-dns:v0.7.6
        args:
        - --source=service
        - --source=ingress
        - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
        - --provider=aws
        - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
        - --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
        - --registry=txt
        - --txt-owner-id=my-hostedzone-identifier
      securityContext:
        fsGroup: 65534 # For ExternalDNS to be able to read Kubernetes and AWS token files

您会注意到几行粗体字表示 AWS IAM 角色 Arn 的注释。IAM 角色将由 ExternalDNS 承担。它应该有权向 Route53 上的托管区域添加记录。以下是创建该角色的方法。

将这个内联策略保存到一个 json 文件。该策略为角色提供了路由 53 托管区域的权限。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets"
      ],
      "Resource": [
        "arn:aws:route53:::hostedzone/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ListHostedZones",
        "route53:ListResourceRecordSets"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

使用 AWS CLI 创建角色。

aws iam create-role — role-name role-example — assume-role-policy-document path/to/policy

将上面命令返回的 Arn 替换到 ExternalDNS 模板中的粗体部分,并部署。

kubectl -n external-dns apply template.yaml

好了,我们完成了外部 DNS 的设置。现在,将为您部署的每个入口或服务自动创建一个 DNS 记录。

它是如何工作的一个例子

这里有一个指向 mynginx.your-domain.com 的 nginx 服务的模板。

apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    **external-dns.alpha.kubernetes.io/hostname: mynginx.your-domain.com**
spec:
  type: LoadBalancer
  ports:
  - port: 80
    name: http
    targetPort: 80
  selector:
    app: nginx---apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
          name: http

为了测试,你可以用kubectl apply -f [your-file-name.yaml]应用上面的模板,然后在 route53 中检查你的托管区域下的记录。你会发现一个新的 A 记录自动为 mynginx.your-domain.com 创建,指向这个 nginx 服务的 DNS 名称。

这就是连接您的域。总的来说,我们已经在您的集群上部署了 ExternalDNS,以便它可以自动将指向您集群上的服务和入口的新记录添加到 Route53 上托管的域的 DNS 中。我们还将您的域迁移到了 Route53,因此它可以由 AWS 管理,并创建了一个新角色来授予 route 53 external DNS 权限。接下来,您需要为您的服务设置 TLS/SSL。我将在下一篇文章中讨论这个问题,并在这里链接。

在 Power BI 中处理历史记录

原文:https://towardsdatascience.com/handling-historisations-in-power-bi-30dc43e9e6f

在报道中,历史化就是一切。但是除了通常的时间序列数据之外,我们需要查看维度表的历史化。我们可以这样做。

Towfiqu barbhuiyaUnsplash 上的照片

介绍

最常见的报告轴是时间。以天、月或年为粒度。

至关重要的是,我们能够不带任何扭曲地看待过去。

本主题中的一个因素是值随时间变化的“通常”时间序列。

但是报告解决方案的另一部分是维度。

当某个东西发生变化,会改变过去数据的结果,会发生什么?这种变化会带来灾难性的后果。

在本文中,我将讨论以下主题:

  • 为什么我们需要维度表的数据历史化?
  • 我们如何在 Power BI 中实现这样的解决方案,我们需要考虑什么?
  • 行级安全性的安全性设置会发生什么变化?

我不会讨论如何生成历史数据。

您可以在下面的参考资料部分找到一些关于这个主题的资源。

如果你想让我写一篇关于如何建立历史维度数据的文章,请发表评论。

但是请注意,构建历史化数据的机制会根据您的数据平台和用于加载数据的工具而变化。

为什么我们要历史化我们的维度?

考虑以下虚构的组织 MyCorp.com:

图 1—MyCorp.com 的组织结构图(作者提供的图)

2022 年 9 月 1 日,组织中的一些人将被提升或改变职位。

现在,新的组织结构图如下图所示:

图 2-晋升后的组织结构图(作者提供的图)

该组织的所有成员都完成了销售。因此,我们可以开始创建销售报告。

让我们看看修改前的报告:

图 3 —变更前的销售报告(作者提供的图)

在实现了数据的更改后,我们将得到以下报告:

图 4 —变更后的销售报告(作者提供的图)

如你所见,所有的数据都变了。这是因为有些人换了部门,关于过去的数据被移到了新的部门。

通常,这不是我想要的。

由于更改发生在 9 月 1 日,我希望在此日期之前的数据不会更改,并且销售额将分配给更改后的新部门。

更改数据

在基本窗体中,雇员表如下图所示:

图 5 —基本雇员表(由作者提供)

该表与带有 PersID 列的 sales 表有关系,以构建下图所示的基本数据模型:

图 6 —数据模型(由作者提供)

当我们希望确保背面不被更改时,当维度表中的数据发生更改时,例如,通过部门的更改,我们必须更改雇员表:

  1. 每个雇员可以有多个具有相同 PersID 的行,因此我们需要一个技术键列作为代理键(SurrID)。每一行都有自己的代理键,而 PersID 是业务键
  2. 我们必须将经理的 PersID 映射到代理键
  3. 我们必须记录数据的有效性。为此,我们必须添加两个新列:
    a. ValidFrom:每一行有效的开始日期
    b. ValidTo:每一行有效的结束日期
    通常,ValidTo 列包含一个遥远未来的虚拟日期,例如 31.12.2199

9 月 1 日,我们的组织发生了上述变化。

我要做的是:

  1. 关闭行:将 ValidTo 列设置为 31.08.2022
  2. 添加生效日期为 01.09.2022 的新行
  3. 将添加的行的 ValidTo 列设置为 31.12,2199

最后一步是将管理器映射到代理键。

在我的 Azure SQL 数据库上,我使用以下 SQL 查询完成了这项工作:

SELECT [E].[SurrID]
        ,[E].[PersID]
        ,[E].[Name]
        ,[E].[Email]
        ,[E].[Position]
        ,[E].[ManagerID]
        ,[M].[SurrID] AS [Mgr_SurrID]
        ,[E].[Department]
        ,[E].[ValidFrom]
        ,[E].[ValidTo]
   FROM [dbo].[EMP_Hist_2] AS [E] → 18 Rows
    LEFT OUTER JOIN [dbo].[EMP_Hist_2] AS [M]
      ON [M].[PersID] = [E].[ManagerID]
      AND [E].[ValidFrom] BETWEEN [M].[ValidFrom] AND [M].[ValidTo];

您可以看到,我必须考虑每一行的有效性,以获得正确的映射。

经过这些更改后,雇员表如下所示:

图 7 —修改后的雇员表(由作者提供)

这种方法称为渐变维度类型 2 (SCD2)。

SCD Type 1 覆盖了所有属性,这就是我在更改维度表之前向您展示的内容。

当数据发生变化时,SCD 类型 2 生成一个新行。每一行都有描述有效性的列(ValidFrom 和 ValidTo)。

通常,您会将第一种和第二种类型结合起来:

  • 对于可以被覆盖的所有列(属性),使用类型 1,例如,邮件地址、电话号码和包含信息的所有属性,对于这些信息,旧值在更改后是无用的
  • 您对所有属性使用 Type 2,这可能会改变结果,如上所示

您可以在下面参考资料部分的第二个和第三个资源中找到关于这个主题的资源。

让我们看看我是如何在 Power BI 中实现这些变化的,以及结果如何。

在 Power BI 中实现

基本的数据模型没有改变。

但是现在,Sales 表通过 SurrID 列与 Employees 表建立了关系。

为了得到这个结果,我在我的 Azure SQL 数据库上使用了以下查询,根据 Sales 表中的日期匹配 Employees 表中的正确行:

SELECT [E].[SurrID]
        ,[S].PersID
        ,[S].[Date]
        ,[S].[Amount]
   FROM [dbo].[Sales] AS [S]
      INNER JOIN [EMP_Hist_2] AS [E]
         ON [E].[PersID] = [S].[PersID]
   WHERE [S].[Date] BETWEEN [E].[ValidFrom] AND [E].[ValidTo];

结果看起来像这样:

图 8 —历史化员工表的结果(由作者提供)

将此图中的值与上面图 3 中的值进行比较可以看出,2022 年 9 月之前的值没有变化。但是从 2022 年 9 月开始,新的分配是活动的,销售被分配到新的部门。

拉兹万·苏驰在 Unsplash 上的照片

但是在处理历史化(SCD2)数据时,还有一个我们必须考虑的话题:历史化维度表的行级安全性。

使用 SCD 的行级安全性

我们希望根据组织中每个成员的职位,根据他在组织结构中的位置,来限制对数据的访问。

例如:

  • 威廉会看到一切
  • 马丁只能看到研究部门下属的数据
  • Jimmy 只能看到他和他的职员 Jordan 的数据
  • 乔丹只看到他的数据

实现这一点;我们需要将父子结构分成单独的列。

当您查看下图时,您将看到从列路径开始的结果:

图 9 —具有扁平层次结构的表格(由作者绘制)

我使用了下面“在 DAX 中扁平化父子层次结构”中引用的文章中描述的技术。
那里的描述非常详尽,非常有帮助。

我们将实现一个行级安全(RLS-)规则来实现访问控制。

首先,我们必须打开 RLS 对话:

图 10 —设置 RLS —打开对话(图由作者提供)

接下来,在对话中,我们必须添加一条新规则:

图 11——设置 RLS——创建一个新规则(由作者提供)

单击 Create 按钮,输入新规则的名称。接下来,单击要创建新规则的表,并在表名右侧的区域中输入新的表达式。

我们想要创建一个规则来检查当前用户的电子邮件地址,并将其与 Path 列中的 id 列表进行比较。
我们可以通过这种方法满足上述要求。

所需的 DAX 表达式如下:

PATHCONTAINS(
    Employees[Path],
      LOOKUPVALUE(‘Employees’[PersID]
              ,’Employees’[Email]
              ,USERPRINCIPALNAME()
              )
      )

让我们从里到外分析一下这个表达式:

  1. 函数的作用是:获取当前用户的用户名(电子邮件地址)
  2. LOOKUPVALUE() 函数获取这个电子邮件地址的用户的 PersID
  3. PATHCONTAINS() 函数在 Employee 表中搜索路径列中包含当前用户 PersID 的所有行

单击保存按钮保存该表达式。

现在,我们可以测试这条规则:

  1. 我点击建模功能区中的查看按钮
  2. 我选择要测试的规则,并勾选“其他用户”复选框
  3. 我输入了马丁的邮件地址:martin@mycorp.com

图 12——设置 RLS——测试规则(图由作者提供)

现在,我们只看到马丁的数据:

图 13 —设置 RLS —查看结果(图由作者提供)

直到我们在历史化的雇员表中引入变化,这才完美地工作。

当我们用历史化的表尝试(由于表名的变化而稍作修改)DAX 表达式时,我们得到一个错误:

图 14 —历史数据的 RLS 误差(作者提供的图)

这个错误只出现在用一个用户测试我们的 RLS 规则时,这个规则会随着时间而改变,比如 Thomas。

为了纠正这一点,我们必须创建一个全新的 RLS 表达式。

在向您展示新的 DAX 表达式之前,我必须讨论解决问题需要什么。

当计算结果时,我们可以想象使用当前的过滤器上下文对结果中的每个数字评估 RLS 规则。

请看托马斯的下图:

图 15—Thomas 使用正确 RLS 规则的结果(由作者提供)

当我们查看 2022 年 11 月的结果时,我们可以想象引擎执行以下步骤:

  1. 评估过滤器上下文:2022 年 11 月
  2. 考虑筛选器上下文,添加 RLS 规则中的表达式
  3. 仅对托马斯计算 2022 年 11 月的结果

因为我们知道结果将在哪个日期计算(30。2022 年 11 月),考虑到 ValidTo 和 ValidFrom 列,我们必须获得 Thomas 的正确行。

使用这种方法,我们将只收到每个日期的一行。

为此,我们需要一个如下所示的 DAX 表达式:

VAR ActDate = MAX(‘Date’[Date])RETURN
  PATHCONTAINS(
    ‘Employees_Hist’[Path],
      CONCATENATEX(
        FILTER(
          SUMMARIZE(ALL(‘Employees_Hist’)
                      ,’Employees_Hist’[SurrID]
                      ,’Employees_Hist’[ValidFrom]
                      ,’Employees_Hist’[ValidTo]
                      ,’Employees_Hist’[Email]
                     )
            ,[ValidFrom] <= ActDate &&
                [ValidTo] >= ActDate &&
                [Email] = USERPRINCIPALNAME()
           )
           ,’Employees_Hist’[SurrID]
      )
)

以下是 DAX 表达式的解释:

  1. 我用当前过滤器上下文中的最新日期(ActDate)创建了一个变量
  2. 我使用summary()来获得所有雇员的列表,列有 SurrID、ValidFrom、ValidTo 和 Email
    我使用 ALL(Employee_Hist)来删除这个表上的实际过滤器
  3. 这个函数包含在一个 FILTER() 函数中,用来限制行,只获取活动的行([valid from]<= act date&&【valid to】>= act date)和那些带有当前用户电子邮件地址的行([Email]=USERPRINCIPALNAME())
  4. CONCATENATEX() 使用 FILTER()的结果作为输入来获得正确的 SurrID
  5. CONCATENATEX)的结果被传递给 PATHCONTAINS() 函数,以检查 Employee_Hist 表中在 Path 列中具有匹配 SurrID 的行

但是为什么我需要使用这个 CONCATENATEX(…)的东西呢?

我需要它,因为 PATHCONTAINS()请求一个值作为第二个参数。而且,因为 FILTER()返回一个表,所以我必须聚合结果。

为此,我使用 CONCATENATEX()。

我也可以使用 SUMX、MAXX 或 MINXX。

因为过滤函数总是返回单个值,所以这无关紧要。

但是当我创建一个计算列来验证结果时,CONCATENATEX()在表达式的开发过程中非常有用。
我可以在使用 FILTER()找到正确的解决方案之前检查结果。

马库斯·斯皮斯克Unsplash 上拍摄的照片

结论

历史化的表格给我们的数据模型带来了新的复杂性。

但是,只要在数据源中相应地准备好数据,Power BI 中的数据模型仍然很简单。

但是,在使用 RLS 时,您需要考虑历史化表中行的有效性,以获得正确的结果。

可能还有其他需要增加更多复杂性的场景。例如,当其中一个员工发生了变化,但他的下属没有发生变化时,未变化的行将映射到哪个维度行?原版的还是新的?您是否也需要为下属创建一个新行?

您必须检查您的数据和可能的场景,以决定是否需要增加所需的复杂程度。

最初,我计划只写关于 RLS 主题的这篇文章。但是我意识到我需要先解释一下历史化的原理,以免混淆,以防你不知道我们为什么需要这个概念。

我希望您能在下面参考资料的帮助下,将我的示例转化为您的用例以及您的数据平台。

谢谢你陪我到最后。

参考

我用随机数据和虚构的名字创建了这里显示的数据集。

设计和构建数据仓库的最佳书籍是由 Kimball Group |维度数据仓库专家撰写的数据仓库工具包,第三版— Kimball Group

在 SQL Server 中使用时态表实现 SCD2: 在 Power BI-zart is 中使用时态表实现 SCD2】。

深入探讨不同级别的 SCD: 在数据仓库中实施渐变维度(SCD)(sqlshack.com)

如何在关系数据库中实现 SCD2 的描述:【DWgeek.com】设计 SQL 中缓变维度类型 2

用 Python 实现 SCD Type2 作者 Vivek chaud hary | Analytics vid hya | Medium

你可以通过互联网搜索找到更多关于 SCD 和你的数据平台的资源。

在 DAX 中展平父子层次结构:

用父子结构实现动态 RLS:已解决:动态 RLS —微软 Power BI 社区

https://medium.com/@salvatorecagliari/membership

在 Python 中处理缺失数据

原文:https://towardsdatascience.com/handling-missing-data-in-python-c1ffe6e0f325

约翰·马特丘克在 Unsplash 上拍摄的照片。

如上图所示的停车库旨在填满每一个空间;空闲点意味着未使用的产能,这意味着收入和利润形式的产出减少。同样,数据科学家希望他们的数据完全填满每个观察值;数据集中缺失的元素会导致从原始数据中提取的信息减少,从而对分析能力产生负面影响。

不幸的是,完美的数据很少,但是 Python 中有几种工具和技术可以帮助处理不完整的数据。本指南将解释如何:

  • 识别缺失数据的存在。
  • 了解缺失数据的属性。
  • 可视化丢失的数据。
  • 确定丢失数据的位置后,准备数据集。

按照下面的例子和 在链接的 Github 页面 下载包含代码示例和数据的完整 Jupyter 笔记本。

数据:Seaborn 的英里每加仑(MPG)数据,修改

Python 数据可视化库 Seaborn 包含几个免费的开源数据集用于实验;点击了解更多信息。在 链接的 Github 页面 上有一个“MPG”数据集版本,其中的元素被有目的地删除,它将作为本指南中使用的数据集。

修改后的“MPG”数据帧截图如下——注意“model_year”列中的几个“NaN”值:

作者截图。

1.检查丢失的数据

前面的截图展示了寻找缺失数据的最简单的方法:目视检查。这种方法的主要缺点是处理大数据;当 Python 的 Pandas 库有一些快速简单的命令来快速找到丢失数据的位置时,为什么要查看每一行呢?

以下代码为查找缺失数据提供了一个简单的起点:

# Load the data into a pandas dataframe:
df **=** pd**.**read_csv('mpg-data.csv')# Display the dataframe's info:
df.info()

这将返回:

作者截图。

请注意,这将返回一个标题为“非空计数”的列,以及有关数据帧形状的信息(398 个条目,9 列)。“非空计数”列显示有几列缺少数据,可通过它们的 sub-398 非空计数来识别。

另一种方法是运行以下代码:

df.isnull().any()

的。isnull()函数标识缺失值;添加中。末尾的 any()将返回一个布尔值(True 或 False)列,这取决于该列是否完整。上述代码返回以下内容:

作者截图。

这清楚地说明了哪些列包含 null(缺失)值。只有三列(mpg、气缸和排量)是完整的。运行与上面相同的代码。any()返回不同的内容:

df.isnull()

这将返回:

作者截图。

若要按列获取 null 值的计数,请运行以下代码。

df.isnull().sum()

这将返回:

作者截图。

这回答了每一列中有多少缺失值的问题。以下代码提供了整个数据帧中所有空值的总和:

df.isnull().sum().sum()

以上返回值为 247。

另一种方法是使用 python 的 pandas 库来操作 isnull()的输出,并使用相反的函数 notna(),该函数返回数据帧中填充值的计数。下面的代码生成一个新的 dataframe,它汇总了 Null 和 Not Null 值:

# Determine the null values:
dfNullVals = df.isnull().sum().to_frame()
dfNullVals = dfNullVals.rename(columns = {0:'Null'})# Determine the not null values:
dfNotNullVals = df.notna().sum().to_frame()
dfNotNullVals = dfNotNullVals.rename(columns = {0:'Not Null'})# Combine the dataframes:
dfNullCount = pd.concat([dfNullVals, dfNotNullVals], ignore_index=False, axis=1).reset_index()
dfNullCount = dfNullCount.rename(columns = {'index':'Category'})# Display the new dataframe:
dfNullCount

这样的输出是:

作者截图。

根据上面的代码输出,很明显数据包含许多分布在不同行和列的空值。一些列比其他列受影响更大。理解缺失值的下一步是可视化。

2.可视化缺失数据

2.1.缺少图书馆

存在几种用于发现缺失数据的可视化技术。一个例子是缺少 no。该库可通过以下方式轻松安装:

pip install missingno

一旦安装,可视化丢失的数据是简单的。以下代码导入库并显示缺失数据的条形图表示:

import missingno as mimi.bar(df)
plt.show()

作者截图。

x 轴显示列,而 y 轴显示填充量,范围为 0 到 1。总数位于条形图的顶部。请注意,很容易就能发现“model_year”的一半以上都不见了。

以下代码显示了另一种可视化方法—矩阵:

mi.matrix(df)
plt.show()

作者截图。

这与条形图不同,它揭示了缺失数据在每一列中的位置。每列中的空白表示缺失的数据;请注意“model_year”是如何在整个列中相当均匀地分布缺失数据的。有关 missingno 的更多信息,请参考数据科学文章中的

2.2.Seaborn 可视化

Python 的 seaborn 库提供了一些简单的可视化选项。具体而言,seaborn 热图可以揭示缺失数据的存在,包括数据在数据帧中的空间位置。以下代码生成了一个 seaborn 热图:

plt.subplots(figsize=(15,5))  
sns.heatmap(df.isnull().transpose(), cmap = 'Blues')
plt.title("Missing Data in MPG Data")
plt.show()

作者截图。

2.3.Plotly

Plotly 为可视化缺失数据提供了一些交互式选项。值得注意的是,它允许重新创建 missingno bar 可视化,并提供交互性和增强的可定制性选项。

第一步包括将数据处理成数据帧,类似于第一部分中所做的。代码块的第二部分创建条形图。代码和输出如下:

# Data Manipulation to Create a Dataframe and Chart Outputting Null and Not Null Value Counts# Determine the null values:
dfNullVals = df.isnull().sum().to_frame()
dfNullVals = dfNullVals.rename(columns = {0:'Null'})# Determine the not null values:
dfNotNullVals = df.notna().sum().to_frame()
dfNotNullVals = dfNotNullVals.rename(columns = {0:'Not Null'})# Combine the dataframes:
dfNullCount = pd.concat([dfNullVals, dfNotNullVals], ignore_index=False, axis=1).reset_index()
dfNullCount = dfNullCount.rename(columns = {'index':'Category'})# Generate Plot
fig = px.bar(dfNullCount, x="Category", y = ['Not Null', 'Null'])
fig.update_xaxes(categoryorder='total descending')
fig.update_layout(
    title={'text':"Null Values Visualization",
           'xanchor':'center',
           'yanchor':'top',
           'x':0.5},
    xaxis_title = "Category",
    yaxis_title = "Count")
fig.update_layout(legend_title_text = 'Status')
fig.show()

输出:

作者截图。

虽然与 missingno 提供的非常相似,但 plotly 可视化的优势在于可定制性和交互性,包括 hoverdata 和易于导出的截图。

3.丢失的数据怎么办?

最后一步是确定如何处理丢失的数据。这将取决于数据科学家试图回答的问题。从上面的可视化中可以明显看出,“model_year”缺少一半以上的条目,这大大降低了它的有用性。

假设“model_year”是一个无用的列,删除它并创建一个新的数据框架很简单:

dfNew = df.drop('model_year', axis=1)

删除剩余的空值也很简单,只需要一行代码就可以创建一个没有空值的新数据帧:

dfNoNull = dfNew.dropna()# Show if there are any nulls in the new dataframe:
dfNoNull.isnull().any()

作者截图。

假设查看具有空值的列是有价值的;创建不完整观察的数据框架很简单:

dfNulls = dfNew[dfNew.isnull().any(axis=1)]# Show if here are any nulls in the new dataframe:
dfNulls.isnull().any()

作者截图。

前面的操作产生了两个新的数据帧:一个没有任何缺失的数据,另一个只包含有缺失数据元素的观察值。

4.结论

虽然数据科学家经常会处理不完整的数据,但有许多方法可以识别给定数据帧中的缺失数据。各种可视化技术有助于发现空值,并帮助讲述数据完整性的故事。选择最合适的方法来发现、可视化和处理空数据将完全取决于客户的需求。

参考资料:

[1] Seaborn, Seaborn:统计数据可视化 (2022)。

[2] M. Alam,Seaborn Python 中数据可视化的基础知识 (2020),走向数据科学。

[3] A. McDonald,使用 missingno Python 库在机器学习 (2021)之前识别和可视化缺失数据,走向数据科学。

处理通用数据工具包中的缺失值

原文:https://towardsdatascience.com/handling-missing-values-in-versatile-data-kit-bb4f2a907b9c

数据预处理

关于如何使用 VDK 处理缺失值来构建数据管道的教程

马库斯·斯皮斯克Unsplash 上拍摄的照片

VMware 最近发布了一个新的框架,多功能数据工具包 (VDK),您可以使用它进行数据摄取和数据处理。 VDK 帮助您轻松执行复杂的操作,例如使用 SQL 或 Python 从不同来源获取数据。换句话说,您可以使用 VDK 来构建数据湖,在这里您接收从不同来源提取的原始数据,包括结构化、半结构化和非结构化数据。

VDK 还提供了许多插件,可以用来导入不同格式的数据,比如 CSV、HTTP 等等。所有可用插件的列表可在 VDK 官方文档中找到。

除了数据的原始导入,您还可以使用 VDK 处理数据,并将其转换为其他人(如数据科学家或数据分析师)可以直接阅读的格式。

数据预处理是将原始数据导入数据湖后的下一步。通常,数据预处理包括不同的步骤,如处理缺失值、数据格式化、数据规范化、数据标准化和数据宁滨。

您可以结合 SQL 和 Python 的力量,直接在 VDK 中执行数据预处理。本文将通过一个实例向您展示如何处理 VDK 缺失的价值观。

文章组织如下:

  • VDK 的环境设置
  • 场景描述
  • 在 VDK 摄取原始数据
  • 处理 VDK 缺失的价值观。

1 VDK 的环境设置

您可以通过pip安装多功能数据套件,如下所示:

pip install -U pip setuptools wheel
pip install **quickstart-vdk**

要使 VDK 正常工作,您需要安装 Python 3.7+。

VDK 支持不同的存储系统,包括 Postgres、Trino 等等。为了简单起见,在这个例子中,我们将使用 SQLite。因此,我们需要安装如下相关插件:

pip install vdk-sqlite

此外,我们将使用vdk-csv插件来获取数据,因此我们也需要如下安装它:

pip install vdk-csv

2 场景描述

例如,我们将使用hepatitis.csv数据集,可在此链接下的公共领域专用和许可下获得。

下图显示了数据集的前 15 行:

作者图片

数据集包含许多缺失值。

这个场景的目标是:

  • 通过vdk-csv插件将数据集摄取到 SQLite 数据库中
  • 使用 VDK 创建一个没有缺失值的新表
  • 使用 VDK 定义用其他值替换缺失值的策略。

要创建新的数据作业,我们打开一个终端,然后运行以下命令:

vdk create -n missing-values -t my-team --local

vdk create命令创建一个新的数据作业,-n参数指定项目名称,-t参数指定团队名称,--local参数指定项目将使用本地文件系统存储数据。

作为输出,该命令创建一个名为 missing-values 的目录,其中包含下图所示的模板文件。

作者图片

扩展名为.sql.py的文件包含摄取或处理步骤。VDK 按照字母顺序运行作业步骤,因此10_sql_step.sql20_python_step.py之前执行。文件requirements.txt包含项目所需的 Python 包列表。config.ini文件包含运行项目所需的配置。在我们的例子中,我们可以使用默认配置。如果您想使用不同的数据库,您应该正确配置config.ini文件的以下部分:

[vdk]db_default_type=SQLITE
ingest_method_default=SQLITE

3 在 VDK 摄取原始数据

为了在 VDK 获取原始数据,我们使用了vdk-csv 插件。目标是将hepatitis.csv接收到 SQLite 数据库中。首先,我们配置一个环境变量,它将被vdk-csv 插件用来理解如何接收数据:

export VDK_INGEST_METHOD_DEFAULT="sqlite"

然后,我们使用vdk-csv插件获取数据集:

vdk ingest-csv -f hepatitis.csv

我们使用了-f参数来指定要摄取的文件。

我们可以通过运行查询来检查我们是否正确地导入了数据集。例如,我们可以通过以下命令直接计算 VDK 中的记录总数:

vdk sqlite-query -q "SELECT count(*) FROM hepatitis"

有 155 项记录。

4 处理 VDK 缺失的价值观

缺失值是数据集中没有提供的值。处理缺失值时有很多策略。在本文中,我们描述两种方式:

  • 删除所有丢失的值
  • 用其他值替换缺失值,如平均值或常数值。

我们将讨论如何在 VDK 使用这两种 SQL 实现这两种策略。

4.1 删除所有缺失值

我们将所有非空值存储在一个新表中,名为dropped_missing_values。首先,我们定义一个名为10_drop_dropped_missing_values_table.sql的新作业步骤,如果该表存在,它将删除该表:

DROP TABLE IF EXISTS dropped_missing_values;

现在,我们构建一个名为20_drop_dropped_missing_values_table.sql 的新作业步骤,它创建了只包含非空值的dropped_missing_values表。以下代码显示了作业的 SQL 版本:

CREATE TABLE dropped_missing_values AS
SELECT *
FROM hepatitis
WHERE age IS NOT NULL AND
  sex IS NOT NULL AND
  steroid IS NOT NULL AND
  antivirals IS NOT NULL AND
  fatigue IS NOT NULL AND
  malaise IS NOT NULL AND
  anorexia IS NOT NULL AND
  liver_big IS NOT NULL AND
  liver_firm IS NOT NULL AND
  spleen_palpable IS NOT NULL AND
  spiders IS NOT NULL AND
  ascites IS NOT NULL AND
  varices IS NOT NULL AND 
  bilirubin IS NOT NULL AND
  alk_phosphate IS NOT NULL AND
  sgot IS NOT NULL AND
  albumin IS NOT NULL AND
  protime IS NOT NULL AND 
  histology IS NOT NULL AND
  class IS NOT NULL
;

前面的代码只是检查所有字段不包含空值。

我们可以如下运行missing-values数据作业中的所有步骤:

vdk run missing-values

4.2 替换缺失值

或者,您可以用其他值替换缺少的值,例如最常见的值或平均值。

在我们的例子中,我们有 3 种类型的列:数字、布尔和字符串。我们替换以下内容中缺失的值:

  • 具有平均值的数字
  • 具有常数值 False 的布尔值
  • 具有常数值的字符串。

在所有情况下,我们使用COALESCE()功能来搜索和替换丢失的值。

在 vdk 中,我们在数据作业中定义了两个步骤。名为10_drop_replace_missing_values_table.sql的第一个作业删除replaced_missing_values表,如果它存在的话:

DROP TABLE IF EXISTS replaced_missing_values;

第二步名为20_create_missing_values_table.sql,创建 replaced_missing 值表:

CREATE TABLE replaced_missing_values AS
    SELECT COALESCE(age, AVG(age) OVER()) AS age,
      COALESCE(sex, "female") AS sex,
      COALESCE(steroid, False) AS steroid,
      COALESCE(antivirals, False) AS antivirals,
      COALESCE(fatigue, False) AS fatigue,
      COALESCE(malaise, False) AS malaise,
      COALESCE(anorexia, False) AS anorexia,
      COALESCE(liver_big, False) AS liver_big,
      COALESCE(liver_firm,False) AS liver_firm,
      COALESCE(spleen_palpable, False) AS spleen_palpable,
      COALESCE(spiders, False) AS spiders,
      COALESCE(ascites, False) AS ascites,
      COALESCE(varices, False) AS varices,
      COALESCE(bilirubin, AVG(bilirubin) OVER()) AS bilirubin,
      COALESCE(alk_phosphate, AVG(alk_phosphate) OVER()) AS alk_phosphate,
      COALESCE(sgot, AVG(sgot) OVER()) AS sgot,
      COALESCE(albumin, AVG(albumin) OVER()) AS albumin,
      COALESCE(protime, AVG(protime) OVER()) AS protime,
      COALESCE(histology, False) AS histology,
      COALESCE(class, "live") AS class
FROM hepatitis;

我们可以按如下方式运行所有作业:

vdk run missing-values

摘要

恭喜你!您刚刚学习了如何使用 VDK 处理缺失值!您可以将 VDK 用于数据接收和处理。

VDK 是一个非常强大的框架,它允许你建立一个数据湖,并通过其插件合并多个来源。在这个例子中,您已经使用了vdk-csvvdk-sqlite插件。您可以在此链接查看可用插件的完整列表。

更多信息,可以阅读 VDK 官方文档,也可以加入 VDK slack 频道

你想知道如何用 Trino DB 配置 VDK 吗?

你可以阅读这篇文章,它使用 Trino 数据库和 MySQL 服务器来存储数据,使用 VDK 来摄取数据库中的数据。

您可能也有兴趣了解如何使用 VDK 从 REST API 接收和处理数据

本文描述了 VDK 的另一个例子,它从 REST API 中提取数据。由于访问 REST API 需要一个秘密密钥,因此该示例还描述了如何配置 VDK 服务器来存储秘密。

处理敏感数据:入门

原文:https://towardsdatascience.com/handling-sensitive-data-a-primer-caed9b408de1

如何了解和管理客户的敏感数据

正确保护敏感的客户数据比以往任何时候都更加重要。消费者越来越坚持认为他们的数据应该得到妥善的保护和管理。监管环境也变得越来越严格,业务需求也变得越来越复杂。公司及其开发团队肩负着在满足这些需求的同时还能取悦用户的重任。

如果这让你陷入困境,我们在这里帮助你快速的数据隐私入门!首先,我们将帮助您了解各种敏感的客户数据以及适用于这些数据的法规。接下来,我们将指导您评估当前对这些数据的处理。最后,我们将提供如何正确管理这些数据的指导。

学习

第一项任务是了解您已经在处理哪种敏感的客户数据,以及哪些法规适用于这些数据。三个因素决定了哪些法规适用于给定的一组数据:

  • 数据本身
  • 贵公司的垂直行业
  • 您企业运营的地点

首先,考虑数据本身。根据系统中存储的数据类型,适用不同的法规。

先说个人信息 (PI)。这可能是最广泛的受管制数据类别,指的是几乎任何与人相关或可能与人相关的东西。PI 受通用数据保护条例(GDPR)加州隐私权利法案(CRPA)NY SHIELD等法规管制。这些数据的例子包括:

  • IP 地址
  • 地理位置信息
  • 内部 ID 号
  • 人种或种族

个人身份信息 (PII)是个人身份信息的一个子类,指的是可用于区分或确定个人身份的任何数据。总的来说,适用于保护投资的同样规定也适用于 PII,尽管敏感度不同。PII 的例子包括:

  • 名称
  • 电话号码
  • 驾照或其他身份证号码
  • 社会安全号码(社会安全号码比其他 PII 更受管制)
  • 生物识别记录

其他类别的私人消费者数据往往是特定行业的。例如,受保护的健康信息 (PHI)是指所有“可单独识别的健康信息”这在美国由 HIPAA 管理,定义为与以下任何内容相关的任何信息:

  • 个人过去、现在或未来的身体或精神健康或状况
  • 向个人提供医疗保健
  • 向个人提供医疗保健的过去、现在或未来付款

类似地,非公开个人信息 (NPI)是指由消费者向金融机构提供的个人可识别金融信息,因此是金融服务机构所特有的。在美国,NPI 受gram-Leach Bliley Act(GLBA)监管。

最后,某些类型的个人信息受特定于位置的法规管辖。敏感个人信息 (SPI)由 CPRA 定义。这是指不直接识别个人身份但如果公开可能造成伤害的数据。示例包括 ID 号、地理位置、帐户登录信息和遗传信息。

私人信息NY SHIELD Act 定义,适用于与纽约居民相关的任何数据。此外,几乎每个隐私法规都有某种位置范围(如欧盟的 GDPR、美国的 HIPAA 等)。

这不是敏感客户数据的法规或类别的详尽列表。然而,考虑到这一点,我们可以看到几个趋势。首先,这些类别中有许多相互重叠。相同的数据可能属于多个法规的范围,必须根据与您的业务相关的所有法规的要求进行处理。第二,相关的法规将在很大程度上取决于你的组织的垂直行业和它运作的地点。最后,即使在给定的法规中,不同的数据也可能具有不同的敏感度。

了解了各种类型的敏感客户数据后,我们现在准备开始评估流程。本评估将回答“我的敏感客户数据现在是如何处理的?”

评定

在确定应如何处理敏感客户数据之前,花些时间评估当前如何处理是有帮助的。首先,汇编一个已经被处理和存储的客户数据列表。接下来,您应该执行两项评估:一项技术评估和一项政策评估

一个技术评估告诉你数据在系统中的流向。从数据进入系统的那一刻开始,通过应用程序的各个部分跟踪它。确保考虑应用程序、服务和数据层。此外,记下数据离开系统的任何地方,并记下数据去了哪里,比如另一个应用程序或业务报告工具。为当前系统中的每一条敏感客户数据执行此操作。当你继续这样做时,记下任何不一致或处理不当的地方,以便以后解决。

追踪用户 PII 在系统中的流动。图片由作者提供。

通过策略评估,您可以审查当前关于数据治理的策略和控制。首先,围绕敏感数据编写您组织的内部文档,并审查书面政策和程序。在此基础上,考虑这些策略是否充分涵盖了贵公司当前处理的敏感数据的类型和数量。该评估的另一个关键部分是确定这些策略是否被有效地执行,或者实际的治理是否偏离了最初的意图。

有了这两项评估,您应该能够自信地描述您的组织当前对敏感客户数据的处理。此外,您将确定需要改进的领域或需要进一步研究的领域。现在,我们准备定义应该对您的敏感客户数据做什么

管理

为了正确管理您的敏感客户数据,我们建议采用三步流程。

  1. 首先,确定适用于您的法规,以及它们适用于哪些数据子集。
  2. 其次,确定哪些策略需要应用于每个敏感数据子集。
  3. 最后,根据所需的策略,设计或找到一个技术解决方案来实施和加强这些策略。

对敏感客户数据进行适当的技术治理可以保护敏感数据,而不会使其变得不必要的难以使用。考虑将您的敏感数据隔离在零信任数据隐私库中,而不是简单地将其与您的其他数据并排存储。这种方法允许您的敏感数据通过自己独立的控件得到适当的管理。此外,您的 data privacy vault 可以随着您的组织处理的敏感数据的范围而增长,从而实现可扩展性。

如果您希望在几天而不是几周内达到数据隐私法规的合规性,那么您可以选择使用专用数据隐私保险库 Skyflow 。Skyflow 采用零信任方式存储所有类型的敏感数据。数据是隔离的、加密的、安全的,但仍可用于您的业务工作流。vault 中的所有数据都有精确的访问策略,并且可以通过 Skyflow 数据治理引擎轻松定义。所有操作都被记录和审计。Skyflow 为金融科技、医疗保健、PII 等行业提供解决方案,并且符合全球隐私法规。

总结

我们已经经历了三个步骤(学习。评估。治理。)来处理您组织中的敏感客户数据。首先,我们浏览了各种类型的敏感数据以及适用于它们的法规。接下来,我们描述了如何评估您的组织如何处理敏感的客户数据。最后,我们勾画了一个适当管理您的敏感客户数据的流程。我们还考虑了像 Skyflow 这样的隔离式数据隐私保险库如何对此有所帮助。

随着新法规的产生和现有法规的加强,敏感数据治理的格局在不断变化。因此,这个过程不是一次就能完成的;它必须随着组织的发展和法规的变化而不断更新。

基于树的时间序列预测中的趋势处理

原文:https://towardsdatascience.com/handling-trends-in-tree-based-time-series-forecasting-fea5e4c066fb

事实是——没有趋势

安娜·昆潘在 Unsplash 上的照片

介绍

通常,当您看到关于使用 Xgboost 或 LightGBM 等模型解决时间序列问题的文章或指南时,作者会提到树模型获取趋势和预测数据边界之外的能力。这被视为一个需要克服的问题。但是,这确实是一个特性,而不是一个缺陷。只有当我们认为我们的预测需要超出范围时,才应该关闭这个功能——而不是因为趋势存在于我们的数据中。

通过用一条线对数据进行去趋势化,考虑您所声明的内容:

在未来的某个时间点,数据将有一个新的最大值或最小值

这是一个相当强有力的声明,你可能应该非常了解你的数据才能做出这样的声明。尤其是当对数据进行去趋势化时,还会从树中窃取信息——即使它不能显式地对其建模。

所以…虽然接受趋势的存在,但是并不总是有用的去模拟它…

激励人心的例子

让我们来看看一个相当著名的时间序列:航空乘客数据集。这些数据随处可得,其中一个来源来自 Kaggle ,它带有一个开放数据库许可证。

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
sns.set_style("darkgrid")#Airlines Data, if your csv is in a different filepath adjust this
df = pd.read_csv(r'AirPassengers.csv')
df.index = pd.to_datetime(df['Month'])
y = df['#Passengers']
plt.plot(y)
plt.show()

作者图片

显然,有上升趋势。但是,一个新的“最大”值会出现多少次?

作者图片

大约有 20%的时间会发生这种情况,大多是在季节性高峰期。那剩下的 80%呢?“允许”模型出界有意义吗,特别是如果我们非常确定接下来的几个时期不是季节性高峰的话?更重要的是——如果我们不需要预测新的最大值,去趋势化会损害我们的预测准确性吗?

建模

对于这个例子,我们将使用我用 LightGBM 开发的用于时间序列预测的包: LazyProphet 。只需快速进行 pip 安装:

pip install LazyProphet

如果你想了解更多关于这个包的信息,你应该看看我以前的文章:

在我们的实验中,我们将保留过去 12 个月的数据,然后使用 LazyProphet 对去趋势预测和标准预测进行扩展预测。然后,我们将查看测试集 MSE 进行比较。下面是实现这一目的的代码片段:

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.metrics import mean_squared_error
from LazyProphet import LazyProphet as lp
import seaborn as sns
sns.set_style("darkgrid")#Airlines Data, if your csv is in a different filepath adjust this
df = pd.read_csv(r'AirPassengers.csv')
df.index = pd.to_datetime(df['Month'])
y = df['#Passengers'][:-12]
results =[]
for i in range(1, 13):
    if (-12 + i) == 0:
        y_test = df['#Passengers'][-12:]
    else:
        y_test = df['#Passengers'][-12:-12 + i]
    lp_model = lp.LazyProphet(seasonal_period=12,
                              n_basis=10,
                              objective='regression',
                              fourier_order=5,
                              ar=list(range(1, 13)),
                              decay=.99,
                              linear_trend=False,
                              scale=True
                              )
    fitted = lp_model.fit(y)
    predicted = lp_model.predict(i)
    no_trend = mean_squared_error(y_test.values, predicted) lp_model = lp.LazyProphet(seasonal_period=12,
                              n_basis=10,
                              objective='regression',
                              fourier_order=5,
                              ar=list(range(1, 13)),
                              decay=.99,
                              linear_trend=True,
                              scale=True
                              )
    fitted = lp_model.fit(y)
    predicted = lp_model.predict(i)
    trend = mean_squared_error(y_test.values, predicted)
    results.append([no_trend, trend])

让我们来看看结果:

plt.bar(x=range(1, 13), height=[i[0] for i in results], alpha=.5, label='No Trend')
plt.bar(x=range(1, 13), height=[i[1] for i in results], alpha=.5, label='De-Trended')
plt.legend()
plt.show()

作者图片

第一个条形图似乎没有“无趋势”值,这看起来可能有点奇怪。该模型实际上准确地预测了它,所以 MSE 值相当小。即使忽略这一点,我们仍然看到,去趋势模型通常在预测范围内具有更高的错误率,直到 7 期范围。事实上,“无趋势”模型在前 6 个层位的误差平均少 30%。

你能猜到 6 期之后会发生什么吗?

我们的测试数据超出了界限,需要一个趋势来允许树到达那里。

这是我的观点。我们的训练数据(和测试数据)中显然存在一种趋势,但是一直对这种趋势建模会损害我们的准确性。这不仅仅是趋势的存在,而是我们是否相信预测范围内的数据突破了我们的上限。这是一个实际问题,而不是统计问题。

一些补救措施

*在我们了解一些“测试”之前,我只想强调,这些应该是用于指导您决策的指标。或者潜在地标记预测以供审查。趋势线可能很危险!

最直接的解决方案是使用一种简单的方法来“预测”我们是否需要用线性趋势来扩展我们的界限。有很多方法可以做到这一点,但是我将使用 LazyProphet 来完成分类任务。我们将需要通过移除缩放和 ar 组件以及调整“目标”来稍微调整模型。

首先,让我们构建我们的新数据集,如果该值是最大值,它将简单地为 1,否则为 0。

y_class = []
max_val = 0
for i in y:
    if i > max_val:
        max_val = i
        y_class.append(1)
    else:
        y_class.append(0)

接下来我们将进行时间序列分类。return_proba参数表示我们是否想要返回概率而不是二进制分类:

lp_model = lp.LazyProphet(seasonal_period=12,
                          n_basis=10,
                          objective='classification',
                          fourier_order=5,
                           # ar=list(range(1, 13)),
                          decay=.99,
                          linear_trend=False,
                          scale=False,
                          return_proba=True
                          )
fitted = lp_model.fit(np.array(y_class))
predicted = lp_model.predict(12)
plt.bar(x=range(1,13), height=predicted.reshape(-1,))

作者图片

看起来不出所料!基于此,如果预测范围超过 6(当概率大于 0.5 时),我们需要去趋势,这是 100%正确的。通过一些简单的逻辑来解释这个输出,我们可以为linear_trend传递一个TrueFalse,这将产生‘最优’性能。

这是可行的,但是我们增加了一些计算,而且按顺序预测对我来说不是很好。

另一种方法是创建桶并检查这些桶的平均值。如果平均值一直在增加,那么我们就有一个趋势。这似乎不是什么新鲜事,但是我们将根据预测范围来选择存储桶的大小。让我们来写函数:

通过逻辑思考,如果您的预测范围为 1,则:

n_bins = int(len(y) / (forecast_horizon))

简化为系列的长度。因此,大部分值(大于给定的阈值百分比)必须增加/减少。随着我们增加预测范围,我们平滑了数据,最终得到 12 个周期范围的类似结果:

作者图片

其在数据的平滑视图中总是增加。

接下来,让我们实际运行这个测试:

trend = []
for i in range(1, 13):
    trend.append(tree_trend_test(y, i, threshold=.9))

这给了我们:

[False, False, False, False, False, True, True, False, True, True, True, True]

这确实在实际需要之前证明了这一点,但是这种方法不需要任何关于季节性的知识,这是有利也有弊的。

结论

去趋势化是一个重要的问题。这个问题需要我们的关注。我不提倡完全自动化去趋势化,尽管我意识到有时这是必需的。但是,你应该总是选择而不是减少树木的趋势。

在介绍中,我提到了使用树模型进行预测的指南,在某些时候,它们通常会对线性趋势进行可能的“测试”。然后继续用“但是没有什么能打败视力测试”来结束这一部分,我同意这一点。我们可以向整个数据科学界展示这些数据,他们都会说这是一种趋势,而且他们是正确的。

从传统的时间序列观点来看,趋势是存在的。

但是我们必须记住,我们是而不是使用传统的时间序列方法。这不是一个趋势存在与否的问题,而是…

我们需要一个趋势吗?

如果你觉得这很有趣,那么你可以看看我的其他文章:

处理非结构化数据

原文:https://towardsdatascience.com/handling-unstructured-data-feaeec2a6231

使用可执行的 BPMN 图和工作流引擎走向智能自动化。

活动发起人Unsplash 上的照片

在这一点上,我相信可以说我们已经很好地处理了结构化数据。作为一个行业,我们有大量的工具来处理、存储和分析数据的行和列。我们有更多的工具来绘制视觉效果、创建仪表板和生成报告。每天都有很多关于执行探索性数据分析(EDA)、机器学习、统计和 SQL 主题的文章。每个月甚至有更多的课程和书籍被开发和发布。但是对于那些行列不整齐的文档,比如 PDF 或网页,该怎么办呢?这些也是结构化的,但是它们没有始终如一的行和列结构。在这些上下文中,术语“非结构化”经常被不严格地使用。我相信,真的没有非结构化数据这个概念。一切都有组织的模式;否则,我们作为人类什么都不会懂。

每天都有大量信息在文档中产生、发布、张贴和共享。我每天都收到大量的电子邮件。因此,我开始考虑创建一个环境,让所有这些“非结构化”的文档可以无缝地转化为信息,被处理、读取、解析并组织成“行和列”。我越想越兴奋。请继续阅读,了解我的想法和方法。

工作流或管道

我们希望处理文档,通过信息提取读取值,建立数据记录并将记录发送到数据库。用一句话写下这样的要求看起来很容易,但是很难与合作的观众交流和想象。和很多人坐下来,让它发生,那就更难了!

所以我们需要的是流程图或图表。如果我们使用可执行图表而不是 PowerPoint 或 Visio 图像会怎么样?现在,开发人员和非开发人员可以平等地参与讨论。最近,我对可执行的 BPMN ( 业务流程模型和符号)图表产生了兴趣。下面的图 1 展示了我们用例的 BPMN 图。

图 1:运行在 Ubuntu 上的 Camunda modeller 应用程序的截图——图片由作者于 2022 年 1 月提供

图 1 直观地表示了需求,但是也可以部署到工作流引擎,因此是可执行的。让我们先看看这些步骤,然后讨论它们是如何执行的。

步伐

  • 从文件中获取文本:对于给定的文档,我们需要提取文本
  • 单词袋:嗯,不是一个非常用户友好的描述。单词包是对 n 元文法列表的文本挖掘描述。或许我们可以将描述更新为‘剖析文本’。 我们需要分析每个文档的文本,以找出如何用可用的解析器匹配文本。
  • 选择解析器:有些人可能不知道什么是解析器!在我们的例子中,我们将从文本中提取信息。然后,基于文本概要,我们将调用特定的解析策略。
  • Parse:在流程图上可能不是一个有用的描述,但是它从文本中提取了信息。我们也可以将该步骤描述为 检索信息 或特定内容。
  • 提交到数据库:一旦我们提取了所需的信息,我们需要创建一个记录,并根据解析策略将该记录提交到数据库。

通过对图表进行一些调整和更新,我们可以很容易地对从给定文档中提取信息的管道和步骤达成共识。制定一个工作流程图,列出要采取的步骤,这是很好的第一步。我们将此理解为——对于每个文档,创建一个工作流实例,执行并跟踪所有步骤,直到完成。

在引擎上执行工作流程图

有一个清晰和一致的可执行图当然很好,但是你还需要执行该执行的技术。因此,举例来说,如果您有一个工作流引擎和服务工作,它会有所帮助。

服务作业需要作为流程模型的助手。在这里,我们谈论这样的事情:-

  • 服务作业可能会检测到要处理的新文档
  • 服务作业必须检索文档名称,并在工作流引擎上创建工作流的新实例,以启动流程迭代
  • 作为工作流的一部分,需要服务作业来处理和执行外部任务。

工作流引擎实现工作流图并管理每个任务的完成状态。图 2 展示了部署到工作流引擎的工作流图。

图 2:cam unda 工作流引擎的截图,带有部署的 BPMN 图——图片由作者于 2022 年 1 月提供

此时,我们有了一个部署在工作流引擎上的业务流程模型图。如下图所示,启动工作流引擎就像执行。蝙蝠还是。提供了 sh 文件。

(base) david@david-Z270N-WIFI:~/Documents/camunda$ ./start.sh

在生产环境中,您可能希望使用 systemd 或类似的策略创建一个服务,并让该服务在引导时启动,在失败时重启。使用 crontab 启动引擎通常是可行的,但是如果没有 systemd 提供的监控或服务重启模式,服务通常会变得不可用或不稳定。

当引擎启动时,您将获得大量日志数据,如图 3 所示

图 3:作者 2022 年 1 月拍摄的 Camunda 工作流引擎启动截图

您可以导航到 localhost:8080 以查看工作流引擎驾驶舱。

随着引擎的运行,我们现在已经在引擎上部署了一个可执行的 BPMN 图,一切都在等待文档的到来。我们现在需要一份服务工作和一份文件。工作流程图可以定义各种任务,例如:-

  • 人工任务:需要人工交互和确认任务完成的表单、web UI 或其他动作。手动离线活动。
  • 外部任务:外部服务任务提供服务并确认任务完成。
  • 内部任务:内置任务或决策可以由平台在没有帮助的情况下执行。

为本文部署的图是基于外部任务的,因此工作流引擎将不会找到任何工作,直到服务作业创建了一个实例,并且每个任务都分配了一个外部工作器。图 4 展示了外部任务的参数。

图 4:作者 2022 年 1 月发布的 BPMN 图和外部任务的截图

图表中的每个步骤或任务都有一组参数。实现被定义为外部的,主题名是外部服务作业的标签。每个具有主题名称的外部任务都需要一个服务作业。因此,我们在图 4 中看到,“getTextFromFile”是一个外部任务,通过主题名“getTextFromFile”引用。哦,亲爱的,不是用户友好的,但向前!

服务工作

就这一点而言,架构很简单。绘制 BPMN 图是客户端笔记本电脑或台式机的一项活动。运行工作流引擎可通过不同方式实现,例如:-

  • 在本地,比如本文中
  • 使用第三方或专有供应商的 SaaS 托管版本
  • 启动云实例、AWS 保留的虚拟机或其他 spot 实例,并托管您自己的服务器。重要的是,使用 systemd 定义的服务安排引擎启动,管理防火墙安全和备份。

因此,如果您有一个独特的工作流引擎服务器或主机,那将是最好的。此外,至少需要两种类型的服务工作,它们是

  • 检测新文档并在工作流引擎上创建实例的作业。您可能正在轮询 SharePoint 列表,监视系统目录中的文件更改,或者对数据库触发器做出反应。将电子邮件接收到邮箱中可能会使用服务作业来注册工作流实例并触发工作流处理。
  • 与工作流引擎连接并为这些外部任务提供服务的作业

如果您有运行时环境、凭证、API 密钥、防火墙访问和其他元素来在生产环境中部署服务作业,这将会很有帮助。为了便于说明,我们将讨论本文工作流中的几个外部任务。

我们需要一个函数从给定的文档中获取文本。您可能开始问自己什么类型的文档,我们是否需要一种方法来用不同的模块或阅读器打开特定的文档?好吧,我希望你问的是这些问题,这些都是很棒的问题。

上面显示的函数“get_data_from_given_path”值得进行一些讨论。它采用一个参数 file_name,该参数的数据类型为“pycamunda.variable.variable”。我们正在使用 Python Camunda 客户端,并使用工作流实例的数据结构。

textback = p.from_file(file_name.value)

那行代码是伏都教的吗!p 是什么?我们需要讨论变量名、清晰可读的代码,以及更好地让人们以后阅读。p 是在代码文件顶部的模块导入阶段定义的。

from tika import parser as p

p 代表 Apache Tika Python 包装

所以我们将文件传递给 Apache Tika,它会计算出我们传递的是什么类型的文件,以及如何为我们获取文本。一行代码,我们就能得到文本!Tika 可以返回文档内容和/或文件级元数据。在 Tika 中,有不同的操作,如语言检测、语言转换和 OCR。一种技术是调用语言检测,并基于返回代码;您知道文件是否包含图像或文本,因此需要 OCR,Tika 可以处理。Tika 与 Tesseract 集成,可从图像中恢复文本。

其余代码行决定返回数据结构,并确保字符串值不超过 Camunda 引擎中的最大字符串长度(4000 个字符)

if len(text) < 4000:
        return {'text': text}
    else:
        return {'text': text[0:3800]}

该函数将返回一个字典或键-值对,键为“text ”,字符串变量不超过 3,800 个字符。这不是一个特别聪明的捷径,但是我们可以将数据类型从字符串类型改为 JSON 对象,以避免数据类型的限制。显然,从简单的字符串类型转移到更复杂的结构会引入更多的处理和代码。

使用 Apache Tika 和 Python 函数,我们可以从文件中获取文本,而无需设计和处理不同的文件格式。Apache 项目和开源维护者万岁!您确实需要阅读文档并构建错误处理。许多文档类型是可用的,并且是很少使用的旧格式的遗产。

def bag_of_words(text: pycamunda.variable.Variable) -> typing.Dict:
    bow = textProcessor.tokenize(text.value)
    print("bow")
    return  {'BoW' : bow}

下一个函数是“单词包”函数。它在调用中使用一个工作流变量,并利用 textProcessor 对象方法 tokenize,从文本中创建一个标记(n-gram)或单词列表。textProcessor 对象是我的 NLP 类的一个实例,你可以在 Github 上找到它。

这两个函数是外部 Python 任务的示例。外部任务可以根据用例用不同的语言编码。接下来,我们需要将这些服务作业粘附到工作流图和引擎上。

worker.subscribe(
        topic="getTextFromFile",
       func=(get_data_from_given_path),
        variables=['file_name']
        )

worker.subscribe(
        topic='BagOfWords',
        func=bag_of_words,
        variables=['text']
    )

BPMN 图中的主题“getTextFromFile”通过订阅 BPMN 任务主题连接到函数 get _ data _ from _ 给定 _path。现在,您可以开始看到服务工作的构建。使用工作人员和主题订阅来执行粘附到工作流引擎的任务的函数。该模型类似于使用 MQTT 和其他消息代理的 Pub/Sub 模型。

我在本文中使用的工作对象是由彼得·克劳克开发和解释的。如果你想了解工人,我建议你读彼得的文章,链接如下。工作人员连接到工作流引擎,收集感兴趣的可用外部任务,使用锁更新工作流引擎以保留任务,然后向引擎提供完成状态和返回值。工作人员必须始终与引擎保持联系,并轮询工作流实例以查找要处理的新任务。

但是。我们如何创建工作流实例或处理单个文档?考虑以下代码。

首先,第 1 行是要处理的文件列表,在本例中是四个测试 PDF 文档。我可以使用操作系统模块,直接从文件夹中获取文件,轮询 SharePoint 列表或任何数量的组合,包括 S3 桶。

在第 7 行,我们有工作流引擎的 URL。第 11 行和第 12 行遍历文件列表,并为每个文件创建一个工作流实例。第 14 行实际上是将实例发送到工作流引擎。

在不涉及太多细节的情况下,我们可以使用 Python 谈论 BPMN 图、工作流引擎和服务作业,让我们能够对文档执行自然语言处理,而不用担心服务器性能或阻塞线程。事实上,将 Apache Tika 与 OCR 相结合,我们可以从文档中获取文本,而不用担心文档的格式。

无可否认,从文档中获取文本并将其转换成单词包(n-grams)是手头任务中最简单的部分。然而,从文本中提取信息并将该信息映射到数据库记录格式要复杂得多。

选择解析器

我们没有讨论工作流中的两个后续步骤,因为它们必须为给定用例中的特定文档流构建。

当确定给定文本流的正确解析器时,开发人员和设计人员有许多不同的机制和选项。工作流引擎支持决策。我们可以基于文档元数据建立一个规则,并且如果有少量具有可靠元数据标记的良好描述的文档类,那么定义一个决策步骤,这是非常简洁和理想的。但是,如果存在定义不完善的文档类或元数据,那么选择合适的解析器可能是一项基于带有下拉选择器的表单的人工任务。任务和参与者的这种强大组合允许某些问题浮出水面进行人工干预,但仍然保持最高水平的自动化。

尽管如此,将文本流映射到预定义的解析器并不是真正的问题。更确切地说,为一类文档预先定义信息提取策略是很有挑战性的。基于 OCR 的发票处理就是一个例子,工程师记录了良好的准确性,这是由于使用标准软件生成大致相似的发票布局的组织很少使用变体。同样,公用事业账单也遵循类似的模式。然而,阅读法律合同更复杂的是提取某些条款、条件和义务。

从语法上分析

如果您成功地预定义、测试和验证了一个信息提取函数,那么调用解析器需要在服务作业中进行编排,以便根据前面的步骤将文本路由到正确的函数。工作流引擎和服务作业策略将运行良好。

构建数据记录并将其发布到数据库

我们开始从非结构化范式过渡回结构化领域。我们可以将提取的信息编码到传统的行和列中,甚至用 JSON 结构表示信息,从而允许对文档数据库(MongoDB 或 CouchDB)进行 CRUD 操作。我更喜欢在解析器函数中进行处理,并在一个离散的步骤中返回要提交的数据库对象。

关闭

从非结构化文档中提取信息是一个大课题,而编排自动化管道是极其复杂的。在这篇文章中,我分享了一个让我感兴趣和兴奋的方法。以前,我对可执行的 BPMN 声明和工作流引擎的优点不自信,但是经过大量的思考、研究和原型制作,我更加自信了。

我使用 Celery workers、REDIS、RabbitMQ、Apache Spark 和许多线程和集群并行处理的变体评估了其他方法。

写这篇文章对我来说是一次旅程,是对不同可用方法的调和,我对 智能自动化 的整个概念感到更舒服。这里描述的方法利用了自然语言处理、OCR 和业务规则确定。一旦这些模型被验证和批准使用,使用分类器或其他机器学习模型很容易作为一个步骤插入到 BPMN 图中。

如果您对智能自动化、从文档中提取信息或工作流程编排有什么看法,我很想听听您的想法。

参考资料和原始材料

彼得的文章链接

https://medium.com/@klauke.peter/implementing-an-external-task-worker-for-camunda-in-python-566b5ebff488

使用 Apache Tika 转换文档

https://medium.com/@masreis/text-extraction-and-ocr-with-apache-tika-302464895e5f https://medium.com/mlearning-ai/convert-any-type-of-document-to-text-with-apache-tika-using-python-api-ff306c467b3

替代方法

拥有 RabbitMQ 的芹菜工人可以结合 Apache Tika 来实现类似的工作流,但是没有可执行的 BPMN 图。

https://betterprogramming.pub/background-processing-with-rabbitmq-python-and-flask-5ca62acf409c

本文中对特定供应商或第三方的引用并不表示认可,所有讨论的技术都基于可用的开源软件。专有工作流引擎提供了重要的功能,如日志和审计跟踪,这些功能更适合集成到受监管的行业中,如 GMP、Sarbanes Oxley 或金融服务监管环境。在部署智能自动化解决方案之前,务必评估控制和监管要求。

https://cognitivedave.medium.com/membership

使用 Python 进行实际线性调频小波变换参数估计

原文:https://towardsdatascience.com/hands-on-chirplet-transform-parameter-estimation-using-python-a5bd6b795d04

这是如何使用 Python 来估计你的线性调频脉冲的参数

阿迪·戈尔茨坦在 Unsplash 上的照片

信号处理最常见的操作之一就是对信号进行变换。我们这样做的原因是,对信号执行操作的最简单方法并不总是通过观察信号并在其自然域内进行分析*。

*我将把自然域称为信号的原始空间。例如,如果信号是时间序列,自然域是 2D 域,其中 x 是时间,y 是信号值

在我的 最新媒体文章 中,我解释了傅立叶变换和 Chirplet 变换的区别。

这两种信号之间的关键区别在于傅立叶变换用于时间和频率之间不相关的信号(频率不依赖于时间)。下面是一个可以使用傅里叶变换进行分析和转换的信号示例:

作者图片

另一方面,一些信号具有不固定的频率(频率确实是与时间相关的)。这是这种信号的一个例子:

作者图片

我们可以使用线性调频脉冲变换来分析该信号。 在我最新的文章 中,我解释了如何定义一个 chirplet 变换,如何在 Python 中实现它,以及如何绘制它。

我收到的问题中有一个特别有趣,是这样的:

作者图片

这正是我们将在本文中讨论的内容🙃

1.挑战

因此,我们知道线性调频脉冲是一个具有众所周知的解析公式的信号:

作者图片

我们已经看到,通过改变参数组(β、α1、α2、fc、τ和φ),我们可以描述不同种类的线调频脉冲。

现在,假设我们有一个新的 chirplet。这个线性调频脉冲由这 6 个值的集合完全定义。

*通过完全定义,我的意思是信号由一组且仅一组参数表示,反之亦然。

假设我们要用线性调频脉冲表征的信号有以下参数:

作者图片

我们如何估计这 6 个参数?

2.暴力:一种不可行的方法

假设我完全迷路了,我不知道如何完成这个任务。一个非常简单的方法是所谓的蛮力。意思是:

“尝试这 6 个参数的所有可能组合,看看哪一个效果更好”

这个方法在理论上肯定是可行的。当然,如果我们对这个 6 维空间进行足够的离散化,最终,我们会对真实的参数集有一个很好的估计。 有什么问题尽管提?

嗯,这种方法的真正问题是,当我们考虑暴力方法时,计算的复杂性。 假设我们生成一个随机的线性调频脉冲。我们使用以下代码来实现这一点:

所以你只需要大约(10^-3)秒来产生一个随机的线性调频脉冲。但是我们需要多少个线调频小波来列举所有可能的线调频小波组合呢?

假设 k_{variable}是你的离散空间的值的个数。例如,如果您考虑的所有 alpha_1 值都是[0,2,5],您将得到:

作者图片

现在,让我们做以下假设:

作者图片

这意味着我们必须考虑的线性调频脉冲数如下:

作者图片

计算时间为:

作者图片

现在,让我们改变这个 K,看看这个计算时间的值。如果我们画出这个图,我们会得到一个非常有趣的结果😅:

作者图片

我觉得当我们等待 9 年来计算 K=80 时,我们也可以同时找到一个更聪明的解决方案🙃

3.形式方法

让我们正式确定我们的目标。同样,我们想找到θ向量:

作者图片

这个θ矢量唯一地定义了下面的线性调频脉冲:

作者图片

现在当然没有这个函数的解析表达式,只有它的时间序列(或者数值表示)。

现在让我们定义一个所谓的线性调频脉冲内核。这个 chirplet 内核有以下表达式。

作者图片

其中:

作者图片

我想我已经够烦你了,所以我不会解释这些参数的所有细节( )但是如果你想知道它们,请在这里阅读https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4037220&tag=1 )。重要的是,正如你所看到的,线性调频小波核具有和我们定义的线性调频小波相同的表达式。现在,这个线性调频脉冲当然是参量的,它取决于这个 hat 伽马矢量。想法是这样的:

我们我们的信号投射到由这个线性调频小波核识别的 N 维向量上。这个投影参数化,它取决于线性调频脉冲内核的参数。然后我们通过改变这个 gamma 向量来改变这个向量,找到最优值,得到对应的 theta ( )再次阅读 这里 了解更多信息! )

作者图片

如果我们想找到这个投影的最大值我们计算它的梯度。这个梯度的 0 值当然会给我们最优的 hat 值。

给定我们问题的正式定义,我们现在可以开始寻找我们的最佳值。特别是:

  • 我们在 alpha1 上迭代,找到最大的系数自变量
  • 我们在 alpha2 上迭代,找到最大的系数自变量
  • 我们使用希尔伯特变换找到τ和β**
  • 我们使用傅立叶变换找到频率(fc)和相位(φ)**

我们来实现这个吧!

4.动手实施

这种估计可以用下面的代码来完成:

来测试一下吧!
使用以下函数,我们估计参数并创建我们的估计线性调频脉冲。

当然,我们希望输入信号与重构信号相同。我们来看看是不是这样。

嗯,正如我们看到的重建是而不是 总是完美的。

尽管如此,我们看到我们正在一个巨大的维度空间中寻找一个解决方案(我说的巨大是指空间随着参数的数量呈指数增长),并且这个问题是一个具有非唯一解决方案的 NP-hard 问题(在这里阅读更多)。

出于这些原因,我觉得这些结果相当不错。🤩

5.结论

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

本文参考的论文如下:线调频信号分解的逐次参数估计算法 。这个 GitHub 文件夹 也被用作起点

使用机器学习和 Python 进行气候时间序列聚类实践

原文:https://towardsdatascience.com/hands-on-climate-time-series-clustering-using-machine-learning-with-python-6a12ce1607f9

下面介绍如何用很少几行代码使用机器学习对无标签的时间序列进行分类。

乔纳森·鲍尔斯在 Unsplash 上的照片

T 何的第一堂机器学习课是这样开始的:

在机器学习场景中有两种任务:分类和回归。

假设你有一张图片,用数学术语来说就是一个矩阵,你想说这是一只猫还是一只狗的图片。这是一个分类问题,因为你当然是在对一个输入对象进行分类。

另一方面,给定一个输入对象,您可能想要获得一个实值。例如,给定一所房子某些特征,你可能想猜测它的价格。

这是一个非常简单的介绍,理解机器学习是关于什么的是有效和有见地的。隐藏的是,当我们考虑所谓的监督机器学习时,这种区别是真实的。

尽管如此,机器学习算法的一个可能不太著名的应用是无监督的和对应的分类操作,对于未被标记为的数据,该操作被称为聚类。

给定一个对象,你想对它进行分类,却不知道它可能有什么标签。让我们说得更清楚些。

想象一下,你是一个外星人,你在一家杂货店里。
即使你是外星人(我不知道是不是真的:),你也可能会认出剃须刀片苹果是不同的。这意味着你在对物品进行“分类”,即使你对它们的标签一无所知。
这就是
集群的作用。

现在,我们有多种机器学习算法来完成聚类工作。最广为人知的叫做K 的意思是 我们来看看吧。

1.k-均值算法

好的,首先,我要说的是,有人非常详细地解释了 K 的意思,这不是我在这篇博文中打算做的。尽管如此,让我来介绍一下 K 均值算法的步骤。

看下面这张 GIF:

学分:Chire-Own work,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=59409335

想象一下,就像我们说的,我们一开始没有任何标签。所以我们只有 N 个数据点。每个数据点由两个值组成:x 和 y。

现在(第一步)我们在这个二维空间内随机定义三个(一般为 k 个)点。我们称这 k 个数据点为“质心”。
第二步是根据数据点和三个(一般也是 k)质心之间的距离对每个数据点进行“分类”。假设这个新的点 x ,我们有三个质心之间的距离值。让我们称这个距离值为 D1,D2 和 D3。我们根据 d_1,d_2,d_3 的 argmin 把这个点分为 1,2,3。比如如果 d_1 < d_2 < d_3 或者 d_1 < d_2 > d_3 就会归类为 1。 接下来我们要做的(第三步)是通过考虑分类为 1、2 或 3 的所有点的平均值来更新这个质心的值。
第四步是返回到第二步L 次,其中 L 为迭代次数。

2.时间序列聚类

当然,K 均值算法也可以应用于时间序列。我们唯一要考虑的是数据集的维数是 M,其中 M 是时间序列的长度。不管怎样,我们可以做得更好。😃

首先,Python 中有一个库叫做 tslearn 他们所做的是将预处理步骤应用于时间序列,并将众所周知的算法应用于时间序列。其中一个算法是我们到目前为止讨论过的聚类算法。

为什么不能直接应用 K 均值呢?有一个问题。如果两个时间序列相同,但其中一个移动了一个单位,则使用传统方法(如均方误差或平均绝对误差)计算的距离仍然很大,即使两个时间序列之间的差异基本上为 0。

我们希望计算“最短路径”并将其称为两个时间序列之间的距离,而不是以传统方式计算距离。
这种操作被称为 距离时间扭曲 ,其工作原理的实际演示可在下图或这里的 tslearn 文档中找到:

图片由作者制作,使用的代码可以在这里找到

3.气候时间序列聚类

在这篇博文中,我们将使用上文解释过的距离时间弯曲算法对气候时间序列进行聚类。特别是,我们将有世界上一些主要城市的平均温度。我们希望对所有时间序列(2012–2017)中天气相似的城市进行聚类。

数据集可以在这里找到。可以免费下载并用于商业目的(更多信息请点击)。

让我们开始玩吧!

3.0 导入库

3.1 数据预处理

让我们导入数据集并查看一下:

让我们绘制一个时间序列:

对于我们正在使用的算法来说,时间序列当然太混乱了:这需要很长时间。出于我们的目的,让我们对数据集进行欠采样:

很好看,都准备好了:)

3.2 集群

现在,预处理可能有点漫长和无聊,但一如既往,应用模型需要两行代码。

这是:

我们决定用 k=3。
让我们将拟合的模型应用于我们的数据集:

让我们定义我们的时间步长数组:

太好了。让我们画出结果:

这实际上是信息丰富的:

  • 第一级范围很广,但好像总是小于等于 310。一般来说,最低值似乎在 260 左右(250 左右的值似乎是异常值)。
  • 第二类量程较小,但数值明显较大;较低和较大的数值均大于第一类对应的数值
  • 第三个类恰好和第一个类似,但是我们在高温下的值比在低温下的值多。

我同意这些结论可能不明显。其实我作弊了一点点:)。在查看了三个类别的直方图后,我找到了这些解释:

为什么我们说这个信息量大,不明显?嗯,因为这些城市在趋势和范围上看起来很相似,但在位置上并不接近。
另一方面,如果你只是在位置上做一个 K 的意思(像这样):

然后我们看到相应的直方图:

没什么意义吧?
这是因为在地理位置上以某种方式“聚集”在一起的城市在气候上并不一定具有相同的行为。我们都知道气候远比这复杂。

6.结论

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

基于 Python 的实用内容推荐系统

原文:https://towardsdatascience.com/hands-on-content-based-recommender-system-using-python-1d643bf314e4

乔纳斯·雅各布森在 Unsplash 上拍摄的照片

基于 Python 的实用内容推荐系统

以下是如何用 Python 通过几个步骤创建一个基于内容的推荐系统

人工智能最令人惊讶和着迷的应用之一无疑是推荐系统。

简而言之,推荐系统是一种工具,它根据你已经看过和喜欢的内容向你推荐下一个内容。像 Spotify、网飞Youtube 这样的公司使用推荐系统向你推荐你已经看过或听过的下一个视频或歌曲。

建立推荐系统的想法肯定不是昨天才产生的。2006 年,网飞宣布奖励研究团队 100 万美元,奖励他们在给定一些测试数据的情况下,能够构建出最好的推荐系统。这叫做“ Netflix 奖 ”,对了。

由于这个想法相对来说比较古老,所以有一些疯狂的好的推荐系统,他们考虑了很多变量和关于用户的具体信息。当然,网飞的推荐系统并不是真正的开源,即使我们有一些关于他们如何工作的想法,我们也没有他们预先训练好的可以使用的神奇模型。

无论如何,有一种方法可以让推荐系统非常简单,易于运行,并且实际上非常有效!

在这本笔记本中,我将向您展示如何使用几行代码和一些关于机器学习代数的领域知识来构建基于内容的推荐系统。

让我们开始吧:)

0.图书馆

这是让它工作所需要的:

附言:我安装了 KMeans 来进行非监督学习方法,但我没有在本笔记本中使用它,所以如果你没有它,就不需要安装它:我们不会使用它。

1.数据集

我们首先需要的当然是数据集。我在这里找到了数据集,它基本上是从 IMDb (是的,著名的网站)中提取的集合。在这个集合中,我们有一个电影列表和它们相应的特征。我们正在使用的功能有:

  • 电影的概述(即简短描述)
  • 标题
  • 它的流派(其实每部电影都有多个流派)

让我们来看看:

1.1 导入它:

1.2 查看它:

2.方法

当处理文本数据时,首先要做的是将文本转换成数字。更准确地说,我们正在将一串文本转换成一个向量

但是我们是如何做到的呢?我们应该如何聪明地转换字符串,使向量代表文本的含义?
嗯,这是一个非常好的问题,当然要找到一个最佳答案并不容易。尽管如此,还是有真正好的模型(或者更准确地说是变形金刚),比如 BERT ,它们能够明智地将句子转换成文本。如果你对细节感兴趣,这张实际上是一张杰作,而且如此清晰。

BERT 预训练和微调的想法。图片摘自伯特的论文(此处)

但是为什么我们首先要把文本转换成向量呢?

嗯,因为现在我们有了向量我们能够做所有你通常在向量上做的操作:)

假设你正在做一个分类任务,你想使用支持向量机。当然,你需要有个向量来做这件事。因此,如果你必须对一个文本进行分类,你首先要将文本转换成一个向量,然后应用 SVM 算法。

在我们的例子中,我们将使用向量化测试来寻找两个向量之间的相似性。我们的推荐将是与我们正在考虑的向量最相似的(5)

下面是一个例子:

我制作的图像

假设 x 和 y 是两个分量(我们会有比两个多得多的分量)。如果一部电影谈论科学、太空和火箭,而另一部或多或少谈论相同的东西,我们希望这两个向量接近,就像蓝色的向量一样。另一方面,如果另一部电影是关于一个爱情故事,我们会期望这个向量很远,像红色和蓝色的。

所以我们要做的是:

  1. 使用 BERT 将我们的文本转换成矢量
  2. 得到一个固定电影(向量)和所有其他电影的余弦相似度(两个向量夹角的余弦)
  3. 挑选余弦相似度最大的电影(矢量)。我们将挑选其中的 5 个。

就这样:)

我希望这听起来已经很简单了,但是当我告诉你怎么做的时候,它会变得更加清晰。所以让我们开始吧!

3.该方法

3.1 从文本到矢量:

下面是你如何将一个文本转换成一个向量:

3.2 PCA(可选)

我现在使用一种非常已知的方法来降低我们数据集的维度(主成分分析)。它只是画出图来,给你一个文本-向量转换结果的概念,所以你可以安全地跳过它。

3.3 余弦相似度和推荐函数

下面是如何计算余弦** 相似度(一行代码)和函数,我们将用它来获得我们的推荐:**

4.结果呢

让我们剧情一些推荐:

我们可以欣赏一些非常酷的东西。算法识别出教父、教父 II 和教父 III 是相似的!****

让我们更深入地探索一下。

所以,如果你刚刚看完《黑暗骑士》,它会给你《小丑》、《肮脏的哈利》、《蝙蝠侠诞生》、《银河护卫队》和《死亡笔记》!我发现这些建议非常准确,尤其是如果我们考虑到算法非常简单的话!

我们可以通过查看来了解这些建议的准确性:

所以,你看过的电影有以下的剧情:

“当被称为小丑的威胁对哥谭市的人民造成破坏和混乱时,蝙蝠侠必须接受一次最大的心理和身体测试,以测试他对抗不公正的能力。”

****第一部推荐的电影有这个情节:

“在哥谭市,精神有问题的喜剧演员亚瑟·弗莱克被社会忽视和虐待。然后,他走上了革命和血腥犯罪的恶性循环。这条路让他直面他的另一个自我:小丑。”

所以他们其实挺像的!

我们甚至可以欣赏到推荐的电影也有相同的类型:

所以你看的电影是一部剧情家庭电影,而推荐的电影是:

  1. 戏剧
  2. 剧情
  3. 剧情
  4. 戏剧、历史、战争
  5. 冒险、历史、家庭

同样,这是一个非常简单的算法的质量指标!

最后,这是你将你的推荐存储到数据帧中的方式:

5.结论

我知道有很多方法可以得到一个推荐系统。我们这里的假设是,我们推荐的东西与你已经看过的东西相似,但是也许你想给用户一个惊喜,所以它不应该像我们建议的那样相似。****

此外,我们只考虑一部电影,我们并没有真正考虑用户的口味,这只是关于电影本身。

换句话说,这只是众多方法中的一种,而且实际上非常简单。尽管如此,我发现这些建议非常准确和有趣,所以这是一个有效的方法,而且从计算上来说,非常便宜!

写这篇文章让我很开心。我希望你读它的时候有很多乐趣。如果你有任何问题或意见,我很高兴在这里听到他们:【piero.paialunga@hotmail.com 。

再见:)

使用 Python 对美国蜂蜜消费进行实践探索性数据分析

原文:https://towardsdatascience.com/hands-on-exploratory-data-analysis-on-honey-consumption-in-the-usa-using-python-ddfb8be519d7

这是我对美国蜂蜜的探索性数据分析,用了几行代码

照片由 Aaron BurdenUnsplash

免责声明:这篇文章可能会冒犯那些关注我并阅读这些故事的素食主义者。虽然我对此提前表示歉意,但请注意,这个练习并不是为了促进蜂蜜的使用、消费或销售。

在下面的文章中,我们将对美国蜂蜜的生产和消费进行探索性的数据分析。

特别是:

  1. 我们将从查看数据集开始
  2. 我们将定义我们将在分析过程中使用的 Python 环境
  3. 我们将清理我们的数据
  4. 我们将执行时间独立时间独立分析
  5. 我们将查看相关值
  6. 我们会玩得很开心。😃

那我们开始吧!

0.关于数据集

EDA 的第一步根本不涉及任何代码,只是基于对数据的定性描述。
首先,数据集来自美国国家农业统计局,USDA ,许可为 CC0:公共领域(开源)。描述说:

“这个数据集提供了对蜂蜜不同状态生产需求供应的洞察。蜂蜜是蜜蜂制造的天然产品。”

这正是我们要做的:对不同州的蜂蜜产量和价格进行探索性的数据分析。

数据集的另一个重要特性是名为“year”的列
这意味着对于给定的州,我们有给定年份的平均产量和平均价格。正如我们将看到的,这将使我们能够比较各州的产量和价格,并了解它如何随着时间的推移而变化。

听起来很刺激,对吧?🙃

让我们从代码开始。

1.导入库

在开始分析之前,我们必须导入我们将要使用的库。很多分析会用到一些绘图,所以我也附上了我对绘图部分的偏好。如果你不喜欢美丽的情节,请随意摆脱它😏

2.导入数据集

让我们导入并显示第一个条目:

很好,让我用魔法数据。数据信息 () :

我们可以看到,除了状态列之外,所有列都是数字。这很好😮‍💨

正如我们所看到的,“state”列是告诉我们实例所在的美国州(阿拉巴马、亚利桑那、阿肯色州等)的列。).

产量列、平均价格年份列是我们在这个具体示例中最常使用的

1.Kaggle 用户告诉我们产量是菌落数量和每个菌落产量的乘积。从广义上讲,考虑到我们正在使用的空间和我们有多少蜂群,我们生产了多少蜂蜜。所以我想说这个名字很简单,但是很明确。这是蜂蜜产量的一个恰当的概括。

2.平均价格是指基于扩大销售的每磅平均价格。

*请记住,这种方法很容易推广,只需更改列字符串,正如我们将看到的那样。

3.数据集中的所有实例都与数据集的年列中指示的特定相关。

3.动手探索性数据分析

3.1 关于美国

第一个问题

我们有数据集中的所有州吗?

为了回答这个问题,我已经从这个 GitHub 文件夹下载了数据集列表(多懒啊,对吧?),将其命名为 状态 ,并将其与我们数据集中的状态列表进行比较:

所以看起来我们遗漏了很多州,但事实并非如此。我给你看下面这个情节:

我们真正缺失的状态是:

  1. 阿拉斯加
  2. 康涅狄格州
  3. 哥伦比亚特区
  4. 特拉华州
  5. 马萨诸塞州
  6. 罗德岛

所有其他状态实际上都在数据集中。唯一的问题是,在原始列表中我们有“NewYork”(空格),而在我们的数据集中,它变成了“New York”(非空格)。*

*要查看这种效果,请查看上面图中的 xticks。

现在,为什么我们没有这些状态?真正的答案当然是不知道。

我推测在那些州我们没有足够的蜂蜜产量。这一假设被证实,因为如果我们看一下美国农业部的报告,这 6 个州都在“其他州”之内,并且加起来的产量比数据集中的其他单个州要小。

3.2 时间独立分析

好吧,让我们暂时忘记时间栏。我们想要得到所有值的汇总。为此,我们可以使用以下函数:

让我给你看一些例子:

  1. 俄亥俄州(我的家乡❤)

2.加州

好,举个例子,我们可以画出每个州的平均产量和平均价格。如果我们这样做,我们可以获得哪个州的产量最大(或最小)以及哪个州的平均价格最大(或最小)的信息。为此,我们必须使用我们定义的 summary_state 函数和以下代码块:****

  1. ****十大生产州:

2.平均价格前 10 名的州(最贵):****

3.概要图:****

我们可以看到的是,平均数的(相对)价格范围小于生产的价格范围。那大概是因为产量和你所在的地方有严格的关系(你不能强迫蜂蜜生长在阿拉斯加)。另一方面,价格与很多商业因素有关,是由男人而不是自然选择的。

现在,我会立即停止做这个分析,因为我感觉它会把我们引向错误的结论。事实上,正如我们将看到的,我们拥有的数据集确实是极其依赖于时间的。这种按时间平均的研究可能会让我们丢失很多重要的分析信息。

3.2 时间相关分析

让我们随机选取三个州,比如俄亥俄州、加利福尼亚州和纽约州,绘制出年与生产线图。

Mh。幅度上的巨大差异。有意思。****

让我们对平均价格做同样的事情。

现在那个就有意思了。就我们数据集的平均价格而言,我们有一个巨大的下降。有两种可能的解释。****

A.我们在数据采集阶段遇到了问题。例如,在第一个年份范围(1995 年至 2018 年),我们正在以美元为单位考虑事情,而从 2018 年至 2021 年,我们正在将单位改为“数百美元”或类似的东西。

B.导致平均价格下降是有实际原因的。这也是可能的。这项研究解决了这个问题,并给出了蜂蜜价格下降的统计推理。

我会说选项 A 是最合理的。我努力想出每磅 350 多美元的价格。😅
我非常确信这是一个 bug,规模不是以美元(如 Kaggle 用户所说)计算,而是以
美分计算。
无论如何,为了这个分析的目的,我们将在我们的分析中去掉那部分数据,这样我们就不会犯任何错误。
****

现在,我们要做的是:

A.从我们的数据集
B 中提取
时间状态相关的数据。对产量和平均价格进行回归分析研究*
比较不同状态的值,查看产量和平均价格的变化。*****

比如说。让我拿俄亥俄州来说。我们将执行以下操作:

  1. 数据集上的训练验证测试拆分
  2. 使用验证集*构建最佳(最小均方误差)多项式回归模型
  3. 提取我们的最优多项式模型,并应用它来拟合生产曲线

*多项式的次数是我们正在调整的超参数。

为此,您需要:

这就是我们从中得到的:

现在我们要做的是一个州一个州地做。

  1. 回归函数:

2.绘图功能:

3.一些例子:

作者提供的图片

但是我们为什么要这么做呢?

因为我们现在有了模型,所以我们可以对更多的数据点进行采样(比如说 1000 个而不是 20 个)。我们将使用这个代理模型来比较两个不同的州。****

我们将使用以下函数来实现这一点:

让我给你看一些例子:

作者提供的图片

这个代理模型让我们看到两个函数的交集在哪里。

换句话说,它告诉我们加州(州 1)何时比俄亥俄州(州 2)生产得多,以及俄亥俄州(州 2)何时比加州(州 1)生产得多。

从我所举的例子中,我们可以得出一些非常有趣的观点。

  1. 从 1995 年到 2012 年,阿拉巴马州的产量远远低于印第安纳州,但在过去 10 年里,它的产量超过了印第安纳州(2015 年有什么变化吗?)
  2. 同样,在过去的 5-6 年里,除了 T5 之外,北达科他州 T1 的产量似乎已经超过了 T2、南达科他州 T3 和 T4,但是现在他们开始越来越接近了,这看起来趋势又要逆转了。
  3. ****加州在整个范围内产生了比俄亥俄州更多的产量(我不会那么信任那一小块正区域),但是随着时间的推移,它们会越来越接近。在过去的两年里,这一差距似乎又要加大了。

我认为这可能非常有用。例如,我们可以使用一个州作为基线(我不知道…弗吉尼亚州),并将其与所有其他州进行比较。作为工程师,我们经常使用“基线的概念和“基线减法”的概念。****

如前所述,如果我们想对价格做同样的事情,我们只需小心地将其调整到正确的点,以避免下跌。
我太爱你了,不想让你知道这个繁琐的数据清理步骤的细节,但是请相信我
或者
看看这个威风凛凛的笔记本。
****

因此,如果您想做同样的分析,但是使用的是平均价格而不是产量列,您可以运行以下代码:****

这是一个可爱的例子:

作者图片

3.3 相关性研究

让我以一个关于相关性的非常小的研究来结束这篇文章。假设我们想知道哪些参数对平均价格的影响最大。我们可以使用两种方法:

  1. 相互信息
  2. 皮尔森相关性

Pearson 相关性是用 pd.corr()实现的,它只不过是一个指标,表明特性之间有多少线性相关性。正如我们已经看到的,即使在第一个数据中,年份和平均价格之间的相关性看起来根本不是线性的。出于这个原因,我还使用了互信息得分,它让您了解两个特征之间的统计相关性,这是我们真正想要的。****

  1. 互信息代码和结果:

除了年份列的之外,没有太多的相关性。这可能是因为数据看起来相当分散(看一些平均价格图)。*和均价高度相关,这和我们在价格图中看到的巨幅下跌是百分之百相关的。如果我们对干净的数据进行分析,我相信这个值会降低。*******

2.线性相关码和结果:****

这很有趣。你拥有的越多,花费越少。这是商业 101,反映在产量和价格之间的负相关性上。线性相关对我们看到的平均价格的下降也是有意义的。我相信,通过使用过滤后的数据,这种相关性将会增加。

4.考虑

在这项关于美国蜂蜜消费和价格的探索性数据分析中,我们做了以下工作:

  1. 我们数据集中缺失状态探索**
  2. 对美国最大产量和最贵蜂蜜的非时变分析。**
  3. 一个回归,时间相关,蜂蜜产量和平均价格的分析。这允许我们为美国的每个州建立一个代理模型。**
  4. 使用替代模型产生的两个输入状态之间的时间相关比较。通过比较,我们得出了一些非常有趣的观点和观察结果。**
  5. 与最后一点相同的研究为平均价格****
  6. 对我们的数据集和 average_price 数据集的特征之间的相关性进行微观研究。

5.结论

如果你喜欢这篇文章,你想了解更多关于机器学习的知识,或者你只是想问我一些问题,你可以:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及数千名其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

用 Python 实现信号处理的生成式对抗网络(GAN)

原文:https://towardsdatascience.com/hands-on-generative-adversarial-networks-gan-for-signal-processing-with-python-ff5b8d78bd28

以下是如何用几行代码构建信号处理的生成式深度学习模型

迈克尔·泽兹奇在 Unsplash 上的照片

在我的研究中,我大量使用机器(深度)学习。两天前,我正在研究生成性对抗网络(GAN ),看看如何将它应用到我的工作中。

代码准备好之后,我开始在媒体上写这篇文章,我试着找到最好的词来开始一个适当的介绍,就像我一直做的那样。

我开始问自己这样的问题:

“读者为什么要读这个?为什么我试图传达的东西是有意义的?在阅读这篇文章之前,我们需要有一个什么样的框架?”

现在,当然,我相信读者应该读这个,因为我觉得我写的东西有意义,有意思。

但事实是我喜欢信号处理,我喜欢写这方面的东西,因为我喜欢信号处理。这篇文章讲的是我最爱的两件事:信号处理人工智能。我把我所有的爱、精力和激情都投入到这两个项目中(我实际上是漂洋过海来研究它们的),我希望你会对这个话题感兴趣。

正如你可能从标题中猜到的,我们将使用生成对抗网络进行信号处理。我们要做的游戏如下:

想象做一个实验。这个实验的设置是由一个发生器完成的。该发生器的输出是一个时间序列(也称为信号)。

作者图片

想象一下,这个实验昂贵,耗费大量能量计算的努力。我们最终想停止做这个实验。要做到这一点,我们需要将我们的生成器变成一个代理。

作者图片

你看到的那个鲑鱼粉色的小脑袋是我们的代理模特。具体来说,这个代理是一个机器学习模型。顾名思义,这个机器学习模型是一个生成式对抗网络 (GAN)。

这篇文章是这样写的:

  1. 构建我们的实验:我们将生成我们控制的数据集,我们将描述它。
  2. 定义我们的机器学习模型:我们将描述我们的 GAN 模型的具体特征。
  3. 探索结果:我们将运行我们的生成模型,并使用我们的代理模型来提取我们的信号。

我希望你和我一样兴奋。我们开始吧!

1.关于实验

来自电气/机械工程师设置的大多数信号都是正弦信号*

*有兴趣的话我写了一篇关于它的文章!这里是你能找到它的地方。

这意味着输出信号是这样的:

作者图片

其中:

  • A 是我们信号的振幅
  • ω频率
  • b偏向

实际上,在现实世界的实验中,我们有噪音元素。
现在,有多种噪声,它们都有各自的颜色对(白色噪声、粉色噪声、蓝色噪声、绿色噪声……)。最典型的噪声之一是所谓的高斯白噪声,这是一种存在于所有频率并且具有高斯分布的噪声。

所以目标信号看起来更像这样:

作者图片

现在,在实践中:

  • 表示通常为 0
  • 标准偏差可以变化,但在我们的实验中,假设它为 1 并且是固定的是安全的。
  • 另一个常数可以被认为是噪声因子前面的一种噪声振幅

所以到最后,它看起来更像这样:

作者图片

现在,这是我们的完美世界,我们的潘多拉,就像他们在《阿凡达》中说的😄

在现实生活中,事情会有所不同。
假设我们固定了一个幅度,但是这个幅度变化很大。
例如,让我们说:

  1. 振幅的范围为 0.1 至 10,步长= 0.1
  2. 偏差可以在 0.1 到 10 的范围内变化,步长= 0.1
  3. 频率的范围为 1 到 2,步长= 0.001
  4. 噪声幅度是固定的,为 0.3(无论如何,噪声的随机性在其概率分布中)

如果我们想合并所有这些随机性,我们可以使用下面几行代码:

以下是一些输出:

作者的图片,使用上面的代码生成

此时,目标应该足够明确:

“假设我们没有目标函数,我们如何生成看起来像是由源生成的信号?”

那我们就从机器学习开始吧🤗

2.关于机器学习

我们正在使用的机器学习模型是生成对抗网络(GAN)

我真的想要这篇关于信号处理的文章,而不是对 GAN 的从头到脚的描述,但我会尝试简单地介绍一下。免责声明:有些人做得比我更好方式(关于这一点,请大点声约瑟夫·罗卡:理解生成性敌对网络(GANs) )

假设 s 是用于 深假 的型号。 这些是生成模型,顾名思义,是通过训练一个生成零件和一个鉴别器实现的。

创成式零件试图生成一个尽可能接近真实模型的模型。如果是这样的话,那就和标准的编码器-解码器没什么区别了。“真正的交易”是区别性部分的存在。

判别部分是一个分类器,试图区分真实和“虚假”(由生成模型生成)实例。

因此,这个游戏是试图构建看起来像训练数据对象的假对象的生成模型和试图区分训练数据对象和假对象的鉴别模型之间的竞争。这个“游戏”是通过最小-最大损失函数伊恩·j·古德菲勒的美丽心灵构建的优雅而简单的算法来实现的。

现在,GAN 最常用的是条件 GAN。条件 gan 是与某个输入相关的生成模型。
假设输入是一个字符串

“一只可爱的飞上月球的猫”

并且输出是图像:

作者图片

在这个例子中,模型比那个更简单,并且创成式模型与特定输入无关。
这个生成模型的输入现在是噪声,所以模型试图从噪声到可能从源产生的信号。

创成式模型的架构如下:

作者图片

区别性模型的架构如下:

作者图片

生成模型是一个 LSTM 模型,它将一个随机噪声向量(一个三维向量)作为输入,并输出一个 300 长的向量,该向量是理想的期望信号:

作者图片

判别模型区分真实(来自训练数据)和虚假(由生成模型生成)输出:

作者图片

该 GAN 的实际实施如下:

现在输入的长度是我们模型的一个参数:

LENGHT_INPUT = 300

噪声向量的维数是 latent_dim 参数。

现在我们必须生成数据集。这意味着建立一个产生 n 个信号的函数。我们还必须产生 n 个具有给定维数的随机噪声输入,并且我们必须构建代码,在给定 n 个随机噪声信号的情况下产生伪信号。

最后但同样重要的是,我们必须构建我们的训练函数。

这段代码将训练我们的生成模型。它还将在每个 n_eval 步骤中,通过绘制真实和虚假数据来显示生成模型的进度(同样,我们所说的虚假是指“由我们的模型生成”)。

3.完整代码

整个剧本

  • 生成数据集数据集
  • 模型
  • 火车火车

是以下内容:

让我向你展示一些进展:

作者图片

现在让我们产生 100000 个随机信号。

这太棒了。想象一下,每个实验花费你 0.5 美元。你刚刚“节省”了 5 万美元。想象一下,每个实验需要 1 分钟。你刚刚“节省”了 70 天。那就是最后用这些 GANs 模型的目的:
“省时省力”。

现在让我们产生 100k 个真实信号。

让我们绘制一些结果:

4.包装它

在本文中,我们:

  1. 我们确立人工智能信号处理牛逼,所以我们决定把它们放在一起。
  2. 我们设计了一个信号处理场景,其中有一个高噪声正弦发生器。这个正弦可以有不同的振幅,不同的频率和不同的偏置
  3. 我们简要描述了 GAN 模型。我们描述了什么是模型的生成部分,什么是判别部分,什么是模型的损失。生成模型的输入是三维噪声,输出是看起来像训练数据之一的信号
  4. 我们训练GAN 模型,我们生成一些随机信号。

这个模型的关键部分是它的生成能力,因此经过训练的生成模型可以节省我们的时间、金钱和精力。这是因为,不需要做实验,你只需要在你的 python 环境中点击“运行”🚀

5.结论

如果你喜欢这篇文章,你想了解更多关于机器学习的知识,或者你只是想问我一些问题,你可以:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新技术的文章。

使用 Python 在 d3js 中创建漂亮的 Sankey 图表的实践指南

原文:https://towardsdatascience.com/hands-on-guide-to-create-beautiful-sankey-charts-in-d3js-with-python-8ddab43edb43

桑基图表是一个很好的方法,通过观察单个项目如何在各州之间流动,就可以发现最突出的贡献。

桑基图表示例。(图片由作者提供)

如果您需要了解系统中的流程,以揭示流程中潜在的低效状态,Sankey 图非常有用。输入数据类似于带有源/目标和权重的网络图,但可以揭示对最突出贡献的新见解。它可以用于许多用例,如改善营销、成本分析、能源流动等方面的客户旅程。 Sankey 图表是D3 blocks 库 的一部分,可以使用 Python 创建。输出完全封装在一个 HTML 文件中,您只需要一个互联网浏览器来显示图形。分享和发布因此变得超级简单。 在这篇博客中,我将介绍桑基图表,并用实际例子演示如何使用它。

如果你觉得这篇文章很有帮助,可以使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 关注我的最新内容!

桑基图表是 D3Blocks 的一部分。

D3Blocks 是一个包含各种图表的库,可视化部分构建在(d3) javascript 上,但可使用 Python 进行配置。通过这种方式, D3Blocks 库将 d3-javascript 的优势(如速度、可伸缩性、灵活性和无限创造力)与 Python 结合在一起,以便快速轻松地访问广泛的社区,如数据科学领域。特别是对于这个领域,关键是它应该能够轻松地扩展到非常大的数据集。D3Blocks 中的每个图表,如 Sankey 图表,都完全封装在一个 HTML 文件中,这使得在网站上共享或发布非常容易。此外,除了浏览器之外,它不需要任何其他技术来发布或共享图表。关于D3 blocks库的更多信息可以在本博客 1 中找到。

桑基图表。

可以用 Python 创建 Sankey 图表,而不用担心任何 d3 javascript 模块。导入 D3Blocks 库后,您可以设置用户定义的参数,并基于您的输入数据集创建图表。 在后台,Sankey 模块将为数据集中的状态和流创建颜色、位置、排序和标签。 它还将包含用户自定义的参数,连接所有 d3 部分,然后最终将其转换成一个单独的 HTML 文件存储在磁盘上。

使用桑基图表的理由。

当一个动作跟随另一个动作跨越时间或状态时,桑基图是有洞察力的。它有助于揭示流程中潜在的低效状态,例如发现流程中的瓶颈。尽管使用源-目标-权重的输入类似于网络分析的输入,但是当需要分析流量时,使用网络分析可能很难解释。桑基图中的每个流的高度可能不同,这取决于其数量,因此确定最突出或最有问题的状态变得更简单。这样的细分使得从数据中得出结论变得容易。

安装。

在我们浏览 Sankey 的功能之前,我们首先需要安装 D3Blocks 库 :

*pip install d3blocks*

输入数据框。

输入数据是一个包含以下三列的数据帧:

  • :描述源状态。
  • 目标 :描述目标状态。**
  • 权重 : 描述了目标状态之间流的相对重要性。

让我们从 能量数据集【2】加载一个输入数据帧的例子。在这个例子中,有 68 行 3 列。 权重的解释 可以看作源-目标关系的强度,从而使得流量的宽度

*print(df) source                   target            weight
0      Agricultural 'waste'     Bio-conversion    124.729
1      Bio-conversion           Liquid            0.597
2      Bio-conversion           Losses            26.862
3      Bio-conversion           Solid             280.322
4      Bio-conversion           Gas               81.144
..                ...           ...               ...
63     Thermal generation       District heating  79.329
64     Tidal                    Electricity grid  9.452
65     UK land based bioenergy  Bio-conversion    182.010
66     Wave                     Electricity grid  19.013
67     Wind                     Electricity grid  289.366[68 rows x 3 columns]*

输入参数。

Sankey 块包含代码部分 1 中描述的各种输入参数。

代码部分 1。桑基图表的输入参数

输出文件。

输出是一个 HTML 文件,存储在磁盘上的指定路径。HTML 包含一个可以共享和发布的全功能图表。

示例:将数据转换为 Sankey 图表。

让我们从一个小例子开始,演示如何将输入数据转换成图表。在下面的代码段中创建一个数据帧,它有 5 个关系,每个关系都有 weight=1

代码部分 2:一个小输入数据集如何转化为 Sankey 图的示例。

图 1A 中的图表显示了目标状态之间的五个预期流量,所有状态的权重=1* 。这表明所有状态的长度相等。然而,状态 A ( 蓝色)和 E ( 黄色)的垂直长度是其他状态的两倍。这是因为在数据帧中,状态 A 被列为源状态两次( A > F 和 A > C ,状态E被列为目标状态两次( B > E 和 D > E )。让我们改变状态 B 的权重,看看会发生什么。如果我们为状态 B 【橙色】设置 weight=2 ,则流的强度加倍(从 1 到 2 ),状态 B 的长度变成之前的两倍垂直长度(如图 1B,橙色状态)。此外,状态 E 的垂直长度也增加,因为状态 B > E 之间的流动强度增加。或者换句话说: 一个状态的垂直长度就是特定源/目标状态被看到的次数,加上权重。 注意,状态计数和权重是归一化的,并且彼此相关。我将加载下一节中设置的能量数据来创建桑基图表。*

图 Sankey 图表是使用代码部分 1 创建的,具有 5 种状态之间的流程。画面 A:所有权重都设置为 1。画面 B:状态 B->E 之间的权重设置为 2。(图片由作者提供)

例如:能源数据集。

这里,我们将使用能源数据集创建桑基图表。如前所述,数据集包含 68 个源-目标行。当我们运行代码部分 1 时,会创建下面的图表:

图 2:能源数据集的桑基图。(图片由作者提供)

整个数据之间的流动是用所有状态组织的,现在可以揭示最突出的贡献或瓶颈的新见解。一些州可能值得进一步调查,因为每个州的总贡献变得异常。

最后的话。

总之,我演示了如何使用 Python 和 d3js 功能创建自己的 Sankey 图表。该图表的开发方式可以处理各种数据集,并允许以交互方式更改颜色、排序和状态定位。桑基图表是 D3Blocks 中的一个模块,d3-javascript 在其中形成基础。使用 d3-javascript 有很多优点,比如速度和灵活性,除了浏览器之外,你不需要任何其他技术来绘制图表。随意摆弄图书馆吧!**

注意安全。保持冷静。

欢呼,E.

如果你觉得这篇文章很有帮助,可以使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 关注我的最新内容!

软件

我们连线吧!

参考

  1. **Taskesen,E,D3 blocks:Python 库,用于创建交互式和独立的 D3js 图表。 中等,2022 年 9 月
  2. 【observablehq.com】, 能源数据集 ,2019 (ISC 许可)

脑机接口设计实践指南

原文:https://towardsdatascience.com/hands-on-guide-to-design-brain-computer-interface-b99bcc198428

情绪估计的一个例子

作者图片

简介—什么是 BCI?

在过去的十年中,脑-机接口(BCI),一种旨在连接大脑和计算机的工具,已经引起了人们极大的兴趣。这种热情的一个具体例子是埃隆·马斯克旨在将大脑与计算机连接起来的初创公司 Neuralink 的每一个公告所引起的大肆宣传。Neuralink 能够创造出能够进行多项任务的植入物,例如用思想控制运动或直接在大脑中播放音乐。

你感到害怕吗?别担心,这很正常。

然而,在这篇博客文章中,我们将只关注一个简单的 BCI 的实现,它带有一个记录大脑电活动的娱乐设备[2],即脑电图(EEG),而不需要任何手术(疼痛或死亡风险)。你(可悲?)不能用它听你最喜欢的播放列表,但可以实时观察穿着 BCI 的人的情绪(用😉).

一个用例——使用 EEG Unicorn 进行情绪估计

如前所述,在本教程中,我们将通过所有必要的步骤来设计一个 BCI 进行一个具体的任务,从想法到具体的实施。作为一个例子,我们提出了一个情绪估计背景下的 BCI。该应用程序旨在评估参与者感受到的情绪

作者对 BCI 情感的阐释。

所提出的流水线的目的是将来自参与者的 EEG 信号作为输入,并在效价/唤醒框架中返回相应的情绪。最后一个目的是在两个轴上表示情绪:第一个轴对应于情绪的情感方面(即积极或消极),第二个轴对应于感受到的情绪的强度。

设计情感识别 BCI 的关键步骤

更具体地说,要设计和部署 BCI,必须遵循几个关键步骤。

范例定义和信号记录

我想建模或评估什么?我申请的目的是什么?我想控制机械手/脚吗?在驾驶任务中评估警惕性?预测疾病?检测癫痫发作?科学界对几个可以插入 BCI 的研究项目有很大兴趣。
在我们的案例中,我们决定专注于之前的一项工作,旨在评估观看视频时的情绪状态[3]。该文件还提出了一个促进特定情绪状态的视频列表(这让我们很感兴趣!).视频列表和相应的情绪都可以在 youtube 上找到,并在[4]中列出。

因此,我们设计了一个实验基准,在观看促进特定情绪的视频时记录 EEG 信号。在我们的中,脚本[registration_pipeline.py](https://github.com/VDelv/eeg_unicorn_basics/blob/main/registration_pipeline.py)提出了一个完成这项任务的代码,用户只需将他想要处理的视频放在专用目录中(或者改变路径)。

大纲分析

在上述基准的帮助下,有可能继续记录 EEG 信号。这些最后将构成训练 ML 模型(甚至 DL)所必需的数据集。

让我们做模型…等一下!

在拥有能够从 EEG 信号中估计情绪的管道之前,我们必须在处理过程中提取信息来帮助模型。如果您有很多信号和/或可用的计算资源,可以跳过这一步。然而,为了保持简单,我们考虑一个更简单的模型来保持一切简单。一种可能的提取信息的方法是基于 EEG 信号的频率特性,即“这个 EEG 段是在高频还是低频范围内振荡?”。在过去,科学家已经发现一些 EEG 信号由几个频带组成,每个频带在特定的任务或行为中增加/减少[4]:

  • 深度睡眠的δ,[0–4Hz]。
  • θ表示困倦,[4–7Hz]。
  • α用于闭眼时的放松和反射,[8–15Hz]。
  • β代表积极思考和专注相关的状态[16–31Hz]。
  • γ表示压力更大的状态[32–50Hz]。

作者对特征提取的说明。

按照这个过程,我们从每个 EEG 片段中提取了一个信息向量。该过程旨在提取信息以更好地处理生物医学信号。这一步可以从脚本的第一部分[outline_analysis.py](https://github.com/VDelv/eeg_unicorn_basics/blob/main/outline_analysis.py)开始。

最后,如果你还在这里,你知道剩下的步骤包括创建一个模型,旨在估计情绪状态(例如,快乐?难过?)从上面预先计算的特征向量。这里,为了保持一种简单易懂的方法,我们将考虑一个由决策树组成的简单模型。这个简单方法背后的思想是找到动态阈值来区分信息向量,例如,对应于低唤醒的第 I 个电极的高α贡献,对应于高价的第 j 个电极的中等γ贡献,等等。

给定特征向量X及其标签y,有可能创建一个分类器(对应于一个决策树)编写为clf。分类器可以很容易地用下面几行代码来训练:

from **sklearn** import **tree**clf = **tree**.**DecisionTreeClassifier**() # definition of the model
clf.**fit**(X, y) # training of the model...

[outline_analysis.py](https://github.com/VDelv/eeg_unicorn_basics/blob/main/outline_analysis.py)的第二部分给出了更完整的解释,包括总体模型描述和培训。在训练完简单的决策树后,可以用joblib库保存它:

...from **joblib** import **dump**
**dump**(clf, 'classifier_file_name')

实时实现

在训练和保存模型之后,剩下的步骤是将每个部分合并在一起。

两个联合脚本必须并行工作:第一个脚本旨在记录、处理和评估来自 EEG 的情绪状态[pylsl_emotion.py](https://github.com/VDelv/eeg_unicorn_basics/blob/main/pylsl_emotion.py),第二个脚本旨在在图表上显示相应的情绪,并带有相应的笑脸,如所述[play_emotion.py](https://github.com/VDelv/eeg_unicorn_basics/blob/main/play_emotion.py)

我们来玩

最后(也是最不重要的):自己试试!代码和自述文件可在 Github 上获得。您可以自己尝试,或者为不同型号或 EEG 耳机改编代码。

乡亲们就这些,感谢阅读!我不声称代码是完美的,但如果你有意见,问题或想知道更多,不要犹豫,与我联系!😊

参考

[1]罗尔夫·温克勒(Rolfe Winkler),埃隆·马斯克(Elon Musk)推出 Neuralink 将大脑与计算机连接起来,《华尔街日报》,2017 ( link )

[2]独角兽混血黑人——大脑接口,(链接)

[3] Katsigiannis,s .和 Ramzan,N. DREAMER:通过来自无线低成本现成设备的 EEG 和 ECG 信号进行情绪识别的数据库。 IEEE 生物医学与健康信息学 (2017 — 链接)。

[4] Gabert-Quillen,Crystal A.《情感电影剪辑的分级》。行为研究方法 (2015 — 链接)。

Katsigiannis,s .和 Ramzan,N. DREAMER:通过来自无线低成本现成设备的 EEG 和 ECG 信号进行情绪识别的数据库。 IEEE 生物医学与健康信息学 (2017 — 链接)。

[5]威廉·O·塔图姆,埃伦·r·格拉斯讲座:非凡脑电图,2014 ( 链接)。

使用 Python 通过主成分分析进行图像压缩

原文:https://towardsdatascience.com/hands-on-image-compression-using-principal-component-analysis-with-python-1cd6cad72366

照片由 Unsplash 上的记者拍摄

使用 Python 通过主成分分析进行图像压缩

从理论到实践,这就是如何使用 PCA 压缩你的图像而不破坏质量

当我和埃森哲https://www.accenture.com/us-en?c=acn_glb_brandexpressiongoogle_12722872&n=psgs_1221&&c=ad_usadfy17_10000001&n=psgs_Brand-|-US-|-Exact_accenture&gclid=Cj0KCQiAi9mPBhCJARIsAHchl1zGVurARH3g4nQKqa8WBZgAE0gxEfbulbQYZ0hrLC72izQCidNYa1caAuXpEALw_wcB&gclsrc=aw.ds一起写硕士学位论文时,我们曾经使用一个确定的固定大小的图像。特别是,我们正在研究一个非常著名的机器学习挑战,它被称为 快速 MRI ,是由脸书人工智能研究(现在的元人工智能)提出的。

我不会说得太详细,但我们有一个具体的目标,那就是提高这些图像的质量。一旦我们做到了这一点,我们开始问自己是否有办法以压缩的形式存储这些大图像,以节省一些存储空间。

我们决定应用主成分分析(PCA)。****

我希望这篇(相当长的)介绍能让你了解 PCA 是如何在行业研究中使用的,因为它是一种非常强大而又相当简单的算法,可以降低你的图像的维度并节省一些空间而不会真正破坏你的图像质量

让我们开始吧。

1.直观的解释

好吧,假设你有这样的数据:

如果你看看这些数据,你会发现一个围绕对角线的特定分布。在某种程度上,如果你只考虑对角线,你也许可以改变数据的维度,从二维转换到一维。

主成分分析方法正是这样做的。它会找到您拥有最多数据集信息的方向,并将您的数据投影到这些方向上。

让我们看看结果:

正如你所看到的,组件 0** 非常有用,你可以使用这个组件来绘制数据。**

假设你的数据集中有 M 个维度。当您使用 PCA 时,您最终会得到:

  • P
  • 允许您切换回原始尺寸的模型

当 P <

Imagine that your data is an image. By all means, this is just a matrix of numbers, let’s say N rows and M columns. What you can do is reduce the columns of your matrix and have a N x P matrix with P <

The next chapter is pretty technical and explains exactly how PCA does what we said it does. Nonetheless, above there should be all you really need to know to go on and produce a practical implementation of the PCA method. So you should be able to implement the PCA and understand it even if you skip chapter 2.

2. Technical Explanation

So that was the idea. Let’s try to make it more technical. Let’s say that the matrix (image) is A 时,这允许具有重要的计算优势。假设 A 是 m x p
那么,我们来定义矩阵 B:

我用这个工具制作的图像。

特征值分解如下:

我用这个工具制作的图像。

这些分解矩阵是:

  • V 是矩阵的特征向量的 p×p 正交矩阵。
  • ****λ是一个 p×p 的正方形对角矩阵。对角线上的条目是非负实数的特征值。

PCA 定义的矩阵如下:

我用这个工具制作的图像

它是在这 p 个标准正交特征向量上的投影。它的形状和原来的 m x p 一样。

如果使用所有的特征向量,可以使用下面的公式重建 A

我用这个工具制作的图像

这是因为特征向量是正交的。通常是前几个(按特征值降序排列)特征向量包含原始矩阵 A 的大部分整体信息。在这种情况下,我们可以只用少量的特征向量来重构矩阵 A 。例如我们可以用 k 个< < p 个特征向量。k 个向量按照方差值排序。使用它们,你可以有一个更小的矩阵、一个** _PCA 和一个模型(我们讨论过的矩阵乘法)来将其转换成原始大小的矩阵。**

3.实际实施

即使执行上述操作并不十分困难,也有一些非常实用的工具可以帮你完成并加速这个过程。伟大的 sklearn 可能是数据科学领域最著名的一个。这里是文档

让我们用一张免费下载的我的团队成员(❤):)的图片

照片由 Danilo ObradovicUnsplash 上拍摄

我们要做这些事情:

  1. ****对不同数量的组件应用PCA 方法

2.重建组件数量较少的图像

3.评估重建图像的质量,将其与原始图像进行比较

我们分析了 1。第二。工作细节,所以我们将花一些时间进行评估。

有许多方法来评估具有地面真实性的重建图像的质量。尽管如此,为了保持简单,让我们使用一个相当通用但有用的方法,即 归一化的 Frobenius 范数 的差。

我们用 4 种不同数量的成分: 0%33%66%100%

让我们绘制重建的图像:

我觉得这个很漂亮。第一次重建绝对是扯淡。当然,当我们增加组件的数量时,重建变得与原始图像相似。尽管如此,这意味着我们也在减少我们的计算优势,因为我们存储了更多的组件(减少的图像的维度增加)。

让我们绘制原始图像和重建图像之间的距离(Frobenius 范数),作为组件数量的变化:

如果我在专业或研究环境中使用它,我可能会使用更多的点来更好地拟合曲线,并了解最佳的组件数量。然而,我觉得这对于我们的目的来说已经足够了,因为表明当我们增加组件的数量时,重建变得更好,这是完全合理的。

4.结论

在某些情况下,降维是必须做的事情。当你必须对高维图像进行预处理时,看看你是否可以使用 PCA 来存储低维图像是一个很好的实践,并且让你这样做的代码非常简单。

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

再见:)

使用 Python 对天际线进行动手图像处理

原文:https://towardsdatascience.com/hands-on-image-processing-on-skylines-using-python-a73571ec7c7a

这里有一个关于使用 Python 在几行代码中描绘城市天际线的快速教程

照片由 Unsplash 上的穆扎米尔·苏尔马拍摄

让我陈述一个显而易见的事实:天际线很美。

我从小就梦想住在美国,其中一个原因是想住在纽约、芝加哥或旧金山美丽的天际线之间。

随着我的成长(并开始在美国生活),我确实意识到美国除了天际线之外还有很多东西,但我仍然非常喜欢它们。

在这篇文章中,我们将学习如何从图片中获取天际线轮廓。大概是这样的:

图片(1) :作者图片,数据来自此处(许可: CC0:公共领域)

让我们开始吧。🤩

0.这个想法

想法很简单。为了检测天际线,我们只需检测天空并拍摄互补图像。

在你之前看到的例子中,我们真正做的是识别天空。下一步当然是获取掩模图像并将其转换为信号,但正如我们将看到的那样,这相对容易。

那么,为什么探测天空比探测摩天大楼容易呢?
嗯,这个概念就是一张天空的图片是相对平的。另一方面,摩天大楼部分是颜色、形状、窗户、水泥和其他材料的混合体。

从数学上来说,我们希望天空的方差比摩天大楼的方差小,并且我们希望 T21 这个参数在区分天空和摩天大楼时是决定性的。

我想用一个例子来证明我所说的。让我们照这张照片。

图片(2) :作者图片,数据来自此处(许可: CC0:公共领域)

太好了。现在让我们在这个区域修剪这张图片:

图片(3) :作者图片,数据来自此处(许可: CC0:公共领域)

现在让我们取 0 和 50 之间的部分,并打印标准偏差:

图片(4) :作者图片,数据来自此处(许可: CC0:公共领域)

这种方差变化可以使用二阶导数来检测。当我们在讨论离散 2D 情形时,我们实际上在讨论拉普拉斯算子。如果我们使用所谓的 五点模板近似 ,可以证明拉普拉斯算子可以被视为卷积,这只不过是使用泰勒近似定义导数。

我太溺爱了。让我在下一节进入正题。

1.该算法

执行图(1)中所示操作的算法如下:

图片(5) :作者图片

我明白这是一个烂摊子。让我一步一步来解释。

1.1 将图像转换成 B&W

我知道你知道一切。但重要的是要说明我们为什么要这么做。如你所知,所有的模糊步骤和过滤在应用到一个矩阵时都是有意义的。彩色图像在技术上是一个张量,因为它有行数 X 列数 X 3 个通道值(红绿蓝)。一幅 B & W 图像实际上是一个由行数 X 列数组成的矩阵。

将此应用于彩色图像的一个简单方法是重复上述相同的过程三次,但我不认为这是必要的。最后,无论如何,即使使用 B&W 的图像,我们也能分辨出天际线。

1.2 模糊步骤

中值和归一化箱式滤波器步骤都是用于在保留边缘的同时过滤信号噪声的步骤。

1.3 拉普拉斯滤波器

这个项目的明星当然是拉普拉斯滤波器。该滤波器被认为是离散空间的二阶时间导数。

为什么我们首先需要二阶时间导数?

嗯,我们说过天空和摩天大楼的标准差是有区别的。这种标准差的变化发生在一个特定的点上,这个点就是一幅图像(以及摩天大楼)的边缘
所以我们想在图像中看到一个的快速变化。特别是,我们希望变化最大为。这意味着我们想要二阶时间导数为零的点(或点的邻居)。

当我们谈论一个离散的 2D 情况时,我们实际上是在谈论拉普拉斯算子。可以证明,如果我们使用所谓的https://en.wikipedia.org/wiki/Five-point_stencil五点模板近似,拉普拉斯算子可以被视为卷积,这不过是使用泰勒近似的导数的定义。****

二阶导数是这样的:

作者图片

这是一个我们将在图像上运行的内核,它将为我们提供二阶导数图像。

1.4 应用 1/0 阈值

我们不关心二阶导数是正还是负。我们关心的只是 0 的一小部分,因为我们认为这是边缘。这就是我们应用 1/0 阈值的原因。

1.5 腐蚀过滤器

腐蚀过滤器是我们用来平滑图像的东西。这背后的想法是,我们想使图像更清晰。用更专业的话来说,有一个内核会忽略图像,并用最小值替换这些值。同样,因为我们现在有 1/0 的图像,它只是让我们的图像更清晰。

1.6 将掩码设置为 0,直到找到最后一个索引

这一步解释起来有点复杂,但是很容易理解。当您完成所有这些操作后,您的图像列中可能会出现 0 和 1 的序列。这没有多大意义,因为你不可能拥有类似“摩天大楼-天空-又是摩天大楼”的东西。为此,我们在列中找到值为 0 的最大索引,并将所有内容设置为 0,直到找到该值。然后,其他都是 0。

2.动手实施

解释起来有点长,但是实现起来非常容易。让我们一步一步来:

2.1 导入库:

2.1 导入数据:

我从 Kaggle 那里得到了数据数据集是开源的,没有版权( CC0:公共领域)。特别是,我只下载了数据集的一部分,其中有 12 个城市的图像,每个城市有 10 座摩天大楼:

2.2 可视化数据

2.3 定义功能:

上述所有理论都是通过以下方式实现的:

2.4 应用算法

这是算法在整个数据集上的应用:

这是一个例子:

输入是原始图像(左)。我们“在意”的结果是中间那个。经处理的拉普拉斯滤波器的结果是正确的。很酷吧?🥰

2.5 将其转换为信号

为了得到正确的图像 图像(1) 我们应用以下函数:

我们可以将其应用于数据集的所有图像:

3.精神食粮!

我认为这项研究很有趣,原因有很多。首先,它很有趣,因为有两个理论上站得住脚的理由。

  • 它解释了如何使用拉普拉斯滤波器以非深度学习的方式应用边缘检测
  • 它解释了如何使用图像进行从头到脚的实验,以及如何创建一个正常工作的图像处理管道

然后,当然,它本身是有趣的,因为它给了你一个分析不同城市天际线的工具!
您可以看到城市 A 和城市 B 具有不同的轮廓,特别是使用提取的信号我们可以通过以下方式深化这项研究:

  • 提取天际线的平均值、中值和标准偏差
  • 使用深度学习对城市的天际线进行分类
  • 对天际线与时间进行统计研究(天际线如何随时间演变?)

请记住,这个项目背后的整个想法是天空的标准差低于摩天大楼的标准差。这种方法的问题可能是,如果天空中发生了一些奇怪的事情,或者天际线是奇怪的平坦。例如,有多朵云的非常分散的天空可能是一个问题。

例如,我们可以使用这种方法作为更复杂研究的起点,并且我们可以使用编码器-解码器来改进这些结果。

4.结论

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

用 spaCy 实现基本 NLP 技术的完整指南(第 4 部分)

原文:https://towardsdatascience.com/hands-on-implementation-of-basic-nlp-techniques-nltk-or-spacy-687099e02816

了解如何使用 Python 库实现基本的 NLP 技术

Unsplash 上的 Shubham Dhage 拍摄的照片

动机

自然语言处理(NLP)是一项非常有趣的技术,因为通过这项技术,计算机可以识别我们的自然语言,并像智能人一样做出反应。起初,当我开始了解 NLP 的魔力时,我感到非常惊讶。

【如果你想了解我的自然语言处理之旅以及自然语言处理的基础知识,我强烈推荐你阅读这篇文章——。]

我相信实践经验是学习一项技术的最好方法,只有理论知识是没有帮助的。苹果的 Siri,微软的 Cortana,谷歌的语音助手,亚马逊的 Alexa 等。,都在用 NLP。他们的作品多有趣啊!希望我们也能创造一些有趣的项目。

所以,是时候动手实践实现标记化、词汇化、词干化、停用词、词性标注等了。我们还将了解哪个 python 库最适合实际应用,以及原因。

让我们开始吧……

自然语言处理 ( NLP )是语言学、计算机科学和人工智能的一个分支,涉及计算机和人类语言之间的交互,特别是如何编写计算机程序来处理和分析大量自然语言数据[1]。

空间和 NLTK 概述

spaCy 和 NLTK 都是开源的自然语言处理库。

空间

spaCy 在 2015 年作为开源的 NLP 库首次进入聚光灯下。它可以有效地执行大多数 NLP 任务。spaCy 主要实现最常见的高效 NLP 技术来执行任务。没有选择特定算法来执行任务的选项。例如,有多种词干提取技术,您希望选择其中一种。不幸的是,空间没有给我们提供灵活性;相反,它会自动选择最常用的算法来执行任务。

**想了解更多 spaCy 的信息,请登陆spaCy【2】官网。

NLTK

NLTK 代表自然语言工具包,是最古老和最流行的自然语言处理库之一。它于 2001 年首次发布,这意味着它比 spaCy 早得多。它促进了许多 NLP 功能,但是效率较低。您可以在 NLTK 中选择不同的算法。

你可以从 这里*【3】获得 NLTK 的官方文档。*

nltk 和 spaCy 的对比分析

NLTK 和 spaCy 都是 NLP 的重要库。有些任务在 spaCy 中是高效的,有些在 NLTK 中是高效的。我们需要在不同的环境中使用这两个库,让我们来看一些比较。

spaCy 与其他 NLP 库的比较(图片由作者提供)

上图清楚地表明,在 标记化标记 的情况下,spaCy 分别比 NLTK 快 20 倍和 443 倍。

SpaCy,NLTK 提供的功能比较[4]

我们不能根据优势对图书馆进行分类;相反,在不同的情况下两者都需要。一般来说,在速度和实现方面,spaCy 比 NLTK 工作得更好,但是 NLTK 也是必需的。

在整篇文章中,我将向您展示 NLP 任务的基本实现,如标记化、词干化、词汇化、词性标注、文本匹配等。让我们用一些代码来弄脏我们的手。首先,我将展示如何为空间创造环境。

空间库的安装和设置

如果您使用 Anaconda,您必须将以下命令写入 Anaconda 命令提示符。

*conda install -c conda-forge spacy
or 
pip install -U spacy*

如果您在本地使用除 Anaconda 之外的库,您可以使用下面的命令。

*pip install -U spacy*

因为我们使用英语进行演示,所以我们需要下载英语的必要元素。在命令提示符下运行命令。

注意——您必须以管理员身份运行该命令或使用 *sudo*

*python -m spacy download en*

与空间合作

*import spacy
nlp = spacy.load('en_core_web_sm')*

当我们运行下面这段代码时,它将导入空间库并将模型加载到nlp。如果我们在文本上调用对象nlp,spaCy 将标记文本并保存到一个Doc对象。之后,Doc对象再次通过不同的步骤,这个过程被称为流水线。通常,管道包含标记器、语法分析器、解析器和命名实体识别器。下图清晰地描述了管道流程[5]。

空间管道的图形表示[5]

通过运行代码nlp.pipepline,我们可以找出管道的组件。有一些用于查找原始标记文本、词汇化、词性标注等的标记属性。在下表中,还有一些其他属性。

使用空间的标记化:

标记化技术将文本分割成小单元。我们来举个例子[6]。

*doc = nlp('"Let\'s go to N.Y.!"')
for token in doc:
    print(token.text)*

如果我们运行代码,我们会发现输出如下。

*"
Let
's
go
to
N.Y.
!
"*

doc对象包含文本的标记,属性.text保存原始文本。spaCy 非常聪明,因为它没有把N.Y.分开,也没有把‘s当作一个令牌。下图清楚地描述了标记化的过程。

来源:https://spacy.io/usage/linguistic-features

具有空间的命名实体

在一个句子中,一个单词或一组单词表示名称(例如,地名、人名、地区名、国家名、州名、货币值等)。命名实体的主要目的是识别它。命名实体可以通过Doc对象的ents属性访问。

代码的输出

*Google | 's | monthly | revenue | is | $ | 6 | million | 
______________________________________________________
Google - ORG - Companies, agencies, institutions, etc.
monthly - DATE - Absolute or relative dates or periods
$6 million - MONEY - Monetary values, including unit*

输出的第一行显示了句子的标记,其余的行显示了命名的实体以及适当的文档。通过使用.noun_chunks属性,我们将得到 基本名词短语

可视化命名实体

spaCy 有一个内置的可视化工具来可视化命名实体。为此,我们必须从spaCy库中导入displacy模块。以下代码显示了如下输出。

*from spacy import displacy
doc = nlp(u'Over last few years USA generates $6 million revenue.')
displacy.render(doc, style='ent', jupyter=True)*

输出

作者图片

可视化依赖关系

使用 spaCy ,我们还可以可视化一个句子的标记的依赖关系。出于演示目的,请遵循以下代码片段。

*from spacy import displacydocument = nlp(u'Bangladesh is a beautiful country')
displacy.render(document, style='dep', jupyter=True, options={'distance': 110})*

输出

标记的依赖性(作者的图像)

用 NLTK 做词干

词干化意味着切分单词/记号以找出它们的词根。但是它并不总是提供有意义的字符串。空间库没有词干分析器;相反,它完全依赖于词汇化。

波特梗器

波特词干分析器有自己的映射规则,根据这些规则,单词在不同阶段被切分。该算法使用五个阶段来缩减单词。首先,使用一些预定义的规则来删除后缀,这些规则在下面给出。

波特词干分析器的一般规则(图片由作者提供)

这里,S1 表示较长文本的后缀,S2 表示单词缩减后的缩减形式。一次只能应用一个规则。

波特词干分析器的复杂规则(图片由作者提供)

上述规则比第一个规则更复杂。m表示长度的度量。如果你想了解更多波特词干分析器算法,请访问 链接【7】。我们来举个编码的例子。

*import nltk
from nltk.stem.porter import *
p_stemmer = PorterStemmer()
words = ['run','runner','running','ran','runs','easily','fairly']
for word in words:
    print(word+' --> '+p_stemmer.stem(word))*

输出

*run --> run
runner --> runner
running --> run
ran --> ran
runs --> run
easily --> easili
fairly --> fairli*

雪球阻止器

词干分析器是 porter 词干分析器的改进版本,它在逻辑和速度方面比以前的词干算法提供了更好的结果。让我们用 NLTK 来实现。

*from nltk.stem.snowball import SnowballStemmers_stemmer = SnowballStemmer(language='english')
words = ['run','runner','running','ran','runs','easily','fairly']for word in words:
    print(word+' --> '+s_stemmer.stem(word))*

输出

*run --> run
runner --> runner
running --> run
ran --> ran
runs --> run
easily --> easili
fairly --> fair*

结果似乎略有改善。

词汇化和词性标注

词汇化不仅仅是像词干化一样减少或删减单词。词汇化的主要思想是找出主要的词根。请从 这里 把我之前的文章读出来,了解更多关于词汇化的知识。

上面的代码产生以下输出

*He           PRON   561228191312463089     -PRON-
is           VERB   10382539506755952630   be
a            DET    11901859001352538922   a
runner       NOUN   12640964157389618806   runner
running      VERB   12767647472892411841   run
in           ADP    3002984154512732771    in
a            DET    11901859001352538922   a
competition  NOUN   4661638505416061516    competition
because      ADP    16950148841647037698   because
he           PRON   561228191312463089     -PRON-
loves        VERB   3702023516439754181    love
to           PART   3791531372978436496    to
run          VERB   12767647472892411841   run
since        ADP    10066841407251338481   since
he           PRON   561228191312463089     -PRON-
ran          VERB   12767647472892411841   run
today        NOUN   11042482332948150395   today*

.pos_属性返回单词的词性,.lemma提供特定单词的哈希值,.lemma_给出单词的引理。如果我们观察令牌running, run, ran,,我们会发现它来自同一个引理run。这真是一份有趣又神奇的工作。

用空格停止单词

停用词在句子中出现得如此频繁,但对改变句子的意思并不重要。像 spaCy 库中的a, an, the, then, etc.,默认有 305 停用词。我们可以根据需要修改停用词列表。让我们举一个成文的例子。

*import spacy
nlp = spacy.load('en_core_web_sm')print(nlp.Defaults.stop_words)*

输出

*{'hers', 'show', 'though', 'various', 'sixty', 'say', 'quite', 'ten', 'anything', 'although', 'hereby', 'in', 'ours', 'herself', 'among', 'unless', 'and', 'whole', 'anywhere', 'latter', 'therein', 'whereafter', 'that', 'one', 'whose', 'either', 'within', 'eight', 'three', 'latterly', 'anyone', 'a', 'less', 'former', 'been', 'same', 'anyway', 'else', 'cannot', 'five', 'i', 'until', 'last', 'thus', 'give', 'move', 'thereafter', 'via', 'than', 'empty', 'off', 'neither', 'too', 'please', 'over', 'just', 'otherwise', 'has', 'her', 'put', 'its', 'whether', 'herein', 'myself', 'me', 'nevertheless', 'whatever', 'someone', 'towards', 'whereby', 'onto', 'sometimes', 'thence', 'them', 'done', 'at', 'back', 'nor', 'another', 'behind', 'together', 'take', 'amongst', 'being', 'seemed', 'seeming', 'fifteen', 'do', 'further', 'something', 'again', 'this', 'were', 'wherein', 'how', 'up', 'must', 'get', 'whereas', 'much', 'upon', 'yet', 'both', 'many', 'very', 'may', 'after', 'regarding', 'full', 'through', 'below', 'his', 'well', 'everything', 'so', 'our', 'should', 'seem', 'while', 'for', 'might', 'mine', 'when', 'with', 'you', 'few', 'never', 'because', 'own', 'also', 'due', 'hence', 'it', 'more', 'their', 'such', 'becomes', 'first', 'hereupon', 'since', 'third', 'twenty', 'who', 'she', 'nobody', 'name', 'really', 'enough', 'least', 'two', 'whoever', 'which', 'yours', 'moreover', 'seems', 'before', 'therefore', 'then', 'used', 'even', 'nowhere', 'without', 'other', 'around', 'made', 'hundred', 'no', 'twelve', 'several', 'your', 'meanwhile', 'per', 'except', 'yourselves', 'why', 'some', 'not', 'yourself', 'sometime', 'somehow', 'become', 'beyond', 'almost', 'will', 'somewhere', 'the', 'everyone', 'about', 'everywhere', 'anyhow', 'side', 'next', 'fifty', 'they', 'most', 'perhaps', 'across', 'themselves', 'besides', 'against', 'can', 'him', 'there', 'noone', 'under', 'formerly', 'already', 'all', 'if', 'my', 'or', 'serious', 'four', 'thereupon', 'whence', 'here', 'whither', 'beside', 'wherever', 'to', 'himself', 'between', 'ourselves', 'none', 'on', 'became', 'an', 'have', 'part', 'did', 'had', 'each', 'six', 'those', 'from', 'whenever', 'any', 'am', 'would', 'make', 'could', 'does', 'go', 'call', 'indeed', 'these', 'often', 'above', 'during', 'by', 'nine', 'thereby', 'others', 'afterwards', 'throughout', 'whom', 'amount', 'as', 'hereafter', 'top', 'mostly', 'us', 'whereupon', 'once', 'only', 'still', 'namely', 'forty', 'ca', 'along', 'be', 'itself', 'where', 'see', 'into', 'toward', 'but', 'is', 'keep', 'bottom', 'ever', 'becoming', 'every', 'always', 'front', 'nothing', 'we', 'of', 'out', 'eleven', 'alone', 'he', 'however', 'rather', 'down', 'thru', 'now', 'using', 'are', 'doing', 'what', 'beforehand', 're', 'was', 'elsewhere'}*

检查一个特定的令牌是否是一个停用词。

*nlp.vocab['myself'].is_stop*

它返回**True** ,因为默认的停用词列表包含单词‘myself’

*nlp.vocab['mystery'].is_stop*

代码返回False,因为默认的停用词列表不包含单词‘mystery’

在默认空间停用词表中添加和删除停用词

代码nlp.Defaults.stop_words.add(‘btw’)将字符串btw 添加到默认列表中,而nlp.Defaults.stop_words.remove(‘hers’)将单词hers从默认停用单词列表中移除。

使用空间创建匹配器

spaCy 提供了名为Matcher的基于规则的匹配工具,它允许我们设置规则或正则表达式来匹配一个 Doc 对象,并返回一个包含找到的匹配的列表。要了解更多信息,请访问 链接【7】。**

基于规则的匹配器

导入 *Matcher* 库并创建一个匹配器对象。

*from spacy.matcher import Matcher
matcher = Matcher(nlp.vocab)*

创建图案并将其添加到匹配器

*pattern_1 = [{'LOWER': 'solarpower'}]
pattern_2 = [{'LOWER': 'solar'}, {'LOWER': 'power'}]
pattern_3 = [{'LOWER': 'solar'}, {'IS_PUNCT': True}, {'LOWER': 'power'}]matcher.add('SolarPower', None, pattern1, pattern2, pattern3)*

上面这段代码包含三种模式。

  • pattern_1用小写solarpower表示任何匹配。
  • pattern_2 表示与相邻小写solarpower的任何匹配。
  • pattern_3 表示带有小写solarpower 以及它们之间的任何标点符号的任何匹配。

将匹配器应用于一个文档对象。

*document = nlp(u'The Solar Power industry continues to grow as demand \
for solarpower increases. Solar-power cars are gaining popularity.')found_matches = matcher(document)
print(found_matches)*

matcher返回元组列表。每个元组包含一个匹配的 ID,start & end 标记映射到 span doc[start:end].

➤为比赛找出课文。

*for match_id, start, end in found_matches:
    # get string representation
    string_id = nlp.vocab.strings[match_id]
    # get the matched span
    span = doc[start:end]       
    print(match_id, string_id, start, end, span.text)*

输出

*8656102463236116519 SolarPower 1 3 Solar Power
8656102463236116519 SolarPower 10 11 solarpower
8656102463236116519 SolarPower 13 16 Solar-power*

match_id就是string_ID‘太阳能’的哈希值。

短语匹配器

如果你想了解 PhraseMatcher,请访问链接**

结论

NLP 是现代计算中令人惊叹的技术之一,通过它,计算机可以识别我们的自然语言。有一些计算机处理自然语言的技术,因为人类和机器的学习过程是不同的。spaCy、NLTK 等不同的库使这个过程变得简单。不可能在一篇文章中包含所有必要的技术。因此,请关注即将发布的文章,了解更多令人惊叹的 NLP 实现技术和项目。你也可以读一下我写的关于 NLP 的文章。

***

参考

[1].https://en.wikipedia.org/wiki/Natural_language_processing

[2].Python 中的 spaCy 工业级自然语言处理

[3]. NLTK::自然语言工具包

[4].【https://spacy.io/usage/facts-figures

[5].https://spacy.io/usage/spacy-101#pipelines

[6].https://spacy.io/usage/linguistic-features

[7].https://spacy.io/usage/rule-based-matching

[8].https://spacy.io/usage/rule-based-matching#phrasematcher***

使用 Python 进行整数(二进制)线性优化

原文:https://towardsdatascience.com/hands-on-integer-binary-linear-optimization-using-python-b6d8160cb1de

用几行代码逐步介绍二元线性优化

乔恩·泰森在 Unsplash 上的照片

1.介绍

我们在日常生活中大量使用优化。有时候我们想都没想就做了。

假设你正在买杂货,你需要买刀片。当然,如果你买了 10000 片剃须刀片,你的银行里就没有钱了。尽管如此,如果你买了 4 个剃须刀片,你将需要在 4 天内再次购买剃须刀片(假设你每天都刮胡子),你将在汽油上花更多的钱,这是不明智的。所以我们通常做的是在心里解决一个最优化问题。

作者制作的图像

我们购买的数量介于两者之间:

  • 足够大,有足够数量的刀片,可以用一两个星期
  • 银行账户里还有足够的钱:)

作者制作的图像

现在,它是真正的最优值吗?大概不会。😃

你在超市里,有特定的价格,特定数量的剃须刀片。所以你只是在探索一个很小的选择范围。

此外,你没有使用任何数学模型。这意味着,即使这个模型实际上是最优的,你也无法证明它。这可不好。

当然,我们在谈论购买食品杂货,如果你告诉我,至少当你购买食品杂货时,你不想写任何代码或做任何数学计算,我相信你。尽管如此,在某些情况下,线性优化可能会变得很方便。

2.理论背景

在本文中,我们将讨论二元线性优化。让我们正确地定义这个问题:

  1. 二进制:这意味着我们试图回答的问题并不像“我应该买多少刀片?”,但更像是“我该不该采取这种策略?”。这意味着答案不会是 0 到无穷大之间的整数,而是可能是 0 或 1。
  2. 线性:这意味着解决方案是我们所有变量和一个成本/得分向量的线性组合。

作者图片

例如,在该等式中,成本(损失)函数是 x_i 值(也是 1 和 0)与由 c_i 值构成的成本向量之和,其中 I 在 1 和 N 之间(在这种情况下,我们需要做出 N 个二元决策)。

3。优化:意思是我们要找到我们上面表达的损失函数的最小值或者最大值。
换句话说,我们想要找到的最优解是这样的(最小化问题):

作者图片

或者类似这样的最大化问题:

作者图片

你可能已经注意到,在最小化和最大化问题中,我们已经定义了一个 X 集合。但这是什么呢?

想象一下,如果我告诉你,你的银行账户里有无限的钱。你会买多少刀片?我猜你会买下商店里所有的剃须刀片,因为你移动它们不会有任何问题(就像你有无限的钱去买世界上所有的汽车一样),你也不会有储存它们的问题(因为你有无限的钱去买世界上所有的房子。

现在,想象你是一个外星人,你根本不需要刮胡子。由于你是外星人,你的问题的解决方案将是花 0 块钱买 0 片剃须刀片。

当然,这简直是荒谬的。因为,当然,没有人有无限的钱,每个人在人生的某个阶段都需要刮胡子。这被正式称为你的问题的一个约束。约束是让你所有的优化模型变得棘手的东西。没有任何约束,答案永远是 0,+无穷大或-无穷大。

现在,我们为什么非要谈 二元线性优化呢?为什么一定要二进制?

嗯,事情是这样的:

作者图片

当它是连续的时候,线性问题是非常容易的。事实上,有一个非常著名的算法可以解决这类问题,它被命名为“ 单纯形算法 ”。如果域是连续的,并且损失函数是凸的,那么求解它也相对容易。如果损失函数甚至不是凸的,问题就很难解决。

从图中可以看出我们定义“的问题时,问题是整数。尽管如此,这并没有吓到我们!在实践中,再次使用单纯形算法,当函数至少是凸的时,我们很擅长解决这类问题。

坏消息 :我们的问题在技术上“很难”,但正如我们将看到的,它将在几分之一秒内得到解决。尽管如此,重要的是要考虑到,当决策变量和约束的数量增加时,我们可能无法得到一个经过验证的最优解。

好消息 :事实并非如此。:)我们的解决方案实际上将是最优的,因为它被认为是用于标准的线性整数优化问题

3.动手示例

正如我所承诺的,将会有一个例子。我拿了一个很有名的问题,那就是梦幻足球那个。我使用了不同的数据集,做了与你在网上找到的其他博客文章不同的事情。然而,你将在这篇文章中看到的东西的一个很好的替代品可以在这个 other(在我看来非常好)文章中找到。

我们将使用的数据集是公开的,每个人都可以下载和使用,可以在这里找到。

让我们通过观察来描述这个问题。首先,这是你需要的:

不外乎一些非常著名的库(numpy,pandas,matplotlib,seaborn,…)和 Pulp,这是我们将用于适当优化部分的库。

您可以像往常一样安装它,就像这样:

pip install pulp

到目前为止没有大的惊喜:)
让我们来看看数据集:

我们有不同的玩家,他们有不同的成本、位置、积分和一系列其他特征。

如果你玩梦幻足球,你的预算有限。这意味着所有参与者的成本之和不能超过某个值(例如 100,1000,2000)。尽管如此,当然,你希望你的最终团队拥有最高的。这也意味着,你希望所有玩家的分数总和尽可能的高。而且,你还得遵守以下规则(列在官方梦幻英超页面):

  • 5 名防守队员
  • 两名守门员
  • 5 名中场队员
  • 3 名前锋

让我们试着把它转换成一个数学模型:

  1. 我们的变量。我们有 628 行。这意味着我们有 628 个二进制变量(1/0)。如果我们选择了这个玩家,我们会得到 1,如果我们不选择这个玩家,我们会得到 0。因此,最终结果是由 628 个条目组成的向量 x :

作者图片

2。预算有限。每个玩家都有成本。这意味着我们将有一个成本列表,姑且称之为向量 c 。给定预算 B,预算约束如下。

作者图片

2。角色约束。我们需要挑选 5 名后卫,2 名守门员,3 名中场和 3 名前锋。假设我们有下面的向量:

作者图片

好的。这部分有点棘手。我们定义了 4 个不同的参与者子集(x1,x2,x3,x4)。第一个子集是后卫的子集,第二个是守门员的子集,第三个是中场的子集,第四个是前锋的子集。那么我们可以说:

作者图片

如果你不从事数学工作,或者你更像是一个软件工程师而不是数据科学家,这可能会很棘手,但这个想法非常简单。我们只是强加了我们正好有 5 个后卫,2 个守门员,…

3.得分功能。在我们的例子中,每个玩家都有一些分数。当然,我们希望最大化它。我们把这个点的矢量叫做 p 。因此,损失(得分)函数如下:

我们的最佳解决方案是:

其中 X 是服从我们讨论过的所有约束的域。

现在一切都有严格的定义。先说编码部分。

首先,让我们创建感兴趣的数据集:

画出玩家角色的分布图:

现在,让我们定义角色约束。

我们已经把它们储存在字典里了。
我们现在将以参数化的方式定义我们的模型。这意味着我们将得到更好的阵容,因为我们将允许我们球队的预算增加。😃

用这个函数我们将打印出实际最优团队给定的一定预算:

让我们探索三种场景:

  • 预算低。 B=80
  • 中间预算。B=100
  • 高预算。B=3000

从数学上来说,我们正在探索的领域越来越大。这意味着我们应该找到更好的解决方案(最大的积分总和)和更好的玩家。我们来看看是不是这样。

现在,有一堆属性被打印出来,但有一个是最重要的:

(B=80) Objective value: 1676
(B=100) Objective value: 2007
(B=3000) Objective value: 2266 

所以我们确实是对的。我们团队的点数随着预算变大而增加。不错:)

让我们打印结果:

B = 80 的最佳团队:

B = 100 的最佳团队:

B = 3000 的最佳团队:

有趣的是,当 B=3000 时,我几乎认识所有玩家,当 B=100 时,我认识一些玩家,而当 B=80 时,我几乎不认识任何玩家:)

现在,我们当然可以添加多个约束。也考虑将这种方法用于长凳。加入一些关于分数,受伤概率,球员被出售的概率的聪明考虑。

尽管如此,看到那几行代码(我不知道,也许 20 行?)可以解决,一个具有数百个变量的非常具有挑战性的问题。我不相信这可能是一个超级智能(实际上我确定它不是 T1),但它肯定在理论上是有趣的,而且对所有幻想的足球经理来说是有实际洞察力的:)

4.结论

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

面向数据科学家的 Github 操作实践介绍

原文:https://towardsdatascience.com/hands-on-introduction-to-github-actions-for-data-scientists-f422631c9ea7

Github 操作

了解如何通过权重和偏差、单元测试、工件创建等实现自动化实验跟踪…

安迪·赫尔曼万在 Unsplash 上的照片

为什么选择 Github Actions?

通俗地说,Github Actions 可以让您自动执行一些例行的和重复的任务——无论是在每次将代码部署到生产分支时测试代码,检查 PRs 上的良好编码实践,跨浏览器代码测试,单元测试,从 MLFlow / WandB 跟踪中检索运行,自动关闭陈旧问题,等等。这个清单真的是无穷无尽的。

虽然你当然可以自己从头开始编写所有这些 Github 动作,但我建议不要重新发明轮子。相反,为您的特定用例搜索可用操作的好地方是市场。让我们看看如何在行动中使用它们。

https://github.com/V-Sher/Github-Actions-PlayGround

注意:尽管运行随心所欲的操作可能很诱人,但私人回购每月只有有限的免费分钟数(约 2000 分钟)和存储空间(约 500MB)(分钟数每月重置,但存储空间不会)。然而,公开回购对 Github 操作的使用没有这样的限制。更多关于计费的细节可以在 这里找到

让我们开始吧…

首先,我们需要在 repo 中创建.github/workflows目录,并在其中创建一个新的.yml文件。一个典型的.yml文件如下所示:

name: Github Actions Demo
on:
  issues:
    types: [opened, edited, deleted] 
jobs:
  Job1:
    runs-on: ubuntu-latest     
    steps:
      - name: "This is Step 1 with bash command."
        run: echo "hello World"
        shell: bash
      - name: "This is step 2 using marketplace action."
        uses: actions/checkout@v3
  Job2:
    ..... Job3:
    .....

需要考虑的事情很少:

  • 我们需要为工作流定义一个name以及何时该工作流应该运行。前者可以是您喜欢的任何东西,后者需要使用on来指定。例如,我们可能希望仅在打开问题、关闭问题、评论 PR、创建和编辑标签时运行工作流。查看可以触发工作流的事件的完整列表。在我们的示例中,每当有人打开、编辑和/或删除问题时,就会触发该事件。
  • 这里我们定义了三个作业(job1job2job3),但实际上,您可以在单个.yml文件中定义任意数量的作业,当on中定义的事件被触发时,它们将同时运行(对此有变通办法,可以延迟运行job2,直到job1完成)。
  • 我们可以选择使用runs-on定义一个服务器来运行您的工作流。稳定的选择包括ubuntu-latestmacos-latestwindows-latest
    注意:注意选择,因为一些 Github 托管的跑步者比其他人消耗更多的时间。从文档来看,运行在 Windows 和 macOS 上的 作业消耗的时间是运行在 Linux 上的 作业的 2 到 10 倍。
  • 作业中的步骤是按顺序运行的。一定要给一个步骤起一个有意义的名字,因为这有助于以后的调试。
  • 作业中的步骤可以做两件事之一——(a)使用run(例如,echo "hello World")运行 bash 命令,或者(b)使用uses使用 marketplace 或第三方 Github 动作(例如,[actions/checkout@v3](https://github.com/actions/checkout)——这是一个流行的动作,可以帮助您签出一个 repo 并使用其中的任何文件作为工作流的一部分——我们将在本教程的后面介绍它)。

动手示例

我们有一个名为Dump event payload的工作流,其中包含一个名为Comment的作业,每次打开、编辑或删除一个问题时都会触发这个作业。

在解释发生了什么之前,让我们通过创建一个新问题来看看它是如何工作的。

接下来,转到动作选项卡,您会看到一个黄色圆点,表示工作流程正在运行。一旦完成,它将变成绿色。

完成后,点击它来查看状态、总持续时间和创建的工件(我们将在教程的后面介绍工件)。

最后,进入Comment作业,我们应该能够看到我们在工作流中定义的所有步骤的输出。

让我们来分解一下工作流程中发生了什么。

它包含一个将转储整个 Github 事件有效负载的步骤。我总是发现将github.event上下文中所有可用的内容转储到终端以查看触发工作流运行的事件的信息非常有用。这通常会返回一个嵌套的字典,我们将使用toJSON()打印出来。

注意:您还可以检查其他上下文,如触发工作流运行的分支名称的 *github.ref* ,回购名称的 *github.repository* 等。完整的名单可以在 这里找到

如上图所示,返回的上下文包含关于操作的信息(即opened)、关于问题本身的信息,例如,创建时间、问题正文、评论数量等。

注意: *github.event* 中的信息将取决于触发工作流的事件类型。例如, *github.event* 的内容会根据问题是否打开而变化,而不是推送到 *main* 分支。

现在我们已经知道了所有的上下文信息,我们可以在工作流中添加一个新的步骤 2,这个步骤将把这些信息的一部分echo到标准输出中。特别是,我们将比较由github.event记录的动作是否是一个问题-编辑事件,而不是一个问题-打开事件。

为了查看实际效果,我们将创建一个新问题,转到 Actions 选项卡,并检查输出。正如所料,它输出一个布尔值 0,表示为False

到目前为止,我们只添加了运行 bash 命令来打印标准输出的步骤。如前所述,通过使用uses而不是run,我们还可以在一个步骤中使用来自 Github marketplace 的动作。为了演示这一点,我们将使用 Peter Evan 的Create-or-Update-Comment操作来创建一个自动感谢新问题创建者的评论。Readme 中解释了它的用法,并且非常简单——我们必须提供需要进行评论的问题编号,以及消息的实际正文。幸运的是,我们可以将前者作为github.event.issue上下文的一部分,后者可以是您想要的任何内容。

让我们添加步骤 3 来实现这一点。我们将添加一个if子句,以确保只有当问题是opened(而不是editeddeleted)时才运行该步骤。

为了测试这一点,创建一个新的问题,您应该会看到下面的 bot 消息。

注意:在下面的完整示例中,我还添加了一些额外的步骤,用于根据问题是已编辑还是已打开来定制消息。

完整示例:

这是我日常使用的三个主要 Github 操作的入门知识。

用例 1:在一个分支上运行测试push

每当我们将提交推送到一个分支时,我们倾向于使用pytest运行一些单元测试,以确保过程中没有任何中断。

为了模拟这个过程,让我们假设我们现在正在处理一个新的 [hello-world](https://github.com/V-Sher/Github-Actions-PlayGround/tree/hello-world) 分支,它增加了三个新的内容——两个目录(srctests以及一个requirements.txt文件)。目录结构如下所示:

[Github-Actions-PlayGround](https://github.com/V-Sher/Github-Actions-PlayGround)
│   README.md
│   requirements.txt    
└───src
│   │   utils.py
└───tests
    │   test_example.py

utils.py(左侧)和test_example.py(右侧)的内容如下:

左边:utils.py; On right test_example.py

最后,我们准备在hello-world分支上的.github/worklfows/unit_test.yml中创建一个工作流,该工作流将在提交到分支的任何时候运行tests目录中的测试(目前,我们在tests/test_example.py中只定义了一个测试,但您已经明白了)。

为了让工作流成功运行,我们需要确保在运行测试之前,我们应该定义在运行环境中安装requirements.txt文件的步骤(参见下面的步骤 2)并将目录添加到PYTHONPATH,如果有的话(参见下面的步骤 3)。
(附:如果你还在疑惑我是否/如何/为什么需要一个 *pythonpath* ,看看 这篇 的文章吧。)

需要考虑的事情很少:

  • 如果我们在一个步骤中运行多个 bash 命令,我们使用管道符号(|)。例如,请参见步骤 2。
    P.S .其他步骤我加了 *|* 只是为了简洁。
  • 在步骤 3 中,我们可以简单地执行以下操作来设置正确的PYTHONPATH
- name: "Step3: Add ./src to PYTHONPATH"
  id: first_update_step
  run: PYTHONPATH=$GITHUB_WORKSPACE/src

因为我想证明我们确实正确地设置了 pythonpath,所以在步骤 3 中我们将输出echo$GITHUB_ENV——稍后在步骤 4 中使用env.PYTHONPATH检索。

  • 如前所述,一个步骤可以是您通常可以在终端中运行的任何 bash 命令,在最后一步,即步骤 5 中,我们使用pytest命令运行单元测试。

现在有趣的部分来了——看到我们的工作流程在运行。用这个新的分支hello-world创建一个公共关系,并尝试向它提交一个新的承诺。在每次推送时,您会看到检查自动开始,由一个黄色标记表示(见左图)。一旦完成,它们将变成绿色(见右图)。

用例#2:在一个拉取请求下,显示从 WandB 运行的注释

对任何数据科学家来说,修改超参数都是模型训练的一部分。通常实施某种实验跟踪(如 MLFlow 或 Weights & Biases(或wandb))来跟踪每个不同超参数组合的结果。

因为重要的决策(比如是否合并分支并在生产中使用模型)必须基于这些来制定,所以我们获取这些运行并将其作为拉请求的一部分进行文档化是很重要的。这有助于提高代码审查过程中的透明度和责任性,因为每个人都可以看到模型的性能。

为此,[machine-learning-apps/wandb-action](https://github.com/marketplace/actions/get-runs-from-weights-biases) marketplace action 提供了一个简单易用的解决方案。让我们看看如何通过在main分支中创建一个新的工作流.github/workflows/wandb_runs.yml来获取一个虚拟运行(从所有记录的wandb运行中获取,这里是)。我们将一步一步地构建它。

注意:我记录的模拟运行是一个涉及拥抱脸变形金刚项目的一部分。如果您想了解如何使用 Wandb 和记录跑步,请查看 这个 快速演示🤗变形金刚只是多了 2 行代码。即使您没有使用 Huggingface,* *wandb* 也将为您工作,因为它是框架不可知的——这意味着它可以记录使用 Pytorch、Tensorflow、Scikit Learn、Keras 等训练的模型。具体框架查看他们的教程 这里 *

检测触发短语

首先,我们需要一个触发词/短语,当它出现在 PR 注释的主体中时,指示工作流获取一个wandb运行。除了这个触发字,我们还必须传递我们想要获取的运行的 id。我们将使用名为[machine-learning-apps/actions-chatops](https://github.com/machine-learning-apps/actions-chatops)的市场行动来达到同样的目的。

要使用这个动作,我们只需要使用with定义一个TRIGGER_PHRASE。它可以是任何字符串,但在我们的例子中是/get-runs

注意:您会注意到该操作还需要使用 *env* 设置一个名为 *GITHUB_TOKEN* 的环境变量,但是,GitHub 会自动创建一个唯一的 *GITHUB_TOKEN* 秘密以在您的工作流中使用——这意味着您不需要做任何事情!你可以在这里阅读更多关于https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret

因为我想检查该步骤返回的所有内容,所以我将用它指定一个id。现在,我们可以使用这个带点符号的id(例如,steps.chatops)将所有内容转储到第 3 步中使用的toJSON()的标准输出中。

要查看工作流,创建一个新的 PR,希望将推送到hello-world分支的提交与main分支合并。接下来,用触发词和运行 id 在 PR 下添加新注释(见下图):

用 Github 动作检测触发字

注:您可以在 *wandb* 工作区的 *run.id* 栏中找到运行 id。

现在,让我们转到 Actions 选项卡,看看步骤 3 返回了什么。

不出所料,我们得到了一些有用的信息,比如分支机构名称和评论者姓名。此外,与触发字一起传递的运行 id 存储在TRAILING_TOKEN下。至此,我们已经准备好进入步骤 4,该步骤将使用machine-learning-apps/wandb-action获取运行结果。

在步骤 4 中,我们遵循官方文档中的指南,并使用with条款提供一些强制输入。

  • PROJECT_NAME是与您的wandb项目相关联的实体/项目名称。在上面的代码片段中,entityvsherprojectGithubActionsDemo
  • 从上一步转储的数据中,我们知道可以使用steps.chatops.outputs.TRAILING_TOKEN提取RUN_ID
  • 除了由RUN_ID指定的运行,我还想获取我在重量和偏差工作区中手动标记为baselinereference的运行。这可以使用BASELINE_TAGS来完成。
  • 还定义了一些指标(DISPLAY_METRICS)和配置变量(DISPLAY_CONFIG_VARS)。确保您在这里传递的列名也作为wandb日志记录的一部分被记录,并且没有任何打字错误。
  • 我们需要提供的最后一个输入是WANDB_API_KEY。一旦你登录到你的wandb账户,你会在这里找到你的 API 密匙:https://wandb.ai/authorize复制它,然后前往 Github Settings - > Secrets(在左侧窗格)- > Actions,创建一个新的库秘密,名称为WANDB_API_KEY,值为您刚刚复制的密钥!

创建 Github 操作秘密

最后,我们将使用toJSON(steps.wandb)转储该步骤的全部输出。要查看实际情况,请向 PR 提交一个 commit,然后前往 Actions 选项卡进行检查。

输出是不言自明的,但是,您可以在这里检查每个字典键的含义。更重要的是,我们可以使用点符号引用这些输出,例如steps.wandb.outputs.BOOL_COMPLETEsteps.wandb.outputs.outcome

创建工件

现在你可能会想,所有这些步骤都很好,但是实际的运行应该在哪里被获取并显示在 PR 评论中!

通读文档,要记住的一件事是machine-learning-apps/wandb-action不在 PR 注释中显示运行,而是将一个名为wandb_report.csv的 csv 文件(包含提取的运行)保存到默认工作目录指定的路径中。由于我们已经在工作流的步骤 1 中使用actions/checkout@v3检查了回购,我们的 csv 文件将在home/runner/work/Github-Actions-PlayGround/Github-Actions-PlayGround中创建。

为了验证这一点,我们将添加一个新步骤,使用 操作/upload-artifact 操作从我们的工作流中上传这个 csv 工件。

要看到这一点,将一个新的 commit 推送到 PR 分支,然后转到 Actions 选项卡。您将在屏幕底部的工件选项卡下看到一个新创建的 wandb_report 。请随意下载并检查它的内容。

通过 Github 操作创建的工件

在公共关系评论中显示 wandb 运行

现在进入工作流中最激动人心的一步——在拉请求中将这个 csv 显示为 markdown 格式的注释。我们将使用标准的 Github REST API 来创建注释

注意:简单介绍一下 API 的工作原理。利用 python 的 *requests* 模块,我们制作一个的 API 调用到 URL : *https://api.github.com/repos/{repo-name}/issues/{pr_num}/comments* ,其中 *repo-name* *pr_num* 需要显式传递。post 请求的 主体 是反映评论内容的简单字符串。**

***# REST API Example: Add a simple comment to PR*import requestsurl = f"https://api.github.com/repos/{repo-name}/issues/{pr_num}/comments"
data = {"body": "Making a new comment using API"}
result = requests.post(url=url, headers=headers, json=data)**

API 示例排序后,我们将在一个名为[wandb_results.py](https://github.com/V-Sher/Github-Actions-PlayGround/blob/main/action_files/wandb_results.py)的新文件中实现类似的功能,我们将在工作流中运行该文件。python 脚本包含上述的requests.post()方法,以及应用于 csv 文件的一些数据帧重新格式化(在作为消息体传递之前)。

注:我要承认 *wandb_results.py* 很大程度上是基于代码可用 这里

您会注意到,在[wandb_results.py](https://github.com/V-Sher/Github-Actions-PlayGround/blob/main/action_files/wandb_results.py)的最开始,我们使用了三个环境变量。前者,即GITHUB_REPOSITORY对运行工作流的服务器自动可用。后两个— GITHUB_TOKENPR_NUM —需要在工作流步骤中设置(参见下面的第 42–43 行)。

最终揭示

要查看我们的完整工作流程,请前往公关部门,做一个类似于/get-runs <run-id>的新评论。几分钟后,您应该会看到机器人显示提取的运行。

用例 3:在多个 python 版本上测试脚本

在不涉及太多细节的情况下,我将快速介绍 Github 动作的另一个用例。动作/设置——python允许你在多个版本上测试你的 python 脚本。参见下面的示例用法。

**jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['2.x', '3.x']
    name: Python ${{ matrix.python-version }} sample
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
          architecture: x64
      - run: python my_script.py**

结论

到现在为止,您已经对 GitHub Actions 的许多奇迹有了更深的理解和深刻的欣赏。希望到现在为止,您也应该能够使用相关文档自己实现它们。作为一名数据科学家,如果您在日常工作中遇到其他有用的节省时间的行动,请告诉我!

一如既往,如果有更简单的方法来做/解释本文中提到的一些事情,一定要让我知道。一般来说,避免不请自来的破坏性/垃圾/敌意评论!

直到下一次✨

注:除特别注明外,所有图片均为作者所有。

我喜欢写循序渐进的初学者指南、操作指南、面试问题、ML/AI 中使用的解码术语等。如果你想完全访问我的所有文章(和其他媒体上的文章),那么你可以注册使用 我的链接这里* ***

** **

Python 强化学习实践介绍

原文:https://towardsdatascience.com/hands-on-introduction-to-reinforcement-learning-in-python-da07f7aaca88

通过教机器人走迷宫来理解奖励

照片由布雷特·乔丹Unsplash 拍摄

传统机器学习的最大障碍之一是,大多数有监督和无监督的机器学习算法需要大量数据才能在现实世界的用例中有用。即使这样,如果没有人类的监督和反馈,人工智能也无法学习。如果人工智能可以从头开始学习会怎样?

作为最著名的例子之一,谷歌的 DeepMind 构建了 AlphaGo ,它能够击败历史上最好的围棋选手 Lee Sedol。为了学习最佳策略,它使用了深度学习和强化学习的结合——就像在,通过与自己对弈成千上万的围棋游戏。李·塞多尔甚至说,

我认为 AlphaGo 是基于概率计算的,它只是一台机器。但是当我看到这个举动的时候,我改变了主意。毫无疑问,AlphaGo 很有创造力。

强化学习消除了对大量数据的需要,并且还优化了它可能在广泛的环境中接收的高度变化的数据。它密切模拟了人类的学习方式(甚至可以像人类一样找到非常令人惊讶的策略)。

更简单地说,强化学习算法由代理和环境组成。代理为环境的每个状态计算一些奖励或惩罚的概率。这个循环是这样工作的:给一个代理一个状态,代理向环境发送一个动作,环境发送一个状态和回报。

让我们试着编码一个机器人,它将试着在尽可能少的移动中通过一个 6×6 的迷宫。首先,让我们从创建代理和环境类开始。

环境和代理

我们希望我们的代理能够根据以前的一些经验来决定做什么。它需要能够基于一组给定的操作做出决策并执行一些操作。避免拟人化的定义代理是什么,以更严格地定义你的代理将有什么样的方法和功能——在强化学习中,代理不能控制的任何东西都是环境的一部分。

环境是代理可以与之交互的代理之外的任何事物,包括系统的状态。它不一定是您想象的完整环境,只要包括当代理做出选择时真正改变的东西。环境还包括你用来计算奖励的算法。

在名为environment.py的文件中,创建这个类:

import numpy as npACTIONS = {'U': (-1, 0), 'D': (1, 0), 'L': (0, -1), 'R': (0, 1)}class Maze(object):
    def __init__(self):
        # start with defining your maze
        self.maze = np.zeroes((6, 6))
        self.maze[0, 0] = 2
        self.maze[5, :5] = 1
        self.maze[:4, 5] = 1
        self.maze[2, 2:] = 1
        self.maze[3, 2] = 1 self.robot_position = (0, 0) # current robot position
        self.steps = 0 # contains num steps robot took self.allowed_states = None # for now, this is none
        self.construct_allowed_states() # not implemented yet

根据我们编写的代码,下面是我们的迷宫的样子(在我们的代码中,1 代表墙壁,2 代表机器人的位置):

R 0 0 0 0 X
0 0 0 0 0 X
0 0 X X X X
0 0 X 0 0 X
0 0 0 0 0 0 
X X X X X 0 <- here's the end

这是我们需要存储在环境中的核心信息。根据这些信息,我们可以在以后创建函数来更新给定动作的机器人位置,给予奖励,甚至打印迷宫的当前状态。

您可能还注意到,我们添加了一个allowed_states变量,并在其后调用了一个construct_allowed_states()函数。allowed_states将很快拥有一本字典,将机器人所处的每一个可能的位置映射到机器人可以从那个位置到达的可能位置的列表。construct_allowed_states()将构建此地图。

我们还创建了一个名为ACTIONS的全局变量,它实际上只是一个可能的移动及其相关翻译的列表(我们甚至可以省略方向标签,但它们是为了便于阅读和代码调试)。我们将在构建允许的州地图时使用它。为此,让我们添加以下方法:

def is_allowed_move(self, state, action):
    y, x = state
    y += ACTIONS[action][0]
    x += ACTIONS[action][1] # moving off the board
    if y < 0 or x < 0 or y > 5 or x > 5:
         return False # moving into start position or empty space
    if self.maze[y, x] == 0 or self.maze[y, x] == 2:
        return True
    else:
        return Falsedef construct_allowed_states(self):
    allowed_states = {}
    for y, row in enumerate(self.maze):
        for x, col in enumerate(row):
            # iterate through all valid spaces
            if self.maze[(y,x)] != 1:
                allowed_states[(y,x)] = []
                for action in ACTIONS:
                    if self.is_allowed_move((y, x), action):
                        allowed_states[(y,x)].append(action) self.allowed_states = allowed_statesdef update_maze(self, action):
    y, x = self.robot_position
    self.maze[y, x] = 0 # set the current position to empty
    y += ACTIONS[action][0]
    x += ACTIONS[action][1]
    self.robot_position = (y, x)
    self.maze[y, x] = 2
    self.steps += 1

这允许我们在迷宫实例化时快速生成状态到允许动作的地图,然后在机器人每次移动时更新状态。

我们还应该在环境中创建一种方法来检查机器人是否在迷宫的尽头:

def is_game_over(self):
    if self.robot_position == (5, 5):
        return True
    return False

现在我们准备为我们的代理开始上课。在名为agent.py的文件中,创建一个新类:

import numpy as npACTIONS = {'U': (-1, 0), 'D': (1, 0), 'L': (0, -1), 'R': (0, 1)}class Agent(object):
    def __init__(self, states, alpha=0.15, random_factor=0.2):
        self.state_history = [((0, 0), 0)] # state, reward
        self.alpha = alpha
        self.random_factor = random_factor

        # start the rewards table
        self.G = {}
        self.init_reward(states)

现在,很多内容看起来都不太熟悉,但这是一个介绍奖励算法的好时机,我们将使用该算法来培训我们的代理。

奖励

所有代理人的目标都是回报最大化。就像任何机器学习算法一样,奖励将采取数字的形式,根据某种算法而变化。代理将尝试估计其每个行动选择的损失,然后采取行动,然后从环境中获得行动的真实回报,然后调整其对该特定行动的未来预测。

我们将为我们的环境提出一个非常简单的奖励政策:机器人每走一步,我们罚-1 分(因为我们想要最快的解决方案,而不是任何解决方案),然后当机器人到达终点时,奖励 0 分。因此,采取 20 个步骤的解决方案将奖励代理总共-20 分,而采取 10 个步骤的解决方案将奖励代理-10 分。我们奖励政策的关键是保持简单——我们不想过度监管我们的代理。

现在让我们将它编码到我们的环境中。将这些方法添加到您的Maze类中:

def give_reward(self):
    if self.robot_position == (5, 5):
        return 0
    else:
        return -1def get_state_and_reward(self):
    return self.robot_position, self.give_reward()

就是这样!

好吧,但是有一个问题——代理人怎么可能预测每一次行动会得到的回报?

情节剧

这里的目标是创建一个函数,在一集(在我们的例子中,一集是一场游戏)为每个州的预期未来奖励建模。这些奖励随着代理经历更多的情节或游戏而不断调整,直到它收敛于环境给定的每个状态的“真实”奖励。例如,我们可能有这样一个状态表:

+--------+-----------------+
| State  | Expected Reward |
+--------+-----------------+
| (0, 0) | -9              |
| (1, 0) | -8              |
| ...    | ...             |
| (X, Y) | G               |
+--------+-----------------+

其中 G 是一个状态(X,Y)的给定期望报酬。但是我们的机器人将从一个随机化的状态表开始,因为它实际上还不知道任何给定状态的预期回报,并将试图收敛到每个状态的 G。

我们的学习公式是*G_state = G_state +* α(target — *G_state*) 。在实践中,在一集结束时,机器人已经记住了它所有的状态和相应的奖励。它也知道自己当前的 G 表。使用这个公式,机器人将根据这个简单的公式更新 G 表中的每一行。

我们来分解一下。我们实际上是在给定状态下,增加了实际奖励(目标)和我们最初预期奖励之间的差额百分比。你可以把这个差额想象成损失。这个百分比被称为 alpha 或α,熟悉传统机器学习模型的人会将其视为学习率。百分比越大,它可能越快地向目标回报靠拢,但是它越有可能超过或高估真正的目标。对于我们的代理,我们将默认学习率设置为 0.15。

实现成功的奖励算法有多种方式,这都取决于环境及其复杂性。例如,AlphaGo 使用深度 q 学习,这种学习实现了神经网络,可以根据过去有益举动的随机样本来帮助预测预期回报。

让我们编码我们的算法。首先,我们需要一个函数来初始化我们的Agent类中的随机状态表,这个函数在代理初始化时被调用:

def init_reward(self, states):
    for i, row in enumerate(states):
        for j, col in enumerate(row):
            self.G[(j,i)] = np.random.uniform(high=1.0, low=0.1)

我们将 G 的随机值初始化为总是大于 0.1,因为我们不希望它将任何状态初始化为 0,因为这是我们的目标(如果一个状态最终从 0 开始,代理将永远不会从该状态中学习)。

其次,我们需要一种方法,允许代理在一集结束时“学习”G 的新值,给定该集的状态和奖励对(由环境给定)。将这个添加到Agent类中:

def update_state_history(self, state, reward):
    self.state_history.append((state, reward))def learn(self):
    target = 0 # we know the "ideal" reward
    a = self.alpha for state, reward in reversed(self.state_history):
        self.G[state] = self.G[state]+ a * (target - self.G[state]) self.state_history = [] # reset the state_history
    self.random_factor = -= 10e-5 # decrease random_factor

你会注意到我们在最后也把random_factor缩小了一点。我们来谈谈那是什么。

探索与利用

现在,代理人可以总是采取它认为会导致最大回报的行动。然而,如果一个行动,代理人估计会有最低的回报,最终却有最高的回报呢?如果一个特定行为的回报随着时间的推移会有回报呢?作为人类,我们能够估计长期回报(“如果我今天不买这部新手机,我就能在未来攒钱买车”)。我们如何为我们的代理复制这一点?

这就是通常所说的探索与利用的困境。一个总是利用(比如,总是采取它预测会有最高回报的行动)的代理人可能永远不会找到解决问题的更好的办法。然而,一个总是探索的代理(总是随机选择一个选项来看它通向哪里)将会花很长时间来优化自己。因此,大多数奖励算法将结合使用探索和利用。这是我们的Agent课程中的random_factor超参数——在学习过程的开始,代理将探索 20%的时间。随着时间的推移,我们可能会减少这个数字,因为随着代理的学习,它可以更好地优化利用,我们可以更快地收敛到一个解决方案。在更复杂的环境中,您可以选择保持相当高的探索率。

现在我们知道了我们的机器人会如何选择一个动作,让我们把它编码到我们的Agent类中。

def choose_action(self, state, allowed_moves):
    next_move = None n = np.random.random()
    if n < self.random_factor:
        next_move = np.random.choice(allowed_moves)
    else:
        maxG = -10e15 # some really small random number
        for action in allowed_moves:
            new_state = tuple)[sum(x) for x in zip(state, ACTIONS[action])])
            if self.G[new_state] >= maxG:
                next_move = action
                maxG = self.G[new_state] return next_move

首先,我们根据我们的random_factor 概率随机选择探索或利用。如果我们选择探索,我们从给定的允许移动列表中随机选择我们的下一步移动(传递给函数)。如果我们选择利用,我们循环遍历可能的状态(给定 allowed_moves 列表),然后从 G 中找到期望值最大的一个。

完美!我们已经完成了代理和环境的代码,但是我们所做的只是创建类。我们还没有检查每一集的工作流程,也没有让代理人学习的方式和时间。

把所有的放在一起

在我们代码的开始,在创建了我们的代理和迷宫之后,我们需要随机初始化 G 。对于我们想玩的每一个游戏,我们的代理应该从环境中获得当前的状态奖励对(记住,除了最后一个方块,每个方块都是-1,应该返回 0),然后用它选择的动作更新环境。它将从环境中接收一个新的状态-奖励对,并在选择下一个动作之前记住更新的状态和奖励。

在一集结束后(迷宫无论走了多少步都完成了),代理应该查看该游戏的状态历史,并使用我们的学习算法更新其 G 表。让我们用伪代码描述一下我们需要做什么:

Initialize G randomly
Repeat for number of episodes
 While game is not over
  Get state and reward from env
  Select action
  Update env
  Get updated state and reward
  Store new state and reward in memory
 Replay memory of previous episode to update G

您可以在以下要点中看到这一点的完整实现:

在这段代码中,我们要求代理玩游戏 5000 次。我还添加了一些代码来绘制机器人在 5000 次游戏中每次完成迷宫所需的步数。尝试以不同的学习速率或随机因素运行代码几次,比较机器人收敛到 10 步解决迷宫需要多长时间。

另一个挑战是尝试打印出机器人完成迷宫的步骤。在Maze类中的方法print_maze()中有一些起始代码(下面显示了完整的类),但是您需要添加代码,从代理接收 state_history 并在打印函数中格式化它,比方说,作为 R,用于每一步。这将允许您查看机器人最终决定的步骤-这可能很有趣,因为在我们的迷宫中有多条十步的路线。

环境和代理的完整代码如下。

我要感谢菲尔·泰伯的精彩课程《动态强化学习》。

Neha Desaraju 是德克萨斯大学奥斯丁分校学习计算机科学的学生。你可以在网上estau dere . github . io找到她。

在 Python 中使用 causallib 进行实际操作的反向倾向加权

原文:https://towardsdatascience.com/hands-on-inverse-propensity-weighting-in-python-with-causallib-14505ebdc109

因果推理世界的介绍,并附有一个用最流行的方法回答因果问题的实例

照片由 Unsplash 上的 Piret Ilver 拍摄

因果问题

理解一个行为对观察到的结果的影响对于许多领域都是重要的。例如,戒烟如何影响体重增加。这类问题似乎很容易回答:只要看一个已经戒烟的人,将他们的平均体重变化与没有戒烟的人进行比较(也称为未调整估计)。假设戒烟者的平均体重增加了 3 公斤,而未戒烟者的平均体重增加了 1 公斤。那么我们可以得出结论,戒烟会导致体重增加。然而,这个结论将是非常错误的,因为这些群体不一定具有可比性。可能有混淆的因素导致了这一点。例如,戒烟者可能会感到食欲增加,因此体重增加更多。

作者图片

估计因果效应的“黄金标准”是进行随机对照试验。这意味着我们招募人员,并通过例如抛硬币的方式将他们随机分配到暴露组。这在我们的例子中是行不通的,因为我最后一次检查时,告诉人们开始/戒烟,然后检查他们 10 年内的体重是不道德和不合时宜的😁(布雷迪·尼尔有很好的例子来介绍因果关系)。

让我们从数学上来看这个(我保证前面没有吓人的方程!).在因果关系领域,符号 Y(a)是某个人接受治疗的潜在结果,意味着如果他们接受治疗,会发生什么。因此,群体的平均治疗效果(最常见的是两个潜在结果之间的预期差异):

作者图片

正如我们在上面看到的,如果有混淆,这是而不是等于两个观察组(戒烟者与持续吸烟者)之间的关联差异:

作者图片

尽管存在这种不平等,但获得治疗效果的无偏估计是因果推断的本质。当我们确定这三个基本假设成立时,这个陈述就变成真的了(米格尔·埃尔南的“因果推论:如果”第三章)。一旦我们断定影响是可识别的,我们就可以使用像 IPW 这样的因果效应估计器来估计给定治疗 E[Y|A]的平均结果。

可能的解决方案

反向倾向加权(IPW)是一种通过给每个数据点不同的权重来平衡组的方法,因此每个组中要素的加权分布是相似的。

为了理解 IPW 是如何发挥其魔力的,我们需要知道什么是倾向得分。倾向得分只是一个花哨的词,用于描述在给定其特征 X 的情况下,个体属于治疗组 A 的概率:

作者图片

这个概率可以用你内心渴望的任何 ML 模型来估计💕(虽然我们在技术上可以使用任何 ML 模型,但重要的是避免通过使用非常复杂的模型来过度拟合。要进一步了解这一点,请查看这本笔记本。一旦我们估计了这个概率,给每个样本的权重就是倾向得分的倒数!(有关 IPW 的更详细解释,请参见 Miguel Hernan 的“因果推断:如果...会怎样”的第 12 章)重新加权创建了一个不再具有潜在混杂关联的伪总体,这相当于移除了因果图中的箭头:

作者图片

何时选择 IPW

所有因果模型都需要有多个假设才能可靠:

  • 存在混杂因素——治疗分配和结果都受到一些协变量的影响。如果不是,则不需要对混杂进行校正。
  • 没有不可测量的混杂因素——所有的混杂变量都在您的模型中考虑到了。
  • 不存在阳性违规——每个样本都有属于两个治疗组的阳性概率。

在以下情况下,应选择 IPW 而非其他因果模型:

  • 您不需要单个水平的预测,只需要整个群体的平均值。
  • 由于 IPW 在给定协变量的情况下对治疗分配进行建模,您需要感觉自己很好地理解了治疗分配程序。

这一切都很棒,但实际上是如何做到的呢?这就是 causallib 发挥作用的地方。

用 causallib 寻找因果关系

Causallib 是一个开源的 python 包,只要对数据的假设有效,它就可以让你插入任何 sklearn ML 模型,得到因果预测。该软件包可以执行多种因果模型,如 IPW、结果模型和双稳健方法,并提供一套评估模型性能的评估。它在 PyPi 上可用,可以通过运行pip install causallib来安装。这里显示的代码是使用版本 0.9.0 运行的。

在这个例子中,我们将观察戒烟对体重变化的影响。数据来自 1566 名年龄在 25-74 岁的吸烟者,他们进行了基线访问和 10 年后的随访。接受治疗的个体(A=1)是那些在随访前报告戒烟的个体,而未接受治疗的个体(A=0)则不然。数据摘自 Miguel Hernan 的“因果推理:如果……会怎样”,可以在找到

我们的目标是估计戒烟(治疗) A 对体重增加(结果) Y 的平均因果效应。从数据来看,戒烟者的平均体重增加了 4.5 公斤,非戒烟者的平均体重增加了 2.0 公斤。因此,差异为 2.5 千克,95%置信区间为 1.7 至 3.4。正如我在本文开头提到的,这种类型的估计被称为“未调整的估计”。所以,你可能会想,太好了,我们找到了问题的答案!但是这并没有告诉我们戒烟对减肥有什么影响,它只是报告了戒烟者和非戒烟者之间体重变化的差异。如果戒烟是随机分配的,我们可以将此作为有效的效果评估。但是,由于戒烟的可能性本身受到个体协变量的影响,简单地比较两组的平均值会产生对治疗效果的有偏估计。为了消除估计的偏差,我们需要对混杂因素进行偏差调整。所以,让我们在 IPW 的帮助下再试一次。

causallib 的 IPW 是一个“元学习者”。它包装了一个通用的二元结果预测模型,并使用它来估计倾向和效果。底层学习者可以是任何东西,只要它支持 sklearn 接口。对于这个例子,我们将使用良好的旧逻辑回归作为我们的核心估计,因为它对过度拟合相对稳健,并且在我对该数据进行实验时具有与其他模型相当的性能。

首先,我们用我们选择的学习者实例化 IPW 类,并使其适合数据:

  • 数据。x 是所有对象的特征矩阵
  • data.a 是每个受试者的治疗(戒烟/未戒烟)

接下来,我们估计每个治疗组的平均平衡结果。我们将使用 hor vitz–Thompson 估计值,它是 Y 的反向倾向加权平均值。

该函数输出一系列(“结果”),其中预测了两个治疗组的平均潜在结果。

最后,一个“效果”是两个潜在结果的对比,我们必须在加法(差异)和乘法(比率)尺度上自由指定治疗效果。我们将使用不同之处:

作者图片

我们可以看到,戒烟者的平均体重增加了 3.4 公斤,这与我们未经调整的估计值(2.5 公斤)不同。这与 Miguel Hernan 的“因果推理:如果”第 152 页中看到的结果相同。

使用 causallib 进行评估

因果推理模型和最大似然模型之间的关键区别是,在监督学习中,我们几乎总是有基础真理。假设我们正在训练一个分类器来预测戒烟十年后体重下降的公斤数。当我们测试模型时,我们可以看到哪些样本具有较大的残差,因为它们被标记了。因为“因果推理的基本问题”(在布雷迪·尼尔因果推理简介 2.2 中深入解释),这种检查你的模型实际工作得有多好的能力在这里并不存在。简而言之,我们永远无法直接验证潜在的结果是否正确,因为我们无法在同一个人身上,在两种不同的行动下,观察到两种不同的结果。一个人不可能既戒烟又不戒烟。

Matheus Facure Alves 的照片,来自“勇敢和真实的因果推理

即使您不能评估因果推理中的基本事实,causallib 也提供了一些评估来帮助您检测模型中的问题。

evaluate功能使我们能够交叉验证模型,创建评估图并计算分数。首先,我们为我们的模型指定我们感兴趣的评估指标。评估是通过交叉验证和在每个折叠上重新装配模型来完成的。

我们将生成一个新的模型,这个模型与之前的数据不符,并检查它的执行情况。

爱情情节

爱情图计算加权前后每个协变量组间的标准化平均差异。我们希望加权后所有协变量的差异将小于某个阈值,通常为 0.1。这一结果表明,加权成功地创建了一个伪群体,其中协变量在两组之间平均分布。

作者图片

倾向分布图

另一个重要的评估图是两个治疗组的倾向分数的分布。理想情况下,这两个分布应该是重叠的,但不是相同的。如果它们是相同的,这将意味着在给定协变量的情况下,两个治疗组是不可区分的。这也证实了不存在阳性违反,因为每个受试者在任一治疗组中都有非零概率,并且分布重叠(查看本笔记本中的阳性违反示例)。

作者图片

讨论

在这篇文章中,我们展示了如何使用 causallib 的 IPW 来了解治疗和结果之间的因果关系。causallib 包使我们能够利用丰富的 Scikit-Learn 模型和评估指标库来进行因果估计,从而可以轻松地将这些类型的问题纳入任何数据探索流程。

有更多的因果模型可以使用,如标准化、双稳健模型、X-learners 等。每个都有不同的超参数来调整个性化的评估,因为你喜欢。

一些有用的链接:

感谢迈克尔·M·丹齐格埃胡德·卡拉瓦尼帮助创建这个帖子!

实践强化学习课程:第 4 部分

原文:https://towardsdatascience.com/hands-on-reinforcement-learning-course-part-4-55da5eae851f

线性 Q 学习

我们跳舞好吗? 约根德拉·辛格 ❤️

欢迎来到我的强化学习课程❤️

这是强化学习实践课程的第 4 部分,带你从零到英雄🦸‍♂️.

第一部分:强化学习简介
第二部分:表格 Q-learning
第三部分:表格 SARSA
👉🏻第四部分:线性 Q 学习(今天)

很抱歉让你等了这么久,我想和你分享整个学习过程,这样你就知道好的结果来之不易。但是一旦他们这么做了,他们就值 trouble️.奖了

今天,我们进入了新的领域…

强化学习遇到了现代机器学习中必不可少的优化技术的领域解决大量不同问题和环境的杀手锏🚀。

我们要解决的问题是著名的推车杆平衡,目标是通过左右移动推车来平衡连接在推车上的杆。

这是我们将在本次冒险结束时实现的 Deep Q-Agent 的外观:

我们将在这一部分探讨的技术是过去 5 到 10 年中强化学习领域令人印象深刻的成就背后的支柱。

有很多东西需要消化,所以我们将工作负载分成 3 部分:

  • 在第 4 部分(这个!)我们实现了一个线性 Q 代理来获得一个不错的解决方案。
  • 在第 5 部分中,我们增加了深度并实现了一个 Deep Q 代理来获得一个好的解决方案。
  • 在第 6 部分,我们将看到如何微调所有的超参数,以最大限度地提高性能。在这里,我们终于得到了你在上面看到的可怕的深 Q 代理!

在每一部分中,我们都会加入新的想法、技巧和你需要掌握的实现细节。更重要的是,我希望你在构建 RL 解决方案时习惯于失败。因为大多数时候都是这样。

高级 RL 技术,如我们将在这三部分中看到的技术,非常强大,但需要仔细实施和超参数调整。

调试 RL 算法不是一件容易的事情,而变得更好的唯一方法就是犯错。当我开始学习强化学习时,我最大的挫折之一是算法表面上的简单,以及试图复制已发表的结果时的极端困难。

强化学习本身就很难,所以我们尽量不要让它变得更加复杂。一步一步来!

这节课的所有代码都在 这个 Github repo 里。 Git 克隆它来跟进今天的问题

还有别忘了给它一个⭐!

第四部分

内容

  1. 大车杆子问题🕹️
  2. 环境、行动、状态、奖励
  3. 随机代理基线🤖 🍸
  4. 参数 Q 学习
  5. 你好 PyTorch!👋
  6. 线性 Q 代理🤖
  7. 重述✨
  8. 家庭作业📚
  9. 下一步是什么?❤️

1.推车杆子问题🕹️

一根杆子用一个未启动的接头连接到一辆手推车上。你的目标是移动推车的位置,左右移动,防止杆子掉下来。

我们将使用CartPole-v1的实现,你可以在 OpenAI Gym 中找到。

为什么会有这个问题?

到目前为止,我们已经在离散/表格环境中使用了经典的强化学习算法、Q-learning(第 2 部分)和 SARSA(第 3 部分)。

今天的问题稍微复杂一点,因为它的状态空间太大,无法离散化。相反,我们需要升级我们的游戏,并使用更强大的 RL 算法。

我们将使用参数 Q-learning,这是一种将我们在第 2 部分看到的经典 Q-learning 与参数近似相结合的技术,参数近似可以是线性的(在第 4 部分),也可以是更复杂的,如神经网络(在第 5 部分)。

使用神经网络的参数 Q 学习(又名深度 Q 学习)是强化学习中许多最新突破的背后,如 DeepMind 的著名 Atari 游戏播放器。

让我们熟悉一下这个环境的具体情况!

2.环境、行动、状态、奖励

👉🏽notebooks/00 _ environment . ipynb

状态由 4 个数字表示:

  • 大车位置 x 从-2.4 到 2.5。
  • 大车速度v
  • 相对于垂直线的极角 θ 从-12 到 12 度(从-0.21 到 0.21 弧度)
  • 极点角速度 ω。 这是 θ的变化率。

大车极点状态向量(图片由作者提供)

当出现以下任一情况时,一集终止:

  • 大车越限: x > 2.4x < -2.4
  • 电杆离垂线太远: θ > 12 度θ < -12 度。
  • 或者我们达到了最大集数 500 步。在这种情况下,代理人完美地解决了插曲。

起始状态是从每个状态的区间[-0.05,0.05]中随机抽样的。有时候,开始的位置如此接近平衡,以至于这一集很容易。其他时候,开始的位置是如此不平衡,以至于插曲很难解决,有时甚至是不可能的。

大车速度 v 和杆子角速度 ω呢。 这些值也有界吗?

首先,让我们加载CartPole-v1环境。

如果你看看 OpenAI 健身房的区间变量env.observation_space.lowenv.observation_space.high,你会发现这两个数字似乎是任意大或小。

实际上,这是不正确的。无论是 v 还是 ω 都有更窄的间隔,但这是你无法直接从env对象中读出的东西。您只能在您的代理探索环境时观察它们的真实范围。

这一点很重要,因为我们今天和第 5 部分将使用的模型,与标准化输入配合使用效果最佳。在这种情况下,归一化状态。要归一化一个数,你首先需要知道它的最大值和最小值。 vω 这两个值不能从env.observation_space中读取。你需要通过一点探索来估计它们。

这张纸条的重点是:

⚠️不会盲目地把``env.observaton_space`中的数值作为每个状态的真实范围。

我们的代理可以执行的操作是什么?

  • 0:向左推推车。
  • 1:向右推推车。

每走一步奖励为+1。这意味着代理人保持杆子站立的时间越长,累积奖励越高。

3.随机代理基线

👉🏽notebooks/01 _ random _ agent _ baseline . ipynb

像往常一样,我们使用一个RandomAgent来建立一个基准性能。

我们用 1000 集来评估这个代理

计算平均回报及其标准差。

让我们看看参数 Q 学习如何帮助我们构建一个更智能的代理!🧠

4.参数 Q 学习

到目前为止,我们已经在离散/表格环境中工作过(在第 2 部分),或者将原始环境转换为离散环境(第 3 部分)。

然而,大多数有趣的环境不是离散的,而是连续的,并且太大而无法离散和求解。

幸运的是,有直接在连续状态空间上工作的 RL 算法。

今天我们将使用参数 Q 学习。该算法类似于我们在第 2 部分中看到的原始 Q 学习,但适用于连续设置。

CartPole的状态空间由 4 个连续数字组成

在哪里

  • x 是大车位置
  • v 是大车运行速度
  • θ 是磁极角度
  • ω 是极点角速度

在这样的连续状态空间中,最佳 Q 值函数

不能用表来表示(因为它会有无限多个维度)。

相反,我们用一个参数形式来表示它

在哪里

  • Q*是模型架构,像线性模型,或者非常深度的前馈神经网络。
  • 这取决于我们将使用代理在训练期间收集的经验 (s,a,r,s’)来估计的一组参数。

为 Q*选择模型架构对于学习好的策略和解决问题至关重要

模型的参数越多,就越灵活。它更有可能是这个问题的一个好模型。事实上,线性模型只是神经网络的特例,没有中间层。

为了简单起见,今天我们将使用线性模型,在下一讲中,我们将引入一个更深(即更多层)的神经网络模型来提高性能。

一旦您为 Q* 选择了模型架构,您就需要找到最佳参数 P.

好的,但是如何学习参数 P 的向量呢?

我们需要一种方法来迭代地找到这些参数 P 的更好估计,因为代理在训练期间收集了更多的经验,并且收敛到最优参数 P*

现在,函数 Q*(s,a,P) 满足贝尔曼最优方程,这是强化学习中的一个关键方程

这告诉我们,最大未来报酬 Q*(s,a,P) 是代理人进入当前状态所收到的报酬 r 加上下一个状态s’的最大未来报酬。**

最佳参数 P 是那些使该等式的左侧尽可能接近右侧的参数。*

这是一个优化问题,你可以用现代机器学习技术来解决。更准确地说,监督机器学习技术。

有监督的 ML 问题有 3 个组成部分:

  1. 输入features和相应的targets
  2. 我们需要确定一组parameters
  3. 依赖于这些parameters并将features映射到model outputs的模型架构

目标是找到使model outputstarget值匹配的parameters

换句话说,我们要找到使距离最小化的参数 P ,也就是 ML 行话中的损耗*

机器学习界解决这个优化问题的一个经典算法是随机梯度下降 (SGD) 方法。更准确地说,小批量随机梯度下降。

给定你当前的估计 P⁰,一个小批量的经验(s,a,r,s’)和一个合适的学习率,你可以用 SGD 更新公式来改进你的估计 P⁰

SGD 更新公式

损失相对于参数的梯度,∇ L 是一个向量,其分量是损失相对于参数向量中每个分量的灵敏度。

实际上,你永远不需要自己计算梯度。PyTorch 或 TensorFlow 等 Python 库使用一种叫做反向传播、的算法为您完成了这项工作,这只是您可能多年前在高中就已经学习过的微积分中链式法则的一个花哨名称。

让我们回顾一下:

  • 当我们的代理探索环境时,您收集成批的经验,并使用这些经验通过 SGD 更新公式来更新参数。
  • 如果你重复这个足够长的时间,你会(希望🤞)得到最佳参数 **P,*并因此得到最佳 Q 值函数。*
  • 从最优 Q函数中,你可以推导出最优策略*

瞧啊。这就是参数 Q 学习的工作原理!

但是等一下…

为什么在**上面说有希望收敛到最优👆**?

与表格设置相反,在表格设置中,Q-learning 的工作有很强的保证,在参数化版本中,事情更加脆弱

本质上,导致事情失败的是我们优化问题的目标值

随着我们更新参数估计而改变。目标在训练过程中会发生变化。他们移动🏃

这个看似微不足道的细节让问题变得更加难以解决。

希望研究人员发挥创意,介绍了一些提示和技巧✨来解决这个问题。

技巧 1:目标✨更新较慢

如果移动目标是个问题,我们能不能尽量少移动它们?

答案是肯定的。我们可以通过使用两个不同的参数向量来实现:

  • P: 主模型的参数(左侧)。这些在每次 SGD 更新后进行调整。不出所料。
  • Pᵀ: 目标模型的参数(右侧)。这些参数在 SGD 更新期间保持固定,我们只在第 N 次迭代中重置它们以匹配 P 中的参数。**

Pᵀ 的更新频率是我们需要调整的一个超参数。

招数二:重放记忆✨

Q-learning 是一个离线算法。这意味着贝尔曼方程适用于任何代理体验 (s,a,r,s’),无论代理遵循哪种策略。

因此,过去的经验可以成批分组,并用于通过 SGD 更新来更新参数。

创建像这样的批量数据消除了经验之间的相关性,这对于更快地训练神经网络模型特别有用。

这段记忆里要储存多少经历?

这个数字(也称为内存大小)是一个我们需要调整的超级参数。

今天,你需要相信我,我们将使用超参数,并等待第 6 部分,看看我们如何得到它们。

调整超参数不是一门艺术,而是一门科学。我们将在第 6 部分中看到如何使用非常流行的 Python 库来实现

最后,如果你已经用 PyTorch 库建立了神经网络模型,你可以跳过下一节。否则,让我把你介绍给你的下一个好朋友🤓

5.你好 PyTorch!👋

PyTorch 是一个 Python 库,允许您训练可区分的模型,包括线性模型和神经网络。

PyTorch 将会是这个库,我们将会在剩下的课程中使用它来解决我们在参数强化学习算法中需要解决的那种有监督的 ML 问题,比如参数 Q 学习。

PyTorch 有一个非常 Python 化的接口(与 Tensorflow 相反),我相信你会很快学会它。

PyTorch 背后的关键特性是它的自动微分引擎,它为我们计算更新模型参数所需的梯度。

PyTorch 中培训脚本的主要构件包括:

👉一批输入数据,包含特征和目标。

👉模型定义封装成 Python 对象torch.nn.Module你只需要实现正向传递,即从输入到输出的映射。举个例子,

👉一个损失函数,例如torch.nn.functional.mse(均方误差),它计算给定模型输出和目标的损失。

👉一个优化器,像torch.optim.Adam(SGD 的一个复杂版本),它调整模型参数以减少批量输入数据的损失函数。

这 4 个要素被组合成一个循环,也就是监督机器学习问题的训练循环。

在这个脚本的最后,如果您的model架构适合数据,您的model参数将会使model_output非常非常接近target

这就是用 PyTorch 求解参数函数近似值的方法。

说够了。让我们来看看代码,实现一个线性 Q 代理!

6.线性 Q 代理

我们使用以下模型将输入状态映射到 q 值函数(也称为我们的 q 函数):

self.q_net

参数的数量等于输入和输出像元之间的连接数(即 4 x 2 = 8)加上我们通常添加到这些线性层以增强其表现力的 2 个偏置项。这总共给出了 10 个参数。

这不是一个非常灵活的模型,但是对于今天来说已经足够了。在接下来的讲座中,我们将使用更强大的神经网络模型。🤑

现在,让我们来看看超参数…

我创建了 2 个笔记本。一个具有坏的超参数,另一个具有好的超参数。

在两节课中,我们将看到如何通过实验找到这些值。目前,相信我,它们是我能找到的最好的(也是最差的)🙂

错误的超参数

👉🏽notebooks/02 _ linear _ q _ agent _ bad _ hyperparameters . ipynb

我们固定所有随机种子,以确保可重复性

然后我们创建QAgent对象

我们训练它 2000 集:

我们在 1000 次随机运行中评估了它的性能

结果看起来…

相当糟糕!

它们比基线更差RandomAgent😵!

战胜

让我们看看当你使用好的超参数时会发生什么。

良好的超参数

👉🏽notebooks/03 _ linear _ q _ agent _ good _ hyperparameters . ipynb

我们重复相同的步骤来训练代理,然后评估它的性能:

惊人的结果!

您可以绘制整个分布图,以查看代理始终得分高于 100!🎉🎉🎉

胜利!

哇!超参数对训练结果有多么巨大的影响。

超参数灵敏度

使用参数近似的强化学习代理对超参数非常敏感。通常,他们对你在训练中用来控制所有随机性来源的随机种子也很敏感。

除非提供所有超参数,否则很难复制发表在论文和期刊上的结果。

我强烈推荐你阅读一篇关于现代/深度强化学习中再现性的优秀论文

📝重要的深度强化学习

我们今天取得了足够的进展,建立了我们的第一个参数 Q 代理。

是时候停下来回顾一下了。

贝尔格莱德的凯(图片由作者提供)

7.重述✨

这是 3 个关键要点:

  • 参数 Q 学习是一种结合经典 RL (Q 学习)和函数逼近(监督 ML)的强大算法。
  • 您使用的参数化是确保算法收敛到最优解的关键。今天我们使用了一个线性模型,但是在下一部分,我们将使用一个更灵活的模型:神经网络。
  • 超参数是至关重要的,可以成为交易的破坏者。

8.家庭作业📚

👉🏽笔记本/04 _ 作业. ipynb

这是我要你做的:

  1. Git 克隆 把回购到你的本地机器上。
  2. 设置 本课的环境03_cart_pole
  3. 打开[03_cart_pole/notebooks/04_homework.ipynb](http://02_mountain_car/notebooks/04_homework.ipynb),尝试完成两个挑战。

在第一个挑战中,我希望你尝试不同的SEED值,并使用我向你展示的良好超参数重新训练代理。还能得到好的表现吗?还是结果很大程度上取决于你用的SEED

在第二个挑战中,我要求你用今天的方法和代码解决第三部中的MountainCar-v0环境。你能用线性 Q-learning 得到 99%的分数吗?

9.下一步是什么?❤️

在下一课中,我们将加入我们的第一个深度神经网络,并创建我们的第一个深度 Q 代理。

令人兴奋,不是吗?

让我们一起继续学习吧!

你想成为(甚至)更好的数据科学家,接触关于机器学习和数据科学的顶级课程吗?

👉🏽订阅 datamachines 简讯

👉🏽 跟着我 上媒。

👉🏽给课程一个⭐github 回购

祝你愉快,🧡❤️💙

避寒胜地

实践强化学习课程:第 5 部分

原文:https://towardsdatascience.com/hands-on-reinforcement-learning-course-part-5-bdb2e7fa243c

深度 Q 学习

我们再深入一点!🙏来自 Pexels 的 Jeremy Bishop

欢迎来到我的强化学习课程❤️

这是强化学习实践课程的第 5 部分,带你从零到英雄🦸‍♂️.

第一部分:强化学习简介
第二部分:表格 Q-learning
第三部分:表格 SARSA
第四部分:线性 Q-learning
👉🏻第五部分:深度 Q 学习(今天)

在第 4 部分中,我们为 Cart Pole 环境构建了一个不错的代理。我们使用线性模型的参数 Q 学习。

今天我们将用一个神经网络代替这个线性模型。

我们将彻底解决手推车的环境问题😎

今天的课程有点长,因为它包括一个关于训练神经网络模型的迷你速成班。除非你是深度学习方面的专家,否则我强烈建议你不要跳过它。

本课所有代码都在 本 Github repo 中。Git 克隆它来跟进今天的问题。

如果你喜欢这个课程,请在 Github 上给它一个⭐

☕.喝了一大口我们准备开始了!

第五部分

内容

  1. 我们深入吧!
  2. 深度学习实践介绍
  3. 深度 Q 学习解决大车杆子
  4. 重述✨
  5. 作业📚
  6. 接下来呢?❤️

1.我们深入吧!

在上一课中,我们使用这种线性参数化来表示最佳 q 函数。

线性 q 函数(图片由作者提供)

这是一个只有 10 个参数的小模型。

参数 Q 学习代理的成功(或失败)很大程度上取决于我们用来逼近最优 Q 值函数的参数化。

线性模型概念简单,训练速度快,运行速度快。然而,他们不是很灵活。给定一组输入和输出,线性图层很难将输入映射到输出。

这是神经网络进入游戏的时候。

神经网络模型是我们拥有的最强大的函数逼近。它们非常灵活,可用于揭示输入要素和目标标注之间的复杂模式。

普适逼近定理 📘是一个数学结果,本质上是说

神经网络就像你希望的那样灵活。如果您设计了一个足够大的神经网络(即具有足够的参数),您将发现输入特征和目标值之间的精确映射。

或者如果你喜欢更哲学的风格…

布鲁斯大师说得再好不过了(由作者从剪贴画编辑)

今天,我们将用最简单的神经网络架构取代第 4 部分中的线性模型:一个前馈神经网络。

前馈神经网络(图片由作者提供)

在课程的后面,我们将使用其他神经网络来处理更复杂的状态空间(例如卷积神经网络)。

正如我在课程开始时所说的,我并不期望你成为神经网络方面的专家。

如果你确实是其中之一,请随意跳过下一部分,直接进入第 3 部分。

否则,就让我们用下面这个我今天为大家创造的模仿学习问题来预热我们的深度学习掌握吧。

要涵盖的内容相当多,所以用深度聚焦来武装自己。

2.深度学习实践介绍:从标记数据中学习最优策略

👉🏽notebooks/05 _ crash _ course _ on _ neural _ nets . ipynb

在本节中,我们将使用深度学习解决一个有监督的机器学习问题。

但是,我们为什么不直接解决大车杆子呢?🤔

有监督的最大似然问题与我们在参数 Q 学习中解决的优化之间的关键区别在于,在超最大似然中,目标是固定的,而在参数 Q 学习中,目标是不固定的,而是移动

正因为如此,有监督的最大似然问题更容易解决,因此它们是我们接触神经网络模型的更好起点。

在监督机器学习中,你有一个数据集对 (输入,输出) ,你想找到输入(又名特征)和输出(又名目标/标签)之间的映射。

好,我们要解决的有监督 ML 问题是什么?

我采用了我们将在下一节中训练的完美 deep-q 代理(也称为完美代理),并生成了 1000 个状态的样本(输入),以及这个完美代理采取的相应动作(输出)。从这个观察样本中,我们想了解代理遵循的基本最优策略。

就当是模仿学习问题吧。从专家的表现中给你 1000 个样本(状态,动作),你的工作是学习代理遵循的基本策略。

说够了。让我们看看代码。我们首先看看如何生成训练数据。然后,我们将训练几个神经网络模型,并提取一些学习。

2.1 生成列车数据

像往常一样,我们从加载环境开始

为了生成训练数据,我们首先需要获得完美的代理参数(和超参数)。我把这些上传到了你可以访问的公共 Google Drive,你可以从那里下载,如下所示:

path_to_agent_data中,您有两个文件:

  • model →用参数函数的参数保存 PyTorch 模型,本例中为神经网络。
  • hparams.json →用于培训代理的超参数

现在,您可以从这些参数(和超参数)实例化一个QAgent对象,如下所示:

在继续之前,我希望你相信我说的代理人是完美的。我们随机 1000 集评估一下,查看一下总奖励。

满分!

500 是最高总奖励,我们的经纪人在所有 1000 集里都拿到了。太棒了。您需要等到下一节自己来训练这个完美的代理。

现在,我们让代理与环境交互几集,直到我们收集到 1000 对(状态、动作)。这就是我们如何生成我们的训练数据

generate_state_action_data函数生成一个 CSV 文件,如下所示:

train.csv

其中:

  • s1, s2, s3, s4是输入特征,和
  • action是目标,在本例中是二进制目标(0 或 1)。我们将解决一个二元分类问题

现在,在我们进入建模部分之前,我们还需要做一件事。

当你训练有监督的 ML 模型(尤其是神经网络)并且想要正确评估它们的准确性时,你不能使用你用来训练它们的相同数据集。

为什么?

因为可能发生的情况是,你的模型只是简单地记住了训练数据,而不是揭示特征和目标之间的真实相关性。这在高参数模型中很容易发生,比如大型神经网络。因此,当您将模型用于模型的新的和不可见的数据时,您的模型性能将低于您在训练期间获得的性能。

为了解决这个问题,我们生成另一个数据集,称为测试数据,我们不使用它来调整任何模型参数。测试数据专门用于评估模型的性能。

我们生成的方式和火车集一样。

观察我们如何使用不同于train.csv的种子,以保证我们不会为训练和测试数据集生成相同的样本。

酷毙了。我们得到了数据。让我们继续到建模部分。

2.2.系统模型化

正如我们在强化学习问题中经常做的那样,最好从建立一个快速基线模型开始,以了解问题有多难。

让我们加载 CSV 文件:

如果我们检查训练数据,我们可以看到目标值(即最佳行动)具有完全平衡的分布。

这意味着预测总是 action = 0(或 action = 1)的非常虚拟的基线模型具有 50%的准确性,这意味着模型预测有 50%的时间匹配正确的标签。

将数据加载到 PyTorch 模型中

在我们进入模型之前,我们需要构建一个数据 管道来快速地将数据从 pandas 数据帧成批移动到我们的 PyTorch 模型。

PyTorch API 提供了两个辅助对象来让您轻松完成这项工作:

  • torch.utils.data.Dataset →包裹您的熊猫数据框的便捷包装。它检索数据帧特征并一次标记一个样本。
  • torch.utils.data.DataLoader →为您完成繁重的工作,批量将数据从Dataset转移到 Pytorch 模型。它使用 Python 的multiprocessing库来加速数据检索。

我们需要两条数据管道,一条用于训练数据,一条用于测试数据。

数据管道(图片由作者提供)

我们创建了一个自定义的Dataset类,并实现了 3 个必不可少的方法:__init__()__len__()__getitem__(idx).

然后,我们实例化 2 个Dataset对象:

DataLoaders甚至更容易实现,因为我们只需要声明它们,如下所示:

很好!数据管道准备好了。现在,我们有了一种快速成批移动数据并将其提供给我们将要构建的模型的方法。

所有模型都将使用交叉熵损失函数进行训练,这是分类问题的标准选择。

我们将使用 TensorBoard 来可视化培训和测试指标(损失和准确性)。尽管 Tensorboard 是由 Google 为其 DL 框架 TensorFlow 开发的,但它与 PyTorch 集成得非常好。

2.2.1 线性模型→ 10 个参数

这是我们学习最优策略的第一个候选人。

线性模型=无隐层的神经网络(图片由作者提供)

我们创建 PyTorch 模型如下:

我们训练这个模型 150 个纪元。一个历元是整个列车数据的完整传递。因此,我们将使用训练数据中的每个样本 150 次来调整模型参数

在每个时期结束时,我们使用测试数据计算模型损失和精确度。通过这种方式,我们可以衡量模型有多好

让我们启动 Tensorboard 服务器来可视化训练和测试指标。我们可以在 Jupyter 笔记本上使用

注意:如果你愿意,你可以直接从命令行启动 Tensorboard,并导航到控制台上打印的 URL,在我这里是localhost:6009/

打开 Tensoboard,选择最近一次跑步。您应该会看到这两个图表:

  • 列车数据上的精度,一批接一批。它稳定在 70%左右。

列车精度(图片由作者提供)

  • 测试数据的准确性,一批接一批。它也稳定在 70%左右。这个数字大于 50%的基线,因此模型正在学习一些东西。

测试准确度(图片由作者提供)

70%没那么差,但也远非完美。

💡提示:绘制训练度量来检测 bug 总是绘制训练准确性和损失,因为它可以帮助您找到代码中的 bug。如果准确度(损失)在每个时期后没有增加(减少),这意味着你的网络没有学习。这可能是由于您需要修复代码中的一个 bug。

🧠学习:欠拟合训练数据
如果模型对于任务来说太小,我们观察到训练和测试精度都处于中等水平,在这种情况下为 70%。我们说模型不符合数据,我们需要尝试一个更大的模型。

让我们扩大网络以改善结果。

2.2.2 具有 1 个隐含层的神经网络→1795 个参数

我们创建一个具有 256 个单元的隐藏层的神经网络:

带有 1 个隐藏层的神经网络(图片由作者提供)

我们训练它 150 个历元,然后去 Tensorboard 检查指标

  • 测试数据的准确性。我们从 70%提高到了 85%左右。

测试准确度(图片由作者提供)

85%看起来好多了。但是,我认为我们可以做得更好。让我们试试更大的神经网络。

2.2.3 具有两个隐藏层的神经网络→ 67,586 个参数

带有两个隐藏层的神经网络(图片由作者提供)

你会观察到它的测试准确率达到 90%。

测试准确度(图片由作者提供)

增加网络规模似乎是一个明智的策略。我们再进一步,再加一层。

2 . 2 . 4 3 隐层神经网络→ 133,378 个参数

具有 3 个隐藏层的神经网络(图片由作者提供)

如果你在测试数据上检查它的准确性,你会看到它达到 90%。因此,这种模式并不能改善我们的最佳结果。

测试准确度(图片由作者提供)

直观地看,我们之前的模型,有两个隐藏层和大约 67k 的参数,做得足够好了。使用更复杂的模型并不能真正带来更好的结果。

🧠学习:过拟合训练数据 如果你的模型相对于训练数据量过大,你会过拟合训练数据。要检测过度拟合,看一看火车和测试损失。
如果训练损失继续减少,而测试损失保持平稳,这意味着你开始过度拟合

在这种情况下,我们可以通过查看序列和测试损耗来检查过度拟合:

  • 列车数据丢失几乎达到 0

列车数据丢失几乎达到 0!(图片由作者提供)

  • 测试数据损失在 0.3 处达到平稳状态,这与具有两个隐藏层的先前模型相同。

测试数据丢失(图片由作者提供)

💡提示:收集更多的数据来改善结果

改进神经网络模型的最有效策略是使用更大的训练集。这个建议适用于任何机器学习模型,而不仅仅是神经网络。然而,神经网络是从更大的训练集受益最多的网络,因为它们是高度参数化的,并且可以灵活地适应数据中最复杂的模式。

正如你所看到的,有相当多的实验来为这个问题找到正确的神经网络结构。

你可能会问…

有没有系统的方法来为我的数据找到合适的架构?

是的,有。在这一节中,我们从小模型到大模型,以便逐步增加复杂性。然而,在实践中,你应该走另一条路。

💡提示:由大变小

一般来说,你应该从一个足够大的网络开始,这个网络要能够适应训练数据。一旦您确定网络有足够的容量,您就开始减少它,以减少对训练数据的过度拟合并提高验证数据的准确性。

安德烈·卡帕西有一篇关于这方面的非常好的博文,我强烈推荐你阅读
📝训练神经网络的方法

我希望在本节之后,您对如何训练神经网络模型有更好的理解。

我建议您浏览一下[src/supervised_ml.py](https://github.com/Paulescu/hands-on-rl/blob/main/03_cart_pole/src/supervised_ml.py)中的代码,以巩固我们在本节中所讨论的内容。在监督设置中训练神经网络模型是现实世界中深度学习的一个非常实际的用例。练习 100 次,如果有问题就告诉我📩。

在下一节中,我们将回到车杆问题。

你准备好把 RL 和你刚刚学到的关于神经网络的知识混合起来了吗?

3.深度 Q-学习解大车杆子

回到参数 Q 学习和推车杆。

我们将完全重用第 4 部分的代码,唯一的区别是我们将替换最优 q 函数的线性参数化

线性模型(图片由作者提供)

具有两个隐藏层的神经网络

带有两个隐藏层的神经网络(图片由作者提供)

这将是课程中第一个深度强化学习算法。在这种情况下,深度 Q 网络。

超参数呢?

RL 算法对超参数极其敏感。深度 Q 学习也不例外。

我不想对你撒谎。寻找正确的超参数可能非常耗时。超参数在深度强化学习中非常关键,许多作者都没有发表它们。这对任何进入这个领域的人来说都是相当令人沮丧的。

甚至训练循环中的随机性,例如来自存储器中成批训练数据的混洗,也会对最终的代理参数产生很大的影响。

正因为如此,我们总是在 Python 脚本的开头修复所有的种子

然而,这不足以确保机器间的可重复性。可能发生的情况是,你和我都使用相同的超参数和随机种子,但我们得到不同的模型,只是因为你在 GPU 上训练,而我没有。

换句话说,不能保证 PyTorch 版本、不同平台或硬件设置(GPU 与 CPU)之间完全可再现的结果。

结果的再现性
当使用我在本节分享的完全相同的超参数时,您可能不会得到与我相同的结果。

不要沮丧。在下一课中,我们将学习如何自己调整超参数,您将能够找到那些对您的设置非常有用的参数,以防它们对您不起作用。

错误的超参数

👉🏽notebooks/06 _ deep _ q _ agent _ bad _ hyperparameters . ipynb

这些超参数绝对不是我发现的最差的。我称它们为坏的,因为它们给出了与第 4 部分中的线性 q 模型相似的结果。

当超参数设置不当时,使用复杂的神经网络模型有什么意义?

这些是超参数:

像往常一样,我们修复种子

我们从这些超参数中声明QAgent

我们训练了 200 集:

然后我们对 1000 集的代理进行评估

结果还不错,但我们可以做得更好。

那就开始吧!

良好的超参数

👉🏽notebooks/07 _ deep _ q _ agent _ good _ hyperparameters . ipynb

这些超级参数在我的 MacBook 上非常管用:

像往常一样,我们修复种子

我们从这些超参数中声明QAgent

我们训练了 200 集:

如果你评价《T2》剧集的经纪人

您将看到它达到了 100%的性能:

呜哇!!Amaaaziiiing!!!

这很酷。我们在 CartPole 环境中找到了完美的 deep q-agent!(如果您还没有在您的计算机上,请等待第 6 部分,我将揭示超参数调谐背后的科学和工程😉).

今天就到这里吧,伙计们。

渴望了解更多信息?

凯·❤️意大利面(图片由作者提供)

4.重述✨

这些是我希望你们从今天的课程中汲取的重要知识:

  • 神经网络是非常强大的函数逼近器。您可以在完全监督的设置中使用它们(例如,从标记数据中学习最佳策略),或者作为 RL 算法的一个组件(例如,逼近最佳 q 值函数)。
  • 找到正确的神经网络架构并不容易。过大(过小)的神经导致过度拟合(欠拟合)。一般来说,从一个过度拟合训练数据的大型网络开始。然后你开始减少它来提高验证的准确性。
  • 深度 Q 学习中的超参数对于确保训练循环收敛到最优解至关重要。此外,跨平台(例如 Windows vs Mac)、底层硬件(GPU vs CPU)和 PyTorch 版本的完全再现性极其困难,如果目前还不可能的话。

5.家庭作业📚

👉🏽笔记本/08 _ 作业. ipynb

让我们弄脏你的手:

  1. Git 克隆 回购到你的本地机器。
  2. 设置 本课的环境03_cart_pole
  3. 打开[03_cart_pole/notebooks/08_homework.ipynb](https://github.com/Paulescu/hands-on-rl/blob/main/03_cart_pole/notebooks/08_homework.ipynb)并尝试完成 2 个挑战。

如果你不是深度学习高手,我推荐你解决第 1 个挑战。在我们的模拟问题中,增加训练数据量并尝试达到至少 95%的准确率。

在第二个挑战中,我希望你能找到一个更简单的神经网络(例如,只有一个隐藏层),它可以完美地解决横竿问题。

6.下一步是什么?❤️

在下一课中,我们将学习如何像专业人士一样使用正确的工具来调整超参数。

在那之前,

爱和学习。

还要特别感谢 Neria Uzan ,感谢他对课程如此投入。感谢你的辛勤工作和给我的反馈!

来吧伙计。(图片由作者提供)

你想成为(甚至)更好的数据科学家,接触关于机器学习和数据科学的顶级课程吗?

👉🏽订阅 datamachines 简讯

👉🏽 跟着我 上媒。

👉🏽给课程一个⭐github 回购

祝你愉快,🧡❤️💙

避寒胜地

使用人工智能和 Open AI 的 ChatGPT,使用 Python 对酒店评论进行实际情感分析

原文:https://towardsdatascience.com/hands-on-sentiment-analysis-on-hotels-reviews-using-artificial-intelligence-and-open-ais-chatgpt-d1939850c79e

以下是如何使用机器学习自动分类好的和坏的评论,只需几行代码

弗洛里安·施梅兹在 Unsplash 上的照片

我是一名研究人员,每天和 AI 一起工作。我可以说,处在我位置上的每个人都兴奋得像一只盯着冰淇淋蛋卷的狗。🤩

这是原因:

打开人工智能的聊天 GPT 是真棒。

对于那些不知道我在说什么的人来说, 聊天 GPT 是一个人工智能聊天机器人,它可以做,嗯,几乎所有的事情。
它可以编码,它可以写文章,它可以帮你装修,它可以编一个菜谱(如果你是意大利人我不建议这么做),不胜枚举。

是的,我们可以说它会在未来引发伦理(不仅仅是伦理)问题。我的母亲是一名高中老师,她非常害怕她的学生会利用聊天 GPT 在考试中作弊,这只是这种令人难以置信的强大技术会出问题的众多例子之一。

但是,问题还是在于的用途,而不是产品。如果我们严格地谈论技术方面(坦白地说,这是我更感兴趣的一个,因为我是一个认证的书呆子),它是令人惊讶的。

现在,许多开发人员已经使用并测试了这个聊天机器人,试图开发他们的代码和他们的人工智能想法,当然,这个聊天机器人的使用严格取决于你的背景。例如,如果您是一名 web 开发人员,您会要求 ChatGPT 使用 HTML 构建一个网站。如果您是一名测试人员,您可以让 ChatGPT 帮助您找到特定系统中的 bug。

就我的具体情况而言,我是一名研究员。具体来说,我的工作是用人工智能建造一些代理模型。假设你想对“A”进行研究,但是要做“A”,你需要大量的钱大量的能量、大量的计算时间。这种替代模型背后的想法是用一种使用人工智能的数据驱动方法来取代它。

现在我们暂时完全换个话题。

假设我是一个企业家,我在美国有很多酒店。给定一个给定酒店的特定评论,我想知道该评论对该酒店是好是坏。我该怎么做?我有三个选择:

  1. 我雇了一个每天阅读数百万条评论并进行分类的人,我可能会被逮捕,因为这显然是对人权的侵犯。
  2. 我雇了一个人,他每天阅读数百篇评论,并对它们进行分类。在个月之后,我能够用这个建立一个数据集。我从数据集中训练出一个机器学习模型。
  3. 我自动生成好差评立即用这个建立一个数据集。我从数据集中训练出一个机器学习模型

因为我重视读者的时间,所以让我跳过第一个选项。

第二个选项是在 ChatGPT 之前你会做什么。你无法提前知道一个评论是好是坏,所以如果你想据此建立一个数据集,你需要雇人,等到数据集准备好。

现在我们有了 ChatGPT,我们可以简单地让他们生成好的和不好的评论!这将需要几分钟(而不是几个月),它将允许我们建立我们的机器学习算法来自动分类我们的客户评论!

恭喜你,这是你的第一个代孕模特。😊

记住我们不会训练 ChatGPT 或者做任何微调。这种模式非常适合这样的任务,在这种情况下不需要微调。现在,ChatGPT 模型的训练当然不是开源的(就像模型本身一样)。我们所知道的只是在开放 AI 的博客中的小描述。他们解释说,该模型是由人类人工智能训练员和一种强化学习监督算法训练的。*

OpenAI 的 ChatGPT 不是开源的这一事实引发了一些非常棘手和有趣的伦理问题。这么强大的模型是应该开源,让所有人(坏人也一样)都能用,还是不开源,让没人能真正信任?

让我重述一下:

作者图片

你看到的这个小小的脑壳是代理模型;正如我们将看到的,这将是一个随机森林。但我说是动手文章,那就一头扎进去吧!(好激动!!!)

抱歉,我喜欢剧透。

1.生成我们的数据集

第一步是使用 Open 的 AI Python API 来生成我们的模拟。
需要考虑的几件事:
1。开放 AI 是天才为非天才用户做的。由于这个原因,如果你想安装它,你只需要做:

pip install --upgrade openai

(那就是可爱的)

2.当然,如果你想发送大量的请求,你将不得不支付额外的费用。假设我们不想这么做,我们只需要等大约 30 分钟就能得到我们的虚假评论数据集。同样,与我们手动操作需要等待的个月的等待时间(和成本)相比,这算不了什么。你也必须登录打开人工智能,并获得你的人工智能钥匙。

3.我们将通过以同一句话开始来自动输入这是一个好评还是差评:“这家酒店太糟糕了。”差评和“这家酒店太棒了。”为了好评。ChatGPT 将为我们完成审查。当然,除了这前四个词,我们无论如何都不会在我们的评论中包括这四个词,其余的评论都会有所不同。

我举个差评的例子:

和一个好的:

现在这是你需要生成整个数据集的代码。

然后,我们将使用 Pandas 将所有内容存储在数据帧中。

  1. 进口熊猫和 df:

2.填充 df:

3.导出 df:

2.机器学习时间!

所以现在我们需要建立和训练一个机器学习算法。
在我们处理文本时,我们需要做的第一件事是使用 矢量器 矢量器是将文本转换为矢量的工具。

比如:

作者形象

如你所见,相似 的文字相似 的向量(我知道,相似性是个棘手的概念,但你知道我的意思)。而不同的文本具有不相似的向量。

执行向量化步骤的方法有很多。有些方法比其他方法更复杂;有些方法比其他方法更有效率有些方法需要机器学习,有些则不需要。

就本项目而言(因为我不是 NLP 机器学习工程师),我们将使用一个相当简单的,名为 TfIDF 向量器,准备在 SkLearn 上使用。

让我们从导入库开始:

通过导入我们刚刚使用 ChatGPT 生成的数据集,这里那里做了点预处理……

现在我们来看看:

太棒了。现在我们来做一下向量化:

正如我之前所说,我们将使用的机器学习模型被称为 Random Forest。什么是随机森林?它是决策树的集合。什么是决策树?

决策树是一种机器学习算法,在给定某种信息论标准的情况下,它会优化数据集要素的所有可能拆分的树搜索,直到找到基于该拆分区分什么是 1 和什么是 0 的方法。*

*我很抱歉,如果这是超级混乱,但解释这在 4 行是一个困难的任务。 这篇文章 从容应对,表现出色。强烈推荐。

现在让我们:

1.定义我们的随机林:

2.将我们的数据集分解为培训和测试:

3.培训我们的模型:

这个结果给留下了非常深刻的印象,特别是考虑到缺少超参数调整。

3.情绪分析

因为我们已经有了训练好的模型,你可以在一个新的,未标记的数据集上使用它。我用了一套在网上找到的纽约市酒店评论,但你也可以用自己的来做一个评论,看看效果如何。

这个数据集是开源的( CC0:公共领域),非常小(2MB),可以在 Kaggle 上下载。

让我们对评论栏(或您的文本)进行预处理:

让我们打印出我们的预测:

我们可以看到,这 5 个被归类为 1 的随机评论其实都不错!

让我们展示一个计数图:

4.考虑

我们在这里做了什么?

  1. 我们承认 ChatGPT 很牛逼
  2. 我们使用 ChatGPT 为我们的代理模型构建数据集。更具体地说,我们使用 ChatGPT 来弥补酒店的好评和差评。
  3. 我们使用我们构建的标记为数据集的来训练我们的机器学习模型。我们使用的模型是一个随机森林分类器。****
  4. 我们在一个新的数据集上测试了我们训练的模型,得到了有希望的结果。****

还有改进的空间吗?一吨。

  1. 我们可以获得开放的人工智能高级服务并产生远远超过 1000 条评论的。****
  2. 我们可以通过给出不同的输入来提高我们的查询技巧,也许还可以用其他语言而不仅仅是英语
  3. 我们可以通过做一些超参数调整来改进我们的机器学习模型****

**现在,让我用一个想法来结束我的发言。

现在有,将来也会有很多关于如何以及谁来使用 Open AI ChatGPT 的担忧。虽然我不是律师(更不用说伦理人工智能专家),但我可以想象这个工具在许多方面和许多不同层面上是多么危险。**

我强烈反对那些对 ChatGPT 的性能不感兴趣的人,因为我发现它非常令人惊讶,我非常期待看到这项技术将如何发展。我希望这个玩具的例子也能在我的读者中激起一些火花。❤️

5.结论

如果你喜欢这篇文章,你想了解更多关于机器学习的知识,或者你只是想问我一些问题,你可以:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

用 Python 实践信号处理

原文:https://towardsdatascience.com/hands-on-signal-processing-with-python-9bda8aad39de

Unsplash 上由Sao tusar拍摄的照片

从理论到实践:下面是如何使用 Python 执行频率分析、噪声过滤和振幅谱提取

如果你想和数据打交道,有一件事是肯定的:要么专攻,要么去死。这种认为数据科学家可以处理文本数据、信号、图像、表格数据和乐高积木的想法是看待这个职业的一种过时的方式。

如今,随着机器学习的出现以及数据分析和计算机硬件方面的巨大进步,深入了解如何处理特定类别的数据至关重要。这是因为在进入另一个数据科学分支之前,关于这个分支有太多的知识需要了解。

就我而言,我每天都用信号工作。我了解他们,因为我有物理学硕士学位,我可以从他们那里获得有用的信息,因为我是一名数据科学家。

在这篇博文中,我将向你展示信号处理的基本操作,即频率分析噪声过滤振幅谱提取技术。

我们将从这些技术的简单理论背景开始,我们将展示它们在应用于一个非常简单(且公开)的数据集时是如何工作的,我们将使用该数据集作为我们的“信号”。

1.理论背景

1.1 傅立叶变换

在我们看来,( 1D)信号只不过是一个时间序列。这意味着我们有一个 x 轴,即时间,和一个 y 轴,即我们考虑的量(如电压)。

从直观的角度来看,对信号进行傅立叶变换意味着在另一个域中看到这个信号。

让我们把它变得更简单。假设你是超人。你所有的朋友都知道你叫克拉克·肯特。然后有一些犯罪,你做你的转变,你成为超人!你永远是你(尽管他们不知道),但他们看到你在另一个领域,穿着另一套服装,做着另一种事情。

作者图片

现在我们可以对信号和它们的正弦分量做同样的事情。

想法是将信号从时域看向频域

作者图片

在该图的左侧,我们看到一个频率为 1 的正弦信号。事实上,在右边,你只看到频率=1 时的一个峰值,其他地方都是 0。

假设您有多个正弦和余弦相互作用:您将看到多个幅度和多个非零频率,因为信号中存在多个模式。

这为什么有用?好吧,多种原因,但让我们选择两个:

  1. 你可以过滤你的信号。你知道,一般来说,你的信号会有一个有限的频带。如果你看到该波段之外的东西,你可以假设它是白噪声(存在于所有频率的噪声),你可以将其过滤掉。(噪声过滤)
  2. 你可以分析你的信号的周期模式,并发现对你的系统的季节性部分非常有用的洞察力。(频率分析)

1.2 小波变换

让我们回到傅立叶变换。进行变换意味着将傅里叶频谱的所有成分(所有频率的所有正弦)投射到信号中。在我们的例子中,通过做这种投影,除了频率 1,你在任何地方都得到 0,当你得到一个不同于 0 的值时。

现在,让我们用一个比正弦函数更复杂的函数,比如下面的 dyb2。

作者图片

我们可以玩这个小东西,收缩和扩张它,分析完整信号的投影。

投影会给我们一个“过滤”的信号,残差是这个投影和原始投影之间的差。

这是一种更多样、更通用的从噪声中过滤信号的方法,它有很大的优势,我们将在后面的动手实践部分看到。

1.3 希尔伯特变换

有时候你看到你的信号充满了起伏,但你并不是真的想要它。你只想拿到信封。从数学上讲,这个操作是通过使用卷积来完成的。特别的,核是 1/(pi*t)。在这个阶段,这里没有什么可谈的,但我们将在一分钟后的实践部分看到这种算法的威力!

2.动手举例

我们将要使用的数据集是一个公共数据集,可以在这里找到。
这基本上是一个能源消耗的时间序列,它非常适合我们的研究,因为无论如何它都可以被视为一个信号。数据集为公共领域数据集( CC0: Public Domain ),无需事先授权即可免费下载使用。

让我们从编码开始。

2.1 导入库

这是我们需要的:

2.2 数据预处理

让我们绘制数据集

我们可以看到,它有一种趋势,它没有零均值。这两个特征会干扰我们的分析。让我们使用 scipy 的去趋势选项来纠正它。

2.3 频率分析

现在是时候使用傅立叶变换对信号进行频率分析了。让我们绘制傅立叶频谱:

我们可以在这里看到非常有趣的山峰。例如,存在大约 24 小时(1 天)或 12 小时(0.5 天)或大约 80 小时(3 天)的周期。

特别是,我们可以对峰进行排序并打印相应的指数:

现在这些索引是粗体的。

我们也可以用“天数”单位打印这些指数:

2.4 噪声过滤(傅立叶变换)

现在我们可以以最高峰为参考,开始筛选比这个最高峰低 0.1,0.2,…0.9 的。例如,我们可以将低于最高峰值振幅 0.5 倍的所有值设置为零。

我们需要小心。如果我们将阈值设置得太高,我们不仅会滤除噪声,还会滤除信号的重要特征。如果阈值太低,我们基本上不过滤任何东西,仍然保留所有的噪声。

让我们做一些尝试:

以下是一些结果:

在这种情况下,0.30 似乎是一个很好的替代值。😃

附注:关于这一特定应用的更多信息,请参阅这篇文章

2.5 噪声过滤(小波变换)

我们也可以使用小波变换进行噪声滤波。在这种情况下,我们有多级过滤。第一级将仅过滤纯噪声,但它们将是保守的。越深入,噪声越少,但也会丢失信号的特征(残差将与原始信号相似)。

附注:关于这一具体应用的更多信息,请参阅这篇文章

2.6 振幅提取

对于这一部分,我只是做了一个向上和柔和的信号。假设我们只想提取它的包络(即所谓的振幅)。您只需要应用 scipy Hilbert 变换并计算绝对值:

超级简单,但在处理信号的数据科学家的日常生活中非常有用。

3.结论

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

使用 Python 进行主题建模实践

原文:https://towardsdatascience.com/hands-on-topic-modeling-with-python-1e3466d406d7

使用潜在狄利克雷分配(LDA)和 pyLDAvis 可视化的主题建模教程

布拉德利·辛格尔顿Unsplash 拍摄的照片

主题建模是自然语言处理和文本挖掘中提取给定文本主题的一种流行技术。利用主题建模,我们可以扫描大量的非结构化文本,以检测关键字、主题和主题。

主题建模是一种无监督的机器学习技术,不需要标记数据来进行模型训练。它不应该与主题分类混淆,后者是一种受监督的机器学习技术,需要标记数据进行训练以适应和学习。在某些情况下,主题建模可以与主题分类一起使用,其中我们首先执行主题建模,以检测给定文本中的主题,并用相应的主题标记每个记录。然后,这个标记的数据用于训练分类器,并对看不见的数据执行主题分类。

在本文中,我们将重点关注主题建模,并介绍如何通过文本预处理准备数据,通过 coherence score 分配最佳数量的主题,使用潜在 Dirichlet 分配(LDA)提取主题,以及使用 pyLDAvis 可视化主题。

在阅读本文的同时,我鼓励您查看我的 GitHub 上的 Jupyter 笔记本以获得完整的分析和代码。

我们有很多事情要谈,让我们开始吧!🤓

1.数据

我们将使用可以从 Kaggle 下载的迪士尼乐园评论数据集。它对巴黎、加州和香港的迪士尼乐园分店有 42,000 条评论和评级。评级栏包括评级分数,可用于主题分类,将未查看的评论分为正面、负面或中性。这超出了本文的范围,但是如果你对主题分类感兴趣,你可以查看下面的文章。

https://medium.com/analytics-vidhya/applying-text-classification-using-logistic-regression-a-comparison-between-bow-and-tf-idf-1f1ed1b83640

我们来读一下数据,看看前几行。

# Read the data
reviews = pd.read_csv('/content/DisneylandReviews.csv', encoding='latin-1')

# Remove missing values
reviews = reviews.dropna()

数据集的前 5 行

让我们只过滤“评论”和“评级”列。

# Filter only related columns and drop duplicated reviews
reviews = reviews[["Review_Text", "Rating"]]
reviews = reviews.drop_duplicates(subset='Review_Text')

让我们使用 seaborn 的countplot打印一个价值计数柱状图,以了解评论的总体情绪。

# Create a bar plot with value counts
sns.countplot(x='Rating', data=reviews)

大多数是正面的,但也有一些负面的评价

2.数据清理和预处理

在开始主题建模之前,我们需要准备文本并进行清洗和预处理。这是所有文本挖掘管道中至关重要的一步,最终模型的性能高度依赖于此。对于该数据集,我们将遵循以下步骤:

  1. 小写每个单词
  2. 将缩写替换为更长的形式
  3. 删除特殊字符和不需要的单词
  4. 使用nltk.WordPunctTokenizer()对每个单词进行标记化我们将从单词或句子的字符串中提取标记。
  5. 使用nltk.stem.WordNetLemmatizer()对每个单词进行词条整理,我们将把单词恢复到它们的字典形式,这样所有具有相似意思的单词将被链接成一个单词。

为了应用所有列出的步骤,我将使用以下函数。然而,为了增加模块化和易于调试,您可以在单独的函数中定义每个任务。

def text_preprocessing(text):

    # Convert words to lower case
    text = text.lower()

    # Expand contractions
    if True:
        text = text.split()
        new_text = []
        for word in text:
            if word in contractions:
                new_text.append(contractions[word])
            else:
                new_text.append(word)
        text = " ".join(new_text)

    # Format words and remove unwanted characters
    text = re.sub(r'https?:\/\/.*[\r\n]*', '', text, flags=re.MULTILINE)
    text = re.sub(r'\<a href', ' ', text)
    text = re.sub(r'&amp;', '', text) 
    text = re.sub(r'[_"\-;%()|+&=*%.,!?:#$@\[\]/]', ' ', text)
    text = re.sub(r'<br />', ' ', text)
    text = re.sub(r'\'', ' ', text) 

    # Tokenize each word
    text = nltk.WordPunctTokenizer().tokenize(text)

    # Lemmatize each word
    text = [nltk.stem.WordNetLemmatizer().lemmatize(token, pos='v') for token in text if len(token)>1]

return text
def to_string(text):
    # Convert list to string
    text = ' '.join(map(str, text))

    return text

# Create a list of review by applying text_preprocessing function
reviews['Review_Clean_List'] = list(map(text_preprocessing, reviews.Review_Text))

# Return to string with to_string function
reviews['Review_Clean'] = list(map(to_string, reviews['Review_Clean_List']))

让我们通过打印一个随机的行来看看新的列。

最后但同样重要的是,在进入下一步之前,我们需要删除停用词。停用词是特定于语言的常用词(即英语中的“the”、“a”和“an”),既不会增加价值,也不会改善对综述的解释,并且往往会在建模中引入偏差。我们将从nltk库中加载英语停用词表,并从我们的语料库中删除这些单词。

因为我们要删除停用词,所以我们可能要检查语料库中最常用的词,并评估我们是否也要删除其中的一些词。这些单词中的一些可能只是经常重复,并没有给意思增加任何价值。

我们将使用藏书库中的Counter来统计字数。

# Import Counter 
from collections import Counter

# Join all word corpus
review_words = ','.join(list(reviews['Review_Clean'].values))

# Count and find the 30 most frequent
Counter = Counter(review_words.split())
most_frequent = Counter.most_common(30)

# Bar plot of frequent words
fig = plt.figure(1, figsize = (20,10))
_ = pd.DataFrame(most_frequent, columns=("words","count"))
sns.barplot(x = 'words', y = 'count', data = _, palette = 'winter')
plt.xticks(rotation=45);

30 个最常用的单词(删除停用词之前)

不出所料,前 30 名中经常出现与迪士尼和公园内容相关的词,如“公园”、“迪士尼”和“迪士尼乐园”。我们将通过将这些词添加到停用词列表中来删除它们。您也可以创建一个单独的列表。

# Load the list of stopwords
nltk.download('stopwords')

stopwords_list = stopwords.words('english')
stopwords_list.extend(['park', 'disney', 'disneyland'])

reviews['Review_Clean_List'] = [[word for word in line if word not in stopwords_list] for line in reviews['Review_Clean_List']]
reviews['Review_Clean'] = list(map(text_as_string, reviews['Review_Clean_List']))

# Join all word corpus
review_words = ','.join(list(reviews['Review_Clean'].values))

# Count and find the 30 most frequent
Counter = Counter(review_words.split())
most_frequent = Counter.most_common(30)

# Bar plot of frequent words
fig = plt.figure(1, figsize = (20,10))
_ = pd.DataFrame(most_frequent, columns=("words","count"))
sns.barplot(x = 'words', y = 'count', data = _, palette = 'winter')
plt.xticks(rotation=45);

30 个最常用的单词(删除停用词和一些常用词后)

奖金

让我们使用之前创建的review_words创建预处理文本语料库的词云。☁️️ ️️☁️ ☁️

# Generate the word cloud
wordcloud = WordCloud(background_color="white",
                      max_words= 200,
                      contour_width = 8,
                      contour_color = "steelblue",
                      collocations=False).generate(review_words)

# Visualize the word cloud
fig = plt.figure(1, figsize = (10, 10))
plt.axis('off')
plt.imshow(wordcloud)
plt.show()

文本预处理后的 Wordcloud

3.词汇袋

为了使用文本作为机器学习算法的输入,我们需要以数字格式呈现它。单词袋是一个向量空间模型,表示单词在文档中的出现。换句话说,单词袋将每个评论转换成单词计数的集合,而不考虑顺序或意义的重要性。

我们将首先使用 Gensim 的corpora.Dictionary创建字典,然后使用dictionary.doc2bow创建单词包。

# Create Dictionary
id2word = gensim.corpora.Dictionary(reviews['Review_Clean_List'])

# Create Corpus: Term Document Frequency
corpus = [id2word.doc2bow(text) for text in reviews['Review_Clean_List']]

通过创建字典,我们用一个整数 id(又名 id2word)映射每个单词,然后我们在每个字典上调用 doc2bow 函数来创建一个(id,frequency)元组列表。

4.确定主题的数量

决定主题建模的主题数量可能很困难。由于我们已经初步了解了上下文,确定建模主题的数量不会太离谱。但是,如果这个数字太大,那么模型可能无法检测到实际上更广泛的主题,如果这个数字太小,那么主题可能有大量重叠的单词。因为这些原因,我们会使用话题连贯性评分。

from gensim.models import CoherenceModel

# Compute coherence score
number_of_topics = []
coherence_score = []
for i in range(1,10):
  lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus,
                                           id2word=id2word,
                                           iterations=50,
                                           num_topics=i)
  coherence_model_lda = CoherenceModel(model=lda_model, 
                                       texts=reviews['Review_Clean_List'], 
                                       dictionary=id2word, 
                                       coherence='c_v')
  coherence_lda = coherence_model_lda.get_coherence()
  number_of_topics.append(i)
  coherence_score.append(coherence_lda)

# Create a dataframe of coherence score by number of topics 
topic_coherence = pd.DataFrame({'number_of_topics':number_of_topics,
                                'coherence_score':coherence_score})

# Print a line plot
sns.lineplot(data=topic_coherence, x='number_of_topics', y='coherence_score')

主题数量的连贯性得分

由于使用四个主题获得了非常高的一致性分数(0.3429),并且从四个主题到五个主题没有大的跳跃,所以我们将使用四个主题构建我们的 LDA 模型。然而,需要注意的是,我们将相干超参数定义为coherence='c_v',但也有其他选项,如‘u _ mass’,‘c _ UCI’,‘c _ npmi’,验证它们将是最佳实践。(详细信息请查看 Gensim 的文档。)

5.基于 LDA 的主题建模

潜在狄利克雷分配是一种流行的用于主题建模的统计无监督机器学习模型。它假设每个主题由单词组成,每个文档(在我们的例子中是每个综述)由这些单词的集合组成。因此,LDA 试图找到最能描述每个主题的词,并匹配这些词所代表的评论。

LDA 使用狄利克雷分布,这是贝塔分布的一种推广,为两个或更多结果(K)的概率分布建模。例如,K = 2 是贝塔分布的狄利克雷分布的特例。

狄利克雷分布用 Dir( α) 表示,其中 α < 1(对称)表示稀疏性,这正是我们想要如何呈现主题和词以进行主题建模。正如你在下面看到的,使用 α < 1,我们在边/角上有彼此分开的圆(换句话说是稀疏的),而使用 α > 1,我们在中心有彼此非常接近并且难以区分的圆。你可以把这些圈想象成话题。

LDA 使用两种狄利克雷分布,其中

  • k 是主题的数量
  • M 表示文件的数量
  • N 表示给定文档中的字数
  • Dir(alpha)是每文档主题分布的 Dirichlet 分布
  • Dir(beta)是每主题单词分布的狄利克雷分布

然后,它对每个单词位置使用多项式分布

  • 为文档 I 中的第 j 个单词选择一个题目;z_
  • 为特定单词选择一个单词;w_

文献中 LDA 的平板标记

如果我们把所有的片段放在一起,我们得到下面的公式,它描述了具有两个狄利克雷分布和多项式分布的文档的概率。

文件的概率

理论够了!🤓让我们看看如何使用 Gensim 中的ldaModel在 Python 中执行 LDA 模型。

 # Define the number of topics 
n_topics = 4

# Run the LDA model
lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus,
                                           id2word=id2word,
                                           num_topics=n_topics, 
                                           random_state=100,
                                           update_every=1,
                                           chunksize=10,
                                           passes=10,
                                           alpha='symmetric',
                                           iterations=100,
                                           per_word_topics=True)

让我们来探究每个主题中出现的单词及其相对权重。

for idx, topic in lda_model.print_topics(-1):
    print("Topic: {} Word: {}".format(idx, topic))

每个主题中出现的单词及其相对权重

我们可以看到,一个话题与排队等待有关;下一个和参观、住宿、美食有关;还有一个跟酒店、门票、村庄有关;最后一个与魔术、爱情和突出巴黎和佛罗里达的节目有关。

6.用 pyLDAvis 可视化

pyLDAvis 是一个基于 web 的交互式可视化工具,用于可视化主题模型。您可以使用pip install pyldavis轻松地在 python 中安装,并使用enable_notebook().在 Python 笔记本上运行可视化

# Import and enable notebook to run visualization
import pyLDAvis.gensim_models
pyLDAvis.enable_notebook()

vis = pyLDAvis.gensim_models.prepare(lda_model, 
                                     corpus, 
                                     dictionary=lda_model.id2word)
vis

主题 1 的 pyLDAvis 表示(λ = 1)

在左侧,我们可以看到每个主题在主题间距离图上表示为一个气泡(多维标度到 x 和 y 轴上),如果我们单击一个主题,可视化会自动调整到该特定主题。气泡之间的距离代表主题之间的语义距离,如果气泡重叠,这意味着有很多常用词。在我们的例子中,主题被很好地分开,没有重叠。此外,主题气泡的面积表示每个主题的覆盖范围,主题 1 覆盖了大约 50%的评论,而其他主题共享几乎相等的数量。

右侧的可视化显示了每个主题的前 30 个最相关的词。蓝色阴影条表示该词在所有评论中的出现,红色条表示该词在所选主题中的出现。在它的顶部,您可以看到一张调整相关性度量λ(其中 0 ≤ λ ≤ 1)的幻灯片,λ = 1 调整每个主题中最有可能出现的单词的可视化,λ = 0 调整仅特定于所选主题的单词。

让我们检查话题 2👀

主题 2 的 pyLDAvis 表示(λ = 1)

主题 3👀

最后是主题 4👀

结论

在本文中,我们探讨了如何从文本数据中检测主题和关键字,以便在不需要扫描整个文本的情况下理解内容。我们讨论了如何应用预处理,包括清理文本、词汇化和删除停用词&为机器学习准备数据的最常用词。我们还创建了一个单词云,帮助我们可视化整体内容。为了找到迪士尼乐园评论数据集的主题,我们使用了潜在狄利克雷分配(LDA),这是一种用于主题建模的概率方法,假设主题可以表示为文本语料库中单词的分布。每个文档(在我们的案例回顾中)可以展示不止一个不同比例的主题。比例最高的主题被选为该文档的主题。我们通过使用 coherence score 来定义主题的数量,最后使用 pyLDAvis 来可视化我们的主题和关键词。

LDA 是一种相对简单的主题建模技术,多亏了 pyLDAvis,您可以向不熟悉该技术范围的其他人展示结果。可视化也有助于描述功能原理,并使主题模型更易于解释和说明。

虽然我们只讨论了 LDA 技术,但是还有许多其他技术可以用于主题建模。举几个例子,(LSA)非负矩阵分解Word2vec 。如果你对这个话题感兴趣,我强烈建议你也探索一下这些方法,它们都有不同的优点&缺点,这取决于用例。

我希望您喜欢阅读和学习主题建模,并发现这篇文章很有用!✨

喜欢这篇文章吗? 成为会员求更!

你可以在这里 阅读我的其他文章和* 关注我上媒*如果有任何问题或建议,请告诉我。✨

参考

  1. 迪士尼乐园查看来自 Kaggle 的数据集。许可证: CC0:公共领域
  2. 标题照片由布拉德利·辛格尔顿Unsplash 上拍摄
  3. 所有其他图片均由作者提供

使用 Keras 和 TensorFlow 讲解图像分类器的 Grad-cam 应用实践教程

原文:https://towardsdatascience.com/hands-on-tutorial-for-applying-grad-cams-for-explaining-image-classifiers-using-keras-and-cbdcef68bb89

了解如何使用 Keras 和 TensorFlow 应用 Grad-CAM 来解释基于深度学习的图像分类器

解释图像分类器的 Grad-CAM 方法的输出(作者图片,基本图片来源: Unsplash

当应用于图像和文本等非结构化数据时,经典的机器学习(ML)算法与深度学习(DL)算法相比效率不高。由于与经典 ML 中的手动特征工程相比,DL 中的自动特征提取的好处,DL 算法在模型精度方面更有效,因此更受欢迎。然而,这些模型比经典的 ML 模型更复杂,更难解释。因此,对于像图像这样的非结构化数据的 DL 模型来说,可解释性总是一个问题。逐层相关性传播 ( LRP )是一种可解释方法,它突出图像的相关区域来解释模型预测。

如果你不太熟悉可解释的人工智能(XAI)概念,我强烈建议观看我过去在 2021 年 APAC 人工智能加速器节上发表的关于 XAI 的演讲:

你也可以浏览我的书 应用机器学习可解释技术 并看看代码库以获得对其他 XAI 方法的实际接触。

https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

如果你想得到关于这本书的详细反馈,这个视频可能对你有用:

在这篇文章中,我将提到一种叫做 Grad-CAM 的流行 LRP 技术的实际应用,用于解释图像分类器。我还将介绍使用 Keras 和 TensorFlow 应用 Grad-CAMs 的一步一步的代码教程。

现在,让我们开始吧!

LRP 简介

为了解释 DL 模型,LRP 是最突出的方法之一。直观地说,这种方法利用网络中的权重和前向传递神经激活,通过网络中的各个层将输出传播回输入层。因此,在网络权重的帮助下,我们可以将对最终模型输出贡献最大的数据元素(图像中的像素和文本数据中的单词)可视化。这些数据元素的贡献是通过网络层传播的相关性的定性度量。此外,对于具有多层的深度神经网络,当通过层间梯度流动过程的信息流保持一致时,学习就发生了。因此,为了解释任何深度学习模型,LRP 方法允许我们可视化网络不同层中的激活的或最有影响力的数据元素,并定性地检查算法的功能。

https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

什么是 Grad-CAM?

类激活图(CAMs) 是用于解释深度学习模型的可视化方法。在这种方法中,模型预测的类别分数被追溯到最后的卷积层,以突出图像中的有区别的感兴趣区域,这些区域是特定于类别的,甚至不是其他计算机视觉或图像处理算法所通用的。 Gradient CAM 或俗称 Grad-CAMs 结合了导向反向传播和 CAM 的效果,在不突出颗粒像素重要性的情况下,突出类别区分感兴趣区域。但是 Grad-CAM 可以应用于任何 CNN 架构,不像 CAM 可以应用于在预测层之前对来自卷积层的输出特征图执行全局平均汇集的架构。为了更详细地了解 Grad-CAM 过程,您可以看看这篇研究论文 Grad-CAM:通过基于梯度的定位从深度网络进行可视化解释,Ramprasaath 等人。艾尔—https://arxiv.org/abs/1610.02391

引导 Grad-CAM 的架构图(来源: Grad-CAM:通过基于梯度的定位,来自深度网络的视觉解释,Ramprasaath 等人。艾尔—https://arxiv.org/abs/1610.02391

使用 Keras 和 TensorFlow 应用 Grad-cam

现在来看这篇文章有趣的部分:学习如何应用 Grad-CAMs!我们将使用 Keras 和 TensorFlow 来应用 Grad-cam 来解释预训练的图像分类器。您将需要以下 Python 框架来应用 Grad-CAMs,这些框架可以使用 Python pip 安装程序进行安装:

**!**pip install --upgrade numpy matplotlib tensorflow

让我们从用 Python 加载所需的模块开始。我会推荐使用本地 Jupyter 笔记本或 Google colab 来运行这个代码教程。

**import** numpy **as** np
**import** matplotlib.pyplot **as** plt
**import** matplotlib.cm **as** c_map
**from** IPython.display **import** Image, display
**import** tensorflow **as** tf
**from** tensorflow **import** keras
**from** tensorflow.keras.applications.xception **import** Xception, preprocess_input, decode_predictions
**from** tensorflow.keras.preprocessing **import** image
**import** os

我们将使用 TensorFlow 和 Keras 框架在 ImageNet 数据集上获得一个预训练的网络,并在从来源:https://images . unsplash . com/photo-1615963244664-5b 845 b 2025 ee?IX lib = r b-4 . 0 . 3&ixid = mnwxmja 3 fdb 8 mhxwag 90 by 1 wywdlfhx 8 fgvufdb 8 fhx 8&auto = format&fit = crop&w = 464&q = 80。更多使用 Keras 和 TensorFlow 的例子请访问:【https://keras.io/examples/】T4。

model_builder **=** Xception
preprocess_input **=** preprocess_input
decode_predictions **=** decode_predictions
IMG_SIZE **=** (299, 299)
last_conv_layer **=** "block14_sepconv2_act"*# The local path to our target image*
image_path **=** keras**.**utils**.**get_file(
    "tiger.jpg", "[https://images.unsplash.com/photo-1615963244664-5b845b2025ee?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=464&q=80](https://images.unsplash.com/photo-1615963244664-5b845b2025ee?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=464&q=80)"
)

display(Image(image_path))

来源推断图像(来源: Unsplash

加载图像后,您需要应用预处理层。由于我们将使用来自 Keras 和 TensorFlow 的预训练异常模型,我们将需要应用相同的预处理。

**def** vectorize_image(img_path, size):
    '''
    Vectorize the given image to get a numpy array
    '''
    img **=** image**.**load_img(img_path, target_size**=**size)
    array **=** image**.**img_to_array(img)
    array **=** np**.**expand_dims(array, axis**=**0) *# Adding dimension to convert array into a batch of size (1,299,299,3)*
    **return** array

现在,让我们将预训练的模型应用于我们预处理的图像,并查看预测。

vectorized_image **=** preprocess_input(vectorize_image(image_path, size**=**IMG_SIZE))
model **=** model_builder(weights**=**"imagenet")
model**.**layers[**-**1]**.**activation **=** **None** *# Removing the last layer as it is the softmax layer used for classification*

model_prediction **=** model**.**predict(vectorized_image)
print(f"The predicted class is : {decode_predictions(model_prediction, top**=**1)[0][0][1]}")

这是我们得到的输出:

The predicted class is : tiger

因此,我们的模型正确地预测了我们的推断图像为老虎。现在,让我们来理解使用 Grad-cam 进行预测背后的基本原理。

建筑 Grad-CAM 热图

我们将构建一个 Grad-CAM 热图可视化工具来突出显示模型中有影响力的超像素。

**def** get_heatmap(vectorized_image, model, last_conv_layer, pred_index**=None**):
    '''
    Function to visualize grad-cam heatmaps
    '''
    gradient_model **=** tf**.**keras**.**models**.**Model(
        [model**.**inputs], [model**.**get_layer(last_conv_layer)**.**output, model**.**output]
    )

    *# Gradient Computations*
    **with** tf**.**GradientTape() **as** tape:
        last_conv_layer_output, preds **=** gradient_model(vectorized_image)
        **if** pred_index **is** **None**:
            pred_index **=** tf**.**argmax(preds[0])
        class_channel **=** preds[:, pred_index]

    grads **=** tape**.**gradient(class_channel, last_conv_layer_output)
    pooled_grads **=** tf**.**reduce_mean(grads, axis**=**(0, 1, 2))
    last_conv_layer_output **=** last_conv_layer_output[0]
    heatmap **=** last_conv_layer_output **@** pooled_grads[**...**, tf**.**newaxis]
    heatmap **=** tf**.**squeeze(heatmap)
    heatmap **=** tf**.**maximum(heatmap, 0) **/** tf**.**math**.**reduce_max(heatmap) *# Normalize the heatmap*
    **return** heatmap**.**numpy()

plt**.**matshow(get_heatmap(vectorized_image, model, last_conv_layer))
plt**.**show()

当我们将热图应用于预训练模型的第四卷积层时,我们得到的输出热图图像如下:

Grad-CAM 热图来自推理老虎图片(来源:作者)

但是这并不能告诉我们什么,除非我们把这个图像叠加到我们的推理图像上。因此,让我们使用下面的代码片段来看看如何做到这一点:

**def** superimpose_gradcam(img_path, heatmap, output_path**=**"grad_cam_image.jpg", alpha**=**0.4):
    '''
    Superimpose Grad-CAM Heatmap on image
    '''
    img **=** image**.**load_img(img_path)
    img **=** image**.**img_to_array(img)

    heatmap **=** np**.**uint8(255 ***** heatmap) *# Back scaling to 0-255 from 0 - 1*
    jet **=** c_map**.**get_cmap("jet") *# Colorizing heatmap*
    jet_colors **=** jet(np**.**arange(256))[:, :3] *# Using RGB values*
    jet_heatmap **=** jet_colors[heatmap]
    jet_heatmap **=** image**.**array_to_img(jet_heatmap)
    jet_heatmap **=** jet_heatmap**.**resize((img**.**shape[1], img**.**shape[0]))
    jet_heatmap **=** image**.**img_to_array(jet_heatmap)

    superimposed_img **=** jet_heatmap ***** alpha **+** img *# Superimposing the heatmap on original image*
    superimposed_img **=** image**.**array_to_img(superimposed_img)

    superimposed_img**.**save(output_path) *# Saving the superimposed image*
    display(Image(output_path)) *# Displaying Grad-CAM Superimposed Image*

superimpose_gradcam(image_path, get_heatmap(vectorized_image, model, last_conv_layer))

瞧啊。我们得到了参考图像的以下叠加热图图像:

用于解释图像分类器的 Grad-CAM 方法的输出(图片由作者提供,基本图片来源: Unsplash

使用 Grad-CAMs 是不是太难了?绝对不行!Keras 和 TensorFlow 使得将这种可解释的技术应用于图像分类器变得更加容易!这是一种非常强大的技术,用于解释复杂的深度学习算法对图像等非结构化数据的工作。虽然这种方法对于初学者来说很难理解。然而,一旦你掌握了它,这是一个非常强大的方法,对模型的可解释性非常有帮助。

希望你喜欢这篇文章!完整的教程笔记本可在:https://github . com/packt publishing/Applied-Machine-Learning-explability-Techniques/blob/main/chapter 02/layer wise % 20 propagation . ipynb获得。我推荐阅读这本书: 【应用机器学习可解释技术】 并探索 GitHub 库以获得更多实际操作的代码示例。

MediumLinkedIn 上关注我,了解更多可解释的 AI 和机器学习。

https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

作者关于 TDS 的其他 XAI 相关文章:

  1. 用于在文本数据上训练的模型的可解释机器学习:将 SHAP 与变压器模型相结合
  2. EUCA——一个有效的 XAI 框架,让人工智能更贴近终端用户
  3. 理解可解释人工智能中使用的 SHAP 和沙普利值的工作原理
  4. 如何用石灰解释图像分类器

https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

参考

  1. Keras Tensorflow 教程示例—https://keras.io/examples/
  2. Grad-CAM:通过基于梯度的定位来自深度网络的视觉解释。艾尔https://arxiv.org/abs/1610.02391
  3. 应用机器学习解释技术
  4. GitHub repo 自《应用机器学习可解释技术》——https://GitHub . com/packt publishing/Applied-Machine-Learning-explability-Techniques/

实践教程:如何提高程序员解决问题的技能

原文:https://towardsdatascience.com/hands-on-tutorial-how-to-improve-your-problem-solving-skills-as-a-programmer-83f0a8d1082f

技术部分是最容易的

奥拉夫·阿伦斯·罗特内在 Unsplash 上的照片

编程最终是解决问题。我们只应用编程语言来表达我们是如何思考问题的,以及我们解决问题的方法。

你能做的最糟糕的事情就是一旦问题出现就开始解决它。这是大多数新手程序员卡住并放弃的地方。回想一下你必须做书面评估的学生时代。通常,试卷(或监考老师)会告诉你有多少时间来计划,应该留出多少时间来写作。编程也是一样。

每个问题都是一系列必须解决的小问题的外衣。一旦你为如何解决问题设计了一个清晰的攻击计划,技术部分总是最容易的。

如果我只有一个小时去砍树,我会花前 45 分钟磨我的斧子。

——亚伯拉罕·林肯。

为了证明这一点,我们将一起解决一个编码问题。编码问题是培养你通过程序思考的能力的好方法。你接触不同类型的问题越多,你解决问题的能力就会显著提高。因此,重要的是你要不断地将自己置于解决新问题的情境中——即使每天只有 15-30 分钟。

问题陈述:字母兰戈利

:本挑战取自hacker rank

给你一个整数 n,你的任务是打印一个 n 大小的字母 Rangoli(Rangoli 是一种基于创造图案的印度民间艺术形式。)

不同大小的字母 rangoli 如下所示:

#size 3

----c----
--c-b-c--
c-b-a-b-c
--c-b-c--
----c----

#size 5

--------e--------
------e-d-e------
----e-d-c-d-e----
--e-d-c-b-c-d-e--
e-d-c-b-a-b-c-d-e
--e-d-c-b-c-d-e--
----e-d-c-d-e----
------e-d-e------
--------e--------

兰戈利的中心有第一个字母表字母 a,边界有字母表字母(按字母顺序排列)。

该函数的输入是一个包含 大小 的单行,它是 rangoli 的大小。您的函数应该返回一个字符串,该字符串由 rangoli 的每一行组成,由换行符(\n)分隔。

#第一步——花时间了解问题

解决任何问题的第一步是理解正在解决的问题。这意味着你能够用自己的话完整地阐述这个问题。

做不到也不要灰心,这是理解过程的一部分。当你遇到一些你不能清楚表达的事情时,这意味着你的理解有差距。如果你想解决这个问题,那么你需要填补空白。

这意味着你必须提问。

当你独自解决一个问题时,你必须问自己更多的问题来充实你不明白的地方——你也可以使用谷歌来更好地了解你对特定部分不明白的地方。如果你正在和一个团队一起工作或咨询某人,那么这是你向他们提问的机会,以填补你理解中的空白。

要点是你必须花时间去完全理解你的问题。从长远来看,这样做会让你受益,并大大简化解决问题的过程。

应用:

鉴于我们的字母兰戈利问题,我们要做的第一件事是理解我们试图解决的问题是什么。以下是我用自己的话表达的方式。

给定指定大小的输入,我们将创建一个返回字母 rangoli 的函数,这是一种来自印度民间的艺术形式,基于模式的创建。

请注意,我清楚地描述了我们期望进入函数的内容,以及期望输出的内容。这是因为,在很高的层面上,我喜欢把解决问题想象成获取某种输入并将其转化为某种输出。目前,映射函数是一个黑盒,但我们的下一步是解构黑盒中发生的事情。

在这一步,我喜欢做的另一件事是用一些自定义输入来绘制自己的示例,以便更好地理解会发生什么。例如,我们知道这是一个字母表 rangoli,字母表只有 26 个字母,但是如果传递的大小大于 26,会发生什么呢?幸运的是,这个问题在简报中得到了回答,但如果不是,我们就必须通过提问来弄清楚会发生什么。

注意 :记住 Python 是切片的,不考虑尾数,所以传递 27 会取前 26 个字母。

这是我画的一个例子:

当 size=4 时的 rangoli 示例图;作者图片

我会画一些来更好地加强我的理解。

#第二步——分解问题

每个问题都是由许多小问题组成的。把一个大问题分解成小问题来解决,会让大问题变得不那么令人畏惧。

当较小的问题得到解决时,需要做的就是将它们连接在一起。如果你仔细考虑每一步的输入和输出,这将导致更大问题的解决。

本质上,我要说的是,在你试图用代码解决问题之前,你应该在纸上或白板上解决问题。一定要详细写下步骤,并清楚地了解发生了什么。

应用:

我首先在纸上解决了 rangoli 的问题,方法是研究我在上面的例子中设计的事实。当我弄清楚事实后,我将它们组织成如下步骤:

**# Description of facts for size=4**
- we need to get the first n letters of the alphabet so we need access to the full alphabet
- the center value for the first line is always the nth value and it's padded with "-"; **what's the length of the padding?** 
- the middle line always has the first letter of the alphabet as the middle value and the boundary is always the nth letter
   --> from L-R: the middle line starts at an and works its way back to a then from a it goes back to N.
   --> all the letters have a "-" instead of a space between them
   --> this means the length of all the lines is the length of the middle line; **We must know the length of the middle line before we can draw the other lines. 
-** split the rangoli into halves that is seperated by the middle line. 
- the top line of the upper starts with n in the middle. the next line has n - 1 in the middle and to the left of it is n and to the right of it is n. the next line has n-2 in the middle with the sequence going n-1 then n to the left, and n-1 then n to the right. The next line has n-3 in the middle with the sequence going n-2, n-1, then n to the left and n-2, n-1, then n to the right. Let's sketch this. 

兰戈利上半部分的设计草图;作者图片

- we can seperate the upper half into halves again by drawing a line down the center. This would mean we have a left and a right side

将兰戈利上半部分的设计草图分成两半;作者图片

- the left have is going from n to n-i in reverse order and the right side is going from n-i to n
- the lower half is literaly the same thing as the upper half but its flipped upside down. 

现在我已经有了事实,我可以设计步骤了。

**The steps
1\. store the letters in the alphabet
2\. get the first n letters of the alphabet
3\. draw the middle line
4\. get the length of the middle line
5\. draw the left side of the upper half and join it to the right side - join the values together by "-" and center n-i and make sure the line is length of middle with the other values made up with "-". 
6\. flip the upper half upside down to draw the bottom half
7\. put it all together**

我把这个问题分解成 7 个小问题,没有使用任何技术术语。下一步是弄清楚如何在技术上实现每一步。

这意味着仍然有可能更深入地解决这个问题,因为我没有讲太多细节。例如,我刚刚写了''画中间的线。'我如何画出中间的线?我没有深入研究这个解决方案,因为我以前解决过类似的问题,所以我对如何绘制中间线有一个清晰的想法(即,要绘制中间线,您必须用“-”符号将前 n 个字母的倒数连接到前 n 个字母(不包括 a)。

如果当你像这样写出来的时候,你不确定如何做某些步骤,那么不要害怕花费额外的时间来进一步分解如何用伪代码实现每个步骤。

#第 3 步——执行

现在你已经在纸上解决了这个问题。你所要做的就是实现你写在纸上的解决方案,但是把它翻译成代码。

这就是你的编程语言知识发挥作用的地方。根据您的环境,您可以使用 Google 方法来做某些事情,例如,如何反转字符串或如何获取字符串的前 n 个字母。

既然你已经有了解决问题的框架,你就不必从第 1-7 步开始解决问题。从最简单的步骤开始,获得一些快速的胜利。

当你获得胜利后,再回到你觉得更有挑战性的问题上来。一旦你解决了所有这些问题,然后把它们放在一起,你就有了你的解决方案。

应用:

以下是我如何解决问题的小部分:

def print_rangoli(n): 
 **# step 1 - store letters of the alphabet** alphabet = "abcdefghijklmnopqrstuvwxyz"

   **# step 2 - get the first n letters of the alphabet**
   first_n = alphabet[:n]

   **# step 3 - draw the middle line**
   middle = "-".join(first_n[::-1] + first_n[1:]) **# step 4 - get the length of the middle line**
   length_of_middle = len(middle)

我把它分解成一个更小的问题。我创建了一个程序,用我的名字得到了左边和右边。

name = "kurtis"
n = **len**(name)**for** i **in** range(1, n): 
    # left side
    **print**(name[n:n-i:-1])**print**("-"* 10)**for** i **in** range(1, n):
    # right side 
    **print**(name[n-i:n])"""
s
si
sit
sitr
----------
s
is
tis
rtis
urtis
"""

现在我要做的就是用“-”将这些值连接在一起,并将中间值(n-i)居中。确保该线与中间线的长度相同,其他值由“-”组成。

name = "kurtis"
n = **len**(name)middle = "-".join(name[::-1] + name[1:])**for** i **in** range(1, n): 
    # left side
    **print**("-".join((name[n:n-i:-1] + name[n-i:n]).center(**len**(middle), "-")))"""
----------s----------
--------s-i-s--------
------s-i-t-i-s------
----s-i-t-r-t-i-s----
--s-i-t-r-u-r-t-i-s--
"""

下一步是将这个解决方案转化为我们问题的代码:

def print_rangoli(n): 
 **# step 1 - store letters of the alphabet** alphabet = "abcdefghijklmnopqrstuvwxyz"

   **# step 2 - get the first n letters of the alphabet**
   first_n = alphabet[:n]

   **# step 3 - draw the middle line**
   middle = "-".join(first_n[::-1] + first_n[1:])

   **# step 4 - get the length of the middle line**
   length_of_middle = len(middle)

   **# step 5 - draw upper half**
   **for** i **in** range(1, n):    
       **print**("-".join((first_n[n:n-i:-1] + first_n[n-i:n]).center(length_of_middle, "-"))) **# step 6 - rotate the upper half**
   **for** i **in** range(n, 0, -1): # <-- rotation happens here
       **print**("-".join((first_n[n:n-i:-1] + first_n[n-i:n]).center(length_of_middle, "-")))

第 7 步是把它们放在一起,这意味着向它传递一个值。让我们给我们的函数传递一个大小为 4 的值,看看它是否与我们上面画的模式相匹配。

print_rangoli(n=4)"""
------d------
----d-c-d----
--d-c-b-c-d--
d-c-b-a-b-c-d
--d-c-b-c-d--
----d-c-d----
------d------
"""

问题解决了。

#第 4 步——反思

解决一个问题有几种方法;没人说我目前对这个问题的解决方案是最好的解决方法。这意味着现在是一个很好的时间来反思我们如何着手解决这个问题,并思考如何使您的解决方案更有效。

我马上意识到的一件事是,我不必手动写出整个字母表。我可以简单地导入string模块并调用ascii_lowercase

**import** string alphabet = string.ascii_lowercase
**print**(alphabet)"""
abcdefghijklmnopqrstuvwxyz **"**

我通常会花这些时间看看其他人的解决方案,看看他们是如何实现同样的事情的。

包裹

编程需要你思考。思考过程的一部分是将问题分解成更小的模块,使它们更容易解决。解决问题的四个步骤是:

  1. 理解问题
  2. 分解问题
  3. 执行
  4. 显示

感谢阅读。

联系我:
LinkedIn
Twitter

如果你喜欢阅读这样的故事,并希望支持我的写作,可以考虑成为一名灵媒。每月支付 5 美元,你就可以无限制地阅读媒体上的故事。如果你使用我的注册链接,我会收到一小笔佣金。

已经是会员了?订阅在我发布时得到通知。

https://kurtispykes.medium.com/subscribe

使用机器学习和 Python 进行实际操作的无监督离群点检测

原文:https://towardsdatascience.com/hands-on-unsupervised-outlier-detection-using-machine-learning-with-python-ec599fe5a6b5

威尔·梅尔斯在 Unsplash 上拍照

以下是如何使用简单的机器学习算法来检测未标记数据集的异常值

数据科学中最丰富和最强大的技术之一是异常检测

这项技术如此吸引人的地方在于“离群值”的定义非常普遍。换句话说,我们可以将数据集的任意集合定义为“离群集合”,并尝试通过使用我们拥有的其他特征来识别它。

当然,检测异常值的一个非常简单的方法是绘制分布图,并提取远离分布中值的值。这种方法的问题是,它意味着您的数据具有类似于高斯分布的分布,但这并不总是正确的。

另一种方法是使用分类方法,并对您的数据应用二元分类算法(异常值/非异常值)。尽管如此,这种方法需要标记的数据。

那么我们能用什么呢?我们可以用高斯过程回归。该模型为您提供了一种回归技术,可输出一个均值和一些与某个概率不确定性相关的预测性边界

让我们开始吧:

1.高斯过程回归

正如我所说,高斯过程回归的假设是,你的数据只不过是一个高斯过程的随机实现,其中这个高斯过程的均值和方差是某个均值函数,方差是某个方差函数。

使用这个制作的图像

这个均值和方差函数都依赖于所使用的内核函数。

使用最多的只是径向基函数(RBF)核:

我制作的图像

l 值给出协方差
的地方,我们添加了一个白噪声内核,它考虑到了您的测量也可能有噪声的事实。

2.代码

2.1 图书馆

这是一篇实践文章,所以让我们开始写代码吧。这就是你需要的:

基本就是 GPR 部分有 Sklearn,matplotlib,numpy 和 pandas

2.2 数据集

我使用的数据集是一个时间序列,我在这里找到了https://www.kaggle.com/arashnic/learn-time-series-forecasting-from-gold-price****。** 数据集将主要用于回归任务,但该方法的实际用途来自我们能够预测的边界。**

我们来导入一下:

并显示一些行:

因为我们的目的只是展示该方法的工作原理,所以让我们使用稍微小一些的数字,并将我们自己限制在数据集的 80%上:

如果我们想应用 GPR 方法,我们有“日期时间对象”的事实是令人不安的。让我们把第 0 天和第 0 天之间的距离看作我们的时间:

让我们绘制日期和新的时间轴(X):

2.3 模型

让我们使用下面的代码来拟合 GPR 模型(可能需要一段时间):

让我们得到的平均值的标准界限:****

让我们将它们转换成两个 dataframe 对象:

让我们画出结果:

我们之前已经表明,原始时间采样是不均匀的,并且它也反映在我们的较小部分数据中。这就是为什么在最低的图中,GPR 方法不太能够识别方差并且很可能高估它( 说到底,如果你的数据点很少,你怎么能说一个新的是异常值呢? )

2.4 异常值检测

我们在前面两个图中设置的阈值相当大(99.7%置信区间)。由于这个原因,我们可以说,在这个边界之外的一切可能是我们过程的异常(或异常值)

让我们创建一个新列,说明“值”是否超出了每行的边界。

让我们画出如此定义的异常值:

有趣的是,我们能够检测出异常值是大于上边界还是小于下边界的异常值。换句话说,我们能够检测出黄金价格是高于我们的预期还是低于我们的预期:

给你:

3.结论

这个想法看起来简单而天真,但是当定制内核函数时,它实际上会变得非常复杂和有趣(假设对我们正在考虑的系统有更精确的理解)。

强有力的想法是,您可以在没有任何标签的情况下分析系统的行为,并通过这样做来检测异常值。

我希望这篇文章是有趣和鼓舞人心的。如果是这样,你想讨论一下,或者你有什么问题,请给我发邮件:*或者在LinkedIn上加我。*****

再见:)

更难、更好、更快、更轻的深度学习,具有直接反馈一致性

原文:https://towardsdatascience.com/harder-better-faster-lighter-deep-learning-with-direct-feedback-alignment-9e837b076baa

通过随机性和激光提高深度学习效率的温和指南

托拜厄斯·科奈尔在 Unsplash 上的照片

在这篇文章中,我们将谈论自从我发现深度学习以来,我所面临的最有趣的主题之一:直接反馈对齐(DFA)。这种方法是标准深度学习训练方法(反向传播)的一种令人难以置信和令人难以置信的替代方法,同时允许更有效的训练。在这篇文章结束时,你会明白混合神经网络,激光和随机性可以提供更多的力量!

这篇文章不是神经网络的介绍。尽管我们将对神经网络背后的数学做一个简要的回顾,但它是为了共享符号并介绍反向传播和 DFA 之间的区别。如果你想在深入研究之前了解更多关于神经网络和深度学习的知识,你可以阅读这篇文章

神经网络 101 概述

神经网络被广泛使用,因为它们能够很好地逼近每一个可能的函数,并且可以扩展到高维空间。它们的主要用途是监督学习,在监督学习中,它们被用于使用数据示例来推断输入和输出之间的关系,我们试图减少预测和目标之间的误差。然而,它们超出了这个范围,可以用来最小化或最大化任何给定的数字目标。

神经网络由相互连接的神经元层组成。这种结构允许使用一系列非线性变换将输入信号处理成输出信号,最终产生全局复变换。给定神经网络执行的转换由其参数(也称为权重和偏差)和激活函数来定义。为了清楚起见,本文中我们只考虑全连通网络。

作者图片

前进传球

现在让我们深入研究它背后的数学原理。

首先,神经网络如何处理输入:

正向传播方案(注意:最后一层的激活不同于其他层)。作者图片

输入被馈送到第一层,在那里使用权重和偏差应用线性变换。然后,通过激活函数修改线性变换的输出,从而允许引入非线性(使用 sigmoid、tanh 或 swish 等函数)或线性修改(如 ReLU 及其变体)。然后,使用激活函数的结果作为下一层的输入,通过其他层重复该过程。

在过程开始时,由于权重已经被随机初始化(这是神经网络中最常见的初始化类型),正向传递的结果输出(以及网络的预测)本质上是随机的。

神经网络的基本问题是:

我如何改变权重,使神经网络做我想要它做的事情?

目标(损失)

知道如何改变权重取决于我们所说的“我希望网络做什么”是什么意思。这个目标的详细说明是通过一个目标函数来完成的,通常称为损失。损失(表示为 L 或 J)是神经网络参数(权重和偏差,表示为θ)的函数,其描述了如何将我们的神经网络的输出与预期输出进行比较。它本质上是对网络错误程度的量化,并因此被最小化。例如,在二进制分类中,一个常见的损失是二进制交叉熵:

二进制交叉熵,其中 m 和 n 是输出单元和小批量索引(符号保持与 DFA 原始论文相同)。作者图片

因此,在这种情况下,目标是最小化这个损失函数,以使网络做我们想要的。我们现在可以将问题更新为:

我如何改变权重,使神经网络最小化损失?

反向传播

损失告诉我们离我们的目标有多远,我们希望有一种方法通过网络传播此信息,将权重(和偏差)更改为一个值,从而导致更低的损失。这意味着揭示每个个体重量对输出的贡献(以及损失),以便能够适当地调整它们。让我们从调整最后一层的权重开始。为此,我们首先想知道我们的损耗(或误差)如何随最后一层的输出而变化:

使用二进制交叉熵和逻辑激活,损耗相对于最后一层激活的导数被简化为输出和标签之间的差。作者图片

现在我们知道了损耗如何随输出层变化,我们想利用这一知识使激活以降低损耗的方式变化。因此,我们想知道如何以这样一种方式改变权重,以引起激活的期望变化:

左:减少损失所需的重量变化,右:重量更新(增加了学习率α)。作者图片

现在,我们将相同的方案应用于其他层:

隐藏层和输入层的权重更新方案。“带点的 o”运算符是 Hadamard 乘积(逐元素乘法)。作者图片

然后…瞧!我们更新了权重(类似的过程也适用于偏差)以减少损失。我们现在可以对新的示例重复该过程,以逐渐降低损失,直到收敛。

那么反向传播有什么问题呢?

尽管这一过程可行,但也并非没有缺陷:

  • 反向传播是一个连续的过程:在计算前一层的梯度之前,我们需要计算最后一层的梯度,然后需要计算前一层的梯度,等等。对于更深的网络,这使得过程非常慢
  • 梯度计算需要矩阵转置:这是一种昂贵的计算(具有 O(n^2 的复杂性),并且需要大量内存。对于较大的网络,这可能很快成为一个问题。

另一个问题,根据原始论文的作者,问题不太大但仍然相关,就是反向传播不是“生物学上合理的”。这是因为在真实的神经元中,一致认为没有信号反向传播。

反向传播学习算法是强大的,但是需要生物学上难以置信的单个突触权重信息的传输。对于反向传播,神经元必须知道彼此的突触权重。[……]在计算机上,在正向和反向计算中使用突触权重很简单,但大脑中的突触单向传递信息

来源 :随机反馈权重支持深度神经网络中的学习,T. P. Lillicrap,D. Cownden,D. B. Tweed,C. J. Akerman,2014

我们不打算在本文中讨论这种说法的真实性,但我们仍然会注意到,这种信念导致了旨在更具生物学合理性的方法的诞生。思路是,如果我们更接近地模仿大脑,我们将有更好的方法,因为大脑比现有的方法更有效。其中一种更符合生物学原理的方法是我们今天感兴趣的。

那么,我们能解决反向传播的缺陷吗?

直接反馈校准

让我们从反向传播开始,在没有顺序计算和矩阵转置的情况下构造我们的梦更新。我们不在乎它是否有意义…现在还不在乎。

从反向传播(BP)到 DFA 的第一层更新修改。图片作者。

为了消除对前一层的依赖性,并因此消除顺序性以允许并行计算,我们使所有层使用相同的反馈:我们将跨所有层使用最后一层的误差(在上面的等式中表示为 e ),而不是使用损耗相对于前一层的激活的梯度(上面的等式中的δ2)。
然后,为了移除矩阵转置,我们用适当大小的固定随机矩阵替换转置的权重矩阵。没有转置计算来运行每一个更新了,只是生成一个随机矩阵每一层,并使用它进行所有的计算。

瞧,我们有一个表达式,它不需要任何顺序计算,因为各层之间没有依赖关系,一旦我们计算了最后一层的误差,我们就可以同时计算所有其他层的更新。我们还删除了矩阵转置,这将进一步加速计算!这种更新称为直接反馈校准(DFA):

与同时计算几个示例的更新但仍以顺序方式进行的并行化不同,DFA 同时处理几个示例,同时更新所有层。红色是第一批,蓝色是第二批,箭头表示不同输入的向前和向后传递。作者图片,灵感来自https://slideplayer.com/slide/12651467/

DFA 是类似技术家族的一部分:

不同反馈校准方法的表示。来源:直接反馈对齐提供深度神经网络中的学习,Arild nkland,2016 年

  • 反馈对准是该过程的第一步,仅去除矩阵转置,但保留反向信号。
  • 直接反馈调整,我们已经讨论过了。
  • 间接反馈对齐,它消除了换位,并将最后一层的误差直接传播到第一层,然后继续向前传播。这允许使用单个随机矩阵而不是每层一个矩阵,从而节省存储器。实际上,这个版本没有 DFA 有趣,除非你的内存很紧张,所以我们不会关注它。

深度魔法

但是等一下…有了这个“更好地更新”我们基本上已经破坏了这个过程中的反向传播,不是吗?我们的新更新如何允许训练神经网络?随机矩阵如何在有意义的更新中发挥作用?

这是一个非常好的问题!首先,让我们看看它与反向传播有何不同:

我们可以看到,尽管进行了修改,DFA 仍然与反向传播(BP)结果相匹配。来源:直接反馈对齐提供深度神经网络中的学习,Arild nkland,2016

我们可以看到,在几个深度学习任务上,DFA 匹配甚至优于 BP 的结果。来源:现代深度学习任务和架构的直接反馈校准量表,j .劳奈、I .里坡、f .博尼法斯和 f .克尔扎卡拉,2020

令人吃惊不是吗?

我们获得了与 BP 类似的结果(更好的结果会令人震惊,因为我们只是使信号变得更糟),同时允许更简单的计算。我们可以更快地得到相同的结果!

但是…怎么做?

太好了,但是……如何?让我们试着理解为什么我们看似破碎的更新仍然为我们的网络传递着一个有意义的信号。

原论文的作者解释说,网络“学习如何学习”。Mhhh,我们见过更清晰的。他们指出,由于反馈现在是一个固定的和随机修改的误差,前馈权重必须自己适应。反馈不再是明确的,而是隐含的。

网络学习如何学习——它逐渐发现如何使用 B(随机矩阵),然后允许有效地修改隐藏单元。起初,对隐藏层的更新没有帮助,但通过改变 W 的隐式反馈过程,它们很快得到改善,使得 eT WBe > 0。为了揭示这一点,我们绘制了由反馈对齐和反向投影规定的隐藏单元更新之间的角度,最初角度平均约为 90°。但随着算法开始采取更接近反向投影的步骤,它们很快就会缩小。h 的这种排列意味着 b 已经开始像 W^T 一样行动。因为 b 是固定的,所以这种排列是由前向权重 w 的变化驱动的。这样,随机反馈权重开始向网络深处的神经元传输有用的教学信号。**

来源:随机反馈权重支持深度神经网络中的学习,T. P. Lillicrap、D. Cownden、D. B. Tweed 和 C. J. Akerman,2014 年

让我们试着解释一下,好吗?基本上,信号在有意义的信息方面要差得多,然而,更新方向大致是正确的,尽管如此,允许学习。更新方向与反向传播大致相同,因此称为“对齐”。

DFA 和 BP 更新之间的角度。随着训练的进行,DFA 的更新几乎与 BP 的更新一致。来源:随机反馈权重支持深度神经网络中的学习,T. P. Lillicrap、D. Cownden、D. B. Tweed 和 C. J. Akerman,2014 年

DFA 的更新围绕真实 BP 更新“振荡”。

直觉

让我们尝试建立一些关于为什么会发生这种情况的直觉(这种直觉大多来自 Yannic Kilcher 的视频,关于这篇文章的视频带有我自己理解的包装)。

即使反向传播的信号被随机矩阵调制,它也不会从误差中去除所有信息。这是由于向量(在我们的例子中是误差 e)乘以一个随机矩阵来表示一个保持角度和距离的投影的性质(为什么会发生这种情况与 Jonhson-Lidenstrauss 引理有关,但我不能 100%确定为什么会发生这种情况,所以我们将在本文中假设它是正确的)。换句话说,通过将我们的信号乘以随机矩阵,我们只是应用了随机旋转,而没有其他修改。

让我们试着从最后一层开始想象。为了举例,我们将假设在一个分类问题中有 3 个可能的类别:c1、c2 和 c3。我们的网络对每个示例(y hat)进行预测,更新告诉我们应该在哪个方向上改变多少权重,以正确地将该示例归属于其类。换句话说,我们希望将预测(y hat,不同类别的概率向量,例如[0.7,0.1,0.2])与正确的类别(例如 c1:[1,0,0])对齐。在这种情况下,要进行的修改将是[0.3,-0.1,-0.2]。

表示将预测(y hat)正确映射到其类(此处:c1)的更新。作者图片

现在对于前面的层,我们必须处理随机乘法。这意味着我们的坐标系被随机旋转,同时保持角度和距离不变。在这个系统中,误差不传达我们应该如何修改预测以使其更接近目标,而是传达如何使其更接近目标的一些随机旋转。

随机矩阵乘法使更新随机旋转,从而不再处于原始方向。作者图片

从单个例子的角度来看,这是不好的,因为更新似乎朝着一个随机错误的方向进行。然而,如果我们考虑多个示例,由于旋转保持不变,属于同一类的示例仍将被拉近,因为它们将被投影到同一旋转的类上。结果,传播的信号不允许指定权重应该被更新的绝对方向。然而,我们仍然可以用相对论的方式做到这一点:不是每次更新都在正确的绝对方向上移动权重,而是网络学习将应该靠近的例子聚集在一起。从某种意义上来说,这可以归结为对示例进行聚类,然后对聚类进行分类,而不是单独对它们进行分类。

隐藏层过程的表示:相同类的例子(绿色+蓝色和绿色+红色)被分组到相同的随机投影类上。作者图片

换句话说,我们确实传播了错误,但是我们没有传播它应该如何解决最终任务。我们只宣传例子应该如何分组在一起。这使得最后一层对示例进行分类的任务大大简化了。为了证实这一点,让我们看看 BP 和 DFA 通过网络各层对输入到网络的示例的内部表示进行比较。

来源:直接反馈对齐提供深度神经网络中的学习,Arild nkland,2016

查看这些表示证实了这种“聚类”方法导致了与 BP 构建的表示类似的结果。换句话说,我们以不同且更简单的方式实现了相同的结果,因为看起来隐藏层不需要显式地将示例映射到空间的特定部分,它们只需要对它们进行聚类。隐藏层构造的变换允许在两种方法中轻松分离最后一层。重要的是隐藏的特征,而不是我们获得它们的方式。DFA 是 BP 更新的一个较弱版本,它保留了聚类特性,因此也保留了学习特性。DFA“足够好”可以工作。

既然我们对它的工作原理有了更清晰的直觉,让我们回到它的性能上来。

我为什么要使用 DFA?

正如我们所看到的,对于相似数量的例子,DFA 收敛得和反向传播一样快(就例子而言)。

各种更新机制中的错误减少。来源:随机反馈权重支持深度神经网络中的学习,T. P. Lillicrap,D. Cownden,D. B. Tweed 和 C. J. Akerman,2014

然而,由于缺少转置和并行化所有层更新的能力,使用 DFA 的网络更新在计算上应该比使用反向传播快得多。虽然我们将在后面看到确切的数字,但由于下一点,很难在速度方面比较 DFA 和 BP。

如果 DFA 在保持性能的同时速度更快,那么我们为什么不使用它呢?

自 1986 年以来,反向传播一直存在并被大量研究。基本上,所有现有的深度学习都围绕着它。作者声称,缺乏 DFA 的优化实现以及研究人员和实践者的习惯阻碍了 DFA 的采用。然而,另一个技巧应该有助于 DFA 获胜…

london and south eastern regional library system 伦敦与东南地区图书系统

激光,是的,激光。

到目前为止,我们一直在标准硬件(CPU 或 GPU)上比较 DFA 和 BP。然而,依赖于随机矩阵乘法的 DFA 更新的特异性允许我们利用一个非常有趣的物理现象:动态光散射

动态光散射的示意图。来源: 通过多重光学散射的随机投影:光速下的近似核 ,a .萨阿德、f .卡尔塔基龙、I .卡隆、l .道代特、a .德雷莫、s .盖刚、f .克尔扎卡拉,2015

532nm 的单色激光被望远镜放大,然后照射数字微镜装置(DMD),该装置能够通过振幅调制对光束上的数字信息进行空间编码,如第三节 b 所述。然后,携带信号的光束通过透镜聚焦在随机介质上。这里,介质是一层厚(几十微米)的 T iO2(二氧化钛)纳米粒子(沉积在显微镜载玻片上的白色颜料)。透射光由第二透镜在远侧收集,穿过偏振器,并由标准单色 CCD 摄像机测量。

来源: 通过多重光学散射的随机投影:光速下的近似核 ,a .萨阿德、f .卡尔塔基龙、I .卡隆、l .道代、a .德雷莫、s .盖刚、f .克尔扎卡拉,2015

换句话说:

我们正在以光速计算随机矩阵乘法。

你可能会说这种技术只限于实验室和研究论文…但不,它已经存在了!法国初创公司 LightOn 已经设计并销售了光学处理单元(OPUs ),可以精确地做到这一点(随机矩阵乘法也可以用于其他应用)。

LightOn 成立于 2016 年,与总部位于巴黎的云计算服务提供商 OVH 集团合作,声称某些机器学习任务的性能有所提高。

OPU 使用激光照射到数字微镜装置(DMD) 上,用光对 1 和 0 进行编码,然后通过透镜和随机散射介质组件进行重定向,然后被偏振,并由传统相机读取这允许并行处理非常大的矩阵。可以做的一个操作就是内核分类。通常,DMD 可以处理 1k 乘 1k 数量级的矩阵。****

对于一个名为转移学习的任务, OPU 显示出比基于 GPU 的解决方案快 6 倍的速度和 5 倍的能效。这意味着耗电量减少了 30 倍。另一个基于时间序列分析的基准测试显示,递归神经网络的速度比采用大内存的传统 CPU 快 200 倍

来源:https://www . eenewsanalog . com/en/startup-integrated-optical-processing-within-data-center-2/

总之,这项技术允许更快地运行随机矩阵乘法计算,极大地改善了缩放,并允许更大的输入。

来源:HPC 中的光子协处理器:使用 LightOn OPUs 进行随机数值线性代数,Daniel Hesslow、Alessandro Cappelli、Igor Carron、Laurent Daudet、Raphael Lafargue、Kilian Muller、Ruben Ohana、Gustave Pariente 和 Iacopo 里坡,2021

结论

通过这篇文章,我们发现了反向传播的一种替代方法,它允许通过巧妙的数学技巧,用更简单的计算表达式来近似相同的更新。尽管在传输的信号中不太明确,但是该表达式仍然允许传播重要的信息,从而允许以隐含的方式进行正确的更新。此外,这种计算更新的方式为通过专用硬件大大加速计算打开了大门,专用硬件利用光物理现象以光速进行计算。

总之,一旦我们获得了通用库中的高效实现以及负担得起且易于使用的专用硬件,直接反馈对准必将在计算速度、内存需求以及降低深度学习及其所有应用的能耗方面带来巨大的改进。

感谢您通读了整篇文章。我希望你和我第一次遇到这个算法时一样对它感到惊讶。如果你有一个替代的直觉命题,我会很高兴知道它们。敬请关注更多内容!

资源

扬尼克·基尔彻在 DFA 上的视频:https://www.youtube.com/watch?v=Hdo81GtLC_4&ab _ channel =扬尼克·基尔彻

最初的 FA 和 DFA 论文:随机反馈权重支持深度神经网络中的学习,T. P. Lillicrap,D. Cownden,D. B. Tweed 和 C. J. Akerman,2014

另一篇关于 DFA 的有趣论文:直接反馈对齐提供深度神经网络中的学习,Arild nkland,2016

关于 DFA 性能的后续论文:直接反馈校准适用于现代深度学习任务和架构,j .劳奈、I .里坡、f .博尼法斯和 f .克尔扎卡拉,2020 年

关于动态光散射的论文: 通过多重光学散射的随机投影:光速下的近似核 ,A. Saade,F. Caltagirone,I. Carron,L. Daudet,A. Drémeau,s .盖刚,F. Krzakala,2015

莱顿的作品网站:https://lighton.ai/photonic-computing-for-ai/

特别感谢 Benjamin Farcy 审阅本文。

利用编程技术改进 R 脚本:

原文:https://towardsdatascience.com/harnessing-programming-techniques-to-improve-r-scripts-e28d09fa0489

使用循环和函数自动化重复性任务

图片来自 Pexels 的 Quang Nguyen Vinh

许多 R 用户是从统计学背景而不是编程/软件工程背景进入 R 编程的,他们以前使用过 SPSS、Excel 等软件。因此,他们可能不了解一些可以用来改进代码的编程技术。这可以包括使代码更加模块化,从而更容易发现和解决错误,但也可以用于自动化重复的任务,如制作表格和绘图等。

这篇短文包括一些基本的编程技术,可以用来提高 R 脚本的质量和可维护性。如果你执行的是重复的任务,而这些重复的任务只有很小的不同,那么这也会节省你大量的时间。我们假设您对用 r 编写简单的脚本有基本的了解。

让我们从一个简单的例子开始。假设我们有几个不同小组的数据。在这种情况下,有 3 种动物(老虎、天鹅和獾),我们收集了一些与此相关的数据(某种分数和数值)。

作者图片

我们可以将它作为 CSV 文件读入 R,或者将其重新创建为数据帧,如下所示:

df <- data.frame(group = rep(c("tiger","swan","badger"), 6), 
 score = c(12,32,43,53,26,56,56,32,23,53,24,65,23,78,23,56,25,75), 
 val = c(24,67,32,21,21,56,54,21,35,67,34,23,32,36,74,24,24,74))

我们可以用 r 中的向量来表示值的列表/列。这是通过使用c函数将这些值放在逗号分隔的列表中来实现的,该函数用于将值组合成一个向量。例如数字 1 到 4:

my_list <- c(1,2,3,4)

如果我们通过输入列表的名称来输出列表:

my_list

哪些输出:

[1] 1 2 3 4

我们用它来为列scoreval提供数据框中的值。我们可以对group列做同样的事情,添加 6 批“老虎”、“天鹅”和“獾”。相反,我们使用rep(复制)函数将这些值重复 6 次。

rep(c("tiger","swan","badger"), 6)

数据框中每一列的值的数量需要相同,否则 R 将产生错误。

我们可以用几种方法查看 R 中的数据帧。我们可以输入数据帧的名称:

df

哪些输出:

 group score val
1 tiger    12  24
2 swan     32  67
3 badger   43  32
4 tiger    53  21
5 swan     26  21
6 badger   56  56
7 tiger    56  54
8 swan     32  21
9 badger   23  35
10 tiger   53  67
11 swan    24  34
12 badger  65  23
13 tiger   23  32
14 swan    78  36
15 badger  23  74
16 tiger   56  24
17 swan    25  24
18 badger  75  74

如果你用的是 R studio。查看功能(大写 V)将在新选项卡中打开数据框,并以表格格式显示:

View(df)

“查看”功能的输出。作者图片

您可以通过单击向上/向下箭头对列进行排序。utils包中还有另一个视图功能(包含实用功能),可以这样访问:

utils::View(df)

这将在弹出窗口中打开数据框,如下图所示。当您想要在不切换标签的情况下同时比较代码和数据时,这很有用。这也将显示比其他View功能更多的数据。

“utils”中“View”函数的输出。作者图片

假设现在我们有一些数据,我们想要绘制三个组中每个组的分数和值。

首先我们可以导入一些有用的库。

library(ggplot2)
library(tidyverse)

ggplot2库用于制作出版质量图。tidyverse库有一些有用的功能,可以过滤和传输来自数据集的数据。例如,我们可以从数据帧中选择与特定组相对应的数据,例如“老虎”。

selected_group <- df %>% filter(group == "tiger")

这里,我们将数据%>%从数据帧传输到名为selected_group的变量中,通过选择对应于“tiger”的组值来过滤组名。接下来,我们可以创建一个简单的散点图,如下所示:

plt1 <- selected_group %>% ggplot(aes(x = val, y = score)) +
    geom_point(size=2) +
    labs(x = "Val", y = "Score") +
    ggtitle("Plot of score/val for tiger group")

ggplot包的工作原理是用不同的信息向图表添加图层,如下图所示:

绘制图层。作者图片

这里我们添加了一个美学(aes)来定义 x 和 y 轴的值。

ggplot(aes(x = val, y = score))

然后我们添加点(圆点),设置它们的大小为 2。

geom_point(size=2)

最后,我们添加轴标签:

labs(x = "Val", y = "Score")

还有一个剧情标题:

ggtitle("Plot of score/val for tiger group")

然后,我们可以输出该图:

plt1

显示分数和价值的老虎组图(图片由作者提供)

然后,我们可以简单地剪切和粘贴这些内容,并针对不同的组进行修改:

selected_group <- df %>% filter(group == "tiger")plt1 <- selected_group %>% ggplot(aes(x = val, y = score)) +
    geom_point(size=2) +
    labs(x = "Val", y = "Score") +
    ggtitle("Plot of score/val for tiger group")
plt1selected_group <- df %>% filter(group == "swan")plt2 <- selected_group %>% ggplot(aes(x = val, y = score)) +
    geom_point(size=2) +
    labs(x = "Val", y = "Score") +
    ggtitle("Plot of score/val for swan group")
plt2selected_group <- df %>% filter(group == "badger")plt3 <- selected_group %>% ggplot(aes(x = val, y = score)) +
    geom_point(size=2) +
    labs(x = "Val", y = "Score") +
    ggtitle("Plot of score/val for badger group")
plt3

虽然这样做可行,但是存在不必要的代码重复。想象你有更多的小组,10 个,100 个,更多?这种方法是不可扩展的,任何改变都需要应用于每个图(例如,改变点的大小需要应用于所有图)。理想情况下,您希望尽可能多地重用代码。这减少了维护工作,并扩展了您的代码以处理任何数量的潜在组。

使用循环

改善这种情况的一种方法是使用“循环”。循环是一种编程结构,它允许我们重复一定次数的代码块,或者直到满足特定的条件。为了将代码重复设定的次数,通常使用一个for循环。

首先,我们将创建一个包含 3 个组的名称的向量:

groups <- c("tiger","swan","badger")

接下来,我们可以创建一个从 1 开始重复 3 次的循环(每组一次)。

for(i in 1:3)
{
}

大括号({ })之间的每一行代码重复 3 次。我们还有一个叫做i的循环计数器。每次执行循环内容时,这个值都会自动增加。在编程中,传统的做法是将循环计数器命名为 I,j,k,x,y 等。尽管你可以用任何你喜欢的名字来命名你的循环计数器。

接下来,您需要考虑如何修改原始代码块,使其在循环中工作。哪些位是所有组通用的,哪些位需要更改以反映不同的组?主要的变化在于我们筛选的分组和图表标题。

selected_group <- df %>% filter(group == groups[i])

我们可以在我们的groups向量中改变所选的组,使其被感兴趣的组过滤。循环计数器i可以用来指向从 1 (tiger)开始的向量中不同的组名。接下来,我们可以为标题创建一个变量,并使用paste0函数将文本的标题字符串连接起来,更新它以显示相关组的名称:

group_title <- paste0("Plot of score/val for ", groups[i], "group")

完成的循环图如下所示:

groups <- c("tiger","swan","badger")for(i in 1:3)
{
    selected_group <- df %>% filter(group == groups[i])
    group_title <- paste0("Plot of score/val for ", groups[i], "group")
    plt <- selected_group %>% ggplot(aes(x = val, y = score)) +  
    geom_point(size=2) +
    labs(x = "Val", y = "Score") +
    ggtitle(group_title) print(plt)
}

唯一的变化是使用print功能来显示图表。由于某种原因,如果在循环和函数中没有使用打印功能,则不会显示图形。

使用循环输出的三个图(图片由作者提供)

另一种使其更加健壮的方法是,不要“硬编码”循环应该运行的次数,因为将来组的列表可能会扩展,或者相反,项目会被删除。相反,我们可以使用length函数返回组向量中的项目数。这样,如果从 vector 中添加或删除项目,它将始终工作。

for(i in 1:length(groups))
{
    …
}

我们还可以使用在 groups 列中查找所有唯一组名的功能来更改 vector 中的显式组名。这对于 3 个组来说似乎没什么大不了的,但是再一次考虑这对于更大数量的组和/或更大的数据集来说如何更有用,以确保没有组被遗漏。

这将改变这一点:

groups <- c("tiger","swan","badger")

变成这样:

groups <- unique(df$group)

这实际上返回了数据框的 group 列中所有唯一项的向量,因此您最终会得到一个更健壮的原始版本,它会自动选取数据框中添加/删除的新组。

使用函数

可以进一步改进的另一种方法是将这段代码放入一个函数中。函数允许你模块化你的代码,使得追踪问题、阅读代码以及以一种逻辑的方式将功能组合在一起变得更加容易。代码块可以放在函数中,只在函数被调用时运行(执行)。数据可以传递给函数进行处理,函数也可以返回数据,尽管您不需要向所有函数提供数据,也不是所有函数都返回数据。这方面的一个例子是将一个数字向量传递给一个函数,该函数计算这些数字的平均值,然后返回计算结果。

这里我们创建了一个名为generateGroupScatterPlots的函数,使用变量current_group传入数据帧和感兴趣的组,更新代码以使用我们传入的组。

generateGroupScatterPlots <- function(df, current_group)
{
    selected_group <- df %>% filter(group == current_group)
    group_title <- paste0("Plot of score/val for ", current_group, "group") plt <- selected_group %>% ggplot(aes(x = val, y = score)) +
        geom_point(size=2) +
        labs(x = "Val", y = "Score") +
        ggtitle(group_title) print(plt)
}

该函数在被调用之前不会运行。为了执行这个函数,我们需要调用它的名字并传入任何可能需要的参数。我们调用循环中的函数,传递数据帧和感兴趣的组groups[i]

groups <- unique(df$group)for(i in 1:length(groups))
{
    generateGroupScatterPlots(df, groups[i])
}

当试图利用循环和函数时,人们经常遇到的另一个问题是动态访问数据帧中的列。例如,假设我们想要对包含数字数据的列求和,您通常会通过指定 dataframe 来访问 R 中的列,然后指定用美元符号$分隔的列名:

df$score

然后,我们可以使用打印功能或查看功能之一来查看该列:

utils::View(df$score)

但是我们如何修改它来使用一个变量呢?在 R 中做同样事情的另一种方法是使用列表符号,它由一组双方括号组成:

df[["score"]]

这将给出与使用美元符号相同的结果。然后,我们可以创建一个变量来指向不同的列名,我们可以使用这种符号,但不使用双引号。例如:

score_col <- "score"
utils::View(df[[score_col]])

然后,我们可以使用一个循环对所有感兴趣的列求和。同样,在本例中,只有两个,因此这没问题:

print(sum(df$score))
print(sum(df$val))

然而,假设您有更多的列,并且您可能还想计算其他指标,如标准差、平均值、总和等。这就是循环的威力所在。首先,我们需要存储感兴趣的列的名称。我们可以做:

col_names <- c("score", "val")

另一种方法是使用colnames函数,并通过数字(即数字 2 和 3,忽略组名的第一列)指定我们想要保留的列名。

col_names <- colnames(df)[2:3]

然后,我们可以对输出总和、平均值和标准差的列进行循环:

for(i in 1:length(col_names))
{
    col <- col_names[i]
    cat("\n\nColumn: ", col, "\n")
    print(sum(df[[col]]))
    print(mean(df[[col]]))
    print(sd(df[[col]]))
}

它产生以下输出:

Column: score
[1] 755
[1] 41.94444
[1] 19.99551Column: val
[1] 719
[1] 39.94444
[1] 19.65428

注意,我们取列名,并将其存储在名为col的变量中。然后,我们使用列表符号[[ ]]添加变量名col,每次循环运行指向向量中的下一列时,变量名都会更新。cat函数(concatenate and print)用于显示输出中的列名。\n表示我们需要一个新行(回车)来防止文本出现在同一行。

让我们以最后一个例子来结束,把这些想法放在一起。假设我们有一个不同的数据集,看起来像这样。

作者图片

在这里,我们有 5 名不同疾病分类的参与者,例如心脏问题、呼吸问题和代谢问题。1 表示他们有那一类的情况,0 表示他们没有。同样,死亡列中的 1 表示他们已经死亡,0 表示他们仍然活着(或者在收集数据时仍然活着)。你可以想象有更多的参与者和更多的疾病分类。假设我们想要获取死于各种疾病的人数。同样,在这种情况下,只需查看表就可以相对容易地做到这一点,但我们希望编写可扩展的代码,以处理更大的数据集和具有许多行和列的问题。

让我们编写一些代码来输出每个类别中死亡的人数。我们将从计算每个类别中的死亡人数的函数开始:

deathsPerCategory <- function(df, col_name)
{
    cols_to_keep <- c("id", "death", col_name)
    selected_col <- df %>% select(cols_to_keep)
    filtered_col <- subset(selected_col, selected_col[[col_name]] == 1 & selected_col$death == 1)
    table <- filtered_col %>% group_by(death) %>% summarise(n=n(), .groups = ‘drop’)

    return(table$n)
}

与前面的例子类似,我们传入数据帧和感兴趣的列的名称。接下来,我们创建一个向量,其中包含我们希望保留在数据框中的列。这是iddeath列以及感兴趣的列。接下来,我们使用select函数从数据帧中选择这些列。然后,我们使用subset函数进一步对其进行子集划分,以过滤数据,从而在死亡列和感兴趣的疾病类别列中都需要有“1”。接下来,我们通过按death分组并汇总死亡人数来生成一个表格。最后,我们返回这个汇总值进行输出。

然后,我们可以在一个循环中使用这个函数来输出 3 个疾病类别的摘要。首先,我们需要从列名中获取疾病类别名称:

col_names <- colnames(df)[2:4]

然后我们可以在循环中使用它来输出每个类别的列名和死亡人数。

for (i in 1:length(col_names)) 
{
    cat("\n", col_names[i], "deaths = ", deathsPerCategory(df, col_names[i]), "\n")
}

这将产生以下输出,我们可以通过查看该表来确认:

cardiac deaths = 1respiratory deaths = 1metabolic deaths = 2

完整代码:

library(tidyverse)deathsPerCategory <- function(df, col_name)
{
    cols_to_keep <- c("id", "death", col_name)
    selected_col <- df %>% select(cols_to_keep)
    filtered_col <- subset(selected_col, selected_col[[col_name]] == 1 & selected_col$death == 1)
    table <- filtered_col %>% group_by(death) %>% summarise(n=n(), .groups = "drop") return(table$n)
}col_names <- colnames(df)[2:4]for (i in 1:length(col_names)) 
{
    cat("\n", col_names[i], "deaths = ", deathsPerCategory(df, col_names[i]), "\n")
}

尽管这里给出的例子使用的是小数据集,但希望您能够看到考虑和构建扩展代码以处理更大数据集和更复杂问题的能力的优势。这使得代码更易于管理、维护和修改,而不必重复不必要的代码。数据科学家的技能之一是能够在分析中利用编程技术,以使用 Excel 等软件无法处理的方式处理大量数据。如果您正从其他更直观的电子表格风格的软件转向 R,那么使用 R 和 Python 之类的工具的主要优势之一就是能够以这种方式扩展您的代码。例如,我通常会先编写代码来生成一个单独的图或计算,检查我是否得到了正确的/期望的输出,然后使用函数、循环等来重构代码。来处理剩余的任务。开始时可能看起来更复杂,但随着时间的推移,对于大型数据集,从长远来看,这将为您节省更多时间,因为单个更改可以级联到所有的图、表、计算中,从而使更改变得简单快捷。

利用机器学习中的随机性

原文:https://towardsdatascience.com/harnessing-randomness-in-machine-learning-59e26e82fdfc

随机应该有多“随机”?

照片由来自 Pexels亚当·费杰斯拍摄

您是否曾经在每次运行相同的代码时,您的模型都显示出不同的结果?您是否经历过训练数据不断变化,或者您的机器学习模型在每次调整时都有不同的参数?

如果你有,很可能你忽略了大多数机器学习任务中存在的一个核心成分:随机性。

随机性是机器学习中的一个重要元素。它有助于消除固有的偏见,并有助于建立一个通用的机器学习模型。

然而,就像其他任何事情一样,不小心加入随机性只会妨碍你项目的结果。

在这里,我们深入研究随机性的重要性,以及如何在机器学习模型的构建中利用它。

机器学习中的随机性

随机性可以在无数的场景中被识别。

当您使用 Sklearn 模块将数据拆分为训练/测试集或拆分训练数据以进行交叉验证时,子集是随机选择的。

此外,包含采样的算法通常包含随机性。例如,随机森林分类器通过替换创建训练数据的随机子样本(称为引导)。

随机性也在深度学习模型中发挥作用。

当训练神经网络时,神经元的初始权重和偏差是随机选择的。此外,神经网络中的脱落层具有从层中随机移除神经元的功能。

随机数生成

在进一步讨论随机性之前,我们需要了解 Python 模块是如何生成随机值的。

机器学习中的随机值是由随机数生成器导出的。

为了创建随机值,发生器首先用一个种子初始化,这个数字代表随机数生成的起点。然后,生成器使用特定算法从该起始点创建随机值。

在这一点上,你可能想知道:如果这些数字是用算法生成的,那么它们就不是真正随机的,不是吗?

那是正确的。

由于这些值并不体现真正的随机性,描述这个概念更合适的术语是伪随机性

用于创建伪随机数序列的生成器被称为伪随机数生成器 (PRNG)。

像 Numpy 这样的许多模块使用 PRNGs 来生成一个数字序列,这个序列“看起来”是随机的,但实际上具有确定性的性质。

随机性的问题

尽管随机性是机器学习模型中至关重要的组成部分,但它有一个严重的缺陷。

随机性是随机的。

当您执行任何种类的实验时,您都希望控制实验的所有组件。

不幸的是,随机性是控制的对立面。

如果您的数据处理或模型构建步骤包含了随机性,您怎么能期望在每次迭代中生成相同的结果呢?

很容易看出这是如何对您的机器学习任务构成障碍的。

您将无法与您的同行适当地共享您的工作,因为您将从相同的代码中获得不同的结果。

此外,由于每次迭代都生成不同的值,您将很难评估和改进您的模型。

真正的随机性没有提供的是再现性的元素,即在任意次数的迭代中获得一致结果的能力。

例如,让我们用 numpy 模块生成 10 个随机值。

代码输出(由作者创建)

输出与预期的一样,但是当您再次运行相同的代码时会发生什么呢?

代码输出(由作者创建)

我们得到一组不同的数字。如果模型在训练中表现出相似的行为,那么很容易理解为什么它们会在不同的迭代中产生不同的结果。

为了进一步展示随机性的问题,我们可以对来自 Sklearn 模块的内置数据集执行两次训练测试分割,以创建两个训练和测试集并对它们进行比较。

代码输出(由作者创建)

理想情况下,训练集和测试集应该是相同的,因为它们是用同一行代码创建的。不幸的是,随机性的影响意味着在每次迭代中,不同的记录被分配给训练集和测试集。

解决方案

将随机性成功纳入机器学习的唯一方法是“控制”生成的随机值,而不失去它们的随机性质。

换句话说,随机生成的值需要满足两个条件:

  1. 生成的值需要随机出现

2.生成的值需要是可再现的

虽然这些条件可能看起来相互矛盾,但它们都可以通过 PRNGs 来满足。

PRNGs 的算法生成看似随机的值,因此它们完全满足第一个条件。

下一步是确保这些值也是可重复的。

换句话说,需要一种方法来保证无论代码运行多少次,从 PRNG 获得的值都保持不变。

实现这一点的方法很简单:定义PRNG 的后裔。

在前面的示例中,用于初始化 PRNG 的种子从未明确定义。因此,每次运行代码时,生成的数字都会有不同的起点。这自然意味着导出的数字在每次迭代中都是不同的。

那么,如果在生成随机值之前定义种子,会发生什么情况呢?

让我们先通过设置种子来修改前面的随机数生成。

代码输出(由作者创建)

现在,无论你运行代码多少次,你都将得到相同的随机数集合,因为 PRNG 将在每次迭代的同一点开始。

在 Sklearn 模块中,许多包含随机性的函数和分类器允许您使用“random_state”参数初始化 PRNG。

以下是拆分数据时如何执行此操作。

代码输出(由作者创建)

这一次,两个训练集都匹配。

也可以为深度学习应用设置种子。

以下是如何为 Tensorflow 做到这一点:

以下是你可以为 Pytorch 做的:

注意:分配给种子的实际值实际上并不重要。只要种子保持不变,生成的数字就保持不变。

结论

照片由 Unsplash 上的 Prateek Katyal 拍摄

简而言之,对于一个成功的机器学习项目,我们需要接受伪随机性,而不是真随机性。

我们可以通过直接设置 PRNGs 的种子来消除随机性,以确保生成的数字尽管看起来是随机的,但却是可再现的。

我祝你在机器学习的努力中好运!

posted @ 2024-10-18 09:29  绝不原创的飞龙  阅读(461)  评论(0)    收藏  举报