TowardsDataScience-博客中文翻译-2019-六十八-

TowardsDataScience 博客中文翻译 2019(六十八)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

不炒作 AI

原文:https://towardsdatascience.com/un-hyping-ai-bf87229b29ea?source=collection_archive---------40-----------------------

问我们任何事情

让我们一劳永逸地揭开艾的神秘面纱。它的根源是什么?AI 真的在这里吗?如果不是,那么当前的现实是什么?

我担任 TDS 的编辑助理已经有几年了,我很高兴看到的内容质量让我深受鼓舞,最重要的是,我从中学习。我还意识到,对于这个不断发展的学科中的所有技术专长,我们也需要回答一些关于人工智能的基本问题。我将在“向我们提问”中回答这些问题。欢迎大家的评论。尽情享受吧!

人工智能真的存在吗?

在最纯粹的定义里,人工智能还没有到来。

谷歌大脑的负责人杰弗里·辛顿认为,计算机可以像人类一样思考,使用直觉,而不是规则。表示[这个](https://cacm.acm.org/news/225209-mr-robot/fulltextcornerstones of):

我们是机器……我们只是被生物制造出来的。大多数做人工智能的人都不会怀疑我们是机器。我们只是极其奇特的机器。而我不应该说只是。我们是特别的、奇妙的机器。

顾名思义,这就是人工智能之父约翰·麦卡锡所说的:

人工智能是制造智能机器,尤其是智能计算机程序的科学和工程。

因此,计算机支持的系统将处理信息,以类似于人类在学习、决策和解决问题中的思维过程的方式产生结果。以下是人工智能的基石:

  • 从经验中学习
  • 它使用学习推理
  • 它感知——意义,识别图像,声音等等。
  • 解决复杂的问题
  • 理解语言及其细微差别
  • 创建透视图
  • 随着时间的推移,它降低了错误率

事实上,人工智能是一个宽泛的术语,出现于 20 世纪 50 年代,当时人们试图让计算机执行人类任务。当我们朝着这个目标前进的时候,我们离这个现实要远得多。

我们今天对人工智能的大多数认同包括大规模的数字处理,它考虑了比人类可能更多的变量,以对输入的数据进行分类,并能够做出相当好的预测。

以下是人工智能的阶段:

  • 狭义 AI(ANI)——专门协助或接管特定任务。
  • 通用 AI (AGI) —机器有自我意识,有能力执行通用智能动作。AI 将军将会有效地处理你扔给它的任何问题。
  • 超级 AI(ASI)——比人类聪明一个数量级的机器。
  • 奇点——在这个阶段,关键词是超越和“由 ASI 实现的指数发展道路可能导致人类能力的大规模扩展

今天,机器被训练。人类编写代码是为了创造一个能够学习一件事的系统。我们正处在这样一个时代,我们正在教机器做一件或几件事情,做得和人类一样好,甚至比人类更好。

Robot Thinker — AI Progress via Deposit Photos

AI 的根源是什么?

生物神经元和人类如何处理信息

为了理解人工智能如何进化,我们还需要理解人脑,一直到单个神经元——这是人工智能的心脏。神经元是大脑和神经系统的特化细胞,在全身传递信号。他们的互动定义了我们是什么样的人。神经元会感知内部和外部刺激。神经元也将处理信息并在全身传递信号。它们会将这些信号以命令的形式发送到我们的肌肉,指导我们的行动。

我们从内部和外部收到的每一个刺激都会将这些信号发送到我们系统中的其他神经元。考虑到普通人每分钟有 48.6 个想法,相当于每天 70,000 个想法。如果这些想法中有 10%在全身传递信号,那么超过 7000 个信号可以发出命令,促使身体肌肉执行诸如去商店、给朋友打电话、搜索信息等功能。因此,通过人工智能,这种方法是通过计算机复制生物神经元的行为:神经元中的每个节点都代表着向网络中的其他节点发出信号的信息。这些信号以难以想象的速度处理网络中的信息,并激活其他神经元的信号…等等…

人脑由大约 10 亿个神经元组成。每个神经元与其他神经元形成约 1000 个连接,总计超过 1 万亿个连接。

据《科学美国人》报道:

如果每个神经元只能存储一个单一的记忆,空间不足将是一个问题。你可能只有几千兆字节的存储空间,类似于 iPod 或 USB 闪存驱动器中的空间。然而,神经元结合在一起,每个神经元同时帮助许多记忆,以指数方式将大脑的记忆存储容量增加到大约 2.5 千兆字节(或 100 万千兆字节)。相比之下,2.5 兆字节相当于大约 300 万小时的电视节目。如果你的大脑像 PVR 一样工作,2.5 千兆字节将足以容纳 300 万小时的电视节目。你必须让电视连续运行 300 多年才能用完所有的存储空间。

计算机能思考到什么程度?

现实检验:计算机的表现和它们被训练的数据一样好。机器学习和深度学习都取得了重大进展。

机器学习 —可以定义为一种通过系统实现人工智能的方法,该系统可以从经验中学习,以在一组数据中找到模式。这意味着,通过例子教计算机识别模式,而不仅仅是用特定的规则给它编程。在常见的例子中,机器学习可以用来训练计算机识别图像,并通过计算机视觉进行分类,理解和分析人类语言,包括文本和语音(自然语言处理)。

理解神经元的功能对 Hinton 在深度学习实践中创建神经网络有着重要的贡献。根据的定义,神经网络是一套算法,大致模仿人脑,设计用来识别模式一个神经网络通常包括大量并行运行的处理器和分层排列的:

  • 输入层 —第一层接收原始输入信息——这类似于人类视觉处理中视神经的功能。
  • 隐藏层 —中间层是由神经元无止境的组合和连接而产生的。每一个连续的层接收来自它前面的层的输出。根据神经元连接的体积和组合,可能有许多隐藏层。隐藏层的作用是将输入转换成输出层可以使用的东西。
  • 输出层 —最后一层产生系统的输出,即输入层和隐藏层交互的结果(或动作)。通过反向传播,输出层也将隐藏层激活转换为输出函数所需的比例。当他们学习和吸收更多关于世界的信息时,他们会改变自己。

我们试图用这种机械的方式来模仿人脑的功能。我们的大脑分布在一个巨大的细胞网络上,由无尽的神经元地图连接,沿着十亿条路径放电、连接和传输。”

要回答这个问题,计算机无法思考,至少在人类的水平上是如此。随着更多信息的获取,计算机能够在数据和表面见解中寻找模式。计算机做不到的是准确定义上下文。人类的认知很容易区分演员汤姆·克鲁斯和一艘游轮。随着时间的推移,计算机需要大量的数据输入才能始终如一地做出这些简单的区分。为了做到这一点,他们还需要时间来成熟,并被他们的前辈——是的,被辛顿视为人类的“特殊奇妙的机器”)抚养长大

感谢阅读。如果您有任何问题想问我们的团队,您可以在这里提问

拆箱机器学习:黑盒模型的特征重要性

原文:https://towardsdatascience.com/unboxing-machine-learning-feature-importance-for-black-box-models-ea12268ddb23?source=collection_archive---------28-----------------------

Source: unsplash — Free stock images

因为当我们理解事物时,生活会更美好

在之前的一篇文章中,讨论了在进行数据科学和机器学习时良好的绘图技巧的重要性,我写了一点关于我们应该如何认真对待可解释性和可解释性。正如我之前已经说过的:你可能是一个天才,但是如果你不能向第三方解释你是如何以及为什么得到那些美妙的预测,那么你可能什么都没有。想象一下,告诉某人她或他有超过 90%的可能性患有致命疾病,但却无法解释她/他你是如何得出这个结论的,或者是什么具体症状导致你得出这样的结论。

事实上,在我最近阅读的一本名为《赤裸裸的统计数据》的书中,作者 Charles Wheelon 花了很多时间讲述医疗费用的增加是如何给在卫生行业工作的数据科学家带来压力的。为什么?历史上,当谈到假阳性与假阴性的权衡时,这个行业是作为一个例子给出的。因为当然,如果我们必须选择,我们总是希望开发一个具有高召回率的模型——最大限度地减少假阴性(即人们患有疾病,但被归类为没有疾病)的数量,而不是一个具有高精确度的模型——最大限度地减少假阳性(即人们没有患病,但被归类为患有疾病)的数量。然而,Wheelon 解释了如今让某人进入医疗系统进行研究和治疗的成本也给尽可能实现更高的精确度带来了很大的压力。对于任何在卫生行业工作的人来说,实现“完美”模型的高压也意味着越来越多的内部和外部需求,以了解为什么机器学习模型会提出这样或那样的建议。在外部,这意味着越来越多的利益相关者要求解释,而在内部,对模型更好的理解通常会导致更好的建模本身。

事实上,在过去几年中,关于机器学习中可解释性主题的论文数量一直在稳步增长:

Source: http://people.csail.mit.edu/beenkim/papers/BeenK_FinaleDV_ICML2017_tutorial.pdf

现在,最大的问题是,今天机器学习世界中一些最准确的模型是我们所说的“黑盒”模型。这些模型缺乏可解释性和可解释性,因为它们通常的工作方式意味着除了一组规则或参数集之外,机器的一个或几个层在没有人类监督的情况下做出决策。并且通常,甚至该领域中最专业的专家也不能理解例如通过训练神经网络实际产生的功能。从这个意义上说,一些最经典的机器学习模型更好。

例如,线性/逻辑回归为我们提供了一个非常清晰的数学方程,当试图最小化损失函数时,每个特征对我们的预测有多大影响。决策树有一个非常清晰的方法来选择特征,根据它们在不同阈值下区分数据成员的有用程度。然而,考虑到 ML 材料的可解释性和可解释性通常与通过查看特征重要性和相关性来分析模型特征相关联,我们如何用简单的英语解释当使用这些复杂的模型之一,甚至是集成工具如 Bagging 或 Boosting 时,哪些特征在驱动我们的预测?

事实上,对于 2018 年 Kaggle DS 和 ML 调查,数千名数据行业的专业人士表达了他们对在什么情况下探索模型洞察力和解释模型预测的看法,尽管原因可能不同,但他们都至少提到了一个对他们的业务很重要的场合:

Source: 2018 Kaggle DS and ML Survey

考虑到分析特征重要性的日益增长和共享的重要性,在这篇文章的剩余部分,我们将看到一个叫做“排列重要性”的工具。

置换重要性为我们提供了一种方法,通过测量当一个特性不可用时得分如何降低来计算任何黑盒估计器的特性重要性。这个想法是这样的:当一个特性不可用时,特性的重要性可以通过查看分数降低多少来衡量。为此,可以从数据集中移除一个特征,重新训练估计器并检查分数。但是这样做的计算量很大。相反,我们可以用随机噪声替换每个特征,并在每个特征的每次迭代中再次评分。这就是为什么这种了解特征重要性的方法也被称为“平均降低准确度(MDA)”。

正如你所想象的,从头开始这样做是完全可能的,但幸运的是,我们在你的机器学习项目中实现了排列重要性,你可以只导入下面的:

from eli5.sklearn import PermutationImportance

使用它非常简单,一旦你训练了你的模型,你唯一要做的就是再次拟合你的数据,调用你的模型,如下所示:

permutation_importance = PermutationImportance(your_model, random_state=1).fit(X_train_data, y_train_data)

考虑到您将对数据集的多个版本进行重新评分,因此该算法将需要一段时间来运行。

一旦 PermutationImportance 完成了它的工作,您可以获得两个有趣的东西:

  1. 当然,您可以通过调用以下命令来获得特性的重要性:
permutation_importance.feature_importances_
  1. 您还可以通过调用以下命令来获取要素重要性的标准差:
permutation_importance.feature_importances_std_

正如你所看到的,这是一个简单而强大的工具。的确,在现实中,当使用高度复杂的模型时,它并没有解决与模型可解释性和可解释性相关的背景问题。然而,它让我们更接近理解我们的数据,以及我们的每个特征对我们的模型有什么贡献。这已经是一个开始了!

最后,别忘了看看我最近的一些文章,比如提高你绘图技能的 10 个技巧我在使用火车测试分割5 分钟内抓取网页时犯的 6 个业余错误。在我的中等档案中可以找到所有这些以及更多信息。另外,如果你想直接在你的邮箱里收到我的最新文章,只需 订阅我的简讯 😃

也可以通过…取得联系

下一篇文章再见!

神经网络的不确定性估计——贝叶斯近似下的丢失

原文:https://towardsdatascience.com/uncertainty-estimation-for-neural-network-dropout-as-bayesian-approximation-7d30fc7bc1f2?source=collection_archive---------6-----------------------

本文的主题是,你可以利用辍学来建立预测信心。

这篇文章主要讲的是我如何从优步的论文开始对优步的时间序列进行深刻而自信的预测。使用神经网络解释模型并不是一件容易的事情,了解神经网络的可信度对企业来说非常重要。尽管这一系列论文中有许多复杂的证明,但它们都试图回答一个简单的问题

我的模型对某个特定的预测有多大把握?

目录

背景

我们正在处理一些商业预测问题,因此我们正在研究预测的新方法,特别是神经网络的新方法。(我知道 LSTM/编码器-解码器/seq2seq,但我没有听到它的很多令人兴奋的性能)。我能找到的大公司关于时间序列的公开讨论不多我能找到最接近的是脸书的 预言家 ,这是一种纯粹的统计基数预测方法。

优步在优步 有一篇论文 对时间序列进行了深刻而自信的预测,这篇论文引起了我们的注意,因为他们是在概率编程上投入大量资源的行业参与者之一。经过一番研究,我发现优步还赢得了M4 竞赛(一个著名的时间序列竞赛)M4 竞赛不仅需要准确的预测,还需要预测的置信区间。他们也开放了源代码 Pyro ,这是一个概率编程库,所以结合这些事实,我有理由相信他们正在做一些有趣的(实际上有用的)工作。

我没有很深的统计学背景,“贝叶斯”这个词对我来说几乎毫无意义,我只知道它与条件概率有关,仅此而已。我非常努力地回忆我关于贝叶斯和频率主义者的统计,这个奇妙的线索很好地解释了这一点。

优步时间序列的深度自信预测

优步已经写了一篇关于这项工作的博文,我从第一篇论文开始,但最后又读了几篇论文(一些是早期的基础工作,一些是后续工作)。我不会花太多的话来解释这些文件,因为我不能理解每一个步骤。相反,我将只强调我的研究旅程中的重要部分,并鼓励你们通读这篇论文。

我们表明,在神经网络中使用脱落(及其变体)可以被解释为一个众所周知的概率模型的贝叶斯近似:高斯过程(GP)

我个人并不是 100%相信这项工作,但他们已经显示出巨大的实际效果,这是最重要的部分。(像 BatchNorm 一样,人们长期以来一直在思考为什么它会以错误的理由工作,但这并不能阻止任何人使用它,因为它的确提高了模型的收敛性)

研究过的论文:

  1. 优步时间序列深度自信预测
  2. 优步时间序列极端事件神经网络预测
  3. 作为贝叶斯近似的漏失:表示深度学习中的模型不确定性
  4. 变分贝叶斯辍学:陷阱与修正
  5. 变分高斯漏失不是贝叶斯
  6. 深度学习中的风险与不确定性:贝叶斯、自助和辍学的危险

其他资源:

  1. M4 竞赛:结果、发现、结论和前进方向
  2. 深度学习中的不确定性 (亚林·加尔的论文)

在阅读一系列材料时,有一个时间线是很有用的。

Timeline

不确定性估计

贝叶斯的一个关键区别是参数是分布而不是固定的权重。

误差=模型不确定性+模型错误设定+固有噪声

贝叶斯神经网络将不确定性分解为模型不确定性模型误设定固有噪声

MCDropout

MCDropout

贝叶斯的一个关键是一切都是概率分布,而不是点估计。这意味着你的体重也有不确定性。

他们使用 MCDropout 来处理模型不确定性和错误设定。基本上,他们已经声称在推断时间使用 Dropout 相当于做贝叶斯近似。这里的关键思想是让辍学者在培训和测试时间做同样的事情。在测试的时候,你会重复 B 次(如论文所说的几百次),也就是把相同的输入以随机的丢包传递给网络。然后,利用您的预测,您可以使用这些# of B 预测生成一个预测间隔。MC 指的是蒙特卡罗,因为退出过程类似于对神经元进行采样。

固有噪音

Inherent Noise

他们还引入了术语固有噪声,指的是不可减少的噪声。简而言之,他们使用一种非常常见的技术来模拟这种错误——拒绝验证。他们称之为自适应方法,谈论平滑和先验,但是我看不出与 ML 社区熟悉的标准训练/验证实践有任何区别。最后,你会把两个误差项合并,得到最终的不确定项。

讨论

你可以在 Reddit 上找到一个有趣的讨论,它从理论的角度提供了一些反驳。事实上,我并不完全相信优步的论文。然而,他们在国内的和 M4 的比赛中都取得了不错的成绩。像深度学习中许多进步一样,理论晚于实际结果。如果您感兴趣,请随意尝试,实现应该相对容易,因为您只需要在推理时保持 dropout。

结论

要点是,不确定性不仅存在于你的模型中,也存在于你的体重中。贝叶斯神经网络试图将权重建模为分布。

MCDropout 提供了一种新的简便的方法来估计不确定性,在大多数现有的网络变化最小。在最简单的情况下,您只需要在测试时保持 dropout on,然后多次传递数据并存储所有预测。不利的一面是,这可能计算量很大,尽管优步声称这增加了不到 10 毫秒。他们没有讨论他们如何实现这一点,但我猜测他们会进行大量的并行计算,因为你可以想象数据的多次传递不会按顺序进行,所以这个过程很容易并行。

我非常渴望听到更多关于最新的时间序列预测和用神经网络估计不确定性的方法的讨论,如果你知道一些更好的方法,请告诉我!

附录

从哪里开始?google 的关键字名称:

  • Yarin Gal(他在论文中提出使用脱落进行贝叶斯近似)
  • slawek Smyl(M4 竞赛获奖者)

如果你只想了解申请。快速浏览一下[2]然后[1],由于[1]是为[1]做铺垫,有些背景是重复的。

[4]很好地概述了使用辍学的一些陷阱

  1. 优步时间序列深度自信预测
  2. 优步时间序列极端事件神经网络预测
  3. 作为贝叶斯近似的漏失:表示深度学习中的模型不确定性
  4. 变分贝叶斯辍学:陷阱与修正
  5. 变分高斯漏失不是贝叶斯
  6. 深度学习中的风险与不确定性:贝叶斯、自助和辍学的危险

https://tensor chiefs . github . io/BBS/files/dropouts-brown bag . pdf(亚林加尔)

不确定性采样备忘单

原文:https://towardsdatascience.com/uncertainty-sampling-cheatsheet-ec57bc067c0b?source=collection_archive---------12-----------------------

当有监督的机器学习模型做出预测时,它通常会给出该预测的置信度。如果模型是不确定的(低置信度),那么人类的反馈可以有所帮助。当一个模型不确定时,获得人类的反馈是一种被称为不确定性采样主动学习

备忘单中涵盖的四种不确定性采样类型是:

  1. 最不自信:最自信预测和 100%自信之间的差异
  2. 置信区间:两个最有把握的预测之间的差异
  3. 置信度:最有把握的两个预测之间的比率
  4. 熵:所有预测之间的差异,由信息论定义

本文分享了这四种计算不确定性的常用方法的备忘单,包括示例、等式和 python 代码。下次你需要决定如何计算你的模型的置信度时,把它作为一个参考!

数据科学家通常使用不确定性采样来对项目进行采样,以便进行人工审查。例如,想象一下,你负责一个机器学习模型来帮助自动驾驶汽车理解交通。你可能有数百万张从汽车前部摄像头拍摄的未标记图像,但你只有时间或预算来标记 1000 张。如果你随机采样,你可能会得到大部分来自高速公路驾驶的图像,自动驾驶汽车已经很自信,不需要额外的训练。因此,您将使用不确定性采样来查找 1,000 个最“不确定”的图像,其中您的模型最混乱。

Confusing traffic lights

当您使用新标记的示例更新您的模型时,它应该会变得更智能、更快。

An uncertain robot

这篇备忘单摘自我的书《人在回路中的机器学习:https://www . manning . com/books/人在回路中的机器学习

有关每种方法的更多细节和比标记更复杂的问题,如预测文本序列和图像的语义分割,请参见这本书。不确定度的原理是一样的,但是不确定度的计算会不一样。

这本书还涵盖了其他主动学习策略,如多样性抽样,以及解释你的模型概率分布的最佳方式(提示:你可能无法相信你的模型的可信度)。

下载代码和备忘单:

您可以从这里下载代码:

[## RM unro/不确定性 _ 采样 _ 数字

针对不确定性的常见主动学习策略的 NumPy 实现对四种不确定性进行采样…

github.com](https://github.com/rmunro/uncertainty_sampling_numpy)

您可以在此下载 PDF 版本的备忘单:

我还将在以后发布 PyTorch 中的代码,以及更多种类的算法。

编辑:PyTorch 版本的备忘单现已发布:http://robertmunro . com/Uncertainty _ Sampling _ cheat sheet _ py torch . pdf

进一步阅读

不确定性抽样已经存在很长时间了,有很多好的文献。一篇关于最不自信的优秀早期论文是:

阿伦·库洛塔和安德鲁·麦卡勒姆。2005.减少结构化预测任务的标记工作。 AAAIhttps://people . cs . umass . edu/~ McCallum/papers/multi choice-aaai 05 . pdf

一篇关于置信区间的优秀早期论文是:

托拜厄斯·谢弗,克里斯蒂安·德科曼和斯特凡·弗罗贝尔。2001.用于信息抽取的主动隐马尔可夫模型。伊达https://link . springer . com/content/pdf/10.1007/3-540-44816-0 _ 31 . pdf

将信息论用于基于熵的采样的一篇好的早期论文是:

伊多·达甘和肖恩·p·恩格尔森。1995.用于训练概率分类器的基于委员会的采样。95 年的 ICML。http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.30.6148

更一般地说,不确定性采样的基础文件是:

戴维·刘易斯和威廉·盖尔。1994.一种训练文本分类器的顺序算法。94 年的 SIGIR。https://arxiv.org/pdf/cmp-lg/9407020.pdf

要获得更多关于不确定性抽样的学术论文,请查找引用上述论文的被广泛引用的近期工作。

这些例子在我自己的文章中也有涉及:

罗伯特·芒罗。2020 年(预计)。人在回路中的机器学习。曼宁出版公司。https://www . manning . com/books/human-in-the-loop-machine-learning

我文本中的章节是按照他们所写的内容出版的——不确定性抽样章节现在已经出版,多样性抽样章节将是下一个。我会边走边分享摘录,就像我最近在机器学习知识象限中做的那样:

[## 机器学习的知识象限

迁移学习、不确定性采样和多样性采样来改进您的机器学习模型。

towardsdatascience.com](/knowledge-quadrant-for-machine-learning-5f82ff979890)

实施不确定性采样

备忘单中的所有方程返回[0,1]范围内的不确定性分数,其中 1 是最不确定的。许多学术论文没有对分数进行标准化,所以你可能会在上面的论文中看到不同的方程。但是,我建议您为任何用于非研究目的的代码实现规范化的[0–1]等式:[ 0–1]范围使下游处理、单元测试和抽查结果更容易。

本文和 GitHub 库中共享的代码都是开源的,所以请使用它来入门!

罗伯特·芒罗

2019 年 7 月

用于真实世界机器或深度学习项目的不寻常的数据清理器

原文:https://towardsdatascience.com/uncommon-data-cleaners-for-your-real-world-machine-or-deep-learning-project-f926d8ecb258?source=collection_archive---------36-----------------------

Cleaning Tools

介绍

数据清理是您的实体课程或在线课程中简要涉及的一个主题。然而,在您作为数据工程师或数据科学家的工作中,您将花费大量时间准备(预处理)数据,以便可以将数据输入到您的模型中。

[## 70%的数据科学学习者做错了什么

在大学工程课程中,我的头反复撞在 2 米长的金属杆上,从中吸取了教训

towardsdatascience.com](/what-70-of-data-science-learners-do-wrong-ac35326219e4)

企业数据科学仍然是一个新领域。许多学者还没有为真正的企业解决真正的问题。因此,他们以一种脱离数据和商业背景的方式教授教科书算法。这可能是智力上的乐趣。但是,如果学生认为这些课程为他们成为数据科学家做好了准备,那他们就错了。

Paso 将提供你清理数据所需的许多工具,但不是全部。

仅仅因为帕索提供了一个工具并不意味着你应该在你的数据集上使用它。例如,删除具有高密度 nan 的行将导致更差的损失度量或不希望的偏差,但并非总是如此。

不同清洗策略(管道)的迭代是 Paso 的基本目标。讨论分为以下几个主要部分:

  1. 首先,我们用一个 Paso 输入器加载boston数据集。它具有相对少的行数,同时具有少于十个特征,以产生快速清洁。
  2. 接下来,我通过管理相对干净的boston数据集来演示每一个清理器。
  3. 最后,我们总结一下 Paso'' 数据清理器以及我们对未来文章和 Paso 版本的计划。

[## paso 为您的 Python 项目提供日志记录和参数服务

paso 为您的 Python 项目提供日志记录和参数服务

paso 为您的 Python Projectmedium.com 提供日志记录和参数服务](https://medium.com/@dr.bruce.cottman/pasos-offering-of-logging-and-parameter-services-for-your-python-project-c3ae2fd6869a)

正如我们在上面标题为 的文章中看到的,paso 为您的 Python 项目提供日志记录和参数服务,我们应该启动 paso 服务。

*import pandas as pd
from paso.base import Paso,Log,PasoError
from loguru import logger
session = Paso(parameters_filepath='../parameters/default-lesson.2.yaml').startup()*

我们将使用Inputer,,只是说明它是一个通用类,用于将数据输入到 pandas dataframe 中。描述文件描述的数据集:city.yaml。在下面的媒体文章中会更详细地讨论Inputer和描述文件:

* [## 第 1 部分:平衡和扩充结构化数据

数据扩充很重要,因为它从我们当前现有的数据集生成(准确地)人工数据。的…

medium.com](https://medium.com/@dr.bruce.cottman/part-1-balancing-and-augmenting-structured-data-4ade0df38662)

from paso.pre.inputers import Inputers
dataset_name = 'boston'
inputer = Inputers(description_filepath='../descriptions/pre/inputers/'+dataset_name+'.yaml')
dataset = inputer.transform()
inputer.target'MEDV'

管理数据集

通常情况下,我们获取数据并必须清理它。这样的数据集是专有的。毕竟,没有人愿意向公众展示他们的肮脏数据(呻吟)。

为了展示这些数据清理器是如何工作的,我们可以找点乐子,整理一个干净的数据集。

清除程序:缺少值

检测和纠正缺失值和异常值(好的或坏的)是一个不断发展的研究领域。我们将在关于Pasoscaler 的文章中讨论异常值。对于本文,我们将只关注丢失的值。

不同的值可以表示缺少一个值。举个例子,

  • 999在某些功能中可能表示“未回答”。
  • NA可能表示不适用于此功能/记录。
  • -1可能意味着缺少此功能/记录。
  • 诸如此类。

在这里你可以找到更多关于缺失数据的熊猫指南的细节。

对于第一个显示的 cleaner,我们添加了特性asv,它具有所有相同的值999

from paso.pre.cleaners import Cleaners
c = Cleaners()
dataset['asv'] = 999.0
c.values_to_nan(dataset,values=[999.,11999.],inplace=True)
dataset.head()

c.values_to_nan on dataset

该清洁剂,c.values_to_nan将所有999值更改为NaN。还要注意的是,作为inplace=True,数据集是自己改变的,通过避免复制dataset来节省内存。

清洁器:计算比率

缺失值(观察值)比率较大的行在统计上不相关。同样,您可能希望估算缺失值,即将缺失值更改为其他值。

每行缺失值的数量是信息,这本身表明它应该是该数据集的一个新特性。

使用此Cleaner,不删除带有NaN的行,而是为每一行计算 number _ of _ nulls/total _ row _ count,并将一个新特征NaN_ratio添加到返回的 pandas 数据帧中。

我们将再次使用同一个Cleaner实例c。同样,让我们通过将第一行的第一个和第二个特性设置为NaN来对dataset进行更多的修改。

Cleaner calculate_NaN_ratio transforming dataset

注意这里有一个新的特性,NaN_ratio。正如我们所料,第一行的NaN/total_row_count比率不同于第二行和后面的行。

Cleaner属性column_missing_value_ratio包含每个特征的缺失值比率。提示:您可以在堆叠合奏中使用这些。我们将在另一篇文章中讨论这个问题。

估算:将 NaN 更改为值

NaN设置为最佳近似值是您数据清理工作的关键,并进一步降低您的预测准确性和能力。关于这个主题的一篇流行文章:

[## 弥补缺失数据的 6 种不同方法(数据插补,附实例)

统计估算数据集中缺失值的常用策略。

towardsdatascience.com](/6-different-ways-to-compensate-for-missing-values-data-imputation-with-examples-6022d9ca0779)

由于各种原因,许多现实世界的数据集可能包含缺失值。它们通常被编码为名词、空格或任何其他占位符。使用具有大量缺失值的数据集来训练模型会极大地影响机器学习模型的质量。一些算法,如 scikit-learn 估计器,假设所有的值都是数字的,并且拥有有意义的值。
处理这个问题的一个方法是去掉有缺失数据的观测值。但是,您可能会丢失包含有价值信息的数据点。更好的策略是估算缺失值。换句话说,我们需要从数据的现有部分推断出那些缺失的值

另一篇关于归因的文章:

[## 缺失数据难题:探索和插补技术

为什么缺少数据

medium.com](https://medium.com/ibm-data-science-experience/missing-data-conundrum-exploration-and-imputation-techniques-9f40abe0fd87)

各国:

为了让我们充分理解缺失数据的重要性,我们需要全面地确定缺失数据发生的原因。第一步是了解你的数据,更重要的是了解数据收集过程。这可以导致减少数据收集错误的可能性。缺失数据的性质或机制可以分为三大类。
1)完全随机缺失(MCAR)
2)随机缺失(MAR)
3)非随机缺失(MNAR

我们提供了估算策略的大杂烩,如Imputers().imputers()所示。我建议您阅读这些和其他关于输入缺失值的文章,这样您就可以最好地使用这些工具。

我们决定在给定的特性列表上进行转换,因为估算策略会随着特性子集的变化而变化。

注意,极端梯度推进(xgboost)将根据所用的训练损失函数,自动学习缺失数据的最佳(不能证明是最佳,但实际上良好 足够)插补值。

作者在其名称中使用了eXtreme ,主要是因为这种能力。它是一个工作非常好的黑匣子,你可以通过研究源代码来打开它。

我建议你先试试xgboost,然后用这里显示的估算和其他数据清理器来提高你的预测。

这里,我将使用一个简单的most_frequent策略,因为它处理分类和连续特征类型。

imputer_file = “../descriptions/pre/cleaners/most_frequent_impute.yaml”
imp = Imputers(description_filepath = imputer_file)
imp.transform(dataset)

first 4 rows of dataset after imputation. Notice, fist row of CRIM and ZN havechanged from NAN

删除 _ 重复 _ 要素

在机器学习竞赛中,你很少会看到两个或更多具有相同值的特征。然而,您几乎总是会在拥有大型和/或多个数据库和/或 ot 数据仓库和/或数据湖的企业中看到它。

随着企业数据库或数据湖的老化,不同的人添加不同的数据源,重复的特性是相当标准的。

如果一个要素与另一个要素具有相同的索引值,则应删除其中一个要素。重复特征是多余的,并且没有预测能力。

Cleaner delete_Duplicate_Features将多余的特征减少为一个独特的特征。

注意,任何NaNs在被传递给这个方法之前都会被从数据集中删除,根据定义,Python 中的NaN不等于另一个NaN。早先,我们遇到了可以删除、替换或Impute NaN值的数据清理器。

我们将创建特征CRIM1CRIM2,它们的值与CRIM相同。

dataset['CRIM1'] = dataset['CRIM12'] = dataset['CRIM']
dataset.head(n=2)

Added CRIM1 and CRIM2 features

c.delete_Duplicate_Features(dataset, inplace=True)
dataset.head(n=2)

Deleted CRIM1 and CRIM2 features

不出所料,delete_Duplicate_Features 删除了功能CRIM1CRIM2.

删除具有单一唯一值的要素

将常数存储在数据中是常见的做法。常数显示为具有唯一值的特征/列。

NaN为空值,因此不是常量或值。

该方法查找所有只有一个唯一值的特征。值之间的变化为零。所有这些特征都从数据帧中删除,因为它们没有预测能力。

在这里,我将一个常量放入数据集中,并用delete_Features_with_Single_Unique_Value.删除它

delete_Features_with_Single_Unique_Value

删除具有所有唯一值的要素

当一个要素的每个值都不相同时,它在回归任务中只具有预测值,并且这些值必须是浮点型或整数型。

商品的 SKU、id 或名称是字符串或对象类型,没有预测能力,只会拖学习者的后腿。应该从数据集中移除这些要素。

在这个例子中,我将索引变成一个 ID,这样我就可以删除它。

delete_Features_with_All_Unique_Values

特征 _ 统计

Cleaner.feature_Statistics将计算每个特征的一组预定统计数据,并返回一个数据帧。

这组统计数据如下所示:

Cleaner.feature_Statistics

这种方法是一种诊断工具(concat = False),用于确定标准偏差或任何其他统计数据是否太小,从而没有显著的预测能力。

它还可以添加到数据集(concat=True),其中统计信息部分描述了行值的分布。特征必须是数字(整数或浮点数)。

您可能希望也可能不希望目标成为分布的一部分。由于测试没有目标,该目标不应该是训练数据集中分布的一部分,因为您正在将目标泄露训练数据集中。

您可能希望移除目标要素,然后将其放回数据集中。

使用Cleaner.column_stats您可以获得每个特性的统计数据。如果您想与其他学员进行叠加(合奏),可以稍后使用此功能。现在不要担心组装;我们将在后面的文章中讨论这一点。

Cleaner.column_stats

注意:在传递给这个方法之前,任何NaNs都应该从数据集中删除,根据定义,Python 中的NaN不等于另一个NaN

注意:我们已经介绍了可以删除、替换或Impute NaN值的数据清理器。

布尔型到整数型

学习者,除了树,还有其他函数,需要将True/Falsevalue_1/value_0的布尔值(特性将只有 2 个值)转换成整数1/0才能正常工作..

类实例方法boolean_to_integer转换所有布尔特征。因为它不影响非布尔特征,所以它可以在任何数据集上运行。

boolean_to_integer

特征 _ 特征 _ 相关性

通过使用seaboard.pairplot(dataset).在数据集中绘制成对关系,可以直观地看到线性和/或非线性行为。您也可以使用dataset.profiling_report来提供关于数据集的更多信息,这是开始 EDA 的好方法。

seaboard.pairplot(dataset)

我们可以用feature_Feature_Correlation来计算一个数据集的关联矩阵,关联矩阵是与所有其他特征相关的所有特征。根据计算,相关性是线性相关性,并不量化任何两个特征之间的非线性行为。

两个特征之间的相关性越高,相关系数越接近绝对值 1.0(开区间-1.0,1.0)。特征本身的值为 1.0,因为它与自身相关。如果它有负值,那么它是反相关的。反相关特征对意味着如果一个特征的值增加,那么另一个特征的值将减少

特征的线性预测强度是它与目标特征的相关程度。然而,特征对(非目标)的相关性越高,特征之一的预测值将降低。

通常,使用皮尔逊相关系数,其仅对两个特征之间的线性关系(或一阶)敏感。

皮尔逊相关系数-0.85 是强负相关,而相关系数 0.15 是弱正相关。此外,如果某个特征与目标的相关系数为|0.99|,那么它的预测值非常高,甚至可能太高。应检查该数据集,尤其是该特征是否有错误。

Spearman 的等级相关系数是衡量两个变量之间的关系能够被单调函数描述的程度。

肯德尔等级相关系数是用于测量两个测量特征之间的顺序关联的统计量。

Spearman 的等级相关系数是对单调函数如何描述两个变量之间关系的度量。

在大多数情况下,对 Kendall 和 Spearman 等级相关系数的解释与 Pearson 相关系数非常相似,因此通常会导致相同的诊断。feature_Feature_Correlation 类计算数据集所有要素对的皮尔逊、斯皮尔曼或肯德尔相关系数。

同样,这个类实例方法是一个诊断工具,它指示一个特征是具有低预测能力还是与另一个特征具有高冗余。

在移除任何特征之前,查看 SHAP 值、相对方差和相关系数,以决定移除特征。

阅读这篇文章可以很好地了解相关性:

[## 了解数据科学项目中相关性的价值

探索数据科学的核心。理解计算相关性的重要性至关重要

medium.com](https://medium.com/fintechexplained/did-you-know-the-importance-of-finding-correlations-in-data-science-1fa3943debc2)

您可以使用feature_Feature_Correlation.计算数据集的特征-特征相关矩阵

feature_Feature_Correlation

您可以使用 plot_corr .绘制数据集的要素-要素相关性矩阵

删除 _ 功能

我应该在这里提一下, sklearn 有一些不同的算法用于特征选择。在移除任何功能之前,您可能需要查看这些内容。

然而,我发现 paso 中给出的特征诊断工具可以处理非线性数据。 SHAP 在确定 2018 财年车型中某个特征的重要性方面是最先进的,而且据我所知仍然是最先进的

如果你有更好的了解,请告诉我们,我们可以添加到帕索。这个领域正在迅速发展。

根据您的分析,您现在可以从 pandas 数据框架中移除要素了。

我将创建一个特征asv ,然后用delete_features.移除它

delete_Features

移除训练和测试中不常见的功能

如果训练或测试数据集具有特征,而另一个没有,则这些特征将没有预测能力,并从两个数据集中移除。例外情况是目标特征存在于训练数据集中,但不在监督问题的测试中。

一个数据集中的特征(训练测试)而不是另一个数据集中的特征(训练测试)可能指出这些数据集中的其他问题。您应该检查数据加载的步骤。

我最常看到的是来自上游服务(Kafka、Google PubSub、Amazon Kinesis Stream、PySpark 和 RabbitMQ 等)的测试数据集。测试数据集的特征被改变,而预训练模型(以及训练集)不具有这些新特征。根据您的错误处理,通常会发生无法预测的情况。

使用:

  1. 移除了训练和测试数据集的特征差异。
  2. 删除的特征将被记录下来,以便以后进行协调。
  3. 预训练模型成功处理了来自输入测试数据集的预测。数据流的一个很好的概述在:

[## Python 中的数据流和在线机器学习

数据已经不仅仅是一组二进制数字,而是每个人日常决策的必要组成部分…

medium.com](https://medium.com/analytics-vidhya/data-streams-and-online-machine-learning-in-python-a382e9e8d06a)

为了创建测试和训练数据集,我们可以使用 30%的City作为测试,剩下 70%的City作为训练。

Clean extra feature in test

摘要

从 Python 3.6 ( PEP 484 )开始,引入了类型提示。类型提示(注意:不是强类型检查)使得对 Python 代码进行静态类型检查成为可能。

Python 语言解释器使用 而不是 类型提示,除了检查正确的语法。类型提示更多地被下游工具使用,比如PyCharmMypy.

更好的文档和在运行时发生类型错误之前将其捕获是您将从第一波工具中看到的一些好处。

你可以打赌,有人正在为 Python 开发编译器,以使它在运行时更快。接下来,您可以想象用类型化符号转换动态类型化 Python 的工具。

你可以打赌,有人正在为 Python 开发编译器,以使它在运行时更快。接下来,您可以想象用类型化符号转换动态类型化 Python 的工具。

真正美妙的是一种语言,它将输入放到下游工具中,使软件工程师能够专注于为什么而将很大一部分如何留给工具。

使用类型提示,CleanersImputers 类方法调用签名被总结如下:

from paso.pre.cleaners import Cleaners
c = Cleaners()# 1
c.values_to_nan(self, X: pd.DataFrame, values: List[str]=[], inplace:bool=True, verbose:bool=True) ->  pd.DataFrame:#2
c.delete_NA_Features(self, X: pd.DataFrame, threshold:float =1.0, inplace:bool=True, verbose:bool=True) ->  pd.DataFrame:#3
c.calculate_NaN_ratio(self, X:pd.DataFrame, inplace:bool=True, verbose:bool=True) ->  pd.DataFrame:#4
c.delete_Duplicate_Features(self, X:pd.DataFrame, ignore:List[str], inplace:bool=True, verbose:bool=True) ->  pd.DataFrame:#5
c.delete_Features_with_Single_Unique_Value(self, X:pd.DataFrame, ignore:List[str], inplace:bool=True, verbose:bool=True) ->  pd.DataFrame:#6
c.delete_Features_with_All_Unique_Values(self, X:pd.DataFrame, ignore:List[str], inplace:bool=True, verbose:bool=True) ->  pd.DataFrame:#7
c.statistics() -> List[str]#8
c.feature_Statistics(self, X:pd.DataFrame, statistics:str="all", concat:bool=True, inplace:bool=True, verbose:bool=True
) -> pd.DataFrame:#9
c.boolean_to_integer(self, X:pd.DataFrame, inplace:bool=True, verbose:bool=True) -> pd.DataFrame:#10
c.feature_Feature_Correlation(self, X:pd.DataFrame, method:str="pearson", verbose:bool=True) -> pd.DataFrame#11
c.plot_corr(self, X: pd.DataFrame, kind:str="numeric", mirror:bool=False, xsize:float=10, ysize:float=10)-> None:#12
c.delete_Features(self, X:pd.DataFrame, features:List[str]=[], verbose:bool=True, inplace:bool=True) -> pd.DataFrame:#13
c.delete_Features_not_in_train_or_test(self):self, train:pd.DataFrame, test:pd.DataFrame, ignore:List[str]=[], verbose:bool=True, inplace:bool=True) -> pd.DataFrame:#14
imputer_file = "../descriptions/pre/cleaners/most_frequent_impute.yaml
**imp** = **Imputers**(description_filepath: str = imputer_file)**imp.imputers**() -> List[str]:#15 **imp.transform**(self, X: pd.DataFrame, verbose: bool = True, inplace: bool = True, features: List[str] = None, **kwargs) -> pd.DataFrame

本文的代码在[.ipynb](https://github.com/bcottman/paso/blob/master/lessons/lesson-2.ipynb).[p](https://github.com/bcottman/paso/blob/master/paso/pre/cleaners.py)y 文件中给出。

您已经看到 paso 为生产数据工程师和研究数据科学家提供了数据清理方法。 paso 支持流数据以及批量提取数据清理。你可以期待 paso 继续为数据清理提供最先进的工具。

关于帕索的其他文章有:

[## paso 为您的 Python 项目提供日志记录和参数服务

paso 为您的 Python 项目提供日志记录和参数服务

paso 为您的 Python Projectmedium.com 提供日志记录和参数服务](https://medium.com/@dr.bruce.cottman/pasos-offering-of-logging-and-parameter-services-for-your-python-project-c3ae2fd6869a) [## 第 1 部分:平衡和扩充结构化数据

数据扩充很重要,因为它从我们当前现有的数据集生成(准确地)人工数据。的…

medium.com](https://medium.com/@dr.bruce.cottman/part-1-balancing-and-augmenting-structured-data-4ade0df38662)

将来,我们将会发表更多关于 paso 功能的文章。

  • 第 2 部分:结构化数据的高级扩充。
  • 第二部分:深度学习输入。
  • 还有更多…

如果你有一个服务或功能或看到一个错误,然后离开帕索项目一个注意。*

通过探索性数据分析发现隐藏的宝石

原文:https://towardsdatascience.com/uncover-hidden-gems-with-exploratory-data-analysis-7a25332f9156?source=collection_archive---------18-----------------------

用熊猫、海鸟和树叶进行基本侦察

Photo by Ilze Lucero on Unsplash

数据科学家的关键特质之一是好奇。在本文中,我们将使用一些流行的 Python 工具探索一个有趣的数据集,但也会尝试用非常规的术语来思考数据。对于欺诈检测等领域,以意想不到的方式连接数据可以梳理出模式,即使数据可能看起来不完整。理想情况下,你会提出一些能打开新商机的见解。

在 Kaggle 寻找供应链数据集时,我发现了一个名为供应链数据,副标题为进口和装运数据。向下扫描页面,我看到数据源名为 walmart-import-data.csv 。嗯,可能会很有趣。啊哦,“关于这个文件”说“还没有描述”。这就是调查开始的地方——我们甚至没有数据字典。

通常当你在做探索性的数据分析时,这是因为你有一个特定的问题,你正试图使用数据来回答,例如上个月有多少箱菠萝从巴哈马群岛运出,但在这里我们将让我们的想象力天马行空,看看数据可能会揭示什么秘密。

为了保持这篇文章的可读性,下面只显示了一些关键的代码片段。Python Jupyter 笔记本在 GitHub 这里,Kaggle 内核在这里。为了清楚起见,我还将大量使用后见之明来简化我通过反复试验发现的一些事情,例如,我如何知道原始数据文件中大约 9%的行都是 NA。我最初发现某些列有很多 NaN 值,但是进一步检查后发现整行都是 NaN。

预赛

为了能够跟随 Jupyter 笔记本,您将需要从 GitHub 这里克隆或下载资源库。或者,您可以为本文运行 Kaggle 内核。

如果您走第一条路,在您克隆了存储库之后,您需要从这里的 Kaggle 下载数据文件,并将文件Walmart-import-data-full . CSV移动到存储库中的 data/raw 子目录。

第一步

目前还不清楚为什么会发布这个数据集,而且它也不是最近才发布的(最近一次发布是在 2013 年 9 月 9 日)。对于我们的目的来说,这很好,如果出现了更新的数据集,这些技术将适用。我们能得到什么样的见解?让我们从加载数据开始。

xdata = pd.read_csv(raw_data_path / 'walmart-import-data-full.csv', low_memory=False)
# About 9% of the rows are all NA; drop them
xdata.dropna(axis=0, how='all', inplace=True)

我们指定 low_memory=False 来避免关于包含混合类型数据的某些列的警告。如果我们超越探索性数据分析(EDA)阶段,我们可以花一些时间均匀化这些列,并为 read_csv 创建一个定制的 dtypes 参数。像往常一样,我们先看一下前几行,以便对数据集有一个大致的了解:

xdata.head(3)

The first few rows and 13/34 columns of the data

查看 xdata.shape 可以看到,数据集中有 175713 行和 34 列,其中 NA 行已被删除。从 xdata.columns 中,我们可以大致了解列中的内容,这些列的名称相当有意义。看看‘原产国’怎么样?看看 2013 年沃尔玛的商品来自哪里可能会很有趣。描述功能对 EDA 非常有用:

xdata['COUNTRY OF ORIGIN'].describe().to_dict(){'count': 174093, 'unique': 71, 'top': 'China', 'freq': 125366}

我们看到,最大的原产国是中国,占出货量的 72%(按数量计算)。然而,有 71 个独特的国家,那么还有谁在向沃尔玛销售呢?

沃尔玛全球供应商的可视化

我们可以看直方图,但在地图上看会更有视觉冲击力。

为了做到这一点,我们可以制作一个 choropleth 地图,用不同的颜色显示每个国家的发货百分比。我们将使用leavy,它使用 Python 和 Leaflet.js 库来创建用于数据可视化的交互式地图。

一个 follow Choropleth 地图需要一个数据框和两列:一列用于索引 JSON 映射数据,另一列包含一个值,该值用于选择地图上的阴影颜色。

虽然我确信有许多更有效的方法可以做到这一点,但由于这是一个探索性的数据分析,而且数据集并不是很大,我们可以使用 groupby、describe 和 xs 来快速制作一个数据框架,其中包含制作一个叶子地图所需的列。如果你很难理解我是如何得出下面这个表达式的,把它分成几个部分,然后显示每个部分。我现在并不真正关心“重量(KG)”列,只是我们可以使用它的“计数”字段。

countries_of_origin = xdata.groupby('COUNTRY OF ORIGIN').describe().xs('WEIGHT (KG)', axis=1).copy()
countries_of_origin.reset_index(level=0, inplace=True)coo_record_count = sum(countries_of_origin['count'])
countries_of_origin['pct'] = countries_of_origin['count'].apply(lambda cnt: 100*cnt/coo_record_count)
countries_of_origin['logpct'] = countries_of_origin['count'].apply(lambda cnt: np.log(100*cnt/coo_record_count))
# We will use the sorting later
countries_of_origin.sort_values(by==['count'])

The first three entries in countries_of_origin, by count

现在我们有了有用格式的数据,让我们用 let 制作一个地图:

# Initialize the map:
m = folium.Map(location=[30, 0], zoom_start=2, no_wrap=True)# geo_data is the map data# Add the color for the chloropleth:
_ = folium.Choropleth(
    geo_data=folium_world_data.as_posix(),
    name='Choropleth',
    data=countries_of_origin,
    columns=['COUNTRY OF ORIGIN', 'pct'],
    key_on='feature.properties.name',
    fill_color='YlGn',
    fill_opacity=0.7,
    line_opacity=0.2,
    nan_fill_color='white',
    legend_name='Country of Origin (%)'
).add_to(m)

# Save to html
map_path = reports_path / 'walmart_folium_chloropleth_pct.html'
m.save(map_path.as_posix())
m

Countries of origin for Walmart shipments, by count

这不是很有用,因为中国控制得如此彻底,其他一切都接近于零。白色区域是根本没有向沃尔玛发货的国家(至少在数据中是这样)。黄色区域向沃尔玛发货,但百分比为个位数。

我在上面的原产国中增加了两列是有原因的。让我们再次绘制地图,但这次使用装运百分比的记录。为了简洁起见,我将省略代码,但我只是用‘log pct’替换了参数中的第二个元素。

Countries of origin for Walmart shipments, by log(count)

这更有指导意义,因为它显示了亚军之间的相对位置。看着这张地图,我对那些几乎为零但又不完全为零的国家感到好奇。从视觉上看,沙特对我来说是一个奇迹。

xdata[xdata['COUNTRY OF ORIGIN']=='Saudi Arabia']['PRODUCT DETAILS'].describe().to_dict(){'count': 3,
 'unique': 3,
 'top': '320 BAGS, 19,200 KG OF ETHIOPI A ARABICA COFFEE SIDAMO GRAD- 2 TOP QUALITY REF P2006A, PA CKAGE: JUTE BAGS OF 60 KGS EA CH DELIVERY TERMS: FOB DJIBOU TI NET SHIPPED WEIGHT FDA R EGISTRATION NO. 11826035706 S',
 'freq': 1}

啊哈,好像是从埃塞俄比亚转运过来的咖啡。看了一眼其他两件物品,显示花岗岩板和个人物品,而不是预期的 pertroleum 产品。另一件值得注意的事情是,“产品详细信息”条目有一些奇怪的断词问题(不限于此条目)。

看着分类数据框的尾端,我看到了韩国,考虑到它们在电子领域的规模,我想它们应该有不止一批货。

countries_of_origin.sort_values(by=['count'], axis=0, ascending=False).tail(4)

果然,韩国在数量上是第三名,如果我们用上面的头(3)替换尾(4),我们会看到这一点,这意味着韩国的单独发货是一个数据输入错误。另请参见中国台湾台湾。向这些数据的所有者提供的一些反馈是,在输入数据时需要标准的国家名称。

在我们离开映射部分之前,我想指出 leav 的一个奇怪之处,我花了一些时间才弄明白。为了正确设置 choropleth 函数的 key_on 参数,我查看了 leav 数据文件leav/examples/data/world-countries . JSON以查找数据结构中的名称,给出了key _ on = ' feature . properties . name '。

重要的事情

现在我们已经确定了哪些国家运送的物品数量最多,让我们来看看运送最重物品的国家。熊猫分组食谱对理解下面的表达很有帮助。

top_by_weight = countries_of_origin.sort_values(by=['max'], axis=0, 
  ascending=False)[0:10]['COUNTRY OF ORIGIN'].valuestw3 = xdata.groupby(['COUNTRY OF ORIGIN']).apply(
    lambda subf: 
        subf.sort_values('WEIGHT (KG)', 
                         ascending=False).head(3))cols_of_interest = ['COUNTRY OF ORIGIN', 'WEIGHT (KG)', 
     'PRODUCT DETAILS', 'ARRIVAL DATE']# [https://www.wolframalpha.com/input/?i=3e%2B07+kg](https://www.wolframalpha.com/input/?i=3e%2B07+kg)
#  ≈ (0.7 to 1) × mass of a Handy size cargo ship
mass_handy_size = 3.0e+07 #kgtw3.loc[(tw3['COUNTRY OF ORIGIN'].isin(top_by_weight)) & (tw3['WEIGHT (KG)']>mass_handy_size)][cols_of_interest]

回想一下原产国是用 groupby 和‘重量(KG)’构成的,所以这里的 max 指的是重量。我不得不承认,我对排名靠前的国家感到非常惊讶,但当我看到这些产品时,我感到更加惊讶。

来自委内瑞拉的装运量最大,高出两个数量级。因为 dataframe 显示截断了“产品详情”栏,所以我们要确保我们在这里谈论的不是橄榄油…

list(xdata[xdata['WEIGHT (KG)']>1e+09]['PRODUCT DETAILS'])[0]'5,550.023 METRIC TONS (49,849 BBLS) LIGHT VIRGIN NAPHTHA'

石油石脑油是一种源自原油精炼的中间烃液体流。通过查看产品详细信息,我们看到出货量最大的是石油产品(烷基化油、汽油、石脑油)、建筑材料(岩石和水泥)和颗粒尿素(!?).把我搞得屁滚尿流他们用那个做了什么……

对我来说,这里隐藏的宝石是供应石油产品的各种意想不到的国家,以及一个预期的石油出口国(科威特)运送尿素。由 Wolfram Alpha 提供的另一个有趣的事实是,从委内瑞拉运来的石脑油几乎和吉萨大金字塔一样重。

停止

因为我们有“重量(KG)”和“集装箱数量”字段,所以我们可以计算出标准集装箱中的装运百分比。

考虑到“重量(KG)”几乎涵盖了 10 个数量级,并且还包括一些零值,我们会发现添加一列“log_weight_kg”很有用。

xdata['log_weight_kg'] = xdata['WEIGHT (KG)'].apply(lambda x: np.log(max(1, x)))

xdata['体重(公斤)']。describe() 我们看到,一批货物的平均重量为 48815.86 千克,Wolfram Alpha 称这大约是一架波音 747–200 f 飞机载重量的一半。绘制“log_weight_kg”列的直方图可以得出:

其中红色虚线是中间值。

接下来,让我们来看看可能用标准 20 或 40 英尺集装箱装运的货物,按重量计算。这里我假设‘重量(千克)’是货物的净重

向数据集中添加一个“kg_per_container ”,在这里我们对缺失值进行标准化,以便我们为每批货物至少准备一个集装箱。

xdata['kg_per_container'] = xdata.apply(calc_kg_per_container, axis = 1)
containerizable = xdata[xdata['kg_per_container'] <= NW_KG_DRY_CONTAINER_40FT]

如果它符合 40 英尺集装箱的重量要求,我们认为它是“可装箱的”,简单的计算表明 99.6%的装运都是如此。通过将我们的注意力缩小到这一大部分出货量,将大的异常值放在一边,我们可以对这些较小的出货量有一个更精细的了解。

每个集装箱的重量基本上稳步下降,除了在 19000 公斤/集装箱左右有一个小高峰。这可能是一个值得进一步研究的有趣领域。

另一个维度

为了强调为每个数据集创建数据字典的重要性,我们现在考虑“M.UNIT”列。我假设‘M . UNIT’是‘MEASUREMENT’列的单位(如果是这样,这种关系应该记录在数据字典中)。

xdata['M.UNIT'].value_counts().to_dict(){'CM': 93812,  'X': 47585,  'CF': 321,  'M': 128,  'F': 24,  'CC': 11,  'MM': 4,  'SS': 3,  'XX': 3,  'FF': 1}

我们可以猜测‘CM’的意思是立方米,‘CF’是立方英尺,但是其他的呢?重复我最初的观点,我们不应该去猜测;这些应该在数据字典中给出。既然看来我们必须猜测,让我们从不太常见的测量开始。

low_units = ['F', 'CC', 'MM', 'SS', 'XX', 'FF']
cols_of_interest = ['COUNTRY OF ORIGIN', 'WEIGHT (KG)', 'QUANTITY', 'CONTAINER COUNT',
                    'MEASUREMENT', 'M.UNIT', 'PRODUCT DETAILS'] # , 'ARRIVAL DATE'
pd.set_option('display.max_colwidth', 125)
pd.set_option('display.max_rows', 50)
xdata[xdata['M.UNIT'].isin(low_units)][cols_of_interest]

The first few entries of the less common M.UNIT collection

对于 low_units 中的六个不太常见的“M.UNIT”值,我可以容易地辨别的唯一模式是,如果“M.UNIT”是“F”、“FF”或“MM”,那么“MEASUREMENT”是零,所以这些可能是可忽略的。其他人将不得不保持神秘,直到我们可以与数据所有者交谈。

我们可以快速了解所有使用 seaborn 制造剥离场的单位的分布情况。我们将自己限制在一个 40 英尺集装箱的数据子集内。

xic = xdata[(xdata['CONTAINER COUNT']>0) & (xdata['WEIGHT (KG)']>0) & (xdata['kg_per_container']<=NW_KG_DRY_CONTAINER_40FT)]g = sns.stripplot(x='MEASUREMENT', y='M.UNIT', data=xic)
sns.despine() # remove the top and right line in graph
g.figure.set_size_inches(6,4)
plt_path = figures_path / 'measure_stripplot.png'
plt.savefig(plt_path.as_posix(), format='png'

Distribution of MEASUREMENT values by M.UNIT

我们将在下面更详细地观察“CM”的分布。

现在让我们来看看最常见的“公制单位”,“厘米”。使用 describe() ,我们知道如果‘M . UNIT’=‘CM’,那么‘MEASUREMENT’有非常大的值和零值,所以我们取一个子集:

xdata_cm = xdata[(xdata['M.UNIT'] == 'CM') & (xdata['MEASUREMENT'] > 0.0)].copy()
xdata_cm['logmeasure'] = xdata_cm['MEASUREMENT'].apply(lambda mm: np.log10(mm))

我们可以在这个子集上使用 seaborn 包来给我们一个漂亮的箱线图,这是一个与我们在上面看到的 stripplot 不同的视图。

max_logmeasure = xdata_cm.logmeasure.max()
max_logmeasure_shipment_id = xdata_cm['logmeasure'].idxmax()g = sns.boxplot(x = xdata_cm['logmeasure'])
# remove the top and right line in graph
sns.despine()_ = plt.annotate(s = max_logmeasure_shipment_id,
             xy = (max_logmeasure,0),
             xytext=(0.85, 0.65), textcoords='axes fraction', # bottom, left
             # Shrink the arrow to avoid occlusion
             arrowprops = {'facecolor':'gray', 'width': 1, 'shrink': 0.09, 'headlength':9},
             backgroundcolor = 'white')g.figure.set_size_inches(6,4)
# plt.show()
plt_path = figures_path / 'logmeasure_box.png'
plt.savefig(plt_path.as_posix(), format='png')

我们添加的注释显示了这个极端异常值的行 id。我们还可以从该图和 describe() 中看到,四分位数范围是 58(从 7 到 65),大约有 2000-50000 个异常值,然后还有几个高于这个值。

cols_of_interest = ['SHIPPER', 'WEIGHT (KG)', 'QUANTITY', 'MEASUREMENT', 'CONTAINER COUNT', 'PRODUCT DETAILS']
xdata_cm.sort_values(by='logmeasure', ascending=False)[cols_of_interest].head(10)

The largest values of log(MEASUREMENT)

最上面的条目,我们的极端异常值,看起来非常可疑。如果“测量”以立方米为单位,这将相当于每年全球石油装运量的 10%左右。更令人难以置信的是“数量”字段。如果消息属实,光是这批货物就能为地球上三分之一的人提供一台 40 英寸的高清液晶电视。我就是不信。

再看看“迈耶工业”,我们得出的单位重量为 13.2 千克,这对于一套铝制炊具来说似乎是合理的。然而,我仍然不能使“测量”字段工作。从重量的角度来看,这批货物可能只装在 6 个 40 英尺的集装箱里,少于报道的 16 个。然而,16 个 40 英尺的集装箱只有 1083 立方米的容积,远远小于“测量”区域的 29000 立方米。

“CM”的“M.UNIT”是立方米,我们的猜测有可能是正确的吗?让我们来看看第三个分位数的一些值。

xdata_cm_sm = xdata_cm[xdata_cm['MEASUREMENT'] < CAPACITY_CONTAINER_40FT]
xdata_cm_sm.sort_values(by='logmeasure', ascending=False)[cols_of_interest].head(10)

Measurement should indicate that it would fit in a 40ft container

纯属巧合的是,这份清单中的第一项也是炊具,每箱重量为 13.2 公斤,同上。快速检查亚马逊上的 18 件套炊具,我们得到的产品尺寸为 11.5 x 22.8 x 13 英寸(3409 英寸或 0.05586 米),运输重量为 21.9 磅。这比这里装运的炊具要轻一点,如果我们按重量差异的比例放大体积,我们得到 0.074225 立方米。所有 942 套,完美包装,则需要大约 69.92 立方米的体积,这在“测量”值 67 的大致范围内(超出 4.3%)。

我们可以看更多的例子,但是有证据表明“CM”的意思是立方米。本节更重要的一点是,该数据集在用于预测之前似乎需要大量清理。

欺诈检查

在我们对最重的货物的探索中,来自巴哈马的物品让我惊讶——当我想到巴哈马时,我会想到蓝色的海水和沙滩,而不是石油出口。对巴哈马最大出口量的描述是“1 大堆 277328.140 桶烷基化油”。烷基化油是车用汽油的高辛烷值调和成分。为了便于讨论,让我们假设审计团队想要检查这可能的欺诈。看起来似乎没有足够的有用数据,但让我们看看是否可以帮助审计团队将这些数据从黄色标志(可疑)变为红色标志(欺诈)或绿色标志(正常交易)。)

我们将把“发货人”和“收货人地址”这样的字段留给我们的私家侦探精英团队,同时我们来看看一些更深奥的东西。需要指出的重要一点是:我不是石油运输方面的专家,所以我在这里做了很多假设。

顺便提一下,当我查看每个集装箱的重量时,我对这个条目产生了兴趣;“容器计数”是 1,但重量很大,所以它弄乱了我漂亮的直方图。

从“产品详情”中,我们得到数量:277328.140 桶。烷基化物的密度取决于温度。如果我们假设密度在 15–38°C 范围内呈线性变化,我们可以推导出一个给定重量和密度的温度公式。

Photo by Manki Kim on Unsplash

我们有桶的数量,事实上一桶是 42 美国标准加仑,换算后我们得到升的数量。我们从“重量(千克)”栏中得到重量,除以重量得到密度。将它代入我们的线性公式,我们发现温度是 21.24 摄氏度(这些计算在 Jupyter 笔记本上有详细说明)。

“抵达日期”是 2013 年 1 月 31 日。一艘轻便的船以大约 14 节的速度行驶;使用这个站点我们看到从巴哈马拿骚到纽约的旅行时间是 3.2 天,2013 年 1 月 27 日的天气在拿骚最低 21°C,最高 27°C。所以重量和产品细节似乎是可信的。

要最终确定这一点,必须看一下合同。我在 SEC 档案中找到的一份协议(不涉及沃尔玛)有这样一个条款:

“Barrel” — 42 U.S. standard gallons measured at 60 degrees Fahrenheit [15.556 °C].

如果我们假设同样的温度适用于这里,我们会有多远?简单的代数告诉我们,如果是这样的话,他们的出货量比必要的多出 0.7%。我想我们可以告诉审计员用绿旗做标记。

最后的想法

如果您将数据想象成一个多维的尖球:

Wolfram Mathematica Version 12 Spikey

您可以这样或那样转动它,看看哪些尖峰最突出(异常值)。之后,如果你去掉尖峰,你可以看看你的更典型的数据的形状。在本文中,我们已经通过观察计数和重量异常值做到了这一点。

如果您正在发布一个数据集,无论是内部的还是外部的,总是要包含一个数据字典,即使这些值看起来很明显。下面的参考资料部分有几个不错的资源。

令人惊讶的是,人们可以对许多数据集做些什么,即使它们似乎有不完整或有限的数据。通过使用来自不同列的数据,扫描一些文本字段,并使用外部来源,人们通常可以梳理出一些有趣的花絮。

感谢你和我一起踏上这个有趣的数据集的漫无边际的旅程。我希望我在这里概述的技术能够对您探索自己的数据集有所帮助。

参考资料和进一步阅读

源代码库中提供了一组完整的链接。这两个探索性数据分析参考都使用 R 语言,但是即使您只使用 Python,也值得一看。

  1. 如何制作数据字典,开放科学框架
  2. 数据字典:如何与最佳实践卡尔·安德森
  3. 数据字典,美国地质调查局
  4. 探索性数据分析与 R ,罗杰·婷·彭
  5. 探索性数据分析,约翰·霍普金斯大学 via Coursera
  6. 针对每个数据集的 3 种出色的可视化技术Rahul Agarwal
  7. GeoJSON 和 choropleth,Felipe,Frank Conengmo,Joshua Cano,FloChehab

机器学习中的奇异值分解:欠定最小二乘

原文:https://towardsdatascience.com/underdetermined-least-squares-feea1ac16a9?source=collection_archive---------11-----------------------

理解 SVD 如何帮助导出超定和欠定线性系统的一致最小二乘权重向量

Source: Tim Hill on Pixabay

本文讨论了超定和欠定线性系统中最小二乘权重向量的差异,以及如何应用奇异值分解 (SVD)来导出一致的表达式。它在很大程度上基于 Rebecca Willet 教授的课程机器学习的数学基础,并且假设了线性代数的基础知识。

“典型”最小二乘法

最小二乘可以描述为:给定形状 n × p 的特征矩阵 X 和形状 n × 1 的目标向量 y 我们要找到一个形状 n × 1 的系数向量w’直觉上,最小二乘法试图通过最小化每个单个方程结果的残差平方和来近似线性系统的解。

在大多数情况下,我们假设 n ≥ p 并且 rank( X ) = p. 换句话说,观测值的数量不小于特征的数量并且没有一个特征是其他特征的线性组合(没有“冗余”特征)。一个线性系统 y = Xw 如果 n ≥ p超定。我们可以用 法方程 得到w’:

但是,如果 n < p 或者当 X 中的某些列是线性依赖时,矩阵 A 可能不可逆。当特征数大于观测数时,我们称线性系统 y = Xw 欠定

欠定最小二乘

n < p 、秩( X ) = n 时,系统 y = Xw 有无穷多个解。在这些解中,我们可以通过拉格朗日乘子法找到一个范数最小的解,并将其作为欠定线性系统的最小二乘权向量。

然而,为什么最小范数解是可取的?想象一个简单的例子,当你有下面的训练特征矩阵和目标向量时:

以下两个权重向量为训练数据提供了完美的拟合:

看这个的一种方式是:第三个特征是规模小。如果它容易受到测量误差的影响,并且我们对它赋予了很大的权重,那么我们对未知数据的预测可能会因为第三个特征而产生很大的偏差,从而远离真正的目标。所以第一种方案比较好。

下面展示了我们如何用拉格朗日乘数法导出最小范数解:我们想要在约束条件为 y = Xw 的情况下最小化∨w∨。介绍拉格朗日乘数 L :

在最佳条件下:

欠定最小二乘的权向量方程与超定最小二乘的权向量方程非常不同。

奇异值分解

本节提供了对 SVD 的基本介绍。考虑一个形状为n×p 的矩阵 X 。总是存在矩阵【σ】V使得:

UV 正交时:

**σ是对角线:

U 的列是左奇异向量,它们构成了 X 列的正交基。

**σ的对角元素称为奇异值(σ₁σ₂≥…≥σₚ≥0)。非零奇异值的个数是矩阵 X 的秩,σ的列是 X 的行的基础。

V 的行称为右奇异向量,它们是列上的基系数,用来表示 X 的每一列。

奇异值分解和最小二乘法

使用 SVD,我们可以重写最小二乘权重向量。以欠定最小二乘法为例:

上面的表达式看起来有点吓人,但是如果我们仔细看看:

这里σ⁺σ的伪逆,形状为 p × n 。我们可以通过转置σ并取其对角元素的倒数来得到它。那么欠定线性系统的最小二乘向量可以重写为:

超定最小二乘法也是如此(随意验证)。有了 SVD,我们就有了权重向量的一致表达式。

确认

为了验证我们的发现,我们将使用 Jester 数据集的子样本。样本包含 100 个观察值和 7200 个特征,可在这里获得。每个观察都是一个笑话,每个特征都是现有用户对该笑话的已知评级,等级为-10 到 10。

假设我们为一家公司工作,该公司根据客户的已知评级向他们推荐笑话。对于评价了 25 个笑话的新客户 Joan,我们希望能够知道她喜欢剩下的 75 个笑话,并向她推荐预测评价最高的笑话。

要做到这一点,考虑一下我们已知的对 100 个笑话的评分的用户。他们代表了不同的品味。我们可以将 Joan 的评级看作这些客户评级的加权和。然后,我们将使用这些 m 客户的 25 个笑话评级作为特征,并将 Joan 的已知评级作为目标来训练回归变量。它应该能够推广到琼还没有预测好的其他笑话,以便我们可以推荐预测得分最高的笑话。琼的评分在这里可以找到。

加载数据,并使用以下块将其分为训练集和测试集。请注意,琼的未知评级表示为-99。

当 m = 20 时,为了简单起见,我们将使用前 20 个用户作为我们的代表用户。我们将根据琼对 25 个笑话的评价来计算权重,并将琼的评价作为目标。线性系统是超定的。当 m = 7200 时,线性系统欠定。使用以下代码准备数据。

使用 SVD 的 scikit-learn 型最小二乘估计器实现如下:

计算权重向量,并将其与从正规方程获得的权重向量进行比较:

对于 m = 20 和 m = 7200,我都得到“真”。你可以自己验证。

为了说明欠定最小二乘法如何提供对训练数据的完美拟合,我们可以在训练集和测试集上可视化预测值和真实目标。在这里有相应的代码

这篇文章是何坤宇写的。昆玉目前是芝加哥大学的硕士生。他发现理解统计建模和机器学习技术、将它们应用于真实世界的数据并帮助创建金融服务行业的端到端解决方案是一件有趣的事情。在 LinkedIn 上联系昆玉!🐷

* [## 昆玉何-即将上任的全球量化策略非周期分析师-美银美林…

芝加哥大学正在接受理学硕士计算分析项目培训的数据科学家。对…充满热情

www.linkedin.com](https://www.linkedin.com/in/kunyuhe/)*

机器学习中的欠拟合和过拟合以及如何处理!!!

原文:https://towardsdatascience.com/underfitting-and-overfitting-in-machine-learning-and-how-to-deal-with-it-6fe4a8a49dbf?source=collection_archive---------3-----------------------

Photo by Markus Spiske on Unsplash

机器学习中模型性能不佳的原因是数据过拟合或欠拟合。

在这个故事中,我们将发现机器学习中的泛化概念以及随之而来的过拟合和欠拟合问题。

我们开始吧!!!

机器学习中的泛化

泛化指的是机器学习模型学习的概念在多大程度上泛化到模型尚未看到的特定示例或数据。

举个例子,假设我给你看一张猫的图片,让你给我“分类”;假设你正确地识别出它像一只猫,如果我把猫向左移动三个像素,你还能识别出它是一只猫吗?如果我把它翻过来呢?如果我把它换成一只不同品种的猫,你还能认出它吗?几乎可以肯定,所有这些问题的答案都是因为我们作为人类,我们以不可思议的轻松进行概括。另一方面,机器学习很难做到这些事情;它只在对一个特定图像进行分类时有效。

虽然机器学习可能能够在某个领域实现超人的性能,但除了它明确创建的领域之外,底层算法在任何其他领域都不会有效,因为它没有能力在该领域之外进行推广。从这个意义上来说,概括指的是智力的抽象特征,它使我们能够同时在数千个学科中发挥作用。

当我们谈论机器学习模型对新数据的学习和推广情况时,有一个机器学习中使用的术语,即过拟合和欠拟合。

过拟合和欠拟合是机器学习算法性能差的两个最大原因。

适合度

在统计学中,a 的拟合优度描述了它对一组观察值的拟合程度。

统计学通常描述拟合优度,它是指用于估计函数的近似值与目标函数匹配程度的度量。

过度拟合与欠拟合

我们可以通过观察相反的问题——欠拟合来更好地理解过拟合。

当模型过于简单(由太少的特征提供信息或太多的正则化信息)时,会发生欠拟合,这使得它在从数据集学习时不灵活。

简单的学习者倾向于在他们的预测中有较少的变化,但是更多偏向错误的结果。另一方面,复杂的学习者倾向于在他们的预测中有更多的变化。

让我给你打个比方来解释过度拟合和欠拟合。

过度拟合的模型就像主题专家:

他们对某个特定领域非常了解,例如主题专家。你问他们关于他们工具功能的任何问题(甚至是细节),他们可能会非常准确地回答你。但是当你问他们为什么油价会波动时,他们可能会做出明智的猜测,并说出一些奇怪的话。

就机器学习而言,我们可以将它们表述为过于关注训练集(程序员)和学习复杂的关系,而这些关系通常对新数据(测试集)可能无效。

不称职的模特就像那些想成为板球运动员但被父母强迫从事工程的工程师。他们对工程和板球都不太了解。他们对自己所做的事情从来都不感兴趣,对所有的事情都没有足够的了解。

就机器学习而言,我们可以说它们对训练集关注太少。既不适合培训也不适合测试。

如何检测欠拟合?

当一个模型试图建模的数据过于简单时,它就不适合。

检测这种情况的一种方法是使用偏差-方差法,它可以表示为:

当你有一个高偏差时,你的模型是不适合的。

如何避免不合身:

更多的数据通常不会有帮助。事实上,这可能会增加训练误差。因此,我们应该增加更多的功能。因为这扩大了假设空间。这包括从现有要素创建新要素。同样,更多的参数也可以扩展假设空间。

如何检测过度拟合?

过度拟合和一般机器学习的一个关键挑战是,在我们实际测试之前,我们无法知道我们的模型在新数据上的表现如何。

为了解决这个问题,我们可以将初始数据集分成单独的训练测试子集。这种方法可以估计我们的模型在新数据上的表现。

如果我们的模型在训练集上比在测试集上表现得更好,那么我们很可能过度拟合了。

例如,如果我们的模型在训练集上有 95%的准确率,但在测试集上只有 48%的准确率,这将是一个很大的危险信号。

如何防止过度拟合

检测过度拟合是有用的,但不能解决问题。幸运的是,您有几个选择可以尝试。

以下是一些最流行的过度拟合解决方案:

  • 交叉验证:找出样本外预测误差的标准方法是使用 5 重交叉验证。
  • 提前停止:它的规则为我们提供了在学习者开始过度适应之前可以运行多少次迭代的指导。
  • 剪枝:剪枝在构建相关模型时被广泛使用。它只是删除了对当前问题没有多少预测能力的节点。
  • 正则化:它引入了一个代价项,用于在目标函数中引入更多的特征。因此,它试图将许多变量的系数推至零,从而减少成本项。
  • 移除特征:有些算法内置了特征选择。对于没有概化的要素,您可以通过移除不相关的输入要素来手动提高它们的概化能力。一个有趣的方法是讲述一个关于每个特性如何适应模型的故事。这就像数据科学家在软件工程师的橡皮鸭调试技术上的旋转,他们通过对橡皮鸭逐行解释来调试代码。
  • 用更多的数据训练:不是每次都管用,但是用更多的数据训练可以帮助算法更好的检测信号。在早期的儿童身高与年龄模型的例子中,很明显采样更多的学校将有助于你的模型。当然,情况并不总是这样。如果我们只是添加更多的噪声数据,这种技术不会有帮助。这就是为什么您应该始终确保您的数据是干净的和相关的。
  • 集成:集成是用于组合来自多个独立模型的预测的机器学习方法。有几种不同的组装方法,但最常用的两种是:

装袋 试图减少复杂模型过拟合的机会。

  • 它并行培养了大量的“强”学习者。
  • 强学习者是一种相对不受约束的模式。
  • Bagging 然后将所有强学习者结合在一起,以便“平滑”他们的预测。

Boosting 试图提高简单模型的预测灵活性。

  • 它按顺序训练出大量的“弱”学习者。
  • 弱学习者是一个受约束的模型(也就是说,你可以限制每个决策树的最大深度)。
  • 序列中的每一个都着重于从之前的错误中学习。
  • 然后,Boosting 将所有弱学习者组合成一个强学习者。

虽然 bagging 和 boosting 都是整体方法,但它们从相反的方向处理问题。

Bagging 使用复杂的基础模型,并试图“平滑”他们的预测,而 boosting 使用简单的基础模型,并试图“提高”他们的总体复杂性。

如果你想了解更多关于集合模型的知识,集合模型的重要技术:bagging 和 boosting。请在下面的链接中浏览我以前的故事。

[## 装袋和助推的区别?

装袋和助推是全球各种数据爱好者常用的术语。但是到底装袋和…

medium.com](https://medium.com/@sainikhilesh/difference-between-bagging-and-boosting-f996253acd22)

我希望这篇文章能让你对这个话题有一个坚实的理解。在这篇文章中,你已经了解了机器学习中过度拟合和欠拟合的泛化术语。

你有任何关于过度合身、不够合身或与这篇文章相关的问题吗?留下评论,提出你的问题,我会尽力回答。

感谢阅读!❤

理解使用时间序列数据的数据分析和可视化。

原文:https://towardsdatascience.com/understand-data-analysis-visualisation-using-time-series-data-ee27827dab25?source=collection_archive---------13-----------------------

《让数据和时间说话》

Photo by Dylan Clifton on Unsplash

H 人类有幸拥有人工智能和数据科学,因为它帮助我们解决日常问题。我们经常会遇到大量的时间序列数据,这些数据与我们的日常活动非常相似。

在本帖中,我们将学习如何使用数据分析来洞察数据,并了解数据的行为。

我们使用了【Junglee Rummy business】时间序列数据集,在这里下载 。数据集归【Junglee Games】所有。访问 链接 以获得数据集的概述。你也可以 游戏。

我们必须了解与数据集相关的术语。让我们来看看:-

  • 入场费:这是玩家以卢比支付的入场费。
  • 座位:可以坐在桌子上的最大玩家数量,即数据集的 2,6 人。
  • 组成:实际加入牌桌的玩家数量。
  • 日期:2018 年 7 月 1 日至 2018 年 9 月 30 日的数据集,给出了每个表配置的每日数据。
  • 配置:定义为入场费—席位—构成的组合。
  • Cut % %:从每个用户的每场游戏中扣除的年龄金额。
  • '#Users ':当天至少玩了一场牌桌配置游戏的玩家(唯一玩家)的不同计数。
  • 用户现金游戏计数:当日用户在牌桌配置上玩的游戏总数。如果用户 A、B、C 一起玩一个游戏,那么值将是 3。
  • Rake:该日期从表配置中生成的收入总额。
  • 赌注:用户根据参加游戏的费用支付的总金额。

我们开始吧!

我们会加载重要的库,让我们来看一看数据。

***import******pandas******as******pd******import******seaborn******as******sns******import******matplotlib.pyplot******as******plt******import******numpy******as******np****# reading the data using pandas*
df = pd.read_excel('BI Skill Test - Data Set.xlsx')
df.head()

数据集非常直观。如果不能理解,请阅读上面的专栏描述。我们将把Cut%乘以 100,使其计算简单。

*# Multiplying cut% with 100 to make it easy for computation*
df['Cut %'] = df['Cut %'] * 100

基本统计

现在我们对数据有了一个简单的了解。分析数据集的基本统计数据是非常必要的。

*# Basic statistics of tha data*
pd.options.display.float_format = '**{:.0f}**'.format
df.describe()

在数据科学中,这些统计数据对于深入了解数据起着至关重要的作用。通过上表中的数字后,观察到的一些情况如下:

  1. 入场费: 用户玩一个游戏平均支付的入场费为 854 卢比,最低入场费为 5 卢比,最高入场费为 10000 卢比。大多数时候,用户支付 100 卢比作为入场费来玩游戏。
  2. 坐席: 坐在一起的玩家平均人数是 5 人,其中,平均 4 人上场。而最多有 6 名玩家。
  3. 削减%平均削减%为 13%。大多数玩家支付 15%作为提成。
  4. 【用户数量: 平均每天至少玩一个游戏的用户数量为 165,而每天至少玩一个游戏的用户数量最多为 1155。
  5. Rake: 公司平均每天赚的钱数是 10137 卢比。公司一天赚的最多的钱是 271200 卢比。公司大部分时间赚 3195 卢比。
  6. 赌注: 玩家投入游戏的最高金额是 4520000 卢比,而大多数时候用户支付 24000 卢比。

仅仅一行代码就包含了大量的信息。感谢熊猫。

将一些信息进一步可视化会很有趣。我们将使用matplotlib python 库来执行同样的操作。

让我们从用户支付的作为游戏入门费的总金额开始。

plt.figure(figsize=(9, 8))
sns.distplot(df['Wager'], color='g', bins=100, hist_kws={'alpha': 0.4})
plt.title("Total amount paid by the users in terms of Entry Fees to play the game")

根据上面的图表,我们观察到大部分时间用户在某一天支付大约 25000 卢比。

现在,让我们来看看该日期从表配置中产生的总收入。

plt.figure(figsize=(9, 8))
sns.distplot(df['Rake'], color='b', bins=100, hist_kws={'alpha': 0.4})
plt.title("Total amount generated in revenue from a table configuration for the date")

通过上面的图表和基本的统计数据,可以认识到公司每天大部分时间的收入在 3000 卢比左右。

B 用户支付卢比进入游戏

num_bins = 60
plt.hist(df['Entry Fee'], num_bins, facecolor='blue', alpha=0.5)
plt.title("Buy-in (money user pays) in rupees to enter the game")
plt.show()

我们观察到,大多数人购买票价低于 1000 卢比的门票。有一些用户花 10000 卢比作为入门费来玩这个游戏。

时间序列分析

数据分析和可视化让我们深入了解数据,在某些情况下,我们可能会遇到奇迹。因此,让我们深入数据集,执行时间序列分析。

我们主要关注的是数据的行为。

我们会将日期(按字母顺序书写)转换为对应的数字,并为日期、月份和年份创建单独的列。使用数字数据很容易进行数据分析。

我们将使用datetime python 类将日期转换为datetime格式。让我们看看它是如何工作的。

*# introducing datetime*
**from** **datetime** **import** datetime, date, time
datetime.strptime('July 1, 2018', '%B **%d**, %Y')

输出:

datetime.datetime(2018, 7, 1, 0, 0)

现在,我们将对整个日期列执行相同的操作。

*# converting date to datetime format*
date = []
**for** d **in** df['Date']:
    x = datetime.strptime(d, '%B **%d**, %Y')
    date.append(x)
df['my_date'] = date

print(df['my_date'][0].month)
print(df['my_date'][0].day)
print(df['my_date'][0].year)Output:7
1
2018

将日期时间转换为单独的列

*# converting datetime to individual columns*
day = []
month = []
year = []
**for** i **in** df['my_date']:
    day.append(i.day)
    month.append(i.month)
    year.append(i.year)df['day'] = day
df['month'] = month
df['year'] = yeardf.head(2)

现在,我们已经将日期转换为日期、月份和年份的个人列。让我们进行时间序列分析。

按月销售

*#sale by month*
sales_by_month = df.groupby('month').size()
print(sales_by_month)*#Plotting the Graph*
plot_by_month = sales_by_month.plot(title='Monthly Sales',xticks=(1,2,3,4,5,6,7,8,9,10,11,12))
plot_by_month.set_xlabel('Months')
plot_by_month.set_ylabel('Total Sales')
plt.title("Monthly sales analysis")

据观察,与其他月份相比,一月份的销售数量较高。随着时间的推移,销售额下降了。

白天销售

*#Sale by Day*

sales_by_day = df.groupby('day').size()
plot_by_day = sales_by_day.plot(title='Daily Sales',xticks=(range(1,31)),rot=55)
plot_by_day.set_xlabel('Day')
plot_by_day.set_ylabel('Total Sales')
plt.title("Daily sales analysis")

我们观察到,与其他月份相比,本月前五天的销售额较高。

如果我们能够获得每小时的数据,我们可以更好地分析销售行为。

每月玩家人数

观察每个月参与游戏的用户数量是个好主意。我们将使用boxplot来可视化相同的内容。

*# number of users played per month*
sns.boxplot(x='month', y='# Users', data=df)
plt.title("Number of users played per month")
plt.show()

随着时间的推移,每月的用户数量逐渐增加。如果我们关注分位数,一月份平均每天大约有 100 人。但最多也就 400 人左右。在 9 月份,平均每天大约有 220 个用户,而每天大约有 1200 个用户。其他月份也是如此。

每月在桌面配置中玩的用户数

*# Number of users played in table configuration per month.*

sns.boxplot(x='month', y='User Cash Game Count', data=df)
plt.title("Number of users played in table configuration per month")
plt.show()

同样,如果我们关注一张桌子上每个月玩的游戏数量。一月份一天大约有 100 人玩,而一天最多有 800 人玩。我们注意到在四月份玩的游戏数量有轻微的下降。在九月份,平均有 500 人在桌上玩,而最多有 3000 人在桌上玩,75%的时间有 900 人在桌上玩游戏。

公司每月赚取的利润

*# Profit earned by company every month*

sns.boxplot(x='month', y='Rake', data=df)
plt.title("Profit earned by company every month")
plt.show()

如果我们观察箱线图,公司在 9 月份平均获得了大部分利润。我们还看到,5 月份一次赚取的最大利润约为 300000 英镑。在二月份,公司收入最少。

用户每月支付的作为玩游戏入门费的总金额。

*# total amount payed by users as entry fee to play games per month.*

sns.boxplot(x='month', y='Wager', data=df)
plt.title("Total amount payed by users as entry fee to play games per month")
plt.show()

我们观察到与上述 RAGE 图相同的情况。在 5 月份,用户玩游戏花费的金额最大。平均而言,9 月份的记录不错。

现在让我们进行日间分析,看看我们是否能得到任何进一步的重要信息。

*# number of cash games played by users per day.* 
plt.figure(figsize=(20,18))
df.plot(kind='scatter', x='day', y='User Cash Game Count');
plt.title("Number of cash games played by users per day")
plt.show()

*# Revenue earned by users in days of month*

df.plot(kind='scatter', x='day', y='Rake');
plt.title("Revenue earned by users in days of month")
plt.show()

*# Amount spent by user every day of the month.*

df.plot(kind='scatter', x='day', y='Wager');
plt.title("Amount spent by user every day of the month")
plt.show()

我们对时间序列数据进行了基本的数据分析,可以从中获得很多信息。这只是操纵数据和灌输思想的游戏。

结论和意见

  • 入场费:首先,最高人数花费 100 卢比进入游戏。
  • 座位:一张桌子最多可以坐 6 个玩家,其中 3 个玩家大部分时间都在玩。
  • Cut%:在大多数情况下,每个用户要扣除 15%的金额。
  • 用户数量:每天至少有 112 名玩家玩桌上游戏。
  • 用户现金游戏:在大多数情况下,一天有 212 名玩家玩桌上游戏。
  • Rake:公司平均每天赚 3195 卢比。
  • 赌注:每天用户平均花费 24000 卢比。
  • 我们观察到,大多数用户花不到 1000 卢比玩游戏。
  • 据观察,与其他月份相比,一月份的销售数量较高。随着时间的推移,销售额下降了。
  • 我们观察到,与其他月份相比,本月前五天的销售额较高。
  • 我们观察到,随着时间的推移,用户的数量逐渐增加。但 5 月份的用户参与度比前几个月高得多。
  • 我们看到,公司在五月份创造了非常高的收入。
  • 我们已经观察到,该月的每一天都显示出公司的统一收入生成。
  • 总的来说,我们发现 5 月份是公司盈利能力最好的月份。它在这方面显示出显著的增长。而就盈利能力而言,二月份对公司来说有点奇怪。

源代码可以在我的 Github repo 上找到。我期待听到任何反馈或问题。感谢您阅读这篇文章。

LinkedIn 上关注我。

理解机器学习中的数据规范化

原文:https://towardsdatascience.com/understand-data-normalization-in-machine-learning-8ff3062101f0?source=collection_archive---------2-----------------------

如果你是数据科学/机器学习的新手,你可能很想知道“特征规范化”这个时髦词的本质和效果。如果您阅读过任何 Kaggle 内核,很可能在数据预处理部分找到了特性规范化。那么,什么是数据规范化,为什么数据从业者如此重视它?

1.定义

有不同类型的数据规范化。假设您有一个数据集 X ,它有 N 行(条目)和 D 列(特征)。 X[:,i] 表示特征 i ,X[j,:]表示条目 j。我们有:

Z 规范化(标准化):

我曾经错误地认为这种方法会产生标准的高斯结果。事实上,标准化并没有改变分销的类型:

pdf of standardized data

此转换将数据的平均值设置为 0,标准差设置为 1。在大多数情况下,标准化是按功能使用的

最小-最大归一化:

该方法将数据的范围重新调整为[0,1]。在大多数情况下,标准化也是按功能使用的

单位矢量归一化:

缩放到单位长度将一个向量(一行数据可以看作一个 D 维向量)收缩/拉伸到一个单位球体。当在整个数据集上使用时,转换后的数据可以被可视化为在 D 维单位球上具有不同方向的一束向量。

哇,正常化确实是一个宽泛的术语,它们各有利弊!在本文中,我将只关注标准化,否则这篇文章会太长。

2.效果

回归

理论上,回归对标准化不敏感,因为输入数据的任何线性变换都可以通过调整模型参数来抵消。假设我们有一个带有参数 WB 的线性模型:

W is D by 1, B is N by 1

通过减去矩阵 M 并乘以对角矩阵 T 可以实现列方式的改变

很容易证明,我们可以通过调整 WB 来抵消这种转换

因此,输入数据的标准化不应影响输出或准确性。好吧,如果数学上说标准化在回归中起不了什么作用,为什么它仍然如此受欢迎?

答。标准化提高了模型的数值稳定性

如果我们有一个简单的一维数据 X,并使用 MSE 作为损失函数,使用梯度下降的梯度更新是:

Y’ is the prediction

X 在梯度下降公式中,意味着 X 的值决定了更新速率。所以更大的 X 会导致渐变景观更大的飞跃。同时,给定 Y,较大的 X 导致较小的 W:

当 X 很大时,初始 W(随机选取的)和全局最小值之间的距离很可能很小。因此,当 X 较大时(学习率是固定的),该算法更可能失败,因为该算法朝着非常接近的目标 W 进行了巨大的跳跃,而需要小步前进。这种超调会让你的亏损振荡或爆发。

实验:

我使用以下代码人工创建了一个数据集:

X = np.arange(-5,5,0.1)
w = 0.5
b = 0.2
Y = X*w+b+(np.random.rand(X.shape[0],)-0.5)#add some noise to Y
X.reshape(100,1)
Y.reshape(100,1)

我在实验中使用了一个简单的线性回归代码:

class linear_regression:
    def fit(self, X,Y, lr=0.00001):
        epoch = 0
        loss_log = []
        while (epoch<8000):
            pred = self.predict(X)
            l = self.loss(pred,Y)# get loss
            loss_log.append(l)
            delta_w = 2*np.matmul((Y-pred).T, X) # gradient of w
            delta_b = sum(2*(Y-pred))
            self.w = self.w + lr*delta_w
            self.b = self.b + lr*delta_b
            epoch = epoch+1
        plt.plot(loss_log)
        plt.ylim([0.07,0.1])
        print (loss_log[-5:-1])
    def loss(self, pred,Y):
        error = Y-pred
        return sum(error**2)/error.shape[0] # MSE
    def predict(self, X):
        return X*self.w+self.b# n by 1
    def __init__(self):# initial parameters
        self.w=0.5# fixed initialization for comparison convenience
        self.b=0.5

下表显示了不同学习率和特征范围的最终 MSE。

final loss (MSE) after 8000 iterations

当 X 具有较大的系数(因此范围较大)时,模型需要较小的学习速率来保持稳定性。

b)。标准化可能会加快培训过程

第一个“定理”的推论是,如果不同的特征具有完全不同的范围,则学习率由具有最大范围的特征决定。这带来了标准化的另一个好处:加快了培训过程。

假设我们有两个特征:

X2 确定的学习率对于 X1 来说并不“伟大”,因为 X1 对于大得多的学习率来说是可以的。我们正在慢慢地走,而大的跳跃本可以被用来代替,这导致了更长的训练时间。我们可以通过标准化这两个特性来减少训练时间。

实验:

我使用以下代码人工创建了一个包含两个要素的数据集:

X1 = np.arange(-5,5,0.1)
X2 = np.arange(-5,5,0.1)
X = np.column_stack((X1,X2))
W = np.array([[0.1],[0.2]])
b = 0.1
Y = np.matmul(X,W)+b+(np.random.rand(X.shape[0],1) -0.5)
# add some noise to labels

使用稍微修改的线性回归代码:

class linear_regression:
    def fit(self, X,Y, lr=1e-4):
        epoch = 0
        loss_log = []
        while (epoch<80000):
            pred = self.predict(X)
            l = self.loss(pred,Y)# get loss
            loss_log.append(l)
            if l < 0.0792:
                print (epoch)
                break
            delta_w = 2*np.matmul((Y-pred).T, X) # gradient of w
            delta_b = sum(2*(Y-pred))
            self.w = self.w + lr*delta_w.T
            self.b = self.b + lr*delta_b
            epoch = epoch+1
        plt.plot(loss_log)
        plt.ylim([0.07,0.1])
        print (loss_log[-5:-1])
    def loss(self, pred,Y):
        error = Y-pred
        return sum(error**2)/error.shape[0] # MSE
    def predict(self, X):
        return np.matmul(X,self.w)+self.b# n by 1
    def __init__(self):
        self.w=np.array([[0.5],[0.5]])# for comparison convenience
        self.b=0.3

下表显示了对于给定的系数和学习率,达到全局最小值所需的迭代次数:

iterations to reach the global minimum

我们可以看到,当数据没有标准化时,模型需要更多的迭代(训练时间)才能完成。

基于距离的算法

K-mean 和 K-NN 等基于距离的聚类算法很有可能受到标准化的影响。聚类算法需要计算条目之间的距离。最常用的距离是欧几里德距离:

distance between i and j

很明显,特征缩放将改变节点之间的数值距离。

实验:

使用以下代码创建数据集:

def random_2D_data(x,y,size):
    x = (np.random.randn(size)/3.5)+x
    y = (np.random.randn(size)*3.5)+y
    return x,y
x1,y1 = random_2D_data(2,20,50)
x2,y2 = random_2D_data(2,-20,50)
x3,y3 = random_2D_data(-2,20,50)
x4,y4 = random_2D_data(-2,-20,50)
x = np.concatenate((x1,x2,x3,x4))
y = np.concatenate((y1,y2,y3,y4))

使用 K 均值对数据进行聚类:

clustering without any feature scaling

然而,对标准化数据做同样的事情会产生完全不同的结果:

affected result

太好了,我们有互相矛盾的结果。我应该选择哪个结果?

标准化为每个功能提供了“平等”的考虑。

例如,X 具有两个特征 x1 和 x2

如果直接计算欧氏距离,节点 1 和 2 会比节点 1 和 3 离得更远。然而,节点 3 完全不同于 1,而节点 2 和 1 仅在特征 1 (6%)上不同,并且共享相同的特征 2。这是因为特征 1 是“VIP”特征,以其大数值控制结果。

因此,如果我们不知道哪些特征是“钻石”特征,哪些是“珊瑚”特征,那么使用标准化来平等地考虑它们是一种很好的做法。

基于树的决策算法

决策树或随机森林等基于树的决策算法会在每个特征中寻找最佳分割点。分割点由使用特征正确分类的标注的百分比决定,该百分比对特征缩放具有弹性。因此,标准化对这种类型的 ML 模型没有任何重大影响。

神经网络

神经网络可以像回归一样抵消标准化。因此,理论上,数据标准化不应该影响神经网络的性能。然而,经验证据表明,数据标准化在准确性方面是有益的[1]。目前,我还没有看到原因,但可能与梯度下降有关。

很容易理解为什么标准化会提高训练时间。大输入值使激活函数饱和,如 sigmoid 或 ReLu(负输入)。这些类型的激活函数在饱和区域反馈很小的梯度或者根本没有梯度,因此减慢了训练。

large input kills backward gradient flow

3.摘要

标准化在许多情况下是有益的。它提高了模型的数值稳定性,并且通常减少了训练时间。然而,标准化并不总是好的。假设特征的重要性相等会损害基于距离的聚类算法的性能。如果特性之间存在固有的重要性差异,那么进行标准化通常不是一个好主意。

参考:

[1]: Shanker M,Hu MY,Hung MS,数据标准化对神经网络训练的影响,https://www . science direct . com/science/article/pii/0305048396000102

了解你的张量流模型是如何进行预测的

原文:https://towardsdatascience.com/understand-how-your-tensorflow-model-is-making-predictions-d0b3c7e88500?source=collection_archive---------10-----------------------

与 SHAP 一起探索学生贷款数据

介绍

机器学习可以比以往更快更准确地回答问题。随着机器学习在更多任务关键型应用中的使用,理解这些预测是如何得出的变得越来越重要。

在这篇博文中,我们将使用来自 TensorFlow 的 Keras API 构建一个神经网络模型,这是一个开源的机器学习框架。一旦我们的模型被训练,我们将把它与可解释性库 SHAP 集成。我们将使用 SHAP 来了解哪些因素与模型预测相关。

关于模型

我们的模型将预测大学毕业生相对于他们未来收入的毕业债务。这一债务收益比旨在作为一所大学投资回报(ROI)的粗略指标。这些数据来自美国教育部的大学记分卡,这是一个公开其数据的互动网站。

下表列出了模型中的功能。关于数据集的更多细节可以在数据文档中找到。

+-------------------------+--------------------------------------+
|         Feature         |             Description              |
+-------------------------+--------------------------------------+
| ADM_RATE                | Admission rate                       |
| SAT_AVG                 | SAT average                          |
| TRANS_4                 | Transfer rate                        |
| NPT4                    | Net price (list price - average aid) |
| INC_N                   | Family income                        |
| PUBLIC                  | Public institution                   |
| UGDS                    | Number of undergraduate students     |
| PPTUG_EF                | % part-time students                 |
| FIRST_GEN               | % first-generation students          |
| MD_INC_COMP_ORIG_YR4_RT | % completed within 4 years           |
+-------------------------+--------------------------------------+

我们从数据集中可用的债务和收益数据中推导出目标变量(债务收益比)。具体来说,就是毕业时积累的债务中位数(MD_INC_DEBT_MDN),除以毕业后 6 年的平均收入(MN_EARN_WNE_INC2_P6)。

创建散点图是为了可视化每个特征与我们的目标变量的相关性。下面的每张图表在 X 轴上显示特征,在 Y 轴上显示债务/收益比率。

我们将使用一个Sequential模型,有两个密集连接的隐藏层和一个 ReLU 激活函数:

model = keras.Sequential([
    layers.Dense(16, activation=tf.nn.relu, input_shape=[len(df.keys())]),
    layers.Dense(16, activation=tf.nn.relu),
    layers.Dense(1)

下面我们看到一个训练过程的图表。训练误差和验证误差之间的差距越来越大,这表明有些过度拟合。过度拟合很可能是由于数据集中具有所有所需特征的样本数量有限(1,117 个)。尽管如此,考虑到平均债务收益比大约为 0.45,0.1 的平均绝对误差证明了一个有意义的预测。

要在浏览器中直接运行笔记本,您可以使用 Colab 。在 Github 中也有。

关于 ML 公平的一句话

我们在这篇博文中调查的大学债务问题与更广泛的社会经济问题有着密切的联系。应该仔细评估任何模型及其训练数据,以确保它公平地服务于所有用户。例如,如果我们的训练数据主要包括来自高收入家庭的学生就读的学校,那么模型的预测将会歪曲那些学生通常有许多学生贷款的学校。

在可能的情况下,对中等收入学生的数据值进行了过滤,以便对不同家庭收入水平的学生进行一致的分析。大学记分卡数据将中等收入阶层定义为家庭收入在 3 万美元至 7.5 万美元之间的学生。并非所有可用的数据都提供此过滤器,但它可用于净价、收益、债务和完成率等关键功能。

记住这个思考过程,分析可以进一步扩展到数据集中的其他方面。同样值得注意的是,可解释性揭示了哪些特征对模型的预测贡献最大。它并不表明特征和预测之间是否存在因果关系。

SHAP 简介

可解释性本质上是理解模型中正在发生的事情的能力。通常在模型的准确性和可解释性之间有一个折衷。简单的线性模型易于理解,因为它们直接暴露了变量和系数。非线性模型,包括由神经网络或梯度增强树导出的模型,可能更难以解释。

进入 SHAP。SHAP,或 SHapley Additive exPlanations,是由 Scott Lundberg 创建的 Python 库,可以解释许多机器学习框架的输出。它有助于解释单个预测或汇总更大人群的预测。

SHAP 通过干扰输入数据来评估每个特征的影响。每个特征的贡献在所有可能的特征交互中被平均。这种方法是基于博弈论中 Shapley 值的概念。它提供了一种稳健的近似,相对于 LIME 等其他方法,这种近似在计算上可能更昂贵。关于 SHAP 理论的更多细节可以在图书馆作者的 2017 NeurIPS 论文中找到。

将 SHAP 与张量流 Keras 模型结合使用

SHAP 提供了几个解释器类,它们使用不同的实现,但都利用了基于 Shapley 值的方法。在这篇博文中,我们将演示如何使用 KernelExplainer 和 DeepExplainer 类。KernelExplainer 与模型无关,因为它将模型预测和训练数据作为输入。DeepExplainer 针对深度学习框架(TensorFlow / Keras)进行了优化。

SHAP DeepExplainer 目前不支持急切执行模式或 TensorFlow 2.0。然而,KernelExplainer 将工作得很好,尽管它明显慢了很多。

让我们从使用 KernelExplainer 绘制模型的概要图开始。我们将首先把训练数据总结成 n 个集群。这是一个可选但有用的步骤,因为生成 Shapley 值的时间会随着数据集的大小呈指数增长。

# Summarize the training set to accelerate analysis
df_train_normed_summary = shap.kmeans(df_train_normed.values, 25)# Instantiate an explainer with the model predictions and training data summary
explainer = shap.KernelExplainer(model.predict, df_train_normed_summary)# Extract Shapley values from the explainer
shap_values = explainer.shap_values(df_train_normed.values)# Summarize the Shapley values in a plot
shap.summary_plot(shap_values[0], df_train_normed)

摘要图显示了每个要素的 Shapley 值分布。每个点的颜色在光谱上,该特征的最高值是红色,最低值是蓝色。通过 Shapley 值的绝对值之和对特征进行排序。

我们从剧情来看一些关系。贡献度最高的前三个特征分别是SAT 平均分%第一代学生%非全日制招生。请注意,这些特征中的每一个都在右侧有显著的蓝点(低特征值),这里有正 SHAP 值。这告诉我们,这些特征的低值导致我们的模型预测高 DTE 比率。列表中的第四个特性净价具有相反的关系,其中净价越高,DTE 比率越高。

也可以使用force_plot()函数解释一个特定的实例:

# Plot the SHAP values for one instance
INSTANCE_NUM = 0shap.force_plot(explainer.expected_value[0], shap_values[0][INSTANCE_NUM], df_train.iloc[INSTANCE_NUM,:])

在这个特殊的例子中,大学的 SAT 平均分对其 0.53 的 DTE 预测贡献最大,推动其值更高。完成率(MD_INC_COMP_ORIG_YR4_RT)是第二重要的特征,将预测值推低。还可以查看整个数据集或一部分 n 实例中显示的一系列 SHAP 值,如下所示:

# Plot the SHAP values for multiple instances
NUM_ROWS = 10
shap.force_plot(explainer.expected_value[0], shap_values[0][0:NUM_ROWS], df_train.iloc[0:NUM_ROWS])

注意相关的特征

SHAP 将在相关变量间分割特征贡献。在为模型选择特征和分析特征重要性时,记住这一点很重要。让我们计算相关矩阵,看看我们会发现什么:

corr = df.corr()
sns.heatmap(corr)

让我们用相关矩阵交叉引用总结图中的前三个特征,看看哪些特征可能会被拆分:

  • SAT 平均分完成率呈正相关,与录取率一代比呈负相关。
  • 一代比兼职比相关,与完成率负相关。

几个相关的特征被分组在摘要图列表的顶部。值得关注的是榜单中排名靠后的完成率录取率

SHAP 有一个dependence_plot()功能,可以帮助揭示更多细节。比如我们来看看一代比兼职比的相互作用。正如我们在汇总图中观察到的,我们可以看到第一代比率与其 Shapley 值呈负相关。依赖图还向我们显示,当大学的兼职学生比例较低时,相关性更强。

shap.dependence_plot('FIRST_GEN', shap_values[0], df_train, interaction_index='PPTUG_EF')

结论

在这篇博文中,我们展示了如何用 SHAP 解释 tf.keras 模型。我们还回顾了如何使用 SHAP API 和几个 SHAP 绘图类型。最后,为了完整和准确的描述,我们讨论了关于公平性和相关变量的考虑。现在,您拥有了更好地了解 TensorFlow Keras 模型中发生的事情的工具!

要了解我在这里介绍的更多信息,请查看以下资源:

推特上让我知道你的想法!

理解 PyTorch 中明凯初始化和实现的细节

原文:https://towardsdatascience.com/understand-kaiming-initialization-and-implementation-detail-in-pytorch-f7aa967e9138?source=collection_archive---------4-----------------------

初始化很重要!知道如何用明凯均匀函数设置扇入和扇出模式

Photo by Jukan Tateisi on Unsplash

TL;速度三角形定位法(dead reckoning)

如果你通过创建一个线性层来隐式地创建权重,你应该设置modle='fan_in'

linear = torch.nn.Linear(node_in, node_out)
init.kaiming_normal_(linear.weight, mode=’fan_in’)
t = relu(linear(x_valid))

如果你通过创建一个随机矩阵显式地创建权重,你应该设置modle='fan_out'

w1 = torch.randn(node_in, node_out)
init.kaiming_normal_(w1, mode=’fan_out’)
b1 = torch.randn(node_out)
t = relu(linear(x_valid, w1, b1))

内容结构如下。

  1. 重量初始化很重要!
  2. 什么是明凯初始化?
  3. 为什么明凯初始化有效?
  4. 理解 Pytorch 实现中的扇入和扇出模式

重量初始化很重要!

初始化是一个创建权重的过程。在下面的代码片段中,我们随机创建了一个大小为(784, 50)的权重w1

*torhc.randn(*sizes)*从均值为 0、方差为 1 的正态分布返回一个填充了随机数的张量(也称为标准正态分布)。张量的形状由变量 argument *sizes*定义。

并且该权重将在训练阶段被更新。

*# random init*
w1 = torch.randn(784, 50) 
b1 = torch.randn(50)

**def** linear(x, w, b):
    **return** x@w + b

t1 = linear(x_valid, w1, b1)print(t1.mean(), t1.std())############# output ##############
tensor(3.5744) tensor(28.4110)

你可能想知道如果权重可以在训练阶段更新,为什么我们需要关心初始化。无论如何初始化权重,最终都会被“很好地”更新。

但现实并不那么甜蜜。如果我们随机初始化权重,就会引起两个问题,即 消失渐变问题爆炸渐变问题

消失渐变问题 表示权重消失为 0。因为这些权重在反向传播阶段与层一起被相乘。如果我们将权重初始化得很小(< 1),在反向传播过程中,当我们使用隐藏层进行反向传播时,梯度会变得越来越小。前几层的神经元比后几层的神经元学习慢得多。这导致轻微的重量更新。

爆炸渐变问题 表示权重爆炸到无穷大(NaN)。因为这些权重在反向传播阶段与层一起被相乘。如果我们将权重初始化得很大(> 1),当我们在反向传播过程中使用隐藏层时,梯度会变得越来越大。早期层中的神经元以巨大的步长更新,W = W — ⍺ * dW,并且向下的力矩将增加。

什么是明凯初始化?

明凯等人通过对 ReLUs 的非线性进行谨慎建模,推导出一种合理的初始化方法,使得极深模型(> 30 层)收敛。下面是明凯初始化函数。

  • a:该层之后使用的整流器的负斜率(默认情况下,ReLU 为 0)
  • fan_in:输入维数。如果我们创建一个(784, 50),扇入是 784。fan_in用于前馈阶段的。如果我们将其设置为fan_out,则扇出为 50。fan_out用于反向传播阶段。后面我会详细解释两种模式。

为什么明凯初始化有效?

我们通过比较随机初始化和明凯初始化来说明明凯初始化的有效性。

随机初始化

# random init
w1 = torch.randn(784, 50) 
b1 = torch.randn(50)
w2 = torch.randn(50, 10) 
b2 = torch.randn(10)
w3 = torch.randn(10, 1) 
b3 = torch.randn(1)def linear(x, w, b):
    return x@w + bdef relu(x):
    return x.clamp_min(0.)t1 = relu(linear(x_valid, w1, b1))
t2 = relu(linear(t1, w2, b2))
t3 = relu(linear(t2, w3, b3))print(t1.mean(), t1.std())
print(t2.mean(), t2.std())
print(t3.mean(), t3.std())############# output ##############
tensor(13.0542) tensor(17.9457)
tensor(93.5488) tensor(113.1659)
tensor(336.6660) tensor(208.7496)

我们用均值为 0、方差为 1 的正态分布来初始化权重,ReLU 后的理想权重分布应该是逐层略微递增的均值和接近 1 的方差。但是在前馈阶段,经过一些层之后,分布变化很大。

为什么权重的均值要逐层小幅递增?

因为我们使用 ReLU 作为激活函数。如果输入值大于 0,ReLU 将返回提供的值,如果输入值小于 0,将返回 0。

if input < 0:
    return 0
else:
    return input

ReLU 之后,所有负值都变成 0。当层变得更深时,平均值将变得更大。

明凯初始化

# kaiming init
node_in = 784
node_out = 50# random init
w1 = torch.randn(784, 50) * math.sqrt(2/784)
b1 = torch.randn(50)
w2 = torch.randn(50, 10) * math.sqrt(2/50)
b2 = torch.randn(10)
w3 = torch.randn(10, 1) * math.sqrt(2/10)
b3 = torch.randn(1)def linear(x, w, b):
    return x@w + bdef relu(x):
    return x.clamp_min(0.)t1 = relu(linear(x_valid, w1, b1))
t2 = relu(linear(t1, w2, b2))
t3 = relu(linear(t2, w3, b3))print(t1.mean(), t1.std())
print(t2.mean(), t2.std())
print(t3.mean(), t3.std())############# output ##############
tensor(0.7418) tensor(1.0053)
tensor(1.3356) tensor(1.4079)
tensor(3.2972) tensor(1.1409)

我们用均值为 0、方差为 **std**的正态分布初始化权重,relu 后的理想权重分布应该是均值逐层略微递增,方差接近 1。我们可以看到输出接近我们的预期。在前馈阶段,平均增量缓慢,std 接近 1** 。并且这种稳定性将避免在反向传播阶段中的消失梯度问题和爆炸梯度问题。**

明凯初始化显示出比随机初始化更好的稳定性。

了解 Pytorch 实现中的 fan_in 和 fan_out 模式

[nn.init.kaiming_normal_()](https://pytorch.org/docs/stable/nn.html#torch.nn.init.kaiming_normal_)将返回具有从均值 0 和方差std中采样的值的张量。有两种方法可以做到。

一种方法是通过创建线性层来隐式创建权重。我们设置mode='fan_in'来表示使用node_in计算 std

from torch.nn import init# linear layer implementation
node_in, node_out = 784, 50**layer = torch.nn.Linear(node_in, node_out)
init.kaiming_normal_(layer.weight, mode='*fan_in*')
t = relu(layer(x_valid))**print(t.mean(), t.std())############# output ##############
tensor(0.4974, grad_fn=<MeanBackward0>) tensor(0.8027, grad_fn=<StdBackward0>)

另一种方法是通过创建随机矩阵来显式创建权重,你应该设置mode='fan_out'

def linear(x, w, b):
    return x@w + b# weight matrix implementation
node_in, node_out = 784, 50**w1 = torch.randn(node_in, node_out)
init.kaiming_normal_(w1, mode='*fan_out*')** b1 = torch.randn(node_out)
**t = relu(linear(x_valid, w1, b1))**print(t.mean(), t.std())############# output ##############
tensor(0.6424) tensor(0.9772)

两种实现方法都是对的。平均值接近 0.5,标准差接近 1。但是等一下,你有没有发现一些奇怪的事情?

为什么模式不同?

根据文件,选择'fan_in'保留了正向传递中权重的方差大小。选择'fan_out'保留反向过程中的幅度。我们可以这样写。

node_in, node_out = 784, 50# fan_in mode
W = torch.randn(node_in, node_out) * math.sqrt(2 / node_in)# fan_out mode
W = np.random.randn(node_in, node_out) * math.sqrt(2/ node_out)

在线性层实现中,我们设置mode='fan_in'。是的,这是前馈阶段,我们应该设置mode='fan_in'。没什么问题。

但是为什么我们在权重矩阵实现中设置模式为 **fan_out**

[nn.init.kaiming_normal_()](https://pytorch.org/docs/stable/nn.html#torch.nn.init.kaiming_normal_)源代码背后的原因

def _calculate_fan_in_and_fan_out(tensor):
    dimensions = tensor.dim()
    if dimensions < 2:
        raise ValueError("Fan in and fan out can not be computed for tensor with fewer than 2 dimensions")if dimensions == 2:  # Linear
        **fan_in = tensor.size(1)
        fan_out = tensor.size(0)**
    else:
        num_input_fmaps = tensor.size(1)
        num_output_fmaps = tensor.size(0)
        receptive_field_size = 1
        if tensor.dim() > 2:
            receptive_field_size = tensor[0][0].numel()
        fan_in = num_input_fmaps * receptive_field_size
        fan_out = num_output_fmaps * receptive_field_sizereturn fan_in, fan_out

这是获得正确模式的源代码。tensor是尺寸为(784,50)的w1。所以fan_in = 50, fan_out=784。当我们在权重矩阵实现中将模式设置为fan_out时。init.kaiming_normal_()实际计算如下。

node_in, node_out = 784, 50W = np.random.randn(node_in, node_out)
**init.kaiming_normal_(W, mode='*fan_out*')**# what init.kaiming_normal_() actually does
    # fan_in = 50
    # fan_out = 784W = W * torch.sqrt(784 / 2)

好吧,有道理。但是如何解释在线性层实现中使用 **fan_in**

当我们使用线性隐式创建权重时,权重被隐式转置。下面是torch . nn . functional . linear的源代码。

def linear(input, weight, bias=None):
    # type: (Tensor, Tensor, Optional[Tensor]) -> Tensor
    r"""
    Applies a linear transformation to the incoming data: :math:`y = xA^T + b`.
    Shape:
        - Input: :math:`(N, *, in\_features)` where `*` means any number of
          additional dimensions
        - **Weight: :math:`(out\_features, in\_features)`**
        - Bias: :math:`(out\_features)`
        - Output: :math:`(N, *, out\_features)`
    """
    if input.dim() == 2 and bias is not None:
        # fused op is marginally faster
        ret = torch.addmm(bias, input, **weight.t()**)
    else:
        **output = input.matmul(weight.t())**
        if bias is not None:
            output += bias
        ret = output
    return ret

权重初始化为(out_features, in_features)的大小。例如,如果我们输入尺寸(784, 50),重量的大小实际上是(50, 784)

torch.nn.Linear(784, 50).weight.shape############# output ##############
torch.Size([50, 784])

这就是为什么 linear 需要先转置权重,再做 matmul 运算的原因。

 if input.dim() == 2 and bias is not None:
        # fused op is marginally faster
        ret = torch.addmm(bias, input, **weight.t()**)
    else:
        output = input.matmul(**weight.t()**)

因为线性层中的权重大小为(50, 784),所以init.kaiming_normal_()实际计算如下。

node_in, node_out = 784, 50**layer = torch.nn.Linear(node_in, node_out)**
**init.kaiming_normal_(layer.weight, mode='*fan_out*')**# the size of layer.weightis (50, 784)# what init.kaiming_normal_() actually does
    # fan_in = 784
    # fan_out = 50W = W * torch.sqrt(784 / 2)

摘要

在这篇文章中,我首先谈到了为什么初始化很重要,什么是明凯初始化。我将分解如何使用 PyTorch 来实现它。希望这个帖子对你有帮助。有什么建议就留言吧。

这个片段中的完整代码

查看我的其他帖子 中等 分类查看
GitHub:
bramble Xu LinkedIn:徐亮 博客:bramble Xu

参考

6 分钟理解机器学习

原文:https://towardsdatascience.com/understand-machine-learning-in-6-minutes-33b84095588c?source=collection_archive---------9-----------------------

看完这个帖子,

  1. 你将对什么是机器学习以及它是如何工作的有一个高层次的理解
  2. 你将能够考虑机器学习在你的业务或部门中的可能性

如果这值得你花六分钟时间——那就往下跳……

设置场景

理论上,软件程序每次运行时都会做同样的事情。这是因为它们采取的行动是显式编程的。

相反,随着经验的积累,机器学习程序会试图提高与目标相关的性能。这是因为只有目标是显式编程的,他们采取的行动是隐含的。

大多数人认为机器学习依赖于花哨的算法。也许有 40%是对的——虽然你需要算法,但它们不是性能或可能性的根本驱动力。重要的是算法用来学习的数据。

如何看待数据

不严格地说,数据只是存储的信息。在现实世界中,我们可以将数据集合分为结构化和非结构化。机器学习可以应用于结构化和非结构化数据,但理解其中的区别很重要。

结构数据

结构化数据存在于由行和列组成的表中。例如:

You’ll also hear ‘tabular data’ as a reference to structured data

非结构化数据

非结构化数据是指不存在于由行和列组成的表格中的所有数据。但是不要烦恼,仅仅因为它的结构更少,并不意味着我们不能用它来进行机器学习。非结构化数据的常见示例包括:

  • 文本
  • 形象
  • 录像
  • 语音记录
  • 文档(例如 1000 个 pdf)

机器学习的类型

机器学习程序分为三类:

  1. 监督学习 ,这里我们的算法给出了我们想要预测的目标答案的例子
  2. 无监督学习 ,其中我们的算法没有可供学习的答案示例,而是从数据中生成新的发现
  3. 强化学习 ,机器被暴露在一个新的环境中,并被要求从试错中学习

监督学习无疑是当今世界上使用最多的框架。如果你开始考虑机器学习的潜在应用,那么监督学习应该是你的第一站。

不过,不要睡在无监督学习上,它有特定的用例,我们很快就会谈到。与此同时,强化学习是一个仍在发展的框架,目前最广为人知的是在复杂游戏中击败人类。

结构化数据的监督学习

都在名字里,我们的模型需要 学会 如何找到目标变量,才会 知道 如何找到变量。机器需要一个数据集来学习,这个数据集必须包含目标变量。

让我们假设我们正在训练一个算法来预测动物的最大寿命。我们可以使用之前的数据集:

我们的算法将检查黄色因变量和绿色目标变量之间的关系。一旦经过训练,我们可以用机器人从未见过的新数据来测试我们的机器人。

如果我们的训练数据是好的,那么我们的算法将高度准确地预测动物(我们的目标变量)的最大寿命。

非结构化数据的监督学习

对于图像和其他非结构化数据,也是同样的逻辑。我们可以训练机器寻找某样东西,但首先,我们需要告诉它要寻找什么。给一个算法几千张有标签的猫和狗的照片,它会很快计算出如何分类你当地的家养动物。

Welcome to the most cliche machine learning example possible

这适用于图像情感、面部识别或任何其他图像分类问题。同样,数据质量是成功的最重要因素。给定高质量的标记数据集,训练模型相对容易。

无监督学习

无监督的机器学习算法检查数据中的模式,以识别新的趋势。一个常见的例子是聚类,其中算法将识别数据集中我们以前不知道的组。

无监督学习在特定的用例中非常有用。众所周知的例子包括:

  • 探测飞机发动机中的危险异常
  • 基于独特的行为将客户分成不同的群组
  • 检测奇怪的、潜在的欺诈性银行交易

强化学习

强化学习涉及动态环境中的算法,例如视频游戏或作为能源系统的控制器。该算法能够探索和尝试不同的行动——它对积极的决定给予奖励,对消极的决定给予惩罚。在一般意义上,强化学习人工复制了人类通过试错来学习的能力。

Humans learn from their mistakes right?

虽然现实世界的应用正在出现,但强化学习在很大程度上集中在研究领域。对于那些对强化学习和人工智能的加速发展感兴趣的人来说, AlphaGo 纪录片是一部精彩的电影。

思考什么是可能的

现在我们已经完成了机器学习 101,我们可以开始考虑潜在的机器学习应用。

x 标记了地点

首先要问的问题是,目标是什么?我们想知道什么?我们可以选择的一些目标变量示例:

  1. 温度->预测每日最高温度
  2. 物种->预测照片中的动物属于哪个物种
  3. 价格->预测什么样的价格能使产品或业务的利润最大化

一旦我们有了目标,我们就可以开始构建相关的数据集。例如,如果预测温度,我们将收集历史天气数据。或者如果识别物种,我们会尽可能多地寻找动物的照片

测量不确定性

很容易看到机器学习有无限的应用。很难说哪些潜在项目会成功。确定目标后,新的、更难的问题出现了——仅举几个例子:

  • 我们有足够的数据准确地代表目标吗?
  • 我们的数据中是否存在我们不想让模型知道的偏差?
  • 我们的算法会比人类表现得更好吗?需要吗?

可以想象,这些问题很少能在项目开始时得到回答。但这并不意味着它们不值得一问。在进行实验之前,理解你所做的假设是很重要的。

然而,虽然计划和风险评估很重要,但你永远不知道你的项目会有多成功。或者需要多长时间。或者你的数据是否带有不必要的偏见。在某些时候,你必须承认这种不确定性并投入其中。这是有趣的部分。

感谢阅读。你可以在推特上的@麦克德拉尼和互联网上的mackdelany@gmail.com找到我

直观地理解伯特的自我关注

原文:https://towardsdatascience.com/understand-self-attention-in-bert-intuitively-cd480cbff30b?source=collection_archive---------8-----------------------

解释什么是自我关注中的查询向量、关键向量和价值向量,以及它们是如何工作的

Photo by Stefan Cosma on Unsplash

先决条件

本文的目标是进一步解释什么是自我关注中的查询向量、关键向量和价值向量。如果你忘记了一些概念,你可以通过阅读插图变压器解剖伯特第一部分:编码器来回忆。

什么是自我关注

在插图变压器的中的“高层次的自我关注”部分,它在跳到代码之前给出了一个非常清晰的概念。

当模型处理每个单词(输入序列中的每个位置)时,自我注意允许它查看输入序列中的其他位置,以寻找有助于更好地编码该单词的线索。

让我重新措辞一下我的话。当模型处理一个句子时,自我注意允许句子中的每个单词查看其他单词,以更好地知道哪个单词对当前单词有贡献。更直观地说,我们可以认为“自我关注”是指句子会审视自身,以确定如何表示每个标记。

The Illustrated Transformer

例如,当模型处理上图右栏中的单词it时,自我注意查看其他单词以便更好地编码(理解)当前单词it。这就是伯特如何根据上下文(句子)理解每个单词的神奇之处。一个单词在不同的句子(上下文)中可以有不同的含义,自我关注可以基于上下文单词为当前单词编码(理解)每个单词。

直观理解自我关注中的 Q,K,V

我将用上面两篇文章中的例子和图表来解释什么是 Q,K,v。

taken from Attention Is All You Need

我们更简单地改写上述自我注意功能。

Q、K、V 分别称为查询、键、值。不要被他们的名字搞糊涂了。唯一的区别是三个代表的权重不同。你可以在下图中看到。

但是直观上,我们可以认为查询(Q)代表我们在寻找什么样的信息,键(K)代表与查询的相关性,值(V)代表输入的实际内容。因为它们在模型中扮演不同的角色。

这里 X 矩阵中的每一行表示一个记号的嵌入向量,所以这个 X 矩阵有 2 个记号。我们使用三个权重W^Q, W^K, W^V乘以相同的输入 X 得到 Q,K,v

为什么要计算查询(Q)和键(K)的点积

首先,点积的物理意义可以表示两个向量之间的相似性。所以你可以认为 Q 和 K 的点积是为了得到不同 tokens 之间的相似度(注意力得分)。比如我们有一个句子,Hello, how are you?。句子长度为 6,嵌入维数为 300。所以 Q,K,V 的大小都是(6, 300)

Q 和 K 的矩阵相乘如下图(softmax 之后)。矩阵乘法是点生成的快速版本。但是基本思想是相同的,计算任意两个标记对之间的注意力分数。

注意力得分的大小是(6,6)。您可能已经注意到,关注分数的大小只与序列长度有关。

每条线代表一个记号和其他记号之间的相似性。当当前令牌是Hello时,我们只需查看关注度矩阵中的第一行,就可以知道从Hello到其他令牌的相似度。比如Hellohow的相似度是6.51*10e-40。我们添加 softmax 来标准化数据。

为什么我们需要值(V)?

注意力得分矩阵可以表示任意两个标记对之间的相似性,但是由于缺少嵌入向量,我们不能用它来表示原句。这就是为什么我们需要 V,这里 V 还是代表原句。

我们用注意力得分(6x6)乘以 V(6300),得到一个加权求和结果。

直观上,我们用嵌入向量来表示每个记号,并且我们假设它们彼此不相关。但是在与关注分数相乘之后,在 V 中嵌入向量的每个令牌(“Hello”)将根据从当前(“Hello”)到其他令牌的关注来调整其在每个维度(列)中的值。

我们可以认为关注度矩阵是一个过滤矩阵,可以让价值矩阵更加关注那些重要的词,而对不重要的词关注很少。

为什么我们用不同的权重来得到 K 和 Q?

一些读者可能想知道为什么我们必须使用不同的权重来得到 K 和 Q?换句话说,我们可以通过 K 和 K 或者 Q 和 Q 的矩阵相乘来计算注意力得分,一个原因是两种计算不会有太大的差别,后一种也可以减少训练时的参数。

我觉得用不同的权重来得到 K 和 Q 是为了提高模型的泛化能力。因为有两个权重 W_K 和 W_Q,把同一个 X 投影到不同的空间。

如果我们用 K 和 K 之间的矩阵乘法,你会发现关注度得分矩阵会变成一个对称矩阵。因为它用了一个权重 W_K,把 X 投影到同一个空间。所以泛化能力会下降。在这种情况下,注意力分数过滤效果对于 value (V)来说不会很好。

查看我的其他帖子 中等 一分类查看
GitHub:
bramble Xu LinkedIn:徐亮 博客:bramble Xu

参考

[## 图示的变压器

讨论:黑客新闻(65 分,4 条评论),Reddit r/MachineLearning (29 分,3 条评论)翻译…

jalammar.github.io](http://jalammar.github.io/illustrated-transformer/) [## 剖析 BERT 第 1 部分:编码器

这是由米盖尔·罗梅罗和弗朗西斯科·英厄姆共同撰写的《理解伯特》的 1/2 部分。如果你已经明白了…

medium.com](https://medium.com/dissecting-bert/dissecting-bert-part-1-d3c3d495cdb3) [## 自然语言处理中的自我注意机制

在过去的几年里,注意机制在各种自然语言处理中得到了广泛的应用

medium.com](https://medium.com/@Alibaba_Cloud/self-attention-mechanisms-in-natural-language-processing-9f28315ff905) [## 《Attention is All You Need》浅读(简介+代码) — 科学空间|Scientific Spaces

2017 年中,有两篇类似同时也是笔者非常欣赏的论文,分别是 FaceBook 的《Convolutional Sequence to Sequence Learning》和 Google 的《Atten…

科学. fm](https://kexue.fm/archives/4765)

了解 CNN 的架构

原文:https://towardsdatascience.com/understand-the-architecture-of-cnn-90a25e244c7?source=collection_archive---------0-----------------------

Architecture of VGG16 (a CNN model)

2012 年,一场革命发生了:在一年一度的 ILSVRC 计算机视觉比赛期间,一种新的深度学习算法打破了记录!这是一个名为 Alexnet 的卷积神经网络。

卷积神经网络的方法论类似于传统的监督学习方法:它们接收输入图像,检测每个图像的特征,然后在其上拖动一个分类器。

但是,功能是自动学习的!CNN 自己执行提取和描述特征的所有繁琐工作:在训练阶段,分类误差被最小化以优化分类器的参数特征!

什么是 CNN?

卷积神经网络是指神经网络的一个子类:因此,它们具有神经网络的所有特征。然而,CNN 是专门为处理输入图像而设计的。他们的架构更加具体:它由两个主要模块组成。

第一个模块使这种类型的神经网络具有特殊性,因为它起着特征提取器的作用。为此,它通过应用卷积过滤操作来执行模板匹配。第一层使用几个卷积核对图像进行滤波,并返回“特征图,然后对其进行归一化(使用激活函数)和/或调整大小。

这个过程可以重复几次:我们过滤用新内核获得的特征图,这给了我们新的特征图来归一化和调整大小,我们可以再次过滤,等等。最后,最后的特征映射的值被连接成一个向量。这个向量定义了第一个模块的输出和第二个模块的输入。

The first block is encircled in black

第二块不是 CNN 的特征:事实上,它位于所有用于分类的神经网络的末端。输入向量值被转换(使用几个线性组合和激活函数)以向输出返回一个新的向量。这最后一个向量包含与类别一样多的元素:元素 I 表示图像属于类别 I 的概率。因此,每个元素在 0 和 1 之间,并且所有元素的总和等于 1。这些概率由该块的最后一层(因此也是网络的最后一层)计算,该层使用一个逻辑函数(二元分类)或一个 softmax 函数(多类分类)作为激活函数。

与普通神经网络一样,层的参数由梯度反向传播确定:在训练阶段,交叉熵被最小化。但是在 CNN 的情况下,这些参数特别指的是图像特征。

The second block is encircled in black

有线电视新闻网的不同层次

卷积神经网络有四种类型的层:卷积层、汇集层、 ReLU 校正层和全连接层。

卷积层

卷积层是卷积神经网络的关键组成部分,并且总是至少是它们的第一层。

其目的是检测作为输入接收的图像中一组特征的存在。这是通过卷积滤波来实现的:原理是在图像上“拖动”一个表示特征的窗口,并计算该特征与扫描图像各部分之间的卷积积。一个特征被视为一个过滤器:这两个术语在上下文中是等价的。

因此,卷积层接收几个图像作为输入,并用每个滤波器计算每个图像的卷积。过滤器与我们想要在图像中找到的特征完全对应。

我们为每一对(图像,过滤器)获得一个特征图,它告诉我们特征在图像中的位置:值越高,图像中相应的位置就越像特征。

Convolutional layer (source: https://www.embedded-vision.com)

与传统方法不同,特征不是根据特定的形式(例如 SIFT)预先定义的,而是由网络在训练阶段学习的!滤波器核指的是卷积层权重。它们被初始化,然后使用梯度下降通过反向传播进行更新

汇集层

这种类型的图层通常位于两个卷积图层之间:它接收多个要素地图,并对每个要素地图应用汇集操作。

汇集操作包括减小图像的尺寸,同时保留它们的重要特征

为此,我们将图像切割成规则的单元格,然后在每个单元格内保留最大值。在实践中,经常使用小正方形单元格来避免丢失太多信息。最常见的选择是不与重叠的 2x2 相邻单元格,或 3x3 单元格,彼此相隔 2 个像素的步长(因此重叠)。

我们在输出中得到与输入相同数量的特征地图,但是这些要小得多。

池层减少了网络中的参数和计算的数量。这提高了网络的效率,避免了过度学习。

与输入中接收到的最大值相比,合并后获得的最大值在要素地图中的定位不太准确,这是一个很大的优势!例如,当你想识别一只狗时,它的耳朵不需要尽可能精确地定位:知道它们几乎位于头部旁边就足够了!

ReLU 校正层

ReLU(整流线性单位)是指由 ReLU(x)=max(0,x) 定义的实非线性函数。从视觉上看,它如下所示:

ReLU 校正层用零替换作为输入接收的所有负值。它作为一个激活功能

全连接层

无论是否卷积,全连接层总是神经网络的最后一层,因此它不是 CNN 的特征。

这种类型的层接收输入向量并产生新的输出向量。为此,它对接收到的输入值应用一个线性组合,然后可能应用一个激活函数

最后一个全连接层将图像分类为网络的输入:它返回大小为 N 的向量,其中 N 是我们的图像分类问题中的类的数量。向量的每个元素指示输入图像属于一个类别的概率。

因此,为了计算概率,全连接层将每个输入元素乘以权重,进行求和,然后应用激活函数(如果 N=2,则为逻辑,如果 N>2,则为 softmax)。这相当于将输入向量乘以包含权重的矩阵。每个输入值都与所有输出值相连接,这一事实解释了术语“完全连接”的含义。

卷积神经网络学习权重值的方式与其学习卷积层滤波器的方式相同:在训练阶段,通过梯度的反向传播。

完全连接的图层决定了影像中要素的位置与类之间的关系。实际上,输入表是前一层的结果,它对应于给定特征的特征图:高值指示图像中该特征的位置(根据汇集的不同,更精确或更不精确)。如果图像中某一点的特征位置是某一类别的特征,则表中的相应值被赋予显著的权重。

各层的参数化

卷积神经网络与其他网络的不同之处在于层的堆叠方式,以及参数化。

卷积层和池层确实有超参数,也就是说您必须首先定义其值的参数。

卷积图层和池图层的输出要素地图的大小取决于超参数。

每个图像(或特征图)都是 W×H×D,其中 W 是其宽度(以像素为单位), H 是其高度(以像素为单位), D 是通道数(黑白图像为 1,彩色图像为 3)。

卷积层有四个超参数:

1.过滤器的数量 K

2.过滤器的尺寸:每个过滤器的尺寸为 F×F×D 像素。

3.拖动与图像上的滤镜相对应的窗口的步骤。例如,步长为 1 意味着一次移动窗口一个像素。

4.零填充 P:给图层的输入图像添加一个 P 像素厚的黑色轮廓。没有该轮廓,出口尺寸更小。因此,P=0 的卷积层叠得越多,网络的输入图像就越小。我们很快丢失了大量信息,这使得提取特征的任务变得困难。

对于每个尺寸为 W×H×D 的输入图像,池层返回一个尺寸为 Wc×Hc×Dc 的矩阵,其中:

选择 P=F-1/2 和 S=1 给出与输入中接收到的相同宽度和高度的特征地图。

池层有两个超参数:

1.单元格的大小 F:图像被分成大小为 F×F 像素的正方形单元格。

2.步骤 S:单元格之间相隔 S 个像素。

对于每个尺寸为 W×H×D 的输入图像,池层返回一个尺寸为 Wp×Hp×Dp 的矩阵,其中:

就像叠加一样,超参数的选择是根据一个经典方案进行的:

  • 对于卷积层,滤镜很小,每次在图像上拖动一个像素。选择零填充值,以便输入音量的宽度和高度在输出时不会改变。一般来说,我们然后选择 F=3,P=1,S=1 或者 F=5,P=2,S=1
  • 对于池层, F=2,S=2 是明智的选择。这个消除了 75%的输入像素。我们也可以选择 F=3,S=2:在这种情况下,单元格重叠。选择较大的小区会导致太多的信息丢失,并且在实践中导致不太好的结果

在这里,你有建立自己的 CNN 的基础!但是不要厌倦这样做:已经有许多适合大多数应用程序的体系结构。

在实践中,我强烈建议你不要从零开始创建一个卷积神经网络来解决你的问题:最有效的策略是采用一个现有的对大量图像进行良好分类的网络(如 ImageNet)并应用迁移学习

2019 年底前了解计算机视觉格局

原文:https://towardsdatascience.com/understand-the-computer-vision-landscape-before-the-end-of-2019-fa866c03db53?source=collection_archive---------40-----------------------

简要概述计算机视觉在过去 50 年中的发展,并了解像‘AI Winter’这样的流行语及其含义。

2019 年即将结束,但在此之前,了解一下我们十年来在机器学习方面的一个流行语不是很好吗?这篇文章将帮助你对计算机视觉有一个简单的了解,足够的知识让你在圣诞晚宴上看起来聪明。

看完这篇文章,你会对计算机视觉、深度学习、机器学习、AI Winter、天网……这些好东西变得熟悉。

我一直听说的计算机视觉是什么?

当有人问你这个问题时,你可以用“计算机视觉就是计算机如何看东西”来回答他们嗯,不完全是,试试下面的解释,肯定会让一些人惊讶。

计算机视觉是机器或系统通过调用一种或多种作用于所提供信息的算法来生成对视觉信息的理解的过程。这种理解被转化为决策、分类、模式观察等等。现在你又回头了。

让我们快速上一堂历史课,看看计算机视觉领域是如何发展的。

当我们开始模仿人体内的感知和视觉系统时,对计算机视觉的需求就出现了。因此,这一旅程始于 20 世纪 60 年代,当时学术界研究了人类的感知,并试图在计算机系统上复制其基本功能。我们的先驱学者旨在为机器人提供看到并描述机器人所观察到的东西的能力。这是天网的第一步(是的,就像电影一样,但这是在那之前)。

Edge Detection. (2019). [image] Available at mathwork.com

让天网看起来像人类并不容易,所以我们期待数字图像处理技术来理解呈现给计算机视觉系统的图像内容。我所说的理解就是从图像中提取边缘信息、轮廓、线条、形状。70 年代都是关于从数字图像中提取信息的算法。

有一点要注意的是第一个 艾冬 发生在 20 世纪 70 年代。对于那些不熟悉术语“人工智能冬天”、的人来说,它可以被描述为一个对人工智能相关领域(如计算机视觉、机器学习等)的兴趣、资金、士气(炒作)和正在进行的研究越来越缺乏的时期。

80 年代和 90 年代的计算机视觉专注于数学和统计学。研究人员和学者开始将计算机视觉技术与数学算法结合起来。描绘数学在计算机视觉和图像处理技术中的应用的一个很好的例子是边缘检测算法。

边缘检测是大多数计算机视觉课程中教授的主要图像处理技术之一。1986 年,约翰·f·卡尼研制出一种奇特而有用的边缘检测器。它被称为 狡猾的边缘探测器 。通过利用数学概念,如微积分、微分和函数优化,John F. Canny 开发了一个非常受欢迎的边缘检测器,它仍然在硕士课程中讲授。

快进到之前的十年;对计算机视觉来说,2000 年是一个颇具革命性的时代。深度学习出现了,计算机视觉再次成为媒体、研究人员和学者的热门话题。

另一个关键定义即将出现。

深度学习是机器学习的一个分支,其中算法利用几层神经网络从输入数据中提取更丰富的特征。深度学习技术的例子有深度卷积神经网络(CNN)递归神经网络(RNN)

这么多术语,在我们继续之前,下面是一些与机器学习相关的术语的链接。

[## 机器学习初学者的 30 个袖珍术语

你在数据科学或机器学习职业生涯中会遇到的有用的机器学习术语列表。

towardsdatascience.com](/30-pocket-sized-terms-for-machine-learning-beginners-5e381ed93055)

2012 年是计算机视觉领域的关键一年。你可能已经知道我要在这里提到什么(嘘,不要破坏了别人的)。有一个名为“ImageNet 大规模视觉识别挑战赛”的比赛,这个比赛每年举行一次,主要是学者,研究人员和爱好者的聚会,比较对图像中的对象进行分类和检测的软件算法。在 2012 年的比赛中,引入了一种深度卷积神经网络(AlexNet) ,其错误率超过了当年和之前几年的其他比赛。

我不会深究 AlexNet 是如何设计的太多细节,网上有很多这方面的资源。但我会提到 AlexNet 给景观带来的两个显著好处。

首先,GPU。AlexNet 令人惊叹的性能是使用图形处理单元(GPU)实现的。虽然 GPU 之前已经在比赛中使用过,但 AlexNet 对 GPU 的利用引起了计算机视觉社区的注意。

其次,CNN 成为标准。AlexNet 展示 CNN 有效性的能力意味着 CNN 变得普及。从那年开始到现在,在大多数计算机视觉应用和研究中都发现了 CNN 的实现。

我将不得不在这里暂停,也许在将来的另一篇文章中继续这个主题。有很多主题和领域我还没有涉及到,但是下面是一些中型文章,它们详细解释了本文中提到的关键术语以及更多内容。

现在你可以去 2020 年,了解计算机视觉及其自 20 世纪 60 年代以来的发展。

如果你喜欢这篇文章,并且想要更多这样的文章,那么就给我一个关注,让我扩展你在机器学习方面的知识。

查看来自 Dhruv Parthasarathy西达尔特 Das詹姆斯勒的关于计算机视觉和一些技术的文章。

[## CNN 在图像分割中的简史:从 R-CNN 到掩模 R-CNN

在 Athelas,我们使用卷积神经网络(CNN)不仅仅是为了分类!在本帖中,我们将看到…

blog.athelas.com](https://blog.athelas.com/a-brief-history-of-cnns-in-image-segmentation-from-r-cnn-to-mask-r-cnn-34ea83205de4) [## CNN 架构:LeNet、AlexNet、VGG、GoogLeNet、ResNet 等等

ILSVRC 中开创性的 CNN 模型以及卷积神经网络的历史

medium.com](https://medium.com/analytics-vidhya/cnns-architectures-lenet-alexnet-vgg-googlenet-resnet-and-more-666091488df5) [## 将改变你看待世界方式的 5 种计算机视觉技术

heartbeat.fritz.ai](https://heartbeat.fritz.ai/the-5-computer-vision-techniques-that-will-change-how-you-see-the-world-1ee19334354b)

O(n)是改进你的算法的唯一方法吗?

原文:https://towardsdatascience.com/understand-the-problem-statement-to-optimize-your-code-c3074b469f92?source=collection_archive---------19-----------------------

蟒蛇短裤

理解问题陈述如何帮助您优化代码

Photo by Patrick Tomasso on Unsplash

每当我们谈论优化代码时,我们总是讨论代码的计算复杂性。

是 O(n)还是 O(n 的平方)?

但是,有时候我们需要超越算法,看看算法在现实世界中是如何被使用的。

在这篇文章中,我将谈谈类似的情况以及我是如何解决的。

问题是:

最近我在处理一个 NLP 问题,不得不从文本中清除数字。

从表面上看,这似乎是一个微不足道的问题。一个人可以用许多方法做到这一点。

我用下面给出的方法做了这件事。该函数将问题字符串中的数字替换为#s。

def clean_numbers(x):    
        x = re.sub('[0-9]{5,}', '#####', x)
        x = re.sub('[0-9]{4}', '####', x)
        x = re.sub('[0-9]{3}', '###', x)
        x = re.sub('[0-9]{2}', '##', x)
    return x

这些都是干净的代码,但是我们能优化它的运行时间吗?在继续下一步之前思考。

诀窍是:

优化的诀窍在于理解代码的目标。

虽然我们大多数人都理解 O(n)范式,并且总是可以去寻找更好的算法,但优化代码的一个被遗忘的方法是回答一个问题:

这段代码将如何使用?

你知道吗,如果我们在替换字符串之前只检查一个数字,我们可以获得 10 倍的运行时间改进!!!

由于大多数字符串没有数字,我们不会评估对re.sub.的 4 次函数调用

它只需要一个简单的 if 语句。

def clean_numbers(x):
    if bool(re.search(r'\d', x)):
        x = re.sub('[0-9]{5,}', '#####', x)
        x = re.sub('[0-9]{4}', '####', x)
        x = re.sub('[0-9]{3}', '###', x)
        x = re.sub('[0-9]{2}', '##', x)
    return x

这样做有什么必要?

对我们使用的数据的理解和对问题陈述的理解。

这些改进当然是隐藏的,你可能需要考虑这段代码要运行多少次?或者谁会触发功能?做这样的改进。

但这是值得的。

把你写的每一个函数都当成你的孩子,尽你所能去改进它。

我们可以使用 Jupyter 笔记本中的%%timeit魔法功能来查看性能结果。

%%timeit
clean_numbers(“This is a string with 99 and 100 in it”)
clean_numbers(“This is a string without any numbers”)

使用第一个函数调用上述简单函数的结果是:

17.2 µs ± 332 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

使用第二个函数:

12.2 µs ± 324 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

即使我们 50%的句子都有数字,我们还是提高了两倍。

由于我们在数据库中不会有那么多包含数字的句子,我们可以这样做并得到很好的改进。

结论

有不同的方法来改进一个算法,甚至上面的问题可以用一些我想不到的逻辑来进一步改进。

但我想说的是,在封闭的盒子里思考并想出解决方案永远不会帮助你。

如果您理解了问题陈述和您试图实现的目标,您将能够编写更好、更优化的代码。

所以,下次你的老板让你降低算法的计算复杂度时,告诉他,虽然你无法降低复杂度,但你可以使用一些定制的业务逻辑让算法变得更快。我猜他会印象深刻。

另外,如果你想了解更多关于 Python 3 的知识,我想向你推荐一门来自密歇根大学的关于学习 T2 中级 Python 3 的优秀课程。一定要去看看。

将来我也会写更多初学者友好的帖子。让我知道你对这个系列的看法。在 媒体 关注我,或者订阅我的 博客 了解他们。

一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @mlwhiz 联系到我。

了解 1D 和 3D 卷积神经网络| Keras

原文:https://towardsdatascience.com/understanding-1d-and-3d-convolution-neural-network-keras-9d8f76e29610?source=collection_archive---------0-----------------------

Image by WallpeperSafari

当我们说卷积神经网络 (CNN)时,通常我们指的是用于图像分类的二维 CNN。但是在现实世界中使用了两种其他类型的卷积神经网络,它们是 1 维和 3 维 CNN。在本指南中,我们将介绍 1D3DCNN 及其在现实世界中的应用。我假设你已经熟悉卷积网络的一般概念。

二维 CNN | Conv2D

这是在 Lenet-5 架构中首次引入的标准卷积神经网络Conv2D 一般用于图像数据。它被称为二维 CNN,因为内核在数据上沿二维滑动,如下图所示。

Kernal sliding over the Image

使用 CNN 的整体优势在于,它可以使用其内核从数据中提取空间特征,这是其他网络无法做到的。例如,CNN 可以检测图像中的边缘、颜色分布等,这使得这些网络在图像分类和包含空间属性的其他类似数据中非常健壮。

以下是在 keras 中添加一个 Conv2D 层的代码。

Conv2D Layer in Keras

参数 input_shape (128,128,3)表示图像的(高度,宽度,深度)。参数 kernel_size (3,3)表示内核的(高度,宽度),内核深度将与图像的深度相同。

一维 CNN | Conv1D

在看完《T21》之前,让我给你一个提示。在 Conv1D 中,内核沿一维滑动。现在让我们在这里暂停博客,想一想哪种类型的数据只需要在一维上进行内核滑动,并且具有空间属性?

答案是时间序列数据。我们来看下面的数据。

Time series data from an accelerometer

这个数据是从一个人戴在手臂上的加速度计收集的。数据代表所有 3 个轴上的加速度。1D CNN 可以从加速度计数据中执行活动识别任务,例如人是否站立、行走、跳跃等。这个数据有两个维度。第一维是时间步长,另一维是 3 个轴上的加速度值。

下面的图说明了内核将如何处理加速度计数据。每行代表某个轴的时间序列加速度。内核只能沿着时间轴在一维上移动。

Kernel sliding over accelerometer data

下面是在 keras 中添加一个 Conv1D 层的代码。

Conv1D Layer in Keras

自变量 input_shape (120,3),表示 120 个时间步长,每个时间步长中有 3 个数据点。这 3 个数据点是 x、y 和 z 轴的加速度。参数 kernel_size 为 5,代表内核的宽度,内核高度将与每个时间步的数据点数相同。

类似地,1D CNN 也用于音频和文本数据,因为我们也可以将声音和文本表示为时间序列数据。请参考下面的图片。

Text data as Time Series

Conv1D 广泛应用于传感数据,加速度计数据就是其中之一。

三维 CNN | Conv3D

Conv3D 中,内核在三维空间滑动,如下图所示。让我们再想想哪种数据类型需要内核在三维空间中移动?

Kernel sliding on 3D data

Conv3D 主要用于 3D 图像数据。如磁共振成像 (MRI)数据。MRI 数据被广泛用于检查大脑、脊髓、内部器官等。计算机断层扫描 (CT)也是 3D 数据的一个例子,它是通过组合从身体周围不同角度拍摄的一系列 X 射线图像而创建的。我们可以使用 Conv3D 对这些医疗数据进行分类,或者从中提取特征。

Cross Section of 3D Image of CT Scan and MRI

3D 数据的另一个例子是视频。视频只不过是一系列图像帧的组合。我们也可以在视频上应用 Conv3D,因为它具有空间特征。

以下是在 keras 中添加 Conv3D 层的代码。

Conv3D Layer in Keras

这里参数输入形状 (128,128,128,3)有 4 个维度。3D 图像是四维数据,其中第四维表示颜色通道的数量。就像平面 2D 图像具有三维,其中第三维表示颜色通道。参数 kernel_size (3,3,3)表示内核的(高度,宽度,深度),内核的第四维将与颜色通道相同。

摘要

  • 1D CNN 中,内核向 1 方向移动。1D CNN 的输入输出数据是 2 维的。主要用于时间序列数据。
  • 2D CNN 中,内核向 2 方向移动。2D CNN 的输入输出数据是 3 维的。主要用于图像数据。
  • 3D CNN 中,内核在 3 方向移动。3D CNN 的输入输出数据为 4 维。主要用于 3D 图像数据(MRI、CT 扫描、视频)。

接下来是

[## 理解自我监督学习,并举例说明

迈向艾将军的一步?

shiva-verma.medium.com](https://shiva-verma.medium.com/understanding-self-supervised-learning-with-examples-d6c92768fafb)

理解演员评论方法和 A2C

原文:https://towardsdatascience.com/understanding-actor-critic-methods-931b97b6df3f?source=collection_archive---------0-----------------------

深度强化学习中的重要概念

预赛

我之前的文章中,我们导出了策略梯度并实现了加强算法(也称为蒙特卡罗策略梯度)。然而,普通的政策梯度有一些突出的问题:嘈杂的梯度和高方差。

但是为什么会这样呢?

回想一下政策梯度:

如同在增强算法中一样,我们通过蒙特卡罗更新(即随机取样)来更新策略参数。这在对数概率(策略分布的对数)和累积奖励值中引入了固有的高可变性,因为训练期间的每个轨迹可以彼此偏离很大程度。

因此,对数概率和累积奖励值的高度可变性将产生有噪声的梯度,并导致不稳定的学习和/或向非最佳方向倾斜的策略分布。

除了梯度的高方差之外,策略梯度的另一个问题是轨迹的累积报酬为 0。政策梯度的实质是在政策分布中增加“好”行为的概率,减少“坏”行为的概率;如果累积奖励为 0,则不会学习“好”和“坏”行为。

总的来说,这些问题导致了普通政策梯度方法的不稳定性和缓慢收敛。

改善政策梯度:用基线减少差异

减少方差和增加稳定性的一种方法是用基线减去累积奖励:

直觉上,通过用基线减去累积奖励来使累积奖励变小,将产生更小的梯度,从而产生更小且更稳定的更新。

下面是一个很有说明性的解释,摘自 Jerry Liu 的帖子“为什么政策梯度法有很高的方差”:

[Taken from Jerry Liu’s post “Why does the policy gradient method have high variance”]

常见基线功能概述

基线可以采用不同的值。下面的方程组说明了演员评论家方法的经典变体(关于加强)。在本帖中,我们将看看 Q 演员评论家和优势演员评论家。

Image taken from CMU CS10703 lecture slides

演员评论方法

在我们回到基线之前,让我们首先再次看一看普通的政策梯度,看看演员批评家架构是如何进来的(以及实际上是什么)。回想一下:

然后,我们可以将期望值分解为:

第二个期望项应该很熟悉;就是 Q 值!(如果你还不知道这一点,我建议你阅读一下价值迭代和 Q 学习)。

将它代入,我们可以将更新等式改写如下:

正如我们所知,Q 值可以通过用神经网络(上面用下标w表示)参数化 Q 函数来学习。

这就引出了 演员的评论家方法, 的地方:

  1. “评论家”估计价值函数。这可以是动作值( Q 值)或状态值( V 值)。
  2. “行动者”按照批评者建议的方向更新策略分布(例如使用策略梯度)。

评论家和演员函数都用神经网络参数化。在上面的推导中,Critic 神经网络将 Q 值参数化—因此,它被称为 Q Actor Critic。

以下是 Q-Actor-Critic 的伪代码:

Adapted from Lilian Weng’s post “Policy Gradient algorithms”

如图所示,我们在每个更新步骤更新评论家网络和价值网络。

回到基线

从权威的角度来说(因为我找不到原因),状态值函数是一个最佳的基线函数。这在卡内基梅隆大学 CS10703 和 Berekely CS294 讲座幻灯片中有所陈述,但没有提供任何理由。

因此,使用 V 函数作为基线函数,我们用 V 值减去 Q 值项。直观地说,这意味着在给定的状态下,采取特定的行动比一般的一般行动好多少。我们将这个值称为 优势值 :

这是否意味着我们必须为 Q 值和 V 值构建两个神经网络(除了策略网络之外)?不行。那样效率会很低。相反,我们可以使用贝尔曼最优方程中 Q 和 V 之间的关系:

所以,我们可以把优势改写为:

然后,我们只需要对 V 函数使用一个神经网络(由上面的v参数化)。因此,我们可以将更新等式改写为:

这是 优势演员评论家。

优势行动者评论家(A2C)对异步优势行动者评论家(A3C)

优势行动者批评家 有两个主要变体:异步优势行动者批评家(A3C)优势行动者批评家(A2C)。

A3C 是在 Deepmind 的论文《深度强化学习的异步方法》(Mnih et al,2016) 中引入的。本质上,A3C 实现了并行训练,其中并行环境**中的多个工人独立更新全局值函数——因此是“异步的”拥有异步参与者的一个主要好处是有效且高效地探索状态空间。

High Level Architecture of A3C (image taken from GroundAI blog post)

A2C 类似 A3C 但没有异步部分;这意味着 A3C 的单工人变体。经验表明,A2C 的性能与 A3C 相当,但效率更高。根据这篇 OpenAI 博客文章,研究人员并不完全确定异步是否或者如何有益于学习:

在阅读了这篇论文之后,人工智能研究人员想知道异步是否会导致性能的提高(例如,“也许添加的噪声会提供一些正则化或探索?”),或者它只是一个实现细节,允许使用基于 CPU 的实现进行更快的训练…

我们的同步 A2C 实现比异步实现性能更好——我们没有看到任何证据表明异步引入的噪声提供了任何性能优势。当使用单 GPU 机器时,这种 A2C 实现比 A3C 更具成本效益,并且当使用更大的策略时,比仅使用 CPU 的 A3C 实现更快。

无论如何,我们将在本帖中实现 A2C ,因为它实现起来更简单。(这很容易扩展到 A3C)

实施 A2C

因此,回想一下新的更新公式,用优势函数替换普通保单梯度中的折扣累积奖励:

在每个学习步骤中,我们更新 Actor 参数(用策略梯度和优势值)和 Critic 参数(用 Bellman 更新方程最小化均方误差)。让我们看看这在代码中是什么样子的:

以下是包含和超参数:

首先,让我们从实现 Actor Critic 网络开始,配置如下:

主循环和更新循环,如上所述:

运行代码,我们可以看到 OpenAI Gym CartPole-v0 环境的性能如何提高:

Blue: Raw rewards; Orange: Smoothed rewards

在此找到完整的实现:

https://github.com/thechrisyoon08/Reinforcement-Learning/

参考资料:

  1. 加州大学柏克莱分校 CS294 讲座幻灯片
  2. 卡内基梅隆大学 CS10703 讲座幻灯片
  3. Lilian Weng 关于政策梯度算法的帖子
  4. Jerry Liu 在 Quora Post 上回答“为什么政策梯度法有很高的方差”
  5. Naver D2 RLCode 讲座视频
  6. OpenAI 关于 A2C 和 ACKTR 的博文
  7. 图表来自 [GroundAI 的博客文章](http://Figure 4: Schematic representation of Asynchronous Advantage Actor Critic algorithm (A3C) algorithm.)“图 4:异步优势行动者评价算法(A3C)算法的示意图。”

其他职位:

查看我关于强化学习的其他帖子:

感谢阅读!

了解 AdaBoost

原文:https://towardsdatascience.com/understanding-adaboost-2f94f22d5bfe?source=collection_archive---------1-----------------------

任何开始学习增强技术的人都应该首先从 AdaBoost 或自适应增强开始。这里我试着从概念上解释一下。

当一切都不起作用时,助推会起作用。现在许多人使用 XGBoost 或 LightGBM 或 CatBoost 来赢得 Kaggle 或黑客马拉松比赛。AdaBoost 是 Boosting 世界的第一块敲门砖。

AdaBoost 是第一个用于解决实际问题的 boosting 算法。Adaboost 帮助您将多个“弱分类器”组合成一个“强分类器”。这里有一些关于 Adaboost 的(有趣)事实!

AdaBoost 中的弱学习器是单分裂的决策树,称为决策树桩。

→ AdaBoost 的工作原理是对难以分类的实例给予更多的权重,而对已经处理得很好的实例给予较少的权重。

→ AdaBoost 算法可用于分类和回归问题。

第 1 部分:使用决策树桩理解 AdaBoost

集合的力量是这样的,即使集合中的单个模型非常简单,我们仍然可以构建强大的集合模型。

D 决策树桩是我们可以构建的最简单的模型,它会为每个新的例子猜测相同的标签,不管它看起来像什么。如果我们猜测数据中最常见的答案是 1 还是 0,那么这种模型的准确性将是最好的。如果,比方说,60%的例子是 1,那么我们只要每次猜 1 就能得到 60%的准确率。

决策桩通过基于一个特征的值将例子分成两个子集来改进这一点。每个树桩选择一个特征,比如说 X2,和一个阈值 T,然后将样本分成阈值两边的两组。

为了找到最适合这些例子的决策树桩,我们可以尝试输入的每个特征以及每个可能的阈值,看看哪一个给出了最好的准确性。虽然这看起来很天真,似乎阈值有无限多的选择,但两个不同的阈值只有在它们将一些例子放在分裂的不同侧时才有意义上的不同。为了尝试每一种可能性,我们可以根据所讨论的特征对示例进行分类,并尝试在每对相邻的示例之间设置一个阈值。

刚刚描述的算法可以进一步改进,但是与其他 ML 算法(例如,训练神经网络)相比,即使这个简单的版本也非常快。

到看看这个算法的运行,让我们考虑一个 NFL 总经理需要解决的问题:预测大学的外接球手在 NFL 中的表现。我们可以通过使用过去的玩家作为例子,将这作为监督学习问题来处理。以下是 2014 年起草的接收器示例。每一个都包括一些当时已知的关于他们的信息,以及他们在 2014 年至 2016 年在 NFL 每场比赛中的平均接收码数:

任何将这些技术应用于外接球员的方法都会试图从许多因素中预测 NFL 的表现,这些因素至少包括对球员运动能力的一些测量和对他们大学表现的一些测量。在这里,我已经简化为每种只有一个:他们在 40 码短跑中的时间(运动能力的一个衡量标准)和他们在大学每场比赛中的接收码数。

我们可以把这作为一个回归问题来解决,如上表所示,或者我们可以把它重新表述为分类,根据他们的 NFL 产量,把每个例子标记为成功(1,橙色)或失败(0,蓝色)。以下是后者在将我们的例子扩展到包括 2015 年选秀的球员后的样子:

The X-axis shows each player’s college receiving yards per game and the Y-axis shows their 40-time.

回到我们的 boosting 算法,回想一下,集合中的每个单个模型都是基于一个示例高于还是低于该模型的特征阈值来对该示例进行投票的。当我们应用 AdaBoost 并在这些数据上构建一个决策树桩集合时,这些分裂看起来是这样的:

1st iteration of AdaBoosting

整个系综包括五个树桩,其阈值显示为虚线。两个树桩看着 40 码的虚线(垂直轴),在 4.55 和 4.60 之间的值分裂。其他三个树桩看的是大学每场比赛的接发球码数。在这里,阈值落在 70、90 和 110 左右。

在分裂的每一边,树桩将与那一边的大多数例子一起投票。对于水平线,线以上的成功比失败多,线以下的失败比成功多,所以 40 码冲刺时间落在这些线以上的例子会得到那些树桩的赞成票,而线以下的得不到任何选票。对于垂直线来说,线右边的成功比失败多,线左边的失败比成功多,所以例子对线右边的树桩投赞成票。

虽然集合模型对这些投票进行加权平均,但如果我们想象树桩具有相同的重量,这种情况就不会太离谱。在这种情况下,我们至少需要获得 5 票中的 3 票,才能获得全体投票成功所需的多数票。更具体地说,对于至少 3 行以上或右边的例子,集合预测成功。结果看起来像这样:

如您所见,这个简单的模型捕捉到了成功出现的大致形状(以非线性的方式)。它有一些假阳性,而唯一的假阴性是小奥德尔·贝克汉姆,一个明显的异常值。正如我们将在本文后面的一些投资示例中看到的那样,针对特征和结果之间的非线性关系进行调整的能力,可能是优于许多投资因素模型中使用的传统线性(& logistic)回归的一个关键优势。

第 2 部分:可视化决策树桩集合

如果我们有两个以上的特征,那么就很难像上图中那样看到完整的系综。(有时有人说,如果人类可以在高维空间中看到东西,那么 ML 就没有必要了。)然而,即使当有许多特征时,我们仍然可以通过分析它如何看待每一个单独的特征来理解决策树桩的集合。

为了说明这一点,让我们再来看一下该合集中所有树桩的图片:

正如我们在这里看到的,有两个基于 40 码冲刺时间决定的树桩。如果一个例子的 40 码冲刺时间超过了 4.59,那么它就会从这两个树桩那里得到一个成功的投票。如果它的时间低于 4.555,那么它会收到双方的反对票。最后,如果它在 4.55 和 4.59 之间失败,那么它会收到一个树桩的成功投票,而不是另一个树桩。整体画面看起来如下。

这幅图说明了这样一个事实,即全体是树桩的加权平均值,而不是简单的多数票。那些 40 码冲刺时间超过 4.55 的例子从第一个树桩获得了成功票,但该票的权重为 0.30。那些时间超过 4.59 的人也可以从第二个树桩获得成功投票,但该树桩的权重仅为 0.16,使赞成票的总权重达到 0.46。当你看到这张图片和下一张图片时,请记住,为了让模型预测一个新的外接球手的“成功”,该球员需要累积至少 0.5 的总权重。

另一个功能“大学每场比赛接收码数”的图片如下所示:

有三个树桩关注这个特性。第一个权重为 0.10,在每场比赛接发球码数至少为 72 码(约 72 码)的所有例子中,它都是成功的。下一个 stump,权重为 0.22,在所有高于 88(或左右)的例子中投票成功。码数高于 88 的例子从两个树桩获得成功票,给出至少 0.32 的权重(0.10 加 0.22)。第三个树桩增加了一个额外的成功投票,对于每场比赛接发球码数在 112 码以上(左右)的例子,权重约为 0.22。这使得该范围内的成功投票的总权重达到约 0.54。

这些图片中的每一张都显示了一个示例将从使用该特定特征的集合子集中获得的成功投票的总权重。如果我们基于它们检查的特征将单个模型分组到子集成中,那么整个模型就很容易描述为:一个例子的成功投票的总权重是来自每个子集成的权重的总和,同样,如果该总和超过 0.5,那么集成预测该例子是成功的。

在训练一个任意级别的分类器后,ada-boost 为每个训练项目分配权重。错误分类的项目被赋予较高的权重,以便它以较高的概率出现在下一个分类器的训练子集中。在每个分类器被训练之后,权重也被基于准确度分配给分类器。越准确的分类器被赋予越大的权重,从而对最终结果产生更大的影响。准确度为 50%的分类器被赋予零权重,准确度低于 50%的分类器被赋予负权重。

相比之下,线性模型迫使我们做出在每个参数中线性缩放的预测。如果某个特征的权重是正的,那么增加该特征预示着更高的成功几率,不管它有多高。不受该限制约束的树桩集合不会建立该形状的模型,除非它可以在数据中找到足够的证据证明这是真的。决策树桩的集合概括了线性模型,增加了查看标注和单个要素之间的非线性关系的能力。

第 3 部分(奖金):比较线性(&逻辑)回归与 AdaBoosting

如果你愿意,你可以跳过这一步,但我坚持要你读。

为了看到应用这些技术的更现实的例子,我们将扩展上面考虑的例子。实际上,我们希望包含更多信息以提高准确性。

我们将增加年龄,垂直跳跃,重量和每场比赛的绝对接球次数,码数和得分,以及球队在这些方面的市场份额。我们将包括他们大学最后一季的数据以及职业生涯的总成绩。总之,这给我们带来了总共 16 个功能。

上面,我们只看了两年的数据。无论用什么标准来衡量,这仍然是一个很小的数据集,这给了线性模型更多的优势,因为过度拟合的风险比通常情况下更大。

在以 8:2 的比例随机分割数据后,逻辑回归仅错误标记了 13.7%的训练样本。这相当于相当可观的 0.29 的“伪 R2”(R2 回归的分类类似物)。然而,在测试集上,它错误标记了 23.8%的例子。这表明,即使使用标准统计技术,样本内误差率也不是样本外误差的良好预测指标。

由逻辑回归产生的模型有一些预期的参数值:如果接球者更年轻、更快、更重,并且接住更多的触地得分,他们就更有可能成功。它不会给垂直跳跃带来任何重量。另一方面还是包含了一些挠头参数值。比如球队接码的市场份额较大是好事,但场均接码的绝对数量较大就是坏事。(也许可解释性问题并不是机器学习模型独有的!)

树桩集成模型将错误率从 23.8%降低到 22.6%。虽然这种下降在理论上看起来很小,但请记住,每年都有值得注意的选秀失利,即使是由全职研究这些球员的 NFL 总经理做出决定。我的猜测是,在这种情况下,20%左右的错误率可能是我们可以预期的绝对最小值,所以提高到 22.6%是一个不小的成就。

像逻辑回归模型一样,树桩群喜欢更重更快的宽接收器。

通过对大学产出的最重要的测量,我们看到了一些明显的非线性,而逻辑回归肯定漏掉了这一点。

结论

正如这些例子所展示的,真实世界的数据包括一些线性模式,但也包括许多非线性模式。从线性回归转换到决策树桩集成(又名 AdaBoost)使我们能够捕捉许多非线性关系,这转化为对感兴趣的问题的更好的预测准确性,无论是找到最佳的广泛接收器来起草还是购买最佳的股票。

如果你想了解背后的数学,这里有一个很好的来源

[## 升压算法:AdaBoost

作为一名消费行业的数据科学家,我通常的感觉是,提升算法对于大多数情况来说已经足够了…

towardsdatascience.com](/boosting-algorithm-adaboost-b6737a9ee60c)

理解亚当:损失函数如何最小化?

原文:https://towardsdatascience.com/understanding-adam-how-loss-functions-are-minimized-3a75d36ebdfc?source=collection_archive---------15-----------------------

Adam:一种随机优化方法

简介

W 在使用基于 PyTorch 构建的 fast.ai 库时,我意识到迄今为止我从未与优化器进行过交互。由于 fast.ai 在调用 fit_one_cycle 方法时已经处理了它,所以我不需要参数化优化器,也不需要了解它是如何工作的。

由于其简单性和速度,Adam 可能是机器学习中使用最多的优化器。它是由迪德里克·金玛吉米·巴雷在 2015 年开发的,并在一篇名为亚当:随机优化方法的论文中介绍。

和往常一样,这篇博文是我写的一张备忘单,用来检查我对一个概念的理解。如果你发现一些不清楚或不正确的地方,不要犹豫,写在评论区。

算法

首先,Adam 指的是自适应矩估计。Adam 背后的基本原理是提出一种优化目标函数的高效算法。该研究论文主要研究高维参数空间中随机目标的优化。

Adam 是随机梯度下降的修改版,这里就不解释了。对于 memo,随机梯度下降更新规则为:

The SGD’s update rule : here J is a cost function

Adam 算法的伪代码如下:

Adam algorithm pseudo-code

每一步我都会讲清楚,但首先我需要介绍一些量。

由于 Adam 是一个迭代过程,我们需要一个索引 t ,它在每一步都增加 1。

α 是步长,相当于随机梯度下降的学习速率。

G(t) 是目标函数 f 在步骤 t 相对于参数向量 θ的梯度。

M(t) 是梯度 G(t) 的一阶矩的指数移动平均线(EMA)。因此 β1 均线的指数衰减率。

V(t) 是梯度 G(t) 的二阶矩的指数移动平均。因此 β2 均线的指数衰减率。

最后, ε 是一个非常小的超参数,防止算法被零除。

为什么亚当用渐变 EMA 而不用渐变?

当计算梯度时,一些小批量可能具有异常值,这可能产生大的信息梯度,因此通过计算每个小批量的梯度的 EMA,无信息梯度的影响被最小化。此外,均线是新旧梯度的加权平均值。如果 Adam 使用算术平均值,所有梯度(第 1 步和第 t 步之间)将具有相同的权重。

让我们注意到,均线作为梯度的估计,我们将在后面看到。

亚当的更新法则

如上所述,亚当的更新规则只不过是梯度下降的更新规则的修改版本。在 Adam 中,梯度的第一个矩的 EMA 被矩的第二个矩的平方根缩放,减去参数向量θ。

Adam’s update rule

在论文中,作者将其定义为 SNR (信噪比)。

SNR 是将期望信号(这里是梯度,即目标函数曲线的方向)的水平与背景噪声(二阶梯度,即该方向周围的噪声)的水平进行比较的度量。

平方根缩放来自 RMSProp (RMS 表示均方根)算法。这个想法是,由于梯度是在多个小批量上累积的,我们需要在每一步的梯度保持稳定。由于一个小批量可以具有与另一个小批量完全不同的数据样本,为了限制梯度的变化,梯度的一阶矩的 EMA 被二阶矩的 RMS 缩放。人们可以将这种技术视为一种标准化,即梯度除以一种标准偏差。

自动退火

SNR 越小,有效步长越接近于零,这意味着与实际信号相比存在大量噪声,因此一阶梯度的方向是否对应于最优方向的不确定性越大。这是一个理想的特性,因为步长较小,从而限制了偏离局部最优值。

SNR 通常变得更接近于 0,趋向于最佳值,导致参数空间中的小有效步长。这使得能够更稳健、更快速地收敛到最优。

初始化偏置-校正

由于 EMA 向量被初始化为 0 的向量,所以矩估计偏向于 0,尤其是在初始时间步长期间,尤其是当衰减率很小时(β接近于 1)。

为了抵消这一点,力矩估计值被偏差修正

使用 v(t)v(t-1) 之间的递归关系,可以得出:

在通过将它与期望值组合来使用这个等式之后,很快就可以得出, E[v(t)]等于

Zeta is a residual parameter to adjust the equation

这就是为什么在每一步初始化权重时,e【v(t)】除以 (1-β2^t)

对于第一梯度矩,遵循同样的推理。

adamax:Adam 扩展

Adamax 是 Adam 的扩展。它用一个加权无穷范数代替梯度的二阶矩。

Adamax pseudo-code

使用这种变体是因为当特征矩阵稀疏时,作者已经提出了一种令人惊讶的稳定解决方案(像在嵌入中一样,考虑一下一键编码)。事实上,由于用于 u(t) 的更新规则不仅仅依赖于梯度,所以该解决方案是健壮的。

g(t) 变得非常小时,由于 max 函数,更新规则选择 β2*u(t-1)

结果

比较 MNIST 数据集上的结果,我们观察到 Adam 比 Adagrad、RMSProp 或 AdaDelta 收敛得更快且更接近最优。

理解 AlphaGo:人工智能如何思考和学习(基础)

原文:https://towardsdatascience.com/understanding-alphago-how-ai-think-and-learn-1-2-da07d3ec5278?source=collection_archive---------5-----------------------

本文将教你游戏人工智能的基础…

“我想象有一天,我们对机器人的重要性就像狗对人类的重要性一样,我支持机器人。”

—克劳德·香农

由 DeepMind 开发的 AlphaGo 在 2016 年的一场围棋比赛中击败了世界顶级人类选手后,获得了全世界的关注。更强大的版本名为 AlphaZero,继续在围棋和国际象棋等游戏中蓬勃发展。一个名为 AlphaStar 的变种在与职业玩家的实时战略游戏中表现越来越好。我们正处于机器接管我们工作的时代,在某些特定领域,机器比我们人类做得更好。

Robot Playing a Game of Chess, Image from Smithsonian.com

但是那些人工智能到底是怎么工作的呢?在这篇文章中,我们将从基础开始讲述这些游戏人工智能是如何工作的。我们将从老式的对抗性搜索和状态机开始。然后,我们将在机器学习领域进行一些探索,从强化学习到蒙特卡罗树搜索,我们将了解现代人工智能如何自我学习(以神奇宝贝ϟϟ(๑⚈․̫⚈๑)∩为例)。

然后我们将进入第 2 部分,在那里我们将更深入地研究深度学习,主要关注人工神经网络和卷积神经网络。在此之后,我们应该能够理解 AlphaGo 的政策网络和价值网络。

不要被这些术语吓跑,因为在本文结束时,你会像专家一样理解它们。我希望这篇文章可以消除对人工智能的一些误解,解答疑问,并鼓励对这一研究领域的更多兴趣。如果你准备好了,让我们的旅程开始吧!

人工智能、历史和基础

“我们的智力是我们成为人类的原因,而人工智能是这种素质的延伸。”

——扬·勒昆

人工智能的第一个概念可以追溯到古希腊神话。赫菲斯托斯是希腊的铁匠、金工、木匠、工匠、工匠、雕刻家、冶金、火和火山之神,他应父亲宙斯的请求,制作了一个青铜机器人塔洛斯,以保护宙斯的配偶欧罗巴不被绑架。赫菲斯托斯还被认为是潘多拉的创造者——一个作为礼物送给人类的完美女人,手里拿着“潘多拉的盒子”——一个邪恶的罐子,它向人类释放了所有邪恶的罪恶,同时在罐子的唇边有【希望】

Talos, a bronze automaton, Image from FANDOM

早在公元前 350 年左右,伟大的哲学家亚里士多德描述了一种通过演绎推理进行正式、机械思考的方法,称为“三段论”。在 1206 年,Ismail al-Jazari 创造了一个可编程的机器人,被称为、【音乐机器人乐队】。几个世纪以来,许多其他杰出的人都受到了启发。一个著名的例子是艾伦·图灵,他在 1950 年发明了一种算法,可以在计算机发明之前和他的朋友下棋。(顺便说一下,他输掉了那场比赛)当然,图灵也因他的“图灵测试”而闻名,我们稍后会更详细地讨论这个测试。

Al-Jazari’s musical robot band, Image from Wikipedia

1956 年夏天,人工智能研究领域在新罕布什尔州汉诺威达特茅斯学院的一个车间里正式启动。术语“人工智能”描述了人类发明的具有认知能力的机器。这项研究有许多子领域,如计算机视觉、自然语言处理、机器学习、专家系统,以及我们今天将要讨论的主题——游戏人工智能。

A view of East Campus from Baker Tower of Dartmouth College, Image from Wikipedia

我们将从游戏中人工智能使用的两个基本算法开始——对抗性搜索和状态机。从这些构件开始,我们可以更深入地研究更高级的算法。

对抗性搜索

敌对搜索,有时被称为极小极大搜索,是一种经常在涉及玩家之间敌对关系的游戏中使用的算法。游戏通常可以通过 alpha-beta 剪枝进行优化,这将在本节稍后介绍。

该算法可以应用于井字游戏或 Nim 游戏,我在下面附上了游戏规则。你可以试试在游戏里玩电脑——提示:你永远不会赢,一会儿我们就知道为什么了。

井字游戏

井字游戏是一种游戏,双方玩家都试图将他们的【X】【O】符号放入一个 3x 3 的棋盘中。玩家通过使他们的符号形成长度为 3 的连接而获胜。连接可以是水平的、垂直的或对角的。

尼姆

Nim 是一种游戏,玩家试图从一组筹码中抽取一定数量的筹码,玩家每回合至少要抽取 1 个筹码。从游戏中拿走最后筹码的玩家赢得游戏。

对抗性搜索

现在让我们进入今天的严肃话题——对抗性搜索。对抗性搜索创建了一个所有可能的游戏状态的树,由可用的选择分支。例如,在一个最多拿 3 个筹码的 Nim 游戏中,每个玩家可以拿 1、2 或 3 个筹码,这样每个树节点就有 3 个分支,如下所示。

Adversarial Search Illustrated with Nim, Part 1

当没有更多的芯片剩余时,树结束。拿到最后一个筹码的玩家赢得游戏。

Adversarial Search Illustrated with Nim, Part 2

该树包含所有可能的游戏状态,在这种情况下, 177 个状态。通过搜索所有的游戏状态,计算机将在采取任何行动之前知道游戏的结果。

🤖机器人 A:“143 移动中的伴侣。”

🤖机器人 B:“哦维尼,你又赢了。”

——Futurama 第二季第二集 Brannigan,重新开始

Robots Playing Chess, Futurama S2E02 Brannigan, Begin Again

在计算机科学领域,我们也重视算法的效率。更少的计算量和存储器消耗意味着更轻的硬件负载和电力消耗,导致运行算法的成本降低。因此,有许多方法可以简化问题,而不是遍历所有可能的状态。

例如,下面显示的井字游戏的 8 种状态是旋转等价的,因此我们可以将它们视为 2 种状态。这些类型的平移和旋转等效将在我们在后面的章节深入研究卷积神经网络时进行更详细的讨论。

The Tic-Tac-Toe States are Rotationally Equivalent

通过消除额外的状态,搜索树的大小可以大大减小。如果不应用这种缩减,在搜索树的前 4 层中有超过 3500 个状态。对于现代计算机来说,搜索 3500 个状态并不是一项很大的任务,但这个数字呈指数增长,当它进入更大的棋盘(如国际象棋)时,可以达到我们宇宙年龄的微秒级。

Reduced Search Tree for Tic-Tac-Toe

消除第一层中的相同状态可以减少 2/3 的额外状态,但是我们能做得更好吗?有一个叫做 alpha-beta 修剪的小技巧,我们将在下一节讨论。

阿尔法-贝塔剪枝

“我从不低估对手,但也从不低估自己的天赋。”

—黑尔·欧文

想象一下,当你在玩井字游戏时,当你的对手已经有两个相连的棋子时,你总是想在另一端挡住他。为什么?因为你可以假设如果你不赢他下一轮会赢。这就是阿尔法-贝塔修剪的思想,你总是期望你的对手尽最大努力去赢。

Illustration of Alpha-Beta Pruning, Player 1 will always choose the winning move

对于井字游戏,结果通常被评估为二进制。然而,对于一些更复杂的游戏,如国际象棋,棋盘可以用分数来评估。例如,白色棋子的得分之和减去黑色棋子的得分之和。这就是 alpha-beta 修剪有助于消除分支的时候。下面有一个视频解释了用象棋进行 alpha-beta 剪枝。

算法解释—极大极小和阿尔法-贝塔剪枝

至于 Nim 游戏,人工智能使用一个简单得多的规则库。我们看了搜索树,只是因为用 Nim 解释搜索树更容易。AI 会将筹码分成大小比最大允许拾取量大 1 个筹码的卡盘,并确保每次通过拾取大块大小和玩家拾取量之间的差异来拾取整个大块。如果卡盘是不可分的,AI 将首先移动并选择余数。这样,玩家就没有办法赢了。

Illustration of Nim AI

对于像国际象棋这样的游戏来说,所有可能的状态都不能像井字游戏或 nim 游戏那样容易地被搜索到。但是一台可以搜索超过 30 层深度的计算机已经很难被击败,因为大多数玩家无法预见那么多的移动。

状态机

“简单可能比复杂更难:你必须努力让自己的思维变得清晰,才能变得简单。”

—史蒂夫·乔布斯

状态机,通常指的是有限状态机,是当今游戏 AI 中经常被低估的概念,尤其是在机器学习多年来获得巨大普及之后。然而,在与其他使用机器学习的星际争霸 AI 进行的 SSCAIT 2018 挑战赛中,这种老派设计以 96.15%的胜率占据了主导地位。

Image of SSCAIT and StarCraft, a Real-Time Strategy (RTS) game that requires high skill to play

在游戏人工智能领域之外,状态机也广泛应用于其他领域,比如谷歌的这款很酷的手机助手人工智能。在这一节中,我们将探究所有这些奇迹背后的理论。

谷歌人工智能助手演示

有限状态机,有时称为有限状态自动机,通常由一组连接的节点表示,正式名称为“图”。下面的展示了典型读者如何与我的文章互动。

Despite Medium asks to not ask for claps, I realize people who ask for claps get more claps

圆圈内是我们称之为“状态”,箭头称为“状态转换函数”。状态转移函数通常由一个条件来描述。例如,当我的读者处于“读者喜欢我的文章”状态时,如果“我请求鼓掌”“读者记得鼓掌”,他们可能会转换到“读者为我的文章鼓掌”状态。有限状态机的更正式的数学定义可以在这里找到。

围绕它发展了许多有趣的理论,最终导致了计算机科学中的两大主题,NP 与 P 问题和图灵机。马尔可夫链等机器学习算法也分享了状态机中的一些概念。我们将在下一节学习强化学习时讨论马尔可夫决策过程。

机器如何学习,强化学习介绍(带神奇宝贝)

如果一个计算机程序在某类任务 T 和性能测量 P 上的性能(由 P 测量)随着经验 E 而提高,则称该程序从经验 E 中学习

汤姆·米切尔

Tom M. Mitchell, Machine Learning professor at Carnegie Mellon University

作为一个被广泛使用的引用,Tom M. Mitchell 将机器学习的概念正式定义为一个计算机程序,它通过积累经验来逐步提高性能。在机器学习算法的驱动下,这些机器将利用它们接收到的新信息不断前进。相关算法被广泛应用于许多正在改变我们生活的领域,如检测我们面部的 Snapchat 过滤器,或帮助我们理解其他说外语的人的谷歌翻译。如果你对其中的一些应用感兴趣,我也写了一个关于面部检测的教程,可以在这里找到。

在这一部分,我们将了解游戏人工智能的机器学习的一个热门领域——强化学习。流行的神经网络将在随后的深度学习部分讨论。

强化学习

"失败只是重新开始的机会,这次会更聪明."

—亨利·福特

“强化学习(RL)是机器学习的一个领域,涉及软件代理应该如何在一个环境中采取行动,以便最大化某种累积回报的概念。”

—维基百科

为了便于理解,下图是一个说明强化学习基本概念的例子。

The truth is, asking for claps also generates more claps.

强化学习有几个概念,我们可以从上面的例子中理解,掌声鼓励作者写更好的文章(并要求更多的掌声)。

  • 环境:环境是智能体相互作用的地方,在这种情况下,媒介社区就是环境。
  • 代理人:代理人就是与他人和环境相互作用的东西,在这里,作家就是代理人。读取器也是代理,可以用前面提到的状态机来描述。
  • 状态:状态包括环境和代理的可能状态。例如,一个作家可能睡着了或者很忙,不能写作。媒体期刊可能会引入合作项目的变化或策划一篇文章,这会影响可见性。
  • 动作:动作是代理可以做的与环境和其他代理交互的事情。例如,作者可以选择写一个有吸引力的标题,这有机会增加浏览量和潜在的掌声。
  • 解释器:解释器是一套为代理评估结果的规则,比如每次拍手让我开心 1 个单位,每次关注让我开心 50 个单位。

代理将尝试优化解释器评估的结果,有几种方法。在这一节中,我们将介绍游戏中人工智能使用的两种流行方法——Q 学习和蒙特卡罗树搜索。一旦我们理解了这两点,我们就应该能够理解后面章节中的深度 Q 学习。

q 学习

Q-Learning 是强化学习的最简单形式。Q-Learning 的目标是学习一个优化代理评估结果的策略。下面的流程图解释了玩家如何找到最好的神奇宝贝。

Flow-Diagram Explaining Q-Learning with Pokémon

策略通常由记录每个状态下每个动作的机会的矩阵来定义。代理将根据策略执行操作,然后根据操作的结果更新策略。例如,如果对手召唤了杰尼龟,代理将随机挑选一个神奇宝贝。如果代理商选择了皮卡丘,并发现对杰尼龟非常有效,代理商将更新政策,因此它更有可能在未来用皮卡丘对抗杰尼龟。还有另外两个值得注意的概念,学习率和马尔可夫决策过程。

1。学习率

学习描述了模型学习的速度。例如,对于“非常有效”的相同结果,低学习率的百分比可以增加 1%,高学习率的百分比可以增加 15%。

2。马尔可夫决策过程

马尔可夫决策过程是描述主体和环境的状态和行为的状态图。它还描述了每个状态之间的转移概率和每个状态的奖励。

Markov Decision Process Illustrated with Pokémon

关于 Q-learning 收敛的严肃数学定义和证明的更多信息,你可以在这里阅读它们

蒙特卡罗树搜索

蒙特卡洛树搜索(MCTS)的工作方式类似于上一节中介绍的对抗性搜索。主要区别是 MCTS 随机选择一个分支,而不是试图遍历所有的分支。然后,该算法根据该分支的结果建立一个配置文件。

Illustration of Monte Carlo Tree Search

形式上,蒙特卡洛树搜索具有以下 4 种状态:

1。选择

  • 通常通过选择具有最高胜率的节点来进行选择,但是具有一些随机性,因此可以探索新的策略。

2。扩展

  • 扩展是算法扩展到未探索的状态。该算法选择随机的未探索的新状态来探索。

3。模拟

  • 模拟是资料片后模拟随机玩法的时候,所以可以评估状态。

4。反向传播

  • 反向传播是用从模拟中获得的新信息更新状态值的过程。

这种算法在状态数量很大的游戏中特别有用,因为要遍历所有的状态几乎是不可能的。通过学习从以前的游戏中获得的经验,将来可以做出更明智的决策。更多关于决定勘探和开发之间的节点的阅读可以在这里找到。

下面是一个关于人工智能如何用算法玩超级马里奥的视频。

人工智能用蒙特卡罗树搜索玩马里奥

强化学习是一个有趣的研究领域,有许多不同的分支。我们在本节中讨论的两个问题肯定会帮助我们理解后面章节中更高级的内容。

未完待续…

祝贺你走到这一步,我们已经在理解现代游戏人工智能如何思考和学习的旅程中走了一半。在本文的第二部分中,我们将回顾深度学习和神经网络,然后我们最终可以进入那些 DeepMind AI 的架构。

还有,让我知道你最喜欢哪种写作风格,我可以做经典的纪录片,严肃的论文,或者那些华而不实的神奇宝贝例子。您的反馈让我能够了解最佳政策矩阵🤖。

理解和计算卷积神经网络中的参数个数

原文:https://towardsdatascience.com/understanding-and-calculating-the-number-of-parameters-in-convolution-neural-networks-cnns-fc88790d530d?source=collection_archive---------1-----------------------

https://www.learnopencv.com/wp-content/uploads/2018/05/AlexNet-1.png

Example taken from coursera: https://www.coursera.org/learn/convolutional-neural-networks/lecture/uRYL1/cnn-example

仅供参考:上图并不代表正确的参数数量。请参考标题为“更正”的部分。如果你只想要数字,你可以跳到那一部分。

如果你一直在玩 CNN,经常会看到上图中的参数摘要。我们都知道计算激活尺寸很容易,因为它仅仅是宽度、高度和该层中通道数量的乘积。

例如,如 coursera 的上图所示,输入层的形状为(32,32,3),该层的激活大小为 32 * 32 * 3 = 3072。如果你想计算任何其他层的激活形状,同样适用。比方说,我们想计算 CONV2 的激活大小。我们所要做的只是乘以(10,10,16),即 101016 = 1600,你就完成了激活大小的计算。

然而,有时可能变得棘手的是计算给定层中参数数量的方法。也就是说,这里有一些简单的想法可以让我记住。

一些上下文(如果你知道术语“参数”在我们上下文中的意思,跳过这个):

让我问你这个问题:CNN 是如何学习的?

这又回到了理解我们用卷积神经网络做什么的想法,卷积神经网络基本上是试图使用反向传播来学习滤波器的值。换句话说,如果一个层有权重矩阵,那就是一个“可学习的”层。

基本上,给定层中的参数数量是过滤器的“可学习的”(假设这样的词存在)元素的计数,也称为该层的过滤器的参数。

参数通常是在训练期间学习的重量。它们是有助于模型预测能力权重矩阵,在反向传播过程中会发生变化。谁来管理变革?嗯,你选择的训练算法,尤其是优化策略,会让它们改变自己的值。

现在你知道什么是“参数”,让我们开始计算我们上面看到的示例图像中的参数数量。但是,我想在这里再次包含该图像,以避免您的滚动努力和时间。

Example taken from Coursera: https://www.coursera.org/learn/convolutional-neural-networks/lecture/uRYL1/cnn-example

  1. 输入层:输入层不需要学习什么,它的核心是提供输入图像的形状。所以这里没有可学习的参数。因此参数的数量= 0
  2. CONV 层:这是 CNN 学习的地方,所以我们肯定会有权重矩阵。为了计算这里的可学习参数,我们所要做的只是将乘以形状的宽度 m高度 n前一层的过滤器 d ,并考虑当前层中所有这样的过滤器 k。不要忘记每个滤波器的偏置项。CONV 层中的参数数量将是: ((m * n * d)+1) k) ,由于每个滤波器的偏置项而增加 1。同样的表达式可以写成:((滤镜宽度的形状滤镜高度的形状上一层滤镜数+1)*滤镜数)。其中术语“过滤器”指当前层中过滤器的数量。*
  3. 池层:它没有可学习的参数,因为它所做的只是计算一个特定的数字,不涉及反向传播学习!因此参数的数量= 0
  4. 全连接层(FC): 这当然有可学习的参数,事实上,与其他层相比,这类层有最多的参数,为什么?因为,每一个神经元都与其他神经元相连!那么,如何计算这里的参数个数呢?你可能知道,它是当前层的神经元数量 c 和前一层的神经元数量 p 的乘积,而且一如既往,不要忘记偏置项。因此这里的参数数量为:((当前层神经元 c 前一层神经元 p)+1c)

现在让我们跟着这些指针计算参数的个数,好吗?

还记得这个练习吗?我们不想滚动,是吗?

Example taken from coursera https://www.coursera.org/learn/convolutional-neural-networks/lecture/uRYL1/cnn-example

  1. 第一个输入层没有参数。你知道为什么。
  2. 第二个 CONV1(滤镜形状=5*5,步距=1)层中的参数为: ((滤镜宽度形状滤镜高度形状上一层滤镜数量+1)滤镜数量)= (((553)+1)8) = 608。
  3. 第三个 POOL1 层没有参数。你知道为什么。
  4. 第四个 CONV2(滤镜形状=5*5,步距=1)层中的参数为 : ((滤镜宽度形状滤镜高度形状上一层滤镜数量+1) 滤镜数量)= (((558)+1)16) = 3216。

5.第五个 POOL2 层没有参数。你知道为什么。

6.中的参数第六个 FC3 层为((当前层 c 上一层 p)+1c) = 120400+1120= 48120。

7.**T5 里的参数第七个 FC4 层是:((当前层 c 上一层 p)+1c) = 84120+1 84 = 10164。**

8.第八个 Softmax 层有((当前层 c 上一层 p)+1c)参数= 1084+110 = 850。

更新 V2:

感谢观察力敏锐的读者的评论。感谢指正。为了更好的理解改变了图像。

参考消息:

  1. 我已经非常宽松地使用了术语“层”来解释分离。理想情况下,CONV +池被称为一个层。

2.仅仅因为池层中没有参数,并不意味着池在 backprop 中没有作用。池层负责分别在向前和向后传播期间将值传递给下一层和上一层。

在这篇文章中,我们看到了参数的含义,我们看到了如何计算激活大小,我们也了解了如何计算 CNN 中的参数数量。

如果你有足够的带宽,我会推荐你使用下面链接的安德鲁博士的 coursera 课程。

来源:

[## 卷积神经网络的参数个数如何计算?

我用千层面为 MNIST 数据集创建了一个 CNN。我正在密切关注这个例子:卷积神经…

stackoverflow.com](https://stackoverflow.com/questions/42786717/how-to-calculate-the-number-of-parameters-for-convolutional-neural-network) [## 卷积神经网络| Coursera

本课程将教你如何建立卷积神经网络…

www.coursera.org](https://www.coursera.org/learn/convolutional-neural-networks)

如果你喜欢这篇文章,那就鼓掌吧!:)也许一个跟随?

在 Linkedin 上与我联系:

https://www.linkedin.com/in/rakshith-vasudev/

在 Keras 中理解和编码 ResNet

原文:https://towardsdatascience.com/understanding-and-coding-a-resnet-in-keras-446d7ff84d33?source=collection_archive---------0-----------------------

用数据做很酷的事情!

ResNet 是残差网络的缩写,是一种经典的神经网络,用作许多计算机视觉任务的主干。这款车型是 2015 年 ImageNet 挑战赛的冠军。ResNet 的根本突破是它允许我们成功地训练具有 150+层的非常深的神经网络。在 ResNet 训练之前,由于梯度消失的问题,非常深的神经网络是困难的。

AlexNet 是 2012 年 ImageNet 的获胜者,也是显然启动了对深度学习的关注的模型,它只有 8 层卷积层,VGG 网络有 19 层,Inception 或 GoogleNet 有 22 层,ResNet 152 有 152 层。在这篇博客中,我们将编写一个 ResNet-50,它是 ResNet 152 的一个较小版本,经常被用作迁移学习的起点。

Revolution of Depth

然而,通过简单地将层堆叠在一起,增加网络深度是不起作用的。由于众所周知的梯度消失问题,深层网络很难训练,因为梯度会反向传播到更早的层,重复乘法可能会使梯度变得非常小。因此,随着网络越来越深入,其性能会饱和,甚至开始迅速下降。

我从 DeepLearning 了解到编码 ResNets。AI 课程由吴恩达主讲。我强烈推荐这道菜。

在我的 Github repo 上,我分享了两个笔记本,其中一个按照深度学习中的解释从头开始编写 ResNet。AI 和另一个使用 Keras 中的预训练模型。希望你拉代码自己试试。

跳过连接 ResNet 的优势

ResNet 首先引入了跳过连接的概念。下图说明了跳过连接。左图是一个接一个地将卷积层堆叠在一起。在右边,我们仍然像以前一样堆叠卷积层,但我们现在也将原始输入添加到卷积块的输出。这被称为跳过连接

Skip Connection Image from DeepLearning.AI

它可以写成两行代码:

X_shortcut = X # Store the initial value of X in a variable
## Perform convolution + batch norm operations on XX = Add()([X, X_shortcut]) # SKIP Connection

编码非常简单,但有一个重要的考虑因素——因为上面的 X,X_shortcut 是两个矩阵,只有当它们具有相同的形状时,才能将它们相加。因此,如果卷积+批量范数运算以输出形状相同的方式进行,那么我们可以简单地将它们相加,如下所示。

When x and x_shortcut are the same shape

否则,x_shortcut 会经过一个卷积层,该卷积层的输出与卷积块的输出具有相同的维度,如下所示:

X_shortcut goes through convolution block

在 Github 上的笔记本中,上面实现了两个函数 identity_block 和 convolution_block。这些函数使用 Keras 实现带有 ReLU 激活的卷积和批范数层。跳过连接技术上是一条线X = Add()([X, X_shortcut])

这里需要注意的一点是,如上图所示,跳过连接是在 RELU 激活之前应用的。研究发现这有最好的效果。

为什么跳过连接有效?

这是一个有趣的问题。我认为跳过连接在这里起作用有两个原因:

  1. 它们通过允许渐变流过这种替代的快捷路径来缓解渐变消失的问题
  2. 它们允许模型学习一个标识函数,该函数确保较高层的性能至少与较低层一样好,而不是更差

事实上,因为 ResNet skip 连接被用于更多的模型架构,如全卷积网络(FCN)U-Net 。它们用于将信息从模型中的早期层传递到后期层。在这些架构中,它们用于将信息从下采样层传递到上采样层。

测试我们构建的 ResNet 模型

然后将笔记本中编码的单位和卷积块组合起来,创建一个 ResNet-50 模型,其架构如下所示:

ResNet-50 Model

ResNet-50 模型由 5 个阶段组成,每个阶段都有一个卷积和标识块。每个卷积块有 3 个卷积层,每个单位块也有 3 个卷积层。ResNet-50 拥有超过 2300 万个可训练参数。

我在 signs 数据集上测试了这个模型,这个数据集也包含在我的 Github repo 中。该数据集具有对应于 6 个类别的手部图像。我们有 1080 张训练图像和 120 张测试图像。

Signs Data Set

我们的 ResNet-50 在 25 个训练周期中达到 86%的测试准确率。还不错!

使用预训练库在 Keras 中构建 ResNet

我喜欢自己编写 ResNet 模型,因为它让我更好地理解我在许多与图像分类、对象定位、分割等相关的迁移学习任务中经常使用的网络。

然而,对于更经常的使用,在 Keras 中使用预训练的 ResNet-50 更快。Keras 的中有许多这样的骨干模型及其 Imagenet 权重。

Keras Pretrained Model

我已经在我的 Github 上上传了一个笔记本,它使用 Keras 加载预训练的 ResNet-50。您可以用一行代码加载模型:

base_model = applications.resnet50.ResNet50(weights= **None**, include_top=**False**, input_shape= (img_height,img_width,3))

这里 weights=None,因为我想用随机权重初始化模型,就像我在 ResNet-50 上编码的那样。否则,我也可以加载预训练的 ImageNet 权重。我将 include_top=False 设置为不包括原始模型中的最终池化和完全连接层。我在 ResNet-50 模型中添加了全局平均池和密集输出层。

x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dropout(0.7)(x)
predictions = Dense(num_classes, activation= 'softmax')(x)
model = Model(inputs = base_model.input, outputs = predictions)

如上所示,Keras 提供了一个非常方便的接口来加载预训练的模型,但重要的是至少自己编写一次 ResNet,这样您就可以理解这个概念,并可能将这种学习应用到您正在创建的另一个新架构中。

Keras ResNet 在使用 Adam optimizer 和 0.0001 的学习率对 100 个时期进行训练后,达到了 75%的准确率。精确度比我们自己的编码模型稍低,我猜这与权重初始化有关。

Keras 还为数据扩充提供了一个简单的接口,所以如果你有机会的话,试着扩充这个数据集,看看这是否会带来更好的性能。

结论

  • ResNet 是一个强大的主干模型,在许多计算机视觉任务中经常使用
  • ResNet 使用跳过连接将早期层的输出添加到后期层。这有助于缓解渐变消失的问题
  • 你可以用 Keras 加载他们预训练的 ResNet 50 或者用我分享的代码自己编写 ResNet。

我有自己的深度学习咨询公司,喜欢研究有趣的问题。我已经帮助许多初创公司部署了基于人工智能的创新解决方案。在 http://deeplearninganalytics.org/的入住我们的酒店。

你也可以在https://medium.com/@priya.dwivedi看到我的其他作品

如果你有一个我们可以合作的项目,请通过我的网站或 info@deeplearninganalytics.org 联系我

参考

了解和实施分布式优先体验回放(Horgan 等人,2018 年)

原文:https://towardsdatascience.com/understanding-and-implementing-distributed-prioritized-experience-replay-horgan-et-al-2018-d2c1640e0520?source=collection_archive---------20-----------------------

利用分布式架构加速深度强化学习

在当前的技术水平下,许多强化学习算法利用了积极的并行化和分布。在本文中,我们将审查和实施 ApeX 框架(Horgan 等人,2018 年),也称为分布式优先化体验重放。特别是,我们将实现顶点 DQN 算法。

在这篇文章中,我试图做到以下几点:

  • 讨论分布式强化学习的动机,介绍分布式框架的前身(gorilla)。然后,介绍 ApeX 框架。
  • 简要回顾优先化的经验重放,并让读者参考这篇论文和其他博客文章进行深入讨论。
  • 简要介绍 Ray,这是一个前沿的并行/分布式计算库,我将使用它来实现 ApeX。
  • 运行我的(简化的)ApeX DQN 实现。

分布式 RL 是从哪里开始的,为什么?

第一个推广分布式强化学习架构的工作是 Gorila(通用强化学习框架;我也在某处看到过“Google 强化学习框架”,但论文写的是“通用”)在 Google 的 Nair et al. (2015)上提出。

Gorila framework from “Massively Parallel Methods in Deep Reinforcement Learning” (Nair et al, 2015)

Gorila 中,我们有一个分离的参与者(数据生成/收集)和学习者(参数优化)过程。然后,我们有一个参数服务器和一个中央重放缓冲区,由每个学习者和参与者进程共享。参与者执行轨迹展开,并将其发送到集中重放缓冲区,学习者从该缓冲区采样体验并更新其参数。在学习器更新其参数后,它将新的神经网络权重发送到参数服务器,参与者同步其自己的神经网络权重。所有这些过程都是异步发生的,彼此独立。

Gorila 框架似乎是现代分布式强化学习架构的底层结构——比如 ApeX 。特别地, ApeX 通过使用优先化重放缓冲器(优先化经验重放,由 Schaul 等人(2015)提出)来修改上述结构;我们将在下一节对此进行简要讨论)。

这种架构的动机来自于这样一个事实,即 RL 的大部分计算时间都花在生成数据上,而不是更新神经网络。因此,如果我们使这些过程彼此异步,我们可以执行更多的更新。

除了来自异步结构的加速之外,这种分布式架构具有改进探索的概念优势;我们可以在不同的种子环境中运行每个 actor 流程,以允许收集不同的数据集。例如,A3C (Mnih 等人,2016 年)将其相对于同步版本 A2C 的显著改进归功于改进的探索。因此,算法的分布式实现也受益于这种效果。

优先体验重放的简要回顾

在强化学习中,并不是所有的经验数据都是相等的:直觉上,有些经验比其他经验更能对主体的学习做出贡献。Schaul 等人(2015 年)建议我们根据时间差(TD)误差对体验进行优先排序:

回忆一下规范的 q 学习算法;我们正试图最小化我们的 Q 值的当前预测和我们的引导目标 Q 值之间的距离(即,时间差异误差)。也就是说,该误差越高,神经网络权重的更新程度就越大。因此,我们可以通过采样具有较高 TD 误差的经验来获得更快的学习。

然而,纯粹基于 TD 误差的采样会给学习带来偏差。例如,具有低 TD 误差的经历可能在很长一段时间内不会被重放,减少了重放记忆的限制,并使模型易于过度拟合。为了补救这一点,Schaul 等人(2015)使用重要性采样权重进行偏差校正。也就是说,对于每个更新步骤,我们将梯度乘以体验的重要性采样权重,计算如下:

当实现优先重放缓冲区时,我们希望有两个独立的数据结构来存储经验数据及其各自的优先级值。为了提高采样效率,Schaul 等人(2015 年)建议使用段树(或总和树)来存储优先级值。我们将使用 OpenAI 基线实现来实现 ApeX,但是请查看的这篇博客文章的实际论文,以获得关于优先体验重放的更详细的讨论。

雷简介

下面是使用 Ray 的一个极其简短的介绍:

Click the jupyter notebook file to get a clearer view!

这应该足以完成代码。我建议查看他们的教程和文档,特别是如果您想用 Ray 实现自己的并行/分布式程序。

履行

我们将使用 Ray 进行多处理,而不是内置的 python-多处理模块——从我个人的经验来看,我在调试多处理队列时遇到了很多麻烦,并且用 Ray 实现 ApeX 更容易。

虽然实现运行正常,但我目前正在修复可能的瓶颈和内存泄漏。为此,我的实现仍在进行中——我建议不要用它们大量并行化任务。一旦内存使用问题得到解决,我会更新这篇文章。

我们将这样分解实现过程:我们将把 actor 和 replay buffer 组合在一起,然后是学习器和参数服务器。下面的 jupyter 笔记本文件是我的完整实现的简化版本,只是为了展示如何实现 ApeX 如果您对完整的实现细节感兴趣,并且希望在您的设备上运行它,请查看我的 GitHub 资源库!

演员和重播缓冲区

每次推出后,参与者都将它们的转换数据异步发送到集中式重放缓冲区。集中式缓冲区为体验分配优先级(如优先体验重放中所述),并将成批的采样体验发送给学习者。

我们将实现下面的 actor 过程,并使用优先重放缓冲区的 OpenAI 基线实现。我们必须修改重放缓冲区的基线实现,使其与 Ray 兼容:

演员

Click the jupyter notebook file to get a cleaner view!

我们可以让参与者保留一个本地缓冲区,并定期将所有内容发送到中央缓冲区,从而使参与者进程的内存效率更高——我将很快更新代码。

优先重放缓冲区

Click the jupyter notebook file to get a clearer view!

学习者和参数服务器

利用从中央重放缓冲器发送的经验批次,学习者更新其参数。由于我们使用优先体验重放,学习者还必须更新所用体验的优先级值,并将该信息发送到缓冲区。

一旦学习器参数被更新,它就将其神经网络权重发送到参数服务器。Ray 的一个优点是它支持零成本读取 numpy 数组;也就是说,我们希望学习者发送其网络权重的 numpy 数组,而不是 PyTorch 对象。然后,行动者周期性地用存储的参数拉和同步他们的 q 网络。

我们将从参数服务器开始,并实现学习者流程:

参数服务器:

Click the jupyter notebook file to get a clearer view!

学员:

Click the jupyter notebook file to get a clearer view!

全面实施

要查找 ApeX DQN 和 ApeX DDPG 的运行实现,请在下面的链接中查看我的 GitHub 库:

[## cyoon 1729/分布式强化学习

分布式强化学习算法的单机实现。请看下面的…

github.com](https://github.com/cyoon1729/Distributed-Reinforcement-Learning)

参考

  1. 深度强化学习的大规模并行方法(Nair 等人,2015)
  2. 优先体验回放(Schaul 等人,2015)
  3. 分布式优先体验回放(Horgan 等人,2015)

理解和减少机器学习中的偏差

原文:https://towardsdatascience.com/understanding-and-reducing-bias-in-machine-learning-6565e23900ac?source=collection_archive---------5-----------------------

'..“即使在观察了对象的频繁或持续的联系之后,我们也没有理由得出关于任何超出我们经验的对象的任何推论”——休谟,一篇关于人性的论文

米蕾尤·希尔德布兰特是一名从事法律和技术交叉领域工作的律师和哲学家,他就机器学习算法中的偏见和公平问题发表了大量的文章和演讲。在即将发表的一篇关于不可知论者和无偏见机器学习的论文中(Hildebrandt,2019 年),她认为无偏见机器学习不存在,生产性偏见是算法能够对数据建模并做出相关预测的必要条件。预测系统中可能出现的三种主要偏差类型如下:

任何行动感知系统固有的偏差(生产性偏差)

一些人认为不公平的偏见

基于被禁止的法律理由进行歧视的偏见

机器学习的性能是通过最小化成本函数来实现的。选择一个成本函数,从而选择搜索空间和最小值的可能值,将我们所说的生产偏差引入到系统中。生产偏差的其他来源来自上下文、目的、足够的训练和测试数据的可用性、使用的优化方法以及速度、准确性、过度拟合和过度概括之间的权衡,每个选择都与相应的成本相关联。因此,机器学习没有偏见的假设是错误的,偏见是归纳学习系统的一个基本属性。此外,训练数据也必然有偏差,研究设计的功能是将接近我们要发现的数据模式的偏差与有区别的偏差或只是计算假象的偏差分开。

机器学习中的偏见被定义为观察结果由于错误的假设而受到系统性偏见的现象。然而,如果没有假设,一个算法在一项任务中不会比随机选择结果有更好的表现,这是一个由 Wolpert 在 1996 年正式形成的原则,我们称之为没有免费的午餐定理。

根据“没有免费的午餐定理”(Macready,1997),当对所有可能的数据生成分布进行平均时,所有分类器都具有相同的错误率。因此,某个分类器必须对某些分布和函数有一定的偏好,才能更好地对这些分布进行建模,这同时会使它在对其他类型的分布进行建模时变得更差。

Figure 1: Depiction of the No Free Lunch theorem, where better performance at a certain type of problem comes with the loss of generality (Fedden, 2017)

还应该始终记住,用于训练算法的数据是有限的,因此不能反映现实。这也导致了由训练和测试数据的选择以及它们对真实总体的表示而产生的偏差。我们做出的另一个假设是,假设有限的训练数据能够对测试数据进行建模和准确分类。

“[……]大多数当前的机器学习理论都基于一个重要假设,即训练样本的分布与测试样本的分布相同。尽管我们需要做出这种假设以获得理论结果,但重要的是要记住,这种假设在实践中必须经常被违反。”
——蒂姆·米切尔

即使我们成功地让我们的系统摆脱了上述偏见,随着时间的推移,偏见仍有可能蔓延:一旦算法经过训练,表现良好,并投入生产,算法是如何更新的,谁来决定系统两年后是否仍然表现良好,谁来决定系统表现良好意味着什么?

意识到这些系统中存在的不同偏见需要解释和诠释它们如何工作的能力,这呼应了阿德里安·韦勒(Adrian Weller)演讲的透明度主题:如果你无法测试它,你就无法质疑它。我们需要清楚确保这些系统功能的生产偏差,并找出训练集或算法中剩余的不公平性。这将使我们能够推断第三种也是最严重的偏见,即基于被禁止的法律理由的歧视。

Krishna Gummadi 是 Max Planck Institute for Software Systems 网络系统研究小组的负责人,他在减少分类器中的歧视性偏见方面做了大量工作,他在该领域的研究从计算的角度处理歧视,并开发了算法技术来最小化歧视。

随着机器学习系统在自动化决策中变得越来越普遍,我们使这些系统对导致歧视的偏见类型敏感是至关重要的,特别是基于非法理由的歧视。机器学习已经被用于在以下领域做出或辅助决策:招聘(筛选求职者)、银行(信用评级/贷款审批)、司法(累犯风险评估)、福利(福利津贴资格)、新闻(新闻推荐系统)等。鉴于这些行业的规模和影响,我们必须采取措施,通过法律和技术手段来防止这些行业中的不公平歧视。

为了说明他的技术,Krishna Gummadi 重点介绍了 Northpointe 公司开发的有争议的累犯预测工具 COMPAS,该工具的输出结果在美国各地被法官用于审前和判决。该算法基于对一份 137 项问卷的回答,其中包括关于他们的家族史、居住环境、学校表现等问题。来预测他们未来犯罪的风险。

算法的结果被法官用来决定量刑的长度和类型,同时将投入产出关系视为一个黑箱。虽然一些研究表明,COMPAS(替代制裁的矫正罪犯管理概况)在预测累犯风险方面并不比随机招募的互联网陌生人更好,但其他研究更侧重于测试不同突出社会群体的算法处理。

Figure 2: Study by Propublica that finds discrimination in the rate at which the algorithm misclassifies non-reoffending defenders at different rates for blacks and whites

ProPublica (Jeff Larson,2016 年)的一项研究表明,与白人辩护人相比,该算法将最终没有再次犯罪的黑人辩护人标记为高风险的可能性是两倍。这是由于黑人被告的假阳性率(FP 率)为 44.85(即 44.85%被归类为再次犯罪的黑人被告没有再次犯罪),而白人被告的假阳性率为 23.45。然而,Northpointe 反驳说,根据他们使用的方法,黑人和白人捍卫者的错误分类率是一样的。

Figure 3: Northpointe’s rebuttal that their scoring on a 10-point scaled classified blacks or whites correctly at similar rates

事实证明,双方都是正确的,这是因为他们使用不同的公平措施。如果黑人和白人的基础累犯率不同,那么没有算法可以在这两种公平性度量上表现得一样好。这两种公平性度量都代表了内在的权衡。

我们需要能够理解这些公平性度量的权衡,以便对它们的区分能力做出明智的决定。这就是为什么我们需要计算视角。因此,让我们先从这个角度来理解什么是歧视。

使用的规范定义是:

相对劣势 强加于人 基于 他们隶属于某个显著的社会群体例如种族或性别**

我们如何操作这个定义,并在算法中实现它?上面的表述包含了几个模糊的概念,需要正式化,“相对劣势”,“错误强加”,“突出的社会群体”等。如果我们只关注“相对劣势”部分,我们将恢复算法中可能出现的第一种歧视,即完全不同的待遇。

Figure 4: Example of a binary classification problem where the algorithm learns whether a loan will be repaid based on m+1 features, of which z is a sensitive feature

克里希纳用上面的二元分类问题来更好地理解不同类型的歧视。问题是基于 m+1 个特征来预测贷款是否会被偿还,其中一个特征是敏感特征,例如客户的种族。

完全不同的待遇:

如果用户的预测结果随着敏感特征的改变而改变,则可以检测到这种类型的相对区分。在上面的例子中,这意味着算法预测白人的还贷标签为正,黑人的还贷标签为负,即使所有其他特征都完全相同。为了防止对种族的任何依赖,我们需要从数据集中移除敏感特征

我们可以将其形式化为:

即输出的概率 P 不应依赖于输出或随输出而变化

完全不同的影响:

如果不同敏感组的阳性(阴性)结果的比例存在差异,则可以检测到这种类型的相对歧视。在上述情况下,如果与白人相比,更多的黑人被归类为违约者,就会发生这种情况。

我们将这一要求正式化为:

即 z=1(白人客户)的正标签(归还贷款)的概率与 z=0(黑人客户)的正标签的概率相同。

完全不同的影响衡量对一个群体的间接歧视程度,也经常出现在人类决策中。即使我们通过删除敏感特征来消除完全不同的待遇,通过其他相关特征(如邮政编码)仍然会发生歧视。衡量和纠正不同的影响可以确保这种情况得到纠正。当训练数据集有偏差时,应该使用此要求。同时被许多人认为是一个有争议的措施,特别是批评家,他们认为一些情况不能摆脱不相称的结果。

完全不同的虐待:

当我们测量不同敏感群体的准确结果的差异时,这种类型的相对歧视是可检测的。这是 Propublica 在 Northpointe 算法中发现的歧视类型,该算法将无辜的黑人捍卫者错误地归类为重新犯罪的比率是白人的两倍。我们可以通过要求所有相关的敏感群体获得相同比例的准确结果来纠正这种不公平。

我们将这一要求正式化为:

其中 z=0,1 代表不同的敏感基团。

非歧视性机器学习的机制:

在正式确定纠正算法中的歧视的机制之前,我们需要考虑这样一个事实,即算法并不像流行的叙述那样是无偏见的。与人类相比,算法是客观的,但这并不使它们公平,只是使它们客观上具有歧视性。算法的工作是优化一个成本函数,以达到产生我们想要预测的输出的实际函数的最佳近似。如果最佳函数是将弱势群体的所有成员分类为重新犯罪或无力支付贷款的函数,那么这就是算法将要选择的函数。因此,客观的决定可能是不公平和歧视性的。

简而言之,算法通过逼近以要素为输入并逼近输出的函数来学习输出的模型。它根据最小化函数输出和实际结果之间差异的参数来决定该函数的最佳参数。这被称为优化问题。我们可以通过要求近似函数也必须服从上述公式化要求中的一个或全部来避免歧视,从而对此问题添加进一步的约束。那就是:

这要求模型以所有敏感组的准确率相同的方式近似。然而,添加约束会导致折衷,这是一种相对公平的算法,但代价是一些精度。克里希纳将这一约束应用于累犯预测算法,并以一点准确性为代价,设法获得了一种对黑人和白人被告具有类似错误率的算法。他对假阳性率(FPR)和假阴性率(FNR)进行了限制,假阳性率是无辜被告被归类为累犯的概率,假阴性率是未来再次犯罪的被告被归类为非再次犯罪的概率。正如我们在图 8 中看到的,随着约束条件的收紧,黑人和白人被告的 FPR 和 FNR 的差异接近于 0,而准确性只有很小的损失(约 66.7%至约 65.8%)。

Figure 5: Correcting Disparate mistreatment for Recidivism prediction dataset.

简而言之,尽管担心算法只会进一步巩固和传播人类的偏见,但人工智能社区仍在努力避免和纠正算法中的歧视性偏见,同时使它们更加透明。此外,GDPR 的出现使这些努力正式化和结构化,以确保各行业在存储和处理大量公民个人数据时有动力遵循最佳实践,并以牺牲一些准确性为代价优先考虑公平。最终,算法系统将是它们试图模拟和近似的社会的反映,这将需要政府和私营部门的积极努力,以确保它不仅能够巩固和进一步加剧我们结构中固有的不平等,而且能够通过采取严厉的惩罚措施和约束来纠正它们。这让我们可以设想这样一个社会,在这个社会中,决策可以通过用客观的算法决策来取代人类偏见的主观性,即使不能完全消除偏见,也能意识到自己的偏见。

如果你喜欢阅读这样的故事,并想支持我的写作,请考虑注册成为一名媒体会员。每月 5 美元,你可以无限制地阅读媒体上的所有报道。如果你使用 我的链接 注册,我会收到一点佣金。

引用的作品

安萨罗。(2017 年 10 月 12 日)。检索自https://medium . com/ansaro-blog/interpreting-machine-learning-models-1234d 735 d6c 9

费登大学(2017 年)。检索自 Medium Inc .:https://Medium . com/@ LeonFedden/the-no-free-lunch-theory-62 AE 2c 3 ed 10 c

希尔德布兰特,M. (2019)。隐私作为不可计算自我的保护:从不可知论者到竞争机器学习。(第 19 (1)页)。即将出版的法律理论研究。

杰夫·拉森,S. M. (2016 年 5 月)。检索自 ProPublica:https://www . ProPublica . org/article/how-we-analyzed-the-compas-recidivis-algorithm

凯文·艾克霍尔特,即(2018)。对深度学习视觉分类的鲁棒物理世界攻击。 CVPR。

兰格(1978)。表面上深思熟虑的行动的盲目:人际互动中“地点”信息的作用。《人格与社会心理学杂志》,36 卷 6 期,635–642 页。

麦克瑞德博士(1997 年)。最优化没有免费的午餐定理。IEEE 进化计算汇刊,第 1 卷,№1。

马尔科·图利奥·里贝罗(2016 年)。“我为什么要相信你?”:解释任何分类器的预测。第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集(第 1135-1144 页)。ACM。

麻省理工新闻。(2018 年 2 月 11 日)。检索自http://news . MIT . edu/2018/study-finds-gender-skin-type-bias-artificial-intelligence-systems-0212

打开 AI 博客。(2017 年 2 月 24 日)。从 https://blog.openai.com/adversarial-example-research/取回

Rich Caruana 等人(未注明)。医疗保健的可理解模型:预测肺炎风险和住院 30 天再入院。第 21 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集(第 1721-1730 页)。美国纽约。

连线公司(2018 年 3 月 29 日)。编码员如何对抗面部识别软件中的偏见。检索自https://www . wired . com/story/how-coders-are-fighting-bias-in-face-recognition-software/

理解和使用 Python 类

原文:https://towardsdatascience.com/understanding-and-using-python-classes-3f7e8d1ef2d8?source=collection_archive---------5-----------------------

Python 是一种解释的、面向对象的、具有动态语义的高级编程语言。后者是官方网站python.org给出的正式定义。让我们打破它,试着理解它:

  • 解释型:与编译型编程语言(源代码必须转换成机器可读的代码)不同,解释型语言不直接由目标机器执行。取而代之的是,它们被称为解释器的其他计算机程序读取和执行;
  • 面向对象:这意味着 python 像任何其他面向对象编程(OOP)语言一样,是围绕对象组织的。python 中的一切(列表、字典、类等等)都是对象;
  • 高级:这意味着代码的语法更容易被人类理解。也就是说,如果你必须在屏幕上显示一些东西,这个内置函数叫做print;
  • 动态语义:动态对象是包含在代码结构中的值的实例,它们存在于运行时级别。此外,我们可以给一个对象分配多个值,因为它会自我更新,这与静态语义语言不同。也就是说,如果我们设置 a=2 ,然后a =‘hello’,那么一旦执行了该行,字符串值将替换整数 1。

在本文中,我想更深入地研究类的概念。类是一种特殊类型的对象。更具体地说,它们是对象构造器,能够构建数据表示和我们可以用来与该对象交互的过程(因此是方法、函数等等)。

要在 Python 中创建一个类,我们需要给这个类一个名称和一些属性。让我们从下面的例子开始:

class Actor:
    def __init__(self, name, surname, age, years_on_stage):
        self.name=name
        self.surname=surname
        self.age=age
        self.years_on_stage=years_on_stage

于是我们创建了一个名为 Actor 的类,它定义了一些特征(名字、姓氏、年龄、登台年数)。有两个要素需要关注:

  • init() :用于初始化数据属性的特殊方法。我们可以把它看作一个初始化器。
  • self :这是一个标准符号,用来指向参数。

现在,我们可以使用我们的类并创建一个类 Actor 的对象:

mario=Actor(
    'Mario',
    'Rossi',
    40,
    13
)

现在,我们可以访问 mario 的所有属性(我们在 init() 中定义的):

mario.name"mario"mario.age40

现在,假设我们想知道 mario 的具体信息,而这些信息并没有存储在它的属性中。更具体地说,我们想知道出道的年份,但只提供给我们在舞台上的年份。所以我们想要的是一个从当前日期减去舞台上的年份的函数,这样它就返回出道的年份。

我们可以这样直接进入我们的演员类:

class Actor:
    def __init__(self, name, surname, age, years_on_stage):
        self.name=name
        self.surname=surname
        self.age=age
        self.years_on_stage=years_on_stage
    def year_of_debut(self, current_year):
        self.current_year=current_year
        year_of_debut=self.current_year-self.years_on_stage
        return year_of_debut

现在让我们在我们的对象 mario 上测试它:

mario.year_of_debut(2019)2006

最后我要讲的是 python 类的一个非常有趣且有用的属性,叫做类继承。其思想是,如果您必须创建一个类(称为子类),它是您已经创建的类(称为父类)的子集,您可以很容易地将其属性导入子类。

让我们通过下面的例子来看看如何做到这一点。假设您想要创建一个名为 Comedian 的子类,它与父类 Actor 有一些共同的属性:

class Comedian(Actor):
    def __init__(self, n_shows, field, shows_schedule, name, surname, age, years_on_stage):
        self.n_shows=n_shows
        self.field=field
        self.shows_schedule=shows_schedule
        super().__init__(name,surname,age,years_on_stage)

可以看到,我们没有为的名字、姓氏、年龄years_on_stage 指定 self.attribute=attribute ,而是通过函数 super() 直接由父类继承。现在,我们可以创建一个子类的对象,并像在父类示例中一样访问它的属性:

a_comedian=Comedian(
           21,
          'politics',
          'late night', 
          'amelia', 
          'smith', 
          '33', 
          '10'
)a_comedian.name'amelia'a_comedian.field'politics'

Python 类的优势显而易见。特别是,它们使得 Python 语言非常具有可定制性:不仅可以创建个性化的函数(除了那些内置的函数),还可以创建能够完美满足您需求的对象生成器。

理解反向传播算法

原文:https://towardsdatascience.com/understanding-backpropagation-algorithm-7bb3aa2f95fd?source=collection_archive---------0-----------------------

了解神经网络最重要组成部分的具体细节

“A man is running on a highway” — photo by Andrea Leopardi on Unsplash

反向传播算法可能是神经网络中最基本的构建模块。它最早于 20 世纪 60 年代提出,近 30 年后(1989 年)由 Rumelhart、Hinton 和 Williams 在一篇名为的论文中推广开来。

该算法用于通过一种称为链规则的方法有效地训练神经网络。简单来说,在网络的每次正向传递之后,反向传播在调整模型参数(权重和偏差)的同时执行反向传递。

在本文中,我想回顾一下训练和优化一个简单的 4 层神经网络的数学过程。我相信这将帮助读者理解反向传播是如何工作的,并意识到它的重要性。

定义神经网络模型

4 层神经网络由 4 个用于输入层的神经元、4 个用于隐含层的神经元和 1 个用于输出层的神经元组成。

Simple 4-layer neural network illustration

输入层

紫色的神经元代表输入数据。这些可以像标量一样简单,也可以像向量或多维矩阵一样复杂。

Equation for input x_i

第一组激活( a )等于输入值。注意:“激活”是应用激活函数后神经元的值。见下文。**

隐藏层

使用z^l-层 l 中的加权输入,以及a^l-层 l 中的激活,计算隐藏神经元的最终值,以绿色t29】表示。对于第 2 层和第 3 层,等式为:

  • l = 2

Equations for z² and a²

  • l = 3

Equations for z³ and a³

WW 是层 2 和层 3 中的权重,而 b 和 b 是这些层中的偏差。

使用激活函数 f 计算激活 aa 。典型地,这个函数 f 是非线性的(例如 sigmoidReLUtanh ),并且允许网络学习数据中的复杂模式。我们不会详细讨论激活函数是如何工作的,但是,如果感兴趣,我强烈推荐阅读这篇伟大的文章

仔细观察,您会发现所有的 x、z、a、z、a、W、W、bb 都缺少上面 4 层网络图中的下标。原因是我们已经将矩阵中的所有参数值组合起来,按层分组。这是使用神经网络的标准方式,人们应该对计算感到舒适。不过,我会检查一下方程式,以消除任何混淆。

让我们挑选第 2 层及其参数作为例子。相同的操作可以应用于网络中的任何层。

  • W 是形状为 (n,m) 的权重矩阵,其中 n 是输出神经元(下一层神经元)的数量, m 是输入神经元(上一层神经元)的数量。对于我们来说, n = 2m = 4

Equation for W¹

NB:任何权重下标中的第一个数字匹配下一层中神经元的索引(在我们的例子中,这是 Hidden_2 层 ) ,第二个数字匹配上一层中神经元的索引(在我们的例子中,这是输入层)。

  • x 是形状 (m,1) 的输入向量,其中 m 是输入神经元的数量。对于我们来说, m = 4

Equation for x

  • b 是形状 (n,1) 的偏置向量,其中 n 是当前层中神经元的数量。对于我们来说, n = 2

Equation for b¹

根据 z、的等式,我们可以使用上述 W、xb 的定义来推导出“z 的等式”:

Equation for z²

现在仔细观察上面的神经网络图。

Input and Hidden_1 layers

你会看到 z 可以用( z_1) 和( z_2) 来表示,其中( z_1) 和( z_2) 是每个输入 x_i 与相应权重( W_ij)相乘的和。

这导致 z 的相同的“T14”方程,并证明 z、a、z 和 a 的矩阵表示是正确的。

输出层

神经网络的最后一部分是产生预测值的输出层。在我们的简单示例中,它被表示为单个神经元,以蓝色着色,评估如下:

Equation for output s

同样,我们使用矩阵表示来简化方程。人们可以使用上述技术来理解底层逻辑。如果你发现自己迷失在方程式中,请在下面留下你的评论——我很乐意帮助你!

正向传播和评估

上述方程构成了网络的前向传播。下面是一个简短的概述:

Overview of forward propagation equations colored by layer

正向传递的最后一步是相对于预期输出 y 评估预测输出 s

输出 y 是训练数据集 (x,y) 的一部分,其中 x 是输入(正如我们在上一节中看到的)。

sy 之间的评估通过成本函数*进行。这可以像 MSE (均方误差)一样简单,也可以像交叉熵一样复杂。*

我们将这个成本函数命名为 C ,并表示如下:

Equation for cost function C

如果成本可以等于 MSE、交叉熵或者任何其他成本函数

基于 C 的值,模型“知道”调整其参数多少,以便更接近预期输出 y 。这是使用反向传播算法实现的。

反向传播和计算梯度

根据 1989 年的论文,反向传播:

重复地调整网络中连接的权重,以便最小化网络的实际输出向量和期望输出向量之间的差的度量。

创建有用的新功能的能力将反向传播与早期更简单的方法区分开来…

换句话说,反向传播旨在通过调整网络的权重和偏差来最小化成本函数。调整水平由成本函数相对于这些参数的梯度决定。

可能会出现一个问题——为什么要计算梯度

要回答这个问题,我们首先需要重温一些微积分术语:

  • 函数 C(x1,x2,…,x_m)在 x 点的梯度是 C 在 x 点的 偏导数 的向量

Equation for derivative of C in x

使用一种叫做链式法则的技术来计算这些梯度。

对于单个重量 (w_jk)^l,的梯度为:

Equations for derivative of C in a single weight (w_jk)^l

类似的方程组可以应用于 (b_j)^l ):

Equations for derivative of C in a single bias (b_j)^l

两个方程中的公共部分通常被称为“局部梯度”,并表示如下:

Equation for local gradient

使用链式法则可以很容易地确定“局部梯度”。我现在不会重复这个过程,但是如果你有任何问题,请在下面评论。

梯度允许我们优化模型的参数:

Algorithm for optimizing weights and biases (also called “Gradient descent”)

  • 随机选择 wb 的初始值。
  • ε(e)是学习率。它决定了渐变的影响。
  • wb 是权重和偏差的矩阵表示。 wb 中的 C 的导数可以使用各个权重或偏差中的 C 的偏导数来计算。
  • 一旦成本函数最小化,就满足终止条件。

我想把这一节的最后部分献给一个简单的例子,在这个例子中,我们将计算 C 相对于单个重量 (w_22) 的梯度。

让我们放大上面神经网络的底部:

Visual representation of backpropagation in a neural network

权重 (w_22) 连接(a _ 2)(z _ 2),因此计算梯度需要通过(z _ 2)(a _ 2)应用链式法则

Equation for derivative of C in (w_22)²

计算 (a_2)C 的导数的最终值需要了解函数 C 。由于 C 依赖于 (a_2) ,计算导数应该相当简单。

我希望这个例子能够揭示计算梯度背后的数学原理。为了进一步提高你的技能,我强烈推荐观看斯坦福大学的 NLP 系列,其中理查德·索彻对反向传播给出了 4 个很好的解释。

结束语

在这篇文章中,我详细解释了反向传播是如何使用计算梯度、链式法则等数学技术进行工作的。了解这种算法的具体细节将巩固你的神经网络知识,并让你对更复杂的模型感到舒适。享受你的深度学习之旅!

谢谢你的阅读。希望你喜欢这篇文章🤩我祝你今天过得愉快!

理解量子计算中测量的基础

原文:https://towardsdatascience.com/understanding-basics-of-measurements-in-quantum-computation-4c885879eba0?source=collection_archive---------4-----------------------

Measuring a Quantum bit

如果你对量子计算理论有更深入的了解,你可能会遇到这个叫做测量的术语。在顶层,测量本质上就是上图所描绘的:对一个量子位的某种操作(基向量|0 >和|1 >的某种叠加状态)以获得一个经典位(其过程是完全随机的)。

开始之前。如果你在理解量子位、叠加、基本向量等术语时遇到困难,我会建议你阅读这篇文章作为介绍bra 和 ket 符号以及这篇线性代数评论(并且不要省略特征向量和特征空间、正交性)。另外,参考其他关于(复)向量空间、内积、线性组合和相关概念的资料。

好吧,前提条件完成了。言归正传!

为什么是这篇文章?

当我开始学习量子测量的时候,事情并不是很顺利。数学没有那么难,但是基本的直觉为什么以他们的方式做事情却不见了,至少在我的消息来源里。当我最终将不同的部分组合在一起时,我认为这将有助于开辟一种不同的方法来理解量子测量(一种自上而下的方法— ,这意味着将数学保留到最后,同时首先理解更广泛的含义)并首先理解为什么我们需要区分我将在这里讨论的两种测量—一般投影POVM。

等等!我没说的两种的三围和命名。别担心。把我的陈述解释成一种带有一定程度不确定性的量子陈述。通过这种方式,你会提出问题并更好地理解(整篇文章都是如此)。

我将从量子力学的前提假设开始:

假设 1

简单来说,如果你有一个孤立的量子系统,有一个内积定义的复向量空间附着在那个系统上,叫做空间。

直观地,这样的空间被描述为将欧几里得(或主要是 2 维空间)微积分和线性代数的概念结合到多维空间。这允许像测量长度和角度的几个操作。

点击此处了解更多关于希尔伯特空间的信息

假设 2

给定一个封闭的量子系统,系统的演化用一个幺正变换来描述。

Unitary transformation of a quantum state

在上面的等式中,U 是一个酉矩阵(或者一个与其伴随矩阵的乘积产生单位矩阵的矩阵)。更一般地,对于连续时间,这种幺正变换可以写成:

You just got introduced to the Schrodinger’s equation!

这也是一个酉变换,尽管它需要一点理解。这里, H 称为哈密顿算符,是厄米算符。简单来说,厄米特的伴随就是算子本身,即 adj(H) = H. 求解上面关于时间的微分方程,得出下面的方程:

exp 部分中的术语需要更多解释。这里,H 是厄米算符。一个厄米算符乘以一个标量(本质上是时间和 Dirac-h 的差的比值)保持了厄米性质。无需深入数学,任何形式为 exp(-i.K) 的东西都会产生酉算子,其中 K 是厄米算子。

回到测量

我将避免在这里直接发起关于度量的正式讨论。我更愿意讨论一个更大的图片,并希望它能使普通投影测量之间的区别更加清晰。

到目前为止,我们意识到了一件重要的事情:

这些假设适用于封闭、隔离的系统。

简单地说,这在现实世界中很难发生。这意味着你关于单一进化的正式观点(公设 2)不是很正确。你的哈密尔顿函数没有给你一个清晰的酉算符,可以完美地描述被观察系统的力学。两个非常简单的例子可以说明这一点:

  1. 在大多数情况下,测量会破坏量子态。
  2. 能量进入和离开系统。

如果你有一些 QM 的正式背景,你可能知道 1 本质上是正确的。一个系统保持在叠加状态,除非它被测量。举例?考虑一下这篇文章的顶部图片。

我们有一个由|0 >和|1 >的某种线性组合形成的量子位(叠加量子态)。测量后,它成为一个经典位(0 或 1)。

现在是时候介绍一下常规、POVM投影测量了。现在把这些测量系统看作是一种黑箱,所以我们可以着眼于更大的图景而不会被细节所困扰。

长话短说,系统是封闭的,并且由一个哈密顿量通过酉时间演化来描述,可以通过投影测量来测量。很明显,系统在现实中不是封闭的,因此使用投影测量是不可测量的。为了测量这样的系统,我们有两个选择:

  1. 较小的开放系统视为较大系统的子部分,该系统关闭。在这种情况下,更大系统的演化可以用酉演化来描述,我们可以用射影测量到把东西测量出来。这将需要将关于完整的较大系统(姑且称之为环境)的完整细节添加到被观察的较小开放系统的哈密顿量中。但是这里有一个固有的缺陷。你知道 关于环境的一切 为了让它成为一个完全封闭的系统吗?这个很难确定。这个问题把我们引向第二种选择。
  2. 让系统打开,并从已知的投影测量中开发一些其他测量技术。

原来 POVM ( 正算子值度量)是对投影度量限制,因此它包含除了环境之外的一切。简而言之,如果你采取了 POVM,你就不需要再关心环境了。或者换句话说,

我们可以从 POVMs 中得到投影测量,如果我们将环境因素考虑在内,使其成为酉时演化,即投影= POVMs +环境

这不正是我们要找的吗?一种不用关心环境就能测量系统的方法。而 POVM 就是答案。还有另外一个微妙的区别——尽管 POVMs一般测量在数学上看起来是一样的(事实上, POVMs 是通过将一个变量代入一般测量方程中获得的),但两者之间有一个重要的区别。然而,为了说明这一点,我需要引入关于这些测量的数学方程。

一般测量值

在量子测量场景中,测量算符本质上是一个矩阵(而不是一个精心选择的矩阵),它以数学方式操纵系统的初始状态。

Probability of the measurement to be m

上式给出了测量值与输出值的概率 m. 如果您熟悉 bra 和 ket 符号,最左边的符号表示原始系统状态的转置、复共轭行向量(原始系统状态是最右边的列向量)。中间是左边算符 M 乘以原算符 M 的伴随。

Post-measurement state

这个等式简单地是操作符对当前状态的应用,除以状态发生的概率。务必理解这一重要等式,因为这将被证明是常规POVM 测量之间的本质区别。

描述我们选择的操作符的性质的几个其他等式(基本上是对所有可能输出的求和,如果我们取伴随矩阵和原始矩阵的乘积,我们最终得到单位矩阵)。第二个方程是概率的基本假设,所有概率的总和本质上是一。

The ‘completeness equation’

我会休息一下,展示一个这些方程的例子。在这里更好地表示方程有点困难,因此我将把它写在纸上,并在这里贴一个屏幕。我已经展示了量子位前三个方程的必要计算。

需要注意的是这两个红色的简单计算语句。

  1. 每个操作员都是隐士
  2. 算符的平方就是算符本身。

An important result!!!

投影测量

记住这些是对经历酉进化的封闭系统的测量,,因此利用了最基本的直觉之一- 特征值和特征向量。

简单来说,特征向量的作用是算子的操作分解成几个独立的向量方向。因此,现在可以在不同的方向上独立地和单独地观察操作者的动作。此外,算子在这些方向上的动作仅仅涉及特征向量的拉伸、压缩、翻转(或数学上的标量乘法)

可能需要一段时间才能理解,但这是一个可以充分利用的非常强大的属性。

上面的等式是可观测 M 的谱分解,它只是将 M 分解成几个投影到 M 的本征空间,乘以 M 的本征值别担心,我会演示如何做。

其余所有来自一般测量值的方程得到相当简化:

Probability of the measurement yielding output as the eigenvalue m

The post-measurement state calculation equation

任何满足一般度量、要求的算子,如果遵循一个附加限制,就成为射影度量算子。**

Additional restriction for being projective!

不难将这些点联系起来,这里要注意的是,这个附加限制仅在封闭系统中得到满足,或者更具体地说,在这些系统中,测量是非破坏性测量,,即它们在测量时不会使量子态崩溃。为什么这样让我给出数学解:

可以看出,重复使用投影不会改变输出。一次又一次得到相同测量值的概率是 1。因此,投影不是我们在现实世界中可以使用的东西。

现在让我用一个例子演示一下投影计算的所有数学方面:

Note: The bottommost calculation wrongly computes using [0 1] instead of the previously assumed [1 0]. Thanks to Brian Droncheff for pointing this out in the comments.

上面的例子显示了一旦一个运算符 Z 被分解成一组向量,它的应用变得多么简单。这也展示了特征向量是如何相互独立地被分析和处理的,从而使事情变得简单得多。

POVM 测量

数学上,POVMs 由给定的一般测量概率分布:形成

Probability distribution of a general measurement

只需进行以下替换:

得到下面的等式:

Probability distribution

Completeness relation

我们结束了吗?好吧。号码

乍一看似乎很容易,但这里隐藏着一些东西。幸运的是,你已经知道我要求你记住的关于一般测量*和 POVMs 之间区别的关系。*

The post measurement state

现在,如果你从最初的运算符 M 开始,你就可以开始了。但是如果从关于 E 的初始知识开始呢?在这种情况下,将 E 分解成另一个矩阵 M 及其伴随矩阵是完全不可能的。因此,我们失去了 M,并因此失去了测量测量后状态的能力。在我们不需要知道任何关于测量后状态的情况下,POVMs 是惊人的。此外,这也是大多数标准文本倾向于仅从通用测量关系开发 POVMs 的原因。

另一个要联系的点是投影= POVM +环境,或者 POVM 是对不考虑环境的投影的限制。为此,请看下面的等式:

POVMs = projections. The extreme right P(m) comes from the middle expression utilising the fact that the operator P is Hermitian and square of the operator is the operator itself (statements in red ink in my handwritten example above in general measurements)

当且仅当:

The additional restriction for projections

这意味着关于POVM+environment = Projections的讨论仅仅意味着让操作者遵守上面描述的附加限制。此外,这也意味着同样的等式导致投影依赖于系统的单一时间演化和隔离,或者换句话说,给予系统对其环境足够的响应性。

结论

我希望这篇文章能帮助你抓住这些测量背后的基本直觉,以及它们在更大范围内是如何相互关联的。了解这些基础知识是理解量子力学公设 3 的关键。

祝你今天开心!玩的开心!

理解贝叶斯定理

原文:https://towardsdatascience.com/understanding-bayes-theorem-7e31b8434d4b?source=collection_archive---------7-----------------------

Photo by Antoine Dautry on Unsplash

理解著名定理背后的基本原理

这是统计和概率世界中最著名的方程式之一。即使你不从事定量领域的工作,你也可能不得不在某个时候为了考试而记忆它。

P(A|B) = P(B|A) * P(A)/P(B)

但这意味着什么,为什么会起作用?在今天的帖子中找出我们深入探索贝叶斯定理的地方。

更新我们信念的框架

不管怎样,概率(和统计学)的意义是什么?它最重要的应用之一是不确定情况下的决策。当你决定采取一项行动时(假设你是一个理性的人),你在打赌完成这项行动会让你比没做时过得更好。但是赌注本身是不确定的,所以你如何决定是否继续?

含蓄地或明确地,你估计成功的概率——如果概率高于某个阈值,你就勇往直前。

因此,能够准确估计这一成功概率对于做出好的决策至关重要。虽然机会总是在结果中发挥作用,但如果你能持续地积累对你有利的机会,那么随着时间的推移,你会做得很好。

这就是贝叶斯定理的用武之地——它为我们提供了一个量化框架,当我们周围的事实发生变化时,我们可以更新我们的信念,这反过来允许我们随着时间的推移改进我们的决策。

让我们试试这个公式

让我们再看一下公式:

P(A|B) = P(B|A) * P(A)/P(B)

  • P(A|B) —是给定 B 已经发生的概率。
  • P(B|A) —是给定 A 已经发生的情况下,B 的概率。它现在看起来是循环的和任意的,但是我们很快就会明白为什么它会起作用。
  • P(A)—A 发生的无条件概率。
  • P(B) —是 B 发生的无条件概率。

P(A|B)是条件概率的一个例子——只测量世界上某些状态(B 出现的状态)的概率。P(A)是一个无条件概率的例子,在世界上所有的州都可以测量。

让我们通过一个例子来看看贝叶斯定理。假设你是一名刚刚毕业的数据科学训练营的学生。你还没有收到一些你面试过的公司的回复,你开始紧张了。因此,你决定计算一家特定公司向你发出要约的概率,因为已经过去 3 天了,他们仍然没有给你打电话。

让我们根据我们的例子重写公式。在这里,结果 A 是“收到一个提议”(编辑:这篇文章的早期版本错误地将 A 标识为“没有提议”——现在已经被更正为“收到一个提议”),结果 B 是“3 天没有电话”。所以我们可以把公式写成:

P(Offer | NoCall)= P(NoCall | Offer)* P(Offer)/P(NoCall)

P(Offer|NoCall)的值,即 3 天没有电话的情况下收到 Offer 的概率,很难估计。

但是反过来,P(NoCall|Offer),或者说如果你收到了公司的邀请,3 天内没有电话的可能性,更像是我们可以合理确定价值的东西。从与朋友、招聘人员和工作顾问的交谈中,你了解到,如果一家公司打算给你一份工作,它不太可能保持沉默长达 3 天,但这并不罕见。所以你估计:

p(无呼叫|报价)= 40%

40%还不错,好像还有希望!但是我们还没完。现在我们需要估计 P(Offer),即在一段时间内获得工作机会的概率。每个人都知道找工作是一个漫长而艰难的过程,在得到那份工作之前,你可能至少需要面试几次,所以你估计:

p(报价)= 20%

现在我们只需要估算 P(NoCall),3 天没有接到公司回电的概率。一家公司可能三天不给你打电话有很多原因——他们可能决定放弃你,或者他们可能还在面试其他候选人,或者招聘经理可能感冒了。哇,他们可能没有打电话的原因有很多,所以你估计的最后一个可能性是:

P(NoCall) = 90%

现在把它们全部插入,我们可以计算 P(Offer|NoCall):

p(Offer | NoCall)= 40% * 20%/90% = 8.9%

这相当低——所以不幸的是,我们不应该抱太大希望(我们绝对应该继续投简历)。如果这看起来有点武断,不要担心。当我第一次学习贝叶斯定理时,我也有同样的感觉。现在让我们来解释一下我们是如何以及为什么会达到 8.9%(记住你最初估计的 20%已经很低了)。

公式背后的直觉

还记得我们说过贝叶斯定理是更新我们信念的框架吗?那么我们的信仰从何而来?他们通过先验的 P(A)进来,在我们的例子中是 P(Offer)——这是我们关于有多大可能收到要约的先验信念。在我们的例子中,你可以认为先验是我们对你在走出面试室的那一刻收到工作机会的可能性的信念。

现在,新的信息来了——3 天过去了,公司还没有给你打电话。所以我们用等式的其他部分来调整我们对已经发生的新事件的先验。

让我们检查 P(B|A),在我们的例子中是 P(NoCall|Offer)。当你第一次学习贝叶斯定理时,很自然会想知道 P(B|A)项的意义是什么。如果我不知道 P(A|B ),那么我怎么能神奇地知道 P(B|A)是什么呢?这让我想起了查理·孟格曾经说过的话:

“反转,一直反转!”—查理·孟格

他的意思是,当试图解决一个具有挑战性的问题时,更容易把问题反过来看——这正是贝叶斯定理正在做的。让我们用统计术语重新定义贝叶斯定理,使它更容易解释(我首先在这里读到这个):

Bayes’ Theorem reframed so that it is more intuitive

对我来说,这是一种更直观的思考公式的方式。我们有一个假设(我们得到了这份工作),一个先验,并观察到一些证据(3 天没有电话)。现在我们想知道在给定证据的情况下,我们的假设为真的概率。正如我们上面讨论的,我们已经有了 20%的优先权。

反转时间到了!我们用 P(证据|假设)来反过来问这个问题:“在我们的假设为真的世界里,观察到这个证据的概率是多少?”因此,在我们的例子中,我们想知道在一个公司已经明确决定向你发出邀请的世界里,3 天没有电话的可能性有多大。在上面公式的注释图中,我称 P(证据|假设)为缩放器,因为这正是它的作用。当我们将它与先验相乘时,定标器会根据证据是有助于还是有损于我们的假设来放大或缩小先验——在我们的例子中,定标器会缩小先验,因为没有电话的日子越来越多,这将是一个越来越糟糕的迹象。3 天的无线电沉默已经不好了(它减少了我们 60%的先验),但 20 天的沉默会彻底摧毁我们得到这份工作的任何希望。因此,我们积累的证据越多(没有打电话的天数越多),缩放器就越能减少我们的先验。定标器是贝叶斯定理用来调整我们先验信念的机制。****

编辑:在这篇文章的最初版本中,我有些纠结的一件事是阐明为什么 P(证据|假设)比 P(假设|证据)更容易估计。这是因为 p(证据|假设)是一种更受约束的思考世界的方式——通过缩小范围,我们简化了我们的问题。一个简单的方法是用流行的火和烟的例子,火是我们的假设,观察烟是证据。p(火|烟)更难估计,因为很多东西都可能引起烟——汽车尾气、工厂、有人在炭火上烤汉堡。 P(烟|火)更容易估计——在一个有火的世界里,几乎肯定会有烟。

The value of the scaler decreases as more days pass with no call — the lower the scaler, the more it reduces the prior as they are multiplied together

我们公式的最后一部分,P(B),又名 P(证据)是规格化器。顾名思义,它的目的是归一化先验和定标器的乘积。如果我们不除以规格化器,我们将得到以下等式:

注意,prior 和 scaler 的乘积等于一个联合概率。因为其中一个术语是 P(证据),联合概率会受到证据稀有性的影响。

这是有问题的,因为联合概率是一个考虑了世界上所有状态的值。但是我们不关心所有的州——我们只关心证据出现的州。换句话说,我们生活在一个证据已经发生的世界,我们证据的丰富或稀缺不再相关(所以我们根本不希望它影响我们的计算)。将 prior 和 scaler 的乘积除以 P(Evidence)使其从联合概率变为条件概率——条件概率是只考虑证据发生的世界状态的概率,这正是我们所希望的。

编辑:考虑为什么我们用规格化器除定标器的另一种方式是,它们回答了两个不同的重要问题——它们的比值以一种有用的方式组合了信息。让我们用我关于朴素贝叶斯的新帖中的一个例子。比方说,我们试图根据单一特征敏捷性来判断被观察的动物是否是猫。我们只知道这种动物很敏捷。

  1. 标度告诉我们猫敏捷的比例——这应该很高,比如说 0.90。
  2. 标准化器告诉我们总体上有多少比例的动物是敏捷的——这应该是中等的,比如 0.50。
  3. 比率 0.90/0.50 = 1.8 告诉我们扩大我们的先验——它说无论你以前相信什么,现在是时候修改它了,因为看起来你可能在和一只猫打交道。之所以这么说,是因为我们观察到一些证据表明这种动物很敏捷。然后我们发现猫的敏捷比例大于所有动物的敏捷比例。鉴于我们目前只知道这一条证据,其他一无所知,合理的做法是修正我们的信念,即我们正在与一只猫打交道。

把所有的放在一起

现在我们知道了如何考虑公式的各个部分,让我们最后一次从头到尾回顾一下我们的例子:

  • 面试结束后,我们从先前开始——有 20%的机会你会得到你刚刚面试的工作。
  • 随着时间的推移,我们使用缩放器来缩小我们的先验。例如,三天过去了,我们估计在你得到这份工作的世界里,只有 40%的机会公司会等这么久才给你打电话。将 scaler 和 prior 相乘,我们得到 20% * 40% = 8%。
  • 最后,我们认识到 8%是对世界上所有国家进行计算的。但是我们只关心你面试后 3 天没有接到公司电话的情况。为了只捕捉这些状态,我们估计 3 天没有接到电话的无条件概率为 90% —这是我们的标准。我们将之前计算的 8%除以规格化器,8% / 90% = 8.9%,得到最终答案。因此,在世界上那些你已经三天没有收到公司回复的州,你有 8.9%的几率会收到一份工作邀请。

希望这是有帮助的,干杯!

更多数据科学与分析相关帖子由我:

数据科学家是做什么的?

数据科学家面临自动化的风险吗

二项分布

了解 PCA

维度的诅咒

理解神经网络

理解伯努利分布和二项式分布

原文:https://towardsdatascience.com/understanding-bernoulli-and-binomial-distributions-a1eef4e0da8f?source=collection_archive---------2-----------------------

每当你处理随机变量时,识别与它们相关的概率函数是很重要的。后者是一个函数,它给随机变量 X 的每个可能结果分配一个 0 到 1 之间的数。这个数字是与结果相关的概率,它描述了结果发生的可能性。

在离散随机变量中(也就是说,随机变量的支持是可计数的值),可能最重要的概率分布是伯努利分布和二项式分布。

在这篇文章中,我将通过证据和例子来解释每个分布背后的思想,它们的相关值(期望值和方差)。

二项分布

伯努利分布是随机变量的离散概率分布,采用二进制布尔输出:1 表示概率 p,0 表示概率(1-p)。这个想法是,每当你在进行一个可能导致成功或失败的实验时,你可以将你的成功(标为 1)与概率 p 联系起来,而你的不成功(标为 0)将具有概率(1-p)。

与伯努利变量相关的概率函数如下:

成功概率 p 是伯努利分布的参数,如果离散随机变量 X 遵循该分布,我们写为:

想象一下,你的实验由抛硬币组成,如果输出是尾巴,你就赢了。再者,既然硬币是公平的,你就知道有尾巴的概率是 p=1/2。因此,一旦设置 tail=1,head=0,就可以按如下方式计算成功的概率:

再一次,假设你要掷骰子,你把钱押在数字 1 上:因此,数字 1 将是你的成功(标为 1),而任何其他数字都将是失败的(标为 0)。成功的概率是 1/6。如果你想计算失败的概率,你会这样做:

最后,让我们计算期望值(EV)和方差。已知离散随机变量的 EV 和 V 由下式给出:

接下来,对于伯努利随机变量 X :

现在,伯努利分布背后的想法是,实验只重复一次。但是如果我们运行不止一个试验,假设试验是相互独立的,会发生什么呢?

二项分布

这个问题的答案是二项分布。这个分布描述了 n 个随机实验的输出行为,每个实验都有一个概率为 p 的伯努利分布。

让我们回忆一下之前抛公平硬币的例子。我们说过我们的实验包括抛一次硬币。现在让我们稍微修改一下,假设我们将掷硬币 5 次。在这些试验中,我们会有一些成功(尾部,标为 1)和一些失败(头部,标为 0)。每次试验都有 1/2 的成功概率和 1/2 的失败概率。我们可能有兴趣知道获得给定数量的成功的概率是多少。我们将如何进行?

让我们想象一下这个实验:

所以我们掷了 5 次硬币,前 3 次我们输了,后 2 次我们赢了。既然我们说成功=尾部=1,失败=头部=0,我们可以重新架构如下:

现在,每个试验都是一个伯努利随机变量,因此如果它等于 1,它的发生概率就是 p,否则就是 0。因此,如果我们想计算发生上述情况(3 次失败和 2 次成功)的概率事前,我们会得到这样的结果:

由于试验是相互独立的:

概括这一推理,如果我们已经进行了 n 次试验并取得了 x 次成功:

现在需要引入一个进一步的概念。实际上,到目前为止,我们已经计算了按照上面显示的顺序成功两次的概率。然而,由于我们对给定数量的成功感兴趣,而不考虑它们给我们的顺序,我们需要考虑所有可能的 x 次成功的组合。

也就是说,假设我们掷硬币三次,我们想计算三次试验中有一次出现尾巴的概率。因此,我们将在以下情况中胜出:

如你所见,有三种不同的结果组合会导致成功。我们如何将这一概念纳入我们的概率函数?答案是二项式系数,由下式给出:

其中 n 是试验的次数,而 x 是我们想要知道发生概率的成功次数。

因此,当我们运行 n 个独立实验时,每个实验都有一个参数为 p、的伯努利分布,我们想知道有 x 个成功的概率,概率函数将是:

这样一个随机变量是这样表达的:

现在让我们计算 EV 和 v,首先回想一下,对于二项式定理:

因此:

注意,如果二项式分布的 n=1(只进行试验),那么它就变成了一个简单的伯努利分布。此外,二项式分布也很重要,因为如果 n 趋于无穷大,并且 p 和(1-p)都不是无限小的,那么它很接近高斯分布。因此,后者是二项分布的一种极限形式。

您可以很容易地将其形象化,如下所示:

正如你所看到的,试验次数 n 越高,我们的二项随机变量的形状就越能回忆起众所周知的高斯分布的钟形曲线。

如果你对伯努利分布和二项式分布的所谓“对应物”感兴趣,它们是几何和逆二项式分布,请查看我的下一篇文章这里

理解 BERT:它是 NLP 中的游戏改变者吗?

原文:https://towardsdatascience.com/understanding-bert-is-it-a-game-changer-in-nlp-7cca943cf3ad?source=collection_archive---------1-----------------------

自然语言处理领域最具突破性的发展之一是由伯特的发布(被认为是自然语言处理的 ImageNet 时刻),这是一个革命性的自然语言处理模型,与传统的自然语言处理模型相比是最棒的。它还启发了许多最近的 NLP 架构、训练方法和语言模型,如 Google 的 TransformerXL、OpenAI 的 GPT-2、ERNIE2.0、XLNet、RoBERTa 等。

让我们深入了解 BERT 及其转变 NLP 的潜力。

伯特是什么?

BERT(来自变压器的双向编码器表示)是谷歌的研究人员在 2018 年开发的开源 NLP 预训练模型。作为 GPT(广义语言模型)的直接后裔,BERT 在 NLP 中的表现超过了几个模型,并在问答(SQuAD v1.1)、自然语言推理(MNLI)和其他框架中提供了顶级结果。

它建立在预训练上下文表示的基础上,包括半监督序列学习(由 Andrew Dai 和 Quoc Le 完成)ELMo(由 Matthew Peters 和来自和 CSE 的研究人员完成)ULMFiT(由 fast.ai 创始人和 Sebastian Ruder 完成)OpenAI Transformer(由 open ai 研究人员、Narasimhan、Salimans 和 Sutskever 完成)以及 Transformer ( Vaswani

它与其他模型的独特之处在于,它是第一个深度双向、无监督的语言表示,仅使用纯文本语料库进行预训练。由于它是开源的,任何具有机器学习知识的人都可以很容易地建立 NLP 模型,而不需要为训练模型寻找大量数据集,从而节省时间、精力、知识和资源。

最后,BERT 在一个大型未标记文本语料库上接受预训练,其中包括整个维基百科(大约 25 亿字)和一本书语料库(8 亿字)。

它是如何工作的?

传统的上下文无关模型(如 word2vec 或 GloVe)为词汇表中的每个单词生成单个单词嵌入表示,这意味着单词“右”在“我确定我是对的”和“向右转”中将具有相同的上下文无关表示。“然而,BERT 将基于上一个和下一个上下文进行表示,使其成为双向的。虽然双向的概念已经存在很长时间了,但 BERT 是第一个在深度神经网络中成功预训练双向的。

他们是如何做到这一点的?

Source: BERT [Devlin et al., 2018]

他们使用两种策略——屏蔽语言模型(MLM)——通过屏蔽掉输入中的一些单词,然后双向调节每个单词来预测被屏蔽的单词。在将单词序列输入 BERT 之前,每个序列中 15%的单词被替换为一个[MASK]标记。然后,该模型尝试根据序列中其他未屏蔽单词提供的上下文来预测屏蔽单词的原始值。

第二种技术是下一个句子预测(NSP) ,在这里 BERT 学习对句子之间的关系进行建模。在训练过程中,模型接收句子对作为输入,并学习预测句子对中的第二个句子是否是原始文档中的后续句子。让我们考虑两个句子 A 和 B,B 是语料库中 A 后面的实际下一个句子,还是只是一个随机的句子?例如:

当训练 BERT 模型时,两种技术被一起训练,从而最小化两种策略的组合损失函数。

架构

BERT is deeply bidirectional, OpenAI GPT is unidirectional, and ELMo is shallowly bidirectional. Image Source: Google AI Blog

BERT 架构建立在 Transformer 之上。有两种变型可供选择:

伯特基础:12 层(变压器块),12 个注意头,和 1.1 亿个参数

BERT Large: 24 层(变压器块),16 个注意头,3.4 亿个参数

结果

SQuAD v1.1 上,BERT 获得了 93.2%的 F1 分数(一种准确性衡量标准),超过了之前 91.6%的最高分数和 91.2%的人类水平分数:在极具挑战性的 GLUE benchmark(一组 9 个不同的自然语言理解(NLU)任务)上,BERT 还将最高分数提高了 7.6%。

伯特来了——但他准备好面对现实世界了吗?

BERT 无疑是机器学习用于自然语言处理的一个里程碑。但是我们需要反思如何在各种 NLP 场景中使用 BERT。

文本分类是自然语言处理的主要应用之一。例如,该概念已在票证工具中使用,以根据简短描述/电子邮件对票证进行分类,并将票证分类/发送给正确的团队进行解决。同样,它也可以用于分类电子邮件是否是垃圾邮件。

你可以在日常生活中找到它的一些应用。

Gmail’s Suggested Replies, Smart Compose & Google Search Autocomplete

聊天机器人凭借其回答用户查询和处理各种任务的能力,正在颠覆信息产业。然而,最大的限制之一是意图识别和从句子中捕获实体。

问答模型是自然语言处理的基本系统之一。在 QnA 中,基于机器学习的系统从知识库或文本段落中为作为输入提出的问题生成答案。BERT 可以用在聊天机器人中吗?当然可以。BERT 现在被用在许多对话式人工智能应用中。所以,你的聊天机器人应该变得更聪明。

然而,BERT 只能用于回答非常短的段落中的问题,并且需要解决许多关键问题。作为一项常规任务,NLP 太复杂了,有更多的含义和微妙之处。BERT 只解决了一部分问题,但肯定会很快改变实体识别模型。

今天的伯特只能解决有限的一类问题。然而,还有许多其他任务,如情感检测,分类,机器翻译,命名实体识别,摘要和问题回答需要建立。现在一个常见的批评是,这种任务是基于对表示的操纵,没有任何理解,添加简单的对抗性内容来修改原始内容会使其混淆。

只有在运营中得到更广泛的采用,现场场景得到改善,从而支持跨组织和用户的广泛应用时,才能实现 BERT 在 NLP 中的真正优势。

然而,随着一波基于变压器的方法(GPT-2,罗伯塔,XLNet)的出现,事情正在迅速变化,这些方法通过展示更好的性能或更容易的训练或其他一些特定的好处来不断提高标准。

让我们看看在伯特的介绍之后出现的其他一些发展

罗伯塔

RoBERTa 由脸书开发,基于 BERT 的语言掩蔽策略,并修改了 BERT 中的一些关键超参数。为了改进训练过程,RoBERTa 从 BERT 的预训练中移除了下一句预测(NSP)任务,并引入了动态屏蔽,使得屏蔽的令牌在训练时期期间改变。它还在比 BERT 多一个数量级的数据上接受了更长时间的训练。

蒸馏酒

由 HuggingFace 开发的 DistilBERT 学习了 BERT 的一个蒸馏(近似)版本,在 GLUE 上保留了 95%的性能,但只使用了一半数量的参数(只有 6600 万个参数,而不是 1.1 亿个)。这个概念是,一旦一个大的神经网络被训练,它的全部输出分布可以用一个较小的网络来近似(像后验近似)。

XLM/姆伯特

由脸书开发的 XLM 使用已知的预处理技术(BPE)和双语言训练机制与 BERT 一起学习不同语言中单词之间的关系。在多语言分类任务中,该模型优于其他模型,并且当预训练的模型用于翻译模型的初始化时,显著提高了机器翻译。

艾伯特

由谷歌研究院和丰田技术研究所联合开发的 ALBERT(一个用于自我监督语言表示学习的 Lite BERT)将成为 BERT 的继任者,它比 BERT 小得多,轻得多,也更智能。两个关键的架构变化使得 ALBERT 不仅表现出色,而且显著减小了模型的大小。第一个是参数的数量。它通过跨所有层共享所有参数来提高参数效率。这意味着前馈网络参数和注意力参数都是共享的。

研究人员还从词汇嵌入的大小中分离出隐藏层的大小。这是通过将一个热点向量投影到低维嵌入空间,然后投影到隐藏空间来实现的,这使得在不显著增加词汇嵌入的参数大小的情况下增加隐藏层大小变得更加容易。

谈到预训练,艾伯特有自己的训练方法,叫做句序预测(SOP) ,与 NSP 相反。作者提出的 NSP 理论的问题是,它将主题预测与连贯性预测混为一谈。

ALBERT 代表了 NLP 在几个基准上的新水平,以及参数效率的新水平。这是一个惊人的突破,它建立在 BERT 一年前所做的伟大工作的基础上,并在多个方面推进了 NLP。

伯特和像它这样的模型肯定是 NLP 的游戏规则改变者。机器现在可以更好地理解语音,并实时做出智能响应。许多基于 BERT 的模型正在开发中,包括 VideoBERT、ViLBERT(视觉和语言 BERT)、PatentBERT、DocBERT 等。

你对 NLP 和 BERT 的状态有什么看法?

理解偏差和方差

原文:https://towardsdatascience.com/understanding-bias-and-variance-25b079e6b44b?source=collection_archive---------30-----------------------

用一点插图和一点代码简化这些概念

任何学习数据科学 101 课程的人都会遇到这些定义机器学习模型准确性的术语偏差和方差。我发现它周围的一些材料令人困惑,所以我想我会尝试用一些插图和代码来解释。

在我开始写代码之前,基本上偏差只不过是应用于不同测试数据集时模型中的预期误差(误差的平均值)。让我用飞镖靶来类比。圆圈中的数字代表误差,直到圆圈的圆周处。

Board A

在电路板 A 中,平均误差或偏置等于(0 + 0 + 0 + 1 + 2) / 5 = 0.6

Board B

尽管电路板 B 看起来与电路板 A 不同,但它具有相同的平均误差或偏差= (0 + 0 + 1 + 1 + 1) / 5= 0.6

现在的问题是你会赌哪个飞镖手?一个使用板 A 或板 b,这就是差异的来源。

方差是应用于不同测试数据点时误差的方差。现在让我们分别用 A 板和 B 板试着把这个概念应用到两个投掷飞镖的人身上。

棋盘 A 的方差= (0 + 0 + 0 + 1 + 2 ) / 5 = 1.0

棋盘 B 的方差= (0 + 0 + 1 + 1 + 1 ) / 5 = 0.6

这表明,虽然板 A 飞镖投掷者击中靶心的次数比板 B 飞镖投掷者多 50%,但当他不正确时,他更加不稳定。另一方面,B 板飞镖手稳稳的,总是在靶心标上或靶心标周围盘旋。在机器学习模型的世界中,通常类似于棋盘 B 飞镖投掷者的模型是优选的,因为它避免了令人尴尬的错误并且更加稳定。

事实证明,类似于棋盘 B 的行为发生在过度拟合的机器学习模型中(相对于训练集过度拟合),即,即使模型的偏差较低,方差也会较高。因此,差异越大,你就越担心把它推向生产,因为一旦出了问题,它会变得非常糟糕。

在一个没有过度拟合(可能是正则化)的模型中,方差将会很低——这意味着在测试集上遇到的错误不会是荒谬的。

我已经通过将线性和三次回归应用于具有随机扰动的线性数据集说明了这一点。

Universe of data points

Points sampled for training

Cubic regression

Linear Regression

浏览下面的代码(希望是不言自明的)将帮助您看到,尽管三次和线性回归的平均误差(偏差)有些相似(类似于我们的飞镖游戏),但是三次回归的方差太高,这使它类似于 a 板上出色但不稳定的飞镖游戏。

在这种情况下,这意味着数据科学家应该选择线性回归模型来推广到生产中。

总之,作为数据科学家,重要的是不要看平均误差(偏差),还要注意方差。方差越大,意味着虽然有些情况下模型是超级准确的,但也有一些情况下模型会出现严重错误,这是您希望避免的。

在 3 分钟内了解偏差-方差权衡

原文:https://towardsdatascience.com/understanding-bias-variance-trade-off-in-3-minutes-c516cb013513?source=collection_archive---------29-----------------------

机器学习照明讲座—2019 年 10 月 11 日

Balancing them is like magic

躲在付费墙后面?点击这里阅读完整的故事与我的朋友链接。

偏差方差是在训练机器学习模型时要调整的核心参数

当我们讨论预测模型时,预测误差可以分解成两个主要的子分量:由于偏差、造成的误差和由于方差造成的误差。

偏差-方差权衡偏差引入的误差和方差产生的误差之间的张力。为了理解如何最大限度地利用这种权衡,并避免我们的模型过拟合或欠拟合,让我们首先学习偏差方差。

偏差引起的误差

由于 偏差 产生的误差是模型的预测值 和真实值 的 之间的距离。在这种类型的错误中,模型很少关注训练数据,并且 过度简化 模型,并且不学习模式。模型通过不考虑所有特征来学习错误的关系****

由于差异导致的误差

给定数据点或数值的模型预测可变性 告诉我们数据的分布 。在这种类型的错误中,模型在训练数据 中花费了 l ot 的注意力,以至于记住它而不是从中学习。方差误差较大的模型不能灵活地对以前没有见过的数据进行归纳。

如果偏见和差异是阅读的行为,那就像略读课文和记忆课文一样

我们希望我们的机器模型从它接触到的数据中学习,而不是“知道它是关于什么的”一个字一个字地记住它。

偏差—方差权衡

偏差-方差权衡是关于平衡,而 是关于在偏差引起的误差和方差引起的误差之间找到最佳平衡点** 。

这是一个适配不足和适配过度的两难选择

Plot by Jake VanderPla

如果模型用灰色线表示,我们可以看到高偏差模型是一个过度简化数据的模型,而高方差模型是一个过于复杂而过度拟合数据的模型。

简而言之:

  • 偏差是模型做出的简化假设,使目标函数更容易逼近。
  • 方差是在给定不同训练数据的情况下,目标函数的估计将改变的量。
  • 偏差-方差权衡是我们的机器模型在偏差和方差引入的误差之间执行的最佳点。

在本帖中,我们讨论了 c 偏差和方差的概念含义 。接下来,我们将探讨 代码中的概念。

未来阅读:

理解偏差-方差权衡 斯科特·福特曼-罗著

《统计学习的要素》 作者:特雷弗·哈斯蒂、罗伯特·蒂布拉尼和杰罗姆·弗里德曼

理解二进制数据

原文:https://towardsdatascience.com/understanding-binary-data-fc4c78c9e677?source=collection_archive---------6-----------------------

让我们说些咒语。

“You get used to it, I don’t even see the code, All I see is blond, brunette, redhead”

在这篇文章中,我解释了真实存在于我们电脑中的数据。如果你想知道 1 和 0 的序列是如何产生有意义的信息的,这篇文章就是为你准备的。

比特和字节

计算机中的所有数据都表示为一系列 1 和 0。取决于数据存储的位置—内存、固态硬盘、硬盘、DVD 等。—1 和 0 的物理编码不同,但从概念上讲,它们是两种不同的状态——这就是全部。

Hard drives and computer memory just stores ones and zeros. Photo by Patrick Lindenberg on Unsplash

一个这样的数据片段——0 或 1——被称为 。八位组成一个 字节 。字节作为一个单元是相关的,因为——一般来说——它们是最小的可寻址内存单元。

假设你有 40 位数据,那么 5 个字节:

01001000``01100101 01101100``01101100

您可以通过指定从起始点的偏移量来请求读取或写入其中一个字节的数据。你总是一次读或写一个完整的字节,而不是单个的位。因此,除了压缩机制之外,大多数信息都是以字节为基本单位进行编码的,而不是以比特为单位。

顺便说一句,在文章的最后你将能够回到上面的 40 位,并弄清楚它们的意思。当你到了那里,试着回来看看。你会想出办法的。我保证。

为什么一个字节是 8 位,而不是 10 位?

历史和现实的原因交织在一起。

我会试着暗示潜在的实际问题。让我们后退一步:对我们来说,乘以或除以 10 的幂是微不足道的,只需添加零或移动小数点,对吗?

3.1415 ✕ 100 = 314.15

这在我们的十进制系统中是正确的——一个基于 10 的幂的数字系统。

计算机内部做二进制运算。二进制算术以 2 的幂为基础。在二进制算术中,像 8 = 2 这样的 2 的幂同样方便。

让我们看一个二进制算术的例子:

13 ✕ 8 = 104对应00001101 ✕ 1000 = 01101000

它只是将输入向左移动三位。先不要试图理解编码。只要注意到结果是通过将数字向左移动而简单地计算出来的。

总之:如果数据单元的大小是 2 的幂,比如 8 = 2,那么计算机需要做的许多内部计算就比其他情况简单得多。

一千字节有多少字节?

好问题。没有关于千字节、兆字节、千兆字节等的官方标准。直到 1998 年。然而,这些设备在技术人员和消费者中被广泛使用。你买了一个硬盘,它的大小以千兆字节为单位。

技术人员正在计算 2 ⁰ =每千字节 1024 字节,每兆字节 1024 千字节,每千兆字节 1024 兆字节,等等。正如我们所了解的,当你使用计算机内存时,2 的幂是很实用的。

众所周知,销售硬盘的营销人员有一个巧妙的想法,即缺乏官方标准,他们可以声称“他们的”单位是基于 1000,因此“他们的”千兆字节是 1000 = 1,000,000,000 字节——而不是 1024 = 1,073,741,824,这样他们就可以在空间上少给你一笔钱。驱动力越大,差异越大。

您购买了 500GB 的硬盘,并一直想知道为什么您的计算机一直声称它只有 465.66 GB。

嗯,标准化最终于 1998 年发生。可惜的是,企业贪婪成为了官方标准,原来基于 2 ⁰=1024 的单位变成了‘bi’单位: kibibytes,mebibytes,gibibytes 等。更糟糕的是,通常的缩写形式,KB,MB,GB 等。也被吸引住了。最初的 base-2 单位现在是 KiB、MiB 和 GiB。

It’s kibibytes, not kilobytes. You’re a professional. Sound like a Teletubbie!

在学术界之外,大多数技术人员仍然认为一千字节是 1024 字节。软件世界分裂了,一些公司开始采用这个“标准”,一些没有。有些让你选择。

For me, kilobytes will also always have 1024 bytes. Byte me!

但是我跑题了。

剖析一个字节

让我们来看一个样本字节值:01101101

大声读出该值,并根据记忆重复一遍。不太容易,是吧?

当与人类交流二进制数据时,1 和 0 的效率非常低。让我们将一个字节值分成两组,每组 4 位——这些组被称为半字节——并为一个半字节可以采用的所有位模式分配一个符号。

我们可以开始使用符号来代替位模式。我们的字节值01101101变成了6D

这被称为十六进制记法,简称 hex,因为有 16 种不同的符号。此外,由于十进制数可能会产生歧义,因此十六进制值通常会以 0x 作为前缀来消除这种歧义。所以我们在看0x6D

这还不是一种解释,只是一种更简洁的方式来书写和表达价值。

解释二进制数据

无论 1 和 0 代表什么,都完全取决于上下文。

“那么 0x6D 的信息量是多少呢?”

“这是一种 1 和 0 的模式”

“是啊,但这意味着什么?”

“这只是 1 和 0”

“我明白了”

如果您将 0x6D 解释为一个 ASCII 字符,它将是m。如果你把它解释为一个二进制补码数,那么它就是 T1。如果你要把它解释成一个有三个小数的定点数,那就是13.625

当给定一段二进制数据时,通常必须给出上下文才能理解它。对于文本文件来说,它是编码,目前主要是UTF-8——一种兼容 ASCII 的文本字符编码。对于其他类型的文件,比如说 PNG 文件,你必须在相应的文件格式规范中查找数据的含义。

二进制整数

一个字节(或一个字节序列)的第一种和默认解释是正整数。在解释字节值时,文档通常暗示您知道如何将字节作为整数读取。

来自 PNG 文件格式规范:

" PNG 数据流的前八个字节总是包含下列(十进制)值:

137 80 78 71 13 10 26 10"

那么…这些十进制值的位模式是什么?暂时还是坚持我们的0x6D值吧。我们会找到答案的。十六进制值0x6D就是数字109,但是我怎么知道这个呢?

我们习惯于十进制系统。但是选择10作为基数和0–9作为数字是完全任意的。

我们只是手上有 10 个手指的动物,这使得数量在计算时既熟悉又方便——比如牲畜或大米袋。数字 10 本身并不特别,只是对我们人类来说很实用。

十进制系统

当我们写下数字时,我们写下一个范围在0-9内的数字,代表我们的基数10的每个幂,从右边的 10⁰开始。我们在左边增加了 10 的额外幂的数字,只要我们需要它们来表达我们的数字。

numbers in the decimal system

八进制系统

我们可以用更小的基数8来代替使用数字0–7。它被称为八进制系统。这不是一个完全虚构的例子。其实是用过的。也许你已经在 Linux 系统上的文件权限的上下文中见过了。正如十六进制数通常以 0x 为前缀以消除歧义一样,八进制数通常以 0 为前缀。

numbers in the octal system

十六进制系统

所以我们把基数从 10 降到了 8。我们也可以上去,去说基地16。不过,我们会在数字上遇到麻烦。

我们需要0–15和过去 9 的数字,我们没有既定的惯例。让我们使用十六进制数字:A=10, B=11, C=12, D=13, E=14, F=15

numbers in the hexadecimal system

二进制

只要我们手头有商定的数字,基数的选择完全是任意的。让我们完全简化,使用基数2,数字0–1

numbers in the binary system

整数摘要

现在你可以看到011011010x6D109 are对同一个整数的不同表示法。现在看一下像这样的 ASCII 表应该就明白了,它们是用各种格式索引的。这只是一种礼貌,所以你可以在手边的任何系统中使用索引来查找这个字符。

二进制文本

打开一个文本编辑编辑器,创建一个新文件,把“Hello World”放进去,保存为一个简单的文本文件。

现在得到一个十六进制编辑器。十六进制编辑器只是一个文件编辑器,它不会为您解释文件的内容——它只是向您显示原始的二进制内容。任何基本的免费十六进制编辑器都可以。你也可以使用在线十六进制编辑器

在十六进制编辑器中打开文本文件。它会显示文件的二进制内容。它应该看起来像这样。

binary contents of a simple text file

十六进制编辑器通常显示三列:从文件开始的偏移量(通常是十六进制)、文件的二进制内容(也是十六进制),第三列显示被解释为 ASCII 字符的文件字节。

如果您的文件内容在开头有一些额外的字节,很可能您的文本编辑器在您的文件中保存了一个 BOM 。别担心。

还记得我们之前的 40 比特吗?你现在知道了你需要弄清楚它说什么的一切。

01001000``01100101 01101100``01101100

更深入

我们已经有了基本的东西。以下每个主题都值得写一篇自己的文章。但是我们已经在空间、时间和读者的注意力上捉襟见肘了,所以我把你引向稍后阅读的资源。

我知道你还有疑问!🤓

固有整数

到目前为止,我们只讨论了正整数,一次只讨论一个字节。但是…

“编码大于 255 的整数怎么样?一个字节中没有足够的位来存储更高的值。而负数呢?”

好问题。您使用固定长度的连续字节—通常是 2 字节、4 字节和 8 字节—这扩展了 2 的幂。对有符号整数使用二进制补码编码。

大多数非玩具计算器带有正常的、科学的和程序员的观点。在研究这些东西时,打开计算器上的“程序员视角”。

A “Programmer” view of your system calculator probably supports hex and binary views

一旦你开始使用不止一个字节来表示一个值,字节序就变得很重要,尤其是从文件或网络中读取字节时,所以要记住这一点。

分数

到目前为止,我们只讨论了整数。关于:

π=3.1415926535…

有一个标准化的,硬件支持浮点小数的表示。最常用的版本是 4 字节单精度,通常称为'浮点型',以及 8 字节版本,通常称为'双精度型'。

The interpretation of bits in a 4 byte a float

大致思路如下:

符号存储在最左边的位。0 代表正数,1 表示负数。我们的示例编号是正数。

红色阴影表示一个分数,即1加上所选的负 2 次方的和——如二分之一、四分之一、八分之一等。…在上面的示例中,我们仅在四分之一位置设置了一个位。所以分数是1.25

请注意,分数将始终介于1.02.0之间。

在下一步中,您将计算由绿色阴影部分给出的指数。我们的指数是124。标准要求我们将分数乘以2^(exp-127),所以在我们的例子中,我们乘以2^-3 = 1/8

最后,我们的位模式编码的数字是:

1.25 × 1/8 = 0,15625

您可能想知道如何使用这种编码有效地将十进制数转换为浮点数。在实践中,您永远不需要手动操作,生态系统——就像您的编程语言标准库——会为您处理好。

哦,关于π,试着解释一下这个模式:

0 10000000 10010010000111111011011

你可能也想知道对小数的近似有多精确,现在我们用的是 1/2 而不是 1/10。很多人做,连做的那帮家伙都比优秀。

结论

我们的数据只是 1 和 0。它被分组和解释的方式使它有意义。在这种情况下,如果您曾经被要求处理二进制数据,您现在应该有足够的信息来正确理解它所附带的文档。

为了测试你的理解,试着看一下形状文件格式规范,看看它是否有意义。

Photo by Scott Blake on Unsplash

理解碧溪通勤者:用 Python 分析蒙特利尔的自行车共享系统

原文:https://towardsdatascience.com/understanding-bixi-commuters-an-analysis-of-montreals-bike-share-system-in-python-cb34de0e2304?source=collection_archive---------20-----------------------

蒙特利尔的自行车共享系统 BIXI 于 2009 年问世。当时,这是自行车共享系统的早期尝试之一。它的模型后来被出口到世界其他城市,如纽约和伦敦。作为一名蒙特利尔人、自行车爱好者和软件工程学生,我很好奇去探索其公开可用的数据,所以我下载了【2018 年以来的 530 万次 BIXI 旅行。

通过此分析,您将了解蒙特利尔人何时何地使用碧溪自行车,气温等因素如何影响骑行量,以及骑行量在社区内和社区间如何变化。在接下来的部分中,我将更详细地介绍这些见解和代码(可在 GitHub 上获得):

  1. 数据
  2. 乘客偷看,想象全天的交通流量
  3. 高峰时段通勤者的空间进出流量
  4. 预测骑行习惯和温度之间的关系
  5. 数据的聚类和图形分析

数据

BIXI 提供的两个数据集:

车站:

  • 密码
  • 名字
  • 纬度
  • 经度

旅行:

  • 开始日期
  • 起点站代码
  • 结束日期
  • 终点站代码
  • 持续时间秒
  • 是成员

我开始使用 2019 年 5 月的数据进行分析,以评估全天的客流量和地点(第 2 节和第 3 节)。然后使用 2018 年全年的数据将乘客量与温度相关联,并根据我需要的更多粒度形成聚类(第 4 和第 5 节)。

在清理数据时,持续时间不到 2 分钟的行程被删除,因为任何人都很难在这么短的时间内到达另一个站点。

每个月的数据发布在不同的 csv 文件中,但是可以使用 Pandas(一个用于数据操作的 python 库)轻松合并这些数据。它预装了 Anaconda。Pandas 也在整个项目中使用,因为它使操作数据成为一个用户友好的过程。代码读取并合并 2018 年与熊猫的所有数据。

import pandas as pd#read CSV file
def read_trips():

 data_files = glob.glob(‘data2018/OD_2018-*.csv’)
 li = []
 for filename in data_files:
 df = pd.read_csv(filename, index_col=None, header=0)
 li.append(df)

 #convert argument to datetime
 data = pd.concat(li, axis=0, ignore_index=True)
 data[‘start_date’] = pd.to_datetime(data[‘start_date’], format=’%Y-%m-%d’, errors=’coerce’)
 data[‘end_date’] = pd.to_datetime(data[‘end_date’], format=’%Y-%m-%d’, errors=’coerce’)

 #filtering out trips that were less than 2 min
 data = data.drop(data[data[‘duration_sec’] < 120].index)

 #adding a day number column to identify days of the week
 data[‘day_number’] =   pd.to_datetime(data[‘start_date’]).dt.dayofweek
 data = data.drop(data[data[‘day_number’].isin([5, 6])].index)

 return data

可视化全天的交通状况

首先要调查的是 BIXI 用户的个人资料。通过绘制数据可以看出,该系统在一周内的使用量比周末多。此外,通过查看一周中的使用高峰(图 1),可以假设许多用户通过使用 BIXIs** 在早上 7 点到 9 点之间上下班,在下午 4 点到 6 点之间下班。在周末(图 2),分布更加平稳,用户大多在下午骑自行车,这可能表明骑自行车的人使用 BIXIs 进行休闲。**

****

通过使用 python 库 Pandas 处理数据并使用 Matplotlib 绘制数据,很容易创建这样的可视化,如下所示。

import pandas as pd
import matplotlib.pyplot as plt#creates a bar chart with the departures per hour during the week
def visualizePerHourWeek(data, column_name, color=’#0000FF’, title=’Avreage Number of Trips Per Hour During the Week — May 2019'):

 dataWeek = data.drop(data[data[‘week_day_b’] == 0].index)
 plt.figure(figsize=(20, 10))
 ax = ((dataWeek[column_name].groupby(dataWeek[column_name].dt.hour)
 .count())/23).plot(kind=”bar”, color=color)

 ax.set_xlabel('Hour')
 ax.set_ylabel('Number of Trips')
 ax.set_title(title)
 plt.rcParams.update({‘font.size’: 22})
 plt.show()

高峰时间通勤者的空间流入和流出

查看一周内每小时出行次数的条形图,通过尝试确定 BIXI 骑手在早上和晚上往返的区域来完善这一分析是很有趣的。

为此,计算了 2019 年 5 月每个车站的净流入量。出行净流入量由特定时间窗口内某个站点的进入出行量减去离开出行量确定。绿色站点有净流入量,红色站点有净流出量。圆圈的大小基于净流入或流出流量计数。

查看下图(图 3 和图 4)可以看到用户主要在一英里终点进出市区。这并不奇怪,因为这些地区有很多办公室。

Each circle is a station. Red stations have a net outflux of trips. Green stations have a net influx of trips. The size of the circle is [= (trips in — trips out)]. The analysis was performed for May 2019.

上面的可视化效果是使用 were 创建的。Folium 允许用户创建地理可视化,它可以使用 pip 安装。上面的可视化效果是使用下面的代码创建的。应当注意,传递给该功能的数据帧包含与特定时隙的每个站相关的净流入或流出流量。

import folium
def densityMap(stations):

 #generate a new map
 Montreal = [45.508154, -73.587450]
 map = folium.Map(location = Montreal,
 zoom_start = 12,
 tiles = “CartoDB positron”)

 #calculate stations radius
 stations[‘radius’] = pd.Series( index=data.index)
 stations[‘radius’] = np.abs(stations[‘net_departures’])
 stations[‘radius’] = stations[‘radius’].astype(float) #set stations color
 stations[‘color’] = ‘#E80018’ # red 
 stations.loc[stations[‘net_departures’].between(-10000,0), ‘color’] = ‘#00E85C’ # green

 lat = stations[‘latitude’].values
 lon = stations[‘longitude’].values
 name = stations[‘name’].values
 rad = stations[‘radius’].values
 color = stations[‘color’].values
 net_dep = stations[‘net_departures’]

 #populate map
 for _lat, _lon, _rad, _color, _name, _nd in zip(lat, lon, rad, color, name, net_dep):
  folium.Circle(location = [_lat,_lon], 
  radius = _rad/5,
  color = _color,
  tooltip = _name + “ / net. dep:” +str(_nd),
  fill = True).add_to(map)

 #save map
 f = ‘maps/map_density.html’
 map.save(f)

骑车习惯与温度的相关性

现在已经确定骑自行车的人使用 BIXI 上下班,让我们看看其他的预测因素。蒙特利尔是一个温度变化很大的城市,夏天很容易达到 30 摄氏度,冬天则低至零下 30 摄氏度。来自碧溪的自行车在 11 月从街上拿走,然后在 4 月被带回来。值得一问的是,温度在多大程度上预测了网络的使用情况。

Each dot is the count of trips on a given day in 2018

从上面的图中可以看出,随着气温变暖,日客流量增加,预计出行次数在 0 到 20 摄氏度之间增加了两倍,从 10,000 次增加到 30,000 次。可以认为,三次多项式回归提供了这种情况下的最佳拟合,因为人们会预计,随着温度接近冰点,日客流量将保持较低水平。当气温变暖时,日客流量会迅速增加,但当天气太热时,客流量会停滞甚至下降。从图上看,每天的旅行次数似乎在 22 摄氏度左右开始减少。这种减少也可能是因为人们在炎热的月份里度假。

从 R 平方得分可以看出,70%的可变性是用三阶多项式回归的温度来解释的,其他要考虑的因素可能是周末与一周。我也尝试过关联离地铁站的距离,但结果并不确定。

Variance r2 score linear: 0.63
Variance r2 score poly2: 0.65
Variance r2 score poly3: 0.70

可以使用库 Sklearn 在 python 中执行回归。用于该分析的日平均温度来自加拿大政府的公开的数据集。下面是用来执行这个线性回归的代码。

import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import r2_scoredef scatterPlot(dataDay):

 X = dataDay[[‘Mean Temp (°C)’]].values
 X_1 = dataDay[[‘Mean Temp (°C)’]].values
 X_2 = dataDay[[‘Mean Temp (°C)’]].values
 X_3 = dataDay[[‘Mean Temp (°C)’]].values
 Y = dataDay[[‘departures_cnt’]].values

 #Linear regression
 linear_regressor = LinearRegression()
 linear_regressor.fit(X, Y)
 Y_pred_linear = linear_regressor.predict(X)
 print(‘Variance score linear: %.2f’ % r2_score(Y, Y_pred_linear))

 #polynmial degree 2 regression
 polynomial_feat = PolynomialFeatures(degree=2)
 x_poly_2 = polynomial_feat.fit_transform(X)
 polynomial_regressor = LinearRegression()
 polynomial_regressor.fit(x_poly_2, Y)

 Y_pred_poly_2 = polynomial_regressor.predict(x_poly_2)
 print(‘Variance score poly2: %.2f’ % r2_score(Y, Y_pred_poly_2))

 #polynmial degree 3 regression
 polynomial_feat_3 = PolynomialFeatures(degree=3)
 x_poly_3 = polynomial_feat_3.fit_transform(X)
 polynomial_regressor_3 = LinearRegression()
 polynomial_regressor_3.fit(x_poly_3, Y)

 Y_pred_poly_3 = polynomial_regressor_3.predict(x_poly_3)
 print(‘Variance score poly3: %.2f’ % r2_score(Y, Y_pred_poly_3))#Ploting the data
 plt.figure(figsize=(20, 10))
 plt.title(‘Daily Bike Ridership With Regards to Temperature’)
 plt.scatter(X_1,Y,c=’blue’,marker=’o’)
 plt.xlabel(‘Mean Temperature (°C)’)
 plt.ylabel(‘Number of Daily Trips’)
 plt.plot(X_1, Y_pred_linear, color=’red’)

 sort_axis = operator.itemgetter(0)
 sorted_zip = sorted(zip(X_2,Y_pred_poly_2), key=sort_axis)
 X_2, Y_pred_poly_2 = zip(*sorted_zip)
 plt.plot(X_2, Y_pred_poly_2, color=’green’)

 sort_axis = operator.itemgetter(0)
 sorted_zip = sorted(zip(X_3,Y_pred_poly_3), key=sort_axis)
 X_3, Y_pred_poly_3 = zip(*sorted_zip)
 plt.plot(X_3, Y_pred_poly_3, color=’magenta’)

 plt.plot(X_1, Y_pred_linear, ‘-r’, label=’degree=1') 
 plt.plot(X_2, Y_pred_poly_2, ‘-g’, label=’degree=2') 
 plt.plot(X_3, Y_pred_poly_3, ‘-m’, label=’degree=3')
 plt.legend(loc=’upper left’)

 plt.rcParams.update({‘font.size’: 22})
 plt.show()

数据的聚类和图形分析

此分析的最后一部分是关于估计整个网络的流量。为了做到这一点,这些站点形成了光谱簇。谱聚类是一种来自图论的技术。它试图通过使用连接节点的边来识别节点组,在这种情况下是站点,在这种情况下是行程。为此,它最大限度地减少不同集群之间的出行次数,最大限度地增加集群内部的出行次数。最后,它给出了骑车人从车站骑车时所处地理区域的概念。

从下面的地图可以看出,2018 年 53%的出行发生在蓝色集群内,表明网络中的大部分交通发生在高原社区和市中心之间。此外可以看出,大多数集群由地理特征界定,这些地理特征通常是高速公路或火车轨道。例如,红色和蓝色集群之间的分裂主要发生在火车轨道上。此外,市中心区和老港口社区沿着 Ville-Marie 高速公路分为蓝色和紫色两部分。

****Each dot on the map is a station and its color identifies to cluster to which it pertains. On the graph on the right the color of the nodes identifies the cluster and the vertices identify the percentage of the traffic that occurred within or between clusters in 2018. for Instance 5.02% or the traffic occurred from a red station to a blue station in 2018. Edges representing less than 0.5% of yearly traffic have been removed.

查看下图,我们可以假设,为了促进蒙特利尔的自行车运动,该市应该投资巩固自行车爱好者已经存在的网络,在这种情况下,蓝色集群,并促进与其他集群的联系。例如,城市应该确保在蓝色集群中有安全的自行车道可用,骑车人也可以高效、安全地穿过高速公路或火车轨道,这些道路会将他们与其他相邻集群隔开。****

上面的图形分析是使用库 fleur 和库 Graphviz 中的 Diagraph 进行的。这两者都必须使用 pip 安装。地图的绘制与上面的相似。使用 Pandas 数据框,通过下面的代码可以快速生成 Graphviz。

def create_graphviz(data):
 #create the graph
 G = Digraph(format=’png’)
 G.attr(rankdir=’LR’, size=’10')
 G.attr(‘node’, shape=’circle’)
 nodelist = [] #prepare the data
 data = data.drop([‘count’], axis=1)
 data[‘from’] = pd.to_numeric(data[‘from’], downcast=’integer’)
 data[‘to’] = pd.to_numeric(data[‘to’], downcast=’integer’)
 data[‘from’] = data[‘from’].apply(str)
 data[‘to’] = data[‘to’].apply(str)
 #add the nodes and edges to the graph 
 for idx, row in data.iterrows():
  node1, node2, weight = [str(i) for i in row] if node1 not in nodelist:
   G.node(node1)
   nodelist.append(node2)
  if node2 not in nodelist:
   G.node(node2)
   nodelist.append(node2) #transform the edge label to XX,XX% format
  percent = float(weight)
  percent = percent*100
  percent = round(percent, 2)
  percent = str(percent)
  G.edge(node1,node2, label = (“”+ percent +” %”)) #show graph
 G.render(‘bixi_graph’, view=True)

结论

总之,这一探索性分析是使用 2018 年和 2019 年 5 月的 BIXI 数据进行的。人们已经看到通勤者在工作日使用碧溪上下班,周末使用碧溪休闲。此外,网络的使用受到温度的严重影响,因为天气变冷时用户会减少。此外,大部分网络用户仍然停留在市中心、高原和周边地区。这可能是因为地理障碍,如高速公路和火车轨道,使得他们很难通勤到附近的社区。

进一步的分析也有助于了解趋势和模式,例如用户在早上和晚上通勤的具体路径。这也将为自行车手对自行车道网络的需求提供深刻的见解。访问站点容量等其他数据将有助于更好地了解网络的局限性和重新平衡的需求(通过卡车将自行车运送到其他站点)。因此,描绘一幅完整的形势图,以优化蒙特利尔的 BIXI 和自行车运动。

最后,我要感谢其他开发者和作家,他们用自己的分析启发了我的工作,更具体地说是托德·w·施耐德伊登·奥乔恩·诺德比

了解加拿大的算法影响评估工具

原文:https://towardsdatascience.com/understanding-canadas-algorithmic-impact-assessment-tool-cd0d3c8cafab?source=collection_archive---------21-----------------------

这是与联邦政府做生意的必备条件

From Unsplash.

(注:我不隶属于加拿大联邦政府。我们的公司是一家 合格的 AI 厂商 ,但是我这篇文章的目标仅仅是展示如何解释和执行我认为将是任何厂商项目向前发展的强制性要求。)

随着最近新的加拿大政府的预先合格的人工智能供应商名单和关于自动决策的指令的出现,已经投入了同等的努力来刺激护栏内的创新,这似乎是一个充满政府创新的未来。

这种方法的基础是一个(某种程度上)集中的框架,它允许技术人员和非技术人员就部署的解决方案的可持续性和长期影响以及他们在各自组织中的角色进行透明的讨论。

虽然领导和执行团队的努力值得称赞,但是有可能扩展它的覆盖范围,以帮助确保高度技术性的项目的更少的长期暴露。经过一定的修改(见下文),我建议您在自己的项目中使用该工具,以帮助确保商业和生产准备就绪,无论政府是否参与。

背景

已经有一篇透彻的文章解释了算法影响评估需求背后的基本原理,所以这里是关键的要点:

  • 早在 2018 年 12 月,财政委员会秘书处更新了他们关于自动化决策的任务
  • 开发该工具是为了帮助组织“通过提供适当的治理、监督和报告以及审计要求,更好地理解和减轻与自动化决策(ADM)系统相关的风险。”(摘自超治篇)。)
  • 从 2019 年 2 月开始,有一个不言而喻的期望,即任何政府实体都将使用该工具(或其版本)来监督、控制和缓解 ADM 系统部署的潜在问题。

The website of the ADM directive as it came out in February 2019.

等等——财政委员会秘书处是做什么的?

对于加拿大以外的人来说(即使是在加拿大境内,也不直接与联邦政府打交道),国库委员会秘书处有点像一个神话人物。

The TBS website.

尽管它的主要任务是“就政府如何在项目和服务上花钱向财政部长委员会提供咨询和建议”(来自网站),但它不同于英国内阁办公室美国创新办公室。它列出了下列义务:

  • 政府开支和运作的透明度
  • 政策、标准、指令和指南
  • 开放式政府
  • 公共服务的创新
  • 公共服务的价值观和道德
  • 公共服务中的专业发展

这不同于你的标准行政部门。他们正在通过加速和简化政府职能来试验和寻找为加拿大人服务的新方法。现在不用看政治,你就能明白为什么他们非常适合在政府内部颁布使用人工智能的最佳实践。

工具——保险清单

算法影响评估工具是一种记分卡,旨在引起人们对可能被忽略的设计和部署决策的注意。它提出了许多关于为什么、做什么以及如何建立一个系统的问题,以避免陷阱和问题(以及对政府的潜在指责,这在选举季节总是一个风险)。

这个工具可以在 github.io 上交互使用,从一开始就已经做了大量的修改。这无疑是对其早期基于 Excel 的记分卡(可从 AIA 原始网站获得)的升级。该工具的新版本与现有的和未来的政府政策更加紧密地联系在一起,因此为了清楚起见,让我们探讨一下早期版本。

The clumsy-but-specific spreadsheet-based system.

主要影响评估包括 4 个主要部分:

  • 商业案例。你是想加快速度吗?您是否正在尝试清理积压的活动?你正在努力使你的组织现代化吗?
  • 系统概述。主要的技术基础是什么?图像识别、文本分析,还是流程和工作流自动化?
  • 决策失察。它是否与健康、经济利益、社会援助、出入和流动性或许可证和执照有关?
  • 数据源。是否来自多个来源?它是否依赖于个人(潜在可识别的)信息?安全分类是什么,由谁控制?

这些支票避免了明显的“我认为这很酷”的问题,浪费了金钱。它还意外地设定了衡量成功的总体标准,通常与部门的关键绩效指标挂钩。

(关于新友邦保险的完整问题列表,您可以参考 github repo 的问卷调查的 raw JSON 。)

好的,坏的和丑陋的

这篇文章的大部分内容是对所完成的工作的持续缓慢的点头,就像有人向米开朗基罗竖起大拇指让他继续前进。下面列出了需要更多注意的几点。

好的—最佳实践在前面和中间

很多问题涵盖了这个工具应该涵盖的内容。它询问临时部署的关键功能,以便进行检查和平衡。以下是一些例子:

"你会维护一个日志,详细记录对模型和系统所做的所有更改吗?"

"当需要时,系统能够为它的决定或建议提供理由吗?"

“是否有授予、监控和撤销系统访问权限的流程?(是/否)"

“该系统是否允许人工干预系统决策?是否有适当的流程来记录执行覆盖时的实例?”

太好了,这正是它需要问的。但是仍然有很多东西需要修复。

不好的方面——缺乏量化或精确性

当我们使用记分卡时,不强迫回答的能力会比仅仅填补空白更有帮助。以下是一些例子:

“决策的风险很高吗?(是/否)"

“决策对个人经济利益的影响可能是:(很少或没有影响/中度影响/高度影响/非常高度影响)”

“在你的机构中,你是否对系统的设计、开发、维护和改进赋予了责任?(是/否)"

现在,“利害关系”、“风险”和“责任”可以在每个部门的基础上量化和定义,但我希望看到一个标准的定义(如 ISO 的影响与概率计算)。

还有一个让我有点困惑的令人惊讶的问题:

“您是否有记录在案的流程来针对偏见和其他意外结果测试数据集?这可能包括应用框架、方法、准则或其他评估工具的经验。”

这就是这个工具的目的。我承认其崇高的包罗万象的性质不允许每一种可能的情况下的细节,但至少应该提到或提及“这是你如何知道你在正确的轨道上”的参考。

丑陋的政治化

与旧版本相比,这是该工具当前版本令我惊讶的一个方面。它旨在帮助各部门为现在和即将成为公民的人提供更好的服务,而不是通过不搅动罐子来帮助一个政党获得或保持权力。问题是:

“项目是否处于公众严格审查(例如,出于隐私考虑)和/或频繁诉讼的范围内?”

虽然我知道,从表面上看,这似乎是一个适当的问题,但这样一个问题的历史背景确实有很多政治含义。(对于那些好奇的人来说,首席审计员称联邦雇员的薪资改革是一次“不可理解的失败”。值得带着一袋爆米花去读。)

如果某个特定的领域受到公众的密切关注,并且经常被提起诉讼,那么它就应该被更新和创新。

我真心希望我读错了。我不希望政府内部的创新能力被政治动荡拖慢

面向未来的约定

在不影响到目前为止在建立一个全面彻底的框架方面所做的巨大努力的情况下,我建议修改检查表,添加以下内容。

1.对问题的简单修改

将许多是/否问题移到“示范”文档中,有助于更彻底地检查解决方案。例如:

  • Change " 您会开发一个流程来记录数据质量问题在设计过程中是如何解决的吗?"to " 您计划如何记录和传达已发现的数据质量问题?"
  • "您是否在您的机构中分配了系统设计、开发、维护和改进的责任?"应该变成“是系统的设计、开发、维护、修复、重构、和改进的责任方?”
  • "您是否有记录在案的流程来测试数据集是否存在偏差和其他意外结果?"可以"针对偏见和其他意外结果测试数据集的所有记录流程是什么?

2.长期所有权和变革管理

谁将拥有算法?该工具现在有一个简单的责任问题。然而,我的好朋友 Jen 说,最好的流程和技术是那些像员工一样管理的流程和技术:它们在某人的监督下,并且有明确的成功衡量标准。因此:

  • 谁来维护?此人/这些人的工作职责是否已更新,以包括此特定系统?
  • 就人员、预算和时间而言,未来用于维护 it 的资源有多少?
  • 是否为预期的技术变化制定了维护计划?(至少每季度或每两年一次。)

3.翻译和评估成功的衡量标准

我过去曾在智能系统环境中谈论过“正确构建事物”与“构建正确的事物”,深受 ISO 13485 的启发。这适用于功能系统与业务案例脱节的情况,因为它在技术上得到了维护(例如,本周发布的 VueJS 的任何版本),但没有重新处理以回答核心组织问题。

如果没有对每个团队和部门如何建立和度量进展(更不用说成功)的清晰理解,就不可能评估一个系统是否在不投入大量资金的情况下产生了实质性的差异。

花额外的一两个月时间为项目构建定制的记分卡,这样在初始部署后就不会出现太多意外。

结论

AIA 工具满足了政府创新任务中的一个关键需求,即建立探索性项目的监督机制。

具有讽刺意味的是,目前与该工具相关的最大风险与它试图评估的每个项目相同——好主意,糟糕的执行。在这种特殊情况下,执行是关于更新和教育的,这样每个人都知道什么是向前发展的最佳实践集。

如果应用正确,这个工具将确保您的项目可以承受未来几年,而不需要在更具支持性的基础上从头开始重建。如果做错了,貌似合理的否认会导致诉讼(或者更糟),所以现在就花额外的时间来确保你的项目有一个坚实的基础。

如果您对本文或我们的 AI 咨询框架有其他问题,请随时通过LinkedIn*或通过* 电子邮件 联系。

你可能喜欢的其他文章

我的首席技术官丹尼尔·夏皮罗(Daniel Shapiro)的其他文章您可能会喜欢:

使用机器学习了解癌症

原文:https://towardsdatascience.com/understanding-cancer-using-machine-learning-84087258ee18?source=collection_archive---------11-----------------------

机器学习(ML)在医学中的应用变得越来越重要。一个应用实例可以是癌症检测和分析。

(Source: https://news.developer.nvidia.com/wp-content/uploads/2016/06/DL-Breast-Cancer-Detection-Image.png)

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

介绍

正如许多研究人员所证明的[1,2],机器学习(ML)在医学中的应用现在变得越来越重要。研究人员现在将 ML 用于 EEG 分析和癌症检测/分析等应用中。例如,通过检查生物数据,如 DNA 甲基化和 RNA 测序,就有可能推断哪些基因会导致癌症,哪些基因反而能够抑制其表达。在这篇文章中,我将向你介绍我是如何检查关于 TCGA 肝癌、宫颈癌和结肠癌的 9 个不同数据集的。所有的数据集都是由 UCSC 谢轩(加州大学圣克鲁兹分校网站)提供的。对于所考虑的 3 种不同类型的癌症中的每一种,使用了三个数据集,包含关于 DNA 甲基化(甲基化 450k)、基因表达 RNAseq (IlluminaHiSeq)和最终外显子表达 RNAseq (IlluminaHiSeq)的信息。然后,这些数据集按信息类型而不是按癌症进行分组。我决定使用这些数据集,因为它们具有所有的共同特征,并且共享相似数量的样本。此外,我决定选择这些类型的癌症,因为它们提供了人体基因和染色体特征的不同观点,因为不同的癌症位于身体的不同部位。这样,在这项工作中获得的分类结果可以推广到其他形式的癌症。DNA 甲基化在基因表达的调节中起着重要作用,其修饰可以导致癌细胞的产生或抑制[3]。

分类

每个数据集都必须进行转置和预处理。在形成最终的三个数据集之后,进行不同类型癌症之间的分类。为了产生这些结果,使用了 70%训练,30%测试的分割比率。如表 1 所示,考虑了许多分类算法。这些结果是利用整个数据集和旨在正确区分三种不同类型癌症的分类器获得的。

特征抽出

我对 3 个给定的数据集执行了主成分分析(PCA ),以查看仅使用前两个主成分会如何影响分类精度结果(表 2)。主成分分析旨在降低数据集的维数,同时尽可能多地保留方差。从表 2 中可以注意到,将数据维数减少到两个特征并没有导致准确性的急剧下降。

图 1 提供了使用逻辑回归的 PCA 分类结果,两个轴代表 PCA 产生的两个主要成分。外显子表达数据集似乎受五氯苯甲醚的影响最大,最高准确率为 65%。这一结果的原因是不同类别之间的主要重叠,如图 1(c)所示。

最后,我决定应用另一种特征提取技术,如 t-SNE。这种技术可以实现将高维数据可视化到低维空间中,从而最大化不同类别之间的分离。结果如图 2 所示,双轴代表由 t-SNE 设计的两个主要组件。三种不同类型的癌症中的每一种都用不同的颜色标记(TCGA 肝癌= 0,宫颈癌= 1,结肠癌= 2)。从图 2 中可以看出,t-SNE 创造了两个能够很好地区分三个不同类别的特征。

特征选择

前面几节向我们展示了使用整个数据集可以获得非常好的分类结果。使用特征提取技术,如主成分分析和 t-SNE,已经表明有可能减少维数,同时仍然产生可观的分类分数。由于这些结果,我决定绘制一个决策树,代表分类中使用的主要特征(权重最大的特征),以便更仔细地研究最重要的特征。由于决策树在所有三个数据集中的分类性能,我决定使用决策树进行分析。结果见图 3 (DNA 甲基化)、图 4(基因表达)和图 5(外显子表达)。

在每个图中,不同的癌症类型用不同的颜色表示(TCGA 肝癌= 0,宫颈癌= 1,结肠癌= 2)。所有三种癌症的特征分布都表示在树的起始节点中。只要我们向下移动每个分支,算法就会尝试使用每个节点图下面描述的功能来最好地分离不同的分布。沿着分布生成的圆表示在跟随某个节点之后被正确分类的元素的数量,元素的数量越大,圆的大小就越大。

为了生成这些图形,我使用了 Terence Parr 和 Prince Grover 创建的 dtreeviz.trees 库。我决定使用这个库,因为它使我能够可视化树的每个分支中的特性分布。当试图分析类别之间的差异以及观察算法如何做出分类决策时,这在生物学领域可能特别重要。

估价

表 3 总结了三个不同树的顶部(前两层)使用的特性。经过仔细研究,查看在线可用数据库,为每个特性添加了一系列相关注释(表 3)。对于 cg27427318 和 chr 10:81374338–81375201,无法找到任何相关信息。

从分析的特征中推断出的一些最有趣的结果是:

  1. PFN3 已被鉴定为与 cg06105778 最接近的基因。根据邹丽、丁志杰等人在 2010 年进行的一项研究,轮廓蛋白(Pfns)可能被归类为乳腺癌中的一种肿瘤抑制蛋白[4]。
  2. 根据诺埃尔·j·埃亨、古汉·兰加斯瓦米等人的“Holt-Oram 综合征男性前列腺癌:TBX5 突变的首次临床关联”,TBX5 基因“被认为在突变时上调肿瘤细胞增殖和转移”[5]。Yu J,Ma X 等人的另一项研究证明,患有 TBX5 结肠癌的患者存活率低得多[6]。
  3. Alexa Hryniuk、Stephanie Grainger 等人开展的研究强调,“Cdx1 的缺失导致远端结肠肿瘤发病率显著增加”[7]。

仅使用表 3 中列出的各个数据集的特征,我最终决定使用 PCA 和线性判别分析(LDA)将数据减少到二维,并执行朴素贝叶斯(NB)和支持向量机(SVM)分类,以查看覆盖了多少数据方差。结果如表 4 所示,该表显示,仅使用数据集中最重要的特征即可获得出色的分类结果(由于噪声降低)。在所有考虑的情况下,原始数据差异的 83%到 99%被保留。

结论

总来说,这个项目产生了很好的结果。作为进一步的发展,尝试替代的特征选择技术,如递归特征选择(RFS)或 SVM(如我的另一篇文章中所解释的),看看是否可以识别其他类型的基因/染色体,这将是有趣的。这种分析的另一个可能的改进是使用包含来自健康受试者的数据的数据集来交叉验证所获得的结果。

我要感谢 Adam Prugel-Bennett 教授给我这个机会来实施这个项目。

联系人

如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:

文献学

[1]维里戴安娜·罗梅罗·马丁内斯。使用深度学习检测组织病理学图像中的乳腺癌。访问:https://medium . com/datadriveninvestor/detecting-breast-cancer-in-organism-photo-images-using-deep learning-a 66552 AEF 98,2019 年 4 月。

[2]胡子龙嘎,唐金山,等.基于图像的癌症检测和诊断的深度学习,一项调查。查阅网址:https://www . science direct . com/science/article/ABS/pii/s 0031320318301845,2019 年 5 月。

[3] Luczak MW,Jagodzi nski PP . DNA 甲基化在癌症发展中的作用。访问时间:https://www.ncbi.nlm.nih.gov/pubmed/16977793, 2019 年 5 月。

[4]邹丽、丁志杰和帕萨·罗伊。Profilin-1 过表达抑制 MDA-MB-231 乳腺癌细胞增殖部分通过 p27kip1 上调获得:https://www . NCBI . NLM . NIH . gov/PMC/articles/PMC 2872929/pdf/NIH ms-202017 . pdf,2019 年 5 月。

[5]诺埃尔·埃亨、古汉·兰加斯瓦米和皮埃尔·蒂里翁。Holt-Oram 综合征男性患者的前列腺癌:TBX5 突变的首次临床关联于 2019 年 5 月在https://www.hindawi.com/journals/criu/2013/405343/获得。

[6]于军,马 X,等.一种新的肿瘤抑制基因 T-box 转录因子 5 的表观遗传失活与结肠癌相关.访问时间:https://www.ncbi.nlm.nih.gov/pubmed/20802524, 2019 年 5 月。

[7] Alexa Hryniuk,Stephanie Grainger 等。Cdx1 和 Cdx2 具有肿瘤抑制功能。访问时间:https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4246091/, 2019 年 5 月。

使用等曲线了解分类阈值

原文:https://towardsdatascience.com/understanding-classification-thresholds-using-isocurves-9e5e7e00e5a2?source=collection_archive---------18-----------------------

你在一个会议室里,展示你的一个分类问题。您展示了您在特征工程、预测器选择、模型选择、超参数调整和集成方面的所有神奇之处。你用预测概率和 ROC 曲线以及奇妙的 AUC 来结束你的陈述。你坐下来,对自己出色的工作充满信心。

经理说,“我该怎么处理这些概率和 ROC 之类的东西?我只是想知道我应该做 x 还是 y 。”x 可能在哪里,我是否应该将此邮件归类为垃圾邮件?还是面对这种路况我的特斯拉应该踩刹车?或者我该不该批准这笔贷款?

Optimal thresholds using different metrics, with isocurves

在你解释如何解释模型并应用它之前,你作为数据科学家的工作还没有结束。这意味着为激励模型的商业决策选择阈值。

作为一名数据科学家,你可能会说… “一篇关于阈值的博文?这甚至不是一个数据科学问题,而是一个业务问题。”

你是对的!阈值选择缺乏吸引力,比如说,生成性对抗网络。

但这也是橡胶遇到道路的地方,在这里你用奇特的算法做的所有创造性的东西与现实世界的决策相互作用。

它受到了冷遇。因此,这里有一个深入的阈值选择,包括 F1 分数及其与其他指标的比较。让我们开始吧!

1.你需要一个度量或者一个成本函数来优化。

企业不关心 Kaggle 指标。企业在数据科学上投资的唯一正当理由是:1)获得并留住客户,2)降低成本,3)更好地开展业务,从而 4)增加利润。如果您了解模型的业务目标,模型可以改进哪些关键绩效指标(KPI ),并应用科学方法来提出正确的问题并改进这些 KPI,您可能会成为 A-team 数据科学家。

在预测观察值属于正类的概率的算法的情况下,阈值选择是必要的。这是大多数(但不是全部)分类算法的工作方式。接下来的问题是,如果我们需要根据建模的概率进行离散预测,那么将一个观察结果归类为阳性的最佳阈值是什么?

要问的第一个问题是:您能使用企业关心的 KPI 量化第一类和第二类错误的成本吗?什么是假阳性的边际成本,什么是假阴性的边际成本?如果你能确定正确的成本函数,你的工作基本上就完成了。

选择使交叉验证中的假阳性和假阴性的总成本最小化的阈值。(始终处于交叉验证中:永远不要选择超参数或使用训练数据或测试数据对您的模型做出任何决定;分类阈值可以被认为是一个超参数。)

假设我们预测一个借款人是否会拖欠信用卡。提供本应被拒绝的信贷会造成 50,000 美元的信贷损失和管理成本。拒绝本应提供的信贷会导致客户损失 10,000 美元的终身价值(LTV)。选择在交叉验证集合(或折叠)中假阳性和假阴性总成本最低的阈值。

2.当您改变分类阈值时,ROC 曲线可视化了一组可行的解决方案,隐含地改变了假阳性相对于假阴性的成本。

如果阳性类别代表检测到停车标志或医疗状况,则假阴性的成本很高。你需要一个低门槛来最大限度地减少假阴性,这些假阴性会导致你冲过十字路口,与交通相撞,或者无法获得进一步的救命诊断或治疗。

如果您的问题是垃圾邮件检测,阻止一封重要的电子邮件比让垃圾邮件通过的成本更高。所以你倾向于使用更高的阈值来将邮件标记为垃圾邮件,以减少误报。

图一。ROC 曲线

这是来自 Kaggle 数据集的 ROC 图。

我们来回顾一下如何解读 ROC 剧情:

  • 真阳性是被正确预测为真的真实观察。
  • 真阳性率(TPR)真阳性/真阳性的数量(也称为召回灵敏度)。地面真阳性=真阳性+假阴性:TPR = tp / (tp+fn)
  • 假阳性是错误预测为真的错误观察。
  • 假阳性率(FPR)假阳性/真阴性数 (1 — FPR 是特异性)。地面真阴性=真阴性+假阳性:FPR = fp / (tn + fp)
  • ROC 图上最好的点是左上角,100% TPR,灵敏度或回忆,0% FPR,或 100%特异性。
  • 最佳可行点在 ROC 曲线上。当你从左向右移动时,你降低了将一个观察归类为积极的阈值。你得到更多的真阳性,但也有更多的假阳性。
  • 一个很好的类比是用网捕鱼:当你使用更细的网时,漏网的鱼会更少,但你也会捕获更多的海藻和垃圾。这个价值 64,000 美元的问题是如何使用一张网来获得最好的结果。

3.ROC 曲线的斜率反映了每接受一个假阳性,您获得了多少个真阳性。

我们来讨论一下如何解读 ROC 曲线的斜率。

图二。ROC 曲线斜率

我们把 TPR 放在左轴,把 FPR 放在底轴。我们也用虚线画出了 45 度线。45 线是 ROC 曲线,如果你用基本比率对你的观察值进行随机分类,你会得到这条曲线。在这个例子中,大约 20.8%的观察结果是基本事实。如果您使用随机分类器将 20.8%随机分类为阳性,您的 ROC 曲线将大致遵循 45°线。这是你不用做任何建模就能得到的最好的 AUC(ROC 曲线下面积)。或建模尝试失败的最坏情况 AUC,其不能找到任何预测信号。

回想一下,TPR 是真阳性,作为基础真阳性的百分比,我们将实际真阳性计数放在右轴上。同样,由于 FPR 是假阳性占地面真实阴性的百分比,所以实际的假阳性计数在顶轴上。

这有助于我们解释斜率:斜率是通过接受一个额外的假阳性而获得的额外的真阳性的数量。(近似值,记住 ROC 曲线是由离散点组成的)。

45°线在 TPR/FPR 空间中的斜率为 1(FPR 每增加一个百分点,TPR 增加一个百分点)。在原始真阳性/假阳性空间中,45°线的斜率是阳性总数/阴性总数。如果正类以概率 p 出现,则斜率为 p / (1 — p)

如果你有一个理想的 ROC 曲线,斜率连续下降(凹下),你可以从左下开始,一直向右上,只要假阴性表达的额外真阳性的成本是可接受的。

(真实世界的 roc 通常更混乱,可能没有连续递减的斜率。但是 ROC 曲线总是正倾斜的,除了在边缘处,从不平坦或垂直。这将意味着两点,其中一点在一个维度上更好,而在另一个维度上相等。那么只有一个可能是最优解,而且只有那个应该在 ROC 曲线上。此外,最合理的阈值选择度量将忽略不在“外壳”上但暂时向左下角倾斜的区域中的点。所以考虑一条斜率连续下降的 ROC 曲线是合理的。)

4.精确度、召回率和 F1 分数

现在,如果您不能确定假阳性和假阴性的真实成本,会发生什么?

一个常用的指标是 F1-score ,它是精确度和召回率的调和平均值。

  • 精度是真阳性/预测阳性,即我们正确预测的阳性预测的百分比。
  • 回忆一下是 TPR:真阳性/基本事实阳性,即我们正确预测的基本事实阳性的百分比。
  • 为了计算谐波平均值,我们反转输入,计算它们的平均值,然后反转平均值。

为了获得关于调和平均值的直觉:如果车辆以速度 x ( 例如 60 km/h 向外行驶距离 d ,并以速度 y ( 例如 20 km/h 返回相同的距离,那么其平均速度是 x的调和平均值

这并不等于算术平均值(40 km/h ),如果您在两个不同速度的路段中行驶了相同的时间,则算术平均值是适用的。

如果任一条腿上的速度接近 0,则无论另一条腿上的速度如何,整个距离的调和平均值都将接近 0。如果任何一段的速度正好为 0,你就永远不会到达目的地,所以整个行程的平均速度为 0。

F1 分数平衡了精确性和回忆性,惩罚了其中任何一个方面的极端弱点。

F1 的分数是不对称的。我们有不平衡的 79.2%/20.8%的负面/正面比率。假设我们的分类器预测一切都是积极的。那么召回率是 1,精度是 0.208,F1 是 0.344。现在假设标签反了,你预测一切都是正的,回忆是 1,精度是 0.792,F1 是 0.884。这看起来很棒,但事实并非如此,因为我们所做的只是将所有东西归类为多数类。由于这种不对称性,我们总是小心翼翼地将少数类标记为正类来计算 F1 分数。

不对称有时是好的。有时业务问题是不对称的。在一个搜索引擎应用程序中,我们不太关心我们没有检索到的所有文档。

我们可以通过使用加权平均值而不是等加权平均值来将阈值向精确度或召回率倾斜,在这种情况下,我们称之为 F2-score 等。

F-score 似乎是合理的,虽然调和平均值的适用性对我来说不是完全直观的。我从未遇到过假阳性和假阴性的真实成本函数是调和平均值的业务问题。

5.等曲线可帮助您可视化任何评分或成本函数,如 F1

如果你想要最好的折衷,用等曲线可视化折衷是有帮助的。等值成本曲线或无差别曲线描绘了一组具有相同成本或度量值的点:例如,F1 值为 0.5 的所有点。这可以让您直观地看到当您沿着 ROC 曲线移动时,指标是如何演变的。

对于 F1 指标,等曲线看起来像这样。

图 3。f1-得分等曲线

  • 底部轴:回忆= 0,F1 = 0
  • 左上角:我们完美地分类了:召回率= 1,精确度= 1,F1 = 1
  • 右上方:我们对所有阳性进行分类:召回率= 1,精确度= 0.208,F1 = 0.344

要选择具有最高 F1 的点,选择 ROC 曲线上位于最佳 F1 等曲线上的点,即最接近左上的等曲线。

6.线性成本等值线

F-score 是一个非线性成本函数。如果成本函数是 TPR 和 FPR(或假阳性和假阴性)的线性函数,用一个假阳性换一个假阴性的相对成本是常数,并且你有均匀间隔的线性等曲线。

图四。线性成本等值线

再次选择 ROC 曲线上的点,该点也在最靠近左上方的等曲线上。在这个例子中,相对价格是 p/(1-p) 。所以等曲线平行于 45°线,对应于使用基本速率 p 的随机分类器。

与 F1 等曲线相比,当你上升时,F1 在左侧上升得更快。因此,当你提高 ROC 时,在其他条件相同的情况下,连接最佳 F1 点的路径将向左弯曲(凹下)。连接最佳线性成本的路径将是一条直线。就像他们说的,证据是作为练习留下的。

我们可以衡量假阳性对假阴性的相对成本。当我们这样做时,等曲线的斜率会发生变化,我们会倾向于精度高于回忆,反之亦然。

7.圆形或“最接近左上”等曲线

假设我们希望通过欧几里德距离尽可能接近左上。对应于圆形等曲线。成本函数是从左上角开始的距离:

图五。最靠近左上角:圆形等曲线

我们还可以对平方根下的项进行加权,以提高精确度或召回率,并将曲线做成水平或垂直的椭圆。

与恒定成本等曲线相比,圆形等曲线倾向于将最佳点保持在中间,靠近对角脊,从而平衡精确度和召回率。

8.交互信息

最后再来看互信息。互信息是一种信息论度量,就像 日志损失 。Log loss 可以解释为我们的预测与实际结果之间的错误或意外,用比特来衡量。 互信息 可以解释为我们预测中的正确信息量,用比特来衡量。

互信息是我们用来测量电话线或无线信道上信号的带宽容量的。我们可以把预测看作是关于未来的信号。在同样的意义上,互信息衡量的是一个信道上可以传输多少有用的信号,互信息告诉我们有多少关于未来的有用信息。

如果我们用互信息作为我们的成本函数,我们会得到这样的等值线。

图 6。互信息等曲线

在信息论的意义上,最大化互信息可以最小化预测中的意外或错误,并最大化“正确”信息。由于没有假阳性和假阴性的明确成本,互信息似乎是一个自然的度量选择。

然而,互信息等曲线符合 ROC 曲线的一般形状。所以他们在选择是偏向精确还是偏向回忆方面可能不是很稳定。

倾向于精确还是召回的选择是基于算法在精确还是召回方面更好,而不是任何现实世界的成本。因此,阈值的选择可能是任意的,很难解释。

同样值得注意的是,完全错误的预测与完全正确的预测包含相同的互信息,因为您可以从该信号中提取正确的预测。这也有点违反直觉。

互信息具有理论吸引力,但可解释性具有挑战性。

9.结论

当我开始建立分类模型时,我经常使用 F1 分数。现在,我一般用 AUC 进行模型选择和超参数调优。对于阈值选择,我尝试识别最相关的真实世界度量。

我发现线性等曲线最容易解释。在没有一个好的先验成本函数的情况下,我还发现证明 p/(1-p) 比 F1 或其他更复杂的指标更容易。圆形等曲线更难解释,但有利于精确度和召回率之间的平衡。但从经验上看,F1 表现不错。

要选择一个门槛,就要把某个东西最大化。您最大化的指标应该是可解释的,并与现实世界的成本相关联

外卖:

  • 阈值选择是数据科学与现实决策相结合的地方。
  • 不要自动使用 50%的阈值,甚至 F1 分数;考虑假阴性和假阳性的真实成本。
  • 要选择一个阈值,你必须优化一些指标:一个成本函数。
  • 业务环境决定了您正在优化的成本函数:您愿意在第一类和第二类错误之间做出的真实世界的权衡;为了以假阳性为代价获得更多的真阳性,您应该将阈值降低到什么程度。
  • 等曲线等高线图是一种可视化,每当您必须权衡两个变量时,它都可以为您的成本函数提供良好的直觉。
  • 最小化成本函数时,选择 ROC 曲线与最低成本(或最高度量)等曲线相交的最佳分类阈值。

等曲线可用于在任何一组竞争的备选方案之间做出合理的选择,而不仅仅是分类阈值。这篇文章涵盖了大约 30%最重要的经济学原理:人们面临权衡;某物的成本是你为了得到它而放弃的东西;理性的人在边际思考;你必须选择最大化什么。

选择优化 KPI 和实现业务目标的阈值,可以最大化您作为数据科学家的价值…这是一个真正的最佳结果。

可视化的代码在 GitHub 这里

另请参见:

福塞特,汤姆。" ROC 图:研究人员的注意事项和实际考虑."机器学习 31.1(2004):1–38。【https://www.hpl.hp.com/techreports/2003/HPL-2003-4.pdf

《通过科学做出更好的决策》《科学美国人》, 2000 年第 283 卷第 4 期,第 82-87 页。JSTOR,www.jstor.org/stable/26058901

grandenberger,评估分类模型,第 3 部分:Fᵦ和其他加权毕达哥拉斯方法的精确度和召回率

了解 CNN(卷积神经网络)

原文:https://towardsdatascience.com/understanding-cnn-convolutional-neural-network-69fd626ee7d4?source=collection_archive---------3-----------------------

数据科学家的技术说明

你学习图像分类深度学习的第一步

Source Unsplash

想象一下 Google 相册:对于你所有的图片,你是如何用物体来标记的?要不要一个一个贴标签?可以搜索一下你最新的马里兰鸡快照吗?进入 CNN!

理解图像分类

图像分类定义图像对象,并从标记的例子中标记这些图像。

我们的大脑是快速判断物体的大师。当你进入一家杂货店时,你可以把香蕉和鞋子等其他商品分开。我 2 岁的侄女知道如何区分猫和狗。

然而,用计算机来教这些分类是非常困难的。

My search for the word “cat”

看看这些图片。在几个惊鸿一瞥之内,你应该已经意识到,在猫的形象中间,有几个来自音乐剧《猫》的女演员。也有一些是猫涂鸦的图片,但不是猫。那么我们如何教会我们的计算机理解这些图像呢?

经典图像分类

过去,图像分类模型使用原始像素对图像进行分类。您可以通过颜色直方图和边缘检测对猫进行分类,边缘检测允许您通过颜色和耳朵形状对猫进行分类。这种方法是成功的,但是直到该方法遇到更复杂的变体。

Imagine if our classifiers only specify cats by their black color and ear shape. Are all of these pictures cats?

这就是经典图像识别失败的地方,因为模型没有考虑其他特征。但是这些的其他特征是什么呢?需要一个一个讲型号吗?你会发现这即使不是不可能,也是一件非常麻烦的事。

介绍卷积神经网络(CNN)

CNN Architecture

CNN 是一种神经网络模型,它允许我们提取图像内容的更高表示。与传统的图像识别不同,在传统的图像识别中,您需要自己定义图像特征,CNN 获取图像的原始像素数据,训练模型,然后自动提取特征以进行更好的分类。

让我们来看看下面的视错觉,了解 CNN 是如何工作的。

CNN 的直觉——想象一个视错觉

Psychologist Edwin Boring introduced the painting of “My Wife and My Mother-in-Law” where the figure seems to morph from young lady to old woman, to the public in 1930. (Source)

考虑这个图像。你看到一位年轻女士还是一位老奶奶?如果你把焦点放在图像中间的一个点上,你会看到一位年轻的女士。然而,如果你把焦点放在图像中下方的黑色条纹上,你会看到一位老太太。请看图片上的红色方框。

这张图片提供了人类如何识别图像的见解。因为人类的大脑被设计用来捕捉模式以对物体进行分类,所以改变你观察的焦点也会改变你对整体图像的理解。

与人类大脑的工作方式类似,CNN 区分图像中有意义的特征,以便对图像进行整体分类。

CNN 原理

盘旋

卷积通过图像扫描窗口,然后计算其输入和过滤点积像素值。这允许卷积强调相关特征。

1D Convolution Operation with features(filter)

看看这个输入。我们将用一个小窗口包住窗口元素,用点乘它与过滤器元素,并保存输出。我们将重复每个操作以导出 5 个输出元素作为[0,0,0,1,0]。从这个输出中,我们可以知道序列 4 中的特征变化(1 变成 0)。过滤器很好地识别了输入值。同样,这也发生在 2D 卷积。

2D Convolution Operation with features(filter) — Source

通过这种计算,您可以从输入图像中检测出特定的特征,并生成强调重要特征的特征图(卷积特征)。这些卷积特征将总是根据受梯度下降影响的滤波器值而变化,以最小化预测损失。

此外,部署的过滤器越多,CNN 提取的特征就越多。这允许发现更多的特征,但是代价是更多的训练时间。有一个甜蜜点的层数,通常,我会把 150 x 150 大小的图像 6。

Feature map in each layer of CNN (source)

然而,边角值呢。它们没有足够的相邻块来适合过滤器。我们应该移除它们吗?

不,因为你会丢失重要信息。因此,你要做的反而是填充;用 0 填充相邻的特征图输出。通过将 0 插入其相邻像素,您不再需要排除这些像素。

本质上,这些卷积层促进了权重共享来检查内核中的像素,并开发视觉上下文来对图像进行分类。与权重独立的神经网络(NN)不同,CNN 的权重被附加到相邻像素,以提取图像每个部分的特征。

最大池化

We take the maximum max pooling slices of each 2x2 filtered areas (source)

CNN 使用 max pooling 用 max summary 替换输出,以减少数据大小和处理时间。这使您可以确定产生最大影响的特征,并降低过度拟合的风险。

最大池有两个超参数:步幅和大小。步幅将决定价值池的跳跃,而大小将决定每次跳跃中价值池的大小。

激活函数(ReLU 和 Sigmoid)

在每个卷积和最大池操作之后,我们可以应用校正线性单元(ReLU)。ReLU 函数模拟我们的神经元在“足够大的刺激”下的激活,从而为值 x>0 引入非线性,如果不满足条件,则返回 0。这种方法对于解决梯度递减是有效的。在 ReLU 激活功能后,非常小的权重将保持为 0。

CNN 大图+全连接层

CNN architectures with convolutions, pooling (subsampling), and fully connected layers for softmax activation function

最后,我们将使用全连接图层(FCL)提供卷积和最大池要素地图输出。我们将特征输出展平为列向量,并将其前馈到 FCL。我们用 softmax 激活函数包装我们的特征,该函数为每个可能的标签分配十进制概率,其总和为 1.0。前一层中的每个节点都连接到最后一层,并表示要输出哪个不同的标签。

最终结果如何?你将能够对狗和猫的图片进行如下分类。

Finding the perfect image classification with softmax (Source)

CNN 中的清洗和防止过拟合

不幸的是,CNN 也不能幸免于过度拟合。如果没有适当的监控,模型可能会被训练得太多,以至于不能概括看不见的数据。通过我的经验,我犯了许多初学者过度拟合的错误,我是如何解决它们的如下:

使用测试集作为验证集来测试模型

即使我们不使用测试集来训练模型,模型也可以用测试集来调整损失函数。这将使训练基于测试数据集,并且是过度拟合的常见原因。因此,在训练过程中,我们需要使用验证集,然后用看不见的测试集最终测试完成的模型。

数据集相对较小

当数据集很小时,很容易专注于几组规则而忘记概括。例如,如果您的模型只将靴子视为鞋子,那么下次您展示高跟鞋时,它不会将其识别为鞋子。

因此,在训练数据集很小的情况下,你需要人为地提振训练样本的多样性和数量。这样做的一个方法是添加图像增强并创建新的变体。这些包括转换图像和创建尺寸变化,如缩放、裁剪、翻转等。

Image augmentation Source

过度记忆

过多的神经元、层和训练时期会促进记忆并抑制概括。你训练你的模型越多,它就越有可能变得过于专业化。为了解决这个问题,你可以通过去除一些隐藏层和每层的神经元来降低复杂度。

或者,您也可以使用正则化技术,如 Dropout 来移除每个梯度步长训练中的激活单元。每个历元训练去激活不同的神经元。

因为梯度步骤的数量通常很高,所以所有神经元将平均具有相同的丢失发生率。直觉上,你退出的越多,你的模型记忆的可能性就越小。

Drop out images

处理彩色图像

您还可以轻松地包含具有 3 层颜色通道的图像:红绿蓝(RGB)。在卷积过程中,您为每个颜色通道使用 3 个单独的卷积,并训练 3 级过滤器堆栈。这允许您检索 3D 要素地图。

我们如何做得更好?—迁移学习

随着用例变得复杂,模型的复杂性也需要提高。有了几层 CNN,你可以确定简单的特征来分类狗和猫。然而,在深度学习阶段,你可能希望从图像中分类更复杂的对象,并使用更多的数据。因此,迁移学习允许你利用现有的模型快速分类,而不是自己训练它们。

迁移学习是一种将现有模型重新用于当前模型的技术。你可以在现有模型的基础上制作,这些模型是由专家精心设计的,并用数百万张图片进行了训练。

然而,你需要遵循一些注意事项。首先,您需要修改最终层以匹配可能的类的数量。第二,您需要冻结参数,并将训练好的模型变量设置为不可变的。这阻止了模型的显著变化。

你可以使用的一个著名的迁移学习工具是 MobileNet。它是为内存和计算资源较少的移动设备创建的。你可以在 Tensorflow Hub 找到 MobileNet,里面聚集了很多预训练的模型。你可以简单地在这些模型上添加你自己的 FCL 层。

结论:CNN 感知我们的视觉世界

CNN 是一门很难的课程,但却是一门值得学习的技术。它教会我们如何感知图像,并学习对图像和视频进行分类的有用应用。在学习了 CNN 之后,我意识到我可以在谷歌的项目中使用这个来检测网络钓鱼攻击。

我也意识到对 CNN 的了解很深。多年来,CNN 变体有许多改进,包括最新的 ResNet,它甚至在 ImageNet 分类中击败了人类评论者。

  1. 乐网(杨乐村,1998 年)
  2. 亚历克斯·奈特(2012 年)
  3. VGGNet (2014) —深度神经网络
  4. 初始模块 Google Net (2014) —堆栈模块层
  5. ResNet (2015) —首个超过人类图像网络的网络

对我来说,我写这篇文章是为了我在谷歌工作的一个项目探索我对 CNN 的基本理解。因此,如果我在写作中犯了任何错误或知识空白,请随时给我反馈。索利·迪奥·格洛丽亚。

参考

我真诚地希望这能激起你更深入了解 CNN 的兴趣。如果你有,这里有一些你可能会觉得非常有用的资源:

  1. CNN 的 Yann LeCun 论文
  2. CS 231 斯坦福
  3. 谷歌 ML CNN
  4. 和许多其他人

最后…

我真的希望这是一本很棒的读物,是你发展和创新的灵感来源。

请在下面评论以获得建议和反馈。就像你一样,我也在学习如何成为一名更好的数据科学家和工程师。请帮助我改进,以便我可以在后续的文章发布中更好地帮助您。

谢谢大家,编码快乐:)

关于作者

Vincent Tatan 是一名数据和技术爱好者,拥有在 Google LLC、Visa Inc .和 Lazada 实施微服务架构、商业智能和分析管道项目的相关工作经验。

Vincent 是土生土长的印度尼西亚人,在解决问题方面成绩斐然,擅长全栈开发、数据分析和战略规划。

他一直积极咨询 SMU BI & Analytics Club,指导来自不同背景的有抱负的数据科学家和工程师,并为企业开发他们的产品开放他的专业知识。

文森特还在 10 日至 8 日开放了他的一对一导师服务,指导你如何在谷歌、Visa 或其他大型科技公司获得你梦想中的数据科学家/工程师工作。

  1. 如果你需要转介到谷歌,请通知他。谷歌在招人!
  2. 如果你正在寻找良师益友,请在这里预约你和他的约会。

最后,请通过LinkedInMedium Youtube 频道 联系文森特

理解置信区间

原文:https://towardsdatascience.com/understanding-confidence-interval-d7b5aa68e3b?source=collection_archive---------8-----------------------

思考频率主义者,而不是贝叶斯:在 Udacity 参与度数据集上模拟一百万次实验

"我们有 95%的把握总体均值落在置信区间内."

事实证明,上述说法具有误导性。置信区间是一个源于频率统计的概念,而陈述表达了贝叶斯信念。在本文中,我们将通过对真实数据的模拟实验来找出置信区间的真正含义。

频率主义者和贝叶斯统计之间的区别是根本性的。教科书上的例子是抛硬币。一个经常光顾的统计学家会将硬币抛 100 万次,如果观察到 50 万个头像,他会宣布硬币是公平的。贝叶斯统计学家会从硬币是否公平的先验信念开始,当他抛硬币时,根据证据逐渐调整他的信念。

在实验背景下,频率主义者认为,无论你相信什么,都只有一个正确的总体均值,而贝叶斯主义者认为总体均值是一个随机变量:你假设它在一个可能值的范围内,你用概率来对冲你的信念。在下面的模拟中,我们将看到为什么置信区间只能用频率主义的方式来解释。

Udacity 参与度数据集

我们将使用来自 Udacity 的参与度数据集。每个数据点都是学生观看视频教程的时间片段。如果一个学生看完了整个课程,他是 100%投入的,他的数据点是 1。啮合遵循指数分布。大多数学生一开始就辍学,只有少数学生完成了整个课程,这并不奇怪。

在现实世界中,我们会将该数据集视为大小为 8702 的样本。但是在这个模拟中,我们将它视为整个人口,并从中抽取 100 万个大小为 300 的样本(这个过程称为 Bootstrap 抽样)。因为我们这里有完整的总体,我们可以很容易地看出,抽样分布的均值是总体均值的无偏估计量(0.07727)。此外,很容易确认经验计算的标准误差与分析的标准误差相同(0.0062)。

总体分布显然不是正态的,但是中心极限定理保证了抽样分布是正态的,给定足够大的样本量(300 就足够了)。如密度图所示,抽样分布确实非常正常。我添加了两条垂直线,标记平均值上下 1.96 的标准误差。这是双尾显著性水平为 0.05 的 z 得分。在正态分布中,有 2.5%以上的概率,和 2.5%以下的概率。

在我们的例子中,我们有 2.06%的下尾部和 2.83%的上尾部。抽样分布是正偏的,因为我们不能有负值。这和 QQ 剧情一致。在低端,极值出现的频率低于正常预期,而在高端,极值出现的频率高于正常预期。

但实际上,这种抽样分布不仅仅满足正态假设:大多数数据点恰好落在 QQ 图对角线上。这是一个重要的健全性检查:正态抽样分布是 z-检验和 t-检验的基本假设(稍后将详细介绍 t-检验)。如果抽样分布不正态,所有测试结果无效。

事实上,我们不知道总体均值或标准误差。毕竟知道了总体均值,就不需要统计检验或者置信区间了!此外,我们不能成为常客。没有人有钱或时间去画一百万个样本,或者把一枚硬币掷一百万次。我们通常只获得一个样本,计算样本平均值和平均值的标准误差,加上和减去一些标准误差的 t 分数倍数,以获得我们的置信区间。

一个常客模拟

如果我们能提取几十万个样本呢?我们已经模拟了一百万个样本。在下面的代码中,我们为每个样本建立了一个置信区间,并检查总体均值是否在置信区间内。请记住,我们已经精确地计算出人口平均值为 0.07727。

结果是 94.4%的置信区间捕捉到了总体均值。这就是置信区间的真正含义:如果我们无限次重复抽样程序,大约 95%的置信区间将包含总体均值。

换句话说,大约有 5%的置信区间没有捕捉到总体均值。在下图中,当蓝色点(上限)低于总体平均值时,或者当橙色点(下限)高于总体平均值时,就会发生这种情况。

Visualizing upper and lower bounds of confidence intervals

那么为什么贝叶斯解释不准确呢?给定任何一个置信区间,我们都不能对总体均值本身做出任何陈述。我们不知道它是属于包含总体均值的 95%区间,还是不属于总体均值的剩余 5%。我们甚至不能推断数据在置信区间内的分布。置信区间可以包含细尾的一部分,或者正好位于总体均值的中心。

A confidence interval could cover any part of the distribution

总之,我们对数据如何在置信区间内分布一无所知,更不用说它是否包含总体均值了。我们能做的陈述是关于置信区间的边界,而不是总体均值的位置。

结论

本文主要研究总体均值的置信区间。我们经常会遇到关于比例(z 检验)和线性回归参数的置信区间。尽管如此,解释是一样的。

我们生活在一个贝叶斯世界。一个人说“我们 95%有信心……”你的经理毕竟不想重复一百万次实验,这很容易被原谅,但是当我们告诉别人这意味着什么时,我们不应该忘记置信区间是一个频繁出现的概念。

延伸阅读

下面的博客涵盖了与 AB 测试相关的主题,以及对本文中提到的关键概念的更深入的回顾。

  • 可视化贝塔分布和贝叶斯更新[ 链接
  • A/B 测试的威力[ 环节
  • 超越 A/B 测试:多臂强盗实验[ 链接 ]
  • 你知道可信区间[ 链接
  • 代码在我的 Kaggle 笔记本里。

理解卷积神经网络:CNN——Eli 5 方式

原文:https://towardsdatascience.com/understanding-convolution-neural-networks-the-eli5-way-785330cd1fb7?source=collection_archive---------14-----------------------

ELI5 项目机器学习

Photo by Efe Kurnaz on Unsplash

通用逼近定理表示,前馈神经网络(也称为多层神经元网络)可以作为强大的逼近器来学习输入和输出之间的非线性关系。但是前馈神经网络的问题是,由于网络内存在许多要学习的参数,网络容易过度拟合。

我们是否可以拥有另一种类型的神经网络,它可以学习复杂的非线性关系,但参数较少,因此容易过拟合?。卷积神经网络 (CNN)是另一种类型的神经网络,可用于使机器能够可视化事物并执行任务,如图像分类、图像识别、对象检测、实例分割等,这是 CNN 最常用的一些领域。

概述

在本文中,我们将深入探讨卷积神经网络的工作原理。本文大致分为两个部分:

  1. 在第一部分中,我们将讨论卷积运算在不同输入(1D、2D 和 3D 输入)中的工作原理。
  2. 在第二部分,我们将探讨卷积神经网络的背景以及它们与前馈神经网络的比较。之后,我们将讨论 CNN 的关键概念。

引用说明:本文的内容和结构基于四分之一实验室——pad hai的深度学习讲座。

1D 卷积运算

让我们从基础开始。在本节中,我们将了解什么是卷积运算,它实际上是做什么的!。

想象一下,有一架飞机从阿里格纳安娜国际机场(印度钦奈)起飞,向英迪拉·甘地国际机场(印度新德里)飞去。通过使用某种仪器,你可以定期测量飞机的速度。在典型的情况下,我们的设备可能不是 100%准确,因此我们可能希望采用过去值的平均值,而不是依赖设备的最新读数。

Readings of aircraft

由于这些读数是在不同的时间步长获取的,而不是简单的平均读数,我们希望给予最近的读数比以前的读数更大的重要性,即…给当前读数分配更大的权重,给以前的读数分配较小的权重。

假设在当前时间步分配给读数的权重是 w₀,先前读数的权重是 w₋₁,依此类推。权重按递减顺序分配。从数学的角度来看,想象一下,我们有无限多的飞机读数,在每一个时间步,我们都有分配给该时间步的权重,一直到无穷大。那么当前时间步长的速度由(Sₜ)给出,

The weighted sum of all values

让我们举一个简单的例子,看看如何使用上面的公式计算当前时间步长的读数。

从上图可以看出,我们想计算飞机在当前时间步(t₀).)的速度我们从仪器中得到的实际速度是 1.90,我们不相信这个值,所以我们将通过取以前读数的加权平均值以及它们的重量来计算一个新值。我们从这个操作中获得的新读数是 1.80。

在卷积运算中,我们得到一组输入,我们根据所有先前输入及其权重计算当前输入的值。

在这个例子中,我没有谈到我们如何获得这些权重,不管这些权重是对还是错。现在,我们只关注卷积运算是如何工作的。

2D 卷积运算

在上一节中,我们已经了解了卷积运算在 1D 输入中的工作原理。简而言之,我们将特定输入的值重新估计为其周围输入的加权平均值。让我们讨论一下如何将同样的概念应用于 2D 输入。

Convolution with 2D filter

为了便于解释,我把上面显示的图像看作只有一个颜色通道的灰度图像。想象一下,上图中的每个像素都是由照相机拍摄的读数。如果我们想要重新估计任何像素的值,我们可以取其邻居的值,并计算这些邻居的加权平均值,以获得重新估计的值。该操作的数学公式由下式给出:

哪里有

k-表示分配给像素值的权重的矩阵。它有两个索引 a,b——a 表示行,b 表示列。

I-包含输入像素值的矩阵。

sᵢⱼ-某一位置像素的重新估计值。

让我们举个例子来理解公式的工作原理。假设我们有一个泰姬陵的图像和 3x3 的权重矩阵(也称为内核)。在卷积运算中,我们对图像施加核,使得感兴趣的像素与核的中心对齐,然后我们将计算所有邻域像素的加权平均值。然后,我们将从左到右滑动内核,直到它通过整个宽度,然后从上到下计算图像中所有像素的加权平均值。卷积运算看起来像这样,

模糊图像

考虑我们将使用 3×3 单位核矩阵来重新估计图像中的像素值。我们这样做的方法是系统地检查图像中的每个像素,并放置内核,使像素位于内核的中心。然后将该像素的值重新估计为其所有邻居的加权和。

blur

在这个操作中,我们平均取 9 个邻居,包括像素本身。因此,合成的图像会变得模糊或平滑。

使用 3D 滤波器的 2D 卷积

在 3D 输入的情况下,如何执行卷积运算?

到目前为止,我们看到的任何图像都是 3D 图像,因为有 3 个输入通道——红色、绿色和蓝色(RGB ),但为了便于解释,我们忽略了这一点。但是,在本节中,我们将考虑原始形式的图像,即… 3D 输入。在 3D 图像中,每个像素都有 3 个值,分别代表红色、绿色和蓝色值。

在 2D 输入中,我们在水平和垂直方向滑动内核(也是 2D)。在 3D 输入中,我们将使用 3D 内核,这意味着图像和内核的深度是相同的。由于内核和图像具有相同的深度,因此内核不会随深度移动。

类似于 2D 卷积运算,我们将在水平方向上滑动内核。每次我们移动内核时,我们都要对整个 3D 邻域进行加权平均,即 RGB 值的加权邻域。因为我们只在两个维度上滑动内核——从左到右和从上到下,所以该操作的输出将是 2D 输出。

尽管我们的输入是 3D 的,核是 3D 的,但是我们执行的卷积运算是 2D 的,这是因为滤波器的深度与输入的深度相同。

我们可以对同一个图像应用多个滤镜吗?

实际上,我们可以在同一幅图像上一个接一个地应用具有不同值的多个核,而不是应用一个核,这样我们就可以获得多个输出。

Application of Multiple Filters

所有这些输出可以堆叠在一起,形成一个卷。如果我们对输入应用三个过滤器,我们将得到深度等于 3 的输出。卷积运算的输出深度等于应用于输入的过滤器数量。

计算输出尺寸

到目前为止,在前面的章节中,我们已经了解了卷积运算在不同输入情况下的工作原理。在这一节中,我们将讨论如何计算卷积运算后输出的维数?。

假设我们有大小为 7x7 的 2D 输入,我们从图像的左上角开始对图像应用 3x3 的过滤器。当我们在图像上从左到右从上到下滑动内核时,很明显输出小于输入,即… 5x5。

为什么产量变小了?

因为我们不能把内核放在角落,因为它会穿过输入边界。图像外的像素值是不确定的,所以我们不知道如何计算该区域像素的加权平均值。

对于输入中的每个像素,我们不是计算加权平均值和重新估计像素值。这适用于图像中存在的所有阴影像素(至少对于 3x3 内核),因此输出的大小将会减小。这个操作被称为有效填充

如果我们希望输出和输入的大小相同呢?

原始输入的大小是 7x7,我们也希望输出大小是 7x7。因此,在这种情况下,我们可以在输入周围均匀地添加一个带有零的人工填充,这样我们就可以将内核 K (3x3)放在角点像素上,并计算邻居的加权平均值。

通过在输入周围添加这种人工填充,我们能够保持输出的形状与输入相同。如果我们有一个更大的内核( K 5x5),那么我们需要应用的填充量也会增加,这样我们就能够保持相同的输出大小。在此过程中,输出的大小与输出的大小相同,因此得名 Same Padding (P)

到目前为止,我们已经在图像中看到,我们以一定的间隔从左到右滑动内核(过滤器),直到它通过图像的宽度。然后我们从上到下滑动,直到整个图像横向移动。步距****【S】定义应用过滤器的间隔。通过选择大于 1 的步幅(间隔),当我们计算邻居的加权平均值时,我们跳过了几个像素。步幅越高,输出图像的尺寸越小。

如果我们将本节所学的内容结合到一个数学公式中,就可以帮助我们找到输出图像的宽度和深度。公式应该是这样的,

最后,对于输出的深度,如果我们对输入应用' K '滤波器,我们将得到' K '这样的 2D 输出。因此,输出的深度与过滤器的数量相同。

卷积神经网络

我们是如何得到卷积神经网络的?

在我们讨论卷积神经网络之前,让我们回到过去,了解在前深度学习时代如何进行图像分类。这也是为什么我们更喜欢卷积神经网络用于计算机视觉的一个动机。

Photo by Dominik Scythe on Unsplash

让我们以图像分类为例,我们需要将给定的图像分类到其中一个类别中。实现这一点的早期方法是展平图像,即将 30×30×3 的图像展平为 2700 的向量,并将该向量输入到任何机器学习分类器,如 SVM、朴素贝叶斯等。此方法的关键要点是,我们将原始像素作为输入输入到机器学习算法,并学习图像分类的分类器参数。

从那以后,人们开始意识到并不是图像中的所有信息对于图像分类都是重要的。在这种方法中,我们不是将原始像素传递到分类器中,而是通过应用一些预定义或手工制作的过滤器(例如,在图像上应用边缘检测器过滤器)来预处理图像,然后将预处理的表示传递到分类器。

一旦特征工程(预处理图像)开始给出更好的结果,像 SIFT/HOG 这样的改进算法就被开发出来,以生成图像的精确表示。由这些方法生成的特征表示是静态的,即……在生成表示时不涉及学习,所有的学习都被推送到分类器。

而不是手动生成图像的特征表示。为什么不将图像展平成 2700×1 的向量,并将其传递到前馈神经网络或多层神经元网络(MLN)中,以便网络也可以学习特征表示?

与 SIFT/HOG、边缘检测器等静态方法不同,我们不固定权重,而是允许网络通过反向传播进行学习,从而降低网络的整体损耗。前馈神经网络可以学习图像的单个特征表示,但是在复杂图像的情况下,神经网络将不能给出更好的预测,因为它不能学习图像中存在的像素依赖性。

卷积神经网络可以通过应用不同的滤波器/变换来学习图像的多层特征表示,使得它能够保持图像中存在的空间和时间像素依赖性。在 CNN 中,网络要学习的参数数量明显低于 MLN,因为稀疏连接和网络中的权重共享允许 CNN 传输得更快。

稀疏连接和权重共享

在第节中,我们将了解前馈神经网络和卷积神经网络在稀疏连接和权重共享方面的区别。

假设我们正在执行一项数字识别任务,我们的输入是 16 个像素。在前馈神经网络的情况下,输入/隐藏层中的每个神经元都连接到前一层的所有输出,即…它对连接到该神经元的所有输入进行加权平均。

在卷积神经网络中,通过在图像上叠加核,我们一次只考虑几个输入来计算所选像素输入的加权平均值。使用稀疏得多的连接而不是考虑所有连接来计算输出 h₁₁。

请记住,当我们试图计算输出 h₁₁时,我们只考虑了 4 个输入,对于输出 h₁₂.也是如此需要注意的重要一点是,我们使用相同的 2x2 内核来计算 h₁₁和 h₁₂,即使用相同的权重来计算输出。不像在前馈神经网络中,隐藏层中存在的每个神经元将具有单独的权重。这种利用输入的相同权重来计算加权平均值的现象被称为权重共享。

汇集层

考虑我们有一个长度、宽度和深度为 3 个通道的输入体积。当我们对输入应用相同深度的滤波器时,我们将得到 2D 输出,也称为输入的特征图。一旦我们得到了特征图,我们通常会执行一个叫做汇集操作的操作。因为学习图像中存在的复杂关系所需的隐藏层的数量将是巨大的。我们应用池操作来减少输入特征表示,从而减少网络所需的计算能力。

一旦我们获得了输入的特征映射,我们将在特征映射上应用一个确定形状的过滤器,以从特征映射的该部分获得最大值。这就是所谓的最大池。它也被称为子采样,因为我们从内核覆盖的整个特征图部分采样一个最大值。

类似于最大池,平均池计算内核覆盖的特征图的平均值。

全连接层

LeNet — 5

一旦我们对图像的特征表示进行了一系列卷积和汇集操作(最大汇集或平均汇集)。我们将最终池层的输出展平为一个向量,并通过具有不同数量的隐藏层的完全连接的层(前馈神经网络)来学习特征表示中存在的非线性复杂性。

最后,完全连接的层的输出通过所需大小的 Softmax 层。Softmax 层输出一个概率分布向量,帮助执行图像分类任务。在数字识别器的问题中(如上所示),输出 softmax 层有 10 个神经元,用于将输入分类为 10 个类别(0-9 个数字)中的一个。

Photo by Fab Lentz on Unsplash

继续学习

如果你想用 Keras & Tensorflow 2.0 (Python 或者 R)学习更多关于人工神经网络的知识。查看来自 Starttechacademy的 Abhishek 和 Pukhraj 的人工神经网络。他们以一种简单化的方式解释了深度学习的基础。

结论

在这篇文章中,我们已经讨论了卷积运算如何在不同的输入上工作,然后我们继续讨论了一些导致 CNN 的图像分类的原始方法。之后,我们讨论了 CNN 的工作,也了解了卷积神经网络的一些重要技术方面。最后,我们看了在 CNN 的《学习复杂关系》的末尾附上 MLN 的来解决图像分类问题背后的原因。

推荐阅读

[## 深度学习:解释前馈神经网络

你的第一个深度神经网络

medium.com](https://medium.com/hackernoon/deep-learning-feedforward-neural-networks-explained-c34ae3f084f1) [## 使用免费 GPU 在 Google Collab 中开始使用 Pytorch

在 CUDA 支持下学习 Colab 中的 Pytorch

medium.com](https://medium.com/hackernoon/getting-started-with-pytorch-in-google-collab-with-free-gpu-61a5c70b86a)

在我的下一篇文章中,我们将讨论如何使用 Pytorch 可视化卷积神经网络的工作。所以确保你在媒体上跟踪我,以便在它下降时得到通知。

直到那时和平:)

NK。

你可以在 LinkedIn 上联系我,或者在 twitter 上关注我,了解关于深度学习和人工智能的最新文章。

免责声明 —这篇文章中可能有一些相关资源的附属链接。你可以以尽可能低的价格购买捆绑包。如果你购买这门课程,我会收到一小笔佣金。

利用大数据分析了解客户流失

原文:https://towardsdatascience.com/understanding-customer-churning-with-big-data-analytics-70ce4eb17669?source=collection_archive---------12-----------------------

如何利用数据科学为您的企业带来价值的实例

Photo by Matt Hoffman on Unsplash

猜猜看。目前世界上最有价值的资产是什么?

不是黄金,不是原油……是数据。您一定听说过流行的术语“大数据”,并且想知道这个术语到底是什么意思。想想你最喜欢的音乐流媒体服务——Spotify、Pandora 等。在世界各地,每秒钟都有许多不同的用户登录到该服务,与该服务进行公平的交互。由于每一次移动都对应一个可收集的数据点,所以您可以想象存储如此大的数据会面临怎样的挑战。

幸运的是,如果以正确的方式使用,这些大型数据集可以为企业带来真正的价值。在这篇博文中,我们将讨论这些大数据集的一个常见用例——预测客户流失。

了解流失

客户流失指的是从大量客户中悄悄流失客户的行为。一些客户可能会转向竞争对手,而一些人可能会永远离开服务。

开始时可能不明显,但随着时间的推移,这种损失的影响会逐渐积累。作为这些音乐流媒体服务提供商的决策者,我们希望了解这种搅动行为的成因,这将成为我们今天项目的主要目标。

我们将从检查可用的数据集开始。

完整的数据集是存储在 12 GB 中的用户日志。json 文件——这个大小只能由一些大数据工具处理,比如 Spark。为了充分理解可用的字段,我们将从获取数据的一个小子集(大约 128 MB)开始,以便在单台机器上进行探索性的数据分析。我们将通过以下命令加载数据集,

# create a Spark session
**spark = (SparkSession.builder 
                    .master("local") 
                    .appName("Creating Features") 
                    .getOrCreate())**# Read in .json file as events **events = spark.read.json('mini_sparkify_event_data.json')
events.persist()**

Spark 有一个很棒的单行快捷方式,可以显示所有字段及其各自的数据类型

**events.printSchema()**root
 |-- artist: string (nullable = true)
 |-- auth: string (nullable = true)
 |-- firstName: string (nullable = true)
 |-- gender: string (nullable = true)
 |-- itemInSession: long (nullable = true)
 |-- lastName: string (nullable = true)
 |-- length: double (nullable = true)
 |-- level: string (nullable = true)
 |-- location: string (nullable = true)
 |-- method: string (nullable = true)
 |-- page: string (nullable = true)
 |-- registration: long (nullable = true)
 |-- sessionId: long (nullable = true)
 |-- song: string (nullable = true)
 |-- status: long (nullable = true)
 |-- ts: long (nullable = true)
 |-- userAgent: string (nullable = true)
 |-- userId: string (nullable = true)

在查看数据集的头部后,我们会发现所有的用户交互都记录在页面的列中。

当大多数用户继续播放下一首歌曲时,有一些用户进入了“取消”页面——他们都通过“取消确认”页面确认了他们的取消(参见相同数量的“取消”和“取消确认”.我们将搅动活动具体定义为取消确认的数量。第列有“取消确认”的用户将是我们特别感兴趣的搅动用户。

特征工程

我们已经成功地识别了流失的用户,现在是时候用我们的商业思维来思考用户流失的影响因素了。 如果你真的很讨厌你的音乐流媒体服务,你会怎么做? 我想出了下面 7 个特性,

  1. 代表性用户互动

我们有理由期待其他一些用户互动最终会导致我们的用户流失。我们可以使用箱线图来执行第一级过滤。箱线图将有效地帮助我们可视化特定数据分布的最小值、第 25 个百分点、平均值、第 75 个百分点和最大值。通过绘制搅动和非搅动用户的箱线图,我们可以清楚地解释特定交互中两类用户之间的差异。

以下相互作用显示了两组之间的显著分布差异,

  • 添加好友——喝醉的用户不太可能添加好友
  • 添加到播放列表 —喝醉的用户不太可能添加到播放列表
  • 升级 —被搅动的用户有各种各样的升级活动
  • 下一首歌——喝醉的用户不太可能播放下一首歌
  • 拇指朝上——喝醉的用户不太可能竖起大拇指
  • 滚动广告——被搅动的用户在滚动广告上有更广泛的传播
  • 设置 —搅动的用户不太可能访问设置页面
  • 注销 —大量用户不太可能注销(由于登录次数减少)
  • 帮助——不焦虑的用户更有可能寻求帮助
  • 首页——不安的用户不太可能访问主页

请注意,我们所有的用户交互都在同一列中,我们需要透视和聚合每个客户的某个交互的总数。基于以上筛选,我们将去掉一些不太重要的交互。

**events = events.drop('firstName', 'lastName', 'auth',
                      'gender', 'song','artist',
                      'status', 'method', 'location', 
                      'registration', 'itemInSession')****events_pivot = (events.groupby(["userId"])
                      .pivot("page")
                      .count()
                      .fillna(0))****events_pivot = events_pivot.drop('About', 'Cancel', 'Login',  
                                 'Submit Registration','Register',
                                 'Save Settings')**

2.平均音乐播放时间

对我自己来说,我使用它的时间可能会比普通用户短。因此,用户花在播放音乐上的平均时间长度将是一个非常重要的因素。一个简单的可视化显示确认结果如下。

我们将把这个特性添加到我们的 events_pivot 表中,

# filter events log to contain only next song
**events_songs = events.filter(events.page == 'NextSong')**# Total songs length played
**total_length = (events_songs.groupby(events_songs.userId)
                           .agg(sum('length')))**# join events pivot
**events_pivot = (events_pivot.join(total_length, on = 'userId', 
                                  how = 'left')
                     .withColumnRenamed("Cancellation Confirmation",
                                        "Churn")
                     .withColumnRenamed("sum(length)", 
                                        "total_length"))**

3.活动天数

我们还期望搅动组和非搅动组之间活动天数的差异。由于 datetime 列只包含以秒为单位的单位,我们将需要使用一个窗口函数来合计每个客户的总活动时间,并将该值转换为天数。我们将把这个特性添加到 events_pivot 中。

**convert = 1000*60*60*24** # conversion factor to days# Find minimum/maximum time stamp of each user
**min_timestmp = events.select(["userId", "ts"])
                     .groupby("userId")
                     .min("ts")****max_timestmp = events.select(["userId", "ts"])
                     .groupby("userId")
                     .max("ts")**# Find days active of each user
**daysActive = min_timestmp.join(max_timestmp, on="userId")
daysActive = (daysActive.withColumn("days_active", 
                      (col("max(ts)")-col("min(ts)")) / convert))****daysActive = daysActive.select(["userId", "days_active"])**# join events pivot
**events_pivot = events_pivot.join(daysActive, 
                                 on = 'userId',
                                 how = 'left')**

4.付费用户的天数

类似地,我们也可以通过使用窗口函数来计算付费用户的天数,我们只需要为要成为付费用户的客户添加一个过滤器。

# Find minimum/maximum time stamp of each user as paid user
**paid_min_ts = events.filter(events.level == 'paid')
                    .groupby("userId").min("ts")****paid_max_ts = events.filter(events.level == 'paid')
                    .groupby("userId").max("ts")**# Find days as paid user of each user**daysPaid = paid_min_ts.join(paid_max_ts, on="userId")
daysPaid = (daysPaid.withColumn("days_paid", 
                    (col("max(ts)")-col("min(ts)")) / convert))****daysPaid = daysPaid.select(["userId", "days_paid"])**# join events pivot
**events_pivot = events_pivot.join(daysPaid,
                                 on = 'userId', 
                                 how='left')**

5.免费用户的天数

现在使用免费用户过滤器,我们可以找到每个客户作为免费用户的天数,

# Find minimum/maximum time stamp of each user as paid user
**free_min_ts = events.filter(events.level == 'free')
                    .groupby("userId").min("ts")
free_max_ts = events.filter(events.level == 'free')
                    .groupby("userId").max("ts")**# Find days as paid user of each user
**daysFree = free_min_ts.join(free_max_ts, on="userId")
daysFree = (daysFree.withColumn("days_free", 
                        (col("max(ts)")-col("min(ts)")) / convert))****daysFree = daysFree.select(["userId", "days_free"])**# join events pivot
**events_pivot = events_pivot.join(daysFree, 
                                on = 'userId', 
                                how='left')**

6.会议次数

音乐播放的次数也可能是一个影响因素。由于这个数据集中有 sessionId ,我们可以使用 groupby 子句直接计算每个用户的惟一 Id 的数量。

# count the number of sessions **numSessions = (events.select(["userId", "sessionId"])
                      .distinct()
                      .groupby("userId")
                       .count()
                      .withColumnRenamed("count", "num_session**s"))# join events pivot
**events_pivot = events_pivot.join(numSessions,
                                 on = 'userId',
                                 how = 'left')**

7.用户访问代理

流服务在不同的用户代理上可能具有不同的性能。我们将尝试在模型中加入这一因素。由于有 56 个不同的用户代理,我们将使用 Spark 的 one-hot 编码器将这些不同的用户代理转换成一个向量。

# find user access agents, and perform one-hot encoding on the user 
**userAgents = events.select(['userId', 'userAgent']).distinct()
userAgents = userAgents.fillna('Unknown')**# build string indexer
**stringIndexer = StringIndexer(inputCol="userAgent",      
                              outputCol="userAgentIndex")****model = stringIndexer.fit(userAgents)
userAgents = model.transform(userAgents)**# one hot encode userAgent column
**encoder = OneHotEncoder(inputCol="userAgentIndex", 
                        outputCol="userAgentVec")
userAgents = encoder.transform(userAgents)
                    .select(['userId', 'userAgentVec'])**# join events pivot
**events_pivot = events_pivot.join(userAgents, 
                                 on = 'userId',
                                 how ='left')**

模型构建

在我们设计了适当的功能后,我们将构建三个模型——逻辑回归、随机森林和梯度推进树。为了避免编写冗余代码,我们将构建 stage 对象,并在管道末端用不同的分类器构建管道。

# Split data into train and test set
**events_pivot = events_pivot.withColumnRenamed('Churn', 'label')
training, test = events_pivot.randomSplit([0.8, 0.2])**# Create vector from feature data
**feature_names = events_pivot.drop('label', 'userId').schema.names
vec_asembler = VectorAssembler(inputCols = feature_names,
                               outputCol = "Features")**# Scale each column
**scalar = MinMaxScaler(inputCol="Features", 
                      outputCol="ScaledFeatures")**# Build classifiers
**rf = RandomForestClassifier(featuresCol="ScaledFeatures", 
                            labelCol="label",
                            numTrees = 50, 
                            featureSubsetStrategy='sqrt')****lr = LogisticRegression(featuresCol="ScaledFeatures",  
                        labelCol="label", 
                        maxIter=10,
                        regParam=0.01)****gbt = GBTClassifier(featuresCol="ScaledFeatures", 
                    labelCol="label")**# Consturct 3 pipelines
**pipeline_rf = Pipeline(stages=[vec_asembler, scalar, rf])
pipeline_lr = Pipeline(stages=[vec_asembler, scalar, lr])
pipeline_gbt = Pipeline(stages=[vec_asembler, scalar, gbt])**# Fit the models
**rf_model = pipeline_rf.fit(training)
lr_model = pipeline_lr.fit(training)
gbt_model = pipeline_gbt.fit(training)**

现在三个对象 rf_modellr_modelgbt_model ,代表了 3 种不同的拟合模型。

车型评价

我们将测试拟合模型的性能,并选择具有最佳性能的模型作为最终模型。我们将首先构建一个专门用于此目的的函数,

**def modelEvaluations(model, metric, data):**
    """ Evaluate a machine learning model's performance 
        Input: 
            model - pipeline object
            metric - the metric of the evaluations
            data - data being evaluated
        Output:
            [score, confusion matrix]
    """
    # generate predictions
    **evaluator = MulticlassClassificationEvaluator(
                metricName = metric)
    predictions = model.transform(data)**

    # calcualte score
 **score = evaluator.evaluate(predictions)
    confusion_matrix = (predictions.groupby("label")
                                   .pivot("prediction")
                                   .count()
                                   .toPandas())
    return [score, confusion_matrix]**

我们将调用上面的函数来评估上面的模型

**f1_rf, conf_mtx_rf = modelEvaluations(rf_model, 'f1', test)
f1_lr, conf_mtx_lr = modelEvaluations(lr_model, 'f1', test)
f1_gbt, conf_mtx_gbt = modelEvaluations(gbt_model, 'f1', test)**

梯度推进模型在测试集中表现出最好的性能(F1 分数)。F1 分数定义为精确度和召回率的调和平均值,计算如下

精度是计算正确的正类标识的比例,在数学表达式中是这样的

精度= tp/(tp + fp)

召回是计算实际正类样本被正确识别的比例,在数学表达式中,

召回= tp/(tp + fn)

您可能想知道为什么我们选择更复杂的度量标准而不是最直观的准确性,这是因为数据集中存在不平衡的类分布。由于只有一小部分用户最终会流失,我们希望我们的模型能够正确识别他们,而不是追求高整体性能。想象一下,如果只有 6%的客户会在真实的人口分布中流失,预测每个人都不会流失仍然会给我们 94%的准确性。另一方面,F1 分数将惩罚单个班级的不良表现,这将有效地缓解这些问题。不平衡类特征将出现在每个流失预测问题中——F1 将始终是未来使用的指标。

特征重要性

我们将利用特征重要性函数,并可视化我们构建的每个特征的相对重要性等级。由于最后一个特性 userAgentVec 实际上是一个热编码向量,我们将把 userAgentVec 特性视为一个。下面的代码将对从独热编码向量获得的所有子特征的所有特征重要性值求和。

**feature_importances = np.array(gbt_model.stages[-1]
                               .featureImportances)****userAgentVec = feature_importances[len(feature_names) :].sum()
feature_importances = feature_importances[:len(feature_names)]
                      + [userAgentVec]**

现在我们绘制梯度推进树的特征重要性。

我们构建的大多数功能都是用户流失的重要因素,其中 days_active 是最重要的因素。

全数据集运行

我们已经构建了适当的框架——我们准备按照上面相同的步骤,使用 AWS 的 EMR 服务让模型在完整的 12 GB 数据集上运行。我们将通过以下方式初始化会话

# Create spark session
**spark = (SparkSession 
        .builder 
        .appName("Sparkify") 
        .getOrCreate())**# Read in full sparkify dataset
**event_data = "s3n://dsnd-sparkify/sparkify_event_data.json"
events = spark.read.json(event_data)**

我们不再重复这些步骤——我已经在 nbviewer 网站上附上了完整的脚本。

最终,梯度推进模式产生了 0.8896 的 F1 成绩,这是一个很棒的表现。

+-----+----+---+
|label| 0.0|1.0|
+-----+----+---+
|    0|1612| 70|
|    1| 163|344|
+-----+----+---+

经营战略

我们经历了怎样的旅程——但我们还没有完成我们的使命。在数据科学领域,每个模型背后都有一个商业意图。有了我们创造的功能重要性,我们肯定可以想出一些商业策略来应对客户的抱怨。我们将简要讨论两种可能的策略,它们将真正为我们的提供商带来一些价值。

我们知道活跃天数是最重要的因素,我们可以建议高层管理人员建立一个奖励系统,鼓励低活跃度用户长时间保持在线

此外,由于用户用来访问服务的代理也很重要,我们还可以找出表现不佳的代理,并让我们的工程团队专门解决这个问题。

我希望你能像我喜欢写这篇文章一样喜欢读这篇文章。我们一起使用大数据分析框架 Spark 来构建端到端的机器学习工作流,以从用户日志中识别潜在的音乐流媒体服务客户。我们执行了以下步骤,

  1. 探索性数据分析
  2. 特征工程
  3. 模型结构
  4. 模型评估
  5. 模型放大
  6. 商业策略

由于我们正在处理的数据规模庞大,执行超参数搜索变得尤为困难。可以想象,让笔记本电脑长时间开着并不是使用资源的最有效方式。使用 ssh 来保持程序运行的一些好技巧肯定有助于应对这一挑战。

如果说我们应该从这篇文章中学到什么的话,那就是我们在故事开始时提到的那一点。作为杰出的工程师,我们经常被吸引去通过各种技术构建最好的高性能模型,但是我们的模型需要解决商业问题才能有价值。

理解数据工程术语:模式和主/分支

原文:https://towardsdatascience.com/understanding-data-engineering-jargon-schema-and-master-branch-525dff66fcb8?source=collection_archive---------17-----------------------

为非工程师解释的技术工程术语

Photo by Austin Distel on Unsplash

“如果一个人不了解一个人,他就会被认为是一个傻瓜。”——卡尔·荣格

说得好,郑先生。我们很多人都这样。当跨职能项目中出现错误时,我们倾向于责怪我们最不了解的一方。我这篇文章的目的是解释一些您可能从您的数据工程、分析师或科学家朋友那里听到的技术术语和概念。本文将集中在定义模式和分支,它们是什么,它们有什么不同,以及它们如何协同工作。

首先,简单介绍一下背景

让我们了解一下贵公司整体数据结构中发生了什么。一般来说,会有许多不同类型的数据进入并存储在公司的“数据湖”中。可以把数据湖想象成所有信息都被倾倒进去的地方,没有真正的结构。数据湖将以接收时的格式存储数据。可能有来自 Stripe 或 PayPal 的支付信息,可能有来自您的计费系统的发票信息,或者由移动应用程序提供的数据。数据也可以放入“数据仓库”中,在那里数据被更加结构化和格式化,以满足特定的用户需求。如果数据湖是一个通过溪流和雨水填充的大型水体,那么数据仓库将所有水源和瓶子按照体积、纯度和氟化物水平进行排列。我不会详细介绍数据湖或数据仓库中的数据结构,但只要知道这是数据的来源,就足以构建组织中其他成员使用的其他报告和表格。

这种数据收集是实时的,随着事件和事务的发生而实时发生。一天结束后,运行一个流程来收集完整的一天数据,并开始提取、转换和加载(也称为 ETL)这些数据到各种数据库中。用户和应用程序使用数据库中这些有组织的数据来进一步创建各种表格和报告。

Data from different sources are stored into the data lake. From here on a regular interval (usually daily after working hours) the databases retrieve data from the data lake and transform it into a more structured form.

ETL 过程由一组主指令(主代码)定义,该主指令由数据库中的模式使用。为了理解这最后一点,让我们更深入地研究模式和主/分支代码。

图式之谜被解开了

模式可以定义为数据组织背后的逻辑。用于开发一个表(或一组表)的数据就是模式。它将定义一个给定的表如何与另一个表相关,以及一个表应该由什么组成。模式很像 DNA。它是数据库的一部分,也是定义如何构建数据库的一组指令。

一个数据库通常包含一个主模式作为事实的来源。这个模式在主代码上运行,用于在其中创建表。当数据分析师和科学家查询数据时,他们通常会对这个主模式执行查询,因为它将提供最新的信息。

本质上,模式可以物理地位于服务器上。您可以直接进入服务器群,找到装有包含您的数据的磁盘的机架,该模式将始终由指导它的指令集来组织。

主和分支去神秘化

还记得我们一直在谈论模式背后的逻辑,或者主指令集吗?所有的代码都保存在一个代码库中,数据库将访问这个代码库来决定如何在其中构建表。你可能听说过 GitHub。GitHub 是模式代码所在的地方,存储库中有一个主代码库,简称为 master。当数据库从数据湖或其他来源获取数据时,它会查看主数据库来决定如何安排它的表。从这组代码中,创建了“主模式”。

如果有人想改变主密码呢?更改它可能会造成混乱,如果其他人不知道什么时候更改了什么,他们会感到困惑。当用户想要试验或者需要更新主文件时,他们会创建一个分支。分支是主模式的副本,主模式在构建表时不会考虑它。在分支中,用户可以在不影响主节点的情况下进行任何他们想要的更改。一旦他们完成了所做的更改,他们就可以将更改提交给 master。此时,代码通常会通过同行评审。一旦收到审查和批准,分支就被合并到主分支,现在当模式更新它们的表时,它将遵循更新的指令集。

The database here will follow the master code when determining how to structure the data. Feature 1.1 instructs it to simply add the variables a and b. A branch is created during day 2, but the database will still follow the master code. Once the feature 1.2 is merged prior to day 3, the database will use the updated master code to utilize the new feature where it will subtract the sum of a and b with x.

由于一个组织将有许多主代码的用户,因此可以同时创建多个分支。GitHub 等应用程序将管理单个用户分支,并在对主用户进行多次更改时帮助反映所做的更改。

但是分行代码影响的是什么数据库? 大问题!我们现在有一个问题,用户需要看到他们代码更改的结果,但是他们不应该针对当前模式运行分支代码,因为这会改变它们!这里的解决方案是制作一个不会按计划自动更新的模式副本。这有两个原因:

  1. 如果有大量用户使用他们自己的主模式副本进行更改,那么定期更新每个副本所需的资源将会非常低效。
  2. 我们希望避免对主模式进行任何更改,因为其他人可能会主动报告该模式。如果我们迭代代码更改并在模式中重建一个表,其他用户可能会查询不正确的数据。

因此,有了一个给定模式的副本,以及一个可以自由编辑代码的主模式分支,我们的工程师和分析师就可以自由地开发和试验,而不会影响主模式。由于复制的模式中的表通常不会使用数据湖中的最新数据进行更新,因此这些复制的模式中的数据可能会变得“陈旧”。这不是问题,因为工程师只需要用新数据重建表。这是一个手动过程,因此为了节省时间,工程师将使用“陈旧的”数据来迭代他们的工作,直到他们真正需要用最新的数据来测试他们的工作。

综上所述,了解这些如何帮助你与你的分析师和工程师互动?

因此,主代码是模式逻辑所在的主要代码库,模式是在物理磁盘(可能是服务器)上维护的有组织的表,其中也可以制作模式的副本,主代码的分支允许工程师和分析师在不影响主模式的情况下构建新功能。

让我们用这些新发现的知识浏览几个用例:

  1. 工程师向您提交了一份新创建的收入报告,但总额计算有误。
    • 分支代码可能是正确的,但是模式副本尚未更新到主模式的数据。

    • 分支代码可能包含错误,导致报告不正确,但由于该代码尚未合并到主代码库中,因此不存在影响其他相关报告的风险。

  2. 一份新的报告先前通过了测试,但第二天同样的报告失败了。
    • 代码可能已经通过了您的审查,并已提交给主模块,但是代码还没有经过进一步的同行审查,而这是在代码与主模块合并之前所需要的。

    • 代码可能已与 master 合并,但运行夜间批处理报告的数据库可能有延迟。代码仍然有效,工程师只需解决与工作负载相关的问题,即可完成夜间批处理过程。(这就是为什么我们不自动更新批处理中的每个模式,这会降低夜间批处理的速度)。

思考这些可能性有助于解决问题,并在工程师、分析师和他们的各种商业伙伴之间创造更好的期望。

从开发人员的角度来看,在与业务伙伴的沟通中保持透明,以帮助他们理解存在的开发阶段,并设置检查点,以便他们知道数据何时真正准备好进行审查。作为工程师提供的报告的消费者,您的关注点要清晰简洁,并询问您的工程师他们如何确保数据的完整性。

随着对这些术语的更多理解,以及对数据工程过程的更多了解,我希望每个商业伙伴在合作时能有更多的共识。

了解数据集转换

原文:https://towardsdatascience.com/understanding-dataset-shift-f2a5a262a766?source=collection_archive---------0-----------------------

如何不被数据捉弄?

数据集转移是一种具有挑战性的情况,其中输入和输出的联合分布在训练和测试阶段之间不同。 数据集转移,麻省理工学院出版社。

数据集转移是其中一个简单的主题,也许简单到被认为是显而易见的。在我自己的数据科学课上,这个想法被简单地讨论过,但是,我认为对数据集转移的原因和表现的更深入的讨论对数据科学社区是有益的。

这篇文章的主题可以用一句话来概括:

数据集移位是指训练和测试分布不同时。

An example of differing training and test distributions.

虽然你可能会嘲笑这种说法的琐碎,但这可能是我在查看 Kaggle 挑战的解决方案时看到的最常见的问题。在某些方面,对数据集转移的深刻理解是赢得 Kaggle 竞赛的关键。

数据集偏移不是一个标准术语,有时被称为概念偏移概念漂移分类的变化环境的变化分类学习中的对比挖掘断点数据间的断裂。

数据集转移主要发生在监督学习的机器学习范式和半监督学习的混合范式中。

数据集偏移的问题可能源于输入特征的利用方式、训练和测试集的选择方式、数据稀疏性、由于非稳定环境导致的数据分布偏移,以及深层神经网络层内激活模式的变化。

为什么数据集转移很重要?

它依赖于应用程序,因此很大程度上依赖于数据科学家的技能来检查和解决。例如,如何确定数据集何时发生了足够大的变化,从而给我们的算法带来了问题?如果只有某些特征开始发散,我们如何确定通过移除特征的准确度损失和通过错误的数据分布的准确度损失之间的权衡?

在本文中,我将讨论不同类型的数据集转移、它们的出现可能带来的问题,以及可以用来避免它们的当前最佳实践。本文不包含代码示例,纯粹是概念性的。为了便于演示,将使用分类示例。

我们将研究数据集转移的多种表现形式:

  • 协变量移位
  • 先验概率转移
  • 观念转变
  • 内部协变移位(协变移位的一个重要亚型)

这是机器学习中一个巨大而重要的话题,所以不要期望对这个领域有一个全面的概述。如果读者对这一主题感兴趣,那么会有大量关于这一主题的研究文章——其中绝大多数集中在协变量转换上。

协变量移位

在数据集移位的所有表现形式中,最容易理解的是协变量移位。

协变量移位是指协变量的分布变化,具体来说,就是自变量的分布变化。这通常是由于潜在变量状态的变化,可能是时间的(甚至是时间过程的平稳性的变化),或空间的,或不太明显的。——Quora

协变量移位是一个学术术语,指数据分布(即我们的输入要素)发生变化的情况。

以下是协变量移位可能导致问题的一些例子:

  • 人脸识别算法主要针对较年轻的人脸进行训练,但数据集中有更大比例的老年人脸。
  • 预测预期寿命,但在吸烟者的训练集中样本很少,而在训练集中样本更多。
  • 将图像分类为猫或狗,并从训练集中省略在测试集中看到的某些物种。

在这种情况下,输入和输出之间的基本关系没有变化(回归线仍然相同),但是该关系的一部分是数据稀疏的、省略的或错误表示的,使得测试集和训练集不反映相同的分布。

在执行交叉验证时,协方差变化会导致许多问题。交叉验证在没有协变量转移的情况下几乎是无偏的,但在协变量转移的情况下会有很大的偏差!

先验概率转移

协变量移位关注特征( x )分布的变化,先验概率移位关注类别变量 y 分布的变化。

这种类型的转换可能看起来更令人困惑,但它本质上是协变量转换的反向转换吗?一种直观的思考方式可能是考虑一个不平衡的数据集。

如果训练集对您收到的垃圾邮件的数量具有相同的先验概率(即,一封电子邮件是垃圾邮件的概率是 0.5),那么我们预计 50%的训练集包含垃圾邮件,50%包含非垃圾邮件。

如果在现实中,只有 90%的电子邮件是垃圾邮件(也许不是不可能的),那么我们的类别变量的先验概率已经改变。这种想法与数据稀疏性和有偏差的特征选择有关,它们是导致协方差偏移的因素,但它们不是影响我们的输入分布,而是影响我们的输出分布。

这个问题只出现在 Y → X 问题中,通常与朴素贝叶斯有关(因此出现了垃圾邮件示例,因为朴素贝叶斯通常用于过滤垃圾邮件)。

下图中的先验概率转移取自机器学习一书中的数据集转移,很好地说明了这种情况。

概念漂移

概念漂移不同于协变量和先验概率转移,因为它与数据分布或类别分布无关,而是与两个变量之间的关系有关。

思考这个观点的一个直观方法是看时间序列分析。

在时间序列分析中,通常在执行任何分析之前检查时间序列是否是平稳的,因为平稳时间序列比非平稳时间序列更容易分析。

为什么会这样呢?

这更容易,因为输入和输出之间的关系并没有持续变化!有多种方法可以消除时间序列的趋势,使其保持平稳,但这并不总是有效的(例如股票指数通常包含很少的自相关或长期变化)。

举一个更具体的例子,假设我们考察了 2008 年金融危机前公司的利润,并根据行业、员工数量、产品信息等因素制作了一个算法来预测利润。如果我们的算法是根据 2000 年至 2007 年的数据训练的,但在金融危机后没有用它来预测同样的信息,它可能表现不佳。

那么是什么改变了呢?很明显,由于新的社会经济环境,投入和产出之间的整体关系发生了变化,如果这些没有反映在我们的变量中(例如,金融危机发生日期的虚拟变量和该日期前后的培训数据),那么我们的模型将遭受概念转变的后果。

在我们的具体案例中,我们希望在金融危机后的几年里看到利润发生显著变化(这是一个中断时间序列的例子)。

内部协变量移位

这个话题最近引起兴趣的一个原因是由于深度神经网络(因此有“内部”一词)的隐藏层中的协方差偏移的可疑影响。

研究人员发现,由于来自给定隐藏层的输出(用作后续层的输入)的激活分布的变化,网络层可能遭受协变量移位,这可能妨碍深度神经网络的训练。

The situation without batch normalization, network activations are exposed to varying data input distributions that propagate through the network and distort the learned distributions.

这个想法就是批量归一化的刺激,由 Christian Szegedy 和 Sergey Ioffe 在他们 2015 年的论文 “批量归一化:通过减少内部协变量移位加速深度网络训练” 中提出。

作者提出,隐藏层中的内部协变量移位会减慢训练,并且需要较低的学习速率和仔细的参数初始化。他们通过添加一个批处理规范化层来规范化隐藏层的输入,从而解决了这个问题。

该批次规范层获取一批样本的平均值和标准差,并使用它们来标准化输入。这也给输入增加了一些噪声(因为不同批次之间的平均值和标准偏差中固有的噪声),这有助于调整网络。

How batch normalization fits within the network architecture of deep neural networks.

该问题用于将变化的分布转化为更稳定的内部数据分布(更少的漂移/振荡),这有助于稳定学习。

Varying data distributions across batches are normalized via a batch normalization layer in order to stabilize the data distribution used as input to subsequent layers in a deep neural network.

批处理规范化现在在深度学习社区中被很好地采用,尽管最近的一篇论文暗示,从该技术获得的改进结果可能不纯粹是由于内部协变量偏移的抑制,而可能是平滑网络损失前景的结果。

对于那些不熟悉批处理规范化、其目的和实现的人,我建议看看吴恩达的相关 Youtube 视频,其中一个视频链接如下。

数据集转移的主要原因

数据集偏移的两个最常见原因是(1) 样本选择偏差和(2) 非稳定环境

需要注意的是,这些都不是数据集移位的类型,并不总是会导致数据集移位。它们只是我们的数据中可能发生数据集偏移的潜在原因。

样本选择偏差:分布中的差异是由于通过有偏差的方法获得的训练数据,因此不能可靠地代表分类器将被部署的操作环境(用机器学习的术语来说,将构成测试集)。

非稳定环境:当训练环境不同于测试环境时,无论是由于时间还是空间变化。

样本选择偏差

样本选择偏差不是任何算法或数据处理的缺陷。这纯粹是数据收集或标记过程中的系统缺陷,导致从总体中选择的训练样本不一致,从而导致训练过程中形成偏差。

样本选择偏差是协方差变动的一种形式,因为我们正在影响我们的数据分布。

这可以被认为是对操作环境的曲解,因此我们的模型将其训练环境优化为一个人为的或精选的操作环境。

当处理不平衡分类时,由样本选择偏差导致的数据集偏移尤其相关,因为在高度不平衡的域中,少数类对单一分类错误特别敏感,这是因为它所呈现的样本数量通常很少。

Example of the impact of dataset shift in imbalanced domains.

在最极端的情况下,少数类的一个错误分类示例就可能导致性能的显著下降。

不稳定的环境

在现实世界的应用 it 世界的应用中,数据通常不是(时间或空间)静态的。

最相关的非平稳场景之一涉及对立的分类问题,例如垃圾邮件过滤和网络入侵检测。

这种类型的问题在机器学习领域受到越来越多的关注,并且通常处理非静态环境,因为存在试图绕过现有分类器的学习概念的对手。就机器学习任务而言,这个对手扭曲了测试集,使其变得不同于训练集,从而引入任何可能的数据集转移。

识别数据集转移

有多种方法可用于确定数据集中是否存在移位及其严重程度。

Tree diagram showing the methods of identifying dataset shift.

无监督的方法可能是识别数据集变化的最有用的方法,因为它们不需要进行事后分析,这种延迟在一些生产系统中是无法承受的。存在监督方法,其本质上观察模型运行时不断增加的错误以及外部维持(验证集)的性能。

统计距离
s统计距离 方法对于检测您的模型预测是否随时间变化非常有用。这是通过创建和使用直方图来实现的。通过制作直方图,您不仅能够检测模型预测是否随时间变化,还可以检查最重要的特征是否随时间变化。简而言之,你形成训练数据的直方图,随着时间的推移跟踪它们,并比较它们以查看任何变化。金融机构通常在信用评分模型中使用这种方法。

Two distributions are their KL-divergence (effectively the ‘distance’ between the two distributions). If the two distributions overlap, they are effectively the same distribution and the KL-divergence is zero.

有几个指标可用于监控模型预测随时间的变化。其中包括 人口稳定指数【PSI】柯尔莫哥洛夫-斯米尔诺夫统计库尔贝克-勒布勒散度 (或其他-散度)直方图交集

Data plotted along one feature axis for a training and test set. There is ~72% intersection of the distributions which indicates a reasonable level of covariate shift between the distributions.

这种方法的主要缺点是对于高维或稀疏特征来说效果不是很好。然而,它可能非常有用,并且在我看来应该是处理这个问题时首先要尝试的。

A comparison between KL-divergence, KS statistic, PSI, and histogram intersection for two examples. The left example shows little to no covariate shift, whilst the right example shows a substantial covariate shift. Notice how it affects the expected values of the statistical distances.

2)新颖性检测
一种更适合计算机视觉等相当复杂领域的方法是 新颖性检测 。这个想法是创建一个模型来模拟源分布。给定一个新的数据点,您尝试测试该数据点从源分布中提取的可能性。对于这种方法,您可以使用各种技术,例如大多数常见库中可用的单类支持向量机。

如果您处于同质但非常复杂的交互状态(例如,视觉、听觉或遥感),那么这是一种您应该研究的方法,因为在这种情况下,统计距离(直方图方法)将不是一种有效的方法。

这种方法的主要缺点是它不能明确地告诉你发生了什么变化,只能告诉你已经发生了变化。

3)判别距离
判别距离 的方法不太常见,尽管如此,它也可以是有效的。直觉上,你想训练一个分类器来检测一个例子是来自源领域还是目标领域。您可以使用训练误差作为这两个分布之间的距离的代理。误差越大,它们越接近(即分类器不能区分源域和目标域)。

判别距离具有广泛的适用性和高维性。虽然这需要时间并且可能非常复杂,但是如果您正在进行领域适应,这种方法是一种有用的技术(对于一些深度学习方法,这可能是唯一可行的技术)。

这种方法对高维稀疏数据有很好的效果,适用范围广。然而,它只能离线完成,并且比以前的方法实现起来更复杂。

处理数据集移位

如何纠正数据集偏移?如果可能的话,你应该经常再培训。当然,在某些情况下,这可能是不可能的,例如,如果再培训存在延迟问题。在这种情况下,有几种技术可以纠正数据集偏移。

1)特征移除

通过利用上面讨论的用于识别协变量偏移的统计距离方法,我们可以使用这些方法作为偏移程度的度量。我们可以为可接受的偏移水平设定一个界限,通过分析单个特征或消融研究,我们可以确定哪些特征对偏移负有最大责任,并将其从数据集中移除。

如您所料,在移除导致协变量偏移的特征和增加额外特征并容忍某些协变量偏移之间存在权衡。这种权衡是数据科学家需要根据具体情况进行评估的。

一个在训练和测试过程中差别很大,但是不能给你很多预测能力的特性,应该总是被放弃。

例如,PSI 用于风险管理,0.25 的任意值用作限制,超过该值则视为重大变化。

2)重要性重新加权
重要性重新加权的主要思想是你想得到与你的测试实例非常相似的训练实例。本质上,您尝试更改您的训练数据集,使其看起来像是从测试数据集提取的。这个方法唯一需要的是测试域的未标记的例子。这可能导致测试集的数据泄漏。

On the left, we have our typical training set and in the center our test set. We estimate the data probability of the training and test sets and use this to rescale our training set to produce the training set on the right (notice the size of the points has got larger, this represents the ‘weight’ of the training example).

为了弄清楚这是如何工作的,我们基本上通过训练和测试集的相对概率来重新加权每个训练示例。我们可以通过密度估计、通过核方法(如核均值匹配)或通过区别性重新加权来做到这一点。

3)对抗性搜索

对抗搜索方法使用对抗模型,其中学习算法试图构建一个预测器,该预测器对测试时的特征删除具有鲁棒性。

该问题被公式化为寻找相对于对手的最优极大极小策略,该对手删除了特征,并且表明该最优策略可以通过求解二次规划或者使用有效的最优化束方法来找到。

文献中已经对协变量移位进行了广泛的研究,并且已经发表了许多关于协变量移位的建议。其中最重要的包括:

  • 对数似然函数的加权(Shimodaira,2000 年)
  • 重要性加权交叉验证(杉山等人,2007 年 JMLR)
  • 集成优化问题。辨别学习。(比克尔等人,2009 年 JMRL)
  • 核均值匹配( Gretton 等人,2009 )
  • 对抗性搜索( Globerson 等人,2009
  • Frank-Wolfe 算法(【文】等,2015 )

最终意见

在我看来,数据集转移是一个极其重要的话题,但却被数据科学和机器学习领域的人们低估了。

鉴于它可能对我们算法的性能产生的影响,我建议花一些时间研究如何正确处理数据,以便给你的模型更多的信心,并希望有更好的性能。

时事通讯

关于新博客文章和额外内容的更新,请注册我的时事通讯。

[## 时事通讯订阅

丰富您的学术之旅,加入一个由科学家,研究人员和行业专业人士组成的社区,以获得…

mailchi.mp](https://mailchi.mp/6304809e49e7/matthew-stewart)

参考

[1]http://iwann . ugr . es/2011/pdf/invited talk-FHerrera-iwann 11 . pdf

[2] J.G .莫雷诺-托雷斯、t .雷德尔、r .阿莱兹-罗德里格斯、N.V .舒拉、f .埃雷拉。分类中数据转移的统一观点。模式识别,2011,出版中。

[3] J .基诺内罗·坎德拉、m .杉山、a .施瓦格霍夫和 N. D .劳伦斯。机器学习中的数据集转移。麻省理工学院出版社,2009。

[4]雷德尔、霍恩斯和舒拉出版公司。分类器性能评估中分类器可变性的后果。,ICDM 2010 年 IEEE 数据挖掘国际会议论文集。

[5]莫雷诺-托雷斯,J. G .,&埃雷拉,F. (2010 年)。基于遗传规划的特征提取在不平衡领域中重叠和数据断裂的初步研究。《第十届智能系统设计与应用国际会议论文集》(ISDA,2010)(第 501–506 页)。

[6]https://www . NCBI . NLM . NIH . gov/PMC/articles/PMC 5070592/pdf/f 1000 research-5-10228 . pdf

使用 Scikit-Learn 了解决策树分类

原文:https://towardsdatascience.com/understanding-decision-tree-classification-with-scikit-learn-2ddf272731bd?source=collection_archive---------1-----------------------

基尼指数、管道和网格研究

Trees! (Source: Author’s Own Work)

决策树是用于分类和回归任务的最基本的机器学习工具之一。在这篇文章中,我将介绍:

  1. 以基尼系数作为衡量分裂标准的决策树算法。
  2. 决策树在现实数据分类中的应用。
  3. 创建一个管道,并使用 GridSearchCV 为分类任务选择最佳参数。所有代码和情节的 GitHub 链接将在文章末尾给出。

让我们开始吧…

决策树:

决策树算法的思想是学习一组可以导致决策的 if/else 问题。这里有一个很幼稚的给一个人分类的例子。如果他/她看完博客后拍手称赞,那么这个人被认为很棒,否则,就没那么棒了。该树基于是/否问题。但是即使对于数字数据,这个想法也是一样的。决策树可以结合数字和分类数据。下图显示了决策树中使用的一些术语—

这里我们可以看到节点是如何根据它们在 DT 中的位置来划分的。首先我们需要学习如何选择根节点,这里我们需要学习一个决定节点的标准,基尼系数。

基尼杂质:

基尼系数是以意大利统计学家科拉多基尼命名的。基尼不纯可以理解为一个最小化误分类概率的标准。为了理解决策树的定义(如图所示)以及我们如何构建决策树,让我们从一个非常简单的数据集开始,根据不同的天气条件,我们决定是否玩户外游戏。根据定义,仅包含一个类别的数据集将具有 0 基尼系数杂质在建立决策树时,我们的想法是选择基尼系数最小的特征作为根节点,以此类推...让我们从简单的数据集开始——

这里我们看到,根据 4 个特征(前景、温度、湿度、风),决定是否打网球。那么根节点上会有什么特性呢?决定我们将利用基尼系数。先说功能‘Outlook’吧。重要的是要注意,当“展望”是阴天,我们总是出去打网球。该节点只有一类样本(如下图所示)。

由于这些是分类变量,如果我们想要应用决策树分类器并适合数据,首先我们需要创建虚拟变量。

在这里,我们可以确定一件事,一旦我们创建了一个决策树,根节点将肯定是功能' Outlook _ cover '。让我们看看决策树(如下图所示)。当“展望 _ 阴”≤0.5 为假时,即当“展望阴”为 1 时,我们有一个基尼不纯度为 0 的纯样本的叶节点。

对于根节点,让我们计算基尼系数。由于我们有 9 个 1('是')和 5 个 0('否'),所以基尼杂质是~ 0.459。下一个节点是“湿度 _ 高”,因为该特征将为我们提供最少的基尼系数杂质。对于像这样的小数据集,我们总是可以使用 Pandas 数据框特征来检查这一点,并计算每个特征的基尼系数。一旦我们将“Outlook _ govern”作为根节点,我们将在叶节点中获得 4 个样本(“yes”)。在剩下的 10 个样本中,我们有 5 个“是”和“否”。然后选择“湿度高”作为特征,节点的基尼系数为 0.5,以此类推

Gini 杂质计算可能比熵计算有一点优势,因为熵需要计算 log [1] [2],所以为大型数据集构建决策树花费的时间可能更少。《Python 机器学习》一书的作者 Sebastian Raschka 有一篇精彩的博客,讲述了我们为什么使用熵而不是分类错误来构建决策树[3]。看看这个。让我们进入下一节,为一个真实的数据集实现决策树算法。

银行定期存款数据集:

这里我将使用加州大学欧文分校机器学习库中的银行营销数据集。网站所述数据集的摘要如下

摘要:该数据与一家葡萄牙银行机构的直接营销活动(电话)有关。分类的目标是预测客户是否会认购定期存款(变量 y)。

让我们用熊猫加载数据集

因此有 16 个特征,包括分类变量和数值变量,样本总数为 11162。首先,我们检查标签(“是”、“否”)是如何分布的。我们可以使用下面的 Seaborn countplot

数据集稍微偏向于更多的拒绝次数(“否”)。因此,稍后当数据集将被分为训练集和测试集时,我们将使用分层。我们还可以使用 Matplotlib Hist 检查一些数字变量的分布,如下所示

Histogram plots of two numerical features — Age and Balance.

数值变量的相关图(使用 Seaborn Heatmap 绘制)显示特征之间的相关性很小。一旦我们玩够了数据集,就让我们为应用 DT 算法准备数据集。由于有几个分类变量,我们需要将它们转换成虚拟变量。我放弃了“持续时间”这个特性,因为正如在数据集的描述中提到的,这个特性极大地影响了目标变量(当持续时间=0 时,y=“否”)。

下一步是选择特征和标签—

下一步是将数据集分成训练集和测试集—

应用决策树分类器:

接下来,我创建了一个 StandardScaler (标准化特性)和 DT 分类器的管道(参见下面关于特性标准化的注释)。我们可以从 Scikit-Learn 导入 DT 分类器作为from sklearn.tree import DecisionTreeClassifier 。为了确定 DT 分类器的最佳参数(分裂标准和最大树深度),我还使用了网格搜索交叉验证。下面的代码片段不言自明。

接下来,我应用了 3、4、5 倍交叉验证来确定最佳参数—

这里我们已经看到,如何在网格搜索交叉验证中成功地应用决策树分类器,来确定和优化最佳拟合参数。因为这个特殊的例子有 46 个特性,所以很难在一个中等大小的页面中可视化这个树。因此,我通过删除“月”特征(因为它创建了虚拟变量的最大数量,12)使数据框更简单,并再次进行拟合过程,特征数量现在是 35。

让我们用最大深度 6 和“基尼”作为标准来绘制决策树。使用 Scikit Learn 可视化树需要一些编码—

让我们更详细地看看树的根和前几个节点—

First few nodes of our decision tree!

在这里,我们看到“contanct_unknown”被选为根节点的特征。训练样本总数为 8929,基尼系数约为 0.5。接下来,我们看到一个数值变量“pdays”被选为属性以分割样本,等等…由于有如此多的特征和特别广泛分布的数值特征,手动构建一个树是非常困难的,这种情况可以与以前使用的更简单的网球数据集进行比较。我们还可以使用 DecisionTreeClassifier 类的feature_importance_属性来绘制在构建树时哪些特性是重要的。下图显示了—

正如从树中所预期的,作为树的根节点的“contanct _ unknown”具有最高的重要性,并且许多特征几乎没有或可以忽略的作用。具有低特征重要性或零特征重要性的特征可能意味着存在编码相同信息的另一个特征。

注意:关于这篇文章的另一个相关信息是,即使我使用了标准化,DT 算法对数据的缩放是完全不变的[4]。由于每个要素都是单独处理的,因此要素的缩放对分割没有任何影响。

综上所述,我们已经了解了使用基尼系数作为划分标准来构建 DT 的基本原理。我们还实现了网格搜索交叉验证,为我们的模型选择最佳参数,以对现实数据集进行分类。希望,你已经发现所有这些小有帮助!

保持坚强,干杯!

参考资料:

[1] 用决策树进行二元分类;塞巴斯蒂安·拉什卡

[2] 决策树:卡洛斯·盖斯特林,华盛顿大学,课堂讲稿。

【3】为什么要用熵来生长决策树?;塞巴斯蒂安·拉什卡

【4】用 Python 进行机器学习的介绍;吉多·穆勒

[5]sci kit-学习决策树手册。

[6] 链接所有代码和图像。

了解分类决策树(Python)

原文:https://towardsdatascience.com/understanding-decision-trees-for-classification-python-9663d683c952?source=collection_archive---------1-----------------------

This tutorial goes into extreme detail about how decision trees work.

由于各种原因,决策树是一种流行的监督学习方法。决策树的好处包括它们可以用于回归和分类,它们易于解释并且不需要特征缩放。它们有几个缺点,包括容易过度拟合。本教程涵盖了分类决策树,也称为分类树。

此外,本教程将涵盖:

  • 分类树的剖析(树的深度、根节点、决策节点、叶节点/终端节点)。
  • 分类树如何进行预测
  • 如何使用 scikit-learn (Python)制作分类树
  • 超参数调谐

和往常一样,本教程中使用的代码可以在我的 GitHub 上获得(解剖学预测)。就这样,让我们开始吧!

什么是分类树?

C 分类 a nd R 回归 T rees (CART)是 Leo Breiman 引入的一个术语,指的是可以学习用于分类或回归预测建模问题的决策树算法。这篇文章涵盖了分类树。

分类树

分类树本质上是一系列旨在指定分类的问题。下图是在 IRIS 数据集(花卉种类)上训练的分类树。根节点(棕色)和决策节点(蓝色)包含分解成子节点的问题。根节点只是最顶层的决策节点。换句话说,这是您开始遍历分类树的地方。叶节点(绿色)也称为终端节点,是不会分裂成更多节点的节点。叶节点是通过多数投票分配类别的地方。

Classification tree to classification one of three flower species (IRIS Dataset)

如何使用分类树

要使用分类树,从根节点(棕色)开始,遍历树,直到到达叶(终端)节点。使用下图中的分类树,假设你有一朵花瓣长度为 4.5 厘米的花,你想对它进行分类。从根节点开始,你会先问“花瓣长度(cm) ≤ 2.45 吗”?长度大于 2.45,因此该问题为假。进行到下一个决策节点,问“花瓣长度(cm) ≤ 4.95 吗”?这是真的,所以你可以预测花种为杂色。这只是一个例子。

分类树是如何生长的?(非数学版)

分类树学习一系列 if then 问题,每个问题涉及一个特征和一个分割点。看下面(A)的部分树,问题,“花瓣长度(cm) ≤ 2.45”根据某个值(本例中为 2.45)将数据拆分成两个分支。节点之间的值称为分割点。一个好的分割点值(能产生最大信息增益的值)能够很好地将一个类从其他类中分离出来。查看下图的 B 部分,分割点左侧的所有点被归类为 setosa,而分割点右侧的所有点被归类为 versicolor。

该图显示 setosa 在所有 38 个点上都被正确分类。它是一个纯节点。分类树不会在纯节点上分裂。这不会导致进一步的信息增益。然而,不纯的节点可以进一步分裂。请注意,图 B 的右侧显示许多点被错误分类为杂色。换句话说,它包含两个不同类别的点(virginica 和 versicolor)。分类树是一种贪婪算法,这意味着默认情况下,它将继续分裂,直到它有一个纯节点。同样,该算法为不纯节点选择最佳分裂点(我们将在下一节讨论数学方法)。

在上图中,树的最大深度为 2。树深度是对一棵树在进行预测之前可以分裂多少次的度量。这个过程可以继续进行更多的分裂,直到树尽可能的纯净。这个过程的许多重复的问题是,这可能导致具有许多节点的非常深的分类树。这通常会导致对训练数据集的过度拟合。幸运的是,大多数分类树实现允许您控制树的最大深度,从而减少过度拟合。例如,Python 的 scikit-learn 允许您预编译决策树。换句话说,您可以设置最大深度来阻止决策树超过某个深度。为了直观地了解最大深度,你可以看看下面的图片。

Classification trees of different depths fit on the IRIS dataset.

选择标准

This section answers how information gain and two criterion gini and entropy are calculated.

这一节实际上是关于理解什么是分类树上根/决策节点的好的分割点。对于给定的标准(本例中为基尼系数或熵),决策树在导致最大信息增益(IG)的特征和相应分裂点上分裂。粗略地说,我们可以将信息增益定义为

IG = information before splitting (parent) — information after splitting (children)

为了更清楚地了解父母和孩子,请看下面的决策树。

一个更合适的信息增益公式如下。

由于分类树具有二元分割,因此该公式可以简化为下面的公式。

用于衡量节点杂质的两个常用标准I是基尼指数和熵。

为了更好地理解这些公式,下图显示了如何使用基尼系数计算决策树的信息增益。

下图显示了如何使用熵计算决策树的信息增益。

我不打算对此进行更详细的讨论,因为应该注意的是,不同的杂质指标(基尼指数和熵)通常会产生类似的结果。下图显示基尼指数和熵是非常相似的杂质标准。我猜 Gini 是 scikit-learn 中的默认值的原因之一是熵的计算可能会慢一些(因为它使用了对数)。

Different impurity measures (Gini index and entropy) usually yield similar results. Thanks to Data Science StackExchange and Sebastian Raschka for the inspiration for this graph.

在结束这一部分之前,我应该注意到有各种不同的决策树算法。一些比较流行的算法是 ID3、C4.5 和 CART。Scikit-learn 使用了一个优化版本的 CART 算法。你可以在这里了解它的时间复杂度

使用 Python 的分类树

前面几节回顾了分类树的理论。学习如何用编程语言制作决策树是件好事,原因之一是处理数据有助于理解算法。

加载数据集

Iris 数据集是 scikit-learn 附带的数据集之一,不需要从外部网站下载任何文件。下面的代码加载 iris 数据集。

import pandas as pd
from sklearn.datasets import load_irisdata = load_iris()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['target'] = data.target

Original Pandas df (features + target)

将数据分为训练集和测试集

下面的代码执行训练测试分割,将 75%的数据放入训练集,25%的数据放入测试集。

X_train, X_test, Y_train, Y_test = train_test_split(df[data.feature_names], df['target'], random_state=0)

The colors in the image indicate which variable (X_train, X_test, Y_train, Y_test) the data from the dataframe df went to for this particular train test split.

请注意,决策树的一个好处是您不必标准化您的数据,不像 PCA 和逻辑回归对未标准化您的数据的影响很敏感

sci kit-学习 4 步建模模式

步骤 1: 导入您想要使用的模型

在 scikit-learn 中,所有的机器学习模型都是作为 Python 类实现的

from sklearn.tree import DecisionTreeClassifier

步骤 2: 制作模型的实例

在下面的代码中,我设置了max_depth = 2来预编译我的树,以确保它的深度不超过 2。我应该注意到,教程的下一部分将介绍如何为你的树选择一个最佳的max_depth

还要注意,在我下面的代码中,我做了random_state = 0,这样你可以得到和我一样的结果。

clf = DecisionTreeClassifier(max_depth = 2, 
                             random_state = 0)

第三步:根据数据训练模型

该模型正在学习 X(萼片长度、萼片宽度、花瓣长度和花瓣宽度)和 Y(鸢尾的种类)之间的关系

clf.fit(X_train, Y_train)

步骤 4: 预测看不见的(测试)数据的标签

# Predict for 1 observation
clf.predict(X_test.iloc[0].values.reshape(1, -1))# Predict for multiple observations
clf.predict(X_test[0:10])

请记住,预测只是叶节点中实例的主要类别。

衡量模型性能

虽然有其他方法来衡量模型性能(精确度、召回率、F1 分数、 ROC 曲线等),但我们将保持简单,使用精确度作为我们的衡量标准。

精确度定义为:

(正确预测的分数):正确预测/数据点总数

# The score method returns the accuracy of the model
score = clf.score(X_test, Y_test)
print(score)

调整树的深度

找到max_depth的最佳值是调整模型的一种方法。下面的代码输出了具有不同max_depth值的决策树的精确度。

# List of values to try for max_depth:
max_depth_range = list(range(1, 6))# List to store the accuracy for each value of max_depth:
accuracy = []for depth in max_depth_range:

    clf = DecisionTreeClassifier(max_depth = depth, 
                             random_state = 0)
    clf.fit(X_train, Y_train) score = clf.score(X_test, Y_test)
    accuracy.append(score)

由于下图显示,当参数max_depth大于或等于 3 时,模型的精确度最高,因此最好选择最不复杂的带max_depth = 3的模型。

I choose max_depth =3 as it it seems to be an accurate model and not the most complicated.

记住max_depth和决策树的深度不是一回事,这一点很重要。max_depth是一种预编译决策树的方法。换句话说,如果一棵树在某个深度已经尽可能纯净,它就不会继续分裂。下图显示了max_depth值为 3、4 和 5 的决策树。请注意,max_depth为 4 和 5 的树是相同的。它们的深度都是 4。

Notice how we have two of the exact same trees.

如果你想知道你训练的决策树有多深,你可以使用get_depth方法。此外,您可以通过使用get_n_leaves方法来获得经过训练的决策树的叶节点数。

虽然本教程涵盖了更改树的选择标准(基尼指数、熵等)和max_depth,但请记住,您还可以调整要分裂的节点的最小样本数(min_samples_leaf)、最大叶节点数(max_leaf_nodes)等等。

特征重要性

分类树的一个优点是它们相对容易解释。scikit-learn 中的分类树允许您计算特征重要性,这是基尼指数或熵由于给定特征的分割而减少的总量。Scikit-learn 为每个特性输出一个介于 0 和 1 之间的数字。所有要素的重要性都被规范化为总和为 1。下面的代码显示了决策树模型中每个功能的功能重要性。

importances = pd.DataFrame({'feature':X_train.columns,'importance':np.round(clf.feature_importances_,3)})
importances = importances.sort_values('importance',ascending=False)

在上面的例子中(对于虹膜的特定训练测试分割),花瓣宽度具有最高的特征重要性权重。我们可以通过查看相应的决策树来确认。

The only two features this decision tree splits on are petal width (cm) and petal length (cm).

请记住,如果某个要素的要素重要性值较低,这并不一定意味着该要素对预测不重要,而只是意味着该特定要素没有在树的特定早期级别被选择。也可能该特征与另一个信息特征相同或高度相关。要素重要性值也不会告诉您它们对哪个类具有很高的预测性,也不会告诉您可能会影响预测的要素之间的关系。值得注意的是,当执行交叉验证或类似操作时,可以使用来自多个训练测试分割的特征重要性值的平均值。

结束语

C 分类 aR 回归 T rees (CART)是一项相对古老的技术(1984 年),是更复杂技术的基础。决策树的好处包括它们可以用于回归和分类,它们不需要特征缩放,并且它们相对容易解释,因为你可以可视化决策树。我应该注意到,如果你对学习如何使用 matplotlib 和/或 Graphviz 可视化决策树感兴趣,我有一篇关于它的文章在这里。如果你对教程有任何问题或想法,欢迎在下面的评论中或通过 Twitter 联系。如果你想了解我如何制作我的一些图表,或者如何利用 Pandas、Matplotlib 或 Seaborn 库,请考虑参加我的Python for Data Visualization LinkedIn 学习课程

理解决策树(一劳永逸!)🙌

原文:https://towardsdatascience.com/understanding-decision-trees-once-and-for-all-2d891b1be579?source=collection_archive---------5-----------------------

Photo by David Vig on Unsplash

这篇文章是为完全的机器学习初学者编写的,他们希望理解一个最简单的算法,但也是最重要的算法之一,因为它的可解释性、预测能力以及在不同变体(如随机森林或梯度推进树)中的使用。
这篇文章也是写给所有和我一样奔向决策树(随机森林或梯度提升树)孩子的机器学习者,因为他们通常在 Kaggle 竞赛中表现更好,忘记了熟悉决策树,揭开了它所有的神秘面纱。🔮

文章的第一部分是关于建立数据集和模型,第二部分是关于理解模型:决策树。

这篇文章还附有一个笔记本,你可以在这里找到。

设置数据集和模型

定义目标

Iris sepal and petal

为了揭开决策树的神秘面纱,我们将使用著名的 iris 数据集。这个数据集由 4 个特征组成:花瓣长度花瓣宽度萼片长度萼片宽度。要预测的目标变量是鸢尾物种。其中有三种: 鸢尾云芝海滨鸢尾

Iris species

我们可以注意到的第一件事是,对于像我这样的非园艺专家来说,很难区分这三种鸢尾的区别。让我们用机器学习来做这个任务吧!😃

分析数据集

现在我们知道了我们要寻找什么,让我们更仔细地看看数据集。

First 10 rows of the iris dataset

在上图中,我们可以看到虹膜数据集的前 10 行。前 4 列是我们将用于预测目标鸢尾物种的前 4 个特征,由最后一列的数值表示:0 代表 setosa ,1 代表 versicolor ,2 代表 virginica
我们总共有 150 个观察值(150 行),每个鸢尾物种 50 个观察值:数据集是平衡的。

准备数据集和要素选择

为了便于我们理解决策树是如何工作的,我们将只研究两个特征:花瓣宽度萼片宽度。(然后,我们删除这些特征重复的观察结果,以便能够看到图表上的每个点,我们将绘制这些图来帮助我们理解)。

建模和评估

如您所知,所选的型号是…

…决策树!!!😉

在没有优化超参数(如树深度、节点中的最小叶子数或分割节点……)的情况下,仅用两个特征,我们已经在测试集上获得了 93%的准确率

准确度是好预测的数量与预测的数量之比。

这个指标很有意思,但并不能帮助我们理解决策树犯了什么错误。混乱矩阵可以帮助我们。

Confusion matrix of the Decision Tree on the testing set

上面的混淆矩阵由两个轴组成, y 轴目标,鸢尾物种的真实值, x 轴是决策树已经为该鸢尾预测的物种。在左上角的方块中,我们可以看到对于 5 个刚毛鸢尾来说,决策树已经预测了该物种的刚毛鸢尾。第二行显示在 16 个杂色鸢尾中,14 个被归类为杂色,2 个被误认为海滨鸢尾。这就是我们没有 100%准确率的原因。最后右下角的方块显示所有的海滨鸢尾都被归类为海滨鸢尾。多亏了混淆矩阵,我们可以恢复准确性:所有对角线元素都是好的预测,5+14+9=28,所有预测都是正方形,5+14+2+9=30。我们发现同样的准确率 28/30 = 93%。

了解决策树是如何构建的

现在我们已经建立了数据集和模型,我们终于可以开始构建决策树了!😜

可视化树

Decision Tree built after training

上面我们可以看到训练后建立的树。在训练阶段,决策树添加节点,将它们分成导致叶子的分支。

我们如何获得这棵树?🌳

由于训练集,从根到叶迭代地构建树。事实上,数据集被分成两部分:决策树用来训练自身的训练集和用来测量决策树的性能测试集,该测试集是通过将决策树的预测与真实值进行比较而构建的。

决策树的目标是将训练集分成同质区域,在这些区域中,根据给定的特征(这里是花瓣和萼片的宽度),只存在一种鸢尾属物种。

节点 0:根节点

上图根据选取的两个特征显示了鸢尾属物种的分布:x 轴上的花瓣宽度,y 轴上的萼片宽度。圆点的颜色代表鸢尾的种类:红色代表刚毛鸢尾,黄色代表杂色鸢尾,蓝色代表海滨鸢尾
上图右边的根节点,给了我们几个信息:
-有 68 个虹膜(' samples=68' ),我们可以在左边的图上数出来的虹膜点;

  • ' value=[23,20,25]' 描述了这些鸢尾在鸢尾属物种的三个可能类中的分配,即 setosa 为 23, versicolor 为 20,virginica 为 25;
    -'class = virginica '。这是决策树在根节点预测的鸢尾物种。之所以做出这个决定,是因为在根节点上,海滨锦鸡儿是数量最多的物种(25 海滨锦鸡儿,相比之下,20 云芝和 23)。这就是为什么左图的背景颜色是蓝色的原因,这是为 virginica 物种选择的颜色。
    根节点也给我们多了两条信息'花瓣宽度(cm) ≤ 0.8' 和' gini = 0.664' 。我们现在将讨论它们的含义…😃

节点 0:让学习开始吧!😎

左边的这个图与上一个图相同,但带有树的第一个决策边界:**petal width = 0.8 cm**

这个决策边界是怎么决定的?

通过测试分割数据集的所有可能的决策边界,并选择使两个分割的基尼系数杂质最小的一个,来决定决策边界。

什么是 基尼杂质

基尼系数是衡量随机选择的元素(此处为虹膜)被错误分类的概率的指标,即选择一个元素的概率乘以被错误分类的概率。如果我们对所有 J 个可能的类别求和,我们得到基尼不纯:

最后一个表达式是我们将要用来执行基尼系数测试的表达式。

让我们计算第一个节点的基尼系数

在根节点处,所有的数据点都是混合的。用上面的结果基尼不纯是:

这给了我们:

我们可以通过检查根节点上的基尼信息来验证这个数字:‘基尼= 0.664’。对于第一个节点,我们的基尼系数为 0.664。

让我们回到第一个决策边界

确定一个决策边界要问的问题是: 如何分裂鸢尾物种,以便我们创建更同质的群体?
直观地,我们可以在上面的图表中观察到,我们可以通过沿着花瓣宽度轴分割数据集来创建一个仅包含 setosa 物种的同质组。

但是算法没有直觉。那么它是如何找到最佳分割点的呢?

  • 它将沿着所有特征尝试所有可能的边界,即所有轴花瓣宽度萼片宽度
  • 对于每次分割,该算法将计算所创建的两个组的基尼系数。
  • 最后,它将选择给出两组的最低基尼系数杂质的决策边界(或者对每组的基尼系数杂质求和,或者求平均值)。

让我们回到第一个节点和第一次拆分

在根节点的情况下,该算法已经发现,在所有可能的分裂中,具有**petal width = 0.8 cm**的分裂给出最低的 Gini 杂质。
左叶的基尼杂质为:

我们用树形图验证了这个结果。这个结果并不令人惊讶,因为在与图的左边部分相匹配的左叶中,我们只有 setosa iris,所以该组是非常同质的,基尼系数是同质性的度量。

右叶的基尼系数为:

我们发现与树形图中显示的结果相同。此外,这种基尼系数接近 0.5,因为海滨鸢尾和杂色鸢尾几乎一样多。

节点 1

所描述的过程将迭代地继续,直到树成功或试图分离所有的数据点,或者对算法应用限制条件,如树深度的限制。

由于**petal width <= 0.8 cm**的 Gini 杂质为 0,即我们不能有一个更同质的组,算法将不再尝试分割这一部分,并将集中在树的右边部分。

直观上,决策树继续使用花瓣宽度功能将右边部分一分为二。事实上,使用花瓣宽度而不是萼片宽度似乎更容易创建同质群组。在**petal width <= 0.8 cm** 分裂产生了一个只有海滨鸢尾的群体(因此基尼系数为 0)。设法创造一个只有一个物种的群体并不总是最好的选择,我们将在下一次分裂中看到…

由于算法已经创建了一个只有 virginica 的节点,该节点将不再被分割,它将是一片叶子。

节点 2

对于这个节点,算法选择在**petal width = 1.55 cm**分裂树,创建两个不同的组。凭直觉,我们会在**petal width = 1.3 cm****sepal width = 3.1 cm**分开,创建一个只有杂色虹膜的组。事实上,这将创建一个基尼系数为 0 的节点。但事实上,所创建的另一个节点更不均匀,以至于该节点的基尼不纯度大于用另一个分裂所创建的两个节点之和的基尼不纯度。

我们来验证一下这个:

基尼不纯与分裂于**petal width = 1.55 cm**

  • 左侧节点:

我们在树上验证了这个结果。

  • 右节点:

我们再次在树上验证了这个结果。

  • 这种分裂的基尼系数是:

一个分裂的基尼指数是由每一组的点数来衡量的。

基尼不纯与 **petal width = 1.3 cm**的分裂

  • 左侧节点:

  • 右节点:

  • 这种分裂的基尼系数是:

算法是对的,而我们的直觉是错的。实际上,第一次分割产生的基尼系数最低,因此这种分割更可取。提醒:该算法尝试每个特征的每个可能的分割。

节点 3

首先要注意的是,之前的拆分并没有改变拆分**petal width = 1.55 cm**上下树的决策函数。事实上,对于创建的两个节点,杂色仍然占大多数。

对于这个级别,决策树最终使用萼片宽度特征。创建的两个分割是**petal width = 2.65 cm**(在细分**0.8 cm** < **petal width <= 1.55 cm**中)和**petal width = 3.15 cm**(在细分**1.55 cm** < **petal width <= 1.75 cm**中)。

节点 4、5、6

一次又一次地应用相同的原理,该算法将试图隔离每个点,直到它只有同类组。例如,如果我们不限制树的大小,这会导致过度拟合。(树正在用心学习训练集,而不是理解它,这将阻止他在测试集上做出好的预测)。

在上图中,我们可以看到深度为 4、5、6 的树的决策边界。深度 6 是树叶的深度,并结束树的构建。

构建的树如何做出决定?

在上面的图中,我们可以看到决策树已经被训练(并且已经过拟合)的训练数据(由 o 表示)和测试数据(由 x 表示)。

当决策树必须为属于测试集的虹膜预测目标(虹膜种类)时,它从根节点沿树向下行进,直到到达叶子,通过针对父节点条件测试正在测试的虹膜的特征值来决定去左边还是右边的子节点。

例如,在根节点处,如果测试的虹膜**petal width <= 0.8 cm**到达作为叶子的左侧节点,并且将虹膜分类为 setosa 虹膜。否则,它会转到正确的节点,并继续相同的过程,直到到达一个叶子。

正如我们在混淆矩阵中看到的,两只云芝被错误地归类为弗吉尼亚:

  • **1.75 cm < petal width**区域:我们可以看到黄色的十字,即蓝色背景上的杂色鸢尾,即决策树将其归类为海滨
  • **1.55 cm < petal width <= 1.75 cm****sepal width <= 2.75 cm**区域:推理同上。

其余的测试虹膜已经被很好地分类,这给了我们 0.93 的精度。

在测试阶段,该算法取每个点,并遍历决策树,根据被测试虹膜的特征值选择左边或右边的节点。

结论

在本文中,我们剖析了决策树,以理解构建该算法背后的每个概念,这是必须知道的。👏为了理解决策树是如何构建的,我们举了一个具体的例子:由连续特征和分类目标组成的虹膜数据集。决策树也可以使用分类特征(甚至更简单,因为一个分支是一个类别)或连续目标(这里可能有点复杂,因为它不使用基尼系数来衡量同质性,而是使用方差度量……)。这可能是另一篇文章的主题…

了解差异隐私

原文:https://towardsdatascience.com/understanding-differential-privacy-85ce191e198a?source=collection_archive---------2-----------------------

从理论背后的直觉到私人的人工智能应用。

Privacy by Nick Youngson CC BY-SA 3.0 Alpha Stock Images

他的文章是对差分隐私的简明介绍。通过阅读,你将从差异隐私的重要概念背后的直觉和原因,如隐私损失,隐私损失和准确性(差异隐私输出)之间的关系。然后,这些直觉将通过具体的说明性故事来解释,并通过编程进行定性和定量分析来加强。在文章的最后,我们期待的是在 MNIST 手写数字数据集上使用私人聚集教师集合算法(PATE)的私人人工智能应用。

注意:该应用将要求读者必须熟悉 Pytorch。

“差分隐私使科技公司有可能收集和分享关于用户习惯的聚合信息,同时维护个人用户的隐私。”

对话

差分隐私有哪些实际应用?

在 21 世纪,我们面临许多大数据泄露,迫使政府、组织和公司重新考虑隐私。相比之下,机器学习的几乎突破都来自于需要大量训练数据的学习技术。此外,研究机构经常使用和共享包含个人敏感或机密信息的数据。此类数据的不当披露会对数据主体的私人信息产生不利后果,甚至会导致民事责任或人身伤害。

差分隐私等正式隐私模型的发展有助于解决这个问题。因此,越来越多的组织和公司正在应用差分隐私来保护敏感信息,如个人信息、用户事件、个人实时位置,如本文所述:差分隐私的高级介绍。甚至有一个开源差分隐私项目,用于在任何标准 SQL 数据库上执行差分隐私查询。

简而言之,差分隐私许可:
—公司在不违反隐私的情况下访问大量敏感数据用于研究和业务。
—研究机构可以开发差分隐私技术,在各国的云共享社区中实现隐私流程自动化。因此,他们可以保护用户的隐私和解决数据共享问题。

差分隐私简介

Figure 1: Information in data under Differential Privacy view.

什么是差分隐私?
—差分隐私(DP)是在统计和机器学习分析的背景下对隐私的一个强有力的数学定义。根据这个数学定义,DP 是隐私保护的一个标准,许多用于分析敏感个人信息的工具都是为了满足这个标准而设计的。[1].

上图显示了 DP 视图下数据中包含的信息。因此,一般信息是不特定于任何单个数据主题的任何信息。一般信息可以理解为数据中整个总体的信息(不仅仅是一个个体或一组数据主体)。与一般信息形成对比的是私人信息,即特定于任何单个数据主体的信息。

Figure 2 [1]: Differential privacy.

如何区分私人信息和一般信息?
——在 DP 看来,隐私信息是数据中的信息在个体数据主体选择退出前后的变化(如图 2 所示)。这也解释了名字中的“差”字。

  • 它能保证什么?
    差分隐私从数学上保证,任何人看到差分隐私分析的结果,都会对任何个人的隐私信息做出相同的推断,无论该个人的隐私信息是否包含在分析的输入中。[1]
    — DP 提供了一种数学上可证明的隐私保护保证,可以抵御大范围的隐私攻击(包括差异攻击链接攻击、重构攻击)【2】。
  • 它不能保证什么?DP 并不保证一个人认为是自己的秘密会一直保密。重要的是要识别哪些是一般信息,哪些是私人信息,以便从 DP 保护伞中获益并减少伤害。DP 保证只保护私人信息(如上所述)。所以,如果一个人的秘密是一般信息,它将不受保护!

为了理解这一点,让我们考虑一个场景,当你,一个吸烟者,决定被纳入调查。然后,对调查数据的分析表明,吸烟会导致癌症。作为一个吸烟者,你会受到分析的伤害吗?也许——基于你是一个吸烟者的事实,人们可能会猜测你的健康状况。他在研究后对你的了解肯定比之前知道的更多(这也是说这是“一般信息”,而不是“公开信息”背后的原因),但你的信息被泄露了吗?差分隐私将认为它不是,理由是对吸烟者的影响是相同的,与他是否在研究中无关。影响吸烟者的是研究得出的结论,而不是他在数据集中的存在与否。[2]

它是如何工作的?

让我们考虑一个典型的例子,看看满足 DP 标准的 DP 算法是如何工作的:假设你是一名社会数据科学家,想要对一个非常禁忌的行为的调查数据进行分析。数据中的每个条目都是被调查人群中个人的一个答案(真相),即“是”或“否”。由于隐私政策,数据持有人或馆长永远不会允许您直接访问数据。

作为一名数据挖掘专家,您向馆长建议了一种数据挖掘算法,用于删除数据中的私人信息,从而可以对数据进行分析。因此,对于每个条目,策展人将应用以下算法:

  • 抛硬币(硬币的偏向是其结果是正面的概率,它将被表示为 p_head 。).
  • 如果是正面,返回条目中的答案。
  • 如果是反面,再掷一次硬币,如果是正面,返回“是”,如果是反面,返回“否”。

Figure 3. Flow diagram of the Differential privacy algorithm.

现在,每个人都受到“似是而非的否认”的保护,因为一个人通过抛硬币的随机性来似是而非地否认答案。假设你想从嘈杂的数据中推断出人口中无辜者的百分比( p_innocent )。这可以通过以下步骤实现:

  • 假设个人不是无辜的,计算返回“是”的概率:P("是" |不是无辜的)=P _ head+(1-P _ head)**P _ head。*

  • 假设个人是无辜的,计算返回“是”的概率:P(" yes " | innocent)=(1-P _ head)**P _ head。*

  • 计算P _ innocent:
    P _ innocent=(P(" yes ")-P(" yes " | not innocent))/(P(" yes " | innocent)-P(" yes " | not innocent))= 1-(P(" yes ")-(1-P _ head)**P _ head)/P _ head。*(演绎证明)

注:以上结果是由大数定律保证的渐近结果。

Figure 4: Compute on a simulated survey data of 20,000 individuals. Low bias coins add more noise to the data. A consequence of adding noise is the decrease in privacy loss.

  • DP 告诉我们什么?
    如图 4 所示,当 p_head 接近 0 时, p_innocent 的方差急剧增加并接近无穷大,这导致隐私损失迅速减少。DP 也给了我们同样的结论。因此,当 p_head 为 0 时,无论个人是否无辜,返回结果的分布都是相同的(2 个分布的距离为 P(" yes " | not innocent)-P(" yes " | innocent)=P _ head,偏差)。如果参与数据的无辜者的数量发生变化,它不会导致有噪声的返回数据中的信息发生任何变化。意味着在嘈杂的返回数据中没有私人信息。

差异隐私的原因

DP 具有有价值的属性[2]使其成为分析敏感个人信息和隐私保护的丰富框架:

  1. 隐私损失的量化。
    隐私损失是任何 DP 机制和算法中的一个度量。它允许不同技术之间的比较。隐私损失是可控的,这确保了它和一般信息的准确性之间的权衡。
  2. 作文。
    损失的量化允许通过多次计算对累积隐私损失进行分析和控制。理解组合下差分私有机制的行为使得能够从较简单的差分私有构建块设计和分析复杂的差分私有算法。
  3. 群体隐私。
    DP 允许对家庭等群体发生的隐私损失进行分析和控制。
  4. 闭合下的后处理。
    DP 不受后处理的影响:一个数据分析师,如果没有关于私有数据库的额外知识,就不能计算差分私有算法输出的函数并使其不那么差分私有。

测量差分隐私并报告最大噪音

现在,我们准备好了微分隐私的数学定义。让我们来看看:

随机化算法 k 给出了ε-差分隐私如果对于所有数据集 d 和 d’至多在一行上不同,以及任何 S ⊆范围(k)

DP 算法中必须考虑的两个量是:

  • Epsilon (ε):数据差异变化(添加、删除 1 个条目)时隐私损失的度量。值越小,隐私保护越好。
  • 准确性:DP 算法的输出与纯输出的接近程度。在带 PATE 的私人机器学习部分,我将使用测试集上的分类精度作为评估精度的统计量。

注:还有另外一个量,对于拉普拉斯机制以外的机制,没有提到的是δ(δ)【2】

有些东西你需要补上:

  1. ε减小会导致精度下降。
    如果你的算法是 0-差分隐私,很好的保护了隐私,那么它的准确率很低,那就没用了。因为除了噪音你什么也得不到。这也显示在图 4 中。你可以在这里验证一下:https://georgianpartners.shinyapps.io/interactive_counting/
  2. ε=0(一般情况下δ=0)相当于绝对隐私。
    可以直接从差分隐私的定义中推导出来。简而言之,ε=0 相当于 Pr[K(D)] = Pr[K(D')],这导致算法 K 独立于数据,从而完美地保护了隐私。

Figure 5: Confidence intervals of the average of results of an ε=0.03-differential privacy mechanism over 1000 queries. Note the confidence level is 95%, and that “Within_one” means the estimate is in the interval [2.5, 3.5]. Take from https://georgianpartners.shinyapps.io/interactive_counting.

小心!

对数据应用算法的次数越多,隐私损失就越多。类似于玩“我是间谍。”。你的任务是猜测间谍看到的物体。随着间谍的每一个回答,你会得到更多关于这个物体的信息。所以,经过一定次数的查询,你就能知道是什么东西了。在这种情况下, DP 的组合属性 将有助于分析敏感的个人信息。对这一事实感到好奇的读者可以阅读参考资料中的“隐私预算”概念[1]和这个故事 T25。

报告噪声最大值算法

对于 PATE 算法的解释,我将讲述关于报告噪声 Max (RNM)算法。

为什么是 RNM?
RNM 算法(在【差分隐私】发明者辛西娅·德沃克的差分隐私算法基础中介绍)适用于:

…“我们希望知道在一组被调查者的病史中,哪种疾病(大约)是最常见的,因此,对于所考虑的每种疾病,我们的问题是,被调查者是否接受过这种疾病的诊断。由于个人可能经历许多情况,这组问题的敏感性可能很高。尽管如此,正如我们接下来所描述的,这项任务可以通过在每个计数中增加 Lap(1/ε)噪声来解决(注意噪声的小范围,它与条件总数无关)。至关重要的是,m 个嘈杂的计数本身不会被发布(尽管“获胜”的计数可以在没有额外隐私成本的情况下发布)。

差分隐私的算法基础,第 35 页。

RNM 算法的朴素伪实现;

*输入:**一个标签向量:X,隐私损失水平:ε,标签数:n
输出:一个嘈杂的最大答案
从 X 计算标签数,将结果赋给 y
从一个零中值拉普拉斯分布中画出一个随机的 n 维向量 L,方差为 2/(ε
ε)(L 中的元素相互独立)。

返回 arg max(Y + L)

Figure 6. PDF of zero median Laplace distributions.

RNM 算法被证明是ε-差分隐私,其中ε是隐私损失等级(来源:**差分隐私算法基础,第 35 页)。******

使用 PATE 实践差分隐私

教师集合的私有聚集算法

在这一部分,我将解释教师集合的私有聚合算法(PATE) [3],并使用它来加强对 DP 的理解。**

  • 为什么是肉酱?
    利用置信度信息的模型反转攻击及基本对策
    【4】论文表明,利用机器学习算法输出的私人信息是可能的。PATE 就是为了解决这个问题而发明的,它是一种普遍适用的方法,可以为训练数据提供强大的隐私保证。
    ****
  • 它是如何工作的?
    PATE 背后的思想是对敏感模型的输出应用 DP 聚合(RNM 算法),称为“教师”(敏感模型直接在标记的敏感数据上训练)。聚集的结果将用于在未标记的公共数据上训练另一个公共模型。因此,对教师的回答应用 DP 可以被视为保护敏感数据隐私的代理,并且
    教师必须接受数据不相交子集的培训
    ****

为什么它们一定是不相交的?
想象一下,如果每个教师都在整个数据上接受培训,那么移除一个教师不会对聚合结果中任何单个数据主体的参与产生任何影响,因为该单个数据主体仍然参与培训其他教师。这将使得对教师的回答应用差别隐私不再是保护敏感数据中个人数据主体隐私的有效代理。因此,训练数据集必须是不相交的。

安装 PySyft

使用 Pysyft 可以分析PATE 的差分隐私,或者执行 PATE 分析。您可以按照这些步骤来安装 Pysyft 和相关的库。**

  • 安装所需库的最简单方法是使用 Conda 。创建一个新环境,然后在该环境中安装依赖项。在您的终端中:

  • 如果您有任何与 zstd 相关的错误,请运行以下命令(如果上面的一切安装正常,则跳过这一步):

  • 重试安装 syft (pip 安装 syft)。

PATE 差异隐私分析的 API

我们将使用 Pysyft 中“pate”包的 Numpy 和 perform_analysis 函数:

执行 _ 分析功能的描述:
输入(参数为文章目的而简化):
**

—( m,n)个教师模型输出的二维数组。
m:教师数量或产出数量。
n:查询次数。
—最多投票标签的向量。
—RNM 算法的ε。

输出:

—数据无关 epsilon [3]:最坏情况下的隐私丢失。
—数据相关的 epsilon [3]:基于教师模型输出的真实值的隐私损失的紧界。
计算数据相关的ε:
对于每个查询,计算聚集数据的紧界隐私损失,这是通过将 RNM 算法应用于教师模型的输出而生成的。
对紧界隐私损失求和,然后将结果分配给数据相关的 epsilon。

返回:数据无关的ε和数据相关的ε

描述 cal_maxnoise _ max功能:**

cal_max 具有为每个查询找到投票最多的标签的功能。并且,noise _ max是 RNM 算法。

PATE 分析

我将用“数据”这个词来表示教师模型的输出。

让我们考虑这些场景,并将我们的预期与分析结果进行比较:

在前三个场景中,我将使用具有较大隐私损失级别(ε=5)的 RNM 算法,以减少其对数据的影响。因此,允许我们能够“观察”固有数据的私有信息。

  • 首先,数据中没有信息:

创建数据:

**array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]])**

期望:
在汇总结果中没有一般信息,也没有私人信息。因此,依赖于数据的ε应该较低。

执行 PATE 分析:

**Warning: May not have used enough values of l. Increase 'moments' variable and run again.
Data Independent Epsilon: 10000.164470363787
Data Dependent Epsilon: 0.16447036378528898**

依赖于数据的ε非常低,反映了预期。

  • 第二,数据中有丰富的信息,教师之间有很强的一致性:

创建数据:

**array([[  0,   1,   2, ..., 997, 998, 999],
       [  0,   1,   2, ..., 997, 998, 999],
       [  0,   1,   2, ..., 997, 998, 999],
       ...,
       [  0,   1,   2, ..., 997, 998, 999],
       [  0,   1,   2, ..., 997, 998, 999],
       [  0,   1,   2, ..., 997, 998, 999]])**

期望:
数据中的信息丰富可能导致一般信息和私人信息的丰富。但是,在这种情况下,老师们有一个强烈的共识。因此,选择退出教师不会影响最后的结果。意思是没有私人信息。这样,数据相关的ε应该很低,即使 RNM 算法的隐私损失水平很大(ε=5)。

PATE 分析(相同代码):

**Warning: May not have used enough values of l. Increase 'moments' variable and run again.
Data Independent Epsilon: 10000.57564627325
Data Dependent Epsilon: 0.5756462732485115**

接得好!

  • 三、随机数据:

创建数据:

**array([[74, 60, 81, ..., 44, 95, 90],
       [77, 50, 72, ..., 40, 14, 49],
       [69, 60, 54, ..., 57, 60,  9],
       ...,
       [57, 47, 67, ..., 40, 59, 55],
       [26, 74, 21, ..., 27, 88, 57],
       [85, 39, 39, ...,  7, 84, 30]])**

期望:这个案例与之前的案例形成了鲜明的对比,之前的案例中老师们不再有强烈的共识。因此,信息的丰富性与一般信息和私人信息共享。因此,数据相关的ε应该很高。

PATE 分析(相同代码):

**Data Independent Epsilon: 10000.57564627325
Data Dependent Epsilon: 8135.9030202753**

依赖于数据的ε如预期的那样高。

  • 第四,随机数据和小隐私损失水平(ε=0.001) RNM

创建数据(与第三个场景相同):

期望:
在所有情况下,RNM 隐私损失水平的降低将减少隐私损失。因此,与数据无关的ε和与数据相关的ε应该较低。

PATE 分析(相同代码):

**Data Independent Epsilon: 0.3054858613811872
Data Dependent Epsilon: 0.3054858613811865**

再说一次,我们是对的。与数据无关的ε和与数据相关的ε较低。

使用 PATE 的私人机器学习(Pytorch)

Figure 7 [3]: Private Machine Learning with PATE.

它是如何工作的?
使用 PATE,我们将使用教师模型的聚合结果,在未标记(不完整)的公共数据上训练另一个模型,即“学生”。这有助于我们从敏感数据源中获益。

问题描述

  • 数据:

我们将在“火炬视觉”包中使用由灰度手写数字组成的 MNIST 数据集。每个图像都是 28x28 像素的数字图像,如下图所示:

因此,训练数据集表示已标记的敏感数据集,而测试数据集表示未标记的公共数据。

  • 目标:
    —为被标记的敏感数据集提供强大的隐私保障。
    —训练一个模型,用于从未标记的公共数据中对手写单个数字(0-9)的输入图像(28×28 像素)进行分类。

履行

导入库

下载aggregation . py导入它和相关库。**

加载 MNIST 数据

培养学生模型

我将假设您已经有了 250 个微调教师模型的预测-来自未标记公共数据的 2048 个输入样本的 2048 个查询,它存储在一个二维数组中,如 PATE Analysis 部分所述:

***array([[7, 2, 1, ..., 3, 4, 6],
       [7, 2, 1, ..., 3, 9, 5],
       [7, 2, 1, ..., 3, 4, 6],
       ...,
       [7, 9, 7, ..., 9, 9, 8],
       [2, 2, 2, ..., 7, 1, 7],
       [6, 6, 6, ..., 6, 6, 6]])***

PATE 分析:

***Data Independent Epsilon: 751.0955105579642
Data Dependent Epsilon: 0.7707510458439465***

使用 2048 个查询的输入和 RNM 输出(隐私损失水平ε=0.3)来训练该学生模型:

培训代码:

结果: 该模型具有 82.5% 的准确率和小于 0.771 的总隐私损失。

你可以在这个 GitHub 项目 中找到源代码。

最后的想法

差分隐私是量化和解决隐私相关实际问题的有力工具。其灵活的定义使其有可能应用于广泛的应用中,包括机器学习应用。所有这些只是一个起点,但我希望这也是一个迹象,表明有可能在不牺牲隐私的情况下从大数据技术中获得所有好处。

参考

[1] Kobbi Nissim 等人差分隐私:非技术受众入门。2018 年 2 月 14 日。

[2]辛西娅·德沃克和亚伦·罗斯。差分隐私的算法基础。理论计算机科学的基础和趋势,9(3 4):211–407,2014。

[3] Nicolas Papernot 等从私人训练数据进行深度学习的半监督知识转移。2017.

[4]弗雷德里克松、马特&贾、萨默什&里斯坦帕尔、托马斯(2015).利用信任信息的模型反转攻击和基本对策。1322–1333.10.1145/2810103.2813677.

理解机器学习的降维

原文:https://towardsdatascience.com/understanding-dimensionality-reduction-for-machine-learning-ad9a3811bd89?source=collection_archive---------14-----------------------

Photo by Oliver Schwendener on Unsplash

最近,我被要求处理一个有点偏重的数据集。它太大了,以至于我的 Excel 程序在加载时会停止响应几分钟,手动浏览数据开始变得非常痛苦。

我还是机器学习界的新手。因此,我不得不多次返回 Excel,以决定在机器学习模型中应该使用哪些功能。

但是,在经历了漫长而痛苦的时间后,我终于能够建立一个能给我一些不错的结果的模型了!我开始自我感觉良好,并开始相信我可以成为一名机器学习工程师!

但后来我遇到了下一个障碍:我如何向普通人展示我的成果?

我可以创建两列,一列显示真实世界的结果,另一列显示 ML 模型给我的结果。但这并不是视觉上最吸引人的方式。虽然机器在理解大量数字数据方面比我们更好,但人类思维更容易理解图形和绘图等视觉数据。

所以剧情是最好的前进方式。但是我们的屏幕是二维的,我们的数据可以有两个以上的特征,每个特征可以被认为是一个维度。这个图的两个维度之一将会是输出。因此,我们应该问自己的问题是:我们如何在一个维度中表示我们所有的特征,这些特征可能有数百个到数千个。

这就是降维发挥作用的地方!

什么是降维?

降维是机器学习中的一种技术,可以减少数据集中的要素数量。降维的好处在于,它不会对你的机器学习模型的性能产生负面影响。在某些情况下,这种技术甚至提高了模型的准确性。

通过减少数据集中的要素数量,我们也减少了存储数据所需的存储空间,我们的 python 编译器将需要更少的时间来遍历数据集。

在本帖中,我们将看看两种最流行的降维技术,主成分分析(PCA)和线性判别分析(LDA)。

入门指南

在我们继续之前,让我们确保您的系统已经准备好使用一些 python 代码。

Python 有两个主要版本:2.x 和 3.x。我建议您确保在系统上安装了 3.x 版本。如果不是这样,那么你可以从这里得到。

接下来,我们需要一个好的代码编辑器,它将有助于使您的编码体验更加容易和愉快。我个人的选择是惊艳的 VSCode ,不过你也可以试试 Spyder 或者 Jupyter 笔记本。还有一些在线代码编辑器,比如 ReplGoogle Colab 你可以试试。使用在线编辑器可以让你跳过安装 Python 库的浪费时间和存储的任务。

我们将致力于葡萄酒数据集。这个数据集完全是数值型的,不包含任何缺失值,非常适合本文,因为我不必在数据预处理技术上浪费时间,比如将分类数据转换成数值数据,以及将数据输入空单元格。

让我们从导入一些脚本中需要的 Python 库开始:

import pandas as pd
from sklearn.preprocessing import StandardScaler

我们还需要将葡萄酒数据集加载到我们的 python 脚本中。让我们使用来自pandas库的read_csv()函数来实现:

dataset_url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv'dataset = pd.read_csv(dataset_url, sep=';')

数据集看起来像这样:

quality列将是我们机器学习模型的因变量,其余列将是自变量。因此,让我们相应地将数据集分成两部分:

X = dataset.iloc[:, 0:-1].values
y = dataset.iloc[:, -1].values

X包含 11 列,y包含第 12 列。

我们还需要对数据进行一些特征缩放。我们使用StandardScalar函数来完成这项工作。该函数将以这样一种方式转换我们的数据,即数据的分布将具有平均值 0 和标准差 1。我们将对independent变量进行特征缩放,因为我们希望dependent变量尽可能保持原样。

sc = StandardScaler()
X = sc.fit_transform(X)

我们现在准备执行降维!先从 PCA 开始,再进行 LDA。我建议创建一个新的 python 脚本文件,将您的代码复制到其中,稍后在 LDA 部分使用它。

主成分分析

主成分分析(PCA)是最流行的降维算法之一,也可用于噪声过滤、股市预测、数据可视化等等。

PCA 通过检测数据集中特征之间的相关性来减少特征的数量。当特征之间的相关性足够强时,它们将合并在一起并形成单个特征。

我们可以看一看算法背后的数学原理,并试图理解它是如何工作的,但我发现进入代码并查看我们得到的输出更容易。

从上一节我们留下代码的地方继续,让我们从从sklearn导入PCA类开始:

from sklearn.decomposition import PCA

接下来,我们需要创建一个PCA类的本地实例。

pca = PCA(n_components=None)

我们正在传递一个名为n_components的参数,我们将首先传递一个值None

接下来,我们将调用pca上的fit_transform方法,并将X_train数据集作为输入传递给它。我们还将调用transform方法,并将X_test数据集作为输入传递

X = pca.fit_transform(X)

一旦这样做了,我们需要得到数据集不同主成分的解释方差。我们的pca对象有一个名为explained_variance_ratio_的属性,它包含一个百分比数组。

variances = pca.explained_variance_ratio_

如果您打印这个变量,您将得到一个类似如下的数组:

[0.28173931 0.1750827  0.1409585  0.11029387 0.08720837 0.05996439  0.05307193 0.03845061 0.0313311  0.01648483 0.00541439]

我们可以看到这个数组的元素是降序排列的。但是这些价值观是什么意思呢?每个值都解释了数据集中 11 个主成分的方差。

因此,如果只取第一个主成分,我们将有 28.17%的方差。如果我们取两个主成分,我们将得到数组前两个元素的和,其方差约为 45.68%,依此类推。

现在我们可以使用 Python 编译器,将传递给PCA内部n_componentsNone值替换为期望的维数。让我们看看选择1作为所需的维度数量会得到什么

pca = PCA(n_components=2)
X = pca.fit_transform(X)// Output
[[-1.61952988]  
 [-0.79916993]  
 [-0.74847909]  
 ...  
 [-1.45612897]  
 [-2.27051793]  
 [-0.42697475]]

瞧啊。我们已经成功地将输入数据集的维数从 11 减少到 1!

线性判别分析(LDA)

与 PCA 类似,LDA 也是一种降维算法。但与 PCA 不同的是,LDA 也将找到最大化多个类别之间的分离的特征。

你可能会问自己:为什么我要为这个新算法费心,这个新算法基本上和以前的算法做同样的事情?

PCA 和 LDA 都是降维算法。但是在 PCA 被认为是无监督算法的情况下,LDA 则被认为是有监督的。

有监督和无监督?这些是常见的机器学习术语,分别定义算法是否使用因变量。所以 LDA 使用因变量,而 PCA,正如我们之前看到的,不使用。

让我们来看一些代码,并理解如何在 python 代码中实现 LDA 算法。

如果您还没有这样做,那么从入门部分获取代码,并将其粘贴到一个新的 python 脚本文件中。然后,从sklearn导入LinearDiscriminantAnalysis类。

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

接下来,我们从LinearDiscriminantAnalysis创建一个名为lda的本地对象。我们还会给它传递一个名为n_components的参数。现在我们可以做所有的事情,找到每个主成分引入的方差的百分比。但是我将跳过这一部分,将n_components参数设置为1的值。

lda = LinearDiscriminantAnalysis(n_component=1)

最后一件事!在lda上调用fit方法,将Xy数据集作为输入传递给它,然后链接一个transform方法,将X作为其输入。

X = lda.fit(X,y).transform(X)// Output
[[-1.51304437]  
 [-1.28152255]  
 [-1.11875163]  
 ...  
 [ 0.71637389]  
 [-0.32030997]  
 [ 0.8645305 ]]

Tada!🎉我们现在已经成功地将X的尺寸减小到 1!

感谢你阅读这篇关于降维的文章。我希望它对你学习机器的旅程有一点点帮助。降维算法真的很棒,不仅有助于可视化您的结果,还有助于减少处理时间,并通过防止系统读取大型数据集来减轻系统压力。

了解 PyTorch 中的维度

原文:https://towardsdatascience.com/understanding-dimensions-in-pytorch-6edf9972d3be?source=collection_archive---------5-----------------------

通过对 3D 张量求和过程的可视化,对 PyTorch 维数有了更好的直觉

Photo by Crissy Jarvis on Unsplash

当我开始用 PyTorch 张量做一些基本运算时,比如求和,对于一维张量来说,它看起来很容易,也很简单:

>> x **=** torch.tensor([1, 2, 3])>> torch.sum(x)tensor(6)

然而,一旦我开始摆弄 2D 和 3D 张量,并对行和列求和,我就对torch.sum的第二个参数dim感到困惑。

让我们从官方文件上说的开始:

torch.sum(input,dim,keepdim=False,dtype=None) → Tensor

返回给定维数 dim 中每一行输入张量的总和。

我不太理解这种解释。我们可以对多列求和,那么为什么有人提到它只是“返回每行的总和”呢?这是我第一次不理解。

然而,正如我所说,更重要的问题是每个维度的方向。我的意思是。当我们描述 2D 张量的形状时,我们说它包含一些和一些列。所以对于一个 2x3 张量,我们有 2 行 3 列:

>> x = torch.tensor([
     [1, 2, 3],
     [4, 5, 6]
   ])>> x.shapetorch.Size([2, 3])

我们首先指定行(2 行),然后指定列(3 列),对吗?这使我得出结论,第一维( dim=0 )适用于行,第二维( dim=1 )适用于列。按照维度 dim=0 表示行方式的推理,我期望*torch.sum(x, dim=0)* 产生一个 1x2 张量(1 + 2 + 34 + 5 + 6产生一个tensor[6, 15])。但结果我得到了不同的东西:一个 1x3 张量。

>> torch.sum(x, dim=0)tensor([5, 7, 9])

我惊讶地看到现实与我预期的相反,因为我最终得到了结果tensor[6, 15],但是在传递参数 dim=1 时:

>> torch.sum(x, dim=1)tensor([6, 15])

为什么会这样呢?我找到了一篇关于 Aerin Kim 的文章🙏解决同样的困惑,但是对于 NumPy 矩阵,我们传递第二个参数,称为。除了 PyTorch 中的 dim 在 NumPy 中被称为之外,NumPy sum 与 PyTorch 中的几乎相同:

numpy.sum(a,axis=None,dtype=None,out=None,keepdims=False)

理解 PyTorch 中的 dim 和 NumPy 中的如何工作的关键是 Aerin 文章中的这段话:

理解 numpy sum 的的方法是:它 折叠 指定的轴。因此,当它折叠轴 0(行)时,它就变成了一行(按列求和)。

她很好地解释了参数在 numpy.sum. 上的作用,然而,当我们引入第三维时,它变得更加棘手。当我们观察一个 3D 张量的形状时,我们会注意到新的维度被预先考虑并占据了第一个位置(在下面的粗体中),即第三维度变成了dim=0

>> y = torch.tensor([
     [
       [1, 2, 3],
       [4, 5, 6]
     ],
     [
       [1, 2, 3],
       [4, 5, 6]
     ],
     [
       [1, 2, 3],
       [4, 5, 6]
     ]
   ])>> y.shapetorch.Size([**3**, 2, 3])

是的,相当混乱。这就是为什么我认为对不同维度的求和过程进行一些基本的可视化会大大有助于更好的理解。

这个 3D 张量的第一维( dim=0 )是最高的一维,包含 3 个二维张量。因此,为了对它进行总结,我们必须将它的 3 个元素一个接一个地折叠起来:

>> torch.sum(y, dim=0)tensor([[ 3,  6,  9],
        [12, 15, 18]])

它是这样工作的:

对于第二维度( dim=1 ),我们必须折叠行:

>> torch.sum(y, dim=1)tensor([[5, 7, 9],
        [5, 7, 9],
        [5, 7, 9]])

最后,第三维度在列上折叠:

>> torch.sum(y, dim=2)tensor([[ 6, 15],
        [ 6, 15],
        [ 6, 15]])

如果你像我一样,最近开始学习 PyTorch 或 NumPy,我希望这些基本的动画示例能帮助你更好地理解维度是如何工作的,不仅是对于 sum 也是对于其他方法。

感谢阅读!

参考资料:

[1] A .金, Numpy 和轴直觉

理解有效边界

原文:https://towardsdatascience.com/understanding-efficient-frontier-46f1a429d526?source=collection_archive---------12-----------------------

诺贝尔奖得主理论让你的投资获得更高回报

问题:什么是好的投资组合?

一个好的投资组合不仅仅是一长串好的股票和债券。这是一个平衡的整体,为投资者提供了各种保护和机会。—哈里·马科维茨

诺贝尔奖得主哈里·马科维茨的现代投资组合理论可以通过使用优化程序来实现。

“该理论为你不应该把所有鸡蛋放在一个篮子里的直觉提供了坚实的基础,并向投资者展示了如何组合证券以最小化风险”(伯顿·g·马尔基尔)。

文章目标

本文将记录以下三个要点:

  1. 对有效边界的理解
  2. SciPy 包的快速概述
  3. 如何在 Python 中生成高效的投资组合?

请阅读 fintech explainedisclaimer。这个应用程序是基于我的意见,他们可能是错误的。在投资之前,一定要向专业理财顾问寻求建议。

1.让我介绍一下有效边界

让我们假设你有 10,000 美元的现金,并且你有兴趣投资它。你的目标是将这笔钱投资一年。像任何理性的投资者一样,你希望一年后的最终金额高于你想要投资的 10,000 美元。

你最不希望的事情就是失去你开始投资的 10,000 美元。

到目前为止,一切顺利!

1.1 理解风险收益关系

有许多投资选择,如购买国债或公司股票等。一些投资选择比其他的风险更大,因为它们吸引我们获得更高的回报。

因此,要注意的一点是,存在风险回报权衡。

作为投资者,我们的唯一目标可能是投资于风险最小、回报最高的投资选择。

如果我们购买一些资产,如不同公司的股票,那么投资组合的总风险可以由于多样化而降低。这意味着投资者可以通过在投资组合中选择不同比例的不同资产来降低总风险,增加回报。这是因为资产可以相互关联。

1.1 A —投资组合回报

现在,如果我们将投资组合的回报率计算为:

其中每项资产的预期回报率为:

回报计算如下:

1.1 B —投资组合风险

我们可以将投资组合的风险计算为资产的波动性:

波动率是通过计算每只股票收益的标准差以及每对股票和股票权重之间的协方差来计算的。

这意味着权重可以改变投资组合的风险。

1.2 有效前沿理论

我们知道资产的分配(权重)可以改变投资组合的风险。因此,我们可以随机生成 1000 个投资组合,其中每个投资组合将包含一组不同的资产权重。

我们知道,随着投资组合数量的增加,我们将更接近真正的最优投资组合。这是一种蛮力方法,可能会是一项耗时的任务。此外,不能保证我们将找到正确的分配。

如果我们将每个投资组合的风险和回报绘制在图表上,那么我们会在投资组合的顶部看到一条拱形线。

我们可以看到图表在我用黑笔标出的投资组合顶部形成了一个拱形。

这条线本质上指向最有效的投资组合。这条线被称为有效边界。

有效边界是一组投资组合,以最低的风险给我们带来最高的回报。

其他所有不在有效边界上的投资组合都不那么有效,因为它提供了与有效边界上的投资组合相同的回报,但承担了更高的风险。

因此,任何其他投资组合都不如有效边界上的投资组合。因此,我们可以忽略不在有效边界上的投资组合。

2.SciPy 优化快速概述

Python 中有许多库可以对 CVXPY 和 SciPy 等函数执行优化例程。

在这一节中,我将简要介绍 SciPy 包,这是需要熟悉的关键 Python 包之一。特别是,我将解释我们将执行的计算有效投资组合的函数,以及每个参数的含义。

优化技术帮助我们更快地找到一个函数的解,而不需要收集大量数据,也不需要使用分析技术。

可以对优化施加约束。我们也可以使用最优化技术来找出 x 的最小值和最大值。

其工作方式是,优化器试图找到我们的目标变量 x 的值,通过保持在指定的边界内,使实际值和观察值之间的差异最小化。

如果你想理解这个概念,请阅读这篇文章:

[## 数学优化是如何工作的?

以直观的方式理解最优化科学

medium.com](https://medium.com/fintechexplained/how-does-mathematical-optimisation-work-d1aa046c9bdd)

2.1 SciPy 优化

scipy 包中的 scipy.optimize 模块提供了多种优化算法。该模块包括无约束算法、全局优化程序、最小平方最小化、标量和多变量最小化等。

它提供了牛顿-克雷洛夫,牛顿共轭梯度,SLSQP,曲线拟合和双重退火算法等。

2.2 SciPy 最小化功能

scipy.optimize 模块中有一个 minimize 函数,它执行一个或多个变量的标量函数的最小化。最小化函数使我们更容易对目标函数执行所需的算法。

该方法的特征是:

**scipy.optimize.minimize(***fun***,** *x0***,** *args=()***,** *method=None***,** *jac=None***,** *hess=None***,** *hessp=None***,** *bounds=None***,** *constraints=()***,** *tol=None***,** *callback=None***,** *options=None***)**[**[source]**](https://github.com/scipy/scipy/blob/v1.3.0/scipy/optimize/_minimize.py#L42-L626)

关键论点是:

  • fun: 这是我们想要最小化的目标函数。在我们的案例中,我们的投资组合由许多资产组成。我们希望找到每种资产的配置,使我们的风险最小。该函数的第一个参数是分配的一维数组。我们也可以向函数传递一组其他参数。
  • x0 :这是初步猜测。我们可以赋值 1/资产数,作为 x 的初始值。
  • args :这是一个可以包含额外可选参数的元组。例如,如果我们的目标风险函数接受协方差矩阵,那么我们可以在 args 元组中传递它。
  • 方法:这是一个字符串参数,我们可以在其中传递算法名,比如 SLSQP
  • 约束:这是我们要传入约束的地方,比如分配的总和应该是 1。
  • bounds :这些基本上是 x 中每个元素的最小和最大对。作为一个例子,我们可以指出我们不希望分配的值为负,这意味着我们不想出售资产。

2.3 SLSQP 算法

要对多元标量函数执行约束最小化,我们可以使用 SLSQP 算法来使用 minimize 函数。

SLSQP 代表序列最小二乘编程。想法是最小化服从约束函数的 x 的函数。约束可以是线性的和非线性的。它们被定义为词典。

字典的关键字包括:

  • 类型:指定约束的类型,如 ineq(不等式)或 eq(等式)
  • fun :投资组合中资产配置之和等约束的函数应该等于 1。

3.如何在 Python 中生成高效的投资组合?

文章的最后一节将使用上面解释的知识来建立一套有效的投资组合。

3.1 有效边界的 7 个步骤

我们需要执行以下 7 个步骤:

  1. 第一步(第 1-3 步)是计算我们股票的日收益。
  2. 第二阶段是第 4 步,我们需要优化配置,为我们的每个目标回报找到最佳投资组合。
  3. 最后一个阶段是使用分配来计算风险和回报,并绘制投资组合。

3.2 在 Python 中实现高效边界

  1. 一旦我们获得了股票价格,我们就需要计算每只股票的预期平均收益:
import numpy as np
def asset_return_function(stock_prices):
  returns = np.log(stock_prices / stock_prices.shift(1))
  return returns.mean()

2.然后,对于每一个目标,我们将让优化者最小化风险(我们的目标函数),并给我们分配资产。

投资组合的风险计算如下:

import numpy as np
from functools import reduce
def risk_function(allocations, cov):
 return np.sqrt(reduce(np.dot, [allocations, cov, allocations.T]))

投资组合的回报计算如下:

def return_function(returns, allocations):
  return sum(returns * allocations)

3.最后,这段代码片段展示了我们如何使用 SciPy 优化器。

我已经生成了随机回报和协方差,这样我们就可以专注于优化器如何处理界限和约束了!

#initialise
returns = np.random.rand(3) covariance = np.random.rand(3,3)#set variables portfolio_size = len(returns)
risk_free_rate=0for my_return in [0.1,1.0,2.6,5.0]:

    x0 = np.ones(portfolio_size) * (1.0 / portfolio_size) bounds = ((0, 1),) * (portfolio_size)constraints=[]
    constraints.append({’type’: 'eq’, 'fun’: lambda inputs: 1.0 - np.sum(inputs)})
    constraints.append({’type’: 'eq’, 'args’: (returns,),
        'fun’: lambda allocations, returns:
    my_return - return_function(returns, allocations)})#optimised allocations allocations = minimize(risk_function, x0,
        args=(covariance), method=’SLSQP’,
        #prints covergence msgs
        options={’disp’: True},
        constraints=constraints,
        bounds=bounds).xexpectedreturns = return_function(returns, allocations) print(’Allocations For Target Return '+str(my_return)+’: '+str(allocations))

一旦我们运行上面的代码,它会产生以下输出:

我们可以看到优化例程运行了四次;每个目标返回一个。我们为每个分配指定了下限 0 和上限 1。增加了对分配的约束,以确保我们最大化回报,分配的总和为 1。

在每个优化例程中,优化器运行多次迭代,直到实现优化的分配。这些分配给了我们最好的投资组合,这就是所谓的有效边界。

对于每一个目标,它都返回了最优的投资组合。分配数组是构成我们每个目标回报的投资组合的资产的权重(比例)

后续步骤:

我将实现一个端到端的解决方案,展示我们如何在 Python 中运行有效边界,从获取股票价格到绘制有效边界。如果你感兴趣,请告诉我。

摘要

本文记录了以下三个部分:

  1. 对有效边界的理解
  2. SciPy 包的快速概述
  3. 如何在 Python 中生成高效的投资组合?

如果您有兴趣查看 Python 中高效前沿的端到端解决方案,请告诉我。

理解编码器-解码器序列到序列模型

原文:https://towardsdatascience.com/understanding-encoder-decoder-sequence-to-sequence-model-679e04af4346?source=collection_archive---------1-----------------------

Photo by Capturing the human heart. on Unsplash

在本文中,我将尝试对序列对序列模型给出一个简短的解释,该模型最近在机器翻译、视频字幕、问答等相当复杂的任务上取得了显著的成果。

先决条件:读者应该已经熟悉神经网络,特别是递归神经网络(RNNs)。此外,了解 LSTM 或 GRU 模型更佳。如果你还不熟悉 RNNs,我推荐阅读 这篇文章 它会让你快速入门。对于 LSTM 和 GRU,我建议看看 【了解 LSTM 网络】 以及 【了解 GRU 网络】

序列对序列模型的用例

您每天面对的众多系统背后都有一个序列对序列模型。例如,seq2seq 模型支持谷歌翻译、语音设备和在线聊天机器人等应用。一般来说,这些应用程序包括:

  • 机器翻译——谷歌 2016 年的一篇论文展示了 seq2seq 模型的翻译质量如何“接近或超过目前所有公布的结果”。

  • 语音识别 —另一篇 Google 论文在语音识别任务上对比了现有的 seq2seq 模型。

  • 视频字幕—2015 年的一篇论文展示了 seq2seq 如何在生成电影描述方面产生巨大的结果。

这些只是 seq2seq 被视为最佳解决方案的一些应用。该模型可用作任何基于序列的问题的解决方案,尤其是输入和输出具有不同大小和类别的问题。我们将在下面详细讨论模型结构。

序列到序列模型的定义

由 Google 于 2014 年首次推出,序列到序列模型旨在将固定长度的输入与固定长度的输出进行映射,其中输入和输出的长度可能不同。

For example, translating “What are you doing today?” from English to Chinese has input of 5 words and output of 7 symbols (今天你在做什麼?). Clearly, we can’t use a regular LSTM network to map each word from the English sentence to the Chinese sentence.

这就是为什么序列对序列模型被用来解决这样的问题。

序列对序列模型如何工作?

为了充分理解模型的基本逻辑,我们将浏览下图:

Encoder-decoder sequence to sequence model

该模型由 3 部分组成:编码器、中间(编码器)向量和解码器。

编码器

  • 几个循环单元(LSTM 单元或 GRU 单元,性能更好)的堆栈,其中每个单元接受输入序列的单个元素,收集该元素的信息并将其向前传播。
  • 在问答问题中,输入序列是问题中所有单词的集合。每个单词被表示为 x_i ,其中 i 是该单词的顺序。
  • 隐藏状态 h_i 使用以下公式计算:

这个简单的公式代表了普通递归神经网络的结果。正如你所看到的,我们只是将适当的权重应用于先前的隐藏状态 h_(t-1) 和输入向量 x_t.

编码器向量

  • 这是从模型的编码器部分产生的最终隐藏状态。它是用上面的公式计算的。
  • 该向量旨在封装所有输入元素的信息,以帮助解码器做出准确的预测。
  • 它充当模型解码器部分的初始隐藏状态。

解码器

  • 几个循环单元的堆栈,每个循环单元在时间步长 t 预测一个输出 y_t
  • 每个递归单元接受来自前一个单元的隐藏状态,并产生和输出它自己的隐藏状态。
  • 在问答问题中,输出序列是答案中所有单词的集合。每个单词表示为 y_i ,其中 i 是该单词的顺序。
  • 任何隐藏状态 h_i 都是使用以下公式计算的:

如你所见,我们只是使用前一个隐藏状态来计算下一个。

  • 使用以下公式计算时间步长 t 的输出 y_t :

我们使用当前时间步长的隐藏状态以及相应的权重 W(S)来计算输出。 Softmax 用于创建一个概率向量,该向量将帮助我们确定最终输出(如问答问题中的单词)。

这个模型的强大之处在于它可以将不同长度的序列相互映射。正如你所看到的,输入和输出是不相关的,它们的长度可以不同。这开启了一系列全新的问题,现在可以使用这种架构来解决。

进一步阅读

上面的解释只涵盖了最简单的序列对序列模型,因此,我们不能期望它在复杂的任务中表现良好。原因是使用单个向量来编码整个输入序列不能捕获全部信息。

这就是引入多种增强功能的原因。每一个都旨在增强该模型在具有长输入和输出序列的稍微复杂的任务上的性能。例如:

如果你想加强你对这种奇妙的深度学习模型的了解,我强烈推荐你观看 Richard Socher 关于机器翻译的讲座。如果你仍然感到迷茫或有任何问题,请在评论区提问,我很乐意帮助你。

我希望这篇文章能让你很好地理解处理序列的最新模型(seq2seq ),并对你激动人心的深度学习之旅有所贡献。

还有哪些 AI 内容?在 LinkedIn 上关注我的每日更新。

感谢您的阅读。如果你喜欢这篇文章,给它一些掌声👏。希望你有一个伟大的一天!

理解实体嵌入及其应用

原文:https://towardsdatascience.com/understanding-entity-embeddings-and-its-application-69e37ae1501d?source=collection_archive---------5-----------------------

Knowledge, Alfons Morales — Unsplash

最近,在被指派研究一个预测问题后,我读了很多关于实体嵌入的文章。

手头的任务是,给定我们数据仓库中的历史招聘广告数据,预测给定职位的工资。很自然,我不得不寻找如何使用深度学习来解决这个问题——因为现在用深度学习而不是简单的线性回归来做事情要性感得多(如果你正在阅读这篇文章,并且因为只有数据科学家才会阅读这篇文章,我相信你会理解:)。

还有什么比从 fast.ai 中寻找例子更好的学习深度学习的方法呢?

瞧,他们确实有这样的例子。

[## 表格数据深度学习介绍 fast.ai

有一种强大的技术正在赢得 Kaggle 比赛,并在谷歌广泛使用(据杰夫…

www.fast.ai](https://www.fast.ai/2018/04/29/categorical-embeddings/)

完成代码和所有非常相似的问题,卡格尔罗斯曼挑战。我想我的任务结束了。

虽然已经运行了代码并将其改装到我的数据中,但显然还有很多东西需要理解,以便能够像作者预期的那样顺利运行。

我对这样一个想法很感兴趣:不仅可以用向量来表示单词,甚至可以表示基于时间的数据?—当时对我来说是新闻。那时我知道,我必须更深入地研究用向量来表示事物的概念,以及使用它还能完成什么。

因此有了这个帖子。

实体嵌入

什么事?

不严格地说,实体嵌入是某种东西(也就是一个实体)的向量(一列实数)表示。例如,在自然语言处理(NLP)中,某个东西(也就是实体)可以是一个单词、一个句子或一个段落。

“ The GloVe word embedding of the word “stick” — a vector of 200 floats (rounded to two decimals). It goes on for two hundred values. “. [1]

然而,它真的不仅限于此。

实体(向量)也可以被认为是一个物体、一个上下文或一个想法。在流行的 Word2Vec 模型[8]中,那个东西——就是单词。但是最近,研究人员采用了在给定上下文的情况下创建嵌入的想法(回想一下,Word2Vec 是在给定其周围单词的上下文的情况下创建嵌入的),并将其应用于其他类型的对象(我将在后面介绍)。

例如,在下图中,嵌入了的 Twitter 用户实体的可视化演示了在给定的向量空间中,具有相似特征的用户彼此更接近。

From Twitter [2]

为什么重要?

在 NLP 中,能够在嵌入中表示单词允许我们使用少得多的内存,因为向量长度通常比语言的词汇表短得多(传统上可以执行一键编码来表示词汇表中的每个单词)。此外,Word2Vec 论文还表明,嵌入也存储了单词的一些语义意义。

但更重要的是,能够将实体(如单词、Twitter 用户、一段时间内的购买行为)表示为向量,这为我们对其执行各种操作提供了可能性(典型的例子是,将它用作机器学习模型的输入)。

应用程序

以下是一些著名组织如何利用它的优势的例子。这并不意味着详尽或深入。如果需要更多细节,建议读者查阅各自的原始资料(参考资料部分提供了链接)。

模型特征

嵌入主要是作为一种以矢量格式表示事物的方式被创建的,用于深度学习模型。拥有它们是很有用的,因为它允许我们从原始数据中捕获并转发最重要的信息到我们的模型中。

使用嵌入作为输入特征的模型将受益于它们的编码知识,并因此提高性能。最重要的是,假设嵌入的紧密性,模型本身将需要更少的参数,从而在训练和服务期间在基础设施方面产生更快的迭代速度和成本节约。[2]

对于基于文本的数据,已经开发了许多形式的模型架构来更好地捕获文本可以包含的不同种类的信息。从简单的一键编码,TF-IDF,到基于神经的架构,如 Word2Vec、GloVe,再到当前的技术水平,如 ELMo、ULMFiT 和 BERT,今天的单词嵌入已经从仅仅存储二进制的是或否状态发展到捕获句法关系和上下文。

对于其他类型的信息,如 Twitter 用户、Pinterest pins 或历史产品销售收入,通常需要一种全新的模型架构。

对于 Instacart 来说,试图优化他们的个人购物者的效率;已经建立了一个深度学习模型来预测对它们中的项目进行排序的最快顺序。对于该模型,他们通过使用 Keras [3]中的Embedding 方法将商店位置、购物项目和购物者嵌入到一个 10 维向量空间中。

The store location embedding enables the model to learn store layouts and generalize learnings across retailers and locations. The shopper embedding learns that shoppers may take consistently different routes through stores.

随后深入观察嵌入层会发现一些有趣的见解。

2-dimensional space representation of the embeddings using t-SNE [3]

大多数这些聚类(如上)对应于部门,即使部门数据从未用于学习嵌入。此外,我们可以放大到一个区域,比如左上角的蓝色肉类和海鲜部。还有其他产品出现在肉类和海鲜附近,但不是肉类和海鲜。相反,这些是在肉类和海鲜柜台出售的产品(如香料、卤汁、熟食或其他物品)。该模型比我们拥有的部门和通道编码数据更好地学习了商店的组织结构。[3]

类似的技术也用于出租车目的地预测 Kaggle 比赛[5],作者选择使用神经网络方法最终赢得比赛。

Categorical data (ie Client ID, Taxi ID, and Stand IDD) are represented in 10-dimension. Time is broken down to several bucket types and later embedded with the same dimension count.

特征压缩

在前面的出租车目的地预测示例中,我们看到嵌入了 6 个项目——3 个不同的 ID 类型和 3 个时间段。如果这种模型部署在生产中,并且随着我们不断向模型中添加越来越多的功能以提高其性能,在推理时间内处理所有事情的时间将会太慢。

因此,我们可以做的是在模型被训练后存储嵌入,并在以后加载它(像 Word2Vec 嵌入)。但是请注意,应该只存储本质上静态的嵌入(比如 IDs)。有效地使用加载已经预训练的嵌入将减少推断时间期间的计算和存储器负载。

最近邻搜索

正如我们之前在 Instacart 的可视化嵌入中看到的,相似的项目实际上在它们存在的多维向量空间中彼此更接近。利用这种行为,如果我们有一个基于距离感兴趣的样本向量,我们实际上可以寻找具有相似属性的项目。

例如,Pinterest 为它的 Pin 创建了一个 128 维的嵌入(又名 Pin2Vec)来捕捉每个 Pin 如何与 Pinners 相关的上下文[4]。然而,它的创建并不简单(不像 Instacart 或 Taxi competition ),因为他们采用了类似于 Word2Vec 的方法来实现这个表示。

“The learned Pin2Vec groups Pins with respect to a Pinner’s recent engagement” [4]

Pin2Vec architecture is inspired by Word2Vec [4]

结果是,与前一个建议相比,提出了一个更相关的建议。然而,对于数据稀疏的长尾引脚,他们仍然使用后者。

在 Pinterest 应用程序中,检索相关的 pin 码(即搜索结果)不仅仅是基于点击一个 pin 码。人们也可以利用视觉搜索功能,或应用程序顶部的文本栏。在这种情况下,还可以使用基于最近邻的搜索吗?

谷歌的丹·吉利克在伯克利的演讲中提出,如果我们能够放置来自文本、图像、视频或音频的所有不同的对象/实体,这是可能的;在同一个向量空间中。[6 (42:05) ]

By training all the model together, we can ensure that the embeddings reside in the same space.

以上图为例,有 2 个带标签的数据集:(I)问题-图像和(ii)问题-文档。通过一起训练两个模型数据集,我们可以确保问题、图像和文档都存在于单个向量空间中。

迁移学习

迁移学习是实体嵌入的另一个常见用途。本质上,它的意思是我们训练一个模型(即。一个语言模型),并将其用于另一类问题(即。文本分类)。

Training a classifier using BERT [1].

一般来说,使用预训练模型构建的模型训练速度更快,并且可以获得更好的结果。在我目前的组织中,我们利用 BERT 来完成我们的一个文本分类任务,在这个任务中,对于给定的问题,它很快获得了最先进的结果。

摘要

从仅仅表示单词及其语义,到表示时间和空间位置——能够将实体很好地表示成向量似乎有明显的优势。

然而,这里的关键词是“能够”。

虽然在将单词或文本表示成嵌入方面已经有了很大的发展,但是对于其他类型的实体来说就不一样了。正如我们在 Pin2Vec 的案例中所看到的,提出嵌入确实需要对问题有所了解,并在解决问题时有所创新。

即使这样,重要的是我们不要假设学习到的表征是 100%正确的。即使是 Word2Vec,尽管大肆宣传,在某些情况下也不是那么可靠。例如,在下面的图表中,奥巴马和巴拉克的关系就像萨科齐和尼古拉的关系一样有意义,因为上下文是名和姓;普京和梅德韦杰夫就不一样了,他们是两个独立的个体。关于单词嵌入的更多细节,请查看[7]中的文章。

Word2Vec paper [8]

参考文献(排名不分先后)

[1]杰·阿拉玛,插图画家伯特—http://jalammar.github.io/illustrated-bert/

[2]Embeddings @ Twitter—https://blog . Twitter . com/engineering/en _ us/topics/insights/2018/embeddingsattwitter . html

[3]使用表情符号的深度学习-https://tech . insta cart . com/Deep-Learning-with-e mojis-not-math-660 ba 1 ad 6 CDC

[4]对相关引脚应用深度学习—https://medium . com/the-graph/Applying-deep-learning-to-Related-Pins-a6 fee 3c 92 f5e

[5]人工神经网络在出租车目的地预测中的应用—https://arxiv.org/pdf/1508.00021.pdf

[6]万物嵌入:神经网络时代的搜索—https://www.youtube.com/watch?time_continue=36&v = jghvjxp 9 nhw

[7]超越单词嵌入第 3 部分—https://towards data science . com/超越单词嵌入-第 3 部分-四个常见缺陷-最先进的-神经-NLP-模型-c1d35d3496d0

[8]向量空间中单词表示的有效估计:https://arxiv.org/pdf/1301.3781.pdf

其他参考文献

理解失败

原文:https://towardsdatascience.com/understanding-faiss-619bb6db2d1a?source=collection_archive---------4-----------------------

…。相似性搜索的世界

FAISS: Facebook AI Similarity Search

几周前,我偶然发现了 FAISS——脸书的图书馆,用于对非常大的数据集进行相似性搜索。我的兴趣被激起了,几个小时的网上搜索让我找到了一个知识宝库。在这篇文章中,我希望写下(或者更确切地说,写下)一些与这个库相关的基本概念。在我的后续文章中,我将深入挖掘并探索一些更高级的概念。

相似性搜索和机器学习

通常在相似性搜索中,经常会有一个查询记录与存储的记录数据库(文档或图像等)进行比较。主要目的是检索一组与查询记录相似的数据库记录。所以,如果你有一张狗的图片,相似性搜索应该会给你一个有狗的图片列表(不是彩虹!)在他们身上。

当机器学习出现时,数据库对应于向量的集合。向量可以被视为由机器学习算法生成的输入数据的高维表示。这个上下文中的相似性搜索意味着基于某种相似性或距离度量来搜索给定查询向量的相似向量。

基于相似性进行搜索的一种简单方法是将查询向量与数据库中的所有其他向量进行比较。但是如果数据库有超过一百万个向量呢?输入 FAISS…

FAISS 的故事及其倒排索引

FAISS 是一个 C++库(当然有 python 绑定!)当向量的数量可能达到数百万或数十亿时,这确保了更快的相似性搜索。

它的核心是索引。请注意,索引无处不在!(尽管形式和名称不同)。在这篇文章中,我将详细阐述一个:“倒排文件索引”或“试管婴儿”

让我告诉你一个小故事(请在这里耐心听我说,我保证它很重要……)

Someland 的女王刚刚征服了一片新的领土,发现这片土地上的土著被隔离在三个不同的部落中,他们根本无法相互容忍。因此,为了避免争斗,她决定为每个部落建立三个独立的城市。有趣的是,每个部落都有一套独特的技能。这有助于女王识别一个人属于哪个部落。格林一家似乎生来就擅长园艺,大部分时间都在照料植物。廷克一家是聪明、善于分析的一群人,主要由建筑师、建筑商和科学家组成。最后,还有创意奇思妙想,他们以精通美术而闻名。他们大多是诗人、舞蹈家或艺术家。

城市建成了,部落首领被任命为各自部落的代表。出于行政管理的目的,女王的大臣们保留了一本“总名册”,记录了部落首领的名字以及每个城市的市民的名字。

一天,一群旅行者来到这个王国,请求避难。女王现在遇到了一个问题。她必须找到合适的志愿者,他们会同意让旅行者住在他们家里。(显然王国里没有客栈)。她知道市民们相当谨慎,只对与他们志趣相投的人感兴趣。

终于找到了解决办法。对于每个旅行者,酋长根据旅行者的特征与部落特征的匹配程度来决定他或她属于哪个部落。当旅行者到达他们各自的城市时,一些市民走出来,自愿为其中一位旅行者提供住宿,因为他们觉得这位旅行者的特点与他们的相符。嗯…问题解决了!(女王现在可以安心睡觉了)。

维奥拉。我刚刚给了你一个倒排索引如何工作的鸟瞰图。

技术细节…

我们用上面的故事打个比方。

王国的所有公民都是数据库中的向量,三个部落对应于三个独立的“集群”或“细胞”。然后,根据某种相似性度量,将向量分配给这三个聚类之一。(还记得不同的部落使用不同的技能使他们彼此区分开来吗?).通常,L2 距离测量以及类似 K-means 的聚类算法被用于此。

就像我们故事中的部落酋长一样,每个集群都由一个集群质心或“代码”来表示。就像部长们的“主书”一样,维护着一个单独的“码本”,它记录着每个簇的代码(或簇形心)及其相应的向量。这实质上是“倒排文件”或索引。

量化器用于决定向量属于哪个簇(我猜这主要是女王的工作)。因此,当一个查询向量进来时(就像我们故事中的旅行者),会根据它与聚类中心的相似性为查询向量找到一个合适的聚类(就像部落酋长根据他们的特征选择旅行者一样)。最后,在所选聚类中选择数量的相似向量作为查询结果返回(如自愿为旅行者提供住宿的城市居民)。这可以看作是倒排索引的一个非常基本的工作。

和一些代码…

首先,用 python 绑定安装 FAISS 库。请按照以下网址给出的说明操作:https://github . com/Facebook research/faiss/blob/master/install . MD

然后,使用以下命令导入 python 中的库和其他依赖项:

import numpy as np import faiss  # this will import the faiss library

现在,让我们为数据库创建一些向量。FAISS 要求预先定义数据库向量的维度。我们创建了大约 200 个维数为 128 的向量。这将创建一个(200 * 128)矢量矩阵。请注意,所有向量值都存储在 float 32 类型中。

dimension = 128    # dimensions of each vector n = 200    # number of vectors np.random.seed(1) db_vectors = np.random.random((n, dimension)).astype('float32')

我们对向量使用“IndexIVFFlat”索引类型。这里的“平坦”表示矢量被原样存储,没有任何压缩或量化(稍后将详细介绍)。试管婴儿指数有两个参数:

  • nlist:指定要形成的簇的数量
  • 量化器:将向量分配给特定的簇。这通常是另一个使用 L2 距离度量的指数(我们使用 FlatL2 指数)
nlist = 5  # number of clustersquantiser = faiss.IndexFlatL2(dimension) index = faiss.IndexIVFFlat(quantiser, dimension, nlist,   faiss.METRIC_L2)

必须首先训练索引以创建“nlist”个聚类,然后将向量添加到这些聚类中。“is_trained”标志表示索引是否被训练,“ntotal”属性显示添加到索引的向量的总数。

print(index.is_trained)   # Falseindex.train(db_vectors)  # train on the database vectorsprint(index.ntotal)   # 0index.add(db_vectors)   # add the vectors and update the indexprint(index.is_trained)  # Trueprint(index.ntotal)   # 200

接下来,我们在索引上搜索 10 个查询向量。“nprobe”参数指定在搜索操作期间要访问的集群数。这可以被视为超参数,可以对其进行调整以获得不同的结果。请注意,“nprobe”不能超过“nlist”。

“k”指定了从被访问的聚类中返回的相似向量的数量。

nprobe = 2  # find 2 most similar clustersn_query = 10 k = 3  # return 3 nearest neighboursnp.random.seed(0) query_vectors = np.random.random((n_query, dimension)).astype('float32')distances, indices = index.search(query_vectors, k)

搜索操作将返回每个查询向量的 k 个最相似向量的 id(向量存储中的行号或索引)以及它们各自的距离。

distances: [[15.770459 16.773014 17.17131  17.439615 17.443993] [16.476107 18.52229  18.811913 18.974785 19.02668 ] [15.520995 16.500256 17.069542 17.483345 17.742079] [16.842718 17.712341 17.828487 18.699772 19.345257] [18.325392 18.495464 18.684456 18.70239  18.904179] [17.531885 18.18179  18.331263 19.429993 19.700233] [16.840158 17.03664  17.091755 17.34306  17.487806] [15.984037 16.380917 17.270592 17.620832 17.663855] [18.018503 18.0761   18.766172 18.956903 18.985767] [17.113918 17.385284 17.65757  18.122086 18.170212]]indices: [[185  35  96  80  75] [118  51 122 108  31] [148 149 173  27  84] [175 177  50  38  81] [ 44 144 174 105  70] [156  74 151 167 182] [ 57 144  18 174  74] [ 82  12  46  64 127] [ 52  73  59 138 131] [ 82  46  90  37 179]]

可以使用 write_index()函数将索引保存在磁盘上,以后可以使用 read_index()函数加载索引

faiss.write_index(index,"vector.index")  # save the index to diskindex = faiss.read_index("vector.index")  # load the index

那里!理解 faiss 索引的基本代码!

FAISS 还提供什么?

FAISS 有一些功能,包括:

  • GPU 和多线程对索引操作的支持
  • 降维:使用主成分分析可以将维数较大的向量降维
  • 量化:FAISS 强调压缩和存储大规模向量的产品量化
  • 批处理,即一次搜索多个查询

这个可以用在哪里?

相似性搜索和信息检索是老朋友了!图像检索或文档检索甚至推荐系统都使用相似性搜索。比方说,你在网上购买某个品牌的手表时,在你的推荐列表中看到各种性质相似的手表。

另一个探索的途径是分类。例如,如果我们以陈词滥调的“猫和狗”图像识别为例,我们实际上可以预测给定的查询图像是猫还是狗,这取决于从猫和狗图像的数据库返回的最相似的图像(嗯…这绝对是另一个帖子!)

最后的想法

我觉得我几乎没有触及表面!FAISS 是一个有趣的图书馆,肯定还有很多值得探索的地方。将所有内容都压缩在一篇文章中可能会让你滚动很长时间!因此,我的下一篇文章将进一步深入这个库,并解释一个叫做产品量化的高级概念。

参考资料:

[## facebookresearch/faiss

一个用于高效相似性搜索和密集向量聚类的库。- facebookresearch/faiss

github.com](https://github.com/facebookresearch/faiss/wiki)

感谢阅读!!!

了解修正初始化

原文:https://towardsdatascience.com/understanding-fixup-initialization-6bf08d41b427?source=collection_archive---------17-----------------------

如何在没有归一化层的情况下训练残差网络?

我们为什么要关心初始化呢?

权重矩阵的正确初始化极其重要。根据杰瑞米·霍华德的说法,由于初始化不当,人们几十年来都无法训练神经网络。为了看到它,我们可以重现杰里米讲座中的一个实验。让我们初始化一个随机权重矩阵和一个向量。我们可以通过取 x - > Ax 并重复这个过程 n 次来模拟一个神经网络。

因此,我们将看到,均值和标准差都是无穷大。错误在于我们的随机初始化。

幸运的是,还有其他初始化权重矩阵的方法。其中之一是修复。

什么是修正?

fixup(fixup-update initial ization)是最近由、Yann N. Dauphin 和马腾宇等人提出的一种用于资源网的初始化方法。在他们的论文中,作者展示了在没有批量范数层的情况下训练残差网络是可能的。此外,作者还在图像分类和机器翻译方面取得了很好的效果。

修复的动机

让我们考虑没有规范化层的 ResNet 的基本块。在这种网络的某些区域(正同质块),该术语的详细描述在文章中提供。)方差随深度呈指数增长:

Relationship between variance in the subsequent layers.

因此,可能会出现收敛、训练速度和推广能力方面的问题。标准化层是一个解决方案。近年来,人们认为这个解决方案是独一无二的。

然而,正如我们将看到的,这是不真实的。

目标

如果我们以直观的方式考虑分解梯度(如果梯度变得太大,那么很容易超过最小值),我们可以注意到,如果在每一步中输出的变化是 O(η),其中η是学习速率,则问题不会发生。更正式地说:

Condition for change in f after each step.

因此,如果我们有 L 个剩余分支,我们希望每个分支平均更新 O(η/L)。

现在,我们假设每个剩余分支有 m 层,其中 m 是一个小正整数(通常是 2 或 3)。

作者证明了如果标度因子(除了最小的那个)的乘积为 O(η),则 SGD 每一步的输出变化为 O(η)。

The constraint for the product of scaling factors.

因此,提出了以下公式:

Scaling factors a_i.

加速修复

现在,我们已经实现了我们的主要目标,我们可以考虑提高网络性能的东西。

使用标量偏差和乘数是一种常见的做法,因为它们使每一层的输出适合后续层的激活。如果我们想改变平均值,我们只需添加一个偏差。类似地,乘数有助于操纵标准差。

此外,作者还发现:

“我们发现,在每个权重层和非线性激活层之前只插入一个标量偏差就可以显著提高训练性能。”

在具有乘数的分支中,这反过来导致乘数的增长,从而增加其他层的有效学习率。特别地,我们观察到,每个剩余分支仅插入一个标量乘数模仿了具有归一化的网络的权重范数动态,并且使我们免于搜索新的学习速率表。”

记住所有这些,建议残差块的以下架构:

Basic residual blocks of ResNet, Fixup with and without bias.

总而言之,为了修复和初始化您的网络,您必须:

1.将每个残差分支的分类层和最后一层初始化为 0。

2.使用标准方法(例如,何等人(2015))初始化每隔一个层,并通过 L^(1/(2m-2 仅缩放剩余分支内的权重层)

3.在每个分支中添加一个标量乘数(初始化为 1 ),在每个卷积、线性和元素激活层之前添加一个标量偏差(初始化为 0)。

值得注意的是,第二点是在没有正则化的情况下训练深度神经网络所必须的,而其他两点可以提高其性能。

PyTorch 实现

论文的实现可以在作者的一个 GitHub 上找到。我们将讨论最重要的部分。

首先,我们初始化两个基本的修正块:FixupBasicBlock 和 FixupBottleneck。如论文中所述,标量偏差和比例因子分别设置为 0 和 1。

与 FixupBasicBlock 相比,FixupBottleneck 多了一个卷积层和两个偏差。

然后,我们准备构建我们的第一个修正初始化 ResNet。我们首先定义基底,如层数、卷积等。

然后我们遍历网络的所有部分并初始化权重。请注意,比例因子是根据公式 L^(1/(2m-2)).计算的顶部的额外因子 2 有助于保持标准差等于 1。

由于 FixupBasicBlock 有 2 层,m=2,我们通过因子 L^(-0.5).来缩放权重类似地,FixupBottleneck 有三层,所以我们按 L^(-0.25 缩放)

最后,我们可以定义我们的修正初始化 ResNets!

结论

修正初始化是初始化权重矩阵的强大工具。这是非常重要的,因为它是第一种方法之一,允许在没有批量范数层的情况下训练甚至非常深的神经网络。

使用无监督主题建模理解堡垒之夜的 Reddit 社区

原文:https://towardsdatascience.com/understanding-fortnites-reddit-community-using-unsupervised-topic-modeling-30f984f58129?source=collection_archive---------18-----------------------

概观

堡垒之夜打破了抽搐流记录,成为一个全国性的现象。不足为奇的是,正如许多视频游戏发生的那样,Reddit 上形成了大型社区来讨论这款游戏。虽然有多个堡垒之夜子街道,但我主要关注 r/FortNiteBR 和 r/FortniteCompetitive。r/FortNiteBR 目前拥有 110 万用户,可以说是堡垒之夜最大的专门论坛,而 r/FortniteCompetitive 目前拥有 18.3 万用户,与 r/FortNiteMobile 等子网站相比,它可以更好地了解竞争社区。由于这两个子街道都有一年多的历史,它们随着堡垒之夜史无前例的崛起而成长。我们可以使用这些子街道上的非结构化数据来洞察社区吗?

个人动机

作为这两个子编辑的订阅者,我注意到 r/FortNiteBR 和 r/fortnitecompetic 上的对话有很大的不同。顾名思义,r/FortNiteBR 适用于整个社区,而 r/fortnitecompetic 仅适用于该社区。由于我不会阅读每个子网站上的所有帖子,通常只看最受欢迎的,所以我想比较所有子网站,而不是根据我有限的个人阅读进行比较。在普通社区和竞争社区上举行的对话之间有可量化的差异吗?

商业案例

除了我的好奇心之外,还存在一个商业案例,用于对每个子主题中讨论的主题进行建模。Subreddit 管理员可以从总体上感受到他们的社区正在讨论什么。此外,堡垒之夜背后的公司 Epic Games 可以看到社区如何应对游戏变化,什么主导了围绕游戏的讨论,以及他们的社区是如何划分的。有了这些见解,Epic Games 可以调整他们的游戏开发计划,以迎合某些群体,并保持他们的玩家群参与。在过去,Epic Games 因不听取他们社区的意见而赢得了声誉,并因此让游戏失败。

抓取 API

首先,我使用 Python 的内置请求库点击了以下端点:

[https://api.pushshift.io/reddit/search/submission/](https://api.pushshift.io/reddit/search/submission/')

Pushshift.io 是抓取 Reddit 数据的一个很好的资源,因为他们自己有一个很大的存储,并且有一个比 Reddit 相对更容易理解的 API。端点将返回最多 500 个帖子,因为我想要多个 subreddit 的全部,所以我不得不多次点击这个端点。我用以下参数达到了端点:

params = {
 ‘size’:’500', 
 ‘subreddit’: SUBREDDIT, 
 ‘num_comments’:’>10', 
 ‘before’ : checkpoint[‘date’]
}

before参数允许我在多次调用中抓取所有子编辑。我存储了一个本地 JSON 文件checkpoint,它记录了我在子编辑历史中的位置。由于这个过程花费了相当多的时间,本地文件允许我在保持状态的同时随意启动和停止抓取脚本。最后,我过滤了 10 条评论或更少的帖子,假设参与度低的帖子不能反映社区的情绪。

改变我的方法

在遇到多个 API 极限错误并等待脚本完成几个小时后,我意识到我需要用不同的方法来抓取注释。一个帖子可能有超过 100 条评论,由于对一个请求返回的评论数量也有限制,我需要运行更多的请求。

为了解决第一个问题,我改用 Reddit API 而不是 Pushshift。Reddit 的速率限制是每个账户每分钟 60 个请求,而 Pushshfit 的速率限制是 200 个请求。然而,如果需要,我可以做多个 Reddit 开发帐户。实际上,我在 Reddit API 上收到的速率限制错误比 Pushshift 少得多。最流行的 Python Reddit API 包装器是 [Praw](https://praw.readthedocs.io/en/latest/) ,但是 Praw 是写在请求库之上的,这是阻塞的。为了解决后一个问题,我不得不切换到异步方法。

对于异步请求,我使用了 aiohttp 。这个包的语法非常类似于请求。aiohttp 旨在与 asyncio 一起使用,asyncio 是将带有async / await语法的并发编程引入 Python 3.4 的库。有一个轻微的学习曲线,因为这是我第一次使用 asyncio。然而,使用 Node.js 的经验使这个过程变得更加容易。

最后,Reddit API 以嵌套的 JSON 结构返回注释。这反映了 Reddit 评论的树形结构。为了获得表格形式的评论,我必须在评论树上运行一个修改过的 BFS。见下文:

数据

抓取之后,我们有三个数据框架:帖子、评论和补丁。对于下面的 post 数据框架,我们主要关注的是titleselftext列。注意score每一行都是 1.0;这是 Pushshift API 的一个缺点,因为它在爬行时存储帖子的分数(与当前值相比)。

Posts DataFrame

评论数据框架也相对简单。Body是评论的文本,parent_id是评论所属文章的 id,是上票数减去下票数。请注意,由于使用了 Reddit API,这些分值会得到更新。

Comments DataFrame

最后,我们有一个数据框架,列出了每个补丁,补丁发布的日期,以及补丁内容的快速总结。这些都是用 IGN 的美汤(bs4)刮出来的。

Patches DataFrame

清理数据

由于刮擦数据的性质,数据相当脏。我不得不删除许多非字母数字字符。此外,还有不间断的空格符、换行符等。接下来,我删除了作者为[deleted]的行,因为这意味着标题和自我文本也被删除了。许多帖子也是图片,所以自我文本是空的;这些行也被删除。

接下来,我遵循标准的 NLP 管道,删除停用词,对数据进行标记化和词条化。下面的代码片段展示了这个过程的大部分:

最后,我使用 gensim 的短语模型在语料库中寻找二元和三元语法。这些子街道中常见的双字母组合的一个例子是battle_royale,因为这两个词经常一起出现。

建模主题

潜在狄利克雷分配

LDA 是一种从一组文档中提取潜在或隐藏主题的方法。LDA 假设文档由从概率分布中采样的一组主题组成,主题由从概率分布中采样的单词组成。实际的学习方法及其背后的数学原理是另一个讨论的话题。但是,更多的阅读可以在这里完成。需要注意的是,LDA 不为你选择话题数量,也不为话题贴标签;根据主题中最常用的词来标记主题是由你决定的。

Gensim 使得 LDA 很容易实现:

我们过滤掉最常用和最罕见的词。docs是一个 2d 数组,其中每个文档是一个令牌(单词)数组。单个文档可以用多种方式定义。

定义文档

一个潜在的狄利克雷分配模型期望文档有合适的大小。Reddit 标题通常不符合这一标准。除了过滤长度不超过 5 个令牌的帖子和评论之外,我还尝试了帖子标题、自我文本和评论的不同组合。我使用 pyLDAvis 软件包通过目测选择了最佳组合。pyLDAvis 允许您传递一个 gensim 模型,并在笔记本中获得一个 d3 构建的可视化。

我很快发现,仅仅使用 Reddit 标题不会提供连贯的主题。然后,我尝试将文档定义为帖子的标题、自我文本和所有评论。这个文档定义提供了相对一致的主题,但由于文档较大,所以速度较慢。此外,假设子注释应该是单个文档的一部分,这是一个逻辑上的小跳跃。最后,我决定将帖子的标题和自我文本作为一个单独的文档。结合使用 n 元语法,这种方法提供了最连贯的主题模型。

选择主题的数量

使用与 k-means 聚类时选择最佳主题数量相同的方法,我使用了 elbow 方法来选择具有最大化模型一致性分数的主题数量的模型。我使用了 Gensim 的内置一致性分数,但更深入的解释可以在这里找到

12 topics seem to be optimal

比较子记录

我现在对文档运行两个独立的 LDA 模型(文章标题+文章自我文本)。

r/FortNiteBR

我们看到合理的话题。例如,主题 6 可以是关于建筑,主题 8 可以被解释为武器平衡,而主题 9 可以是控制台对 PC 的辩论。

r/FortniteCompetitive

我们看到一些类似的话题。在第 6 节中,我们讨论了双泵,所以我们可以把这个话题称为武器战略,第 4 节是建筑战略,第 7 节是关于竞技玩家和流的讨论。当我们检查每个子编辑中主题的大小以及主题中使用的确切单词时,就会出现差异。虽然两个模型都有一个讨论飘带的主题,但 Nickmercs、Tfue、偷猎、忍者和神话是竞争子编辑中的常用词,而在普通子编辑中只有忍者和神话。

如果你想自己玩这些可视化,也可以通过补丁过滤,看看我做的 React 应用

未来计划

React 应用

我决定建立一个小的 React 应用程序,允许任何人检查每一个可视化。这款应用在https://jeromecohen.github.io/fortnite举办,它允许任何人通过子编辑和补丁检查主题。pyLDAvis 允许您将可视化保存为 JSON 文件或独立的 HTML。我将 HTML 文件从 CDNs 中提取的脚本(d3 和一个定制的 d3 脚本)导入到我的 React 项目中。pyLDAvis 使用定制脚本来解析 JSON 文件并将其转化为可视化。d3 v3 不适合我,所以我找到了一个对 pyLDAvis 库的 pull 请求,该请求更新了他们的 d3 脚本以与 d3 v5 兼容。在安装了 d3 v5 并稍微调整了 pull 请求之后,可视化就可以运行了!

在线应用程序

自从我上一次刮起 subreddits 以来,堡垒之夜社区发生了很多事情。如果我的应用程序可以自动更新,那就太酷了。gensim 模型允许在线培训,即当新文档可用时更新模型。对 scraper 笔记本稍加调整,它可以作为一个独立的脚本运行在 cron 作业上,从任何子编辑中获取新的帖子或评论。一旦脚本完成,新文档就可以被传递给一个 gensim 模型,该模型被包装在一个简单的 Flask API 中。API 会将表示更新后的可视化的 JSON 文件返回给我已经构建好的 React 客户端。React 客户机已经预料到了,所以唯一需要的改变是改变 GET URL(当然,也可以改变 UI)。

分支项目

随着时间的推移,探索这两个社区的情绪可能会产生一些有趣的视觉效果。或许,我们会看到特定地区的平均情绪出现正峰值或负谷值。如果想用这些数据建立一个预测项目,可以很容易地使用 post ids 获得更新的分数。对于关心因果报应的社区成员来说,预测给定帖子的分数或评论数量可能是一个有用的模型。

感谢阅读!在【https://github.com/JeromeCohen/fortnite】检查所有代码或获取数据

理解高斯过程,苏格拉底的方式

原文:https://towardsdatascience.com/understanding-gaussian-process-the-socratic-way-ba02369d804?source=collection_archive---------0-----------------------

高斯过程是一种机器学习技术。你可以用它来做回归,分类,以及其他事情。高斯过程是一种贝叶斯方法,其预测具有不确定性。例如,它将预测明天的股票价格为 100 美元,标准差为 30 美元。了解不确定性对于算法交易等应用很重要。我设计过赚了大钱的交易策略和亏了大钱的策略。我亲身体会到不确定性会给你带来多大的影响。所以我决定研究高斯过程的内部运作。

高斯过程可以用几个公式来解释。但是这些公式背后有丰富的直觉和含义。为了学好英语,我将运用苏格拉底式教学法,即提问和回答。

我将使用以下模板进行解释:

  1. 高斯过程模型部分定义了高斯过程先验和似然性。并解释了模型参数的先验性和似然性。
  2. 计算后验概率的部分从先验和似然中导出后验概率。它描述了如何使用后验概率进行预测。
  3. 参数学习部分找到模型参数的最佳具体值。上一节中的后验概率是一个提到模型参数的符号表达式。在我们找到模型参数的具体值之后,我们可以将后验估计成一个具体的数字。

这篇文章作为高斯过程的基本介绍;它帮助你在头脑中建立第一个 GP-sense。在应用程序设置中,您可能会遇到两个使高斯过程模型更实用的技巧:

根据我的经验,理解本文中的基础知识至少占了概念负担的一半。在你建立了足够的 GP-sense 之后,理解高级高斯过程模型就容易多了。

一些符号

中支持文本中的 Unicode。这允许我写很多数学下标符号,比如 X₁Xₙ.但是我不能写下其他的下标。例如:

所以在正文中,我会用一个下划线“”来引出这样的下标,比如 *X** 和 X_1* 。

如果一些数学符号在你的手机上显示为问号,请尝试从电脑上阅读这篇文章。这是一个已知的 Unicode 呈现问题。

高斯过程模型

本节介绍回归的高斯过程模型。它解决了一个回归任务。

回归任务

在一个回归任务中,我们有一组成对的训练数据点 (X₁,Y₁)(X₂,Y₂) ,…, (Xₙ,Yₙ) ,其中 XᵢYᵢ,为实值。我们用符号ℝ来表示所有实数值的集合。并用 (X,Y) 表示训练数据,其中 XY 都是长度为 n 的向量。

任务是找到一个函数 f ,它取一个实值并返回一个实值,记为 f : ℝ ⟼ ℝ.这个函数应该接近训练数据 (X,Y) 。“接近”意味着如果我们在 f 中插入一个 Xᵢ ,我们应该得到一个接近 Yᵢ 的值。这是机器学习中典型的回归任务。

定义函数的映射视图

我们习惯看到一个函数带体,像 f(x) = x+1 ,带体" x+1" 。这个主体根据其输入 x 计算函数值。很多机器学习技术都是为功能找身体。比如线性回归以 f(x) = ax+b 的形式找到函数体。

但是在数学中,我们可以定义一个没有任何物体的函数。功能是从输入到输出的映射。body 仅仅是描述这种映射的一种简洁的方式。我们可以通过指定函数的所有输入输出映射来定义函数,而不是使用主体。例如,下面的映射定义了一个函数 f: ℝ ⟼ ℝ,域为{1,5},范围为{7,4}:

我们不知道这个函数的主体是什么,但这并不妨碍我们定义它——我们只需要写下从每个输入到输出的映射。我们需要更多的空间来写下它们,但这在数学上是有效的。

现实生活中作为函数的映射

你可能会问,我们在日常生活中使用函数的这种映射视图吗?是的,我们一直在使用它。在学校,我们看到了三角表:

表格的第三列显示了半径为 0、π/2、的正弦函数值,以此类推。你的初等数学书给你这个表而不是一个函数体来计算任意次的正弦值,因为那个公式非常复杂 —想想看,你并不真的知道如何从一个输入计算正弦函数值,比如π —你记得它的值,那是一个输入-输出映射视图。

这个表的缺点很明显,你不知道正弦在π/5,或者 2.7π的值。出于篇幅原因,该表仅列出了输入-输出映射的子集。这就是回归可以发挥作用的地方——它可以找到完整的映射。

在本文中,我们将使用高斯过程来学习一个看起来像正弦函数的函数。定义函数的映射观点是高斯过程背后的直觉。

首先,让我们生成一些训练数据。我们在 0 和 2π之间的一些 x 轴位置计算真正弦函数值,并向其中添加噪声。x 轴位置不是等距的。如下图所示,一些 x 轴区域比其他区域包含更多的数据点。在此图中,蓝色十字“x”标记训练数据点。有 50 分。我用这个代码来生成训练数据。如果要运行代码,请克隆 publicunderstanding _ Gaussian _ processGithub 库,用 Python 3 解释器运行代码。

Training data points. Blue “x” markers are the data points. They are not equidistant.

我们的回归任务是学习一个能很好解释这个数据的函数。我们已经知道了正确的答案——这个函数是一个正弦函数。我们将看到高斯过程如何从生成的训练数据中学习该函数。

代表位置的实数集

函数 f : ℝ ⟼ ℝ将ℝ作为它的域,这意味着它接受任何实值输入。在我们的回归任务中,输入 x 是我们希望 f 接近 sin(x) 的值的位置。我们可以将域ℝ分成三组不相交的位置:

  • X 是我们训练数据中的一组位置。 X 是一个长度为 n 的向量:

  • 我们想要评估我们的底层函数 f 的一组测试位置。记住这个回归任务的目标是找到 f ,这样我们就可以在测试位置得到它的值。X_* 是有限的,因为实际上,在我们的一生中,我们只能在有限数量的测试位置评估一个函数。 X_* 是长度为 n_* 的向量:

  • X ₒ(下标是字母“o”代表其他,不是数字 0)是ℝ.除 XX_* 以外的地点集合集合 X_o 的长度是无限的,因为在全实直线中,除了 XX_* 之外,还有无穷多个。记下 X ₒ为无限长的向量 nₒ :

代表函数值的随机变量

在我们定义了函数 f 的输入之后,我们开始定义它的输出。对于每个输入位置 x ,我们引入一个随机变量 f(x) 来表示函数 f 在这个位置的可能的输出。你可以这样理解 f(x) :

  1. 随机变量 f(x) 有它的分布,我们还没有定义这个分布,但是剧透一下,它会是高斯的。我们使用这个分布来模拟 f 在位置 x 的可能值和它们出现的概率。高斯分布完全由其均值和方差来参数化。
  2. 在位置 x 最终的实际观测来自于 f(x) 的分布。换句话说,观测值是来自 f(x) 分布的样本。 f(x) 的方差控制这个样本可以偏离 f(x) 的平均值多少。请注意“最终”这个词,因为我们将引入另一个随机变量来对观测值进行抽样。原因在可能性部分会很清楚。

你可以看到这个模型与我们如何生成训练数据 (X,Y) 完全吻合。因为我们通过首先获得位置 X 处的真实正弦值(即平均值)并添加噪声(模拟方差)来生成 Y

注意 f(x) 只是位置 x 的随机变量的名字。请不要将 f(x) 解释为调用带参数 x 的函数 f 的函数应用。我决定在随机变量名称中包含位置信息,以使数学更容易理解。

由于我们正在模拟一个具有无限个输入的函数,我们需要引入无限个随机变量来表示它的输出,每个输入位置一个。对应于我们之前定义的位置的三个部分,我们将这些随机变量组织成三个相应的不相交集合:

  • f(X),长度为 n 的随机变量的向量,
  • f(X_)* ,长度为 n_* 的随机变量的向量。
  • f(X) ,一个无限长的随机变量向量 nₒ

重要提示(再次)

请注意 f(X) 是我们给一个随机变量列表的名字。那就是:

其中每个元素 f(X₁)f(X₂) 、…、 f(Xₙ) 都是与位置 X₁X₂ 等相关联的单个随机变量。请不要将 f(X) 解读为将函数 f 应用于输入 X ,因为我们不会定义函数 f 。同样适用于 f(X_)* 和 f(X)。

函数值是相互依赖的

既然我们已经为函数值引入了随机变量,我们需要假设它们是相互依赖的。这是一个非常重要的假设。没有它,我们就无法继续。

这是因为如果相反,我们假设这些随机变量是彼此独立的,那么知道在训练位置 X 的随机变量 f(X) 的观察数据 Y 将不会给出关于在测试位置 X_* 的可能随机变量值 f(X_)* 的任何信息。这意味着我们将无法学习一个可以描述测试位置值的回归函数。

所以我们需要一种方法来描述随机变量之间的依赖关系。在高斯过程中,我们使用随机变量 f(X)f(X_)* 和 f(X) 的多元高斯分布来定义它们的相关性和均值。

多元高斯分布由平均向量和协方差矩阵指定:

以上是多元高斯分布的模板。要完全定义这个分布,我们需要定义:

均值函数 m 给出这些随机变量的均值。我们使用 m(x) 来表示均值,也称为随机变量 f(x) 在位置 x. 处的期望值由于 x 表示一组位置, m(x) 是向量的形式,包含随机变量组的均值。因此,您将拥有:

  1. x=X 时,随机变量 f(X) 的均值向量 m(X)
  2. x=X_* 时,随机变量 f(X_)* 的平均向量 m(X_)* ,
  3. x=Om(Xₒ) 为随机变量 f(Xₒ) 的均值向量。

注意 m(x) 不是一个随机变量,它是一个以 x 为自变量的函数,返回位置 x 处相应随机变量的平均值。

我们还需要定义协方差矩阵中出现的协方差函数 k 。我们称 k内核函数。我们使用 k 来定义位置 xx’处任意两个随机变量 f(x)f(x’)之间的协方差。你会明白选择 k 是高斯过程中的关键。

均值函数 m

均值函数定义了向量 [f(X),f(X_),f(X* ₒ )]ᵀ 中每个随机变量的期望值。这里“ᵀ”代表转置运算符,它将列向量转换为行向量,这样我们就可以将它写在文本行中。均值函数 m 有值域ℝ和值域ℝ,即 m : ℝ ⟼ ℝ.当我们将 m 应用于上述每个位置时,我们得到一个平均值向量:

m 应该是什么样子?如果我们有关于函数 f 在每个位置的期望值的领域知识,我们可以将这些知识编码到 m 中。例如,如果您正在模拟服务器机房在给定时间 X 的温度,并且您知道平均温度,因为您将空调温度设置为 20 度,那么您可以设置 m(X) = 20 。但在大多数情况下,我们不知道。所以我们定义均值函数为零函数:

无论 x 是什么值,该函数都返回 0。你可能想知道为什么零均值函数是可以的,因为真实数据可能没有零均值。嗯,你总是可以标准化你的数据,所以它们的平均值为零。在大多数情况下,这是可行的。但有时,你确实需要更努力地思考非零均值函数,以获得更好的模型。

注意与 f(X) 不同的是, m(X) 不是一个随机变量,它是一个以 X 为自变量,返回一个实向量的函数。我们通常设置 m(X) = 0。

内核函数 k

协方差矩阵中的每一项代表一对随机变量 f(x)f(x’)之间的协方差。X 和X′可以来自位置集合 XX_* 。我们需要定义一个函数 k(x,x’)来返回 f(x)f(x’)之间的协方差。k应该是什么样子?

从我们的训练数据中,我们注意到如果两个位置 xx′在附近,它们对应的函数值是相似的。这就是平滑函数的表现。我们想对相似函数值的这种影响建模,当它们的评估位置在附近时。

请记住,我们使用随机变量 f(x)f(x’)来模拟函数 f 在位置 xx’的可能值。在随机变量的语言中,相似意味着具有高的正协方差。这是因为当 f(x)f(x’)具有高的正协方差时,当来自 f(x) 的样本是大值时,来自f(x’)的样本也更可能是大值——f(x)f(x’)同向协变。这些相近位置的相似值构成了平滑曲线中的点。

两个自变量 xx′的许多函数满足我们的要求,当 xx′靠近时返回较大的正值,当它们远离时返回较小的值。我们关注以下一个:

在这个公式中, exp 是指数函数。 l 称为长度刻度, σ 称为信号方差。 lσ 是标量。它们是模型参数。我们不知道这些模型参数的值;我们将使用参数学习来为它们找到好的值。这个核函数由于其结构而被称为平方指数核。

请注意,内核函数只提到了 xx’。完全没有提到函数值 Y 。这是因为要决定两个位置之间的距离,知道 xx′就足够了。别担心,我们在引入可能性的时候会用到 Y

我们可以验证这个核函数满足我们的要求:

  1. 指数函数和 σ 都是正的,所以协方差总是正的。
  2. x 等于x’,k 有最大值 σ ,所以它们的距离最小为 0。指数函数的值为 1,因此核函数的值为 σ。
  3. 随着 xx′漂移分开,当 x 和x′无限分开时,核函数减小并达到其最小值 0。

现在我们可以定义协方差矩阵中的元素:

我们需要使用 k 来定义这个协方差矩阵中的九个块条目。让我们以 k(X,X) 为例,其余条目类似。

让我们将 k(X,X) 表示为 n ×n 矩阵,其中我们将函数 k 应用于 X. 中的每一对位置,并且我们将这些位置对按照以下精确顺序放置:

同样,我们可以定义 n×n_* 矩阵 k(X,X_)。由于核函数的定义, k(x,x’)= k(x’,x),协方差矩阵是对称的。所以我们有协方差 k(X_,X) = k(X,X_)ᵀ* 。并且我们定义了 n * *×n** 矩阵 k(X_,X_)。

我们可以继续写下与 X ₒ相关的五个词条,比如 k(X,Xₒ)k(X_,Xₒ)* 。这些条目将是无限维的矩阵,因为 X ₒ的长度是无限的。写下无限维的矩阵似乎不是一个有趣的任务。操纵它们似乎也不容易。

好消息是,我们不必处理那些无限矩阵这是因为,实际上,我们只对与 XX_* 相关的部分感兴趣。这些部分是有限的。因此,我们只需要下面用红框突出显示的联合概率密度的部分:

高斯边缘化规则告诉我们,高亮部分也形成多元高斯分布。这个分布是随机变量 f(X)f(X_)* 的分布,其均值和协方差矩阵与红色框中突出显示的完全相同。因此,从现在开始,我们将使用以下有限分布:

或者,我们可以用概率密度函数来表示这种分布:

在上面的公式中,我用 K 来表示整个协方差矩阵,以节省空间。 det(K) 表示协方差矩阵 K 的行列式, K⁻ 表示 K 的逆矩阵。常数 的幂为 (n+n_)/2* 因为 [f(X),f(X_)]ᵀ* 的长度为 n+n_ —* 由于 GP 先验是一个 n+n_* 维高斯分布,每个数据点都有一个单独的维,包括训练数据点(编号为 n )和测试数据点(编号为

写公式的时候,概率密度函数相当长,所以我经常用符号𝒩(a;μ,σ)来表示具有均值 μ 和协方差σ的随机变量 a 的高斯概率密度函数。

顺便说一下,我知道多元高斯的概率密度函数看起来很吓人。我天真的建议是自己写几遍,不要看。多元高斯是现代机器学习中非常重要的主题。你可以在生成人脸或者时间序列预测中找到。

高斯过程先验(GP 先验)

我们称上述多元高斯分布为高斯过程先验(GP 先验)。它代表了我们对正在建模的底层函数值如何联合分布的假设。

GP prior 是函数上的分布

人们说 GP prior 是函数的分布。要理解为什么我们需要理解以下两点:

  1. 随机变量向量【f(x)】,f(X_)]ᵀ* 代表一个函数。这就是我们需要映射视图来定义函数的地方。
  2. 这些随机变量的多元高斯分布为不同的函数给出了不同的概率

GP 先验是随机变量向量上的多元高斯分布:

请注意,集合 XX_* 是固定的,因为实际上 X 是作为训练数据的一部分给出的,它是固定的。 X_* 包含测试位置;它也是固定的——我们知道要在哪里计算函数。

所以上面的随机变量向量代表位置 XX_* 的函数值。从映射视图来定义函数,这些随机变量代表下面的函数。

由于 XX_* 是固定的,这个函数就可以用随机变量向量【f(x)】,f(X_)]ᵀ* 来表示。现在很容易看出 GP 先验描述了函数的分布。让我们通过假设零均值函数再次写下 GP 先验的概率密度函数,并使用 K 来表示协方差矩阵以节省空间:

让我们在同一个固定的 X={1}X_={2}* 上写下两个示例函数。第一个功能 f₁ 是:

第二个功能 f₂ 是:

在这个例子中,因为 XX_* 的长度都是 1,所以概率密度函数接受长度为 2 的向量并返回 0 和 1 之间的概率数。

如果我们将向量[3,4] f₁ 和[5,6】f₂ 代入上述概率密度函数,我们得到两个标量数 prob₁prob₂ :

下图说明了这种概率密度函数。我在 x 轴上画出了函数 f₁ 和函数 f₂ 的位置,以及它们在 y 轴上对应的概率数。钟形曲线代表全概率密度。

Illustration of distribution over functions, with highlighted function f₁ and f₂

该图显示了为什么 GP 先验是函数的分布:GP 先验概率密度函数将函数值向量,如 f₁ 和函数f₂作为输入,并返回概率数。

请注意:

  1. 在上图中,x 轴代表函数值向量。所有这些函数都有相同的域(x 轴位置,在我们的例子中是 1 和 2)。
  2. 这个数字只是一个说明。实际上, f₁ 的矢量不必在左边,而 f₂ 的矢量不必在右边。函数的这种分布没有必要看起来像钟形曲线。并且 prob₁ 不必大于 prob₂

之前从 GP 取样

由于 GP 先验是多元高斯分布,我们可以从中抽样。我生成了 600 个 0 到 2π之间的等距值,以形成我的采样位置。所以我的 GP 先验是 600 维多元高斯分布。我使用了一个零均值函数,并设置了长度标度 l = 1 和信号方差 σ =1。下图显示了从本次 GP prior 中抽取的 50 份样本。我用这个代码从 GP 之前采样。

Samples from the GP prior

请暂时忽略橙色箭头。在图中,每条曲线由 600 个数据点组成。

在图中,我给了一些曲线更不透明的颜色,给了一些更透明的颜色,以证明根据先验知识,一些函数比其他函数更可能被绘制出来。一个函数越可能,我用来显示它的曲线的不透明颜色就越多。

为什么不同的曲线有不同的概率?这是因为每条曲线(由 600 个点组成)都是从 600 维高斯分布中抽取的样本。该多元高斯分布的概率密度函数定义了样本在抽奖中出现的可能性。如果一个函数越接近先验分布的均值,它被抽样的概率就越高。

从上图也可以看出,即使我们将均值函数 m(x) 设置为零(这样在每个 x 轴位置,对应的随机变量均值为零),所抽取的样本(其值在 y 轴显示)也不一定为零。就像当你从均值为零的单变量高斯分布中抽取样本时,样本可能不等于零。

纯属运气,我注意到在这 50 个采样函数中,有一个是橙色曲线,有一个橙色箭头指向它。这条曲线非常接近我们想要找到的正弦函数。当运气来临时,让我们利用它来强调重要的一点。这条橙色曲线说明了贝叶斯学习的本质:我们设计先验分布来包含一大组候选函数,然后使用训练数据来重新加权这些候选函数。

我们可以从以下意义上理解这种“重新加权”:

  1. 我们事先设计 GP 不是通过考虑训练数据,而是通过考虑我们使用的分布的数学便利性以及它可以描述什么函数。在我们的上下文中,我们选择高斯分布是因为它具有良好的性质,我们选择平方指数核来模拟平滑函数。这意味着先验可能无法很好地解释训练数据,如上图所示,对于甚至不像正弦波的函数,先验的概率很高。
  2. 给定训练数据,以及我们将在下一节中介绍的可能性,贝叶斯学习使用贝叶斯规则来重新加权先验中的函数。贝叶斯规则输出后验分布。后验分布是与先验分布相同的一组函数的分布,但是它将不同的概率与这些函数相关联。后验概率给出了接近训练数据集的函数比远离训练数据集的函数高得多的概率。

通过下图中的后验概率抽样函数(稍后我将展示如何计算后验概率),您可以看到贝叶斯规则的效果。它绘制了来自后验概率的 50 个采样函数:

Sampled functions from the posterior

这些采样函数非常接近我们的训练数据点,这些数据点用蓝色的十字标记。这些曲线的高不透明度表明它们来自后验分布的高概率。这表明后验可以比先验更好地解释训练数据-通过高概率,后验区分出与训练数据点相似的函数。你看不到曲线远离正弦波,因为它们在后验概率很小,不容易采样。

贝叶斯规则,在重新加权视图中

注意因为我们的先验是连续随机变量的分布,它描述了一个无限的函数集。贝叶斯规则需要遍历这些无限数量的函数,并对它们重新加权。一个经历无限事物的过程如何终止?让我们来看看贝叶斯法则:

我们从一个候选函数 f(X) 开始,它具有来自先验的某个概率,那就是 p(f(X)) ,它是介于 0 和 1 之间的概率数。贝叶斯规则用一个因子来衡量这个概率,写成分数。这个比例因子与给定候选函数的数据的似然性成比例,这是分子,由平均似然性归一化,在所有可能的(和无限个)候选函数上平均,这是分母。

积分是贝叶斯规则中的一部分,它遍历无限可能的函数集。我们已经知道积分是在有限的步骤中计算出的无穷和。这就是为什么贝叶斯规则的计算会终止。

注意,我应该将集成中的名字 f(X) 重命名为 g(X) :

这个版本的贝叶斯法则在数学上更清晰。在数学中,一个名字只能代表一件事——2 总是代表数字 2,而不是这里代表 3,那里代表 4。所以在上面的公式中, f(X) 是我们要计算后验概率的函数; g(X) 是积分变量,对所有可能的 n 维实向量进行积分。他们是两个不同的东西,所以我们给他们不同的名字。

然而,在贝叶斯规则的第一个版本中,我们使用 f(X) 来表示我们想要计算后验概率的函数和积分变量。这在数学上令人困惑,但不幸的是,人们通常就是这么写的。

继续我们的橙色曲线示例,并尝试理解“后验概率给了这条橙色曲线更高的概率”这句话的含义:这条橙色曲线在 600 个固定 x 轴位置处的 y 值形成了一个 600 个实数的向量。这个向量应该在我们的后验分布中得到更高的概率(顺便说一下,它也是一个多元高斯分布,你稍后会看到)。

之前,我们说过贝叶斯规则为接近训练数据的函数赋予更高的概率。现在让我们想想后验是如何做到这一点的。它必须给予接近训练观察值 Y 的实数向量(代表函数值)更高的概率。因此,训练位置 X 处的后验均值不能为零;他们应该更靠近 Y 吧?就像如果你想让一个单变量高斯分布给一个数很高的概率,比如说 6,那么这个高斯分布应该有一个更接近 6 的均值,希望方差不要太大。

目前,直观地理解贝叶斯规则采用 GP 先验,参考训练数据,计算后验就足够了。稍后在计算后验概率部分,您将看到这种理解是如何反映在数学中的。

贝叶斯学习的本质表明,当你设计先验时:

  1. 你不希望你的先验过于宽泛,否则寻找子集会更加困难。
  2. 您也不希望您的先验过于严格,因为它可能会排除我们想要建模的真正功能。

贝叶斯学习的这种观点是使用数据对先验的东西进行重新加权,这就是我们想要查看先验样本的原因——我们想要确保我们设计的先验允许我们想要建模的函数。例如,通过查看另一组样本,我将长度比例 l 更改为 0.1:

Samples from the GP prior with lengthscale 0.1, and signal variance σ²=1

我们立即知道这个先验不适用于正弦函数建模。因为样本是两个摆动的,看起来不像正弦波。

在实践中,您从先验中抽取样本,以查看这些样本函数的外观和感觉是否与您拥有的实际训练数据相似。样本用作健全性检查。然而,通常你会发现很难决定一个样本是否与你的训练数据相似。在这种情况下,接受使用样本的健全性检查有其局限性,并继续前进。

以上两个数字也揭示了长度刻度 l 的值很重要。它极大地影响了先验模型的函数形状。

与长度缩放的效果相比,信号方差参数 σ 仅缩放 y 轴上的函数。例如,如果 σ10 而不是 1,来自 GP 先验的样本看起来如下:

这些函数的外观与上图相似,只是 y 轴上的值被缩放以具有更大的范围。

GP 先验的固定和可变部分

我们的 GP 先验具有多元高斯结构,并且它具有长度尺度 l 和信号方差 σ 作为参数。我们通过指定其均值 m(x) 和协方差 k(x,x) 分量来固定多元高斯结构。但是我们没有说明 l 和σ 的具体值

多元高斯结构和模型参数值都有助于定义我们的先验包括的函数集。在参数学习过程中,我们改变模型参数值,以查看哪些值会产生最好地解释训练数据的后验概率。但是在参数学习期间,我们保持先验的高斯结构不变。这是因为如果我们改变先验的结构,我们将不再讨论高斯过程模型,这个模型可能是完全不同的,具有非常不同的性质。

可能性和边际可能性

GP prior 只提到了 X 。这是在实际观察 Y 之前连接来自 GP 的随机变量的可能性。根据先验和似然,我们可以计算后验。从后面,我们做出预测。

可能性

可能性是给定来自先验的随机变量 f(X)f(X_)* 观察到 Y 的概率。要说观测到 Y 的概率,我们需要引入一组新的随机变量。对于 X 中的每个位置 x ,引入一个新的随机变量 y(x)。我们假设我们在位置 x 的观察值是这个随机变量 y(x) 的一个样本。在 Y 中有 n 个观测值,所以我们有一个长度为 n 的随机变量向量 y(X)

我们应该给 y(X) 什么分布?为了建立 y(X) 和随机变量 f(X) 之间的联系,我们将 y(X) 的分布定义为具有均值 f(X) 和协方差 η Iₙ 的多元高斯分布,其中 η 为标量模型参数,称为噪声方差, I ₙ为大小为 n×n 的单位矩阵

我用的是符号𝒩(y(x);f(X),η Iₙ) 来表示随机变量y(x)的多元高斯概率密度函数,这个概率密度有均值 f(X) 和协方差矩阵 η Iₙ

描述相同随机变量 y(X) 的等效方式是使用高斯线性变换形式:

该公式将 y(X) 表示为随机变量 f(X) 加高斯噪声 ε 的线性变换。变换矩阵不是别人,正是 n×n 单位矩阵 Iₙ 。同样,这两种定义 y(X) 的方式是等价的。

可能性的公式是给定 f(X) 的随机变量 y(X) 的概率密度函数:

似然性是三个自变量的函数: y(X)f(X)和模型参数 {l,σ,η } ,我们将整套模型参数作为单个自变量处理。

为什么我们这样建模 y(X) ?因为:

  1. 我们使用 f(X) 来模拟位置 X 处的可能函数值,很自然地将其用作我们的观察随机变量 y(X) 的平均值。
  2. 我们想要模拟我们的观察值 Y 来自 f(X) 但是不知何故被随机噪声破坏了。所以我们引入了噪声方差 η Iₙ 。每个位置的腐败 x 是相互独立的,这就是为什么 η Iₙ 是一个对角矩阵,所以两个不同位置的噪声之间没有相关性。

你可能会疑惑, f(X) 已经是一个有自己方差的随机变量,由 k(X,X) 定义,为什么还要引入另一个层次的方差 η Iₙ

答案是:不必。这是你的造型。你想怎么建模都行。您可以将观察值 Y 建模为来自 f(X) 的样本,而无需引入 y(X) 。这被称为无噪声高斯过程(此处为,第 15 页)。

但更常见的是引入观测噪声。因为这样我们就有了更好的关注点分离: f(X) 及其方差侧重于对底层系统动态及其固有的不确定性进行建模。而 y(X) 及其方差则侧重于观察过程中出现的不确定性。这更接近真实系统。

你可能也想知道:为什么噪声需要在 X 的每个位置都是独立的?因为如果噪声不是独立的,例如,如果噪声随着 X 中的位置以线性方式变大而变大,那么它不再是噪声。这是系统的一个特征,我们应该事先对其建模。

你可能也想知道,可能性通常不是观察随机变量的概率密度,给定所有先前介绍的随机变量?换句话说,你会建议可能性是:

还有为什么我把可能性定义为 p(y(X)|f(X)) 没有随机变量 f(X_)* ?答案是:你是对的。可能性应该是你建议的公式。但是你的配方和我的一样。这是因为我将观测随机变量建模为 y(X)=Iₙ f(X) + ε,所以 y(X) 只取决于 f(X) ,而不取决于 f(X_)* 。我认为这种建模是有意义的,因为在测试位置 X_* 对依赖于随机变量 f(X_)* 的 y(X) 建模会很奇怪。

由于 y(X) 不依赖于 f(X_)* ,我们可以在条件中去掉 f(X_)* 这个不相关的提及,那么 *p(y(X)|f(X),f(X _ )就变成了 p(y(X)|f(X)) 。如果你想了解更多关于如何从概率密度中去除随机变量的知识,请去我的另一篇文章揭秘 Tensorflow 时间序列:局部线性趋势搜索“如何从公式中去除随机变量”。

根据我们的模型,实际观测值 Y 是来自随机变量 y(X) 的一个样本。于是 f(X)f(X_)* 就成了随机变量,它们的样本我们永远也观察不到。在概率论中,我们称 f(X)f(X_)* 潜在随机变量

边际可能性

我们已经提到,观测随机变量 y(X) 可以用高斯线性变换方式定义:

从这个公式中,我们可以应用高斯线性变换规则来推导出 y(X) 的概率密度函数,而不用提及 f(X)。

首先,通过应用多元高斯边缘化规则,我们可以从 GP 先验中得到随机变量 f(X) 的分布:

我们以前曾经使用过这个规则来去除任何与 X ₒ相关的东西,比如**内核函数 k* 中的 f(Xₒ)y(Xₒ) 。这里我们用同样的规则从先验中去掉 f(X_)* 得到的只是 f(X) 的分布。所以:*

然后,我们可以应用高斯线性变换规则(参见我的文章揭开 Tensorflow 时间序列的神秘面纱:局部线性趋势了解该规则的详细信息)来获得随机变量 y(X) 的分布。以下是多元高斯线性变换规则:

如果多元随机变量 a 来自以下高斯分布:

随机变量 b 是从 a 的线性变换,其中 A 为变换矩阵,并添加了高斯噪声 η :

那么 b 的分布为:

b 的分布使用了 a 的分布中的量,但没有提及随机变量 a 。这是很重要的一点。

多元高斯线性变换绝对值得你花时间去记住,它会在机器学习的很多很多地方出现。例如,你需要它来理解卡尔曼滤波算法,你也需要它来推理最小二乘线性回归中的不确定性。

对于我们来说, af(X)by(X)AIₙηε。我们应用线性变换规则推导出 y(X) 的分布:

其概率密度函数为:

这个概率密度函数就是著名的边际似然。与似然的概率密度函数不同,上述边际似然密度只提到了随机变量 y(X) 而不再提到 f(X) 。你能指出这个概率密度函数和可能性密度函数之间的 4 个区别吗(当你家里有一个小孩时,这种问题自然会出现)?

由于我们将随机变量 f(X) 从似然公式中剔除,我们将结果称为边际似然。

边际似然概率密度函数有两个自变量, y(X) 和模型参数集。知道一个函数的哪些未知数/自变量是重要的。因为后面我们会用边际似然公式作为参数学习的目标函数。所以我们需要确定边际可能性是一个只有模型参数作为自变量的函数。

虽然边际似然有两个自变量, y(X) 和模型参数集,但是我们有针对 y(X) 的观测值 Y 。我们可以将 Y 插入到 y(X) 的位置,得到一个只有一个自变量的函数——模型参数集。

你可能会想,我们通常不都是通过把潜在随机变量 f(X) 积分出来得出边际似然的吗,像这样:

你是对的,如果你计算这个积分(我将提供另一篇文章来进行这个计算),结果与上面我们应用高斯线性变换规则时的结果相同。

应用高斯线性变换规则的优点是它简单得多。缺点是当一切都是高斯时,我们只能使用高斯线性变换规则。然而,使用积分的上述推导适用于任何概率系统,因为它仅使用概率论的基本规则。

计算后验概率

在贝叶斯方法中,我们需要根据先验和似然性计算后验概率。后验概率是与前验概率相同的一组随机变量。

我们的 GP 先验由两个潜在的随机变量向量 f(X)f(X_) 组成,但是我们只对寻找后验的 p(f(X_)|y(X))* 感兴趣,因为我们需要它在测试位置 X_* 进行预测。我们可以随意地计算 p(f(X)|y(X)) 的后验概率,首先计算 p(f(X_)|y(X)),*,然后将 X 代入 X_。**

为了计算后验概率 p(f(X_)|y(X)) ,我们依赖于这样一个事实,即 f(X_)* 和 y(X) 都是多元高斯随机变量,并且我们知道这两个变量的分布。*

*f(X_) 的分布是通过在去除与 f(X)相关的东西之前将多元高斯边缘化规则应用于 GP 而得到的。

这是我们第三次应用多元高斯边缘化规则:

可能性和边际可能性部分,我们推导出了 y(X) 的分布,这就是边际可能性:

由于 f(X_)y(X) 都是高斯分布,我们可以把它们的联合分布写下来(我们为什么要写联合分布的原因下面几段就清楚了)如下,前提是我们可以计算出 f(X_)* 和 y(X) 之间的协方差,用 Cov(f(X_),y(X))* 表示:*

如果我们记得协方差的定义,计算 Cov(f(X_),y(X)) 就很简单:*

线(2)示出了在给定它们的平均值 m(X_)m(X)的情况下 f(X_)y(X) 之间的协方差的定义。**

第(3)行插入 y(X) = f(X)+ε 的定义。这里我们忽略了恒等式矩阵 Iₙ 前面的 f(X) 作为 Iₙ 不改变向量 f(X)。

第(4)行重新组织了项,因此我们可以通过使用期望的线性属性在第(5)行将单个期望分成两个期望:和的期望等于操作数的两个期望的和。

第(6)行认识到第一个期望是 f(X_)f(X) 之间的协方差的定义。并且线(7)插入这个已知的量 k(X_,X)* 。*

第(8)行识别出随机变量 f(X_)-m(X_)* 和随机变量 ε 是独立的。所以它们的乘积的期望等于这两个随机变量的乘积,即E[(f(X _ )—m(X _ ))ε]=E[f(X _ )—m(X _ )]E[ε]。由于E【ε】为 0 因为 ε 是均值为 0 的随机变量,所以整个乘积为 0。*

所以现在我们可以在 f(X_)y(X) 之间有一个完全指定的联合分布:*

现在距离后验概率 p(f(X_)|y(X)) 只有一步之遥,我们应用多元高斯条件规则来计算它。我们之所以要写下 f(X_)* 和 y(X) 之间的联合分布,是想应用这个规律。*

多元高斯的条件规则是:

该规则给出了当 p(x,y) 为多元高斯时,从联合 p(x,y) 得到 p(x|y) 的公式。让我们将该规则中的术语与我们在 f(X_)y(X) 之间的联合分布中的术语进行匹配:*

应用这条规则后,我们得到后验分布:

有了后验均值和后验协方差:

哇,这两个量是不是很复杂!但是不要担心,我们将研究它们的结构来回顾它们的直觉。直觉很有道理。请继续读下去。

但在我忘记之前,我需要指出这些步骤:

  1. 将我们的高斯潜在随机变量和非潜在观测随机变量组织成联合高斯分布;
  2. 应用多元高斯条件规则推导后验概率密度。

这两个步骤是贝叶斯学习中反复出现的模式。这里我们用它来计算高斯过程模型的后验概率。另一个著名的例子是卡尔曼滤波算法。参见我的另一篇文章揭开 Tensorflow 时间序列的神秘面纱:局部线性趋势卡尔曼滤波器部分,尤其是卡尔曼滤波器算法的总结。

你可能会想,为什么我们不用通常的贝叶斯法则来计算后验概率:

我们可以,我会提供一篇关于它的文章。得到的后验概率和这里一样,但是推导过程比这里复杂得多。原因是当一切都是高斯分布时,使用多元高斯分布的性质和规则是贝叶斯规则的捷径。

现在让我们研究后验均值和后验协方差的结构。

后验均值和协方差的结构

首先,你可以验证后验均值 μ_ 是一个长度为 n_* 的向量。并且后验协方差 σ_* 是大小为 n * *×n的矩阵。下面我把每个分量矩阵的大小用红色表示(记住 nf(X) 的长度,或者说是训练数据点的个数)。 n_* 为 f(X_)* 的长度,或测试位置的数量)😗

后验均值和协方差是符号* c 表达式——它们是提到模型参数 {lσ、 η }的数学表达式。我们不知道这些模型参数的值。所以即使我们把已知的量:训练地点 X ,测试地点 X_* 和观测 Y 代入 y(X) 之后,我们还是有一个符号表达式。只有在我们使用参数学习为我们的模型参数找到最优值之后,我们才能将这些符号表达式评估为具体的真实值。*

让我们从后验的意思开始:

为了便于研究,我们假设均值函数 m 为 0,因此 m(X)=0 ,并且 m(X_)=0 。现在让我扩展这个公式。事实上,通常你可以通过展开向量和矩阵来帮助自己理解线性代数表达式。*

第(1)行是我们之前推导的 μ_ 的公式。*

第(2)行用 0 代替了 m(X_)m(X) 以便于我们的研究。*

第(3)行将我们的部分观察数据 Y 插入 y(X)

第(4)行扩展了 k(X_,X) 的定义。*

第(5)行将 Y 扩展为实际矢量。

第(5)行的公式揭示了关键信息:

  1. 单个测试位置的平均值,比如说 x_1 ,是所有观察值 Y 的加权和。权重由测试位置 x_1* 和 X 中所有训练位置之间的内核定义。即使先验函数的均值为零,后验均值也不一定为零。这个公式显示了我们之前提到的内容——后验权重函数来自于先验,使得它们与训练数据更加一致。并且这种重新加权导致非零均值的后验概率。*
  2. 中间的部分 (k(X,X) + η Iₙ)⁻ 没有提到 x_1 ,所以相对于 x_1* 是常数。你可以想象一下,幂 把项 k(X,X) + η Iₙ 放入一个分数的分母,其中分子是 k(x_1,X)* 乘以 Y 。那么你就可以理解后验均值确实是观测值的加权和 Y ,权重 k(x_1,X)* 。并且这个加权和通过( k(X,X) + η Iₙ)⁻ 归一化。*

我在这段代码中实现了高斯过程。我用这个代码来绘制后验均值和方差。GP 的代码是将上述公式直接翻译成 NumPy 语法。阅读时,注意使用 assert 语句检查矩阵形状。当编写机器学习算法时,确保矩阵具有正确的形状可以防止大量错误的发生——记住这一点。如果你想了解更多关于编写断言来帮助你开发机器学习代码的知识,这是一本好书:将 Tensorflow 调试时间减少 90%

让我们看看后验均值是如何表现的。以下是一个非常重要的数字。我使用 0 到 2π之间的 50 个等距位置作为我们的测试位置 X_ ,并计算这 50 个位置的后验均值和方差在该图中,红点代表这些测试位置的后验平均值。连接所有红点的红色曲线是 matplotlib.plot 效果。蓝色条带表示后验方差,即后验协方差矩阵主对角线上的值。我将在下一节解释后验协方差。训练数据点用蓝色十字“x”标记。我用了 lengthscale l=0.4 ,信号方差 σ=1,噪声方差 σ=0.01。*

Posterior mean and variance for test locations. Blue crosses are training points, red dots are testing points.

我们首先关注后验均值。第一个印象是,连接所有后均值的红色曲线有点类似于正弦波。不完美,但很接近。

为了查看后验均值后面的“加权Y 之和”解释,在下图中,我用一个大红点突出显示了一个单独的测试位置。我用蓝色标记画出训练数据点,蓝色标记的大小与大红点的后验均值中的权重成比例。

现在,您可以验证训练点离突出显示的测试点越近,相应观察值的权重就越大,因此蓝色标记就越大。随着训练点远离高亮显示的测试点,蓝色标记的大小会减小。

重新审视定义功能的映射视图

在理解了后验均值是观察值的加权和之后, Y,现在我们理解了为什么定义函数的映射视图对于高斯过程是重要的。

高斯过程不会像线性回归给你的那样,找到一个传统意义上的 f(x)=ax+b 只需要一个新的 x 并返回一个 y 的函数体。相反,它给出了每个测试位置 x_ 到函数平均值(当然还有它的方差)之间的映射。该映射不仅涉及测试位置 x_* ,还涉及所有训练数据 XY 。注意即使你可以有一个无限数量的测试位置的映射,实际上,你只需要做有限数量的预测,所以你只需要计算有限数量的这样的映射。*

我们意识到这种差异非常有趣:使用线性回归,一种所谓的参数模型,在您使用训练数据来确定 f(x)= ax+b 中参数 ab 的值(这称为参数学习)之后,您可以丢弃训练数据。因为对新的 x 进行预测不需要训练数据。但是用高斯过程,一个所谓的非参数模型,即使在参数学习之后,你仍然需要保留训练数据,因为训练数据出现在后验均值和方差中,高斯过程依靠后验进行预测。

您可能想知道高斯过程是否能够节省空间来进行预测。它不是。前面我们已经说过,你通常需要更多的空间来写下一个通过输入输出映射定义的函数。这是从数学的角度来看。现在让我们从计算机科学的角度来看看这种空间非效率:

  • 在参数模型中,如形式为 f(x) = ax+b 的线性回归。在参数学习找到参数 ab 的值后,您只需要存储这两个数字的空间来预测新的测试位置 x_ 。也就是说,参数学习后,就可以扔掉训练数据了。*
  • 在非参数模型中,例如高斯过程,在参数学习以找到模型参数的值之后,您仍然需要保留所有训练数据 (X,Y) ,因为模型参数和训练数据都出现在后验中。所以如果 (X,Y) 由一百万个数据点组成,准备好为它们分配内存。

后验协方差

现在让我们来看看后验协方差矩阵:

它是描述 f(X_)|y(X): 的后验概率中每对随机变量之间协方差的矩阵*

注意,该矩阵中的条目不是 k(X_i,X_j)* ,因为这是后验协方差,并且 k(X_i,X_j) 用于定义先验。所以我使用符号 Cov(X_i,X_j) 来表示后验协方差矩阵中的条目。*

主对角线上的条目是 f(X_) — 中每个随机变量的方差,一个随机变量与其自身之间的协方差称为方差。*

让我在下面再次展示后验均值和方差的图。

Posterior mean and variance for test locations. Blue crosses are training points, red dots are testing points.

在该图中,蓝色带代表 95%的置信区间。提醒我们自己,我们生成了非等间距的训练点。所以有的地区训练点多,有的少。后验方差代表模型的不确定性水平。我们可以看到,在附近有训练数据点的区域中,条带很薄,这意味着后验方差很小。换句话说,模型更确定函数值应该出现在测试位置的什么地方。在附近没有训练数据的地区,差异很大。换句话说,模型是相当不确定的。这是常识。这就是为什么人们说“训练数据解释了不确定性”。

现在我们来看看这个常识是如何体现在数学上的。但首先,你可能会想,后验方差是方差,它应该是非负的。后验均值公式总是非负的吗?

是的,它是。让我们在只有一个训练数据点和一个测试数据点的情况下说服自己。由于只有一个测试点,所以 f(X) 中只有一个随机变量。后验协方差矩阵成为后验方差。我们进一步假设没有观测噪声,换句话说, η =0 ,所以 η Iₙ =0。所以后验方差变成了:*

第(1)行是无观测噪声的后验协方差公式,所以矩阵求逆中没有 η Iₙ 。注意,在这个公式中,所有的 k 项都计算为一个标量数,因为我们只有一个训练数据点和一个测试点。

第(2)行简化了公式,因为标量的转置是它本身。

线(3)扩展和减少 k(X,X)

第(4)行扩展并减少 k(X_,X_)* 。*

第(5)行扩展了 k 的定义。

第(6)行显示后验协方差是非负的,因为指数函数的输入是负的量,所以指数函数具有最大值 1。所以整个公式的计算结果为非负值。

训练数据解释不确定性

同样从上面的公式,第(6)行,我们可以看到为什么当测试点离训练点越近时,后验协方差变得越小。随着 X_ 越来越接近 X ,两者的平方距离趋近于 0;指数计算出这个最大值 1。因此总体后验方差评估为其最小值。*

另一方面,当 X_X 非常远时,指数评估为 0,因此总体后验方差评估为其最大值 σ 。这是一个有趣的行为,意味着后验方差以 σ 为界,它不会无限大,最终会达到最大。稍后您将看到一张显示这种最大化行为的图片。*

先验的后验权重函数

让我们重温一下我们在 GP 先验部分的采样中开发的视图:后验概率为接近训练数据的函数提供更高的概率。**

为了验证这一点,我们研究当我们将 X_ 设为 X 时,后验概率 p(f(X_)|y(X))* 是什么样子。也就是说,我们想知道在等于 X 的位置,即训练位置,函数的后验分布是什么。我们希望看到的是后验赋予函数 X⟼Y 一个大概率,其中 XY 是我们的训练数据。*

后验均值 我们继续使用零均值函数,假设没有观测噪声,那么 η Iₙ=0 。并且我们设置 X_ = X 。后验均值公式变为:*

第(1)行是原始的后验均值公式。

*第(2)行使用零均值并插入训练数据:将 X_ 替换为 X ,将 y(X) 替换为 Y

第(3)行显示后验均值与我们的观察数据 Y 完全相同。注意这里 k(X,X)k(X,X)⁻ 相消,因为我们假设 η Iₙ=0.η Iₙ≠0 时,这两项不会互相抵消,所以后验均值不会等于 Y

后验协方差 后验协方差公式变为:

第(1)行是原始的后验协方差公式。

第(2)行插入训练数据:将 X_ 替换为 X 。在这里,类似于后验均值的情况 k(X,X)k(X,被取消,因为我们假设 η Iₙ=0.但是他们不会互相抵消,如果 Iₙ≠0。*

第(3)行简化了公式。

第(4)行表明,由于 k(X,X) 是对称矩阵,所以等于它的转置。

线(5)简化了公式,以显示训练数据位置 X 处的后验协方差为 0。

以上两个推导表明,当 X_ = X 时,后验分布具有均值 Y 和协方差零 如果你把观测值 Y 代入这个概率密度函数,你会得到最高的概率,因为高斯概率密度函数在均值的位置有最大值。事实上,你不能把 Y 代入这个后验分布,因为协方差为零,后验分布不再是有效的高斯分布。它只是一个平均向量,等于 Y 和一个零协方差矩阵,您可以将其解释为选择一个通过所有训练数据点的单一函数。*

做预测

后验分布 p(f(X_)|y(X)) 为潜变量 f(X_)* 。但是请记住,我们将观察值建模为潜在变量的线性变换,并添加高斯噪声。所以观测随机变量的后验 y(X_)|y(X)* 为:*

在哪里

由于我们从上一节知道了 f(X_)|y(X) 的分布,即后验分布,通过应用多元高斯线性变换规则,我们可以推导出 y(X_)|y(X)* 的分布:*

这是我们需要预测测试位置 X_ 函数值的分布。类似于 f(X_)|y(X)* 的后验均值和方差, y(X_)|y(X)* 的后验均值和方差也是具有单个自变量的函数,即测试位置 X_* 。该预测是具有均值和方差的高斯分布的形式。有了这两个量,你就可以画出均值曲线和置信区间。*

我们可以看到,在测试位置预测新函数值的高斯过程机制只是潜在随机变量 f(X_) 的后验均值和方差上面的一层薄薄的东西。*

高斯过程以有原则的方式模拟不确定性

上述用于进行预测的公式揭示了一个非常重要的事情:高斯过程模型以高斯分布的形式进行预测。它的平均值告诉我们一个预测的平均值或期望值,它的方差告诉我们模型对于这个预测的不确定性。

先验的不确定性(由协方差矩阵测量)和似然的不确定性通过我们用来导出后验的多元高斯条件规则(以及等价的贝叶斯规则)传播到后验的不确定性中。这就是为什么我们说高斯过程以一种有原则的方式模拟不确定性。

你可能会想,这种不确定性是主观的吗?这意味着我们主观上决定对 GP 先验和似然性都使用多元高斯分布,而不确定性来自这两个分布的不确定性。如果我们选择不同的分布(比如,我们选择了 student-t 分布并设计了一个“student-t 过程”模型),我们可能会有不同的不确定性特征。是的,你是对的。不确定性对我们选择的分布是主观的。由于我们不直接观察不确定性,这总是一个主观的选择,在模型表达能力和计算简便性之间进行平衡。

我们已经通过了相当多的材料,唯一剩下的事情是我们需要为我们在建模期间引入的三个参数找到好的值,长度尺度 l ,信号方差 σ 和噪声方差 η。为它们寻找好值的过程叫做参数学习。但是在我们开始描述参数学习之前,我想为您总结一下高斯过程模型。

高斯过程模型摘要和模型参数

高斯过程模型

我们把 GP 先验和似然一起称为高斯过程模型。事实上,所有的贝叶斯模型都由这两部分组成,先验和似然。

先验是两个随机变量向量 f(X)f(X_) 之间的联合高斯分布。它们分别代表训练位置 X 和测试位置 X_* 的可能函数值。先验未提及的观察值 Y. 其公式为:*

其中 m 是通常为零的函数,而 k 是核函数:

先前引入了两个模型参数:长度尺度 l 和信号方差 σ

可能性是一个多元高斯分布,将我们的观察随机变量 y(X) 与潜在随机变量 f(X) 联系起来:

似然性引入了一个额外的模型参数:高斯观测噪声的方差 η

就是这样,一个简单的模型。这个模型引入了三个随机变量(每个都是一个随机变量向量):

****f(X)*: latent random variables that represent possible values at 
      training locations *X*.*****f(X_*)*: latent random variables that represent possible values at 
        testing locations *X_**.*****y(X)*: random variables that represent possible values for 
      observations at training location *X*. We model our actual 
      observations *Y* as a sample from *y(X)*.**Note: the above three are random variables, so when you see the expression *f(X)*, *f(X_*)*, and *y(X)*, don't interpret them as function applications. They are random variable names.Note: the expression *m(X)* is a function application. It represents the mean function we use in the prior. It is a function application, and not the name of a random variable.*

该模型定义了先验和似然。这两个部分在模型中,因为它们需要人的参与:我们需要确定均值是一个零函数;我们需要决定平方指数核,我们需要决定我们的观察随机变量是我们的潜在随机变量的线性变换。一旦我们决定了这些部分,计算后验概率和做出预测都是机械的,遵循概率论和高斯分布的规则。

现在我想更多地谈谈这三个模型参数。

模型参数

总之,高斯过程模型引入了三个模型参数。让我们讨论一下他们的直觉。

长度刻度l**

正如我们已经从 GP prior 部分的采样中看到的,lengthscale 极大地改变了我们的 GP prior 可以建模的函数的外观。让我们通过查看其公式来了解 lengthscale 是如何做到这一点的:**

我们可以看到,长度比例的倒数控制着两个随机变量在(x-x’)的意义上需要有多远,以便它们变得不相关。它是 lengthscale 的倒数,因为 l 出现在指数函数的分母中。下图显示了对于固定信号方差 σ =1,两个核函数是什么样子。一个是红色的长度刻度 l=0.01π ,另一个是蓝色的长度刻度 l=0.5π

Kernel function values with different lengthscales, l=0.5π* in blue, and l=0.01π in red.*

在该图中,x 轴是 x 和x’之间的距离。我们来看距离(x-x’)= 0.5π≈1.57。也就是图中的蓝点和红点。当 l 为 0.5 π,相距 0.5 π 距离的两个随机变量仍然相当相关,协方差约为 0.6。相反,当 l 为 0.01 π 时,相距 0.5 π 距离的两个随机变量几乎不相关,协方差值约为 0。

当试图理解改变函数参数的影响时,我发现分析极端情况是有用的。在我们的内核示例中:

  1. 当 lengthscale l 趋近于 0 时,内核值趋近于 0;我们的模型认为,任何两个不同的随机变量都是不相关的,不管它们有多接近。
  2. 当 lengthscale l 趋近于∞,核值趋近于 1;我们的模型认为,任何两个随机变量都是 100%相关的,无论它们相距多远。

随机变量协方差的这种变化如何影响我们的 GP prior 可以建模的函数的外观和感觉?让我们看两个样本,每个样本来自一个 prior。红色样本来自长度为 0.01π的先验样本,蓝色样本来自长度为 0.5π的先验样本:

Samples from the GP prior with different lengthscales

在该图中,数据位置被有意选择为均匀间隔 0.04 π ,因此两个相邻数据点之间的距离大于长度刻度 0.01π,但小于长度刻度 0.5π。

我们先来看一下 l=0.5π的蓝色曲线。l=0.5π 意味着 0.5ππ窗口内的随机变量(即蓝点)应该是高度相关的。我用绿色矩形突出显示了这样一个窗口。所以一条平滑的曲线,比如蓝色,与这些协方差特征是一致的。

“一致”是什么意思?记住所有的随机变量:

  1. 具有相同的均值 0,因为我们使用的是均值为 0 的函数。具有相同的平均值意味着平均而言,来自那些随机变量的样本应该出现在相同的 y 轴水平上。
  2. 具有相同的方差,因为它们的方差定义在协方差矩阵的主对角线上。它们都有方差 σ。具有相同方差的随机变量表明来自它们的样本应该在相同的水平范围内变化。
  3. 随机变量是正相关的。这表明,如果来自随机变量 f(x₁) 的样本大于均值 0,则在 l=0.5π 纵向尺度距离 f(x₂) 内的另一个随机变量的样本也更有可能大于 0。这是我们期望从正相关随机变量中看到的行为——它们在同一个方向上变化。

突出显示的绿色窗口中的蓝点是先前随机变量的样本(每个随机变量一个样本),长度标度为 l=0.5π ,符合这些特征。

另一方面,绿色窗口中的红点不符合这些特征。红点显然来自不同的方式,它们在 y 轴的不同范围内变化。事实上,对于红点,它们的长度尺度是 l= 0.01π,小于每两个数据点之间的距离 0.04π。所以任何两个红色数据点都来自实际上不相关的随机变量。这就是连接红点的红色曲线上下跳动的原因。

信号方差σ**

模型参数为 σ ,但通常我们写为 σ 是为了强调它是一个方差。正如我们在 GP prior 部分的采样中已经看到的,不同的 σ 值缩放我们的 GP prior 可以在 y 轴维度上建模的函数。这是这个模型参数的直觉——它反映了你希望你的全科医生能够优先处理的功能范围。**

观测噪声的方差 η

同信号方差,我们写 η 强调 σ 定义一个方差。我们有 η ,因为我们假设我们的观测值 Y 是来自随机变量 y(X) 的样本,并添加了高斯噪声。高斯噪声的均值为 0,其方差为 η

我们不知道这三个模型参数的值。我们使用参数学习为它们找到好的值。

参数学习

模型参数的良好值有助于我们的模型更好地解释训练数据。参数学习是调整那些模型参数值直到它们能够足够好地解释训练数据的过程。

在高斯过程中,这种模型参数值的调整是通过优化完成的。我们首先提出一个目标函数,量化我们的模型如何解释训练数据。该目标函数将并且仅将所有模型参数作为自变量,并返回一个实数。当模型更好地解释训练数据时,我们从目标函数中解释更大的数字。参数学习试图找到具体的模型参数值,以最大化目标函数。

选择目标函数

这个目标函数看起来应该是什么样子,以便“解释训练数据”?“解释训练数据”是什么意思?嗯,至少,它需要提到训练数据 XY

在我们的高斯过程模型中,我们有两个公式提到了完整的训练数据 XY 。可能性 p(y(X)|f(X)) 和边际可能性 p(y(X))

可能性

当我们将 Y 代入上述公式时,我们得到一个具有两个参数的函数,即模型参数集和潜在随机变量 f(X) ,如下所示。该函数将模型参数作为参数,因为它提到了观察噪声方差 η 以及长度标度 l 和信号方差 σK 。它有自变量 f(X) ,因为在指数函数中提到了 f(X) 。其他都是不变的。

不同的模型参数值会导致观察到我们的观察数据的概率不同 Y. 我们可以把一个高概率解释为“更好地解释了训练数据”。因此,似然函数可能是目标函数的候选。

似然函数的问题是除了提到所有的模型参数,还提到了随机变量 f(X)。这违反了我们的要求,即目标函数应该是只提及模型参数而不提及其他未知量的函数。我们有这个要求,因为优化算法——梯度下降——只对标量未知的函数有效,对随机变量未知的函数无效。

边际可能性

所以让我们看看边际可能性 p(y(X)) :

这是一个只有一个参数的函数,即模型参数集。这是因为(1)即使 y(X) 是一个随机变量,我们也可以代入 Y 将其移除。(2) m(X) 不是一个随机变量,它是一个给定 X. 我们可以计算的量,我们通常设 m(X)=0 。(3)我们知道 X 。(4)提到了所有的模型参数。其他都是不变的。

我们仍然可以将高边际似然值解释为我们的模型能够更好地解释训练数据。说到底,边际似然的意义就是期望似然 p(y(X)|f(X)) 相对于来自先验的随机变量f(x):f(x)~ 𝒩(0,k(X,X))😗*

注意,即使我们使用高斯线性变换规则来推导边际可能性的公式,而不是上述积分,变换规则只是上述积分的捷径。

我们可以理解,边际可能性是我们的模型在以下意义上解释训练数据的程度的度量:

  1. 我们的模型对观察数据的解释有多好 Y 是用我们代入 Y 时的似然值来衡量的——p(Y(X)= Y | f(X))。这个量依赖于 f(X) 是因为它的公式,也就是多元高斯概率密度函数,提到了 f(X)
  2. f(X) 是来自先验 p(f(X))的随机变量。不同的样本 f(X) 导致我们的训练数据 p(y(X)=Y|f(X)的可能性不同。为了用一个数字量化 Y 的总体可能性,我们看所有这些可能性的平均值,也就是边际可能性。

好消息是边际可能性公式满足了我们对目标函数的要求。所以我们选择它作为我们的目标函数。

我们想要最大化关于模型参数的边际似然性,因为我们想要找到那些模型参数的具体值,使得观察数据 Y 可以由我们的具有最大似然性的模型生成。

由于边际可能性是一个指数函数,我们可以取它的对数来抵消指数。 log 函数是严格递增的,因此最大化 log p(y(X)) 会产生与最大化 p(y(X)) 相同的最佳模型参数值。

理解目标函数

目标函数将我们对模型质量的定义嵌入到一个数字中。理解这个函数的行为是很重要的。让我们写下它的公式:

目标函数中有三项。我用红框突出显示了它们——模型复杂性术语、数据拟合术语和常数术语。我们可以忽略常数项,因为它不会改变优化的结果。我们将仔细研究数据拟合项和模型复杂性项。

请注意数据拟合术语和模型复杂性术语前面包含减号“-”。我们想最大化目标函数。忘记这两个负号会让你觉得下面所有的分析都应该是反方向的。

重新审视空间效率

数据拟合项和模型复杂性项包含矩阵 k(X,X) 。它是一个大小为 n⨉ n 的矩阵,其中 n 是训练数据点的数量。如果你有一百万个数据点, k(X,X) 的大小是百万乘百万,需要很多内存来保存。与线性回归中的批量学习相比,在线性回归中,您只需要在内存中保存一小部分(一个小批量)训练数据,高斯过程方式并不节省空间。

更糟糕的是,我们需要在数据拟合项中对这个矩阵进行矩阵求逆。矩阵求逆是一种缓慢的操作,并且可能存在数值稳定性问题。所以高斯过程做参数学习既不节省空间也不节省时间。

如果你看我实现高斯过程的代码,我用了 NumPy 的逆运算来求 k(X,X) 。只有当你有一个小的训练数据集时,这才有效。在实践中,你会用更聪明的方法,比如乔莱斯基分解k(X,X) 的逆,利用它是一个正定对称矩阵的优势。在以后的文章中会有更多的介绍。

你可能会想,模型复杂度项中行列式运算符的空间和时间复杂度呢?与求逆 k(X,X) 相比,行列式的时间要少得多。 k(X,X) 的反演是高斯过程参数学习的时空分析中的主导因素。

如何理解目标函数中的术语

由于对数运算符应用于边际可能性,数据拟合项和模型复杂性团队出现在目标函数中。我们没有决定将它们加入目标函数:

  • 我们没有决定包括数据拟合项来捕捉我们的模型解释训练数据的程度。
  • 我们没有决定包括模型复杂性术语来控制和鼓励简单模型。

这两个术语的存在是因为目标函数 log(p(Y(X)),的结构,这是贝叶斯机器学习的一个特征。

这不同于我们对带有正则化的线性回归中的目标函数所做的,其中目标函数是欧几里德距离项和 L2 正则化项之和:

其中 w 为模型参数, (X,Y) 为训练数据, λ 为 L2 正则项前的超参数权重。

在这个线性回归目标函数中:

  • 欧几里德距离项(第一项)负责衡量模型预测与训练数据 Y 的接近程度。
  • 正则项(第二项)负责通过 L2 范数鼓励具有小系数的简单模型。

这里,我们明确决定使用欧几里德距离来量化我们的模型与训练数据的拟合程度,并且我们明确决定使用 L2 范数正则化项来控制模型的复杂性。

回到我们的高斯过程设置,在下一节中,我们将弄清楚 log(p(y(X)) 目标函数中数据拟合项和模型复杂性项的语义。你会明白:

  • 数据拟合项不能衡量我们的模型对训练数据的解释程度。这与线性回归设置中的不同。
  • 然而,模型复杂性项通过鼓励更简单的模型来控制模型复杂性。这类似于线性回归设置中的正则项。

数据拟合术语

我们来思考一下为什么 - (y(X)-m(X))ᵀ (k(X,X)+η Iₙ)⁻ (y(X)-m(X)) 被称为数据拟合项。我认为“数据术语”比数据拟合术语更好。我想称之为数据项,因为在目标函数中,这一项是唯一提到观察值 Yy(X) 的项。我不喜欢“数据拟合项”这个名称,因为当我们听到“数据拟合”这个词时,我们往往会想到一个术语,它测量训练位置 X 的模型预测值与这些位置的实际观测值 Y 之间的距离。这是很重要的一点,我来澄清一下。**

例如,在线性回归中,数据拟合项是模型预测 aX+b 与观测y:(ax+b-y)(ax+b-y)ᵀ)之间的欧氏距离。但是在高斯过程目标函数中,所谓的“数据拟合项”-【y(x)-m(x))ᵀ(k(x,x)+ηiₙ)⁻(y(x)-m(x))】并不能代表模型预测与观测之间的这样一个距离。

首先,在高斯过程中,预测的形式是具有均值和协方差的后验分布。无论如何,还不清楚如何计算观察值和分布之间的欧几里得距离。

另一方面,即使我们忽略协方差,只看后验平均值(当我们在位置 X 设置 m(X)=0 )也就是 k(X,X)(k(X,x)+ηiₙ)⁻y。它和观测值 Y 之间的欧几里得距离是:

我们可以看到最小化这个量不同于在前面没有 - 的情况下最小化数据拟合项 : Yᵀ (k(X,X)+η Iₙ)⁻ Y.

在高斯过程中,数据拟合项只是出现在对数边际似然中的一个项。就这样。

但你可能想知道,高斯过程中一定有某种机制来确保 X 位置的模型预测值与观测值 Y 接近,对吗?答案是贝叶斯法则,它给了我们后验概率。贝叶斯规则利用观测数据 Y 将先验分布更新为后验分布,使得后验分布产生 Y 的概率高于先验分布。

你可能会问,如果贝叶斯规则已经给了我们后验分布,根据定义,后验分布应该比先验分布更好地解释观测数据 Y ,为什么我们仍然需要最大化我们的目标函数,即对数边际似然?这是因为:

首先,前 p(f(X)) 和后 p(f(X)|y(X)) 的概率密度函数是模型参数的函数。它们是象征性的表达。只有当我们确定了这些模型参数的一些具体值时,后验概率密度函数才变得可评估。因此,我们需要找到模型参数的具体值的方法。

第二,并不是所有具体模型参数值的选择都一样好。即使先验、似然和后验的结构保持不变,插入不同的模型参数值将会得到不同的先验、似然和后验概率密度。不同的后验概率意味着它们对同一观测数据 Y 的解释概率不同。正如您在过拟合欠拟合部分所看到的,这些模型参数值的错误选择会导致模型无法很好地解释我们的观测数据 Y 。显然,我们想要以非常高的概率解释 Y 的后验。目标函数最大化是选择合理的模型参数值的一种方法。

数据如何适应术语变化

当我们改变长度尺度 l 时,数据拟合项如何变化?如果我们将观测噪声 η Iₙ 设置为 0,将均值函数 m(X) 设置为 0,并将信号方差 σ 设置为 1,则该趋势很容易证明。我们进一步假设只有两个训练点 (X₁,Y₁)(X₂,Y₂) 。在此设置中,数据拟合项变为:

现在,让我们改变长度比例 l ,看看数据拟合项如何变化。当 l 接近 0 时,数据拟合项评估为以下限值:

当 l 接近 时,数据拟合项评估为以下限值:

现在我们看到,当我们将 lengthscale l 从 0 增加到 时,数据拟合项从-【y₁+y₂】*减少到- ∞。*

当信号方差和噪声方差具有不同的值时,这种数据拟合项减少的趋势仍然成立。但是这种减少不是单调的。

上述推导假设 Y₁≠Y₂ ,意味着并非所有的训练 Y 都是相等的。我将在本节结束时分析 Y₁=Y₂ 的情况。

模型复杂性术语

我们来想一想为什么 - log(det(k(X,X)+η Iₙ)) 被称为模型复杂度项。 det(k(X,X)+η Iₙ) 表示矩阵 k(X,X)+η Iₙ 的行列式。类似于数据拟合术语,让我们关注纵向尺度 l

正如我们已经从 GP previous 部分的采样中看到的,较大的长度比例允许我们的 GP 在建模更平滑的函数之前,较小的长度比例允许我们的 GP 在建模更波动的函数之前。这里有两个来自两个 GP 先验的采样函数,蓝色的来自具有较大长度尺度 l=0.5 π的先验,红色的来自具有较小长度尺度 l=0.1π 的先验。**

Samples from the GP prior with different lengthscales

蓝色曲线更平滑,红色曲线更起伏。更平滑的曲线让我们想起使用较低次数多项式的线性回归设置,换句话说,就是更简单的模型。一条更曲折的曲线提醒我们,在线性回归设置中,多项式的次数越高,换句话说,模型越复杂。

如果你对低次和高次多项式线性回归没有概念,我用这个网站在我们的训练数据上用不同次数的多项式尝试线性回归。以下是适合 3 度的情况:

Polynomial linear regression with degree 3

这是 49 度的拟合度:

Polynomial linear regression with degree 49

我们可以看到,在线性回归设置中,较低的拟合度,或者更简单的模型,给出了更平滑的拟合曲线。更高的拟合度,或者更复杂的模型,给出了更扭曲的拟合曲线。

在高斯过程中,我们采用相同的模型复杂性概念。我们称之为 GP 先验,它允许更简单的平滑函数,而模型允许更复杂的波动函数。

来自 GP 先验部分的采样中,我们已经表明 GP 先验可以建模的函数的光滑性取决于长度尺度参数,而不取决于观察值 Y 。术语 - log(det(k(X,X) + η Iₙ)) ,通过不提 Y ,似乎是一个很好的衡量复杂度水平的候选。我们现在研究当 lengthscale l 从 0 变为∞时,该项的值如何变化。

类似于数据拟合项的研究,我们假设 η Iₙ 为 0,那么模型复杂度项为 - log|K| ,我们继续只使用两个训练位置 X₁X₂

当 lengthscale l 接近 0 时,模型复杂度项变为:

在第(3)行,方差项 k(X₁,X₁)k(X₂,X₂) 评估为 1。并且当 l 接近 0 时,协方差项 k(X₁,X₂)k(X₂,X₁) 评估为 0。于是 k(X,X) 就变成了一个单位矩阵。

在第(4)行,单位矩阵的行列式的值为 1。

在第(5)行,log(1)的计算结果为 0。

所以当 lengthscale l 趋近于 0 时,模型复杂度项趋近于 0。

当长度标尺 l 接近 时,模型复杂度项变为:

在第(3)行,当 l 接近 时,协方差项 k(X₁,X₂)k(X₂,X₁) 评估为 1。于是 k(X,X) 就变成了全 1 的方阵。

在第(4)行,全 1 矩阵的行列式计算结果为 0。

在第(5)行,log (0)的计算结果为- ∞。

因此,当长度尺度 l 接近 ∞时,模型复杂度项评估为∞。

这种变化的直觉从行列式运算符的意义上是很清楚的。矩阵的行列式度量矩阵的列向量所包围的空间的体积。例如,如果一个矩阵有三列【a b c】,那么它的行列式就是由 abc、围成的体积,如下图所示(图片改编自此处):

所以在我们的协方差矩阵 k(X,X) 的情况下:

  1. 当 lengthscale 为 0 时,矩阵 k(X,X) 是单位矩阵。单位矩阵中的列向量相互垂直。所以它们围成的空间体积是最大的,1。
  2. 当 lengthscale 趋近于∞, k(X,X) 越来越变成全 1 的矩阵,所以所有列都是 1 列。这些柱子指向同一个方向。所以它们围成的空间体积最小,为 0。

现在我们可以看到,模型复杂性项确实给了我们一个很好的模型复杂性度量。当模型很复杂时,模型复杂性项的计算结果是一个很小的值 0。当模型简单时,该项评估为大值 。因为我们希望最大化目标函数,所以我们希望模型复杂性项更大。换句话说,这个术语表达了我们更喜欢简单模型的想法。

过拟合

现在我们有了模型复杂性的度量。我们暗示过,不必要的复杂模型是不好的。但是为什么呢?因为尽管在数据拟合术语的意义上,复杂模型可以很好地拟合训练数据,但是它没有能力对新的测试位置做出好的预测。这叫做过度拟合。下面是如何看到过度拟合的效果:

  1. 正如我们已经从数据拟合项的分析中看到的,在数据拟合项评估其最大值的意义上,具有非常小的长度范围的复杂模型将为您提供最佳的数据拟合。
  2. 但是,由于 lengthscale 非常小,因此对于任何两个不相等的位置,核函数的值都为 0。假设测试位置 X_ 不同于训练位置 X ,那么 f(X_)* 中的随机变量将与 f(X) 中的随机变量零相关。*
  3. 正如我们在本文开头已经提到的,这意味着知道位置 X 处的值 Y 并不能给我们关于测试位置 X_ 处的函数值应该如何的信息。换句话说,我们极其复杂的模型没有能力在测试位置做出预测,因为训练位置 f(X) 的随机变量独立于测试位置 f(X_)* 的随机变量。复杂的模型将无法推广到测试数据。这太合身了。*

我们通过看后验均值和协方差来看看上面的分析在数学上是如何体现的。我们继续使用有两个训练数据点和一个测试点的设置。

当长度标度接近 0 时,后验均值为:

在第(2)行,由于 lengthscale 非常接近 0,所以当x≠x′时, k(x,x′)计算为 0。所以我们有几个 0 条目。

最后,后验平均值在第(4)行评估为 0。解释是:由于 f(X_) 中的随机变量独立于 f(X) 中的随机变量,除了假设其均值为 0(在 GP 先验中定义)之外,模型不知道任何关于 f(X_)* 的信息。这就是模型给出 0 作为后验均值的原因。*

现在,让我们看看后验协方差:

啊哈,在过度拟合的情况下,模型对其在测试位置的平均预测非常不确定,所以它报告了一个最大方差。

显然,我们不希望过度拟合。但是我们要不要用最简单的模型,长度接近 ?答案是否定的,因为那样我们就会有另一个问题——吃不饱。

欠配合

为了揭示欠拟合的问题,让我们用一个大的长度尺度比如说 l =100 来形成一个简单的模型。在这个设置中, k(x,x’)x≠x’计算出一个非常接近 1 的值,比如说 0.999,而不管 xx’在哪里,因为内核的指数内部的分母占主导地位。让我们通过研究单个测试位置 X_* 的后验均值和协方差,再次看看这个模型做出预测的能力。

后验均值是:

上述公式意味着无论 X_ 在哪里,后验均值都等于训练观测值 Y 的等权和,这是一个常数。这种持续的预测显然是糟糕的。*

最后,当纵向尺度较大时,我们来看看后验协方差:

我们可以看到,当欠拟合时,模型对其预测非常有信心,不像过拟合时,模型非常不确定。

为什么在欠拟合的情况下,模型非常确定?这是因为 lengthscale 非常大,所以任意两个随机变量之间的协方差几乎为 1。这意味着根据我们的模型, f(X) 将包含关于 f(X_) — f(X_)* 与 f(X) 百分之百协变的全部信息。一旦我们知道了 f(X) 的值,也就是我们的观测值 Y (既然我们假设没有观测噪声),那么 f(X_)* 的值就没有变化的空间了。因此协方差为 0,这是绝对确定的。*

正如您在过度拟合和欠拟合情况下所看到的,模型参数值的错误选择会导致模型无法很好地解释观察数据 Y 。好消息是,通过最大化关于模型参数的 log(p(y)) ,我们可以找到避免欠拟合和过拟合的模型参数的合理的具体值。原因如下。

战斗:数据拟合术语与模型复杂性术语

让我们在下表中总结一下数据拟合术语和模型复杂性术语的行为。

我们可以看到,随着 lengthscale l 从 0 增加到∞,数据拟合项和模型复杂性项以相反的方向变化——数据拟合项向负无穷大减少,而模型复杂性项向正无穷大增加。

这两项相互平衡,为我们提供了一个很好地适合训练数据,同时又不太复杂的模型。这种自动平衡的特性是可取的,因为我们不必设计单独的机制来控制模型的复杂性,例如线性回归中的 R1 或 R2 正则化

我们能平凡地解决参数学习吗?

答案是否定的。但让我们先试着理解这个问题。

看着上面的表格,一个有趣的问题可能会出现:因为我们想要最大化目标函数,而唯一有可能变得非常非常大的项是模型复杂性项 - log(det(k(X,X)+η Iₙ)) 当长度标度接近无穷大时。为什么我们不简单地将长度比例设置为一个非常大的数字呢?当然,如果我们这样做,数据拟合项将减少,并驱动目标函数的整体值下降。哪一届会赢?

要回答这个问题,我们需要研究哪个项接近无穷大更快:是数据拟合项接近-∞更快还是模型复杂度项接近∞更快。我们用极限来研究它们的速度。我们继续使用有两个训练数据点 (X₁,Y₁)(X₂,Y₂) 的设置,信号方差 σ1 并且没有观测噪声,所以 η Iₙ=0

为了保持公式的单行性,我将引入符号 r (相关性的简称)来表示位置 X₁X₂.的内核值 k(X₁,X₂) 因为我们只有两个训练地点,我们只有一个 r

所以当 lengthscale l 趋近于无穷大时,也就是我们正在研究的情况, r 趋近于 1,因为指数函数的自变量趋近于 0。

新符号 r 就位后,模型复杂性项变为:

数据拟合项变为:

现在我们研究当长度比例 l 接近 ∞,或者当 r 接近 1:

如第(4)行的解释所示,上述推导是针对 Y₁ ≠Y₂ 的情况。在这种情况下,当长度标度接近∞,或者当相关性 r 接近 1 时,整个目标函数接近-∞。换句话说,即使模型复杂性项增加到∞,数据拟合项减少到-∞的速度更快。所以数据拟合项胜出。因此,我们不能轻易地将 lengthscale 设置为一个非常大的值,并宣布参数学习已经完成。

现在我们研究一下当 Y₁ =Y₂: 的情况

这个更简单。当 Y 中的所有观测值相等时,随着长度标度趋近于∞,或者相关度 r 趋近于 1,对象函数趋近于∞。所以在这种情况下,模型复杂度获胜。也就是说,在所有观测值都相同的异常情况下,我们可以通过选择非常大的长度尺度来轻松解决参数学习。

抛开输赢不谈,重要的是获得直觉,为什么在所有观测值 Y 相等的情况下,大的长度尺度更好。

直觉来自于测试位置的后验均值是所有训练观察值的加权和 Y 。在当前情况下,由于长度尺度较大,所有观测值 Y 与测试位置的函数值具有接近 1 的相关性。因为所有的观察值都是相等的,没有理由给任何一个特定的观察值比其他的观察值更大的权重,因为它们是相同的。所以模型给了他们同等的权重。相等的权重转化为大的长度标度,因此无论 xx’在哪里,k(x,x’)都计算为 1。

因为在大多数情况下,我们不能平凡地解决参数学习,让我们来解决它。

寻找最佳模型参数值

为了找到最大化目标函数的长度尺度值,我以 0.01 为步长从 0 到 3 对其值进行了线搜索。我用这个代码通过线搜索进行参数学习。

下图绘制了 y 轴上的数据拟合项、模型复杂性项和目标函数的曲线,x 轴上具有不同的长度比例值。

随着长度尺度的增加,数据拟合项减少,这意味着我们得到了更差的数据拟合;模型复杂性增加了,这意味着我们得到了一个更简单的模型。这与我们上面的数学分析是一致的。

当 lengthscale l=2.1 时,目标函数有最大值。我用一个大红点突出了最大目标函数值。

Data fit term, model complexity term and objective function curves

以下是最佳长度标度 l=2.1 的后验均值和方差:

Posterior mean and variance with optimal lengthscale l=2.1. Blue crosses are training points, red dots are testing points.

同样,蓝叉“x”是训练数据点,红点是测试数据点。我不得不说,这很像正弦波。而且 95%的置信区间很小,我们再也看不到了。

梯度下降以优化目标

上面的网格搜索只是为了说明。在实践中,我们将使用梯度下降算法来寻找模型参数的最佳值。梯度下降的要求是目标函数相对于模型参数是可微的。这对我们的目标函数来说是正确的。我想指出的另一点是,我们的目标函数相对于模型参数不是凸的。梯度下降将找到局部最大值。

这样,我们就完成了参数学习。恭喜你!

平方指数核的无能

让我们回顾一下我们最初的任务:我们想找到一个函数 f: ℝ ⟼ ℝ,它能很好地解释我们的训练数据。高斯过程模型的后验均值和方差确实给了我们这个函数。

但是,你可能想知道,函数 f 有域ℝ,但是我们只看了从 0 到 2π的域。“给我看 2π以上的预测”,你要求!这是从 0 到 6π的域:

Posterior mean and variance beyond 2π. Blue crosses are training points, red dots are testing points.

哇,我们可以看到,超过 2π,后验均值开始偏离“正确”值,从 4.5π左右的位置开始逐渐回落到 0。同时,后验方差开始增加,直到最终在位置 4.5π附近达到最大值。

预测质量的逐渐恶化是因为当我们到达 4.5π附近的位置时,训练位置和测试位置的随机变量之间的相关性基本上为 0。所以模型只能报告后验均值为均值 0。此外,代表不确定性水平的后验方差达到最大值。

你可能会抱怨,经过这么多的工作,我们还没有找到正弦波的正确回归函数。这是因为正弦是一个周期函数。正弦函数中的两个点相互关联的程度不仅取决于它们相距多远,还取决于它们是否出现在一个周期的同一位置。我们选择的核函数是平方指数核,不能模拟这种周期性效应。

在高斯过程中,除了平方指数核,还有许多其他核,其中一些模拟周期函数。您也可以通过将两个内核相加或相乘来形成新的内核。我将提供另一篇关于内核的文章。目前,理解已经为我们定义了不同的内核就足够了。不同的内核模拟不同种类的函数。而选择核函数是使用高斯过程中最重要的任务。

结论

本文介绍了如何使用高斯过程来执行回归任务。它涵盖了高斯过程回归模型,如何使用后验均值和方差进行预测,以及如何进行参数学习。

本文仅涵盖了在进入更高级的主题之前需要掌握的最基本的知识。正如我在本文开头所说的,要在实际的应用程序设置中使用高斯过程,您可能需要另外两种技术:

当然,高斯过程场包括更多。将来,我将为那些高级主题提供其他文章。

请支持我

如果你喜欢我的故事,如果你考虑支持我,通过这个链接成为灵媒会员,我将不胜感激:【https://jasonweiyi.medium.com/membership。

我会继续写这些故事。

感谢

我要感谢我的许多 Prowler.io 同事,他们帮助我撰写了这篇文章。特别是 Nicolas DurrandeStefanos EleftheriadisVincent AdamVincent DutordoirST John 的想法和灵感,以及他们坐下来与我一起完成许多公式推导的好意。我还要感谢 Sherif AkoushAndrew Liubinas 对本文的反馈。

理解生成敌对网络(GANs)

原文:https://towardsdatascience.com/understanding-generative-adversarial-networks-gans-cd6e4651a29?source=collection_archive---------0-----------------------

一步一步地建立导致 GANs 的推理。

Credit: Devanath on Pixabay

本帖与 巴蒂斯特·罗卡 共同撰写。

介绍

Yann LeCun 将其描述为“最近 10 年机器学习中最有趣的想法”。当然,来自深度学习领域如此杰出的研究人员的这种称赞对于我们正在谈论的主题来说总是一个很好的广告!事实上,自 2014 年 Ian J. Goodfellow 和合著者在文章Generative Adversarial Nets中提出以来,生成对抗网络(简称 GANs)取得了巨大的成功。

那么什么是生成性对抗网络呢?是什么让他们如此“有趣”?在这篇文章中,我们将看到对抗性训练是一个启发性的想法,简单而美丽,代表了机器学习,尤其是生成模型的真正概念进步(就像反向传播是一个简单但非常聪明的技巧,它使神经网络的基础思想变得如此流行和有效)。

在进入细节之前,让我们先快速概述一下 gan 的用途。生成对抗网络属于生成模型集。这意味着他们能够生产/产生(我们将看到如何)新的内容。为了说明“生成模型”的概念,我们可以看看一些众所周知的用 GANs 得到的结果的例子。

Illustration of GANs abilities by Ian Goodfellow and co-authors. These are samples generated by Generative Adversarial Networks after training on two datasets: MNIST and TFD. For both, the rightmost column contains true data that are the nearest from the direct neighboring generated samples. This shows us that the produced data are really generated and not only memorised by the network. (source: “Generative Adversarial Nets” paper)

自然,这种生成新内容的能力让 GANs 看起来有点“神奇”,至少乍一看是这样。在接下来的部分中,我们将克服 GANs 的明显魔力,以便深入这些模型背后的思想、数学和建模。我们不仅将讨论生成性对抗网络所依赖的基本概念,而且,我们将一步一步地从最开始开始建立导致这些概念的推理。

事不宜迟,我们一起重新发现甘氏吧!

注意:虽然我们试图让这篇文章尽可能的自成一体,但是仍然需要一个机器学习的基础先验知识。然而,大部分的概念将会在需要的时候被保留,一些参考文献将会以其他方式给出。我们真的尽力让这篇文章读起来尽可能流畅。请不要犹豫,在评论栏中说出你想了解更多的内容(可能会有更多关于这个主题的文章)。

概述

在接下来的第一节中,我们将讨论从给定的分布中生成随机变量的过程。然后,在第 2 节中,我们将通过一个例子说明 GANs 试图解决的问题可以表示为随机变量生成问题。在第 3 节中,我们将讨论基于匹配的生成网络,并展示它们如何回答第 2 节中描述的问题。最后,在第 4 节,我们将介绍甘斯。更具体地说,我们将介绍具有损失函数的一般架构,并将与前面所有部分联系起来。

  • 本文已使用以下备忘单完成:

https://drive . Google . com/drive/folders/1 lhtjhq 8k 7 aemrqanymylrrwzp 6 bsqqgrb

  • 本文已部分用以下短视频说明:

生成随机变量

在本节中,我们讨论生成随机变量的过程:我们提醒一些现有的方法,尤其是允许从简单均匀随机变量生成复杂随机变量的逆变换方法。尽管这一切似乎有点远离我们的主题,GANs,我们将在下一节看到与生成模型的深层联系。

均匀随机变量可以伪随机产生

计算机从根本上来说是决定性的。所以,理论上,不可能产生真正随机的数字(即使我们可以说“什么是随机?”是一个难点)。然而,可以定义算法来生成其性质非常接近理论随机数序列的性质的数字序列。特别地,计算机能够使用伪随机数发生器来生成近似遵循 0 和 1 之间的均匀随机分布的数字序列。统一情况是一个非常简单的情况,在此基础上可以用不同的方式建立更复杂的随机变量。

用运算或过程的结果表示的随机变量

存在不同的技术,旨在产生更复杂的随机变量。其中我们可以找到例如逆变换方法、拒绝采样、Metropolis-Hasting 算法等。所有这些方法都依赖于不同的数学技巧,主要在于将我们想要生成的随机变量表示为一个操作(对更简单的随机变量)或一个过程的结果。

拒绝采样将随机变量表示为一个过程的结果,该过程不是从复杂分布中采样,而是从众所周知的简单分布中采样,并根据某些条件接受或拒绝采样值。重复这个过程,直到采样值被接受,我们可以表明,在正确的接受条件下,将被有效采样的值将遵循正确的分布。

Metropolis-Hasting 算法中,想法是找到一个马尔可夫链(MC ),使得这个 MC 的平稳分布对应于我们想要从中采样我们的随机变量的分布。一旦找到这个 MC,我们可以在这个 MC 上模拟足够长的轨迹,以认为我们已经达到稳定状态,然后我们以这种方式获得的最后值可以被认为是从感兴趣的分布中提取的。

我们不会进一步深入拒绝抽样和 Metropolis-Hasting 的细节,因为这些方法不会将我们引向 GANs 背后的概念(尽管如此,感兴趣的读者可以参考指向的维基百科文章和其中的链接)。然而,让我们更关注逆变换方法。

逆变换方法

逆变换方法的思想是简单地表示我们的复数——在本文中,“复数”应该总是从“不简单”的意义上理解,而不是从数学的意义上理解——随机变量是函数应用于我们知道如何生成的均匀随机变量的结果。

我们考虑下面的一维例子。设 X 是一个我们想要采样的复杂随机变量,U 是一个我们知道如何采样的在[0,1]上的均匀随机变量。我们提醒一个随机变量完全由它的累积分布函数 (CDF)定义。随机变量的 CDF 是从随机变量的定义域到区间[0,1]的函数,并且在一维中定义为

在均匀随机变量 U 的特殊情况下,我们有

为简单起见,这里我们假设函数 CDF_X 是可逆的,它的逆表示为

(通过使用函数的广义逆,该方法可以很容易地扩展到不可逆的情况,但这确实不是我们在这里想要关注的要点)。那么如果我们定义

我们有

我们可以看到,Y 和 X 有相同的 CDF,然后定义了相同的随机变量。因此,通过如上定义 Y(作为均匀随机变量的函数),我们已经设法定义了具有目标分布的随机变量。

综上所述,逆变换法是一种通过使一个均匀的随机变量经过一个设计良好的“变换函数”(逆 CDF),生成一个遵循给定分布的随机变量的方法。这种“逆变换方法”的概念实际上可以扩展到“变换方法”的概念,更一般地说,它包括产生作为一些更简单的随机变量的函数的随机变量(不一定是均匀的,然后变换函数不再是逆 CDF)。从概念上讲,“变换函数”的目的是使初始概率分布变形/整形:变换函数从初始分布与目标分布相比太高的地方开始,并将其放在太低的地方。

Illustration of the inverse transform method. In blue: the uniform distribution over [0,1]. In orange: the the standard gaussian distribution. In grey: the mapping from the uniform to the gaussian distribution (inverse CDF).

生成模型

我们试图生成非常复杂的随机变量…

假设我们对生成大小为 n 乘 n 像素的狗的黑白正方形图像感兴趣。我们可以将每个数据重新整形为 N=nxn 维向量(通过将列堆叠在彼此的顶部),这样狗的图像就可以用向量来表示。然而,这并不意味着所有的向量都代表一只曾经被整形回正方形的狗!因此,我们可以说,有效地给出看起来像狗的东西的 N 维向量根据非常特定的概率分布分布在整个 N 维向量空间上(该空间的一些点很可能代表狗,而对于其他一些点则极不可能)。本着同样的精神,在这个 N 维向量空间上,存在猫、鸟等图像的概率分布。

然后,生成狗的新图像的问题等价于在 N 维向量空间上生成遵循“狗概率分布”的新向量的问题。所以我们实际上面临着一个问题,关于一个特定的概率分布,产生一个随机变量。

在这一点上,我们可以提到两件重要的事情。首先,我们提到的“狗概率分布”是一个非常大的空间上的非常复杂的分布。第二,即使我们可以假设这种潜在分布的存在(实际上存在看起来像狗的图像和其他不像狗的图像),我们显然不知道如何明确地表达这种分布。前面两点使得从这个分布中产生随机变量的过程相当困难。接下来让我们试着解决这两个问题。

…因此,让我们使用以神经网络为功能的变换方法!

当试图生成我们的狗的新图像时,我们的第一个问题是 N 维向量空间上的“狗概率分布”是非常复杂的,并且我们不知道如何直接生成复杂的随机变量。然而,由于我们非常清楚如何生成 N 个不相关的均匀随机变量,我们可以利用变换方法。为此,我们需要将 N 维随机变量表示为一个非常复杂的函数应用于一个简单的 N 维随机变量的结果!

在这里,我们可以强调这样一个事实,即寻找变换函数并不像我们在描述逆变换方法时所做的那样,仅仅取累积分布函数的封闭形式的逆(我们显然不知道)。转换函数无法显式表达,因此,我们必须从数据中学习。

在大多数情况下,非常复杂的函数自然意味着神经网络建模。然后,想法是通过神经网络来模拟变换函数,该神经网络将简单的 N 维均匀随机变量作为输入,并且返回另一个 N 维随机变量作为输出,该另一个 N 维随机变量在训练之后应该遵循正确的“dog 概率分布”。一旦设计了网络的架构,我们仍然需要训练它。在接下来的两节中,我们将讨论两种训练这些生成网络的方法,包括 GANs 背后的对抗性训练思想!

Illustration of the notion of generative models using neural networks. Obviously, the dimensionality we are really talking about are much higher than represented here.

生成匹配网络

免责声明:生成匹配网络的命名并不标准。然而,我们可以在文献中找到,例如,“生成矩匹配网络”或“生成特征匹配网络”。我们只是想在这里用一个稍微更通用的命名来描述下面的内容。

训练生成模型

到目前为止,我们已经表明,生成狗的新图像的问题可以被重新表述为在 N 维向量空间中生成遵循“狗概率分布”的随机向量的问题,并且我们已经建议使用变换方法,用神经网络来模拟变换函数。

现在,我们仍然需要训练(优化)网络来表达正确的变换函数。为此,我们可以建议两种不同的训练方法:直接训练法和间接训练法。直接训练方法包括比较真实的和生成的概率分布,并通过网络反向传播差异(误差)。这是支配生成匹配网络(GMNs)的思想。对于间接训练方法,我们不直接比较真实分布和生成分布。相反,我们通过使这两个分布通过选择的下游任务来训练生成网络,使得生成网络相对于下游任务的优化过程将强制生成的分布接近真实分布。这最后一个想法是我们将在下一节介绍的生成对抗网络(GANs)背后的一个想法。但是现在,让我们从直接方法和 GMNs 开始。

基于样本比较两种概率分布

如上所述,GMNs 的思想是通过直接比较生成的分布和真实的分布来训练生成网络。然而,我们不知道如何明确地表达真正的“狗概率分布”,我们也可以说生成的分布太复杂而不能明确地表达。因此,基于显式表达式的比较是不可能的。然而,如果我们有一种基于样本比较概率分布的方法,我们可以用它来训练网络。事实上,我们有真实数据的样本,并且我们可以在训练过程的每次迭代中产生生成数据的样本。

虽然在理论上,可以使用任何能够有效地比较基于样本的两个分布的距离(或相似性度量),但是我们可以特别提到最大平均差异(MMD)方法。MMD 定义了两个概率分布之间的距离,可以基于这些分布的样本来计算(估计)该距离。虽然这并没有完全超出本文的范围,但是我们决定不花太多时间来描述 MMD。然而,我们的项目将很快发表一篇文章,其中将包含更多的细节。现在想更多了解 MMD 的读者可以参考这些幻灯片、这篇文章这篇文章

分布匹配误差的反向传播

因此,一旦我们定义了基于样本比较两个分布的方法,我们就可以定义 GMNs 中生成网络的训练过程。给定一个均匀概率分布的随机变量作为输入,我们希望生成的输出的概率分布是“狗概率分布”。GMNs 的想法是通过重复以下步骤来优化网络:

  • 生成一些统一的输入
  • 让这些输入通过网络并收集生成的输出
  • 比较真实的“狗概率分布”和基于可用样本生成的“狗概率分布”(例如,计算真实狗图像样本和生成图像样本之间的 MMD 距离)
  • 使用反向传播进行一步梯度下降,以降低真实分布和生成分布之间的距离(例如 MMD)

如上所述,当遵循这些步骤时,我们在网络上应用梯度下降,损失函数是当前迭代中真实分布和生成分布之间的距离。

Generative Matching Networks take simple random inputs, generate new data, directly compare the distribution of the generated data to the distribution of the true data and backpropagate the matching error to train the network.

生成对抗网络

“间接”训练法

当训练生成网络时,上面提出的“直接”方法直接比较生成的分布和真实的分布。支配 GANs 的绝妙想法在于用一种间接的比较来代替这种直接的比较,这种间接的比较采取对这两个发行版的下游任务的形式。然后,关于该任务完成生成网络的训练,使得它迫使生成的分布越来越接近真实分布。

GANs 的下游任务是区分真实样本和生成样本。或者我们可以说是“非歧视”任务,因为我们希望歧视尽可能地失败。因此,在 GAN 架构中,我们有一个鉴别器,它采集真实数据和生成数据的样本,并尝试尽可能好地对它们进行分类,还有一个发生器,它被训练成尽可能欺骗鉴别器。让我们看一个简单的例子,为什么我们提到的直接和间接方法在理论上应该导致相同的最优生成器。

理想情况:完美的发生器和鉴别器

为了更好地理解为什么训练生成器来欺骗鉴别器会导致与直接训练生成器来匹配目标分布相同的结果,让我们举一个简单的一维例子。我们暂时忘记了生成器和鉴别器是如何表示的,并将它们视为抽象概念(将在下一小节中详细说明)。此外,在不受任何(参数化)模型约束的意义上,两者都被认为是“完美的”(具有无限的容量)。

假设我们有一个真实的分布,例如一维高斯分布,并且我们想要一个从这个概率分布中采样的生成器。我们所谓的“直接”训练方法包括反复调整生成器(梯度下降迭代),以校正真实分布和生成分布之间的测量差异/误差。最后,假设优化过程是完美的,我们应该最终得到与真实分布完全匹配的分布。

Illustration of the concept of direct matching method. The distribution in blue is the true one while the generated distribution is depicted in orange. Iteration by iteration, we compare the two distributions and adjust the networks weights through gradient descent steps. Here the comparison is done over the mean and the variance (similar to a truncated moments matching method). Notice that (obviously) this example is so simple that it doesn’t require an iterative approach: the purpose is only to illustrate the intuition given above.

对于“间接”方法,我们还必须考虑一个鉴别器。我们现在假设这个鉴别器是一种 oracle,它确切地知道什么是真实的和生成的分布,并且能够基于这个信息来预测任何给定点的类(“真实的”或“生成的”)。如果这两种分布相差很远,鉴别者就能很容易地对我们提供给它的大多数点进行分类,并有很高的可信度。如果我们想欺骗鉴别器,我们必须使生成的分布接近真实的分布。当两个分布在所有点上都相等时,鉴别器将很难预测该类:在这种情况下,对于每个点来说,它“为真”或“生成”的机会是相等的,那么平均来说,鉴别器不会比在两个情况中的一个情况下为真做得更好。

Intuition for the adversarial method. The blue distribution is the true one, the orange is the generated one. In grey, with corresponding y-axis on the right, we displayed the probability to be true for the discriminator if it chooses the class with the higher density in each point (assuming “true” and “generated” data are in equal proportions). The closer the two distributions are, the more often the discriminator is wrong. When training, the goal is to “move the green area” (generated distribution is too high) towards the red area (generated distribution is too low).

在这一点上,怀疑这种间接的方法是否真的是一个好主意似乎是合理的。事实上,它似乎更复杂(我们必须基于下游任务而不是直接基于分布来优化生成器),并且它需要一个鉴别器,我们在这里将其视为给定的预言,但实际上,它既不已知也不完美。对于第一点,基于样本直接比较两个概率分布的困难抵消了间接方法明显更高的复杂性。对于第二点,很明显鉴别器是未知的。不过,是可以学的!

近似:对抗性神经网络

现在让我们描述一下 GANs 架构中的生成器和鉴别器的具体形式。生成器是一个模拟转换函数的神经网络。它接受一个简单的随机变量作为输入,并且一旦被训练,必须返回一个遵循目标分布的随机变量。由于它非常复杂和未知,我们决定用另一个神经网络来建模鉴别器。这个神经网络模拟了一个判别函数。它将一个点(在我们的狗的例子中是一个 N 维向量)作为输入,并将这个点成为“真实”点的概率作为输出返回。

请注意,我们现在采用参数化模型来表示发生器和鉴别器(而不是上一小节中的理想化版本)的事实实际上对上面给出的理论论证/直觉没有很大影响:我们只是在一些参数化空间中工作,而不是在理想的全空间中工作,因此,我们在理想情况下应该达到的最佳点可以被参数化模型的精确能力视为“四舍五入”。

一旦被定义,这两个网络就可以以相反的目标被联合(同时)训练:

  • 生成器的目标是欺骗鉴别器,因此生成神经网络被训练成最大化最终分类误差(真实数据和生成数据之间)
  • 鉴别器的目标是检测虚假生成的数据,因此训练鉴别神经网络以最小化最终分类误差

因此,在训练过程的每次迭代中,生成网络的权重被更新以便增加分类误差(在生成器参数上的误差梯度上升),而鉴别网络的权重被更新以便减少该误差(在鉴别器参数上的误差梯度下降)。

Generative Adversarial Networks representation. The generator takes simple random variables as inputs and generate new data. The discriminator takes “true” and “generated” data and try to discriminate them, building a classifier. The goal of the generator is to fool the discriminator (increase the classification error by mixing up as much as possible generated data with true data) and the goal of the discriminator is to distinguish between true and generated data.

这些相反的目标和两个网络的对抗性训练的隐含概念解释了“对抗性网络”的名称:两个网络都试图击败对方,这样做,它们都变得越来越好。它们之间的竞争使得这两个网络相对于它们各自的目标“进步”。从博弈论的角度来看,我们可以将这种设置视为一种 minimax 两人游戏,其中平衡状态对应于生成器从精确的目标分布中产生数据的情况,以及鉴别器对其接收的任何点以概率 1/2 预测“真”或“生成”的情况。

关于 GANs 的数学细节

注意:本节更具技术性,对于全面理解 GANs 并非绝对必要。所以,现在不想读数学的读者可以暂时跳过这一部分。对于其他人,让我们看看上面给出的直觉是如何数学形式化的。

免责声明:以下等式不是伊恩·古德菲勒文章中的等式。我们在这里提出另一种数学形式有两个原因:第一,更接近上面给出的直觉,第二,因为原始论文的方程已经非常清楚,仅仅重写它们是没有用的。还要注意,我们绝对不考虑与不同的可能损失函数相关的实际问题(消失梯度或其他)。我们强烈鼓励读者也看看原始论文的方程:主要的区别是 Ian Goodfellow 和合著者用交叉熵误差而不是绝对误差工作(正如我们下面所做的)。此外,在下文中,我们假设一个生成器和一个具有无限容量的鉴别器。

神经网络建模本质上需要定义两件事:一个架构和一个损失函数。我们已经描述了生成敌对网络的架构。它由两个网络组成:

  • 生成网络 G(.)获取密度为 p_z 的随机输入 z,并返回应遵循(训练后)目标概率分布的输出 x_g = G(z)
  • 有区别的网络 D(。)获取输入 x,该输入可以是“真”输入(x_t,其密度表示为 p_t)或“生成”输入(x_g,其密度 p_g 是由穿过 G 的密度 p_z 引起的密度),并返回 x 为“真”数据的概率 D(x)

现在让我们仔细看看 GANs 的“理论”损失函数。如果我们以相同的比例向鉴别器发送“真实”和“生成”数据,那么鉴别器的预期绝对误差可以表示为

生成器的目标是欺骗鉴别器,鉴别器的目标是能够区分真实数据和生成的数据。因此,在训练发生器时,我们希望最大化这一误差,同时尽量减小鉴频器的误差。它给了我们

对于任何给定的生成器 G(以及诱导概率密度 p_g ),最好的可能鉴别器是最小化

为了最小化(相对于 D)这个积分,我们可以最小化 x 的每个值的积分内部的函数。然后,它定义了给定生成器的最佳可能鉴别器

(事实上,这是最好的方法之一,因为 x 值 p_t(x)=p_g(x)可以用另一种方法处理,但这与后面的内容无关)。然后我们搜索最大化的 G

同样,为了最大化(相对于 G)这个积分,我们可以最大化 x 的每个值的积分内部的函数。由于密度 p_t 独立于生成元 G,我们不能做得比设置 G 更好,使得

当然,由于 p_g 是一个概率密度,应该积分为 1,我们必须有最好的 G

因此,我们已经表明,在具有无限容量的发生器和鉴别器的理想情况下,对立设置的最佳点是这样的,即发生器产生与真实密度相同的密度,并且鉴别器在两种情况中的一种情况下不会比真实情况更好,正如直觉告诉我们的那样。最后,还要注意 G 最大化

在这种形式下,我们更好地看到 G 想要最大化鉴别器出错的期望概率。

外卖食品

这篇文章的主要观点是:

  • 计算机基本上可以生成简单的伪随机变量(例如,它们可以生成非常接近均匀分布的变量)
  • 存在不同的方法来生成更复杂的随机变量,包括“变换方法”的概念,其在于将随机变量表示为一些更简单的随机变量的函数
  • 在机器学习中,生成模型试图从给定的(复杂的)概率分布中生成数据
  • 深度学习生成模型被建模为神经网络(非常复杂的函数),其将简单的随机变量作为输入,并返回遵循目标分布的随机变量(“变换方法”之类)
  • 这些生成网络可以“直接”训练(通过将生成数据的分布与真实分布进行比较):这就是生成匹配网络的思想
  • 这些生成网络也可以被“间接”训练(通过试图欺骗另一个同时被训练的网络来区分“生成的”数据和“真实的”数据):这就是生成对抗网络的思想

即使围绕甘斯的“炒作”可能有点夸张,我们可以说伊恩·古德菲勒和他的合著者提出的对抗性训练的想法确实是一个伟大的想法。这种扭曲损失函数从直接比较到间接比较的方式对于深度学习领域的进一步工作来说是非常鼓舞人心的。最后,假设我们不知道 GANs 的想法是否真的是“过去 10 年机器学习中最有趣的想法”…但很明显,它至少是最有趣的想法之一!

感谢阅读!

:我们强烈建议感兴趣的读者阅读最初的论文“对抗性神经网络”,这确实是一篇科学论文的清晰模型,并观看关于 Ali Ghodsi 的 GANs 的讲座视频,他确实是一位了不起的讲师/教师。额外的解释可以在 Ian Goodfellow 写的关于 GANs 的教程中找到。

巴蒂斯特·罗卡一起写的其他文章:

[## 机器学习中不平衡数据集的处理

面对不平衡的班级问题,应该做什么,不应该做什么?

towardsdatascience.com](/handling-imbalanced-datasets-in-machine-learning-7a0e84220f28) [## 整体方法:装袋、助推和堆叠

理解集成学习的关键概念。

towardsdatascience.com](/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205)

理解遗传算法

原文:https://towardsdatascience.com/understanding-genetic-algorithms-cd556e9089cb?source=collection_archive---------15-----------------------

数据结构和算法

作为优化问题求解战舰棋盘游戏

The USS Intrepid in New York City. Photo: Author

一种遗传算法是技术模仿自然解决复杂问题的一个主要例子,在这种情况下,通过在一种进化算法中采用自然选择的概念。霍兰德在 1960 年引入的遗传算法扩展了艾伦·图灵的“学习机器”概念,最适合解决最优化问题,例如旅行推销员问题。

为了直观地理解采用遗传算法的实际实现和基本要求,我们可以设置一个玩具问题并解决经典猜谜游戏的棋盘,该游戏由 Milton Bradley 于 1967 年首次发布。但是,让我们让我们的遗传算法对整个棋盘进行一系列猜测,而不是调用一系列单独的击球。

设置董事会

遗传算法可以应用于那些解决方案可以用遗传表示法来表达的问题,遗传表示法就是简单的 1 和 0 的数组。每个二元元素被称为一个基因,而多个基因的阵列被称为一个染色体。给定问题的最佳解决方案是导致性能指标的最佳适合度分数的染色体。

一个战列舰棋盘由一个 10×10 的格子组成,我们可以在上面随意放置五艘不同长度的战舰。我们的舰队包括一艘航空母舰(5),一艘战列舰(4),一艘巡洋舰(3),一艘潜艇(3)和一艘驱逐舰(2)。我们可以用二进制表示法来表达棋盘,只需将被我们的船占据的方格表示为 1,将未被占据的方格表示为 0。

我们可以通过几个简单的步骤随机定位我们的每艘船:

  1. 用随机二维元组定位船首。
  2. 用一个随机的基本方向来确定船的航向。
  3. 根据船首的位置、方向和长度来定位船的尾部。
  4. 检查船的尾部是否保持在棋盘的边界内。
  5. 检查该船没有与任何先前定位的船重叠。
  6. 如果船没有通过两个断言测试中的任何一个,重复这个过程。

Python functions to generate a random Battleship board and evaluate candidate fitness. Source: Author⁴

这就产生了一个二维的二进制矩阵,必须转换成符合遗传形式的一维数组。我们可以通过堆叠这些行来重塑棋盘,以创建一个由 100 个基因组成的染色体。由于棋盘解中的每个基因可以是 1,也可以是 0,我们的玩具问题可以用 2 ⁰⁰或 1.27e+30 种可能的方式来排列!

遗传形式的板解

000011110000000000000000011110000000000001000100000000010000000010000000000100000000010000000100000001000000000010000000000000000001000000000000000

Binary representation of Battleship board with 5 ships occupying 17 squares (red 1). Image: Author

猜测整个董事会

我们可以通过用 100 个基因的任意组合生成一条染色体来随机猜测整个棋盘。通过猜测每个基因被占据(红色)或未被占据(蓝色)的概率相等,随机样本应该预期包含 50 个被占据的正方形。通过叠加猜测和解决方案(1 和 0),我们可以看到它们有多匹配。

Random chromosome with 51 occupied squares (red) and 49 unoccupied squares (blue). Image: Author

一条染色体的适合度可以通过计算有多少基因正确匹配遗传解(绿色)中的基因,然后除以基因总数(绿色和红色)来简单评估。我们随机染色体的这个准确率已经是 52%!即使只有 17 个被占据的正方形,任何二项式分布都将接近 50%的中值精度。

遗传算法现在可以从这个适应度度量中学习,以建议甚至更高性能的染色体。健身功能可以根据需要进行完善,以提供更多信息反馈。例如,我们可以计算分类问题中常用的混淆 matrix,⁶来解释假阳性和假阴性,以返回精度召回

Accuracy rate of random chromosome with 52 matches (green) and 48 mismatches (red). Image: Author

既然我们知道如何创建随机染色体并评估其适应性,让我们创建一个由 10 个随机猜测组成的基因库并观察它们的表现。我们可以根据健康水平对染色体进行分类,并将表现最好的(准确率为 57%)标记为精英。即使我们只有一个小样本,样本分布的中位适合度仍然是 52.5%。

Fitness of 10 random chromosomes in generation 1. Image: Author

创造后代

既然我们已经建立了自己的基因库,我们就可以利用适者生存的自然选择概念,从老一代创造出新一代。第一步是选择老一代中的精英染色体作为新一代的父母。这些父母染色体然后可以通过两个流行的遗传操作符创造孩子,这两个操作符被称为交叉突变

精英主义

来自前一代的最适合的染色体,其被选择作为新一代中所有染色体的父代。

交叉

两条染色体可以在一个随机交叉基因上拼接,重组产生两个孩子,共享来自父母双方的基因链。

变化

一条染色体上的随机基因可以通过位翻转来反转,从而产生一个与其父母相比具有微小遗传变异的孩子。

让我们创建第二代 10 条染色体,精英率 20%(双亲),交叉率 20%(一对拼接的孩子),突变率 60%(六个突变的孩子)。我们的比特翻转率是 1%,这样,突变体与它们的父母相比,平均只有一个基因不同。我们可以再一次把我们这一代人按适合度排序,发现我们两个精英现在 58%和 60%适合!

Fitness of 2 elitism, 2 splice pair and 6 mutation chromosomes in generation 2. Image: Author

如果我们反复重复这个过程来创造新的一代,会发生什么?随着每一代的发展,我们只保留最好的表现,放弃非最优的解决方案。通过传承精英,我们保证了一代人的最高表现可能会增加,而不会减少。155 代后,一条染色体达到 100%适合度的解!

Fitness of 2 elitism, 2 splice pair and 6 mutation chromosomes in generation 155. Image: Author

收敛到基因解决方案

我们已经将每一代的大小固定为 10 条染色体,但遗传算法在许多领域都融入了随机性,从我们的随机染色体到交叉基因再到比特翻转率。前 10 代的统计数据显示了自然选择是如何逐渐提高种群适应度的,而离散度在第一个随机世代中最高。

Fitness distribution statistics for generations 1 to 10. Image: Author

最近 10 代的统计数据显示,每个群体都非常适合,最不适合的染色体得分为 95%。随着高适应性染色体接近遗传解,它变得更有可能只能通过突变单个基因来提高其适应性。因此,高突变率和低比特翻转率给合适的世代实现目标解的最好机会。

Fitness distribution statistics for generations 146 to 155. Image: Author

我们可以通过绘制跨代的适应度统计来可视化遗传算法的性能。任何随机二项分布将赋予第一代 50%的适合度。精英主义保证世代峰值性能将单调增加,而交叉促进实质性的初始改进,变异将它们推向顶端。

Convergence of the gene pool towards the optimal solution over 155 generations. Image: Author

调整模型参数

遗传算法的随机性意味着它的性能和效率会随着一系列重复试验而变化。通过求解 1,000 个游戏并绘制所有代中创建的总染色体的分布,我们看到我们的遗传算法通常会在 1.27e+30 种可能性中仅创建约 1,700 条染色体后找到最优解!

这种性能分布特定于我们的模型的超参数,即每代 10 条染色体,20%的精英率,20%的交叉率,60%的突变率和 1%的比特翻转率。将来,我们可以通过最小化这些特征参数的收敛速度来优化我们的遗传算法的效率。

Performance metric of a genetic algorithm with fixed model parameters over 1,000 samples. Image: Author

为该分析编写的源代码可以在 GitHub,⁶上获得,其中包括一个战舰板的随机生成器、一个遗传算法的实现以及本文中给出的示例。虽然掌握遗传算法还有很多细节,但我们应该有信心理解这种优化算法的基本原理。

参考

  1. J.H. Holland,《自然和人工系统中的适应:生物学、控制和人工智能应用的介绍性分析》,剑桥:麻省理工学院出版社,1992 年。
  2. A.m .图灵,“计算机器和智能”, Mind ,第 59 卷,第 236 期,第 433–460 页,1950 年。
  3. E.斯托尔茨,“推销员的进化:Python 的完整遗传算法教程”,走向数据科学,2018 年 7 月 17 日。
  4. A.C. Dick,《设置随机战舰棋盘游戏》,载于 GitHub,https://gist . GitHub . com/AC Dick/11 D2 BC 2d 3c 046306 a 143 FD 5a 0 b 24 b 6 a 9,2019。
  5. H.费雷拉,“机器学习中的混淆矩阵和其他度量”,雨果·费雷拉的博客,2018 年 4 月 4 日。
  6. A.C. Dick,“理解遗传算法”,载于 GitHub,https://github.com/acdick/understanding_genetic_algorithms,2019。

理解几何和逆二项式分布

原文:https://towardsdatascience.com/understanding-geometric-and-inverse-binomial-distribution-ff30722e8bd1?source=collection_archive---------14-----------------------

逐步介绍

在我之前的文章中,我一直在谈论两种最流行的离散随机变量的概率分布:伯努利和二项式。在这里,我将详述他们所谓的“对应物”,即几何和逆二项式。

它们都涉及到伯努利试验序列的概念,因此当我们面对伯努利随机试验时,值得回忆一下。

伯努利分布是随机变量的离散概率分布,采用二进制布尔输出:1 表示概率 p,0 表示概率(1-p)。这个想法是,每当你在进行一个可能导致成功或失败的实验时,你可以将你的成功(标为 1)与概率 p 联系起来,而你的不成功(标为 0)将具有概率(1-p)。

与伯努利变量相关的概率函数如下:

成功概率 p 是伯努利分布的参数,如果离散随机变量 X 遵循该分布,我们写为:

现在,我们知道,如果我们运行多个伯努利试验,并且我们正在查询恰好有 k 个成功的概率,我们正在处理一个二项分布。

但是我们需要多少次试验才能获得一次(或多次)成功呢?

几何分布

几何分布的思想是模拟在获得第一次成功之前进行一定数量的伯努利试验(每次试验都有参数 p )的概率。当然,我们用 k 表示的试验次数的范围从 1(第一次试验成功)到可能的无穷大(如果你非常不幸)。

所以我们用下面的例子直观的推导一下概率函数。想象你正在抛硬币,你想获得头(H)。因此,H 将是你的成功。每次翻转都是一个伯努利随机变量,概率 p 为 H,概率(1-p)为 Tail (T)。

您的目标是计算获得第一个 h 所需的 k 次试验的概率。因此,我们的随机变量 X 将是:

X = "获得第一次成功的伯努利试验次数"

因此,这种情况可以建模如下:

我们希望计算前 k-1 次失败的概率,每次失败的概率为 1-p,然后在第 k 次试验中成功(概率为 p)。由于每个伯努利试验都是相互独立的,我们将:

我们写道:

说我们的随机变量 X 有一个几何概率函数。

逆二项式分布

如果几何分布计算第一次成功的试验次数,则逆二项式模型计算 x 次试验恰好获得 k 次成功的概率。

再一次,让我们用和之前一样的例子来模拟我们的逆二项式。然而,这一次,让我们假设我们想要计算进行 x 次试验的概率,以精确地得到 k 个头。这里的关键区别是,我们可以有这种情况的不同组合:我们必须考虑的唯一约束是我们的 x 次试验的最后结果必须是成功的,否则要有 k 次成功,较低的试验次数就足够了。

因此:

由于每一次失败都有概率(1-p ),每一次成功都有概率 p,我们得到在获得 k 次成功之前进行 x 次试验的概率由下式给出:

其中:

是二项式系数,用来计算所有可能的组合。此外,我们写道:

假设我们的随机变量 X 遵循一个参数为 k,p 的逆二项式。

最后,让我们看看这些分布的形状:

from scipy.stats import geom, nbinom
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(2, 1)p = 0.5
k=3
x = np.arange(geom.ppf(0.01, p), geom.ppf(0.99, p)) #for the geometric
y = np.arange(nbinom.ppf(0.01, k, p),nbinom.ppf(0.99, k, p)) #for the inverse binomial
ax[0].plot(x, geom.pmf(x, p), 'bo', ms=8, label='geom pmf')
ax[0].set_title('Geometric distribution with p=0.5')
ax[0].vlines(x, 0, geom.pmf(x, p), colors='b', lw=5, alpha=0.5)
ax[1].plot(y, nbinom.pmf(y, k, p), 'bo', ms=8, label='nbinom pmf')
ax[1].set_title('Inverse Binomial distribution with k=3,p=0.5')
ax[1].vlines(y, 0, nbinom.pmf(y, k, p), colors='b', lw=5, alpha=0.5)

可以看到,在几何分布中,随着试验次数的增加,概率降低。另一方面,使用逆二项式,在前三次试验中获得三次成功的可能性小于在三次以上试验中获得成功的可能性。然而,在一定数量的试验(5)之后,概率再次降低。

原载于 2019 年 8 月 31 日【http://datasciencechalktalk.com

梯度增强机器入门—使用 XGBoost 和 LightGBM 参数

原文:https://towardsdatascience.com/understanding-gradient-boosting-machines-using-xgboost-and-lightgbm-parameters-3af1f9db9700?source=collection_archive---------3-----------------------

“My only goal is to gradient boost over myself of yesterday. And to repeat this everyday with an unconquerable spirit”; Photo by Jake Hills

嘶..坦白地说: 在过去,我曾经使用和调整过模型,但并不真正了解它们的功能。我试着用梯度推进机器——light GBM 和 XGBoost——做同样的事情,结果是..令人沮丧!

这种技术(或者更确切地说是懒惰),适用于简单的模型,比如线性回归、决策树等等。它们只有几个超参数——learning_rateno_of_iterationsalpha, lambda ——很容易知道它们的意思。

但是 GBM 是一个不同的世界:

  1. 他们有大量的超参数——这些参数可以决定你的模型的成败。
  2. 最重要的是,不像随机森林,他们的默认设置通常不是最佳的!

所以,如果你想用 GBMs 来建模你的数据,我相信,你至少要对内部发生的事情有一个高层次的了解。你不能把它当作一个完全的黑箱来使用。

这就是我想在这篇文章中帮助你的!

我要做的是,围绕梯度增强机器最流行的两种实现方式的参数—light GBMXGBoost ,对梯度增强机器做一个非常简单的解释。这样你就能知道算法中发生了什么,以及你应该调整哪些参数来使它变得更好。我相信,这个实用的解释会让你在自己的分析中直接实现它们!

您可能已经猜到了,在这篇文章中,我不打算深究数学。但是如果你感兴趣,我会张贴一些好的链接,如果你想跳的话,你可以跟随。

那我们就开始吧..

在这篇文章中,作者引用了他的同事迈克·金的话

我唯一的目标是超越昨天的自己。并以不可征服的精神每天重复这一点。

你知道我们每天都在通过关注昨天的错误来提高自己。你知道吗?—GBM 也这样做!

让我们使用 3 个简单部件来了解一下如何操作

1."预测者的集合"

GBM 通过创建一个预测集来做到这一点。一大群预测者。这些预测器中的每一个都是通过关注在它之前的预测器的错误而依次建立的。

你:等等,你在说什么“预测器”?GBM 本身不是预测器吗??

我:是的。这是你需要知道的关于梯度推进机器的第一件事——它是一个由许多更小的预测器组成的预测器。一组更简单的预测器。这些预测器可以是任何回归器或分类器预测模型。每个 GBM 实现,无论是 LightGBM 还是 XGBoost,都允许我们选择一个这样简单的预测器。哦嘿!这就引出了我们的第一个参数—

LightGBM 的 sklearn API 提供了一个参数-

  • **boosting_type** (LightGBM) **booster**(XGBoost):选择该预测算法。它们都提供了选项供您选择——gbdt、dart、goss、rf (LightGBM)或 gbtree、gblinear 或 dart (XGBoost)。****

但是请记住,决策树,几乎总是比其他选择好得多。好的一面是它是这个参数的默认设置;所以你不用担心!

2。“改进先前预测者所做的预测”

现在,我们来看看这些预测器是如何构建的。

我:是的,你猜对了——在这篇文章中,我们看到了 GBM 如何通过“关注昨天的错误”来提高自己!

所以,一个 GBM 基本上创造了许多独立的预测者,他们每个人都试图预测真正的标签。然后,它通过平均所有这些单独的预测给出它的最终预测。

但是我们不是在这里谈论我们正常的三年级平均水平;我们指的是加权平均值。GBM 为每个预测值分配一个权重,该权重决定了预测值对最终结果的贡献大小——权重越高,其贡献越大。

:它为什么要那样做?

因为不是所有的预测者都是平等的..

集合中的每个预测器都是按顺序建立的,一个接一个——和,每个预测器都更关注其前任的错误。

每次训练一个新的预测器时,该算法(从一组新的权重中)为先前的预测器出错的训练实例分配更高的权重。所以,这个新的预测者,现在,有更多的动机去解决更困难的预测。

你:但是,嘿,“平均许多预测者所做的预测”..那不是随机森林吗?

我:啊哈..接得好。“平均许多预测者的预测”实际上是一种集合技术。随机森林和梯度推进机器是两种集成技术。

但与 GBM 不同,随机森林中建立的预测器是相互独立的。它们不是顺序构建的,而是并行构建的。因此,随机森林中的预测因子没有权重。他们生来平等。

你应该看看 装袋助推 的概念。随机森林是一种装袋算法,而梯度推进树是一种推进算法。

简单吧?

模型如何决定要放入的预测因子的数量?
—通过超参数,当然:

  • **n_estimators**:我们传递我们希望 GBM 在*n_estimators*参数中构建的预测器的数量。默认数字是 100。

你:但是我还有一个问题。重复构建新模型来关注标签错误的例子——这难道不是过度拟合的方法吗?

我:哦,那才是开悟!如果你在想这个..你猜对了!

事实上,这是使用梯度增压机的主要问题之一。但是像 LightGBM 和 XGBoost 这样的现代实现很擅长通过创建弱预测器来处理这个问题。

3.“弱预测”

一个弱预测器是一个简单的预测模型,它的表现比随机猜测要好。现在,我们希望 GBM 内部的单个预测器是弱的,这样整个 GBM 模型就可以是强的。

:嗯,这个好像反了!

:嗯,这听起来可能有点倒退,但这就是 GBM 创建强大模型的方式。这有助于防止过度拟合。请继续阅读,了解如何操作..

由于每个预测器都将关注前一个预测器出错的观察值,当我们使用弱预测器时,这些错误标记的观察值往往具有一些可学习的信息,下一个预测器可以学习这些信息。

然而,如果预测值已经很强,那么错误标记的观察值很可能只是样本数据的噪声或细微差别。在这种情况下,模型将简单地过度适应训练数据。

还要注意的是,如果预测因子太弱,甚至不可能从它们中构建出一个强大的集合。

所以,“创造一个弱预测器”..这似乎是一个很好的超参数化领域,对吗?“让我们把真正的问题留给开发者去解决吧!”😛

这些是我们需要调整以做出正确预测的参数(如前所述,这些简单的预测是决策树):

  • **max_depth****(XGBoost 和 LightGBM) : 这提供了每个决策树允许拥有的最大深度。较小的值表示较弱的预测值。****
  • **min_split_gain** (LightGBM),**gamma** (XGBoost):在树的一个叶节点上做进一步划分所需的最小损失减少。值越低,树越深。**
  • **num_leaves** (LightGBM):基础学习者的最大树叶数。值越高,树越深。
  • **min_child_samples** (LightGBM):子(叶)节点中所需的最小数据点数。根据 LightGBM 文档,这是防止过度拟合的一个非常重要的参数。

The subtree marked in red has a leaf node with 1 data in it. So, that subtree can’t be generated as 1 < **min_child_samples** for the above case

注意:这些是您可以调整以控制过度拟合的参数。

注 2: 弱预测值对强预测值——这是 GBMs 和随机森林的另一个不同点。随机森林中的树都很强壮,因为它们彼此独立建造。

就是这样。现在您对 GBM 如何工作的整个故事有了一个很好的概述!

但是在我离开你之前,我想让你知道更多的参数。这些参数并不完全符合我刚刚缝在上面的故事,但它们被用来在性能上挤出一些效率。

我还将讨论如何调优这些超参数。最后,我会给你一些链接,让你更深入地了解 GBMs 背后的数学和理论。

【号外】。二次抽样

即使在正确调整了所有上述参数之后,也可能只是发生系综中的一些树高度相关。

你:请解释一下你说的“高度相关的树”是什么意思。

我:当然。我指的是结构相似的决策树,因为基于相同特征的相似分裂。当集合中有这样的树时,这意味着集合作为一个整体将存储比树不同时所能存储的更少的信息。所以,我们希望我们的树尽可能的不相关。

为了解决这个问题,我们在每次迭代之前对数据行和列进行子采样,并在这个子采样上训练树。这意味着将在整个数据集的不同子样本上训练不同的树。
不同的数据
->不同的树
**

这些是需要注意的相关参数:

  • **subsample**(XGBoost 和 LightGBM):指定在每个子采样阶段要考虑的行数比例。默认情况下,它被设置为 1,这意味着没有二次采样。
  • **colsample_bytree**(XGBoost 和 LightGBM):指定在每个子采样阶段要考虑的列的比例。默认情况下,它被设置为 1,这意味着没有二次采样。
  • **subsample_freq** (LightGBM):这指定了应该在每k次迭代之后进行打包。默认情况下,它设置为 0。因此,如果要启用二次采样,请确保将其设置为某个非零值。

【号外】。学习率

  • **learning_rate**(XGBoost 和 LightGBM 都有):
    也叫缩水。使用它的效果是学习变慢,反过来需要更多的树被添加到集合中。这给了模型一个正则化的效果。它减少了每棵树的影响,并为未来的树留下了改进模型的空间。

【号外】。类别权重

  • **class_weight** (LightGBM):
    当我们有不平衡的类时,这个参数对于多类分类任务极其重要。我最近参加了一个 Kaggle 比赛,在比赛中,只要将这个参数的值设置为balanced,我的解决方案就会从排行榜的前 50%跃升到前 10%。

你可以在这里查看 LightGBM 的 sklearn API,在这里查看 XGBoost 的 sk learn API。

寻找最佳超参数集

即使在理解了所有这些超参数的用法之后,为您的模型找到一组好的超参数也是极其困难的。他们人太多了!

因为我的整个故事是围绕这些超参数展开的,所以我想简单地告诉你如何进行超参数调整

你可以使用 sklearn 的**RandomizedSearchCV**来找到一组好的超参数。它将随机搜索超参数的所有可能组合的子集,并返回最佳的可能超参数集(或至少接近最佳的东西)。

但是如果您希望更进一步,您可以查看使用**GridSearchCV**返回的超参数集。网格搜索将使用每个可能的超参数组合来训练模型,并返回最佳集合。请注意,因为它尝试了每一种可能的组合,所以运行起来会很昂贵。

那么,在哪里可以使用算法呢?

GBM 擅长有效地建模任何类型的结构化表格数据。Kaggle 竞赛的多个获奖解决方案使用它们。

以下是Kaggle 竞赛的获奖模型中使用 LightGBM 的列表。

它们比许多其他堆叠回归技术实现起来更简单,并且也很容易给出更好的结果。

谈到使用 GBMs,我想告诉你更多关于随机森林的信息。我在上面简单地谈过——随机森林是一种不同类型的(基于树的)集合技术。

它们很棒,因为它们的默认参数设置非常接近最佳设置。因此,与需要调优的 XGBoost 和 LightGBM 不同,它们会用默认的参数设置给你一个足够好的结果。但是一旦调优,XGBoost 和 LightGBM 可能会表现得更好。

关于梯度增强的更多信息

正如我所承诺的,这里有几个链接,你可以通过它们来理解梯度推进背后的理论和数学(按照我喜欢的顺序)

我是自由撰稿人。你可以雇我为你公司的博客写类似的深入、热情的文章,解释 ML/DL 技术。给我发电子邮件到 **nityeshagarwal[at]gmail[dot]com** 来讨论我们的合作。

请在下面的评论区告诉我你的想法。也可以在 LinkedIn 或者 Twitter ( 关注我那里;我不会滥发你的饲料;) )

了解梯度下降

原文:https://towardsdatascience.com/understanding-gradient-descent-35a7e3007098?source=collection_archive---------13-----------------------

这一关键数据科学工具的基础

最小化模型和训练数据集之间的误差是数据科学中的一项基本实践。毕竟,如果一个模型与训练数据集不匹配,那么它显然不会有任何预测能力。

关于这个概念的例子,请参见了解线性回归的基本原理了解多元回归。在这两种情况下,特定类型的模型(线性回归或多元回归)通过最小化误差来拟合数据集。

为了最小化模型中的误差,还需要能够计算误差。这样做时,既要抓住情况的复杂性,又要对数据科学家的全局关注保持敏感。这需要一个写得很好的成本函数,正如在成本函数:机器学习的基础中所描述的。

一旦选择了模型类型并编写了成本函数,最后一步就是实现一个工具来最小化成本函数,从而使模型符合数据。成本函数将根据需要改变模型中的参数,以找到最佳拟合。

梯度下降是这个角色的有力工具。

什么是梯度下降?

让我们通过一个例子来解释梯度下降。想象一条抛物线。抛物线既有不断变化的斜率,也有一个极小点。最小点出现在斜率为零的地方,因为这也是另一侧斜率开始增加的地方。

对于熟悉微积分的人来说,这相当于说最小值出现在方程的导数等于零的点上。

现在想象我们从某个点开始,想要到达最小值。我们现在不需要具体说明某一点,因为这都是概念性的。我们可以从起点计算任意方向的斜率,确定哪个斜率是正的,哪个是负的,然后向负斜率的方向移动。这将自动使我们更接近最小值。

逐步反复朝那个方向走,最终会找到最小点。

这就是梯度下降的过程。梯度下降是一系列函数,1)自动识别任意给定点在所有方向上的斜率,2)调整方程的参数以向负斜率的方向移动。这逐渐把你带到一个最低点。

用梯度下降法求一条抛物线的极小点有点傻;对于这个简单的例子来说,这是一个非常强大的工具。但是,当有许多变量,在许多不同的方向上有许多不同的斜率时,会发生什么呢?这就是自动化过程的力量变得清晰的地方。

梯度下降是如何工作的?

G 梯度下降自动执行我们之前抛物线示例中描述的所有步骤。特别是它:

  • 计算每个变量在该点的偏导数,
  • 结合关于每个变量的偏导数以识别向量空间中最负斜率的方向,
  • 朝着最负斜率的方向前进,
  • 重复该过程,直到找到最小点。

这个过程不会立即找到最小点。偏导数中没有足够的信息来告诉梯度下降算法最小点在哪里,相反它只知道向哪个方向移动。因此,梯度下降必须估计最佳步长,向那个方向移动,重新计算偏导数,估计最佳步长,向那个方向移动…等等,直到它最终找到最小值。

这回避了关于步长的问题。梯度下降算法如何选择步长?

我如何选择步长?

事实上,这可能是一个棘手的选择。它通常被描述为一门艺术而不是一门科学。

小步走是最不可能超调和错过最小点的。这很好。小步走最准。另一方面,它们会导致极其耗时的搜索。

想象一下,运行梯度下降,并希望如此确定,你准确地找到了最小值,你使用一个微小的步长,算法需要迭代十亿次。这可不好。

但是,与此同时,您确实希望保持步长足够小,以确保不会超调。

这种困境的一些可能的解决方案包括:

  • 随着时间的推移,你可以逐渐减小步长。这是可行的,因为在开始时超过最小点的风险很小。您可以使用较大的步长对整个参数空间进行粗略搜索。然后,随着算法对最小值的大致位置越来越有信心,它开始使用较小的步长来缩小特定点的范围。
  • 您还可以计算在该方向上产生最小点的步长,并执行该步长。以这种方式,模型识别移动的方向,然后识别在该方向上移动的最佳距离,并且这样做。一旦到达那里,它就搜索新的最佳方向和距离。这个过程大大减少了寻找最小值所需的迭代次数。

不幸的是,这两种方法都不是明显的赢家。

逐渐减小步长的效果并不理想,因为步长减小可能太慢或太快。步长的快速减小导致该算法试图避免的问题,微小的步长和许多迭代。缓慢减小步长会导致超过最小值点的另一个问题。

计算最佳步长非常有效,但是计算量非常大。它确实减少了迭代次数,但每次迭代花费的时间太长,不会显著减少计算时间。

一个很好的解决方案是使用一个计算最优步长的伪版本。这可以通过为算法提供一系列可能的步长来实现。然后,该算法遍历这些可能的步长,找到具有最佳结果的步长,并执行该步长。这比随时间自动改变步长更精确,并且在每一点计算最佳步长更有时间效率。

它提供了灵活的解决方案,在每一点上都能很好地工作,而不需要太大的计算开销。

梯度下降的局限性是什么?

梯度下降法的最大限制是计算时间。对大型数据集中的复杂模型执行此过程可能需要很长时间。这部分是因为梯度必须在每一步对整个数据集进行计算。

这个问题最常见的解决方案是随机梯度下降。

什么是随机梯度下降?

随机梯度下降基于参数空间中每个点的误差是可加的假设。第一点的误差可以加到第二点的误差上,第二点的误差可以加到第三点的误差上,对于所有点都是如此。

这意味着模型不需要同时计算所有点的误差(一个计算量很大的过程)。相反,它可以单独计算每个点的误差,并将它们相加。

顺便说一下,这个假设几乎总是正确的。最好的做法是思考一会儿,以确保它在你的问题中是正确的,而不是简单地假设它是正确的,但你会发现它在大多数情况下是正确的。

通过使用该假设,随机梯度下降能够依次计算每个点的误差。这大大节省了计算时间。

这极大地提高了梯度下降过程中每一步的速度。随机梯度下降仍然是一个迭代的过程,确定一个方向,一步一步向最小值前进。

随机梯度下降的缺点是它不能可靠地找到真正的最小值。相反,它倾向于非常接近,然后永远围绕最小值。为了避免这种情况,设置一个改进阈值是很重要的。如果通过梯度下降函数的重复迭代没有在成本函数中产生显著的减少,那么你仅仅是在围绕最小点。是时候退出梯度下降过程,接受可用的结果了。

将这一切结合在一起

梯度下降是生成数据科学预测模型的重要工具。这是一种常见的优化方法,用于最小化成本函数,从而找到模型中的最佳参数。例如,它通常用于将线性回归多元回归模型拟合到训练数据集。

该算法的工作原理是计算曲线在数据空间中的点在每个方向上的斜率,并调整参数以向最负斜率的方向移动。对于那些熟悉微积分的人来说,它是通过偏导数来实现的。

确定步长是使用梯度下降的一个基本挑战。小的步长确保找到真正的最小值,但是也产生许多许多迭代和长的计算时间。大步长运行得更快,但更有可能超过最小点。常见的解决方案是为模型提供一些不同的步长供选择。然后,它计算每一步长的改进,并移动到那个距离。这比使用大的步长提高了精度,同时避免了小步长的计算时间挑战。

使用梯度下降优化参数集可能是一个非常耗时的过程。这是因为它必须同时计算整个数据集的误差。随机梯度下降通过假设误差是可加的来避免这个问题。这样,它可以依次计算每一点的误差,减少对计算机的计算要求。它产生明显更快的结果。

[1]对于没学过微积分的人来说,偏导数就是单变量的方程的斜率。比如 A = 0.25 + 0.9 * B + B * C + 1.2 C 对 B 的偏导数等于 0.9 + C。

[2]“最负斜率”是指大概会有很多负斜率的方向。为了尽可能快地找到最小值,梯度下降使用负斜率绝对值最高的方向。

[3]它能走多远?它如何知道要使用的步长?好问题。请继续阅读,这些问题很快就会得到解决。

理解梯度下降及其变体

原文:https://towardsdatascience.com/understanding-gradient-descent-and-its-variants-cf0df5c45478?source=collection_archive---------7-----------------------

简要了解优化算法如何支持机器学习模型中的学习过程

机器学习模型很神奇;他们可以识别视频中的物体;它们可以自动为图像生成字幕,并对猫狗图片(有时)进行准确分类。

Image from https://www.kaggle.com/c/dogs-vs-cats

本文将提供对机器学习模型下发生的事情的表面理解。更具体地说,我们将探索使这些机器学习模型能够学习的“主干算法”。

“骨干算法”被称为优化算法。下面是你在这篇文章中会遇到的一些关键词的定义,优化算法也在提供的描述中。

  • 优化算法:执行预定次数的算法,用于寻找问题的最优解,在数学术语中,这些“问题”被称为函数。
  • 梯度下降:该优化算法被用来寻找降低成本函数的值。这是通过梯度值的计算来完成的,该梯度值用于在找到成本函数的局部最小值的每一步选择值。梯度的负值用于寻找局部最小值。
  • 成本函数:这是一种量化机器学习模型执行“有多好”的方法。量化是基于一组输入的输出(成本),这些输入被称为参数值。参数值用于估计预测,而“成本”是预测值和实际值之间的差异。
  • 全局最小值:这是位于成本函数整个域内的最小参数值。您可能会遇到局部最小值,它是指位于成本函数的设定范围内的最低参数值。
  • 收敛:这描述了在机器学习环境中使用时向最佳参数值或全局最小值移动的概念

本文底部是一些标准机器学习术语及其定义的链接。把它当成圣诞礼物😊。

我们将在本文中探索的优化算法是梯度下降。

梯度下降

梯度下降是一种非常常见的优化算法,很可能是许多机器学习工程师和数据科学家引入的第一种优化算法。

让我们画一幅画。我们有一个成本函数,我们需要找到最优解来求解成本函数。接下来是梯度下降,这是一种算法,它通过改变模型中的参数值来工作,所有这些都是为了最小化成本函数。成本函数的一个例子是均方差

梯度下降固有功能的工作原理是,根据从误差函数获得的关于特定数据点的参数的计算梯度,找到朝向局部最小值的方向。

这可能有助于理解一些图像和可视化梯度下降。

让我们使用一个包含一条碗形曲线和一个球的图形,球放在曲线的左上方。球表示最初随机选择的参数空间中的某个点(值),曲线表示相对于参数值范围绘制的成本值。目标是达到提供最低成本值的参数值。

在图的 X 轴上是代表成本的值,在 y 轴上是由‘X’表示的值,其代表我们用来求解成本函数的参数值的范围。

Image of a cost function curvature

最小值(单数)/极小值(复数)是斜率中存在最小化成本函数的最佳值的点,梯度下降是在几个步骤(迭代)中将我们的球导向最小值的算法。

为了求解成本函数,我们寻找曲线的最低点,这是梯度为零或接近零的点。

快速提示:成本函数曲线并不总是具有一个局部最小值的碗形。在上图中使用的示例中,成本函数只有一个输入参数(一维参数空间),但实际上,参数空间往往有更多的维度。

批量梯度下降

我们了解梯度下降是如何工作的,现在可以将其应用于我们的训练数据。梯度下降算法对训练数据的应用有多种形式。一种形式叫做批量梯度下降(BGD)

在上图中,我们朝着局部最小值前进。在 BGD,我们实际上利用我们掌握的每一个训练数据来决定我们向哪个方向移动以及移动多少。我们在每一步都使用所有的训练数据。

对于大量的训练数据,训练过程可能会延长,但在计算上是高效的,因为我们不像梯度下降的其他变体那样经常对我们的模型参数进行任何改变。

尽管 BGD 的内存效率不高,但你可以想象,在训练模型时,我们需要内存中所有可用的数据集。

随机梯度下降

在 BGD 硬币的另一面,我们有随机梯度下降 (SGD)。

与遍历训练集中的每个数据,然后向局部最小值前进相反,SGD 的工作方式是从训练集中实际选取一个数据点,并基于这个数据点计算梯度。

您可能会发现,在 BGD 和 SGD 之间,SGD 是更快的算法,因为您是基于数据的单个实例而不是整个数据集来计算梯度的,但代价是什么。

使用 SGD 时,梯度下降期间在参数空间内进行的更新可能会有噪声。SGD 的噪声特性是其随机特性的结果,当从训练集中选择数据点来计算每一步的梯度时,会出现这种随机特性。

为了适应 SGD 的噪声性质,并确保我们达到最佳参数值,我们必须对训练数据迭代一定次数,并确保在梯度下降过程的开始,训练数据被打乱。

噪声导致求解成本函数的模糊参数值,尽管给定足够的时间,SGD 将接近局部最小值。SGD 的噪声和随机性也是有益的。当算法陷入不是全局最小值的局部最小值时,这很有用。

与 BGD 相比,SGD 在每一步分配参数值时,由于其随机和不稳定的性质,具有避开局部最小值和找到全局最小值的优点。

但是与 SGD 相比,BGD 参数值更接近全局最小值和最优值。当面临在梯度下降算法的两个变型之间进行选择时,在速度和最优性之间有一个折衷。

小批量梯度下降

如何利用新加坡元和 BGD 的优点?

小批量梯度下降基于训练集中随机选择的数据计算梯度,就像 SGD 一样,但在计算梯度时不包括整个数据集,所以它也不完全是 BGD。你可以说它是一个混合体。

Mini Batch GD 在计算梯度时使用少量数据;与 BGD 相比,它更快,但与新加坡元相比,它仍然较慢。

相对于 SGD,小批量 GD 的优势在于降低了参数空间内的噪声。这意味着利用小批量 GD,意味着更容易达到最佳参数值。

唷,这还不算太糟,接下来,你可以在网上寻找关于每种算法的代码实现的资源。

我应该会发布一篇中型文章,概述如何实现本文中提到的一些梯度下降算法。

关注我,获取更多类似的文章。

正如承诺的那样,下面是一些常见机器学习术语定义的链接。

[## 机器学习初学者的 30 个袖珍术语

你在数据科学或机器学习职业生涯中会遇到的有用的机器学习术语列表。

towardsdatascience.com](/30-pocket-sized-terms-for-machine-learning-beginners-5e381ed93055)

理解 IME (Shapley 值)如何解释预测

原文:https://towardsdatascience.com/understanding-how-ime-shapley-values-explains-predictions-d75c0fceca5a?source=collection_archive---------13-----------------------

在最近的一篇文章中,我介绍了三种现有的方法来解释任何机器学习模型的个体预测。在的帖子关注了 LIME 之后,现在轮到了 IME(基于交互的解释方法),这是一种由 Erik Strumbelj 和 Igor Kononenko 在 2010 年提出的方法。最近这种方法也被称为 Shapley 值

IME 背后的直觉

当一个模型为一个观察值给出一个预测时,所有的特征并不扮演相同的角色:它们中的一些可能对模型的预测有很大的影响,而另一些可能是不相关的。因此,人们可能认为每个特征的影响可以通过检查如果该特征不存在时的预测来测量;模型输出的变化越大,特性就越重要。

但是,一次只观察一个特征意味着没有考虑特征之间的依赖关系,这可能会对模型的决策过程产生不准确和误导性的解释。因此,为了避免错过特征之间的任何交互,我们应该观察每个可能的特征子集的预测如何变化,然后组合这些变化以形成每个特征值的唯一贡献。

Source: https://www.ingenioustechnologies.com/blog/are-you-using-the-right-attribution-model-for-your-business/

确切地说,IME 基于这样一种思想,即实例的特征值共同作用,导致模型的预测相对于模型的预期输出发生变化,并且它以一种对所有可能的特征子集的贡献“公平”的方式在特征之间划分预测的总变化。

合作博弈论基础

一个合作(或联盟)博弈是一个元组({1,…,p}, v ,其中{1,…,p}是一个有限的 p 玩家的集合, v : 2ᵖ → ℝ是一个特征函数使得 v (∅)=0.

玩家 S⊂{1,…,p}的子集是联盟,所有玩家{1,…,p}的集合称为大联盟。特征函数 v 描述了每个联盟的价值。我们通常假设大联盟形成,目标是以“公平”的方式在参与者之间分配其价值(由特征函数定义)。因此,解是一个算子φ,它给博弈({1,…,p}, v )分配一个支付向量φ=(φ₁,φ₂,…,φₚ).

对于每一个至少有一个玩家的游戏,都有无限的解决方案,其中一些比另一些更“公平”。以下四个性质是对解φ的“公平性”概念的公理化尝试:

  • 公理 1:效率

φ₁(v)+φ₂(v)+…+φₚ(v)=v({ 1,…,p})

  • 公理 2:对称

如果对于两个玩家 ijv(s ∨{ I })=v(s ∨{ j })对每一个 S 成立,其中 S⊂ {1,…,p}和 i,j∉ S,那么φᵢ( v )=φⱼ( v

  • 公理 3:假人

如果v(s ∨{ I })=v(s)对每个 S 成立,其中 S⊂ {1,…,p}和 i∉ S,那么φᵢ(v)=0.

  • 公理 4:可加性

对于任意一对游戏 vw:φ(v+w)=φ(v)+φ(w),其中(v+w)(S)=v(S+w(S

Shapley 值是一种将总收益 v ({1,…,p})分配给 p 玩家的“公平”方式,从某种意义上说,这是唯一一种具有前面四个期望属性的分配。

此外,Shapley 值有一个等价公式:

其中 Sₚ是有限集合{1,…,p}的对称群(即,玩家集合{1,…,p}的所有置换的集合),Pre^i(O 是置换 O∈ Sₚ中玩家 i 的前辈玩家的集合(即,在置换 O∈ Sₚ).中出现在编号 i 之前的数字)

方法

设 X = X₁× X₂×…× Xₚ是 p 特征的特征空间,用集合{1,…,p}表示。

f 为被说明的模型。在分类中, f(x)x 属于某一类的概率(或二元指标)。对于多个类,IME 分别解释每个类,因此 f(x) 是相关类的预测。在回归中, f(x) 是回归函数。

最后,让 y=(y₁,…,yₚ)∈X 的例子从特征空间的预测,我们要解释。

Strumbelj 和 Kononenko 将特定情况下特征值子集的预测差异定义为通过观察这些特征值引起的期望值变化。形式上:

f 做个模特。让 S={i₁,i₂,…,iₛ}⊆{1,…,p}成为特征的子集。实例 y=(y₁,…,yₚ)∈X 中的特征子集 S⊆{1,…,p}的预测差δʸ(s 是:

注意,δʸ从所有可能的特征子集集合到ℝ定义了一个满足δʸ(∅)=e[f(x₁,…,xₚ)]-e[f(x₁,…,xₚ)]=0.的函数δʸ:2ᵖ→ℝ因此,对于以 p 为参与者的合作博弈,δʸ是一个有效的特征函数。因此,({1,…,p},δʸ)形成了前面定义的合作博弈。换句话说,IME 认为特征是游戏的参与者,其中联盟的价值是由δʸ定义的模型预测的变化,因此 IME 的目标是以“公平”的方式在特征之间分割预测δʸ({1,…,p}的总差异。

对于解释 y 的预测,第 i 个特征的建议贡献是合作博弈({1,…,p},δʸ):)的沙普利值

设{1,…,p}是特征集,δʸ是如上定义的预测差。第 i 个特征对解释 y 的预测的贡献是:

或者,等效地,使用 Shapley 值的替代公式:

其中 Sₚ是特征集合{1,…,p}的所有排列的集合,而 Pre^i(O 是在排列 O∈ Sₚ.中特征 i 的前身的特征集合

请注意,贡献的定义并不随意:联盟博弈({1,…,p}, v )的 Shapley 值\(φ\)是一种将总收益分配给 p 玩家的“公平”方式。在我们的例子中,公理 1 到 3 成为 IME 作为解释方法的三个可取的性质:

1.效率公理:φ₁(δʸ)+φ₂(δʸ)+…+φₚ(δʸ)= δʸ({1,…,p})=e[f|y]-e[f]=f(y)-e[f]

也就是说,在一个观察的解释中,所有 p 贡献的总和等于模型对实例的预测与模型的预期输出之间的差值,在没有关于实例特征值的信息的情况下。这一特性使得不同观测值和不同模型之间的贡献更容易比较。

2.对称公理:

如果对于两个玩家来说,{ t20 } I 和 j ,δʸ(s∪{i})=δʸ(s∪{ j })适用于每一个 S ,其中 S⊂ {1,…,p}和 i,j∉ S,那么φᵢ(δʸ)=φⱼ(δʸ).

换句话说,如果两个特征对预测具有相同的影响,则它们被赋予相同的贡献。

3.虚拟公理:

如果δʸ(s∪{i})=δʸ(s)对每一个 S 成立,其中 S⊂ {1,…,p}和 i∉ S,那么φᵢ(δʸ)=0.

也就是说,如果某个特征对预测没有影响,则该特征的贡献值为 0。

贡献的大小和符号都很重要。首先,如果一个特征比另一个特征具有更大的贡献,那么它对感兴趣的观察的模型预测具有更大的影响。其次,贡献的符号指示该特征是有助于增加(如果为正)还是减少(如果为负)模型的输出。最后,在没有任何关于特性值的信息的情况下,生成的贡献总和为模型的输出预测和模型的预期输出之间的差。总之,我们可以辨别模型的输出因观测的特定特征值而改变了多少,哪些特征负责这种改变,以及每个特征的影响大小。

在实践中,该方法的主要挑战是指数时间复杂度,因为贡献的计算需要使用所有可能的特征子集。为了避免这一问题,Strumbelj 和 Kononenko 开发了一种高效的采样程序,通过扰动实例的输入要素来估算要素贡献:

注意f(x’)f(x’)是分类器对两个观察值的预测,它们只是在第 i 个特征的值上不同。它们是这样构建的:取实例 z ,然后将出现在第 i 个特征之前的每个特征的值按顺序 O (对于x’,第 I 个特征也被更改)更改为我们要解释的 y 观察中的那个特征的值。

例子

设 X₁,X₂是两个二元特征,C={0,1}一个二元类,X={0,1}×{0,1}我们的特征空间。我们假设所有特征值组合都是等概率的,如下表所示。

假设该类由析取 C=X₁∨ X₂定义,也就是说,如果 X₁=1 或 X₂=1,C=1,否则为 0。设 f: X →[0,1]是一个(理想的)分类器。

A simple data set used for illustrative purposes. All combinations of features are equally probable.

我们将计算由 IME 产生的解释,以从类值 1 的角度解释观察值 y=(1,0)的预测。在这种情况下,我们可以分析计算每个特征的贡献。具体来说,我们将使用 Shapley 值的替代公式。

首先,我们需要计算有限集{1,2}的对称群 S₂,它有 2!=2 个元素:S₃={{1,2},{2,1}}

第二,我们必须计算所有特征子集的预测差异,因此如果没有已知的特征值,我们首先计算预期预测:

现在我们可以计算预测差异:

最后,我们可以计算特征的贡献:

第一特征的贡献为正,而第二特征的贡献为负,这是合理的。因为当至少一个特性为 1 时,类为 1,我们实例的第一个特性使模型预测为 1,所以这个值决定了模型预测为 1。相反,第二个特征使得 1 不太可能是预测类,因此它对模型的决策有负面影响。此外,第一个贡献的绝对值大于第二个贡献的绝对值,这意味着第一个特征对于预测是决定性的。最后,注意,当特征值未知时,这两个贡献总计为该实例的预测和预期预测之间的初始差异:φ₁+φ₂=3/8–1/8=1/4=1–3/4=f(1,0)-e[f(x₁,x₂],这由公理 1 保证。

总之,IME 对实例(1,0)预测的解释是,模型的决策受两个特征的影响,第一个特征比第二个特征更有利于(正确地)预测类 1,第二个特征的值与该决策相反。

这是一个非常简单的例子,我们已经能够分析计算,但这些在实际应用中是不可能的,因为我们需要算法的近似解。在以后的文章中,我将解释如何使用 R 和 Python 解释带有 Shapley 值的预测。

理解感知机是如何工作的

原文:https://towardsdatascience.com/understanding-how-the-perceptron-really-works-234b1b7cf44b?source=collection_archive---------15-----------------------

[## 想在数据科学方面变得更好吗?

当我在我发布独家帖子的媒体和个人网站上发布新内容时,请单击此处获得通知。](https://bobbywlindsey.ck.page/5dca5d4310)

感知器模型是一种二元分类器,其分类基于线性模型。所以,如果你的数据是线性可分的,这个模型会找到把它分开的超平面。该模型是这样工作的:

本质上,对于一个给定的样本,你把每个特征, x_i ,乘以它自己的权重, w_i ,然后求和。然后取这个和,应用激活函数。这将是你的预测。但是你用哪个激活功能呢?

激活功能

二元分类标签一般出现为 {-1,1}{0,1} 。感知器模型中使用的激活函数将取决于您选择哪组二进制标签。如果您选择 {0,1} ,您将需要使用 Heaviside 阶跃函数作为您的激活函数,因为它接受任何实数并输出 0 或 1。否则,您将使用符号功能

Sign and heaviside step functions

获取数据

假设你的二进制标签是 {0,1} 。感知器模型预测将是

Equation 1

产生 0 或 1。让我们来看看一个快速的例子,其中一些数据来自 Jason Brownlee 的博客机器学习大师

The data

让我们将数据帧分成训练数据和标签。

Features of the data

感知器推理

要从感知器模型获得预测,您需要实现等式 1。回想一下,等式 1 的矢量化等价物就是

Vectorized Equation 1

权重向量 w 和特征向量 x 的点积。

所以你有 x ,它代表一个样本,其中 x_i 是该样本的一些特征(比如has_scaleshas_fur,如果你试图预测哺乳动物与爬行动物)。但是你从哪里得到重量呢?这就是感知器模型需要从你的标记样本中学习的东西。开始时,你不知道这些值应该是什么,所以你可以让它们全是零。

尝试预测第一个样本:

Prediction: 1.0, Label: 0, Error: -1.0

不出所料,这个模型做得并不太好。让我们看看你是否能想出一种方法,让感知器模型学习它需要什么样的权重才能输出预期的标签。

教感知机学习

首先,你需要指定一个损失函数来告诉你你的模型做得有多差。损失越低越好。对于我们的示例,您可以使用误差平方和作为损失函数:

Sum of squared errors (our loss function)

其中 yhat_i 是感知器模型的预测,而 y 是预测应该是什么(即标签)。该函数简单地确定预测值和真实值之间的平方距离,并将所有这些距离相加。

与大多数现代机器学习方法一样,您现在可能会尝试使用梯度下降法,即获取上述损失函数相对于权重的梯度,并使用该梯度在最小化损失的方向上更新权重。产生的梯度将是:

Gradient of the loss function, but there’s a problem…

但是你看到这里的问题了吗?阶跃函数的导数在任何地方都是 0,除了在没有定义的 x = 0 处。这将迫使整个梯度为 0,权重永远不会更新。感知器模型永远不会学习。同样的问题也困扰着 sign 函数。

那么如何更新权重呢?事实证明,如果您的数据是线性可分的,那么下面的权重更新规则可以保证(通过收敛定理证明)在有限的步骤中收敛到一组权重,从而将数据线性分成两个不同的类。此更新规则定义为:

Weight-update rule for the perceptron

并且仅在 x 被感知器模型错误分类时应用。

但是这个更新规则是在假设二进制标签是 {-1,1} ,而不是 {0,1} 的情况下推导出来的。如果您的标签是 {-1,1} ,那么更新规则中的 y 将是-1 或 1,从而改变权重更新的方向。

但是因为你的二进制标签是 {0,1} ,这就出现了一个问题,因为 y 可能是 0。这意味着如果一个 x 被错误分类,并且它的真实值是 0,那么 w = w + 0 x = w 并且权重永远不会被更新。

幸运的是,您可以通过修改更新规则来解决这一问题,该规则仍然保证收敛,但同时适用于作为二进制标签的**{-1,1}* 和 {0,1} 😗

The more flexible weight-update rule

请注意,如果您的二进制标签是 {0,1}(y - yhat) 如果感知器模型预测正确(从而保持权重不变),则为 0,如果预测不正确,则为 1 或-1(这将确保权重在正确的方向上更新)。如果你的二进制标签是 {-1,1}(y - yhat) 如果感知器模型预测正确就是 0,如果预测错误就是 2 或者-2。这个修正的权重更新规则确保了正确的方向变化,无论你选择哪组二进制标签。

现在您已经知道如何更新权重,试着取一个样本,预测它的标签,然后更新权重。对每个样品重复上述步骤。

*SSE: 2.0
Weights: [4.84644761, 0.20872523, 0.]*

看起来感知器模型还没有找到完美区分这两个类别的权重。不如你给它更多的时间来学习,通过多次通过数据。让我们试三次传球。

*SSE: 2.0
SSE: 1.0
SSE: 0.0
Weights: [ 2.06536401, -2.34181177, -1.]*

不错!误差平方和为零,这意味着感知器模型在分离数据时不会产生任何误差。

适用于不同二进制标签的感知器

现在说你的二进制标签是 {-1,1} 。使用上面相同的数据(用-1 替换标签的 0),可以应用相同的感知器算法。这一次,你会看到 w = w + y xw = w + (y - yhat) x 都找到了一组权重来正确分离数据(即使权重不同)。

以下是感知器模型,其更新规则为 w = w + y x :

*SSE: 5.0
SSE: 4.0
SSE: 0.0
Weights: [ 2.06536401, -2.34181177, -1.]*

现在用 w = w + (y — yhat) x 作为更新规则:

*SSE: 5.0
SSE: 8.0
SSE: 0.0
Weights: [ 3.98083288, -6.85733669, -3.]*

两者融合!

包扎

在这篇文章中,你已经学习了什么是感知机模型,它可以应用于什么样的数据,模型背后的数学和它如何学习,以及用 Python 实现你的所有发现!

当然,在现实环境中,您会希望交叉验证您的模型,并且最好使用 scikit-learn 等库中可用的模型的可靠实现。但我希望这种感知机模型下的窥视有所帮助,如果你有任何问题,请随时通过bobbywlindsey.com联系我,或者通过媒体推特关注我。

原载于 2019 年 10 月 7 日https://www.bobbywlindsey.com

了解如何用“解释向量”解释预测

原文:https://towardsdatascience.com/understanding-how-to-explain-predictions-with-explanation-vectors-15e31e32bfc3?source=collection_archive---------17-----------------------

在最近的一篇文章中,我介绍了三种现有的方法来解释任何机器学习模型的个体预测。在帖子聚焦于 LIMEShapley values 之后,现在轮到解释向量了,这是一种由 David Baehrens、Timon Schroeter 和 Stefan Harmeling 在 2010 年提出的方法。

正如我们在提到的帖子中看到的,解释黑盒模型的决策意味着理解是什么输入特征使模型对正在解释的观察给出预测。

直观地说,如果某个特征值的微小变化导致模型输出的较大变化,则该特征会对模型决策产生很大影响,而如果该变量的较大变化几乎不影响模型输出,则该特征对预测几乎没有影响。

由于模型是一个标量函数,其梯度指向模型输出增长率最大的方向,因此它可用作特征影响的度量。在分类任务中,如果 c 是一个实例的预测类,则在该实例处评估的条件概率 P(Y≠ c|X=x)的梯度指向数据点必须移动以改变其预测标签的方向,因此它提供了对模型决策中最有影响的特征的定性理解。同样,尽管 Baehrens 等人将回归任务的推广工作留给了未来,但使用回归函数的梯度似乎是很自然的,因为它指出了数据点的局部小变化将意味着模型输出的大变化的方向。

因此,解释可以被定义为梯度向量,其表征了数据点必须如何移动以改变其预测,这就是为什么它们被称为解释向量的原因。

分类方法

Baehrens 等人提出,通过类别的条件概率的感兴趣点处的梯度来解释任何分类器的预测,该类别不是给定其特征值的预测类别。因此,解释是一个向量(称为解释向量),其表征了数据点必须如何移动以改变实例的预测标签。

这个定义可以直接应用于概率(或)分类器,它们的输出可以解释为概率,因为它们显式地估计了类别条件概率。然而,分类器(例如,支持向量机)直接估计决策规则,即,它们分配预测的类别标签,而不产生概率估计。对于这种类型的分类器,该方法提出使用核密度估计器(也称为 Parzen-Rosenblatt 窗口)来估计类条件概率,因此我们可以通过概率分类器来近似硬分类器。

概率分类器

设 X=ℝᵖ为特征空间。设 X=(X₁,…,Xₚ)∈ℝᵖ为 p 连续随机变量的向量,y 为{1,…,k}中可能取值(类标)的离散随机变量。设 P(X,Y)为联合分布,大部分时间未知。

f:ℝᵖ→【0,1]ᵏ使得 f₁(x)+f₂(x)+…+fₖ(x)=1,∀ x∈X,是被解释的“概率”分类器。此外,我们假设 f 的所有分量对于所有类别 k 以及在整个输入空间上相对于 X 是一阶可微的。最后,让 y∈ℝᵖ成为被解释的观察。

预测 f(x) 的每个分量 fᵢ 都是条件概率 P(Y=i|X=x)的估计。然而,“概率”分类器可以使用贝叶斯规则变成“硬”分类器,贝叶斯规则是 0-1 损失函数的最佳决策规则:

注意,{1- fᵢ (x)}是对 P(Y≠i|X=x)的估计。也就是说,预测的类别是具有最高概率的类别。

数据点 y∈ℝᵖ的解释向量定义为 y 的条件概率在 x=y 处的梯度不是给定 X=x 的预测类:

因此,解释向量ζ(y)是一个 p 维向量,其指向数据点必须被移动以改变其预测类别的方向。组件的正(负)符号意味着增加相应的特征将降低(提高)将 y 分配给{y}的概率。此外,分量的绝对值越大,该特征在类别标签预测中的影响越大。

解释向量的一个问题是它们可能变成零向量。如果这是因为局部最大值或最小值而发生的,我们可以从 Hessian 的特征向量中学习与模型决策相关的特征,即使我们不会获得它们的方向。然而,如果分类器结果是在 y 的某个邻域中平坦的概率分布,则不能获得有意义的解释。总之,解释向量方法非常适合输出类函数不完全平坦的概率的分类器。

在二元分类的情况下,Baehrens 等人将解释向量定义为正类的学习模型的概率函数 P(Y = 1 | X = x)的局部梯度。形式上,数据点 y∈ℝᵖ的解释向量是:

其中 f : ℝᵖ→ [0,1]是一个二元分类器。

注意 f(x) 是对 P(Y = 1 | X = x)的估计。因此,解释向量指向从数据点到类别 1 的更高概率的最陡上升的方向。此外,每个分量的符号指示当 y 的相应特征局部增加时,预测为 1 的概率是增加还是减少。最后,请注意,当预测类别为 1 时,解释向量的一般定义将不同于二元分类的定义,在这种情况下,负版本-ζ(y)可能特别有用,因为它指示如何移动要分配给类别 0 的数据点。

下图显示了如何应用解释向量来解释二元分类器的预测的示例:我们已标记了用于训练模型(在这种情况下,是高斯过程分类器)的训练数据(面板(a)),该模型为特征空间的每个数据点(面板(b))分配了正类中的概率。然后,我们计算我们想要解释的数据点的解释向量,以便理解是什么特征使得模型给出其预测。例如,在图(c)和(d)中,我们可以看到沿着假设和由数据产生的三角形的角的解释向量具有两个不同于零的分量,而沿着边的解释向量只有一个非零分量。因此,两个解释变量都会影响模型对沿假设边界和三角形拐角处观察值的决策,而只有一个特征与沿边观察值的模型预测相关。此外,解释向量的长度(面板(c))表示相关特征的重要程度,因此我们可以比较观察结果之间的解释。

Example of how explanation vectors are applied to model predictions learned by a Gaussian Process Classifier (GPC), which provides probabilistic predictions. Panel (a) shows the training points and their labels (class +1 in red, class -1 in blue). Panel (b) shows the trained model, which assigns a probability of being in the positive class to every data point. Panels (c) and (d) show the explanation vectors and the direction of the explanation vectors, respectively, together with the contour map of the model. Source: http://www.jmlr.org/papers/volume11/baehrens10a/baehrens10a.pdf

硬分类器

设 X=ℝᵖ为特征空间。设 X=(X₁,…,Xₚ)∈ℝᵖ为 p 个连续随机变量的向量,y 为{1,…,k}中可能取值(类标)的离散随机变量。设 P(X,Y)为联合分布,未知。

f : X=ℝᵖ → {1,…,k}为被解释的“硬”分类器。最后,让 y∈ℝᵖ成为被解释的观察。

设 x、…、xⁿ∈ℝᵖ为训练点,分别贴上标签。设 Iᵢ = {j∈{1,…,n} | f(xʲ) = i}为预测标号为 i 的训练集的指标集。

对于每个类别 i ,条件概率 P(Y=i|X=x)可以通过以下核密度估计量的商来近似:

因此,我们可以定义一个分类器,其组件是 P(Y=i|X=x)的估计值:

注意,我们可以使用经过训练的分类器 f 来生成尽可能多的标记数据,以构建这个近似(概率)分类器。现在我们有了一个概率分类器(它是我们最初的硬分类器的近似),我们可以使用贝叶斯规则来获得预测的类,就像我们在上一节中所做的那样:

然后,我们可以定义数据点 y∈ℝᵖ的估计解释向量如下:

其中 f : ℝᵖ →{1,…,k}是我们的“硬”分类器。

注意,使用实际预测类别 f(y) 来代替近似概率分类器的预测类别。这样做是为了确保估计的解释向量指向必须移动观察的方向,以改变由 f 预测的实际标签,而不是由近似分类器(可能不同)分配的标签。

最后,应当选择单个超参数σ,使得“新的”预测类别标签(即,由近似概率分类器最终分配的类别)尽可能地类似于由原始硬分类器 f 在测试集上做出的实际预测。形式上,如果 z,…,zᵐ∈ℝᵖ是测试数据点,f(z),… ,f(zᵐ)是分类器预测的它们各自的标签。那么,σ的选择值为:

用 skimage-Python 理解图像

原文:https://towardsdatascience.com/understanding-images-with-skimage-python-b94d210afd23?source=collection_archive---------11-----------------------

计算机视觉是当今的热门词汇。通过将计算机视觉技术与人工智能和人工智能相结合,许多有用的应用和系统正在出现

图像处理是每个计算机视觉专业人员工具箱中应该有的重要工具。图像处理是使用算法对数字图像执行各种操作。比如,

  • 增强图像
  • 提取有用的信息
  • 分析图像

图像处理用于各种领域,如医学图像分析、人工智能、图像恢复、地理空间计算、监控、机器人视觉、汽车安全等。

我将撰写一系列文章,让您对使用 Python 中的 skimage 进行数字图像处理的一些关键操作有一个实际的了解。在这第一篇文章中,让我们了解如何捕捉数字图像并以数字格式表示。

如何捕捉图像?

这一切都始于穿过照相机镜头的光线。通过镜头,它被聚焦在照相机的像平面上。图像平面通常以正方形或矩形容纳传感器(像素)。根据相机的构造,有时它们可以是六边形或圆形传感器。光在这个平面上投射的是一个二维的、依赖于时间的、连续的光能分布。该模拟信号的数字快照分三步捕获,

  1. 空间采样-这是将连续模拟信号转换为离散信号的步骤。
  2. 时间采样——这是测量每个传感器定期入射光量的步骤。
  3. 像素值的量化 -以上两个样本是我们数字图像的数据。但是为了存储和处理它,我们需要将它们转换成一系列整数值。(示例 256 = ⁸)

转换后的像素值稍后将以二维有序整数矩阵的格式存储。

尺寸和分辨率

假设“I”是我们图像的矩阵格式。图像的大小就是 I 的宽度和高度。

from skimage import io#replace the path of image
image = io.imread('~/Desktop/Lenna.png')print(image.shape)
print(type(image))Output:
(512, 512, 3)
<class 'imageio.core.util.Array'>

在上面的例子中,输出(512,512,3)表示图像中通道的宽度、高度和数量。看看我们的图像是以数组的形式表示的。

另一方面,分辨率是现实世界中图像的空间维度,通常以每次测量的图像元素数量给出(例如 dpi,每英寸点数)。

图像坐标系

在图像处理中,坐标系在垂直方向上翻转。轴的原点将在左上角。

坐标平面中的每个正方形被称为一个像素。每个像素将保存捕获图像时获得的量化值。像素值通常以 k 的二进制字给出(例如⁸)

from skimage import ioimage = io.imread('~/Desktop/Lenna.png')
print(image[0][0])Output:
[226 137 125]

输出有一个三个不同整数的列表,因为这里我加载了一个彩色图像。通常,彩色图像使用三个通道(RGB)来表示。这里 255、137、125 是红色、绿色、蓝色通道的强度值。

颜色通道

通道是指图像中颜色的数量。基于通道,图像通常分为两类。

灰度图像

灰度图像使用黑色及其变体的单一颜色通道来表示。在这里,如果是 8 位表示,每个像素将获得 0-255 之间的值。但是像素值的范围可能基于 k 位表示而不同。

from skimage import ioimage = io.imread('~/Desktop/Lenna_gray.png')print(image.shape)
print(type(image))
print(image[0][0])Output:
(256, 256)
<class 'imageio.core.util.Array'>
161

正如您在上面的例子中看到的,我们的图像数组的第一个位置只保存了一个值 161。

彩色图像

通常,彩色图像使用 RGB 三色通道来表示。将有三个通道,每个通道中的像素值将根据每个红色、绿色和蓝色的强度在 0-255 之间。

from skimage import ioimage = io.imread('~/Desktop/Lenna.png')print(image.shape)
print(type(image))
print(image[0][0])Output:
(512, 512, 3)
<class 'imageio.core.util.Array'>
[226 137 125]

注意:您可以在 image[0][0]中传递 0 到 width-1,0 到 height-1 之间的任何值。

这里它打印了一个包含三个值的列表,R = 256,G=137,B=125 是强度值。

我希望您已经对图像以及如何加载和获取图像属性有了一些基本的了解。让我们在图像处理的下一个主题中再次相遇。

了解卷积神经网络中的输入输出形状| Keras

原文:https://towardsdatascience.com/understanding-input-and-output-shapes-in-convolution-network-keras-f143923d56ca?source=collection_archive---------0-----------------------

即使我们从理论上理解了卷积神经网络,但在将数据拟合到网络时,我们中的很多人仍然会对其输入输出的形状感到困惑。本指南将帮助您理解卷积神经网络的输入和输出形状。

让我们看看输入形状是什么样的。输入到 CNN 的数据将如下图所示。我们假设我们的数据是图像的集合。

ConvNet Input Shape

输入形状

你总是需要给 CNN 一个 4D 数组作为输入。因此输入数据的形状为 (batch_size,height,width,depth) ,其中第一维表示图像的批量大小,其他三维表示图像的维度,即高度、宽度和深度。对于那些想知道图像深度是什么的人来说,它只不过是颜色通道的数量。例如, RGB 图像的深度为 3,而灰度图像的深度为 1。

输出形状

CNN 的输出也是一个 4D 阵列。其中批次大小将与输入批次大小相同,但是图像的其他 3 个维度可能会根据过滤器内核大小和我们使用的填充的值而改变。

让我们看看下面的代码片段。

Snippet-1

不要被这里的 input_shape 论点所欺骗。虽然它看起来像我们的输入形状是三维的,但你必须在拟合数据时通过一个 4D 数组,应该像 (batch_size,10,10,3) 。因为在 input_shape 参数中没有批量值,所以我们可以在拟合数据时使用任何批量值。

你可以注意到输出的形状是(无,10,10,64) 。第一维表示批量大小,目前为。因为网络事先不知道批量大小。一旦您拟合了数据, None 将会被您在拟合数据时给出的批量所取代。

让我们看看另一个代码片段。

Snippet-2

这里我用批处理输入形状替换了输入形状参数。顾名思义,该参数会提前询问您批次大小,在拟合数据时您可以不提供任何其他批次大小。例如,您必须使 16 个批次中的数据仅适合网络。

现在,您可以看到输出形状的批量大小也是 16,而不是 None

在卷积层上附加密集层

我们可以简单地在另一个卷积层的顶部添加一个卷积层,因为卷积的输出维度与其输入维度相同。

我们通常在卷积层的顶部加上密集层,对图像进行分类。然而输入数据到密集层 2D 数组的形状 (batch_size,units) 。卷积层的输出是 4D 阵列。因此,我们必须将从卷积层接收的输出的维度改变为 2D 阵列。

Snippet-3

我们可以在卷积层的顶部插入一个展平层。展平图层将图像的三维压缩为一维。现在我们只有一个形状为 (batch_size,squaded _ size)的 2D 数组,对于密集层来说是可以接受的。

摘要

  • 你总是需要将一个形状为 (batch_size,height,width,depth) 的 4D 数组输入到 CNN 中。
  • 来自 CNN 的输出数据也是一个形状为 (batch_size,height,width,depth)的 4D 数组。
  • 要在 CNN 图层上添加密集图层,我们必须使用展平图层将 CNN 的 4D 输出更改为 2D。

阅读我的下一篇文章,了解 LSTM 中的输入输出形状。

[## 了解 LSTM | Keras 中的输入和输出形状

当我开始研究 LSTM 网络时,我对输入和输出的形状感到非常困惑。这篇文章将…

medium.com](https://medium.com/@shivajbd/understanding-input-and-output-shape-in-lstm-keras-c501ee95c65e)

理解语言建模(NLP)和使用 ULMFIT

原文:https://towardsdatascience.com/understanding-language-modelling-nlp-part-1-ulmfit-b557a63a672b?source=collection_archive---------9-----------------------

使用带代码的 ULMFIT 进行文本分类

语言模型是单词序列的概率分布。这种语言模型被用作各种自然语言处理任务的基础模型,包括文本分类、摘要、文本生成等等。

建议先对深度学习和迁移学习有一个基本的认识,再继续这个博客。

LMs 使得映射上下文更加容易。男人对女人的映射相当于叔叔对阿姨,国王对女王。这种映射被转换成词汇间的联合概率分布。这被称为统计 LM。

给定这样一个序列,比如长度为 m ,LM 给整个序列分配一个概率 P{w1,w2,…,wm }。

由于词汇表的长度,统计 LMs 面临数据稀疏的问题。而神经语言模型(NLM)仅将单词序列作为输入,这解决了数据稀疏的问题。

在不深入语言模型数学的情况下,让我们理解 ULMFIT 是如何工作的,这将给出一个关于神经语言模型的想法。

通用语言模型微调(ULMFIT)是一种迁移学习技术,可以帮助完成各种 NLP 任务。很长一段时间以来,它一直是最先进的 NLP 技术,但后来它被 BERT(最近在文本分类方面被 XLNet 取代)取代了。我们将在博客的下一部分详细研究 BERT。

乌尔菲特的优点

深度学习需要大量数据集。具体来说,在进行迁移学习时,我们有一个大型数据集,我们的基础模型就是在这个数据集上构建的,我们将学习神经网络的参数迁移到我们的领域特定数据集。当我们有一个更小的特定领域数据集时,模型会过拟合。为了解决这个问题,杰瑞米·霍华德和塞巴斯蒂安·鲁德在他们的论文《关于文本分类的通用语言模型微调的中提出了 3 种不同的技术,用于针对 NLP 特定任务的迁移学习 LMs 中的微调

  • 区别微调
  • 倾斜三角形学习率
  • 逐步解冻

让我们了解使用 ULMFiT 创建文本分类器的各个阶段,通过它我们将了解作者建议的 3 种新技术。

ULMFiT 包括 3 个主要阶段:LM 预训练、LM 微调和分类器微调。

该方法是通用的,因为它满足这些实用标准:

  1. 它适用于不同文档大小、数量和标签类型的任务。
  2. 它使用单一的架构和培训流程。
  3. 它不需要定制的特征工程或预处理。
  4. 它不需要额外的域内文档或标签。

AWD-LSTM 是一个 最先进的 语言模型,一个常规的 LSTM(没有关注、快捷连接或其他复杂的添加),具有各种调整过的丢失超参数。作者使用 AWD-LSTM 作为他们建筑中的 LM。

(a)法律硕士职前培训

LM 在一个通用领域语料库上接受训练,以捕获不同层次语言的一般特征

我们在大型通用领域语料库上预先训练 LM,并使用新技术在目标任务上对其进行微调。因此,作者们使用了 Wikitext-103,这是一个由 2.8 万篇预处理文章组成的数据集,包含 1.03 亿个单词。一般来说,数据集应该非常大,以至于 LM 可以学习语言的所有属性。就计算资源和时间而言,这也是最昂贵的。因此我们只做一次。

(b) LM 微调

在几乎所有情况下,目标任务数据集相对于一般领域语料库将具有不同的分布。在这个阶段,我们通过使用 判别微调和倾斜三角形学习率,在目标任务数据集上微调模型以学习其分布。

由于不同的层次掌握不同的信息,作者建议对每一层进行不同程度的微调。

在随机梯度下降中,我们在每个时间步长 t 更新θ。

Regular SGD

在区别微调中,我们使用θ1、θ2、… θL,而不是各个 L 层的单个θ值。

Discriminative Learning rate

U 在整个培训过程中保持相同的学习率(LR)或一个稳定的学习率并不是实现这种行为的最佳方式。相反,我们提出倾斜的三角学习率(STLR)

The slanted triangular learning rate schedule used for ULMFiT as a function of the number of training iterations.

在 STLR,作者建议线性增加学习速率,并以下列方式衰减它。

在哪里,

  • T 是训练迭代次数
  • cut_frac 是迭代的分数
  • cut 是我们从增加 LR 切换到减少 LR 时的迭代
  • p 是我们分别增加或减少 LR 的迭代次数的分数
  • ****比率指定最低 LR 比最大 LR ηmax 小多少
  • ηt 是迭代 t 时的学习率

STLR 曾经用 达到最先进的 成绩 CV

(c)选粉机微调

微调是迁移学习的最重要的状态,需要尽最大的努力。因为过于激进的微调会使我们的模型过拟合,反之也会使我们的模型欠拟合。作者建议采用逐步解冻的方法来解决这一重大问题。

我们从解冻最后一层开始,因为它包含了最基本的知识。在微调一个时期的未冻结层之后,我们继续下一个较低层,并重复直到我们完成所有层,直到在最后一次迭代中收敛。

用于文本分类的****(BPT3C)语言模型通过时间反向传播(BPTT)来训练,以实现大输入序列的梯度传播。为了使针对大文档的分类器的微调变得可行,作者提出了用于文本分类的BPTT(BPT3C):将文档分成大小为 b 的固定长度的批次,在每个批次开始时,用前一批次的最终状态来初始化模型;跟踪平均池和最大池的隐藏状态;梯度被反向传播到其隐藏状态对最终预测有贡献的批次。在实践中,作者建议使用可变长度反向传播序列。****

所以,现在我们完成了压倒性的理论。让我们深入研究代码!!

我们将在 quora 的问题文本上实现文本分类,找出不真诚的问题。数据集在 kaggle 可用。

代码即将发布。在此之前,请亲自尝试。

理解线性回归和梯度下降的必要性

原文:https://towardsdatascience.com/understanding-linear-regression-and-the-need-for-gradient-descent-2cc0f25763d5?source=collection_archive---------21-----------------------

从头开始实现线性回归

在这里,我将从头开始用 python 实现一元线性回归,以更好地理解算法和梯度下降的需要。在我们开始之前,这里有一个线性回归算法的快速概述。

线性回归:概述

假设我们有所有朋友的身高和体重。假设一个人的体重只是身高的函数,没有其他因素,如果我们知道一个新人的身高,我们如何预测他的体重呢?这就是我们使用一元线性回归的地方。当要预测的值或目标变量是连续的时,我们采用线性回归。线性回归是一种机器学习算法,它试图将给定的一组点拟合到一条直线上,y = ax + b。

在我们的示例中,因变量 y 将是身高,自变量 x 将是体重,线性回归算法的工作是找到 ab 的值,这样 ax + b 将绘制一条符合所有(体重、身高)坐标的直线,即给出相应的体重。现在我们来谈谈它是如何做到这一点的。

该算法

线性回归算法通过最小化预测点和实际点之间距离的均方误差(MSE)来找到 ab 的正确值。

这本质上是一个优化问题,其中需要确定 ab 的值,这是通过找到某个损失函数的最小值来确定的。该算法从 ab 的一些初始值开始,并计算 y。然后找到实际点(y_actual)和由预测 y 值(y_pred)给出的点之间的距离。该算法计算距离的平方和及其平均值。这个平均值或 MSE 是需要通过优化问题最小化的损失函数。

Finding the distance between the predicted points and the actual points

Python 实现

现在我们知道了算法是如何工作的,让我们试着用 python 来实现它。

让我们导入一些我们需要的库,matplotlib 来绘制我们的线,numpy 来处理我们的数据。

import matplotlib.pyplot as plt
import numpy as np

现在让我们为 x 和 y 取一些值,

x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
y = np.array([1, 3, 2, 5, 7, 8, 8, 9, 10, 12])

x 和 y 都具有(10)的形状,绘制时看起来如下图所示,

plt.scatter(x, y)

让我们初始化 a 和 b,并定义计算 y_pred 和 mse 的方程。

a = b = 0y_ = a * x + bmse = np.mean((y — y_)**2)print(mse)>>54.1

对于给定的 x 和 y 值,mse 的初始值为 54.1。我们现在的目标是使其尽可能接近零。

让我们选择一个方向来遍历并更新 a 和 b 的值,直到我们的 mse 为零。我要把 a 和 b 都增加随机值,每一步 0.01,看看会得到什么。

while mse > 0:

  a = a+0.01
  b = b+0.01
  y_ = a * x + b

  if np.mean((y — y_)**2) < mse :
   mse = np.mean((y — y_)**2)

  else :
   print (a,b,mse)
   break>>>1.1900000000000008 1.1900000000000008 0.5634000000000003

当我们的 a 和 b 都是 1.19 时,我们的 mse 值下降到 0.563。

让我们画出结果线,看看它与我们的实际点是如何吻合的。

y_pred = a * x + bplt.figure(figsize = (12, 10))plt.plot(x, y_pred, label = ‘Predicted’)
plt.scatter(x, y, label = ‘Actual’)plt.show()

我们的路线似乎符合要点,但并不那么好。让我们将这个结果与成熟的线性回归模型(如 sklearn 模型)产生的结果进行比较。

x = x.reshape(-1,1)
y = y.reshape(-1,1)from sklearn.linear_model import LinearRegressionreg_model = LinearRegression().fit(x, y)y_pred = reg_model.predict(x)plt.figure(figsize = (12, 10))plt.plot(x, y_pred, label = ‘Predicted’)
plt.scatter(x, y, label = ‘Actual’)plt.show()

sklearn 回归器生成的直线似乎完全符合这些点。让我们看看 a 和 b 的值是多少。

reg_model.intercept_>> array([1.23636364])reg_model.coef_>> array([[1.16969697]])

接近但不相同。显然,他们采取了不同的路线来最小化他们的 mse,并以不同的值结束。

让我们用一组不同的 x 和 y 再试一次。

x = np.linspace(-1, 1, 101)
y = 4 * x + np.random.randn(101) * 0.44
print (x.shape , y.shape)>> (101,) (101,)

我们现在的初始 mse 是 5.79788117428826。让我们再运行一次同样的代码,看看我们得到的 a 和 b 的值是多少,在我们的探索中得到这个 5.7 到 0。

while mse > 0:

  a = a+0.01
  b = b+0.01
  y_ = a * x + b

  if np.mean((y — y_)**2) < mse :
   mse = np.mean((y — y_)**2)

  else :
   print (a,b,mse)
   break>>>1.0300000000000007 1.0300000000000007 4.4175244648874

很明显,我们选择的路线是条死胡同。当我们尝试将 a 和 b 都增加 0.01 时,我们的 mse 停留在 4.4,离 0 很远。没关系,让我们试试不同的路线。

while mse > 0:

 a=a+0.1
 b=b-0.01
 y_ = a * x + b

 if np.mean((y — y_)**2) < mse :
 mse = np.mean((y — y_)**2)

 else :
 print (a,b,mse)
 break>> 4.000000000000002 -0.4000000000000002 0.34416766289398254

那似乎更好。让我们试着画出来,看看这条线有多吻合。

再次,接近,但可以更好。很明显,需要改变的是我们上下遍历数轴寻找 a 和 b 的正确值的方式,但是我们如何知道是减少还是增加,如果是,增加多少?有一百万条不同的路径可供我们选择,但没有一条路径适用于每一个数据集。

这个问题的答案是梯度下降。我们通过在损失负梯度的最陡下降方向上迭代行进来最小化损失。

称为学习率的模型超参数决定步长。学习率 x 梯度给出了我们更新 a 和 b 的值。我们将在以后的帖子中更深入地研究梯度下降算法。

了解逻辑回归系数

原文:https://towardsdatascience.com/understanding-logistic-regression-coefficients-7a719ebebd35?source=collection_archive---------1-----------------------

Photo by Franki Chamaki on Unsplash

或者更好地从证据的角度思考概率

逻辑回归有一个共同的缺点:系数很难解释。如果你符合逻辑回归模型,你可能会说“如果变量 X 增加 1,那么因变量发生的概率增加???"但是“???"有点难以填写。

诀窍在于将“概率”一词改为“证据”在这篇文章中,我们将了解如何量化证据。利用这一点,我们将讨论如何解释逻辑回归系数

最后,我们将在此背景下简要讨论多类逻辑回归,并将其与信息论联系起来。

这篇文章假设你有解释线性回归系数的经验,并且之前至少看过一次逻辑回归

第 1 部分:思考概率的另外两种方式

几率和证据

我们习惯于把概率想成 0 到 1 之间的数字(或者等价地,0 到 100%)。但这只是“似是而非程度”的一种特殊数学表示

还有你所熟悉的第二种“似是而非程度”的表示法:优势比。比如我告诉你“一个观测被正确分类的几率是 2:1”,你可以查一下正确分类的概率是三分之二。同样,“偶数”的意思是 50%。

我的目标是说服你采用第三种方法:对数赔率,或赔率的对数。为了解释,我们将把对数几率称为证据。这是继 E.T. 杰恩斯2003 年的巨著概率论:科学的逻辑之后。

一般来说,使用数学表示法时有两个考虑因素。首先,它应该是可解释的。第二,数学性质要方便。

解释证据:哈特利的测量

为了让你相信证据是可以解释的,我会给你一些数字来校准你的直觉。

首先,证据可以用许多不同的单位来衡量。我们先从一个开始,哈特利号。哈特利有很多名字:艾伦·图灵称它为“ban ”,是以 T2 布莱切利公园附近的一个城镇的名字命名的,二战期间,英国人在这里破译了纳粹的通讯。它也被称为“dit”,是“十进制数字”的缩写

寻找哈特利事件中概率为 p 的证据的公式非常简单:

Computing the evidence, in Hartleys

其中几率为 p/(1-p)。这一点用下面的表格来解释要容易得多。请注意,为了使概率看起来更好,已经明智地使用了舍入。通过这种仔细的舍入,很明显 1 哈特利大约是“19

Table of Evidence, Odds, and Probability

请注意,1 哈特利是一个事件相当多的证据。一个更有用的度量单位可能是十分之一哈特利。一个“德西-哈特利”听起来很可怕,所以更常见的名字是“德西班”或分贝。这是另一个表格,这样你就可以了解一个决策的信息量。希望你能看到这是一个衡量证据的合适尺度:不太大也不太小。

使用证据:贝叶斯法则

我也说过证据应该有方便的数学性质。事实证明,证据自然出现在贝叶斯统计中。

假设我们希望将一个观察结果分为真或假。我们可以写:

Bayes’ Law for Binary Classification

在贝叶斯统计中,每个等式的左侧被称为“后验概率”,是在看到数据后分配的概率。右手边的 P(真)和 P(假)分别是我们在看到数据之前的“先验概率”。我们认为这些概率是信念的状态,贝叶斯法则告诉我们如何从信念的前一状态进入后一状态。如果你不喜欢花哨的拉丁词,你也可以称之为“信念”。

更多关于我们先前的信仰状态。这里的标准方法是计算每个概率。这可能是你曾经被迫做的一件苦差事。巧妙的方法是从考虑几率开始。如果我们把前面的两个等式分开,我们得到一个“后验概率”的等式

The Posterior Odds

然后我们将考虑证据,我们将把它记为 Ev。因此 Ev(True)是真实分类的先验(“之前”)证据。而 Ev(True|Data)是后验(“after”)。我们以哈特利为单位,取 10 为基数的对数:

The Data Science process, quantified

在二元分类的背景下,这告诉我们,我们可以将数据科学过程解释为:收集数据,然后对你已经拥有的假设证据进行加减。通过量化证据,我们可以使这相当字面:你增加或减少数量!

其他单位系统

衡量证据有三种常见的单位约定。我们见过一个,它使用 Hartley/bans/dits(或 decibans 等。).当我们取以 10 为底的对数时,就出现了这种单位的选择。

下一个单元是“ nat ”,有时也被称为“nit”简单的取以 e. 为底的对数就可以算出来,回想一下 e ≈2.718 就是欧拉数

最后一个常见单位是“位”,通过以 2 为底的对数来计算。它有时也被称为香农,以信息论的传奇贡献者克劳德·香农命名。

在计算机发明之前,哈特利是最常用的证据和信息单位,因为它比其他两个更容易计算。(注意,信息与证据略有不同;更多见下文。)

随着计算机的出现,转向比特是有意义的,因为信息理论通常涉及在使用物理比特的计算机上传输和存储信息。

最后,根据数学家的说法,自然对数是最“自然”的。因此,这是许多软件包的默认选择。在物理学中也很常见。

我相信,我也鼓励你相信:

  • Hartley 或 deciban(基数为 10)是最容易解释的,应该由对量化证据感兴趣的数据科学家使用。
  • 对量化信息感兴趣的计算机科学家应该使用这种比特。
  • 物理学家应该使用 nat,例如计算物理系统的熵。

请注意,对于数据科学家来说,这涉及到从默认选项(nat)转换模型输出。

最后,这里有一个单位换算表。我凭经验发现,许多人知道他们头顶上的第一行。0.69 是 72 的法则的基础,常见于金融学。3.01 ≈ 3.0 是很多电气工程师都熟知的(“3 分贝是功率的两倍”)。

Unit Conversion Table for Evidence

将证据转化为赔率和概率

刚刚说了我们应该用 decibans 代替 nats,我将在 nats 中做这一部分,这样如果你以前见过它们,你就能认出它们。让我们将证据(在 nats 中)表示为 S 。公式是:

Formula for the Evidence S in nats

假设真的证据是 s,那么几率和概率可以计算如下:

Converting evidence S to odds or a probability

如果最后两个公式看起来令人困惑,只要计算出你的马赢的概率,如果赔率是 2:3。首先将 2 和 3 相加,然后将 2 除以它们的和。

第 2 部分:理解逻辑回归

如果你相信我,证据是思考问题的好方法,那么希望你开始看到一个解释逻辑回归的非常清晰的方法。首先,记住逻辑 s 形函数:

希望你看到的不是复杂混乱的符号,而是将信息转化为概率的函数。和上面的一模一样!

让我们把因变量看作一个 0/1 值的指标。所以在上面的语言中 0 =假,1 =真。逻辑回归模型是

其中 X 是观测值的向量(包括常数),β是系数的向量,σ是上面的 sigmoid 函数。

这直接告诉我们,我们可以将一个系数解释为相关预测因子的每次变化所提供的证据量。

例如,假设我们正在为在线视频分类“会不会火起来”,我们的预测指标之一是视频中有一只猫(“猫”)的时长。

  • 如果这个“猫”变量的系数达到 3.7,这告诉我们,猫的存在每增加一分钟,我们就有 3.7 个国家(16.1 分位数)的证据证明视频会像病毒一样传播。
  • 将来自所有预测者的所有证据(以及先前的证据——见下文)相加,你会得到一个总分。
  • 如果总证据为正,则分类为“真”或 1,如果总证据为负,则分类为“假”或 0。但更关键的是,看看你有多少证据就知道了!

混合物

我选择了几个不深入探讨的要点。

The logit function is the inverse of the logistic function

  1. 逻辑 sigmoid 函数的逆函数是上面给出的 logit,。许多作者用 logit 来定义逻辑回归。逻辑函数将证据转换为概率,它的逆函数将概率转换为证据。
    此外,像往常一样,数学是以纳特为单位的,但是如果你想要不同的单位,你当然可以自由地使用不同的对数基数。
  2. 没什么可怕的。默认情况下,您选择了“无论如何都没有证据”的优先选项,换句话说,0 个证据。希望这看起来合理。改变你的先验就相当于改变了分类的门槛。这是一个思考如何构建 ROC 曲线的好方法。
  3. 你可以检查一下交叉熵损失(也称为对数损失或偏差)可以描述如下。让模型给出支持错误预测的证据。然后,在限制为 S 较大时,损失为 S 。反之,如果 S 是给出的有利于正确预测的证据,那么,在 S 较大的限度内,交叉熵损失为 exp(-S)

第 3 部分:多类逻辑回归

考虑到上面的讨论,在多类的情况下,直观的做法是量化有利于每个类的信息,然后(a) 分类到具有最多有利信息的类;和/或(b) 预测每个类别的概率,使得任意两个类别之间的对数优势比是它们之间的证据差异。

我们可以通过 softmax 函数来实现(b)。在总共 n 个类别中观察到类别 k 的概率是:

Softmax: Probability of observing class k out of n possibilities given the information in favor of each

将其中的任意两个(比如 k 和ℓ)相除,可以得到合适的对数概率。

我们如何估计有利于每一类的信息?有两种明显的选择:

  1. (多项式)注意,从数学上来说,将整个信息列表向有利于每一类的方向移动一定数量的哈特利不会改变概率分布。这是因为我们只关心类之间的信息差异。因此,我们不妨选择一个类,比如⭑类,并将其信息设置为 0。然后估计每个其他类相对于⭑.类的证据
  2. (一对其余)对于每个类别,比如类别 k,运行简单的逻辑回归(二元分类)以确定“是否是观察类别 k。”

在 n = 2 的情况下,方法 1 最明显地再现了上面的逻辑 sigmoid 函数。方法 2 也证明是等价的。

警告:对于 n > 2,这些方法是 不一样的 。(好消息是,在选项 1 中选择⭑类别不会改变回归的结果。)

我不打算在这里深入讨论这个问题,因为我没有太多好的参考资料。如果你想阅读更多,可以考虑从 scikit-learn 文档开始(其中也谈到了 1v1 多类分类)。如果你有/找到一个好的推荐人,请告诉我!这里的重点更多的是看证据视角如何延伸到多类案件。

第四部分:信息论

这将是非常简短的,但我想指出这是如何符合经典信息论的。信息论开始于研究写下一条信息需要多少位以及发送信息的特性。1948 年,Claude Shannon 能够推导出发生概率为 p 的事件的信息(或熵或惊奇)是:

给定概率分布,我们可以计算每个样本的预期信息量,并获得熵 S:

这里我选择了省略对数的底数,它设置了单位(以位、NAT 或 ban 为单位)。物理上,信息是这样实现的,即不可能无损压缩低于其信息内容的消息。

这种联系对我们来说有些松散,但是在二进制的情况下,真的证据是

负号是非常必要的,因为在信号分析中,总是发生的事情没有惊奇或信息内容;对我们来说,总是发生的事情有相当多的证据。

结论

信息是不确定性的解决方案 ——克劳德·香农

概率是大多数人类共有的共同语言,也是最容易交流的语言。但是它并不是对每种情况都是最好的。在这篇文章中:

  • 我们看到计算证据很简单:你只需添加它;
  • 我们校准了你对“大量”证据(10-20+分贝)、“一些”证据(3-9 分贝)或“不多”证据(0-3 分贝)的感觉;
  • 我们看到了在解释逻辑回归系数和贝叶斯语境中证据是如何自然产生的;和
  • 我们看到了它是如何引导我们正确考虑多类情况的

我希望你能养成习惯,把你的系数转换成分贝/分位数,并根据证据而不是概率来思考。

拉维

参考/建议

我强烈推荐上面提到的 E.T. Jaynes 的

就背景而言,E.T. Jaynes 就是你所谓的激进贝叶斯理论。

  • 我在这里提出的“证据”的观点可归因于他,正如所讨论的,在贝叶斯语境中自然产生。
  • 这本书的另一大特点是它派生了(!!)概率法则来自于对“似真程度”的定性考虑我发现这在哲学上很有趣。

还有:如果你不想要硬拷贝,谷歌上似乎有很多这本书的 pdf 文件。

逐步理解逻辑回归

原文:https://towardsdatascience.com/understanding-logistic-regression-step-by-step-704a78be7e0a?source=collection_archive---------4-----------------------

训练逻辑回归分类器,根据人们的体重和身高预测他们的性别。

逻辑回归是一种流行的用于二元分类的统计模型,即用于类型这个或那个是或否A 或 B 等的预测。然而,逻辑回归可用于多类分类,但这里我们将集中讨论其最简单的应用。

作为一个例子,考虑根据某人的体重身高预测其性别(男/女)的任务。

为此,我们将从一万个人的体重和身高样本的数据集训练一个机器学习模型。数据集取自Conway&Myles Machine Learning for Hackers 一书第二章,可以直接下载这里

这是数据的预览:

每个样本包含三列:身高体重男性

  • 高度英寸
  • 以磅为单位的重量
  • 男性: 1 表示测量对应男性,0 表示测量对应女性。

有 5000 个来自男性的样本,5000 个来自女性的样本,因此数据集是平衡的,我们可以继续进行训练。

Python 的 scikit-learn 代码训练逻辑回归分类器并做出预测非常简单:

一般的工作流程是:

  1. 获取数据集
  2. 训练分类器
  3. 使用这种分类器进行预测

逻辑回归假设

逻辑回归分类器可以通过类比 线性回归假设 得出,即:

Linear regression hypothesis.

然而,逻辑回归假设从线性回归假设中概括出,因为它使用了 逻辑函数 :

结果是逻辑回归假设:

Logistic regression hypothesis.

函数 g(z)逻辑函数,也称为s 形函数

逻辑函数在 0 和 1 处有渐近线,它在 0.5 处穿过 y 轴。

Logistic function.

逻辑回归决策边界

由于我们的数据集有两个特征:身高和体重,逻辑回归假设如下:

逻辑回归分类器将预测“男性”,如果:

这是因为逻辑回归“阈值”被设置为 g(z)=0.5,请参见上面的逻辑回归函数图进行验证。

对于我们的数据集,θ值为:

要获得 scikit-learn 计算的θ参数,可以:

**# For theta_0:**print( fitted_model.intercept_ )**# For theta_1 and theta_2:**print( fitted_model.coef_ )

有了这些系数,一个手动预测(也就是说,不使用函数 clf.predict() )将只需要计算向量积

并检查结果标量是否大于或等于零(预测男性),否则(预测女性)。

为例,假设我们想要预测某个身高= 70 英寸体重= 180 磅 的人的性别,就像上面脚本 LogisticRegression.py 的第 14 行一样,我们可以简单地做:

Making a prediction using the Logistic Regression parameter θ.

由于乘积的结果大于零,分类器将预测男性。

这里可以看到 决策边界 和完整数据集的可视化:

正如你所看到的,在决策边界的上方是大多数对应于男性类别的蓝色点,在它的下方是所有对应于女性类别粉色点。

此外,只看数据你就能知道预测不会完美。这可以通过包括更多的特征(除了体重和身高)以及潜在地使用不同的判定边界来改进。

逻辑回归决策边界也可以是非线性函数,例如高次多项式。

计算逻辑回归参数

scikit-learn 库在抽象逻辑回归参数θ的计算方面做得很好,它是通过解决一个优化问题来完成的。

我们先来定义两个兴趣点的逻辑回归代价函数:y=1,y=0,也就是假设函数预测男性或女性的时候。

然后,我们在这两项的 y 中取一个凸组合,得出逻辑回归成本函数:

Logistic regression cost function.

逻辑回归成本函数是凸的。因此,为了计算θ,需要解决以下(无约束)优化问题:

有多种方法可用于解决这种无约束优化问题,例如一阶方法 梯度下降 需要逻辑回归成本函数的梯度,或者二阶方法例如 牛顿法 需要逻辑回归成本函数的梯度和 Hessian 这是上述 scikit-learn 脚本中规定的方法。

对于梯度下降的情况,搜索方向是逻辑回归成本函数相对于参数θ的负偏导数:

Partial derivative of the logistic regression cost function.

在其最基本的形式中,梯度下降将沿着θ的负梯度方向迭代(称为最小化序列),直到达到收敛。

Prototype of gradient descent.

注意,常数α通常被称为学习速率搜索步骤,它必须被仔细调整以达到收敛。算法如 回溯线搜索 辅助确定α。

总之,这是您下次使用或实现逻辑回归分类器时应该记住的三个基本概念:

1.逻辑回归假设

2.逻辑回归决策边界

3.逻辑回归成本函数

对于应用于具有更多特征的数据集的逻辑回归分类器的讨论(也使用 Python ),我推荐 Susan Li 的这篇中期文章

参考资料和进一步阅读:

我是劳伦斯·伯克利国家实验室的博士后研究员,我在机器学习和高性能计算的交叉领域工作。

如果你觉得这篇文章很有意思,可以随意在LinkedIn打个招呼,我总是很乐意与该领域的其他专业人士联系。

一如既往:欢迎评论、提问和分享!❤️

No Spam, ever.

理解逻辑回归

原文:https://towardsdatascience.com/understanding-logistic-regression-using-a-simple-example-163de52ea900?source=collection_archive---------2-----------------------

通过简单的端到端示例建立直觉

如果你有兴趣运行我在这个分析中使用的代码,请查看我的 GitHub

逻辑回归是进行分类的基本工具之一。作为一名未来的数据科学家,我希望做大量的分类工作。所以我想我更好地理解了逻辑回归在更深层次上的作用(不仅仅是来自 sklearn . linear _ model import logistic regression)。

下面的例子从头到尾介绍了一个非常基本的逻辑回归,这样我(希望你,读者)可以对它的工作原理有更多的直觉。

投篮篮

比方说,我想检查我的篮球投篮准确性和我投篮距离之间的关系。更确切地说,我想要一个模型,它以英尺为单位计算“离篮筐的距离”,并计算出我投篮的概率。

首先我需要一些数据。所以我出去从各种距离投篮,同时记录每个结果(1 表示成功,0 表示失败)。在散点图上绘制时,结果如下所示:

一般来说,我离篮筐越远,投篮就越不准。因此,我们已经可以看到我们的模型的大致轮廓:当给定一个小距离时,它应该预测高概率,当给定一个大距离时,它应该预测低概率。

在高层次上,逻辑回归的工作方式很像传统的线性回归。因此,让我们从熟悉的线性回归方程开始:

Y = B0 + B1X*

在线性回归中,输出 Y 与目标变量(您试图预测的事物)的单位相同。然而,在逻辑回归中,输出 Y 是对数概率。除非你花很多时间在体育博彩或赌场上,否则你可能对赔率不太熟悉。赔率只是事件发生概率的另一种表达方式, P(事件)

赔率= P(事件)/【1-P(事件)】

继续我们的篮球主题,假设我投了 100 个罚球,投进了 70 个。基于这个样本,我罚球的概率是 70%。我罚球的几率可以计算为:

赔率= 0.70/(1–0.70)= 2.333

因此,如果他们基本上告诉我们同样的事情,为什么麻烦呢?概率被限制在 0 和 1 之间,这成为回归分析中的一个问题。如下图所示,赔率范围从 0 到无穷大。

如果我们取概率的自然对数,那么我们得到的对数概率是无界的(范围从负到正无穷大),并且在大多数概率上大致是线性的!由于我们可以通过逻辑回归估计对数概率,我们也可以估计概率,因为对数概率只是概率的另一种表述方式。

Notice that the middle section of the plot is linear

我们可以写出我们的逻辑回归方程:

z = B0+B1 *距离篮子

其中 Z = log(投篮命中率)

为了从对数赔率中的 Z、 得到概率,我们应用了 sigmoid 函数。应用 sigmoid 函数是描述以下转换的一种奇特方式:

投篮命中率= 1/[1+e^(-z]

既然我们已经了解了如何从对数赔率的线性估计到概率,那么让我们检查一下系数 B0B1 在我们用来计算 Z 的逻辑回归方程中是如何实际估计的。这里有一些在幕后进行的数学计算,但是我将尽我所能用简单的英语解释它,这样你(和我)都可以对这个模型有一个直观的理解。

成本函数

像大多数统计模型一样,逻辑回归寻求最小化成本函数。所以我们先来思考一下什么是成本函数。成本函数试图衡量你的错误程度。因此,如果我的预测是正确的,那么应该没有成本,如果我只是有一点点错误,应该有一个小成本,如果我是严重错误,应该有一个高成本。这在线性回归世界中很容易想象,因为我们有一个连续的目标变量(我们可以简单地将实际结果和我们的预测之间的差平方,以计算每个预测对成本的贡献)。但是这里我们处理的是一个只包含 0 和 1 的目标变量。不要绝望,我们可以做一些非常类似的事情。

在我的篮球例子中,我从篮筐的正下方第一次投篮——也就是 【投篮结果= 1 |距离篮筐= 0】。耶,我篮球打得并不差。我们如何将此转化为成本?

  • 首先我的模型需要给出一个概率。假设它估计值为 0.95,这意味着它预计我 95%的投篮都是从 0 英尺外命中的。
  • 在实际数据中,我只从 0 英尺处拍摄了一次,所以我从 0 英尺处拍摄的实际(采样)精度是 100%。带上那个愚蠢的模特!
  • 所以这个模型是错误的,因为根据我们的数据,答案是 100%,但它预测的是 95%。但是这只是一个小小的错误,所以我们只想罚一点点。这种情况下的惩罚是 0.0513(见下面的计算)。请注意,它与实际概率和预测的差值有多接近。还有,我要强调的是,这个误差不同于分类误差。假设默认截止值为 50%,该模型将正确预测 1(因为其预测值为 95% > 50%)。但是这个模型不能 100%确定我会成功,所以我们对它的不确定性进行了一点惩罚。

-log(0.95) = 0.0513

  • 现在让我们假设我们建立了一个蹩脚的模型,它吐出的概率是 0.05。在这种情况下,我们大错特错,我们的代价是:

-log(0.05) = 2.996

  • 这个成本要高很多。模型非常确定我会错过,这是错误的,所以我们要强烈惩罚它;我们之所以能够做到这一点,要感谢我们采用了天然原木。

下面的曲线图显示了成本与我们的预测之间的关系(第一个曲线图描绘了当 实际结果=1 时,成本相对于我们的预测如何变化,第二个曲线图显示了当 A 实际结果= 0 时,成本如何变化)。

因此,对于给定的观察,我们可以将成本计算为:

  • 如果 实际结果= 1 ,那么 成本= -log(pred_prob)
  • 否则如果 实际结果= 0 ,那么 成本= -log(1-pred_prob)
  • 其中 pred_prob 是跳出我们模型的预测概率。

对于我们的整个数据集,我们可以通过下式计算出 总成本 :

  1. 使用上述程序计算每个观察的个体成本。
  2. 将所有单项成本相加得到 总成本

这个 总成本 是我们想要最小化的数字,我们可以通过梯度下降优化来实现。换句话说,我们可以运行优化来找到最小化总成本B0B1 的值。一旦我们搞清楚了这一点,我们就有了我们的模型。激动人心!

把这一切联系在一起

综上所述,首先我们用最优化来搜索使我们的代价函数最小的 B0B1 的值。这给了我们一个模型:

Z = B0 + B1X*

其中 B0 = 2.5,B1 = -0.2(通过优化确定)

我们可以看一下我们的斜率, B1 ,它衡量的是距离对我射击精度的影响。我们估计B1T7 为-0.2。这意味着距离每增加 1 英尺,我投篮的几率就会减少 0.2。 B0 ,y 轴截距,值为 2.5。这是我从 0 英尺(就在篮筐旁边)投篮时,模型的对数赔率预测。通过 sigmoid 函数我们得到了 92.4%的预测概率。在下面的图中,绿点描绘了 Z ,我们预测的对数几率。

Almost there!

我们快完成了!由于 Z 是对数赔率,我们需要使用 sigmoid 函数将其转换成概率:

投篮命中率= 1/[1+e^(-z]

投中概率, 我们所追求的最终输出在下图中用橙色的点来描绘。注意曲率。这意味着我的特征(距离)和我的目标之间的关系不是线性的。在概率空间中(不像对数赔率或线性回归),我们不能说我投篮的距离和我投篮的概率之间有恒定的关系。相反,距离对概率的影响(连接橙色点的线的斜率)本身就是我目前站在离篮子多远的函数。

Nice! We have our probabilities now

希望这有助于你更好地理解逻辑回归(写它肯定帮助了我)。

如果你总体上喜欢这篇文章和我的写作,请考虑通过我的推荐链接注册 Medium 来支持我的写作。谢谢!

通过 PointNet++理解点云上的机器学习

原文:https://towardsdatascience.com/understanding-machine-learning-on-point-clouds-through-pointnet-f8f3f2d53cc3?source=collection_archive---------3-----------------------

介绍

数据可以采用多种形式。对于处理视觉信息,图像是非常常见的。图像存储二维像素网格,通常代表我们的三维世界。机器学习中一些最成功的进步来自涉及图像的问题。然而,对于直接在 3D 中捕获数据,具有表示整个体积的三维像素阵列是不常见的。

在 3D 中检索空间数据的最简单且最具成本效益的方法之一是通过点云。令人惊讶的是,针对点云的机器学习工作做得并不多,大多数人对这个概念并不熟悉。

在本文中,我将:

  1. 定义点云及其所在的空间。
  2. 了解机器学习中涉及点云的问题。
  3. 打开一篇关于点云机器学习的开创性研究论文——point net++。

什么是点云?

顾名思义,点云是空间中数据点的集合。收集 3D 数据的一种流行方式是通过扫描仪,扫描仪通过一系列坐标检测物体的表面。将信息存储为空间坐标的集合可以节省空间,因为许多对象不会占据很多环境。

An image and a 3D point cloud representation detected by a scanner.

然而,点云并不局限于 3D。任何高维物体的集合都可以被认为是点云。即使信息本质上不是可视的,将数据解释为点云也有助于理解多个变量之间的关系。

本质上,点云只是一个数学集合的花哨名称,它是一个无序的对象集合。通常,我们认为这些物体是空间中一堆孤立的点,松散地描述了一些固体结构或表面,但这只是直觉。只要我们有计算两点间距离的方法,这就够了。带有距离概念的空间被称为度量空间,这是点云最通用的设置之一。

点云上的机器学习

动机

The types of problems we’d like to solve on point clouds.

首先,我们想在点云上执行哪些任务?在点云上做机器学习常见的有两大类问题:分类分割

分类提问:这是什么类型的物体?目标是用一个标签对整个点云进行分类。可以有两个标签(即这是猫的数据还是狗的数据?)或多个(即,这是汽车、飞机、船还是自行车的数据?).

分割提问:你能把这个物体分割成可分辨的部分吗?如果我们有一个描述自行车的点云,也许我们想分离车轮、把手和座位(零件分割)。分割还用于处理描述整个环境而不是单个对象的复杂点云。例如,我们可能有一个描述交通路口的点云,并希望区分每辆车、人和交通灯(语义分段)。

如何解决它们?

与其他视觉问题不同,我们不能只是在这个问题上扔一个像卷积神经网络这样的东西。记住:点云没有固定的结构,所以我们不能简单地应用典型的工具来处理图像。

基本思想是这样的:我们有一个度量,它告诉我们点与点之间的距离。这使得我们可以将彼此靠近的点组合在一起,放入小口袋中,然后压缩成一个点。我们可以重复应用这一原理来总结几何信息,并最终标记整个点云。

PointNet++:点云上的深度学习

PointNet++是在点云上应用机器学习的开创性工作。该架构由多个组件组成,这些组件聚合本地信息并将其传递给下一步。

由于点云是无序的,聚合步骤不能依赖于输入的顺序。机器学习算法怎么可能不依赖于其输入的顺序?

这里有一个原则,不管数据类型或问题类型如何,都有帮助:机器学习的本质问题是函数逼近。寻找一个输入不变的函数听起来令人生畏,所以你能想到任何简单的吗,即使是一个只接受三个数字的函数 f(x,y,z) ?这样的函数叫做对称函数。

以下是一些常见的对称函数:

f(x,y,z)= XYZ f(x,y,z) = x + y + z
f(x,y,z) = max (x,y,z)

PointNet++中的组件实际上利用了最后一个函数!对于每一小组点,经过几次初始变换后,会有一个组合所有内容的最大值运算。

PointNet++的架构

The architecture for PointNet++, broken up into multiple stages.

PointNet++的架构有许多阶段,但是每个部分都有明确的目标。从整个点云开始,点被分组为一些簇,并浓缩为携带新信息的单个点。除了它的 d 空间坐标,每个点还携带 C 条信息。

这个过程继续进行,获取新的点并将它们分组到更多的簇中。根据问题的不同,这个过程会反向进行,并尝试重建原始结构。特别是当我们想要对每个原始点进行分类时,网络有一系列从一个点到一组的插值步骤。这些步骤都依赖于利用距离函数。插值步骤使用反距离加权平均值,定义如下。

Inverse distance weighted average for interpolation (quite a mouthful).

这里 f(x) 是坐标 x 处的插值, C 是类的数量, k 是使用的邻居数量(如k-最近邻居)。

结果:PointNet++做的怎么样?

PointNet++构建了同一个组的前一个迭代,称为 PointNet。对于语义分割的任务,显示了扫描厨房的结果。

PointNet is the original model, and PointNet++ is the new one (“Ours”).

除了房间布局之外,还标识了椅子、门和桌子等单独的对象。对于空间识别的任务,PointNet++是一个很好的基线。

结论

点云可以有效地描述各种情况下的空间数据集。其中一篇开创性的论文 PointNet++演示了复杂环境下的点云可以解决语义分割问题。许多较新的论文旨在将这些原则应用于更具体的问题,例如为医学成像分割血管中的分支。

如果你想了解更多关于这篇文章的内容,在下一节中有描述这项工作的网站链接。

感谢阅读!我很有兴趣听到其他关于机器学习的点云论文,这是一个相对未探索的话题。随时添加任何问题或评论,我真的很喜欢阅读你的想法!

参考

[1] Qi,Charles R 和 Su,Hao 和 Mo,Kaichun 和 Guibas,Leonidas J. PointNet:用于 3D 分类和分割的点集的深度学习。arXiv 预印本 arXiv:1612.00593,2016。

http://stanford.edu/~rqi/pointnet/

[2]齐,易,李,苏,郝,吉巴斯,J. PointNet++:度量空间点集的深度层次特征学习.arXiv 预印本 arXiv:1706.02413,2017。

http://stanford.edu/~rqi/pointnet2/

理解马尔可夫决策过程

原文:https://towardsdatascience.com/understanding-markov-decision-processes-b5862c192ddb?source=collection_archive---------11-----------------------

从高层次的直觉来看,马尔可夫决策过程(MDP)是一种数学模型,对于机器学习,特别是强化学习非常有用。该模型允许机器和代理确定特定环境内的理想行为,以便最大化模型在环境中实现某个状态甚至多个状态的能力,这取决于您想要实现什么。这个目标是由我们称之为策略的东西决定的,这个策略根据环境应用于代理的行为,MDP 试图优化实现这样一个解决方案所采取的步骤。这种优化是通过奖励反馈系统来完成的,其中不同的行为根据这些行为将导致的预测状态来加权。

分解它

为了理解 MDP,我们应该首先看看这个过程的独特组成部分。它包含:

  • 存在于我们指定环境中的一组状态:S
  • 在我们指定的环境中,一个或多个代理可以执行的一组可能的操作
  • 每个动作对当前状态的影响的描述
  • 给定期望的状态和动作,给出回报的函数:R(s,a)。
  • 寻求解决 MDP 问题的政策。你可以把它看作是从状态到我们行为的映射。用更简单的术语来说,它表示在状态 s 时要采取的最佳行动 a。

Image overview of MDP

了解模型:

从上图可以看出,我们有 T(S,a,S') ~ P(S'|S,a)。

该模型通常被称为过渡模型。如果你把事情分解开来,理解起来就变得简单了。t 代表了我们行为的概念化。我们从某个状态 S 开始,我们采取行动 a,我们的代理发现自己处于一个新的状态 S’。(这里不要让我的措辞把你搞糊涂了。我们采取的行动完全有可能会让代理处于同样的状态。)

接下来,我们定义 P,或者我们在先前状态下采取行动达到新状态的概率。

让我们看看数学:马尔可夫性质

p[St+1|a, S0 ,…..、St**=P[St+1**| a、 S** t

上面的公式是马尔可夫属性状态的定义。还是那句话,我们来分解一下。

St+1 可以解释为未来的状态,或者我们打算走向的状态和[ S 1 ,…..,St]表示状态历史中存在的所有相关信息的历史。当然,a 仍然代表正在采取的行动。但是,新状态仅依赖于以前的状态。它不依赖于各国过去的历史。

给定马尔可夫状态,定义转移概率。

假设我们的代理处于某个状态 s,有一个概率进入第一个状态,另一个概率进入第二个状态,以此类推,对于每个现有的状态。这是我们的转移概率。

我们可以把这些概率输入一个状态矩阵!让我们定义一个三态天气问题的例子。这是规则

  1. 你住在桑尼镇,但可悲的是,桑尼从来没有连续两天的好天气。永远不会。
  2. 如果你有一个好天气,第二天很可能会下雪或下雨。
  3. 如果下雪或下雨,第二天有 50%的可能会有同样的天气。
  4. 如果天气由下雪或下雨转变,也只会有一半时间转变为晴天。

使用这个假的环境信息,我们可以构建一个状态矩阵,如下所示:

其中矩阵的第一行表示给定雨天的下几天天气的概率。第二行代表正常天气的概率,第三行,正如你可能已经理解的,代表下雪天的概率。这个转移概率矩阵被称为转移矩阵。

现在,让我们从我们的矩阵中尝试一个真实问题的模型,其中 p (ij)。
设 I 代表当前状态,j 代表未来状态。

我们想知道今天下雨的可能性有多大,两天后下雪的可能性有多大?假设正在下雨,我们可能的状态是什么?

唯一的限制是不能连续两天天气都很好。从现在到那时的所有其他状态都是可能的。所以可能明天下雨,第二天下雪,可能明天天气好,第二天下雪,也可能明天下雪,第二天下雪。

用方程式表示:

P (Rain⁰Snow ) = P(下雨)P(下雨+下雪)+ P(正常下雨)P(正常下雪)+ P(下雨+下雪)*P(下雪)

现在我意识到这看起来很伤人,但是你可能已经意识到这本质上是向量和矩阵数学。我们取第 1 行和第 3 行的点积。

视觉化让生活更简单

假设我们希望预测给定 6 天时间周期或 6 个状态转换的 P。我们没有一开始就定义一个单一的状态,我们只是希望在给定初始概率的情况下,找到我们的状态在一个过渡时期的概率。这就是所谓的正规马尔可夫链。如你所见,我们继续使用矢量数学,通过点积来计算每个州的概率。

好的,但是我们如何确定初始状态呢?它将如何影响我们对概率的计算,或者我如何创建马尔可夫链:

我很高兴你问了!我们可以这样定义:u^(n) = uP^(n)

其中 u 是表示初始状态分布的向量,P 是马尔可夫链的转移矩阵。

我们知道我们有三个状态,所以让我们把它代入。u =向上

让我们求解第三天的概率。我们制作一个 1×3 的向量来表示初始分布,并取点积来找出给定一个随机起始状态的第三天每个状态的可能性。

太好了。对于一个期望的结果,我如何找到这么多状态的最优解?这就是我想在这里使用强化学习的原因。

为了理解如何计算我们的状态和动作的最优化,我们需要给它们赋值。为了理解价值,我们需要定义一个政策,为了定义一个政策,我们需要理解回报和回报。

奖励和回报值

强化代理寻求最大化未来报酬的总和。他们想预测能获得最大回报的行动。这被称为 返回 ,我们可以这样建模,R 代表奖励,R 代表返回,下标 t 代表时间步长,在我们的例子中是状态转换。

现在,正如你所看到的,这个等式允许你趋向于无穷大,但是对于处理很多问题来说,它没有意义。我们希望奖励的总和结束。我们把结束的任务称为情节性的。想一个大富翁棋盘游戏。这一集是垄断游戏,从给所有人分配相同的值开始,给定一系列可能的状态和行为,这一集最终以赢家结束。新的一集可以通过创建游戏的新实例开始。我承认垄断游戏有时会让人觉得它们会变得无穷无尽…

比较常见的处理返回值的方法是一种叫做未来累计 贴现 奖励的方法

其中奖励前面的折扣表示 0 到 1 之间的值。这种方法的好处是,回报现在可以更好地模拟无限奖励,并且它给予更直接的奖励更大的权重。该模型现在关心的是更快到来的回报,而不是未来的回报。这个我们可以自己掂量。我们选择的折扣越小,我们就越重视早期奖励。正如您可能想象的那样,折扣 1 成为我们最初的奖励等式,折扣 0 创建一个只关心第一个奖励的模型。这在某种意义上是有用的,因为代理人会知道在那个确切的时刻做什么是绝对最好的,但它对自己的未来缺乏任何洞察力。有点像婴儿对成人。嗯,有些成年人。婴儿只知道在那一刻他需要一件特定的东西,一个成年人可以计划并试图预测他的未来。

更多关于政策

π(s,a)是我们的策略函数。它描述了一种行为方式。它获取当前状态和代理动作,并返回在该状态下采取该动作的概率。有点像我们上面演示的,不是吗?

如果你想一想这意味着什么,所有状态的集合,给定所有动作,等于概率 1,这一定是真的。

我们的政策应该描述在每个州如何行动。

想想乔希·格里夫斯创造的这个政策

大家可以看到,我们吃饱了有奖励,饿了吃了有奖励,吃饱了不吃也有奖励。如果饥饿,我们会受到极其严重的惩罚;如果吃饱了,我们会受到惩罚;如果吃饱了,我们会受到惩罚;如果饿了,我们也会受到惩罚。很容易看出,在这个非常简单的例子中,最优策略是总是在饥饿时进食。

价值函数:

强化学习中的两类价值函数是状态价值函数 V(s)和动作价值函数 Q(s,a)。

状态值函数解释给定特定策略的状态值。当我们从初始状态 s 开始并在我们的政策规则范围内行动时,它是对回报的计算。

当遵循我们指定的策略时,action value 函数返回在给定状态下采取某个操作的值。

现在,假设当选择一个动作时,环境是返回下一个状态的东西,我们必须记住,如果我们的策略改变,那么价值函数也会改变。我们期望看到这些函数的一个给定的返回值,然而,在到达一个特定的状态时会有很大的随机性,转移函数也会影响我们的状态。我们可能没有 100%的概率!

给定环境,我们如何解释返回状态的随机性?

好吧,我们将在下一篇博文中讨论这个话题,但简而言之,我们可以使用贝尔曼方程。这些方程允许我们将状态的值表示为其他状态的值。意思是如果我们知道某个状态的值,我们可以用它来计算其他状态的值。

我们可以用这些方程,推导出状态值和动作值的贝尔曼方程,我保证我们下次会这么做,等我再研究一些:D 之后

直到那时!

来源:

达特茅斯概率正文:http://www . Dartmouth . edu/~ chance/teaching _ AIDS/books _ articles/probability _ book/book . html

麻省理工学院发表论文:【http://www.mit.edu/~jnt/Papers/J083-01-mar-MDP.pdf

理解最大似然估计

原文:https://towardsdatascience.com/understanding-maximum-likelihood-estimation-fa495a03017a?source=collection_archive---------12-----------------------

[## 想在数据科学方面变得更好吗?

当我在我发布独家帖子的媒体和个人网站上发布新内容时,请单击此处获得通知。](https://bobbywlindsey.ck.page/5dca5d4310)

假设您从某个发行版收集了一些数据。正如你可能知道的,每个分布只是一个有一些输入的函数。如果您改变这些输入的值,输出也会改变(如果您用不同的输入集绘制分布图,您可以清楚地看到这一点)。

碰巧您收集的数据是具有一组特定输入的分布的输出。最大似然估计(MLE)的目标是估计产生数据的输入值。有点像逆向工程你的数据是从哪里来的。

实际上,你并不真的对数据进行采样来估计参数,而是从理论上求解;分布的每个参数都有自己的函数,该函数是参数的估计值。

这是怎么做到的

首先,假设数据的分布。例如,如果您正在观看 YouTube 并跟踪哪些视频有 clickbaity 标题,哪些没有,您可能会假设二项分布。

接下来,来自这个分布的“样本”数据,你仍然不知道它的输入。请记住,您是在理论上解决这个问题,所以不需要实际获取数据,因为样本数据的值在下面的推导中并不重要。

现在问,得到你得到的样本的可能性有多大?这个可能性就是得到你的样本的概率。假设每个样本彼此独立,我们可以将似然函数定义为:

Likelihood function

现在您已经有了可能性函数,您希望找到使可能性最大化的分布参数值。这样思考这个问题可能会有帮助:

What you’re trying to do with MLE

如果你熟悉微积分,找到一个函数的最大值需要对它求微分,并使它等于零。如果你真的对函数的 log 求导,这会使求导更容易,你会得到相同的最大值。

一旦你区分了对数似然,就可以求解参数了。如果您正在查看伯努利、二项式或泊松分布,您将只有一个参数需要求解。高斯分布将有两个,等等…

YouTube 视图建模

假设你一年前创办了一个 YouTube 频道。到目前为止,你做得很好,并且收集了一些数据。你想知道在给定的一段时间内,至少有 x 个访问者访问你的频道的概率。分布中最明显的选择是泊松分布,它只依赖于一个参数λ,λ是每个区间出现的平均次数。我们想用最大似然估计来估计这个参数。

我们从泊松分布的似然函数开始:

Likelihood function for Poisson distribution

现在看看它的日志:

Log likelihood for Poisson distribution

然后求微分,把整件事设为 0:

Finding the maximum of the log likelihood for Poisson distribution

现在你有了一个λ的函数,只要插入你的数据,你就会得到一个实际值。然后,您可以将此λ值用作泊松分布的输入,以便对一段时间内的收视率进行建模。很酷吧。

最大化积极因素和最小化消极因素是一样的

现在从数学上来说,最大化对数似然和最小化负对数似然是一样的。我们可以通过类似上面的推导来说明这一点:

取负对数可能性:

Negative log likelihood for Poisson distribution

然后求微分,把整件事设为 0:

Finding the maximum of the negative log likelihood for Poisson distribution

现在,是最大化对数似然还是最小化负对数似然取决于你。但是通常你会发现对数似然的最大化更常见。

结论

现在你知道如何使用最大似然估计了!概括地说,您只需要:

  1. 求对数可能性
  2. 区分它
  3. 将结果设置为零
  4. 然后求解你的参数

原载于 2019 年 11 月 6 日【https://www.bobbywlindsey.com】

了解蒙特卡罗模拟

原文:https://towardsdatascience.com/understanding-monte-carlo-simulation-eceb4c9cad4?source=collection_archive---------5-----------------------

从头开始实施强大的统计工具

蒙特卡洛模拟是一种强有力的工具,可以在很难获得精确分布的情况下近似计算。当对随机变量(RV)应用复杂的变换时,可能会出现这种情况,因为我们知道它的分布。它有多种应用;从期权定价缩小海岸警卫队搜救工作的地理焦点。但是它是如何工作的呢?

概率分布

每个 RV 都有其独特的分布特征。对于连续 RV,概率密度函数(PDF)显示了给定值下连续 RV 的密度。任何给定值出现的概率为零,因此必须对一系列值进行积分,以找到 RV 落在指定范围内的概率。对于离散 RVs,该函数称为概率质量函数(PMF ),它返回特定值出现的概率。它们描述了我们观察随机变量的模式和频率。

CDF 就是 PDF 或 PMF 的累积值。它是随机变量取值小于或等于曲线/阶跃函数正下方值的概率。概率必须介于 0 和 1 之间,因此 CDF 的范围介于 0 和 1 之间。用T5 FT7 表示。

逆变换采样

除了是概率论的基础知识之外,这些与蒙特卡罗模拟有什么关系?通过下面的命题(注意:大写字母表示 RVs,小写字母表示 RV 的实现)。

这意味着我们可以将最小值为 0、最大值为 1 的均匀分布中的随机变量输入到 X 的逆 CDF 中,以生成 X 的随机值。

让我们取一个指数分布的 CDF。它在下面。

CDF of an Exponential(lambda) Distribution

通过定义 UF(X)s 求解 X ,我们可以找到 CDF 的逆。

Inverse CDF of an Exponential(lambda) Distribution

我们现在可以将 U~Uniform(0,1) RVs 输入到这个逆 CDF 中,从指数分布中生成随机抽取。我选择 1 作为我的 lambda 参数。我使用的代码如下。(注意:这是低效的,可以通过矢量化来加速,或者使用 scipy.stats 模块来加速。我这样做是为了清楚地演示逆变换采样是如何工作的)。

The code used to generate Exponential(lambda) RVs

在 10,000 个模拟随机变量时,模拟与理论分布非常接近。

现在让我们尝试一个转换。

近似 RV 的变换

现在让我们生成标准正态随机变量的平方。这实际上是一个卡方(1) RV,它允许我们通过检查精确分布来轻松检查我们的近似有多好。

The code used to generate Chi-Square(1) RVs by squaring standard normal RVs

如你所见,这个近似值相当不错。

在绘制了这些 RVs 之后,我计算了低于 1 的比例(近似概率)为 0.6857。然后,我通过使用评估为 1 的卡方(1) CDF,将这与确切的概率进行比较。准确的概率是 0.6826894921370859。这种近似在 10,000 次模拟中表现得非常好

现在让我们用这个来近似 RV 的分布,它的精确分布需要一点求解。

逼近我的任意 RV

我定义了一些任意的 RV。姑且称之为 A ,定义如下。

找到一个精确的分布需要一些工作,我不喜欢工作。幸运的是,我可以写一个函数来逼近 A 的分布。

现在我们有了一个 A 分布的近似值,并且可以找到用于推断目的的近似概率。

既然我们已经完成了对我的任意 RV 的近似,让我们来看一个假设的用例。

正回报的概率

假设我们知道一些证券的收益分布为𝐿𝑎𝑝𝑙𝑎𝑐𝑒 (0.05,0.07) ,下一期的收益不依赖于本期的收益(这是一个随机游走的例子)。我们在第 5 期的投资回报率为正的概率是多少?

The code I used to generate simulated returns and the spaghetti plot (make sure to load in stats from scipy)

5000 Random Walks of our hypothetical security and the distribution of final returns

通过计算最终收益大于 0 的比例并除以模拟次数,我们发现该证券在 5 期结束时增值的概率约为 0.85。在构建投资组合时,这是有用的信息(尽管我们在现实生活中从未遇到过这样干净的案例)。

奖金申请:蒙特卡罗积分

除了近似分布之外,蒙特卡罗模拟可以用于数值近似难以或不可能解析求解的定积分。这被称为蒙特卡罗积分。它是通过在从 𝑈𝑛𝑖𝑓𝑜𝑟𝑚 ( 𝑎𝑏 )产生的随机变量的实现上评估函数来执行的,其中 a 是定积分的下限,b 是上限。这些结果然后被平均并乘以𝑏𝑎,以获得从 𝑎𝑏 的积分近似值。

取下面的函数:

它的积分不能解析地导出,所以让我们在 0 到 1 的区间上近似它。

运行 10,000 次模拟后,我得到了大约 0.244 的近似值,这与 Wolfram 给出的大约 0.244 的近似值非常接近,因此该函数按预期工作。

结论

如果你逗留了这么久,感谢你的阅读。我希望你了解了一些蒙特卡洛模拟的工作原理。希望这些知识能帮助你继续学习蒙特卡罗模拟的应用,比如马尔可夫链蒙特卡罗。只是另一个提醒使用优化的。来自 scipy.stats 的 rvs() 方法,适用于您感兴趣的任何分布。这比重复追加到列表中要快一个数量级。

更好地理解负对数损失

原文:https://towardsdatascience.com/understanding-negative-log-loss-8c3e77fafb79?source=collection_archive---------6-----------------------

在学习 fast.ai 的时候,我决定在一些数据集上测试“3 行代码”,而不是在课程中使用的数据集。 fast.ai维基页面有一些推荐,我决定尽可能多地尝试。

简单类别下的第一个推荐数据集是狗对猫 Redux: Kernels Edition 。虽然这个和课程里的很像,但我觉得不妨试试。

该数据集包含 25000 幅训练图像和 12500 幅测试图像。使用的评估指标是 LogLoss,描述如下:

这个实验的参考是 github 中的 lesson-1 笔记本

下载文件,启动 Jupiter 笔记本,导入依赖项,设置路径,我们就可以开始了…嗯,不完全是。在我们开始我们的 3 行深度学习之前,我们还需要几行代码。这场比赛提供数据的方式与在 fast.ai 服务器上提供的数据略有不同。有多种方法可以处理这个问题,我发现最简单的方法是使用函数;

图像分类器数据。来自 _ 名称 _ 和 _ 数组(…)

而不是;

image classifierdata . from _ paths(…)

在我们这样做之前,我们需要 2 行额外的代码;

现在我们可以开始我们的 3 行代码了。

这导致验证损失 0.029175 。禁用预计算、解冻层、添加丢失并再训练 7 个历元会使损失降至 0.024749

我在测试集上运行了预测,该模型给了我一个公共排行榜分数 0.06614 。我的验证分数严重下降,但对(几乎)标准化代码来说还不算太坏。现在,我必须缩小我的分数与排名 1 的持有者的分数 0.03302 之间的差距。

震惊

在这一点上,我决定表现得厚脸皮一点。如果图像是猫,实际值为 0,如果图像是狗,实际值为 1。softmax 函数的输出只能是接近 0 或 1 的值,它永远不会是 0 或 1。我想,如果我把预测值推近 0 或 1,那么它可能会帮助我摆脱一些误差。我期待着第三位小数的变化,如果我真的很幸运,也许是第二位小数的变化。

所以我编写了简单的代码来检查我的预测中的每个值。如果该值大于 0.9,则设为 1,如果该值小于 0.1,则设为 0,否则保持不变。生成并上传了一个新的提交文件,并急切地等待着看我的鬼把戏为我赢得了多少位置。令我惊讶的是,我的分数恶化到了 0.19683

我的第一个想法是,我一定是在代码中出错了。但是代码非常简单,只有两行,如下所示。

pred_list_cor 包含原始预测值,即 12500 个测试图像中每一个的 softmax 的输出。嗯,卡格尔不可能错,所以我必须错。但是我相信我的逻辑是正确的。所以我试着在纸上算出来。

两项的结果都是 0。第一个是因为实际值,第二个是因为对数函数。这给出了 0 的理想损耗。当图像是狗的图像时,该逻辑也是有效的。

我现在怀疑的是术语 log(0) ,当然,它是未定义的。值不能为 0 或 1,因为这将导致两个术语中的一个变得不确定。对此,显而易见的解决方案是用' epsilon' '替换' 0 ',用' 1- eplison' '替换' 1 '。这将误差略微改善至 0.14109 。进展,但我仍然不知道发生了什么解释。

如果你把预测值和实际值相匹配,损失应该会下降!但是我看到了相反的效果。我下一次试图理解观察到的行为是使用一个足够高和足够低的值,但不要像 epsilon 那样剧烈。我选择了0.99999&0.00001。使用这些,我的损失下降到 0.12065 。有所改善,但仍比我未改变的预测高很多。

敬畏

很明显,我的修改恶化了错误,而不是改善了错误,但我还不明白为什么。从数学上来说,它应该有所改善。

我觉得,获得更多清晰的唯一方法是检查我的预测到底发生了什么。因为我使用的是 Kaggle 数据集,所以我没有测试集的标签。我煞费苦心地手工标记了前 500 张图片。然后根据我的预测计算损失。损失为 0.00960 ,成绩优秀。然后我用我修改后的预测计算了损失,它是 0.01531 。显著增加,但这一次,我有数据来确定问题的根源。

在仔细检查我的预测和实际标签后,我注意到我的模型在预测中有一个错误。它给一只狗贴上了猫的标签,通过对 0.03824 的预测,它很有把握这张图片确实是一只猫。我的提升逻辑已经将这个值推至接近 0。这就是问题的根源。

测井损失误差会严重影响不正确的预测

我 1 次不正确的预测已经让我损失惨重,但我对预测的修改加剧了误差,导致误差增加了 0.0057。关于这一点的一个很好的解释在这个博客中,我在下面提到了其中的摘录。

比方说,实际值是 1。

如果你的模型是不确定的,预测值为 0.5,那么损失就是;

损失=-(1 * log(0.5)) = 0.69314

如果你的模型被正确地置信和预测为 0.9,损失将是;

损失=-(1 * log(0.9)) = 0.10536

当预测值更接近实际值时,损耗下降

如果你的模型是不正确的,但也有信心和预测 0.1,损失将是;

损失= -(1 * log(0.1)) =2.30258

损失变得更加严重

在处理对数损失函数时,与其自信地错了,不如怀疑自己的预测。这是我对我的模型的疏忽。我假设当我的模型自信地预测时,它总是正确的。如果它得到了一些错误的图像,它必须预测在 0.5 左右。我完全忽略了我的模型自信地错误预测的情况。

理解神经机器翻译:编码器-解码器架构

原文:https://towardsdatascience.com/understanding-neural-machine-translation-encoder-decoder-architecture-80f205643ba4?source=collection_archive---------13-----------------------

机器翻译的技术水平已经利用了使用编码器-注意力-解码器模型的递归神经网络(RNNs)。在这里,我将尝试从一个高层次的角度来介绍它是如何工作的。

语言翻译:组件

我们可以把翻译分成两个部分:单个单位和语法:

为了在神经网络中进行计算,我们需要将单词序列编码到向量空间中。因为单词也具有有意义的序列,所以递归神经网络适合于这项任务:

问题是

然而,这种编码器-解码器架构在大约 20 个以上单词的句子之后就崩溃了:

为什么?较长的句子说明了单向编码器-解码器结构的局限性。

因为语言由记号和语法组成,这个模型的问题是它没有完全解决语法的复杂性。

具体来说,当翻译源语言中的第 n 个单词时,RNN 只考虑源句子中的第一个 n 个单词,但从语法上来说,一个单词的含义取决于句子中之前和之后的单词的顺序:

一个解决方案:双向 LSTM 模型

如果我们使用双向模型,它允许我们输入过去和未来单词的的上下文,以创建准确的编码器输出向量:

但是,接下来的挑战就变成了,在一个序列中,我们需要关注哪个单词?

2016 年,巴赫达瑙等人。艾尔。发表了一篇论文,表明我们可以通过存储 LSTM 细胞以前的输出,然后根据每个输出的相关性对它们进行排序,并选择得分最高的单词,来学习要关注源语言中的哪些单词:

下面,您可以在图表中看到这种情况:最终的架构将这种注意力机制嵌入编码器和解码器之间:

可以看到,与之前的编码器-解码器架构相比,性能有所提升:

简而言之就是这样,这也是谷歌翻译的 NMT 的工作方式,尽管编码器 LSTMs 的层数更多。

简单来说,就是这样:

  1. 编码器获取源语言中的每个单词,并将其编码到向量空间中
  2. 然后,单词的这些矢量表示被传递到注意机制,该机制确定在为期望的语言生成一些输出的同时关注哪些源单词。
  3. 这个输出通过一个解码器,将向量表示转换成目标语言

来自 CS 道场社区的插图

理解神经网络

原文:https://towardsdatascience.com/understanding-neural-networks-19020b758230?source=collection_archive---------1-----------------------

我们探索神经网络如何运作,以建立对深度学习的直观理解

深度学习是目前的热门话题。但到底是什么让它与众不同,让它有别于机器学习的其他方面呢?这是一个深奥的问题(原谅我的双关语)。为了开始回答这个问题,我们需要学习神经网络的基础知识。

神经网络是深度学习的主力。虽然它们可能看起来像黑匣子,但在内心深处(对不起,我将停止可怕的双关语),它们正试图完成与任何其他模型相同的事情——做出正确的预测。

在这篇文章中,我们将探索一个简单的神经网络的来龙去脉。到最后,希望你(和我)会对神经网络如何工作有更深更直观的理解。

30,000 英尺的视野

让我们从一个非常高层次的概述开始,这样我们就知道我们在做什么。神经网络是神经元的多层网络(下图中的蓝色和洋红色节点),我们用它来对事物进行分类、做出预测等。下面是一个简单的神经网络图,它有五个输入、五个输出和两个隐藏的神经元层。

Neural network with two hidden layers

从左边开始,我们有:

  1. 橙色的是我们模型的输入层。
  2. 我们第一个隐藏的蓝色神经元层。
  3. 我们第二层隐藏的洋红色神经元。
  4. 模型的输出层(也叫预测层)是绿色的。

连接这些点的箭头显示了所有神经元是如何相互连接的,以及数据是如何从输入层一直传输到输出层的。

稍后我们将逐步计算每个输出值。我们还将观察神经网络如何使用反向传播过程从错误中学习。

找到我们的方向

但首先让我们找到方向。神经网络到底想做什么?像任何其他模型一样,它试图做出一个好的预测。我们有一组输入和一组目标值,我们正试图获得尽可能与这些目标值匹配的预测。

暂时忘记我在上面画的看起来更复杂的神经网络图,把注意力放在下面这张更简单的图上。

Logistic regression (with only one feature) implemented via a neural network

这是一个通过神经网络表达的单特征逻辑回归(我们只给模型一个 X 变量)(如果你需要逻辑回归的复习,我在这里写了这个)。为了了解它们之间的联系,我们可以用神经网络颜色代码重写逻辑回归方程。

Logistic regression equation

让我们检查每个元素:

  1. x(橙色)是我们的输入,这是我们为了计算预测而赋予模型的唯一特征。
  2. B1(以蓝绿色表示,也称为蓝绿色)是我们的逻辑回归的估计斜率参数,B1 告诉我们 Log_Odds 随着 X 的变化而变化的程度。注意 B1 位于蓝绿色线上,该线将输入 X 连接到隐藏层 1 中的蓝色神经元。
  3. B0(蓝色)是偏差,非常类似于回归中的截距项。关键区别在于,在神经网络中,每个神经元都有自己的偏差项(而在回归中,模型有一个奇异的截距项)。
  4. 蓝色神经元还包括一个乙状结肠激活功能(由蓝色圆圈内的曲线表示)。记住,sigmoid 函数是我们使用从对数几率到概率的函数(在我之前的帖子中搜索“sigmoid”)
  5. 最后,我们通过将 sigmoid 函数应用于量(B1*X + B0)来获得我们的预测概率。

不算太糟吧?让我们回顾一下。一个超级简单的神经网络仅由以下组件组成:

  • 一个连接(虽然在实践中,通常会有多个连接,每个连接都有自己的权重,进入一个特定的神经元),权重“生活在它里面”,它转换你的输入(使用 B1)并将其提供给神经元。
  • 一种神经元,包括一个偏置项(B0)和一个激活函数(本例中为 sigmoid)。

这两个对象是神经网络的基本构建模块。更复杂的神经网络只是具有更多隐藏层的模型,这意味着更多的神经元和神经元之间更多的连接。这种更复杂的连接网络(以及权重和偏差)允许神经网络“学习”隐藏在我们数据中的复杂关系。

现在让我们增加一点复杂性

现在我们有了基本框架,让我们回到稍微复杂一点的神经网络,看看它是如何从输入到输出的。这里再次供参考:

Our slightly more complicated neural network

第一个隐藏层由两个神经元组成。因此,为了将所有五个输入连接到隐藏层 1 中的神经元,我们需要十个连接。下图显示了输入 1 和隐藏层 1 之间的连接。

The connections between Input 1 and Hidden Layer 1

请注意我们对存在于连接中的权重的标注——W1,1 表示存在于输入 1 和神经元 1 之间的连接中的权重,w1,2 表示输入 1 和神经元 2 之间的连接中的权重。所以我将遵循的一般符号是 W a,b 表示输入 a (或神经元 a )和神经元 b 之间连接的权重。

现在让我们计算隐藏层 1 中每个神经元的输出(称为激活)。我们使用下面的公式( W 表示重量,中的表示输入)。

Z1 = W1 * In1+W2 * In2+W3 * In3+W4 * In4+W5 * In5+Bias _ neuro n1

神经元 1 激活=(Z1)

我们可以使用矩阵数学来总结这种计算(记住我们的符号规则,例如,W4,2 表示输入 4 和神经元 2 之间的连接中的权重):

Matrix math makes our life easier

对于神经网络的任何层,其中前一层为 m 元素深,当前层为 n 元素深,这概括为:

[W] @ [X] + [Bias] = [Z]

其中[W]是您的 n 乘 m 权重矩阵(前一层和当前层之间的连接),[X]是您的 m 乘 1 前一层的开始输入或激活矩阵,[Bias]是您的 n 乘 1 神经元偏差矩阵,[Z]是您的 n 乘 1 中间输出矩阵。在前面的等式中,我遵循 Python 符号,用@表示矩阵乘法。一旦我们有了[Z],我们可以将激活函数(在我们的例子中是 sigmoid)应用于[Z]的每个元素,这就给出了当前层的神经元输出(激活)。

最后,在我们继续之前,让我们直观地将这些元素映射回我们的神经网络图,以便将它们联系起来([Bias]嵌入在蓝色神经元中)。

Visualizing [W], [X], and [Z]

通过重复计算[Z]并对每个连续层应用激活函数,我们可以从输入移动到输出。这个过程被称为正向传播。现在我们知道了输出是如何计算的,是时候开始评估输出的质量并训练我们的神经网络了。

神经网络学习的时间到了

这将是一个很长的帖子,所以现在请随意休息一下。还和我在一起吗?厉害!现在我们知道了神经网络的输出值是如何计算的,是时候训练它了。

神经网络的训练过程,在高层次上,就像许多其他数据科学模型一样— 定义一个成本函数,并使用 梯度下降优化 将其最小化

首先让我们考虑一下我们可以使用什么杠杆来最小化成本函数。在传统的线性或逻辑回归中,我们寻找β系数(B0,B1,B2 等。)最小化成本函数。对于神经网络来说,我们正在做同样的事情,但是规模更大,更复杂。

在传统回归中,我们可以孤立地改变任何特定的贝塔系数,而不会影响其他贝塔系数。因此,通过对每个β系数施加小的孤立冲击,并测量其对成本函数的影响,可以相对简单地计算出我们需要向哪个方向移动,以降低并最终最小化成本函数。

Five feature logistic regression implemented via a neural network

在神经网络中,改变任何一个连接的权重(或一个神经元的偏差)都会对所有其他神经元及其在后续层中的激活产生回响效应

这是因为神经网络中的每个神经元都像它自己的小模型。例如,如果我们想要一个五特征逻辑回归,我们可以通过一个神经网络来表达它,就像左边的那个,只用一个单一的神经元!

因此,神经网络的每一个隐藏层基本上都是一堆模型(该层中的每一个单独的神经元就像它自己的模型一样),其输出馈入更下游的更多模型(神经网络的每一个连续的隐藏层包含更多的神经元)。

成本函数

考虑到所有这些复杂性,我们能做什么呢?其实也没那么差。让我们一步一步来。首先,让我清楚地说明我们的目标。给定一组训练输入(我们的特征)和结果(我们试图预测的目标):

我们希望找到一组权重(请记住,神经网络中任何两个元素之间的每条连接线都包含一个权重)和偏差(每个神经元都包含一个偏差),以最小化我们的成本函数,其中成本函数是我们的预测相对于目标结果有多错误的近似值。

为了训练我们的神经网络,我们将使用均方误差(MSE) 作为成本函数:

MSE = Sum [(预测-实际)] * (1 /数量 _ 观察值)

一个模型的 MSE 告诉我们平均起来我们错了多少,但是有一个转折——通过在平均之前平方我们预测的误差,我们对远远偏离的预测的惩罚比那些稍微偏离的预测更严重。线性回归和逻辑回归的成本函数以非常相似的方式运作。

好的,我们有一个成本函数来最小化。是时候点火了梯度下降对吗?

没那么快—要使用梯度下降,我们需要知道我们的成本函数的梯度,即指向最大陡度方向的向量(我们希望在梯度的相反方向上重复采取步骤,以最终达到最小值)。

除了在神经网络中,我们有如此多的可变权重和相互关联的偏差。我们如何计算所有这些的梯度呢?在下一节中,我们将看到反向传播如何帮助我们处理这个问题。

梯度下降快速回顾

函数的梯度是向量,其元素是它对每个参数的偏导数。例如,如果我们试图最小化一个成本函数 C(B0,B1),只有两个可变参数 B0 和 B1,则梯度为:

C(B0,B1) = [ [dC/dB0],[dC/dB1] ] 的梯度

因此,梯度的每个元素都告诉我们,如果我们对特定的参数进行微小的改变,成本函数会如何改变——这样我们就知道要调整什么以及调整多少。总而言之,我们可以通过以下步骤向最小值迈进:

Illustration of Gradient Descent

  1. 计算我们“当前位置”的梯度(使用我们当前的参数值计算梯度)。
  2. 按照与其渐变元素成比例且与其渐变元素方向相反的量来修改每个参数。例如,如果我们的成本函数相对于 B0 的偏导数为正但很小,相对于 B1 的偏导数为负且很大,那么我们希望将 B0 减少很小的量,将 B1 增加很大的量,以降低我们的成本函数。
  3. 重新计算梯度使用我们新的调整参数值,并重复前面的步骤,直到我们达到最小值。

反向传播

我会遵从这本伟大的教科书(在线免费!)对于详细的数学(如果你想更深入的了解神经网络,一定要去查一下)。相反,我们将尽最大努力建立对反向传播如何以及为什么工作的直观理解。

请记住,前向传播是通过神经网络向前移动的过程(从输入到最终输出或预测)。反向传播是相反的。除了代替信号,我们通过我们的模型向后移动误差。

当我试图理解反向传播过程时,一些简单的可视化帮助很大。下面是我脑海中一个简单的神经网络从输入到输出的图片。该过程可以总结为以下步骤:

  • 输入被输入到神经元的蓝色层,并通过每个神经元中的权重、偏置和 sigmoid 进行修改,以获得激活。例如:Activation _ 1 = Sigmoid(Bias _ 1+W1 * Input _ 1)
  • 来自蓝色层的激活 1 和激活 2 被馈入品红色神经元,品红色神经元使用它们来产生最终的输出激活。

前向传播的目的是计算每个连续隐藏层的每个神经元的激活,直到我们得到输出。

Forward propagation in a neural network

现在让我们把它反过来。如果你沿着红色的箭头(在下面的图片中),你会注意到我们现在从洋红色神经元的输出开始。这是我们的输出激活,我们用它来做预测,也是我们模型中误差的最终来源。然后,我们通过我们用于前向传播信号的相同权重和连接,在我们的模型中向后移动该误差(因此,代替激活 1,现在我们有误差 1——归因于顶部蓝色神经元的误差)。

还记得我们说过正向传播的目标是一层一层地计算神经元激活,直到我们得到输出吗?我们现在可以用类似的方式陈述反向传播的目的:

我们想要计算归因于每个神经元的误差(我将把这个误差量称为神经元的误差,因为一遍又一遍地说“归因”是没有意思的),从最接近输出的层开始,一直回到我们的模型的起始层。

Backpropagation in a neural network

那么,我们为什么要关心每个神经元的误差呢?请记住,神经网络的两个构建模块是将信号传递到特定神经元的连接(每个连接中都有一个权重)和神经元本身(有一个偏差)。整个网络中的这些权重和偏差也是我们调整以改变模型所做预测的刻度盘。

这一部分非常重要:

****特定神经元的误差大小(相对于所有其他神经元的误差)与该神经元的输出(又名激活)对我们的成本函数的影响成正比。

因此,每个神经元的误差代表了成本函数相对于该神经元输入的偏导数。这具有直观的意义——如果一个特定的神经元比所有其他神经元有更大的误差,那么调整我们违规神经元的权重和偏差将比摆弄任何其他神经元对我们模型的总误差产生更大的影响。

并且关于每个权重和偏差的偏导数是组成我们的成本函数的梯度向量的单独元素。因此,基本上反向传播允许我们计算归因于每个神经元的误差,进而允许我们计算偏导数并最终计算梯度,以便我们可以利用梯度下降。万岁!

一个有帮助的类比——责备游戏

有很多东西需要消化,所以希望这个类比会有所帮助。几乎每个人在生活中的某个时候都有一个糟糕的同事——当事情出错时,他总是玩推卸责任的游戏,把同事或下属扔到公共汽车底下。

神经元,通过反向传播,是责备游戏的大师。当错误被反向传播到特定的神经元时,该神经元将迅速有效地将矛头指向上游同事(或同事),他们是造成错误的最大原因(即,第 4 层神经元将矛头指向第 3 层神经元,第 3 层神经元指向第 2 层神经元,等等)。

Neurons blame the most active upstream neurons

当神经元不能直接观察到其他神经元的错误时,每个神经元如何知道该责备谁?他们只是根据最高和最频繁的激活来看谁给他们发送了最多的信号。就像在现实生活中一样,那些安全行事的懒人(低激活率和不频繁激活率)会逃避责任,而那些工作最多的神经元会受到指责,并修改其权重和偏好。玩世不恭是的,但也非常有效地让我们得到一套最佳的权重和偏见,使我们的成本函数最小化。左边是神经元如何把彼此扔到巴士下面的图像。

简而言之,这就是反向传播过程背后的直觉。在我看来,这是反向传播的三个关键点:

  1. 它是将误差一层一层向后移位,并将正确的误差量归属于神经网络中的每个神经元的过程。
  2. 归因于特定神经元的误差是改变该神经元的权重(来自通向神经元的连接)和偏差将如何影响成本函数的良好近似。
  3. 当向后看时,更活跃的神经元(非懒惰的)是那些被反向传播过程指责和调整的神经元。

把这一切联系在一起

如果你一路读到这里,那么我对你表示感谢和钦佩(对你的坚持)。

我们从一个问题开始,“是什么让深度学习变得特别?”我现在将尝试回答这个问题(主要从基本神经网络的角度,而不是像 CNN、RNNs 等更高级的表亲的角度)。).依我拙见,以下几个方面使神经网络变得特别:

  • 每个神经元都是自己的微型模型,有自己的偏好和一组输入特征和权重。
  • 每个单独的模型/神经元通过模型的所有隐藏层馈入许多其他单独的神经元。因此,我们最终将模型插入到其他模型中,其总和大于其组成部分。这使得神经网络能够拟合我们数据的所有角落和缝隙,包括非线性部分(但要小心过度拟合——并且一定要考虑正则化,以保护你的模型在面对新的和超出样本的数据时不会表现不佳)。
  • 许多互连模型方法的多功能性以及反向传播过程高效且最优地设置每个模型的权重和偏差的能力,使得神经网络能够以许多其他算法无法实现的方式从数据中稳健地“学习”。

作者注 :神经网络和深度学习是极其复杂的学科。我仍然处于了解它们的早期阶段。写这篇博客是为了发展我自己的理解,也是为了帮助你,读者。我期待您所有的评论、建议和反馈。干杯!

如果你总体上喜欢这篇文章和我的写作,请考虑通过我的推荐链接注册 Medium 来支持我的写作。谢谢!

来源:

神经网络和深度学习作者迈克尔·a·尼尔森

维基百科:反向传播

理解神经网络

原文:https://towardsdatascience.com/understanding-neural-networks-677a1b01e371?source=collection_archive---------21-----------------------

Image of neurons inside our brains

神经网络我们这里要考虑的是人工神经网络( ANN )。顾名思义,人工神经网络是受人脑功能和结构启发的计算系统。

在本文中,我们将讨论什么是神经网络以及神经网络是如何工作的。

什么是神经网络?

在了解什么是人工神经网络之前,我们必须首先了解神经元如何在大脑中相互通信。所以让我们开始吧…

Image of communication between neurons

人脑由数十亿个被称为神经元的细胞组成。信息在神经元内部以电信号的形式传递。任何需要传达给大脑任何其他部分的信息都由神经元中的树突收集,然后在神经元细胞体中进行处理,并通过轴突传递给其他神经元。下一个神经元可以根据其强度接受或拒绝传播的电信号。

现在让我们试着理解什么是人工神经网络:

Image of ANN-1

人工神经网络是试图模仿大脑内部生物神经元功能的人工神经元的集合。每个连接都可以将信号从一个节点传输到另一个节点,在那里可以进一步处理并传输到下一个连接的人工神经元。人工神经网络可以学习和区分非常复杂的模式,这些模式很难人工提取并输入到机器中。人工神经网络由三种类型的层组成,每一层都是一堆人工神经元。每层人工神经元的数量可以根据你的个人选择而有所不同。

为了更好地理解 ANN,让我们来理解每一层的功能。

  • 输入层由人工神经元组成,将输入数据带入系统,供后续人工神经元进一步处理。输入层出现在人工神经网络的起点。
  • 隐藏层在输入层和输出层之间。它接收一组加权输入,并通过激活功能产生输出。该层被命名为 hidden,因为它不构成输入层或输出层。这是所有处理发生的层。根据问题的复杂程度,可以有一个或多个隐藏层。

我们将在本文的后半部分更详细地讨论加权输入激活函数。现在请记住,修改后的输入被输入到隐藏层,在该隐藏层的人工神经元内部发生一些处理,产生一个输出,用作下一个隐藏层或输出层的输入。

  • 输出层是人工神经网络架构的最后一层,为特定问题产生输出。这是在预测问题的结果之前进行任何处理的最后一层。

神经元内部发生了什么?

为了更好地理解 ANN 的工作,我们需要了解神经元上到底发生了什么。所以,让我们开始吧…

Image of ANN-2

这个 ANN 架构由 n 个输入和单个人工神经元以及单个输出y _ j组成。这里 w1,w2…wn 是对应于 x1,x2…的输入信号的强度。xn 分别为

Image of operations inside an artificial neuron

上图显示的是一个人工神经元。在每个神经元处, ∑ xiwi 通过将权重乘以它们各自的输入并求和来计算。其上应用了激活功能【f】。激活只是一个非线性函数,应用于 ∑ xiwi 以在架构中添加非线性。所谓非线性,我的意思是我们在日常生活中面临的大多数问题都很复杂,无法通过线性函数来解决,激活函数帮助我们在我们的架构中添加非线性,以获得解决此类问题的更好结果。一个没有激活函数的神经网络只是线性回归。激活功能帮助它学习更复杂的任务并预测结果。

With the help of activation functions, neural networks are able to classify linearly non-separable data on the right

几个最常用的非线性激活函数是:

Image of the non-linear activation functions

  • s 形函数→f(x) = 1/(1+ exp(-x))

它用于二进制分类问题的输出层,会产生输出 0 或 1。由于 sigmoid 函数的值介于 0 和 1 之间,如果该值大于 0.5,我们可以很容易地预测为 1,否则为 0。对于多类分类问题,Softmax 函数是最常见的选择。softmax 函数类似于 sigmoid 函数。你可以在这里阅读更多关于 Softmax 函数的内容。

  • Tanh 函数→f(x)=2/(1+exp(-2x))-1

它用于神经网络的隐藏层,因为它的值介于-1 到 1 之间,因此隐藏层的平均值为 0 或接近 0。这有助于更容易地学习下一层。

  • RELU 函数→f(x) = max(0,x)

RELU 比 sigmoid 和 Tanh 函数快得多。它涉及简单的数学。如果你不知道选择哪一个激活函数,那么简单地使用 RELU ,因为它是最通用的激活函数,使用最多。

你可以在这里阅读更多关于其他激活功能的信息。

神经网络是如何工作的?

既然我们对人工神经网络体系结构的基本结构以及它的几个组成部分的功能有了概念,我们就可以理解神经网络实际上是如何工作的了。

Image of ANN-3

我们将以(安-3 的图像)为例。

  • 写有 1 的神经元是偏见。偏置单元是添加到每个预输出层的“额外”神经元,存储值 1。偏置单元没有连接到任何先前的层,从这个意义上说,不代表一个真正的“活动”。为了清楚地理解我们为什么需要偏见,你可以阅读这篇文章
  • x_1x_2 为输入。
  • (W _11) 表示从x1分配给隐层第一个神经元的权重,【W _ 12】表示从 x1 分配给隐层第二个神经元的权重,以此类推。上标表示权重分配给哪一层,如 W ,表示权重从输入层到第一个隐藏层, W 表示权重从第一个隐藏层到输出层。
  • 右边的箭头是我们的 ANN 架构的最终输出(将使用 y^来表示)

神经网络的工作过程可以分解为三个步骤:

1) →初始化

设计神经网络后的第一步是初始化:

  • 用正态分布的随机数初始化所有权重 (W _11,W _12 …) ,即~N(0,1)。保持权重接近 0 有助于神经网络更快地学习。
  • 将所有偏差设置为 1。

这些是一些最常见的初始化实践。还有各种其他的权重初始化技术,你可以阅读这篇帖子了解更多信息。

2) →前馈

前馈是神经网络用来将输入转化为输出的过程。我们将参考下图来计算 y^.

Feedforward calculation for ANN-3 architecture

从右到左阅读图像。

  • 第一个操作是将包含偏差的输入向量乘以 W 矩阵。请记住,您可能需要做一些矩阵转换,以使矩阵乘法可行(将输入矩阵转换为 1X3,然后乘以 W,以创建 1X2 形状的输出)
  • 矩阵相乘后,应用 sigmoid 激活函数。
  • 到目前为止,我们已经计算了第一个隐藏层的值,现在我们将添加一个新的偏差到隐藏层矩阵(这里从 1X2 变成 1X3)。下一步是将隐藏层矩阵乘以 W。
  • 在矩阵乘法之后,我们将剩下单个值,该值将被馈送到 sigmoid 激活函数,从而产生 y^.。这种类型的 ANN 架构可以用于二进制分类(如果输出大于 0.5,我们可以预测 1 否则为 0)

按照这些步骤背后的思想,我们可以将一个人工神经网络的输入转化为输出,即使它有 100 个隐藏层。

在开始反向传播步骤之前,我们必须了解一些解释反向传播所需的概念。概念包括:

→成本函数

→梯度下降

什么是成本函数?

神经网络在机器学习领域获得了如此大的流行,因为它们在每次预测其输出时都具有学习和改进的能力。为了能够改进,我们需要一个误差函数或成本函数,让我们知道我们的预测与实际输出有多远(成本函数是一种衡量神经网络相对于其给定训练样本和预期输出“有多好”的方法)。在神经网络中,有许多成本函数。其中一个常用的是伯努利负对数似然损失。

Image of Bernoulli negative loglikelihood loss

忽略 L 前面的“-”。

  • N 这里表示训练样本数据点的数量。
  • p_i 表示我们模型的预测。
  • y_i 为实际输出。
  • M 表示多分类问题中输出类的数量。

成本函数导致总体训练点数的平均损失。通过查看二元和多分类对数似然损失方程,我们还可以得出结论,对于 M = 2,它们导致相同的成本(误差)。如果你有兴趣,你可以在这里阅读更多关于其他成本函数的信息。

什么是梯度下降?

梯度下降是一种优化算法,用于通过沿梯度的负值(斜率或曲线的陡度,使用偏导数计算)定义的最陡下降方向迭代移动来最小化某个函数。在机器学习中,我们使用梯度下降来更新模型的参数。参数包括线性回归的系数和神经网络的权重和偏差。

那么让我们来理解梯度下降是如何帮助神经网络学习的。

Graph of cost function(J(w)) vs weight(w)

我们将使用上面的图像(成本函数(J(w))对权重(w)) 来解释梯度下降。

  • 假设对于特定的权重和偏差值,我们得到下面的平均成本(误差),用图中的球表示我们的训练点。我们还可以观察到,通过微调参数,平均成本的值可以低至 J_min(w)。
  • 为了更新权重和偏差以最小化成本,梯度下降将在箭头指示的方向上迈出小步。它通过计算成本函数相对于权重和偏差的偏导数,并从相应的权重和偏差中减去它来实现。由于球所在位置的导数为正,如果我们从 w 中减去成本函数相对于 w 的导数,它将减小并更接近最小值。
  • 我们迭代地继续这个过程,直到我们到达图表的底部,或者到达我们不能再向下移动的点——局部最小值。对于每个训练样本,神经网络中的所有权重和偏差都会发生这种情况。

这些步骤的大小被称为学习率。有了高学习率,我们可以采取更大的步骤,但我们有超过最小值的风险,因为曲线的斜率是不断变化的。由于学习率很低,我们可以自信地向负梯度的方向前进,因为我们经常重新计算它。低学习率更精确,但是计算梯度很耗时,所以我们需要非常长的时间才能收敛。

3) →反向传播

反向传播算法只是它的一个扩展,使用链式法则来找出连接输入层和隐藏层的权重的误差(对于两层网络)。如果您对链式法则概念不太熟悉,请务必查看下面的链接

反向传播的主要思想是更新可以帮助我们降低网络成本的权重,从而生成更好的预测。要使用梯度下降更新隐藏层的权重,您需要知道每个隐藏单元对最终输出的影响有多大。由于层的输出由层之间的权重决定,因此由单元产生的误差由通过网络前进的权重来缩放。由于我们知道输出端的误差,我们可以使用权重反向工作到隐藏层。

使用梯度下降更新权重

我们可以借助以下等式来更新权重:

Equation-1

其中 η 是学习率, δ 是误差项,表示为

Equation-2

记住,上式中 (y−y^ ) 是输出误差,f′(h)是指激活函数的导数, f(h) 。我们称这个导数为输出梯度。这个δwi被添加到相应的权重,这有助于减少网络的误差,如(成本函数(J(w))对权重(w)的图表图像)中所解释的。

为了更好地理解,我们将考虑一个网络,其中输出层具有归因于每个输出单元 k 的误差 δ⁰_k 。然后,归因于隐藏单元 j 的误差是输出误差,由输出和隐藏层(以及梯度)之间的权重来缩放:

Equation-3

然后,梯度下降步骤与之前相同,只是有新的误差:

Equation-4

其中 wij 为输入和隐藏层之间的权重,为输入单元值。无论有多少层,这种形式都适用。权重步长等于步长乘以图层的输出误差乘以该图层的输入值。

Equation-5

这里,通过从更高层向后传播误差,得到输出误差 、δ输出 。并且输入值 Vin 是层的输入,例如隐藏层激活到输出单元。

通过一个例子

Image of a two-layer network

下图描述了一个双层网络。(注:输入值显示为图像底部的节点,而网络的输出值显示为顶部的 y^ 。输入本身不能算作一个层,这就是为什么这被认为是一个两层网络。)

假设我们试图拟合一些二进制数据,目标是 y = 1。我们将从正向传递开始,首先计算隐藏单元的输入。出于理解的目的,在这个网络中没有偏见。

Equation-6

和隐藏单元的输出。

Equation-7

将此作为输出单元的输入,网络的输出为

Equation-8

有了网络输出,我们可以开始反向传递来计算两个层的权重更新。利用以下事实,对于 sigmoid 函数f'(wa)=f(wa)(1f(wa),输出单元的误差项为

Equation-9

现在我们需要计算带有反向传播的隐藏单元的误差项。这里我们将通过权重 W 将输出单元的误差项与隐藏单元连接起来。对于隐藏单元误差项,(方程式-1 的图像),但是由于我们有一个隐藏单元和一个输出单元,这就简单多了。

Equation-10

现在我们有了误差,我们可以计算梯度下降的步骤。隐藏到输出权重步骤是学习率乘以输出单元误差,再乘以隐藏单元激活值。

Equation-11

然后,对于输入到隐藏权重 wi ,它是学习率乘以隐藏单元误差,再乘以输入值。

Equation-12

计算δwi后,添加到各自的 wi 中。这就是如何更新权重,以使网络在每次迭代中变得越来越好。

从这个例子中,您可以看到使用 sigmoid 函数进行激活的效果之一。sigmoid 函数的最大导数为 0.25,因此输出层中的误差至少减少了 75%,隐藏层中的误差至少减少了 93.75%!您可以看到,如果您有很多图层,使用 sigmoid 激活函数会将输入附近图层中的权重步长快速降低到很小的值。这就是所谓的消失梯度问题。你可以在这里阅读更多关于消失渐变问题

理解神经网络

原文:https://towardsdatascience.com/understanding-neural-networks-a12c999f821f?source=collection_archive---------26-----------------------

神经网络产生了很多兴趣。然而,机器学习社区之外的人并不总是清楚它们适合解决什么问题,它们是什么,或者它们是如何构建的。我们将在这篇博文中讨论这些话题,旨在让所有读者都能接触到神经网络。对于那些有编程经验的人,我在最后附加了一个 Jupyter 笔记本,你可以按照它来构建你自己的神经网络。

神经网络的大多数商业上成功的应用是在监督学习领域。在监督学习中,我们试图建立一个将输入映射到输出的模型。一些例子包括:

我们可以将这些模型表示为接受输入并产生输出的函数:

y = F(x)

其中 x 是输入,y 是输出,F()是我们的模型。神经网络是为许多类问题建立模型(即 F())的特别有效的方法。

让我们简单地考虑一下构建许多模型的传统方法。通过将我们对微积分的理解应用于特定领域的知识,我们可以推导出描述许多现象的模型。在物理学中,这将包括牛顿运动定律,或守恒定律,即在封闭系统中质量、能量和动量守恒。这种方法让我们成功地建立了各种各样的重要模型,例如告诉我们火箭到达太空需要多少燃料的理想火箭方程,或者让我们模拟海岸波浪的 Boussinesq 方程。

对于那些我们对基本动力学没有直觉的问题呢?假设您正在制造一辆自动驾驶汽车,并希望使用来自仪表板摄像头的视频流来识别道路上的其他汽车。尽管事实上我们都很擅长识别汽车,但我们还不能用物理原理来描述汽车的样子。我们不能指出组成汽车的轮子、门和窗户的组合。神经网络为我们提供了一种技术,我们可以用它来有效地解决这类问题。

神经网络通过直接从数据中学习从输入到输出的映射来工作。让神经网络学习这种映射的过程称为训练。训练需要一组训练示例,这些示例是成对的输入和相应的输出(x 和 y)。为了使训练有效,我们需要一个大的数据集,通常是数万到数千万个训练样本。

在训练期间,我们优化神经网络的权重(或参数)。对于每个训练示例,我们对输入运行模型,并使用损失函数将模型输出与目标输出进行比较。使用一种称为反向传播(或简称为反向传播)的算法,我们更新网络中的所有权重,以使模型输出更接近目标输出。权重根据它们对任何不匹配的贡献程度成比例地更新。我们继续循环我们的训练集,迭代更新模型,直到性能不再增加。

让我们来看一个直观的神经网络的可视化。在左手边,我们有输入层。这是我们的数据,比如一个图像的像素,或者某个词在一封邮件中出现了多少次。接下来,我们有两个隐藏层。隐藏层是一个术语,我们指的是输入层和输出层之间的层。最后,我们有输出层。当输入通过神经网络的每一层时,它经历一系列的计算。隐藏层和输出层中的每个“单元”(或“神经元”)包含一组要优化的权重,这些权重控制这些计算。

设计神经网络需要选择控制网络结构和训练过程的超参数。我们使用术语超参数,因为术语参数是权重的替代。与架构相关的超参数包括层数、每层的宽度(即单元数),以及在单元中选择称为激活函数的东西。训练尤其受优化算法的选择、算法使用的学习速率以及是否实现称为正则化的技术的影响。

不幸的是,没有办法预先知道对于你的问题什么是最好的架构,或者训练那个架构的最佳参数是什么。从业者由来自社区的经验、直觉和最佳实践的组合来指导。由于这个领域发展迅速,这就需要不断跟上时代的步伐。通常,从一个问题开始的最佳方式是查看机器学习文献,看看是否有人已经解决了与你类似的问题,并将他们的解决方案作为起点。获得特定问题的解决方案通常需要查看数据、实现想法、修改模型代码和测试的多次迭代。

任何神经网络的一个关键问题是,它能够对以前从未见过的数据执行得有多好。因此,在训练神经网络之前,通常称为测试集的数据中会留出一小部分。在训练神经网络之后,我们比较了神经网络在训练集和测试集上的性能。一种可能的情况是,该模型即使在接受训练的数据上也表现不佳。万一,我们说模型有高偏差。当模型不能很好地拟合其观察到的数据时,超参数应该被重新评估。另一个结果是,该模型在训练集上表现良好,但在测试集上表现不佳。在这种情况下,我们说模型具有高方差,即神经网络已过度适应训练数据。相当于,网络还没有很好地学习概括数据的特征,并且可能已经记住了特定于训练集的特征。为了解决高方差问题,我们通常采用一种称为正则化的技术。在可行的情况下,获取额外的数据也是有益的。

一个重要的细节是,训练神经网络的数据必须与应用神经网络的数据相似。从统计学上来说,您希望您的训练和测试数据来自同一个分布。直观地说,这意味着如果你训练你的自动驾驶汽车只在晴天驾驶,你就不能指望它在降雪期间留在路上。在实践中,这意味着如果你开发一个神经网络来预测客户行为,你将需要随着你的产品、客户和竞争等重要因素的发展定期更新你的模型。

这些是理解如何应用神经网络以及如何与经常使用神经网络的人交流的主要概念。读完这篇文章后,你应该能够自信地运用神经网络进行对话。

总结一下关于神经网络的要点:

  1. 它们是直接从训练数据集构建从输入到输出的模型映射的有效方法。
  2. 神经网络有很多超参数,设计一个好的网络是一个迭代的过程。
  3. 您的训练和测试数据应该来自同一个发行版。

最后,我交谈过的许多软件开发人员都渴望知道神经网络的实现细节。以下 Jupyter 笔记本详细信息是根据您的需求设计的,实现了一个神经网络来识别手写数字,准确率高达 98%。我们假设您已经用 PyTorch 设置了 python 环境。如果您不知道,Anaconda 是推荐的包管理器,并且非常容易上手。

你可以下载 jupyter 笔记本在你自己的机器上运行这里,以及跟随预计算版本这里

https://inletlabs.com】最初发表于

理解 NLP 和主题建模第 1 部分

原文:https://towardsdatascience.com/understanding-nlp-and-topic-modeling-part-1-257c13e8217d?source=collection_archive---------25-----------------------

Photo by Ivo Rainha from Pexels

我们探索如何通过自然语言处理提取主题帮助我们更好地数据科学

自然语言处理(NLP)是数据科学的一个前沿领域。它的终端应用有很多——聊天机器人、推荐系统、搜索、虚拟助手等等。

因此,对于初露头角的数据科学家来说,至少了解 NLP 的基础知识是有益的,即使他们的职业生涯将他们带到了一个完全不同的方向。谁知道呢,通过 NLP 提取的一些主题可能会给你的下一个模型带来额外的分析提升。今天,在这篇文章中,我们试图理解为什么主题建模是重要的,以及它如何帮助我们这些数据科学家。

主题建模,顾名思义,就是使用一种算法来发现最能描述给定文本文档的主题或主题集。你可以把每个话题想象成一个单词或者一组单词。

主题建模的目标

我第一次和 NLP 一起工作时,我对自己说:

" NLP 仅仅是 EDA(探索性数据分析)的另一种形式吗?"

这是因为在那之前,我主要是带着明确的目标构建模型——用 X 来预测或解释 y。NLP 远没有那么结构化和清晰。甚至当我最终成功运行我的主题建模算法时,掉出的主题产生的问题比答案还多。在这里,看看我对 Reddit 的 NLP 分析得出的一些主题:

Topic 10:
book read reading history series love author first people novel world finished
Topic 11:
like feel something people look seem seems stuff actually right always question
Topic 12:
story writing write character main novel chapter short plot first scene advice
Topic 13:
think wait bit better people bad true might worth thinking put sell
Topic 14:
need financial house information relevant situation invest question money making ask consider
Topic 15:
car insurance loan vehicle damage accident hit month payment driver title pay

有些主题有意义,有些没有意义。不管怎样,我应该对这些话题做些什么呢?

这就是数据科学家的生活——通常只有在你最终清理了数据和调试了代码之后,真正的工作才开始。然后,终于,是时候去寻找那些恼人的难以捉摸的见解了。这正是自然语言处理和主题建模的要点。它本身可能不是目的,但通过 NLP 提取主题让我们更接近于生成有用的东西,就像降维技术在数据科学世界的数字方面帮助我们一样。

主题建模允许我们穿过噪音(处理文本数据的高维度)并识别我们的文本数据的信号(主要主题)。

有了这个经过提炼的信号,我们就可以开始真正的工作,产生真知灼见。让我们一步一步来。

维度的诅咒

在许多数据科学应用中,高维数据被视为诅咒。如果你想更详细地了解为什么,这是我以前写的一篇关于维度诅咒的文章。但是对于那些时间紧迫的人来说,这里有一个 TLDR:

  1. 如果我们的特征比观察值多,我们就会冒模型过度拟合的风险——这通常会导致糟糕的样本外性能。
  2. 当我们有太多的特征时,观察变得更难聚类-信不信由你,过多的维度会导致数据集中的每个观察看起来与所有其他观察等距。因为聚类使用一种距离度量,比如欧几里德距离,来量化观察值之间的相似性,这是一个大问题。如果距离都近似相等,那么所有的观察结果看起来都一样(也一样不同),并且不能形成有意义的聚类。

什么时候我们最有可能遇到高维数据(也就是太多的特征)?文本数据。要了解原因,想象一下我们将如何对以下句子的数据进行编码,以便算法可以对其进行处理:

"那个男人穿着一件有金色星星的夹克。"

一种自然的方法是所谓的单词包方法— 单词包将一个给定的文档表示为一个不同单词及其频率的列表。所以上面的句子应该是这样的:

Bag of Words Example

因此,为了捕获给定的文档,我们需要为文档中的每个独特的单词提供一个特征。对于给定的文档,每个特征的值是该单词在文档中出现的次数(因此对于我们之前的示例,除了“a”出现两次之外,每个单词都出现一次)。

现在想象我们的文档不是孤立的,而是一个更大的语料库的一部分。让我们首先弄清楚行话:

  • 文档是你定义的单个观察(也就是一袋单词)的任何东西。它可以是一句话,也可以是一整篇文章,甚至是一整本书——你如何定义它取决于你分析的目标。
  • 语料库是所有文本数据的总和——换句话说,是数据集中的所有文档。

如果你的语料库很大,那么你大概会有至少上万个独特的单词在里面(如果你的语料库包括很多名字的话会更多)。仅仅是试图想象那袋单词就让我头疼。试图在它上面运行算法将会非常慢,并且可能没有帮助——很可能你会有更多的特征(独特的单词)而不是观察(文档)。

NLP 来救援了

现在,让我们用一个实际的例子来看看 NLP 如何帮助筛选维度来揭示信号。假设我们想向一个朋友推荐几本书。我们将如何着手做那件事?

一种方法是问:

“嘿,说出几本你最近读过的、你真正喜欢的书。”

然后根据回复,推荐几本我们最喜欢的、与他或她列出的书最相似的书。我们刚刚描述了一个简单的推荐系统。

为了在算法上做我们刚刚描述的事情,我们需要能够弄清楚如何衡量两本书是否相似。我们可以把这两本书描述成一袋袋的单词,并尝试使用像欧几里德距离这样的距离度量来比较它们,但这真的有帮助吗?答案是否定的,原因有几个:

第一个原因是停用词(真正常见的词有“The”、“a”、“it”、“and”等。)—这些单词在几乎所有的文档中出现得非常频繁,它们会给我们的相似度分数注入许多无意义的噪音(知道两本书都包含许多单词“the”的实例根本没有帮助)。

而且即使我们去掉了所有的停用词,的维度诅咒仍然影响着我们。一本书里有如此多不同的单词,其中许多与书的实际主题毫无关联。因此,我们的相似性度量很有可能锁定这些干扰词中的一个——这基本上是伪相关的文本版本。例如,我们可以有一本关于消防员的书和一本关于钓鲑鱼的书,但将它们列为高度相似,因为我们的算法注意到“杆”和“引擎”这两个词在这两本书中都频繁出现。这是一个偶然的和无意义的相似性,如果我们采取行动,这将是有问题的。

主题建模

这就是主题建模的用武之地。主题建模是使用定量算法梳理出文本主体所涉及的关键主题的实践。它与PCA 之类的东西有很多相似之处,它识别你的特征中的关键定量趋势(解释最大的差异)。PCA 的输出是总结我们特征的一种方式——例如,它允许我们从大约 500 个特征到 10 个总结特征。这 10 个概要特征基本上是主题。

在 NLP 中,它的工作方式几乎完全相同。我们想要将我们的全部书籍和它的 100,000 个特征(不同的单词)提取成 7 个主题(我任意选择了 7 个主题)。一旦我们知道了主题以及它们由什么组成,我们就可以将语料库中的每本书从嘈杂的单词包转换成一个干净的主题加载组合:****

We want to express each book in our corpus as a portfolio of topics

现在我们开始做生意了。使用每本书的主题负载计算的相似性分数比使用原始单词包计算的分数有用得多,因为虚假的相似性现在不太可能了。

甚至一本书的描述性统计在“主题空间”中也比在“词汇袋空间”中更有意义——我们现在可以说一本书在数据科学主题上负载很重,而不是去纠结为什么在我们的词汇袋中最频繁出现的两个词是“森林”和“随机”。

思维练习

在前面的例子中,我们决定将我们的书表达为 7 个主题的负载。但是我们可以选择任何数量的主题(选择主题数量更多的是艺术而不是科学,并且很大程度上取决于你的数据——因此充分了解你的数据是至关重要的)。10 也行,100 也行。但是想想随着我们不断增加主题的数量,每个主题变得越来越细,算法开始失去看到全局的能力,会发生什么。****

例如,假设我们有三本书——第一本是法国旅游指南,第二本是中国旅游指南,第三本是中国城市化的经济史。在我们的 7 主题 NLP 模型中,我们将第 1 本书和第 2 本书归类为旅游书籍(并将其评分为彼此相似),将第 3 本书归类为商务书籍(并将其评分为与其他书籍不相似)。

有 5000 个主题,我们可以将第一本书归类为“骑行乡村法国”,第二本书归类为“旅游城市中国”,第三本书归类为“历史城市中国”。现在还不太清楚我们该如何给它们打分——算法可能只是举手表决,将所有 3 本书评为相同/不同。这不一定是错误的(取决于应用程序)但它确实显示了高维数据(5000 个主题肯定是)会以意想不到的方式引入干扰,扭曲我们的分析。****

主题建模的一般经验法则是,只要你的最终应用程序要求你做的那样具体,不要再多了。

下次

我意识到,到目前为止,我对我们实际上是如何提出我们的主题一直含糊其辞。那是因为我想充分探索为什么 NLP 很重要。下一次,我将(用 Python 代码)介绍两种主题建模算法— LDA(潜在狄利克雷分配)NMF(非负矩阵分解)

在那之前,感谢阅读,干杯!

更多数据科学与分析相关帖子由我:

T5【维度之祸】T6

了解 PCA

数据科学家的商业战略

用 Python 进行业务模拟

理解贝叶斯定理

理解朴素贝叶斯分类器

二项分布

理解 NLP 单词嵌入—文本矢量化

原文:https://towardsdatascience.com/understanding-nlp-word-embeddings-text-vectorization-1a23744f7223?source=collection_archive---------2-----------------------

处理自然语言文本并从给定的单词中提取有用的信息,使用机器学习和深度学习技术的句子需要将字符串/文本转换为一组实数(向量)——单词嵌入。

单词嵌入或单词向量化是 NLP 中的一种方法,用于将单词或短语从词汇表映射到相应的实数向量,该向量用于查找单词预测、单词相似性/语义。

将单词转换成数字的过程称为矢量化。

单词嵌入在以下用例中有所帮助。

  • 计算相似的单词
  • 文本分类
  • 文档聚类/分组
  • 用于文本分类的特征提取
  • 自然语言处理。

在将单词转换成向量后,我们需要使用一些技术如欧氏距离余弦相似度来识别相似的单词。

为什么余弦相似

计算常用词或欧几里德距离是用于匹配相似文档的一般方法,其基于计算文档之间的常用词的数量。

即使常用词的数量增加,但文档谈论不同的主题,这种方法也不起作用。为了克服这个缺陷,使用“余弦相似度”方法来寻找文档之间的相似度。

Figure 1: Cosine Distance. Ref: https://bit.ly/2X5470I

在数学上,它测量两个向量(item1,item2)在 N 维向量空间中投影的角度的余弦值。余弦相似度的优点是,即使欧氏距离是距离,它也能预测文档的相似度。

“角度越小,相似度越高”——余弦相似度。

让我们看一个例子。

  1. 朱莉爱约翰胜过琳达爱约翰
  2. 简爱约翰胜过朱莉爱约翰
John  2   2
Jane  0   1
Julie 1   1
Linda 1   0
likes 0   1
loves 2   1
more  1   1
than  1   1

这两个向量是,

Item 1: [2, 0, 1, 1, 0, 2, 1, 1] Item 2: [2, 1, 1, 0, 1, 1, 1, 1]

两个向量值之间的余弦角(角度越小)为 0.822,最接近 1。

现在我们来看看把句子转换成向量的方法都有哪些。

来自预训练方法的单词嵌入,

  • Word2Vec —来自谷歌
  • 快速文本—来自脸书
  • 手套——来自斯坦福

在这个博客中,我们将看到最流行的嵌入式架构 Word2Vec。

Word2Vec

Word 2 vec——由托马斯·米科洛夫和谷歌的一个研究团队在 2013 年开发的向量空间中的单词表示。

word 2 vec 技术产生的原因:

大多数 NLP 系统将单词视为原子单位。现有系统的局限性在于没有单词之间相似性的概念。此外,该系统适用于较小、较简单的数据,并且在只有几十亿数据或更少的数据上表现优异。

为了用具有复杂模型的更大数据集进行训练,现代技术使用神经网络架构来训练复杂的数据模型,并且对于具有数十亿单词和数百万单词词汇的巨大数据集来说表现更好。

这种技术有助于测量结果矢量表示的质量。这适用于相似的单词,这些单词倾向于接近具有多种相似度的单词。

句法规则:指符合语法的句子纠正。

语义规律:指词汇符号在那个结构中排列的意义。

Figure 2: Five Syntactic and Semantic word relationship test set. Ref: https://arxiv.org/pdf/1301.3781.pdf

所提出的技术被发现,单词表示的相似性超出了句法规则,并且对于单词向量的代数运算惊人地有效。举个例子,

向量(“国王”)—向量(“男人”)+向量(“女人”)=词(“女王”)

其中“Queen”是单词表示的最接近的结果向量。

以下单词表示的模型架构的目标是最大化准确性和最小化计算复杂度。这些模型是,

  • 前馈神经网络语言模型(NNLM)
  • 递归神经网络语言模型

上述所有模型都使用随机梯度下降反向传播进行训练。

前馈神经网络语言模型(NNLM)

NNLM 模型由输入、投影、隐藏和输出层组成。由于投影层中的值密集,这种架构对于投影和隐藏层之间的计算变得复杂。

递归神经网络语言模型

与浅层神经网络相比,RNN 模型可以有效地表示更复杂的模式。RNN 模型没有投影图层;只有输入、隐藏和输出层。

应该使用名为 DistBelief 的大规模分布式框架为庞大的数据集训练模型,这将给出更好的结果。在 Word2Vec 中提出了两个新的模型,

  • 连续词袋模型
  • 连续跳格模型

使用分布式架构,尽量降低计算复杂性。

连续词袋模型

我们把这个模型称为 CBOW。CBOW 架构类似于前馈 NNLM,其中非线性隐藏层被移除,并且投影层被所有单词共享;因此所有的单词都被投射到相同的位置。

Figure 3: CBOW architecture. Ref: https://bit.ly/2NXbraK

CBOW 架构基于上下文预测当前单词。

连续跳格模型

跳格模型类似于 CBOW。唯一的区别是,它不是根据上下文来预测当前单词,而是试图根据同一句子中的另一个单词来最大化一个单词的分类。

Figure 4: Skip-gram architecture. Reference — https://bit.ly/2NXbraK

给定当前单词,跳格结构预测周围的单词。

Word2Vec 架构实现— Gensim

Gensim 库将使我们能够通过在自定义语料库上训练我们自己的 word2vec 模型来开发单词嵌入,或者使用跳格算法的 CBOW。

实现库可以在这里找到——https://bit.ly/33ywiaW。

结论

  • 自然语言处理需要将文本/字符串转换成实数,称为单词嵌入或单词向量化
  • 一旦单词被转换为向量,余弦相似性是用于实现大多数使用 NLP、文档聚类、文本分类、基于句子上下文预测单词的用例的方法
  • 余弦相似性—“角度越小,相似性越高
  • 最著名的架构,如 Word2Vec、Fasttext、Glove,有助于转换单词向量,并利用余弦相似性作为单词相似性特征
  • NNLM,RNNLM 优于巨大的词数据集。但是计算复杂度是一个很大的开销
  • 为了克服计算复杂性,Word2Vec 使用 CBOW 和 Skip-gram 结构,以便最大化精度和最小化计算复杂性
  • CBOW 架构基于上下文预测当前单词
  • 给定当前单词,跳格结构预测周围的单词
  • 详细解释了关于 Word2Vec 架构的论文。

参考资料:

了解对象检测

原文:https://towardsdatascience.com/understanding-object-detection-9ba089154df8?source=collection_archive---------7-----------------------

内部 AI

从物体探测的历史到著名的 fast-RCNN 的内部工作原理

Object detection combines the task of object localization and classification. Source

在这篇文章中,我想给你一个对象检测器的历史概述,并解释如何发展到目前最先进的检测器架构。此外,我将详细介绍更快的 R-CNN 的内部工作原理,因此它被广泛使用,也是 Tensorflow 对象检测 API 的一部分。

物体探测器简史

目标检测结合了目标分类和定位的任务。当前的对象检测器可以分为两类:将确定对象的位置和它们的分类的任务分开的网络,其中更快的 R-CNN 是最著名的网络之一,以及立即预测边界框和类别分数的网络,其中 YOLO 和 SSD 网络是著名的架构。

第一个用于物体检测的深度神经网络是 over feet[1]。他们介绍了一种使用 CNN 的多尺度滑动窗口方法,并表明对象检测也改善了图像分类。他们很快就被 R-CNN:具有 CNN 特征的区域[2]。作者提出了一个模型,该模型使用选择性搜索通过将相似像素合并到区域中来生成区域提议。每个区域都被输入到一个 CNN 中,产生一个高维特征向量。这个向量然后被用于最终的分类和包围盒回归,如图 1 所示。

Figure 1 The standard architecture of a R-CNN network consisting of a region proposal method, mostly selective-search, followed by a CNN for each proposal. The final classification is done with an SVM and a regressor.

它比 Overfeat 网络好得多,但也非常慢,因为使用选择性搜索生成提议非常耗时,而且需要通过 CNN 提供每一个提议。一种更复杂的方法,快速 R-CNN [3],也通过选择性搜索生成区域建议,但通过 CNN 提供整个图像。区域提案通过 ROI pooling 直接汇集在特征图上。汇集的特征向量被输入到一个完全连接的网络中进行分类和回归,如图 2 所示。类似于 R-CNN,快速 R-CNN 通过选择性搜索产生区域建议。

Figure 2: The standard architecture of a Fast R-CNN network. The region proposals are generated by selective-search, but pooled directly on the feature map, followed by multiple FC layers for final classification and bounding box regression.

快速 R-CNN [4]通过提出一种新颖的区域提议网络解决了这一问题,该网络与快速 R-CNN 架构相融合,大大加快了进程,我们将在下一节对此进行更详细的解释。另一种检测图像中对象的方法是 R-FCN [5],区域完全卷积网络,它使用位置敏感得分图而不是预区域子网。

YOLO [6]网络彻底改变了目标探测网络的设计。它遵循与上述模型完全不同的方法,并且能够立即预测类分数和边界框。所提出的模型将图像分成网格,其中每个单元预测具有相应边界框坐标的对象的置信度得分。这使得 YOLO 能够进行实时预测。作者还发布了另外两个版本,YOLO9000 [7]和 YOLOv2,前者能够预测 9000 多个类别,后者能够处理更大的图像。另一个可以同时预测类别和包围盒的网络是单次检测器 SSD [8]。它与 YOLO 相当,但每个网格单元使用多个纵横比和更多的卷积层来提高预测。

更快的 R-CNN

Figure 3: The standard architecture of a Faster R-CNN network, where the region proposal are generated using a RPN, that works directly on the feature map. The last layers are fully connected for classification and bounding box regression.

快速 R-CNN 和 R-CNN 的主要问题是区域提议的时间和资源密集型生成。快速 R-CNN 通过融合快速 R-CNN 和区域提议网络(RPN)解决了这一问题,如图 3 所示。RPN 使用 CNN 的输出作为输入,并生成区域提议,其中每个提议由对象性分数以及对象的位置组成。RPN 可以与检测网络联合训练,从而加快训练和推断时间。更快的 R-CNN 比快速 R-CNN 快 34 倍。在下面的段落中,更详细地解释了更快的 R-CNN 的每个步骤。

主播

更快的 R-CNN 的目标是检测作为矩形边界框的对象。这些矩形可以有不同的大小和比例。当以前的工作试图考虑不同大小和比例的对象时,他们要么创建图像金字塔,其中考虑图像的多个大小,要么创建过滤器金字塔,其中应用多个不同大小的卷积过滤器[1,9,10]。这些方法对输入图像起作用,而更快的 R-CNN 对 CNN 输出的特征图起作用,因此创建了锚的金字塔。锚点是一个固定的边界框,由中心点、特定的宽度和高度组成,并引用原始图像上的边界框。从特征图上的滑动窗口中为每个位置生成一组锚,该组锚由大小和比例的不同组合的多个锚组成。图 4 显示了一个例子,其中大小为 3x3 的窗口生成了 k 个锚点,其中每个锚点在原始图像中具有相同的中心点。这是可能的,因为卷积运算对于平移是不变的,并且可以将特征图上的位置计算回图像中的区域。

Figure 4: Generation of k anchors per position by sliding a 3x3 window over the feature map.

地区提案网

RPN 是一个完全卷积的网络,直接作用于特征地图,以生成区域建议,如图 5 所示。它将锚点作为输入,预测客观分数并执行盒回归。前者是锚作为对象或背景的可能性,后者对应于从锚到实际框的偏移。因此,对于 k 主播,RPN 预测 2 个 k 分数和 4 个 k 盒子回归值。锚的初始数量不需要小于来自任何其他区域提议方法的锚的初始数量,因为 RPN 通过仅考虑具有高客观性分数的区域来显著减少锚的数量。训练 RPN 并不简单。由于这是一种监督学习方法,每个锚点必须被标记为前景或背景。因此,每个锚点都必须通过计算它们在并集上的交集(IoU)来与每个地面真实对象进行比较。如果存在具有大于 0.7 的 groundtruth 对象的 IoU,则锚被认为是前景和正的。如果每个接地真值盒的 IoU 低于 0.3,则认为它是背景和负的。IoU 在 0.3 和 0.7 之间的所有锚都被忽略。积极和消极建议的分布是非常不平衡的,因为每个基础事实箱的消极建议比积极建议多得多。因此,具有固定数量阳性和阴性的迷你批次被取样用于训练过程。如果没有足够多的积极建议,则该批将被填入在各自的基础事实框中具有最高 IoU 的建议。如果仍然没有足够的积极建议,就会用消极的建议来填补。RPN 采用多任务损失同时优化两个目标。对于分类,使用二元交叉熵损失,对于包围盒回归,使用平滑 L1 损失。区域建议网络的架构,这是一个完全卷积的网络。

Figure 5: Standard architecture of a region proposal network

回归损失仅针对正锚点进行计算。在预测之后应用非最大抑制(NMS ),以移除与其他区域提议具有高于某个值的 IoU、但是具有较低的客观性分数的区域提议。NMS 之后,前 N 个方案被选为最终区域方案。

利息集中区域

RPN 之后的下一步是使用区域建议来预测对象类别和定位。与 R-CNN 的方法不同,在 R-CNN 中,每个建议都是通过分类网络提供的,更快的 R-CNN 利用特征图来提取特征。因为分类器期望固定大小的输入,所以从特征图中为每个区域提议提取固定大小的特征。在现代实现中,特征地图被区域提议裁剪,并被调整到固定大小。Max pooling 随后提取最显著的特征,为每个区域提议确定一个固定的大小,然后输入到最终阶段。

分类和回归

快速 R-CNN 的最后一步是对提取的特征进行分类。因此,合并的要素被展平并输入到两个完全连接的图层,这两个图层处理分类和回归。分类层输出 N+1 个预测,N 个类中的每一个都有一个预测,外加一个背景类。回归层输出 4N 个预测,其中每个预测代表 N 个类中每个类的回归边界框。R-CNN 模块的培训与 RPN 模块的培训相当。IoU 大于 0.5 的每个 groundtruth 框都分配有一个建议。IoU 在 0.1 和 0.5 之间的提案被视为负面和背景,IoU 低于 0.1 的提案被忽略。培训期间的随机抽样创建了一个包含 25%前景和 75%背景建议的小批量。分类损失是使用小批量中所有建议的多类交叉熵损失,而定位损失仅使用正建议。为了消除重复,应用基于类的 NMS。最终输出是概率高于特定阈值(通常为 0.5)的所有预测对象的列表。

结论

有许多不同的方法来检测图像中的对象。这篇博文展示了从使用选择性搜索生成区域建议的慢速网络到更复杂的网络(如更快的 R-CNN)的历史。如果你想从物体检测入手,我推荐 Tensorflow 的物体检测 API,它主要以更快的 R-CNN 和 SSD 架构为特色。感谢阅读!

来源

[1] P. Sermanet,D. Eigen,X. Zhang,M. Mathieu,R. Fergus,Y. LeCun, Overfeat:使用卷积网络的集成识别、定位和检测CoRR ,第 abs/1312.6229 卷,2014 年。

[2] R. B. Girshick,J. Donahue,T. Darrell 和 J. Malik,精确对象检测和语义分割的丰富特征层次2014 年 IEEE 计算机视觉和模式识别会议,第 580–587 页,2014 年。

[3] R. B. Girshick, Fast r-cnn ,2015 IEEE 计算机视觉国际会议(ICCV),第 1440–1448 页,2015。

[4] S. Ren,K. He,R. B. Girshick,和 J. Sun,更快的 r-cnn:用区域提议网络实现实时对象检测IEEE 模式分析和机器智能汇刊,第 39 卷,第 1137-1149 页,2015 年。

[5]戴,李,何,孙,R-fcn: 基于区域的全卷积网络目标检测,NIPS,2016。

[6] J. Redmon,S. K. Divvala,R. B. Girshick,a .法尔哈迪,你只看一次:统一的、实时的物体检测2016 年 IEEE 计算机视觉和模式识别大会(CVPR) ,第 779–788 页,2016 年。

[7] J .雷德蒙和 a .法尔哈迪, Yolo9000:更好、更快、更强,2017 年 IEEE 计算机视觉和模式识别大会(CVPR),第 6517–6525 页,2017。

[8] W. Liu,D. Anguelov,D. Erhan,C. Szegedy,S. E. Reed,C.-Y. Fu,A. C. Berg, Ssd:单次多盒探测器,载于2016 年。**

[9] D. A. Forsyth,基于区分性训练的部件模型的物体检测IEEE 计算机,第 47 卷,第 6–7 页,2014。

[10] K. He,X. Zhang,S. Ren,和 J. Sun,用于视觉识别的深度卷积网络中的空间金字塔池IEEE 模式分析与机器智能汇刊,第 37 卷,第 1904–1916 页,2014 年。

理解部分自相关

原文:https://towardsdatascience.com/understanding-partial-auto-correlation-fa39271146ac?source=collection_archive---------6-----------------------

它是什么,如何计算,何时使用

本文将部分自相关置于透镜之下。

我们将回顾推动创建PartialAuto-Cor relationFfunction(PACF)的概念,我们将看到这些概念如何导致部分自相关定义和 PACF 公式的发展。

我将根据基本原理演示如何计算 PACF,并将结果与由stats models . TSA . stat tools . pacf()返回的值进行比较。

最后,我们将了解如何在时间序列预测中使用 PACF。

为 PACF 奠定基础:自回归时间序列

Bouncing ball in strobe light

过去影响现在的现象很多。昨天的事件可以用来预言今天将会发生什么。当这种现象被表示为时间序列时,它们被认为具有自回归特性。在自回归时间序列中,当前值可以表示为前一个值、前一个值等的函数。换句话说,当前值与来自同一时间序列的先前值相关联。

如果时间序列是自回归的,通常情况下,当前值的预测可以计算为仅前一值和一个常数的线性函数,如下所示:

(Image by Author)

这里的 T_i 是在第和第时间步由方程预测的值。 Beta0 是模型的 Y 截距,它对预测应用恒定量的偏差。它还规定了如果前一时间步 T_(i-1) 的值恰好为零,那么 T_i 的预测值是多少。β1告诉我们 T_i 改变 w.r.t. T_(i-1) 的速率。

这个简单等式背后的关键假设是, T_(i-1) 中的方差能够解释时间序列中比 T_(i-1) 更老的所有值所表示的所有方差。这就好像 T_(i-1) 捕获了与比它自身更老的值相关联的所有信息。

但是如果这个假设不成立呢?如果 T_(i-1) 中的方差不能解释 T_(i-2) 中包含的所有方差怎么办?在这种情况下,上述等式将无法将来自 T_(i-2) 的这部分未解释的方差输入到 T_i 中,从而导致 T_i 的预测出现偏差。

幸运的是,很容易解决这个问题,在上面的等式中添加一项,如下所示:

(Image by Author)

在这个等式中,额外的项β2 * T _(I-2)试图捕捉包含在比 T_(i-1) 更老的值中的方差,该方差不能由 T_(i-1) 中的方差来解释。它将这个余额数量的信息直接输入到今天的值 T_i 的预测中。

背景建立后,让我们建立部分自相关函数的定义和公式。

构建 PACF 的定义

让我们复制上面的等式以供参考:

(Image by Author)

了解 T_(i-2) 中方差的余额在预测今天的值 T_i 中有多重要是非常有用的。为什么?因为它告诉我们是否需要在我们的 T_i 预测模型中添加 T_(i-2) 作为变量。如果 T_(i-2) 中的余额方差在统计上不显著,我们可以有把握地假设,比 T_(i-2) 更早的值中的所有方差要么对预测今天的值不显著,要么它们的显著性已经在 T_(i-1) 中被捕获。无论哪种方式,它都给了我们一个理由,让我们回到更早的更简单的方程,它只包含 T_(i-1)

那么我们如何发现 T_(i-2) 中的这个差额量在预测今天的价值 T_i 中有多重要呢?很简单,我们计算两者之间的相关系数。等等,但是 T_i 不也和 T_(i-1) 相关吗?毕竟这是上面两个方程的全部基础!当然是了。因此,我们实际上想要找出的是以下两个变量之间的相关性:

变量 I:T_(i-1) 中的方差解释以外的 T_i 中的方差,以及

变量 II:T (I-2)中的方差是**未用 *T(i-1)* 中的方差解释**的量。

这种相关性称为 T_iT_(i-2)部分自相关

变量 II 的定义似乎有悖直觉。昨天的价值如何解释前天的价值?为了理解这一点,回想一下在自回归时间序列中,前天的值中的一些信息被结转到昨天的值中。这个事实——以一种听起来很奇怪的方式——使得昨天的价值成为前天价值的预测器!

对上述论证进行归纳,得出 PACF 的如下定义:

T _ I 与其自身的 k 滞后版本即 T_(i-k)的部分自相关是以下两个变量之间的相关:

变量 1:T _ I 中未被 T_(i-1)、T_(i-2)…T_(i-k+1)中的方差所解释的方差的量,并且

变量 2:T (I-k)中未被 T(i-1),T_(i-2)…T_(i-k+1)中的方差所解释的方差的量。

为 PACF 制定方案

让我们依靠我们的滞后=2 的例子来发展 PACF 公式。稍后,我们将把它推广到 LAG=k。要知道 T_(i-2) 中有多少方差没有被 T_(i-1) 中的方差解释,我们做两件事:

  1. 步骤 1: 我们用线性回归模型(即直线)拟合 T_iT_(i-1) 的分布。这个线性模型将让我们从 T_(i-1) 预测 T_i 。从概念上讲,这个线性模型允许我们将 T_i 的方差解释为 T_(i-1) 的方差的函数。但是像所有最佳拟合的模型一样,我们的模型不能解释 T_i 的所有变化。这个事实把我们带到了第二步。
  2. 第二步:在这一步中,我们计算在第一步中建立的线性模型的残差。残差是 T_i 的观测值与模型预测值之差。我们对 T_i 的每个值进行残差计算,以获得残差的时间序列。这个残差时间序列给了我们想要的东西。它给出了 T_i 中的方差,这无法用 T_(i-1) 中的方差来解释,当然还有一些噪声。

为了计算相关性中的第二个变量,即 T_(i-2) 中无法用 T_(i-1) 中的方差来解释的方差,我们在 T_(i-2)T_(i-1) 的上下文中执行上面的步骤 1 和 2,而不是分别在 T_iT_(i-1) 的上下文中执行。这给了我们寻找变量 2 的残差序列。

最后一步是将皮尔逊相关系数公式应用于这两个残差时间序列。

这是 PACF(T_i,k=2)的结果公式:

(Image by Author)

T_i|T_(i-1) 是我们在将线性模型拟合到 T_iT_(i-1) 的分布后,从步骤 1 和 2 中创建的残差时间序列。

T_(i-2)|T_(i-1) 是我们在将线性模型拟合到 T_(i-2)T_(i-1) 的分布后,从步骤 1 和 2 中创建的第二个残差时间序列。

等式的分子计算这两个剩余时间序列之间的协方差,而分母使用各自的标准偏差标准化协方差

所以你有它。这就是我们如何计算滞后=2 的 PACF。

PACF 的一般公式(X,lag=k)

在一般情况下,早于一个或两个期间的值也会对当前期间值的预测产生直接影响。因此,可以将预测 T_i 的自回归方程的一般形式写为:

The general auto-regression equation (Image by Author)

我们同样可以推广导致发展滞后=2 的 PACF 公式的论点。PACF 在滞后= k 时的公式为:

Formula for PACF at lag=k (Image by Author)

T_i|T_(i-1),T_(i-2)…T_(i-k+1) 是对 T_(i-1),T_(i-2)…T_(i-k+1) 拟合多元线性模型得到的残差时间序列,用于预测 T_i 。它代表在去除了 T_(i-1),T_(i-2)…T_(i-k+1)的影响后,在 T_i 中的剩余方差。

T_(i-k)|T_(i-1),T_(i-2)…T_(i-k+1) 是用多元线性模型拟合 T_(i-1),T_(i-2)…T_(i-k+1) 得到的残差时间序列,用于预测 T(i-k) 。它代表去除 T_(i-1),T_(i-2)…T_(i-k+1)的影响后,在 T_(i- k 中的剩余方差。

通过一个例子

让我们说到做到。我们将手动曲柄使用上述步骤在真实世界的时间序列上推出 PACF。当然,在实践中,你不必从第一原理计算 PACF。但是知道如何从头开始会让你对 PACF 的机器有一个有价值的了解。

我们将使用的真实世界时间序列是南方振荡数据集,它可以用来预测厄尔尼诺或拉尼娜事件。

Data source: NOAA (Image by Author)

我们将从设置导入开始,并将数据读入 pandas 数据帧。

**import** pandas **as** pd
**from** sklearn import linear_model
**import** matplotlib.pyplot **as** pltdf = pd.**read_csv**('southern_osc.csv', header=0, infer_datetime_format=True, parse_dates=[0], index_col=[0])

接下来,我们将向包含数据的滞后=1 和滞后=2 版本的数据框添加两列。

df['T_(i-1)'] = df['T_i'].**shift**(1)df['T_(i-2)'] = df['T_i'].**shift**(2)#drop the top two rows as they contain NaNs
df = df.**drop**(df.index[[0,1]])

现在,让我们在 T_iT_(i-1) 上拟合一个线性回归模型,并将模型的预测作为一个新列添加回数据框中。

lm = linear_model.**LinearRegression**()df_X = df[['T_(i-1)']] #Note the double brackets! [[]]df_y = df['T_i'] #Note the single brackets! []model = lm.**fit**(df_X,df_y)df['Predicted_T_i|T_(i-1)'] = lm.**predict**(df_X)

接下来,让我们创建与该模型预测相对应的残差时间序列,并将其添加到数据框中。该时间序列为我们提供了计算滞后=2 时 T_i 的 PACF 所需的两个数据序列中的第一个。

#Observed minus predicted
df['Residual_T_i|T_(i-1)'] = df['T_i'] - df['Predicted_T_i|T_(i-1)']

让我们重复上述过程来计算第二个残差时间序列,这一次使用列: T_(i-2)T_(i-1)

lm = linear_model.**LinearRegression**()df_X = df[['T_(i-1)']] #Note the double brackets! [[]]df_y = df['T_(i-2)'] #Note the single brackets! []model = lm.**fit**(df_X,df_y)df['Predicted_T_(i-2)|T_(i-1)'] = lm.**predict**(df_X)#Residual = Observed - predicted
df['Residual_T_(i-2)|T_(i-1)'] = df['T_(i-2)'] - df['Predicted_T_(i-2)|T_(i-1)']

最后,让我们将皮尔逊 r 公式应用于两个残差时间序列,以获得滞后=2 时的 PACF 值。

print(df.**corr**(method='pearson')['Residual_T_i|T_(i-1)']['Residual_T_(i-2)|T_(i-1)'])
#prints: 0.29612303554627606

如前所述,在实践中我们作弊!:=)像这样:

**from** statsmodels.tsa.stattools **import** pacfprint(**pacf**(df['T_i'], nlags=2)[2])
#prints: 0.2996545841351261

以下是完整的代码片段:

这里是链接到南方涛动数据集。

如何在时间序列预测中使用 PACF

您可以在以下方面非常有效地利用 PACF:

  1. 确定在自回归模型的预测方程中要包括多少个过去的滞后。这被称为模型的自回归(AR)阶。
  2. 确定或验证在季节性时间序列的基于移动平均的预测模型的预测方程中包括多少季节性滞后。这就是所谓的季节性移动平均线(SMA)的顺序过程。

让我们看看如何用 PACF 计算这些项。

利用 PACF 确定 AR 过程的阶数

让我们绘制不同滞后的南方涛动数据集的 PACF:

PACF plot for the Southern Oscillations data set (Image by Author)

这个情节引出了以下几点:

  1. 滞后 0 时的 PACF 为 1.0。情况总是如此。一个值总是与自身 100%相关!
  2. 滞后 1 时的 PACF 为 0.62773724。该值只是滞后 0 值和滞后 1 值之间的常规自相关。
  3. 滞后 2 时的 PACF 值为 0.29965458,这与我们手动计算的值基本相同。
  4. 在滞后 3 时,该值刚好在 95%置信区间之外。它可能重要,也可能不重要。

因此,南方涛动数据集具有 AR(2),或者可能具有 AR(3)特征。

下面是生成图表的代码片段:

**import** pandas **as** pd
**from** statsmodels.graphics.tsaplots **import** plot_pacf
**from** statsmodels.tsa.stattools **import** pacf
**import** matplotlib.pyplot **as** pltdf = pd.**read_csv**('southern_osc.csv', header=0, infer_datetime_format=True, parse_dates=[0], index_col=[0])plot_pacf(df['T_i'], title='PACF: Southern Oscillations')print(pacf(df['T_i']))

使用 PACF 确定形状记忆合金过程的顺序

考虑下面的季节性时间序列图。

Average monthly max temperature in Boston,MA from 1998- 2019 (Image by Author)

人们很自然地会认为去年一月份的最大值与今年一月份的最大值相关联。所以我们猜测季节周期是 12 个月。基于这一假设,让我们将 12 个月的单一季节差异应用于该时间序列,即我们将得出一个新的时间序列,其中每个数据点是原始时间序列中相隔 12 个周期的两个数据点的差异。这是季节性差异时间序列:

Seasonally differenced time series (Image by Author)

接下来,我们计算这个季节性差异时间序列的 PACF。这是 PACF 的地图:

PACF values of the seasonally differenced time series at various lags (Image by Author)

PACF 图显示了 12、24、36 个月的显著部分自相关,从而证实了我们的猜测,即季节周期为 12 个月。此外,这些尖峰为负的事实指向 SMA(1)过程。SMA(1)中的“1”对应于原始序列中的周期 12。因此,如果您要为此时间序列构建一个季节性 ARIMA 模型,您应该将 ARIMA 的季节性部分设置为(0,1,1)12。第一个“1”对应于我们应用的单一季节差异,第二个“1”对应于我们注意到的 SMA(1)特征。

以下是生成这些图的代码片段:

**import** pandas **as** pd
**from** statsmodels.graphics.tsaplots **import** plot_pacf
**import** matplotlib.pyplot **as** plt #load the data set
df = pd.**read_csv**('data\\boston_daily_wx_1998_2019.csv', header=0, infer_datetime_format=True, parse_dates=[0], index_col=[0])#plot it
df['Monthly Average Maximum'].**plot**()
plt.**show**()#created the LAG 12 column
df['T_(i-12)'] = df['Monthly Average Maximum'].**shift**(12)#create the differenced column
df['T_i-T_(i-12)'] = df['Monthly Average Maximum'] - df['T_(i-12)']#plot the differenced series
df['T_i-T_(i-12)'].**plot**()
plt.**show**()#drop the first 12 rows as they contain NaNs in the differenced col
df = df[12:]#plot the pacf of the differenced column
**plot_pacf**(df['T_i-T_(i-12)'], title='PACF: Seasonal Time Series')
plt.**show**()

这里是链接到数据集。

所以你有它。PACF 是一个强大的工具,是预测者工具箱中的必备工具。既然你已经知道了它的工作原理和如何解释结果,请一定要使用它,尤其是在构建 AR、MA、ARIMA 和季节性 ARIMA 模型时。

预测快乐!

相关阅读

[## 相关性背后的直觉

两个变量相关到底意味着什么?我们将在本文中回答这个问题。我们还将…

towardsdatascience.com](/the-intuition-behind-correlation-62ca11a3c4a)

如果你喜欢这篇文章,请关注我的Sachin Date获取回归、时间序列分析和预测主题的技巧、操作方法和编程建议。

理解 PCA(主成分分析)

原文:https://towardsdatascience.com/understanding-pca-fae3e243731d?source=collection_archive---------1-----------------------

Photo by Margaret Weir on Unsplash

我们发现主成分分析如何帮助我们揭示数据中的潜在趋势

在数据科学和金融(以及几乎任何定量学科)中,我们总是在大量噪音中寻找信号。现在,如果有一个算法可以为我们做到这一点…

有!今天,我们将探索 PCA(主成分分析)如何帮助我们发现隐藏在数据中的潜在驱动因素——这是一个非常有用的功能,因为它允许我们仅使用几个主成分来总结庞大的功能集。

如果你对我用来生成下面图表的代码感兴趣,你可以在我的 GitHub 上找到它 这里

变化既是我们的敌人,也是我们的朋友

如果你花了一些时间阅读统计学或数据科学教科书,你会注意到,我们费尽周折建立模型的主要原因是为了解释方差。

但是这到底意味着什么呢?让我们一步一步地解开这个。首先,我们所说的方差实际上指的是什么?想象我们的数据是这样的:

A Flat Line Has Zero Variance

你在想,“托尼,你为什么给我看一条直线?这太无聊了。”这正是问题的关键。如果我们的数据只是一条平坦的线,那么预测起来会非常容易(只是一直预测五条),但也完全没意思。扁平线是零方差数据的一个例子,数据中绝对没有垂直变化。

现实生活中有什么零方差数据的例子?这听起来很荒谬,但是让我们假设你的老板让你预测一栋五层楼的楼层数。所以在 100 天的每一天,你都要测量这个建筑的层数,最后你会得到上面的图表,一条直线。当你的老板回来问你的预测时,你自信地说“我预测明天大楼仍然有五层楼高!”火箭科学对吗?

除非发生灾难,否则你有 100%的可能是正确的。但是你的所作所为毫无意义——没有方差的数据没有不确定性,所以我们没有什么可以预测或解释的,它就是这样。如果我们试图使用方差为零的变量作为模型中的 X 变量(以预测方差非零的目标变量),我们会因为特征集中信号的绝对缺乏而变得非常沮丧。

那么有方差的数据是什么样的呢?以下是苹果股票 100 天的每日价格回报(百分比):

100 Days of AAPL Daily Returns

现在我们有东西可以利用了。不出所料,我们的苹果股票回报数据中存在大量的方差— 方差基本上就是数据上下波动的幅度。它越有弹性,就越难预测或解释。苹果的日回报率大幅反弹,在正值和负值之间来回波动,包括一些大幅飙升。

但是在这些噪音中,有弹性的数据也包含信号(也就是信息)。

与没有方差的数据相比,弹性数据作为模型的目标变量比有趣得多,作为模型内部的特征变量有用得多。

这就是为什么我说变化既是我们的敌人也是我们的朋友:

  • 它是我们的敌人,因为我们的目标变量中更多的变化会产生不确定性,使目标更难预测或解释。
  • 但它也是我们的朋友,因为正如我们上面看到的,没有方差的特征是完全没有意思的,根本不包含任何信号。因此,为了有机会建立一个好的模型,我们需要具有信号的特征,或者换句话说,具有方差的特征(实际上,更具体地说,我们想要与目标具有非零协方差的特征)。

用主成分捕获信号

我们生活在一个信息太多而不是太少的世界。数据科学也是如此——几乎总是有一大堆潜在特征可供我们用来做出预测。

尽管我们很想这样做,但我们不可能把它们都用上。我们只是没有足够的观察值-当我们只有目标变量的 5000 个观察值时,使用 10,000 个特征来拟合模型将是一个可怕的想法。我们最终会得到一个严重过度拟合的模型,一旦我们试图在真实世界中运行该模型(基于真正的样本数据),该模型就会崩溃。

但是如果没有领域专业知识和建模经验(有时即使有),也很难决定哪些特性真正值得保留在我们的模型中。现在,如果有一种算法可以将我们的 10,000 个特征转换成一组理想的特征就好了。

理想的功能集

如果我们可以从头开始创建一个理想的特性集,这个集将具有什么属性?我建议它具有以下三个特性:

  1. 方差大:方差大的特征包含了大量的潜在信号——信号(又称有用信息)是建立好模型的基本要求。
  2. 不相关:彼此高度相关的特征用处不大,在某些情况下甚至是有害的(当相关性高到导致多重共线性)。要明白为什么会这样,假设你雇佣了一屋子有才华的股票交易者。你希望他们都以相似还是不同的方式投资?如果是我,我更希望他们彼此尽可能不同——这创造了一种多样化的效果,交易者互相保护,避免犯错,你几乎不会遇到所有人同时犯错的情况。
  3. 没有那么多:相对于我们的目标变量观测值,我们希望有少量的特征。相对于观察值的太多特征将导致过度拟合模型,该模型在样本外表现不佳。

PCA(主成分分析)给了我们一套理想的特征。它创建一组按方差排序的主成分(第一个成分比第二个成分方差大,第二个成分比第三个成分方差大,依此类推)、不相关、数量少(我们可以丢弃排序较低的成分,因为它们包含的信号很少)。

PCA 是怎么做到的?

那么它是如何产生如此神奇的效果的呢?有线性代数的解释或者直觉的解释。我们在这里会选择直观的,但是如果你想检查数学,这篇博文很棒

PCA 通过反复询问和回答以下问题来发挥其魔力:

  1. 在该过程的最开始,PCA 询问特征集中最强的潜在趋势是什么(我们称之为组件 1)?我们将在后面以多种方式形象化这一点,所以如果现在还不清楚,请不要担心。
  2. 接下来,PCA 询问特征集中第二强的潜在趋势是什么,它恰好与组件 1(我们称之为组件 2)不相关?
  3. 然后 PCA 询问特征集中第三强的潜在趋势是什么,它恰好与成分 1 和成分 2 都不相关(我们称之为成分 3)?
  4. 诸如此类…

它是如何发现这些潜在趋势的?如果你曾经谷歌过 PCA,你很可能看到过类似下图的东西:

PCA Simple Example

在图中,我们的数据是黑点。那么最强的潜在趋势是什么呢?我们可以把它当作一个线性回归问题来处理,最强的趋势是最佳拟合线(蓝线)。所以蓝线是组件 1。你可能会问为什么蓝线是分量 1 而不是红线?记住,分量 1 是具有最高方差的主分量(因为最高方差等于最高潜在信号)。

线性回归连接很有用,因为它帮助我们认识到每个主成分都是单个特征的线性组合。就像线性回归模型是与我们的目标变量最接近的特征的加权和一样,主成分也是我们特征的加权和。除了在这种情况下,它们是最能表达我们特征集中潜在趋势的加权和。

回到我们的例子,我们可以直观地看到,蓝线比红线捕捉到更多的差异,因为蓝色勾线之间的距离比红色勾线之间的距离长。标记线之间的距离是我们的主成分捕获的方差的近似值-黑点越多,我们的数据沿着主成分的轴变化,它捕获的方差就越多。

现在对于成分 2,我们想要找到第二强的潜在趋势,附加条件是它与成分 1 不相关。在统计学中,相互正交的趋势和数据是不相关的。

Orthogonal Data

看看左边的那块地。我绘制了两个特征,一个用蓝色,另一个用红色。如你所见,它们是相互垂直的。蓝色特征的所有变化都是水平的,而红色特征的所有变化都是垂直的。因此,当蓝色要素改变(水平)时,红色要素完全保持不变,因为它只能垂直改变。

很好,所以为了找到分量 2,我们只需要找到一个方差尽可能大的分量,它也和分量 1 正交。由于我们之前的 PCA 示例非常简单,只有两个维度,因此对于组件 2,我们只有一个选项,即红线。事实上,我们可能有大量的功能,所以当我们搜索组件时,我们需要考虑许多方面,但即使这样,过程也是一样的。

一个将这一切联系在一起的例子

让我们回到之前的股票例子。除了苹果股票,我还下载了代表多个行业的 30 只不同股票的数据。如果我们画出他们所有的日收益(100 天,同上),我们会得到下面这张混乱的图表:

100 Days of Stock Returns for 30 Different Stocks

每只股票都在做自己的事情,除了每天的股票回报是嘈杂和不稳定的之外,从这张图表中没有太多可以收集的信息。让我们使用 sci-kit learn 来计算主成分 1,然后绘制它( PCA 对你的特征的相对比例很敏感——因为我的所有特征都是每日股票回报,我没有缩放数据,但在实践中,你应该考虑使用标准缩放器最小最大缩放器)。下图中的黑线是组件 1:

Stock Returns with PCA Component 1 (In Black)

所以黑线代表了我们股票回报中最强的潜在趋势。“这是什么?”,你问?好问题,不幸的是,没有一些领域的专业知识,我们不知道。这种解释的损失是使用类似 PCA 的东西来将我们大得多的特征集减少到一个更小的关键底层驱动集的主要缺点。除非我们运气好,或者仅仅是数据专家,否则我们不会知道每一个主成分分析的成分意味着什么。

在这种情况下,我会猜测第一部分是标准普尔 500——在我们所有的股票回报数据中,最强的潜在趋势可能是整体市场,其涨跌会影响每只股票的价格。让我们通过绘制标准普尔 500 的每日收益与第一部分的对比来验证这一点。考虑到数据的噪音,这几乎是完美的匹配!标准普尔 500 指数的日收益率和主成分 1 的相关性为 0.92。

The S&P 500 and Component 1 are Extremely Correlated

所以就像我们猜测的那样,我们股票数据中最重要的潜在趋势是股票市场。PCA 的 scikit-learn 实现还告诉我们每个组件解释了多少差异——组件 1 解释了我们特征集中总差异的 38%。

让我们来看看另一个主成分。下面,我绘制了组件 1(黑色)和 3(绿色)。正如所料,它们之间的相关性很低(0.08)。与组件 1 不同,组件 3 仅解释了我们特征集中 9%的差异,远低于组件 1 的 38%。不幸的是,我不知道成分 3 代表什么——这就是 PCA 缺乏解释来咬我们的地方。

Principal Components 1 and 3

结论

在这篇文章中,我们看到了 PCA 如何帮助我们揭示数据中的潜在趋势——这是当今大数据世界中一种非常有用的能力。PCA 很棒,因为:

  1. 它将潜在信号隔离在我们的特征集中,以便我们可以在我们的模型中使用它。
  2. 它将大量的特征简化为一组更小的关键潜在趋势。

然而,缺点是当我们通过 PCA 运行我们的特征时,我们失去了许多可解释性。如果没有领域专业知识和大量猜测,我们可能不知道除了前一两个组件之外的任何组件代表什么。

但一般来说,这不是一个交易破坏者。如果您确信在您的大量特征中有充足的信号,那么 PCA 仍然是一种有用的算法,它允许您提取大部分信号用于您的模型,而不必担心过度拟合。

如果你总体上喜欢这篇文章和我的写作,请考虑通过我在这里的推荐链接注册 Medium 来支持我的写作。谢谢!

理解概率。终于!

原文:https://towardsdatascience.com/understanding-probability-finally-576d54dccdb5?source=collection_archive---------6-----------------------

数据科学家概率概念图解实用指南

虽然您已经使用随机森林、逻辑回归、K-means 聚类、支持向量机甚至深度学习解决了日常生活中的实际问题,但在本次复习结束时,您将能够自信地谈论概率。

source

本文温和地介绍了数据科学和机器学习背后的概率概念。每一个概念都通过真实的例子被小心地介绍和说明,同时尽可能地避免数学和定理。

作为一名数据科学家,你将最终确定结果、事件、随机变量、概率分布、期望、均值和方差等概念。

本杰明·富兰克林曾经说过,生命中有两件事是确定的:死亡和纳税。

许多人可能会进一步扩展这一主张,断言这些是唯一确定的事情。生活的其余部分是最不可预测的。

然而,我们可以争辩说,即使是不可避免的死亡也可能不像我们想象的那样确定,因为我们并不总是知道它将在何时、何地以及如何发生。

我们如何处理随机现象?凭信念还是凭理智?

信念是对不需要任何证据且被认为无法通过任何经验或理性手段证明的事情的真实性的绝对信念。

理性是思维的能力,通过它我们可以逻辑地得出理性的结论。

虽然信念是冷静处理随机现象的好工具,但理性给了我们学习我们观察到的范围、平均值或可变性的方法。

理性允许我们从更大范围的观察中推断出结构、变化和关系。我们还可以尝试预测未来、可能性,并保证我们对结果有多确定。

推理方法带来了一些好处,比如理解潜在的观察结果,提前计划事情如何变化,以及构建提供最确定结果的东西。

打破不确定性

当我们观察周围的世界并收集数据时,我们正在进行一项实验。一个简单的例子是抛硬币,同时观察它是正面还是反面落地。一个更复杂的例子是试用一个软件,观察我们愿意为它的完整版本支付多少钱。这些实验的所有可能结果构建了所谓的样本空间,表示为ω。

source

在硬币的例子中,样本空间有两个元素:头部和尾部。这是一个离散样本空间,与软件示例中的连续样本空间形成对比。在后一种情况下,为软件支付的金额可以是任何正实数。在这两种情况下,我们都在进行一个概率实验,结果未知 X ,也称为随机变量

在抛硬币实验中,如果硬币正面落地, X 将得到值 h ,否则将得到值 t 。如果实验重复多次,我们通常将随机变量 X 得到小 x 的概率定义为小 x 发生的次数的分数。

概率作为一个函数

在抛硬币的情况下,如果我们用一枚公平的硬币进行足够长时间的实验,几乎无数次,我们将期望正面或反面落地的概率是 1/2。头部或尾部着地的概率都是非负的,总和为 1。

因此,我们可以将概率视为一个函数,它获取一个结果,即样本空间中的一个元素,并将该结果映射到一个非负实数,使得所有这些数字的总和等于 1。我们也把这个叫做概率分布函数

当我们知道了样本空间和概率分布,我们就有了实验的完整描述,我们可以对不确定性进行推理。

均匀概率分布中,样本空间中的所有结果将具有相同的发生概率。我们的抛硬币案例就是这样一个例子。另一个例子是纸牌游戏,从一副标准的 52 张牌中挑出一张给定牌的概率是 1/52。

source

非均匀分布将不同的概率映射到不同的结果或一组结果。下面的饼图展示了一个很好的例子,其中每个类别代表一个结果,比例代表概率。

source

当出现多种结果时

一组结果也被称为概率事件。比如我们掷骰子,所有偶数的集合就是一个事件。如果包含已发生的结果,则发生事件。因此,如果我们掷出数字 4,事件就发生了。

当实验重复多次时,事件的概率将是事件发生次数的分数。例如,如果我们投掷骰子 10 次,我们得到以下数字 5,3,2,3,2,1,4,6,5,2,那么,奇数事件的概率是 5/10=1/2。

如果我们重复掷骰子无数次,则事件的概率将是我们得到偶数的次数的分数,这是 2、4 或 6 次发生的分数之和,这给出了 1/6+1/6+1/6=3/6=1/2。

source

替换或不替换的采样

有时我们可能想多次重复同样的经历,就像抛硬币一样。当重复实验时,一个常见的假设是一个实验的结果对其他实验的结果没有任何影响。换句话说,这些实验是独立的。

source

在现实生活中,我们经常从更大的人群中选择事物并进行分析。有以下两种方法:带替换的采样,不带替换的采样。

当我们用替换顺序选择时,结果可以重复,实验是独立的。

在下面的例子中,我们从一个装有两个球的瓶子中取出两个球,一个是黄色的,另一个是蓝色的。

source

如果我们从罐子里选择了没有替换的,结果就不会重复,实验也是相互依赖的。

source

在迄今为止的所有例子中,顺序确实很重要。有时候顺序并不重要,我们只关心集合。我们不是处理可能结果的元组,而是处理可能结果的集合。

例如,如果我们抛硬币两次,我们可以得到(正面,反面)或(反面,正面)的结果。当顺序无关紧要时,两种结果都会构建事件{(head,tail),(tail,head)}。

现在让我们看看另一种情况,我们从一副有 6 张替换牌的牌中选择 2 张。当顺序很重要时,我们有一个均匀分布,这意味着所有可能的元组(1,1),(1,2),…,(6,6,)都有相同的出现概率 1/36。

然而,当顺序无关紧要时,分布不再均匀,如下图所示。

source

让我们重复同样的实验,这次不用替换。现在,分布是均匀的,如下所示。顺序和抽样方法会对概率产生重大影响。

source

当结果是数字时

一个随机变量将是一个随机结果,其值是数字。研究数字(随机变量)而不是结果有几个好处。

我们可以控制头的数量、尾的数量或者两者之和,而不是把头和尾看作事件。此外,随机变量的概率可以显示在图中,也可以表示为具有特定属性的函数。

随机变量从样本空间中取值。如果样本空间是有限的,比如一组数{1,2,3},那么我们处理的是一个离散随机变量

当样本空间是无限的,比如ℝ,那么我们就有了一个连续随机变量。下面你可以看到一个离散随机变量的例子,它描述了在一个投掷三枚公平硬币的实验中的人头数。

source

上面的表格和图表描述了一个离散随机变量的概率质量函数(PMF) ,它也可以用直方图表示。

在连续随机变量的情况下,显然 PMF 不可能是一致的,也不可能是增函数。然而,它可以是一个递减函数或双无限函数。

区间概率

有时我们对计算随机变量的概率感兴趣,这个随机变量的值小于或等于某个阈值。

累积分布函数(CDF) 允许我们操纵区间概率,如下例所示。

source

我们应该期待什么

为了研究随机变量的不确定性,我们还对可能值的范围、最小值和最大值、范围平均值、元素平均值和样本平均值感兴趣。

特别是,样本均值是我们将来可能观察到的平均值的期望值。样本均值或期望值是一个随机变量的平均值,按概率加权。

下面我们有一个温度分布,大多数时间观察到 0 度。在 10 个温度值的样本中,我们获得样本平均值 19 度,这告诉我们可能观察到的平均温度的概念。

source

当样本数量趋于无穷大时,我们期望看到一个称为随机变量的期望值均值的值,如下所示。也表示为 μ

预期寿命实际上是期望的一个很好的例证。下面我们可以看到发达国家人口统计数字的预期在 50 年内是如何变化的。

source (2017)

与期望值的差异

在我们知道期望什么之后,我们现在可以看看随机变量将如何不同于期望值或均值。具有相同平均值的两个样本可能看起来非常不同。

这些变化由随机变量的方差捕获,该方差被定义为随机变量 X 与其均值 μ 之间的绝对差的期望值。

因为绝对值不容易分析,尤其是它的微分在零处是不可能的,所以方差是使用差的平方来计算的。

标准偏差被定义为方差的平方根。

当所有事情同时发生时

在现实生活中,样本空间是多个变量的组合。如果我们要向学生发送广告,我们可能要考虑他们的年级、学习年份和专业,以便向每个特定的受众传递正确的信息。

source

因此,给定 2 个或更多随机变量,我们考虑所谓的联合分布,其给出变量在样本空间中可以取的每个可能的值元组的概率。

联合分布足以计算边际概率,即单个变量取特定值的概率。

我们应该知道什么

随机变量通常属于流行的分布的族,它们被很好地研究过,并给我们的生活带来便利。

与连续分布相比,离散分布描述了具有可数结果的随机变量。

最简单的非平凡随机变量将取两个可能的值,例如 1 和 0,代表成功和失败,或头和尾。伯努利分布定义了成功概率 p ,以及失败概率 q=1-p 。当进行几个这样的独立二元实验时,给定结果序列的概率很容易计算为各个概率的乘积。

source

二项式分布定义了 n 次独立伯努利试验中特定次数成功的概率,其中成功概率为 p 。它可用于研究临床试验中的阳性应答者数量,或成功转化为付费客户的营销线索数量。

泊松二项式分布是二项式分布的变体,其中成功的概率是不固定的。

source

泊松分布近似二项式分布,表示成功的小概率 p 对于大量的试验 n. 例如,研究患有罕见疾病感染的人数、点击广告的网站访问者人数、垃圾邮件回复数、每日紧急呼叫数、全市人口中逛商店的人数、购买画作的画廊访问者人数非常有用。

source

当我们以成功概率 p 重复独立的伯努利试验时,直到我们观察到成功的试验次数 n 遵循几何分布。例如,侵入计算机系统之前所需的黑客攻击次数和成功开展业务之前的创业公司数量将呈几何分布。

source

在许多情况下,随机变量的值来自一个无限的空间,有无数个可能的值。例如,诸如飞行持续时间、寿命持续时间的时间变量,或者诸如表面和高度的空间相关变量;或者与质量相关的变量,例如重量;或者温度。

这里甚至可以考虑几乎可数的数量,如房屋成本、产品价格、利率和失业率。

在所有这些情况下,我们不再使用概率质量函数。相反,我们应该使用所谓的概率密度函数(PDF)

指数分布将几何分布扩展为连续值。例如,电话呼叫的持续时间、客户拨打客户服务热线的等待时间以及车辆的寿命都可以用参数为λ的指数分布来描述。

source

最流行的是正态高斯分布,这通常适用于添加许多独立因素的情况。它描述了已知平均值和标准差的值的概率。例子包括人们的身高和体重,以及工资。

source

下表总结了连续分布的概率密度函数、均值和方差。

source

结论

在本文中,我们提供了大多数数据科学家想要掌握的概率概念的通俗易懂的复习。我们超越了掷骰子,直观地说明了如何使用结果、事件、样本空间、分布函数、累积函数、随机变量、期望和方差来量化和分析不确定性。

在这篇文章中,我们使用了加州大学圣地亚哥分校的 Alon Orlitsky 教授的教学材料。他和 AdaBoost 算法的发明者 Yoav Freund 教授一起提供了一个关于概率和统计的免费课程。如果您想更深入地了解本文介绍的概念,我们强烈建议您参加本课程。

条件概率不包括在内;也不是贝叶斯方法的本质特征,贝叶斯方法的本质特征是在基于统计数据分析的推理中明确使用概率来量化不确定性。

我们在下面的文章中温和地介绍贝叶斯数据分析。

[## 贝叶斯噩梦。解决了!

通过 Python PyMC3 中的示例和代码对贝叶斯数据分析进行了温和的介绍。

towardsdatascience.com](/bayesian-nightmare-how-to-start-loving-bayes-1622741fa960)

感谢阅读。

了解 Python 虚拟环境

原文:https://towardsdatascience.com/understanding-python-virtual-environments-7ccf690320d7?source=collection_archive---------10-----------------------

使用 VR 的 Python 虚拟环境介绍

A man is using three screens at once. Photo by Maxim Dužij on Unsplash

不,看这篇文章不需要 VR 眼镜。只要一袋注意力和兴奋就够了。

如果您是数据科学和 python 领域的新手,虚拟环境可能看起来是一个非常复杂的想法——但事实恰恰相反。它简单易懂,使用起来更简单!如果你以前体验过虚拟现实(VR),你也会有一个良好的开端(例如,玩虚拟现实游戏或出于任何目的尝试虚拟现实眼镜)。这篇文章涵盖了从什么是环境到设置和使用虚拟环境的所有内容!

什么是环境?

人类的环境可以指他们的周围环境——他们居住的地方。对于像 python 这样的编程语言来说,环境的概念是类似的。对于安装在计算机上的 python,计算机就是它的环境。它通常被称为“本地”环境,因为语言也可以在服务器上运行(服务器只是在数据中心运行的计算机,可以通过互联网访问)。

什么是虚拟环境?

你体验过虚拟现实或者看到有人体验过吗?如果没有,这里有一个例子:

Photo by Hammer & Tusk on Unsplash

回想一下人类对环境的定义——他们的周围环境。对于上面照片中的人来说,他们的周围就是他通过镜头看到的东西。对他来说,现实的概念(在一定程度上)已经从他用肉眼看到的变成了他现在感知到的。

python 的虚拟环境是一个类似的想法:你在一个环境(你的计算机)中给它一个单独的“环境”,并允许它在那里运行。

然而,人类的虚拟现实体验和 python 的虚拟现实体验之间有一些关键的区别。首先,你可以为 python 创建多个虚拟环境(你可以认为 python 有无限多的脸,而人类只有一张脸,所以 python 可以戴任意多的 VR 眼镜)。其次,虽然人类仍然可以触摸和感受“真实”环境中的物体,但 python 不一定能做到这一点。当你戴上 python 的 VR 眼镜时,它可能会也可能不会访问“真实”的环境(取决于你的设置,对于这篇文章来说有点太高级了)。因此,在虚拟环境中,安装在您的计算机上的所有库和包(也称为真实环境)都是不可访问的,反之亦然。

我为什么要关心?

好吧,这听起来很酷,但是虚拟环境的目的是什么?为什么要把酷炫的 VR 眼镜交给枯燥复杂的编程语言?

方便。稳定。安心。不是为了编程语言,而是为了作为程序员的你。注意不同的项目可能需要不同版本的库,甚至可能需要不同的语言?这就是虚拟环境有用的地方。这个想法是为每个项目创建一个单独的虚拟环境。

因为一种语言的资源(库、包等)对真实环境和其他虚拟环境是隐藏的,所以版本之间没有干扰和冲突。例如,假设您在项目 A 的虚拟环境中更新了库 X。因为您在项目 A 的虚拟环境中更新了库 X,所以您可以确保这不会导致库 X 在任何其他环境中更新。因此,您的代码及其在其他地方的依赖项不受影响。

好的,我如何制作一个虚拟环境?

对于这个故事,我将介绍 virtualenv 库,但是有许多不同的(也许更好的)方法来创建 python 虚拟环境。我还将使用 Mac,这是一个基于 UNIX 的系统。因此,如果您的计算机使用不同的系统,步骤可能会有所不同。

您的系统上可能没有安装 virtualenv。您可以使用以下命令进行检查:

virtualenv --version

如果您安装了 virtualenv,“终端”将打印您系统上安装的 virtual env 版本(如 16.4.3)。否则,它会给你一个“命令未找到”的错误。如果是这种情况,请输入以下命令:

pip install virtualenv

PS:如果你没有 pip ,可以为你的系统下载。默认情况下,它包含在 Python 3.4 或更高版本的二进制安装程序中。

接下来,导航到您想要创建虚拟环境的目录。您可以只为环境创建另一个目录,并使用以下命令切换到该目录:

mkdir Environments && cd Environments

这将创建一个名为“环境”的新文件夹,并在终端中打开该目录。您现在已经准备好为 python 创建 VR 体验了。要创建环境,请使用以下命令

virtualenv project_name 

上面的命令在当前工作目录中创建了一个名为“project_name”的环境。将“项目名称”替换为您的项目名称。完成上述步骤后,您的终端窗口应该看起来像这样:

Terminal screen after creating the virtual environment.

但是,虚拟环境尚未激活。每当您想要进入环境或激活它(也就是戴上眼镜)时,您需要运行以下命令:

source project_name/bin/activate

Tada!你现在在你的虚拟环境中。你如何确认你确实在一个虚拟环境中?您的终端将在所有行中以 project_name 为前缀,如下所示:

Terminal screen after activating python virtual environment

就是这样!您已经成功学习、创建并激活了一个 python 虚拟环境。现在,您可以在这个虚拟环境中处理您的项目。您可以像在普通终端上一样安装库,只是这些库将安装在虚拟环境中,而不是“真实”环境中。您可以使用以下命令退出虚拟环境,以“注销”虚拟环境:

deactivate

进一步学习的资源:

你还没有完全发现虚拟环境的世界。您可能想探索许多有趣的事情:

这个故事比较了不同的 python 虚拟环境工具(回想一下,我只展示了 virtualenv):

[## 比较 Python 虚拟环境工具

设置 Python 虚拟环境的各种工具

towardsdatascience.com](/comparing-python-virtual-environment-tools-9a6543643a44)

这是一篇非常适合虚拟环境专家的文章:

[## 如何管理多个 Python 版本和虚拟环境🐍

2019 年 1 月补充:如果你在升级到 macOS Mojave 后回到这个博客,请查看这个 github 问题…

medium.freecodecamp.org](https://medium.freecodecamp.org/manage-multiple-python-versions-and-virtual-environments-venv-pyenv-pyvenv-a29fb00c296f)

以下文章讨论了与虚拟环境相关的最新发展:

[## 再见虚拟环境?

如果您是 Python 开发人员,您可能听说过虚拟环境—“一个自包含的目录树…

medium.com](https://medium.com/@grassfedcode/goodbye-virtual-environments-b9f8115bc2b6)

我希望这篇文章能帮助您理解什么是虚拟环境,并让您开始使用它们。如果您有任何问题,请不要犹豫回应这个故事或联系我。祝 Python 虚拟现实愉快!

通过示例了解 PyTorch:分步指南

原文:https://towardsdatascience.com/understanding-pytorch-with-an-example-a-step-by-step-tutorial-81fc5f8c4e8e?source=collection_archive---------0-----------------------

Photo by Allen Cai on Unsplash

更新(2021 年 5 月 18 日):今天我已经完成了我的书: 深度学习用 PyTorch 循序渐进:入门指南

更新(2022 年 2 月 23 日):平装版现已上市(三册)。更多详情请查看pytorchstepbystep.com

更新(2022 年 7 月 19 日):第一卷《基础》的西班牙语版现已在 Leanpub 上发布。

介绍

PyTorch发展最快的深度学习框架, Fast.ai 在其 MOOC、深度学习 for Coders 及其中也使用了该框架。

PyTorch 也非常 Python 化,也就是说,如果你已经是 Python 开发者,使用它会感觉更自然。

此外,根据安德烈·卡帕西的说法,使用 PyTorch 甚至可以改善你的健康状况

动机

有很多 PyTorch 教程,它的文档非常完整和广泛。所以,为什么要一直看这个循序渐进的教程?

好吧,尽管人们可以找到关于 PyTorch 能做的几乎所有事情的信息,但我错过了从基本原理的结构化方法中得到结构化的方法。

在这篇文章中,我将引导你了解 PyTorch 使用 Python 构建深度学习模型变得更加简单和直观的主要原因,包括亲笔签名的模型、动态计算图、模型类和更多,我还将向你展示如何避免常见的陷阱

此外,由于这是一篇很长的文章,我建立了一个 T2 目录 T3,如果你把它作为 T4 的迷你课程 T5,一次一个主题地浏览内容,会使浏览更容易。

目录

简单的回归问题

大多数教程都是从一些好看的图像分类问题开始,来说明如何使用 PyTorch。这看起来很酷,但我相信它会分散你对主要目标的注意力。

为此,在本教程中,我将坚持使用一个简单的熟悉的问题:一个线性回归 与一个单一特征 x !没有比这更简单的了…

Simple Linear Regression model

数据生成

让我们开始生成一些合成数据:我们从我们的特征 x 的 100 个点的向量开始,并使用 a = 1b = 2 和一些高斯噪声来创建我们的标签

接下来,让我们将我们的合成数据分割训练验证集合,洗牌指数数组并使用前 80 个洗牌点进行训练。

Generating synthetic train and validation sets for a linear regression

Figure 1: Synthetic data — Train and Validation sets

我们知道a = 1 和 b = 2,但是现在让我们看看通过使用梯度下降训练 集合中的 80 个点,我们能多接近真实值…

梯度下降

如果你对梯度下降的内部工作方式很熟悉,可以跳过这一部分。完全解释梯度下降是如何工作的已经超出了这篇文章的范围,但是我将涵盖计算梯度下降需要经历的四个基本步骤

第一步:计算损失

对于一个回归问题,损失均方差(MSE) 给出,即标签 (y)和预测 (a + bx)之间所有平方差的平均值。

值得一提的是,如果我们使用训练集中的所有点(N)来计算损失,我们正在执行批次梯度下降。如果我们每次都使用一个单点,这将是一个随机梯度下降。在 1 和 N 之间的任何其他(n) 表示小批量梯度下降。

Loss: Mean Squared Error (MSE)

第二步:计算梯度

一个梯度是一个偏导数为什么 偏导数?因为它是相对于(w.r.t .)一个单个 参数来计算的。我们有两个参数, ab ,所以必须计算两个偏导数。

一个导数告诉你一个给定的 量变化多少当你稍微* 变化一些其他量。在我们的例子中,当我们改变两个参数中的每一个时,我们的 MSE 损耗变化了多少?*

下面等式的最右边的部分是你通常在简单线性回归的梯度下降实现中看到的。在中间步骤中,我向您展示应用链式法则弹出的所有元素,这样您就知道最终表达式是如何产生的。

Computing gradients w.r.t coefficients a and b

步骤 3:更新参数

在最后一步,我们使用渐变来更新参数。由于我们试图最小化我们的损失,我们反转梯度的符号用于更新。

还有另一个需要考虑的参数:学习率,用希腊字母 eta (看起来像字母 n )表示,这是我们需要应用于梯度的乘法因子,用于参数更新。

Updating coefficients a and b using computed gradients and a learning rate

如何选择一个学习率?这是一个独立的话题,也超出了本文的范围。

第四步:冲洗,重复!

现在我们使用更新的** 参数返回到步骤 1 并重新开始该过程。**

每当每个点已经用于计算损失时,一个历元完成。对于批次梯度下降,这是微不足道的,因为它使用所有点来计算损失——一个历元一个更新相同。对于随机梯度下降,一个历元表示 N 个 更新,而对于小批量(尺寸 N),一个历元N/n 个更新

一遍又一遍地重复这个过程,对于许多时代,简而言之就是训练一个模型。

数字线性回归

是时候使用 Numpy only 使用梯度下降实现我们的线性回归模型了。

等一下…我以为这个教程是关于 PyTorch 的!

是的,但这有两个目的:第一,介绍我们任务的结构,它将基本保持不变,第二,向您展示主要的难点,这样您就可以充分体会 PyTorch 让您的生活变得多么轻松:-)****

为了训练一个模型,有两个初始化步骤:

  • 参数/权重的随机初始化(我们只有两个, ab ) —第 3 行和第 4 行;
  • 超参数的初始化(在我们的例子中,只有学习率周期数 ) —第 9 行和第 11 行;****

确保总是初始化你的随机种子,以确保你的结果的再现性。像往常一样,随机种子是 42 ,一个人可能选择的所有随机种子中最不随机的:)**

对于每个时期,有四个训练步骤😗***

  • 计算模型的预测—这是正向传递 —第 15 行;
  • 使用预测标签和手头任务的适当损失函数计算损失——第 18 和 20 行;****
  • 计算每个参数的梯度——第 23 和 24 行;
  • 更新参数—第 27 行和第 28 行;

只要记住,如果你使用批量梯度下降(我们的例子使用了),你将不得不写一个内循环来执行四个训练步骤用于每个个体点 ( 随机)或 n ( 小批量)。稍后我们将看到一个小批量的例子。**

Implementing gradient descent for linear regression using Numpy

只是为了确保我们没有在代码中犯任何错误,我们可以使用 Scikit-Learn 的线性回归来拟合模型并比较系数。

**# a and b after initialization
[0.49671415] [-0.1382643]
# a and b after our gradient descent
[1.02354094] [1.96896411]
# intercept and coef from Scikit-Learn
[1.02354075] [1.96896447]**

它们匹配多达 6 位小数——我们有一个使用 Numpy 的完全工作的线性回归实现。**

时间到了火炬它:-)

PyTorch

首先,我们需要涵盖一些基本概念,如果你在全力建模之前没有很好地掌握它们,这些概念可能会让你失去平衡。

在深度学习中,我们随处可见张量。嗯,Google 的框架叫 TensorFlow 是有原因的!究竟什么是张量?

张量

Numpy 中,你可能有一个数组三个维度吧?也就是从技术上来说,一个张量

一个标量(单个数)有个零维,一个向量 维,一个矩阵有两个维,一个张量有三个或更多个维。就是这样!

但是,为了简单起见,通常也称向量和矩阵为张量——所以,从现在开始,所有东西要么是标量,要么是张量

Figure 2: Tensors are just higher-dimensional matrices 😃 Source

加载数据、设备和 CUDA

你会问,我们如何从 Numpy 的数组到 PyTorch 的张量?这就是[**from_numpy**](https://pytorch.org/docs/stable/torch.html#torch.from_numpy)的好处。不过,它返回一个 CPU 张量。

但是我想用我的花式 GPU… ”你说。别担心,这就是[**to()**](https://pytorch.org/docs/stable/tensors.html#torch.Tensor.to)的用处。它将你的张量发送到你指定的任何设备,包括你的 GPU (简称cudacuda:0)。**

"如果没有可用的 GPU,我希望我的代码回退到 CPU,该怎么办?你可能想知道……py torch 又一次支持了你——你可以使用[**cuda.is_available()**](https://pytorch.org/docs/stable/cuda.html?highlight=is_available#torch.cuda.is_available)来查找你是否有 GPU 供你使用,并相应地设置你的设备。**

您还可以使用[float()](https://pytorch.org/docs/stable/tensors.html#torch.Tensor.float)轻松地将转换为较低的精度(32 位浮点)。

Loading data: turning Numpy arrays into PyTorch tensors

如果您比较两个变量的类型,您将得到您所期望的:第一个变量为numpy.ndarray,第二个变量为torch.Tensor

但是你的张量“住”在哪里呢?在你的 CPU 还是你的 GPU 里?你不能说……但是如果你用 PyTorch 的**type()**,它会揭示它的位置torch.cuda.FloatTensor —这里是一个 GPU 张量。

我们也可以反过来,使用[**numpy()**](https://pytorch.org/docs/stable/tensors.html?highlight=numpy#torch.Tensor.numpy),将张量转换回 Numpy 数组。应该和x_train_tensor.numpy() 一样简单,但是

**TypeError: can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.**

不幸的是,Numpy 不能处理 GPU 张量……你需要先用[**cpu()**](https://pytorch.org/docs/stable/tensors.html#torch.Tensor.cpu)让它们成为 CPU 张量。

创建参数

用于数据张量与用作(可训练 ) 参数/权重张量有何区别?****

后面的张量需要计算其梯度,因此我们可以更新它们的值(即参数值)。这就是**requires_grad=True**论点的好处。它告诉 PyTorch 我们希望它为我们计算梯度。

你可能想为一个参数创建一个简单的张量,然后发送到你选择的设备,就像我们对数据所做的那样,对吗?没那么快…

Trying to create variables for the coefficients…

第一段代码为我们的参数、梯度和所有的东西创建了两个很好的张量。但他们是 CPU 张量。

**# FIRST
tensor([-0.5531], requires_grad=True)
tensor([-0.7314], requires_grad=True)**

在第二段代码中,我们尝试了将它们发送到 GPU 的简单方法。我们成功地将它们发送到了另一个设备上,但是我们不知何故“丢失”了梯度

**# SECOND
tensor([0.5158], device='cuda:0', grad_fn=<CopyBackwards>) tensor([0.0246], device='cuda:0', grad_fn=<CopyBackwards>)**

在第三块中,我们首先将我们的张量发送到设备,然后使用[**requires_grad_()**](https://pytorch.org/docs/stable/tensors.html#torch.Tensor.requires_grad_)方法将其requires_grad设置到True位置。

**# THIRD
tensor([-0.8915], device='cuda:0', requires_grad=True) tensor([0.3616], device='cuda:0', requires_grad=True)**

在 PyTorch 中,每一个以一个下划线 ( _ )结束的方法都会就地修改,也就是说,它们将修改底层变量。****

虽然最后一种方法工作得很好,但是最好是在创建张量分配给设备

Actually creating variables for the coefficients 😃

tensor([0.6226], device='cuda:0', requires_grad=True) tensor([1.4505], device='cuda:0', requires_grad=True)

简单多了,对吧?

现在我们知道了如何创建需要梯度的张量,让我们看看 PyTorch 如何处理它们——这是……

亲笔签名

亲笔签名的是 PyTorch 的自动微分包。多亏了它,我们不需要担心关于偏导数,链式法则或者任何类似的东西。

那么,我们如何告诉 PyTorch 去做它的事情并且计算所有的梯度?这就是[**backward()**](https://pytorch.org/docs/stable/autograd.html#torch.autograd.backward)的好处。

你还记得计算梯度起点吗?当我们计算它相对于我们的参数的偏导数时,它是损失。因此,我们需要从相应的 Python 变量中调用backward()方法,比如loss.backward().

****坡度实际值是多少?我们可以通过查看张量的[**grad**](https://pytorch.org/docs/stable/autograd.html#torch.Tensor.grad) 属性来考察它们。

如果你检查该方法的文档,它清楚地说明了梯度是累积的。所以,每次我们使用渐变更新参数时,我们需要将渐变归零。这就是[**zero_()**](https://pytorch.org/docs/stable/tensors.html#torch.Tensor.zero_)的好处。

方法名末尾的下划线** ( _ )是什么意思?你还记得吗?如果没有,请返回到上一节并找出答案。**

因此,让我们放弃****手动** 计算梯度并使用backward()zero_()方法来代替。**

就这样?嗯,差不多吧…但是,总有一个抓手,这次和参数更新有关…

在第一次尝试中,如果我们使用与我们的 Numpy 代码中相同的更新结构,我们将会得到下面奇怪的错误…但是我们可以通过查看张量本身得到一个关于正在发生什么的提示——我们再次“丢失”****梯度,同时将更新结果重新分配给我们的参数。因此,**grad**属性变成了**None**,并引发了错误…

# FIRST ATTEMPT
tensor([0.7518], device='cuda:0', grad_fn=<SubBackward0>)
AttributeError: 'NoneType' object has no attribute 'zero_'

然后我们稍微改变一下,在第二次尝试中使用熟悉的就地 Python 赋值。PyTorch 再一次对此进行了抱怨,并引发了一个错误

# SECOND ATTEMPT
RuntimeError: a leaf Variable that requires grad has been used in an in-place operation.

为什么?!原来是“过犹不及”的情况。罪魁祸首是 PyTorch 从每一个 Python 操作中构建一个动态计算图的能力,该操作涉及任何梯度计算张量其依赖关系

我们将在下一节更深入地研究动态计算图的内部工作原理。

那么,我们如何告诉 PyTorch 去“后退”并让我们更新我们的参数而不弄乱它的花哨的动态计算图?这就是[**torch.no_grad()**](https://pytorch.org/docs/stable/autograd.html#torch.autograd.no_grad)的好处。它允许我们独立于 PyTorch 的计算图对张量、执行常规的 Python 操作。****

最后,我们成功地运行了我们的模型,并获得了结果参数。毫无疑问,它们与我们在 Numpy 唯一实现中得到的相匹配。

# THIRD ATTEMPT
tensor([1.0235], device='cuda:0', requires_grad=True) tensor([1.9690], device='cuda:0', requires_grad=True)

动态计算图

“不幸的是,没有人能被告知动态计算图是什么。你得自己去看。”摩耳甫斯

"黑客帝国"有多伟大?对吧。但是,玩笑归玩笑,我想让也自己看看图表

PyTorchViz 包和它的*make_dot(variable)*方法允许我们轻松地可视化与给定 Python 变量相关的图形。

因此,让我们坚持使用最小量:两个(梯度计算 ) 张量用于我们的参数、预测、误差和损失。

Computing MSE in three steps

如果我们调用**make_dot(yhat)**,我们将得到下面图 3 中最左边的****图😗***

Figure 3: Computation graph for every step in computing MSE

让我们仔细看看它的组件:

  • 蓝框:这些对应于我们用作参数张量,我们要求 py torch计算梯度的那些张量;****
  • 灰框:一个 Python 操作,涉及一个梯度计算张量它的依赖;****
  • 绿框:与灰框相同,除了它是计算渐变的起点(假设**backward()**方法是从用于可视化图形的变量调用的)——它们是从图形中的自下而上开始计算的。****

如果我们为**error**(中间)和**loss**(右边)变量绘图,它们与第一个变量唯一的区别中间步骤** ( 灰色方框)的数量。**

现在,仔细看看最左边图的绿框:有两个** 箭头指向它,既然是两个 变量ab*x。似乎很明显,对吧?**

然后再看同图的灰色** 方框:它正在执行一个乘法,即b*x。但是只有一个箭头指向它!箭头来自与我们的参数 b 对应的蓝色 。**

为什么没有一个盒子放我们的数据 x ?答案是:我们不为它计算梯度!因此,尽管计算图执行的操作中涉及到更多的张量,但它显示了梯度计算张量的依赖关系。**

如果我们为我们的参数 a** 设置**requires_grad****False**,计算图会发生什么?**

Figure 4: now variable a does NOT have its gradient computed anymore. But it is STILL used in computation

不出所料,参数 a** 对应的蓝框没了!很简单:没有渐变,没有图形。**

关于动态计算图最好的事情是,你可以让它如你所愿一样复杂。你甚至可以使用控制流语句(例如 if 语句)来控制渐变的流(显然!) 😃

下面的图 5 显示了一个例子。是的,我知道计算本身完全是无意义的

Figure 5: Complex computation graph just to make a point 😃

【计算机】优化程序

到目前为止,我们一直在使用计算出的梯度手动更新参数。这对两个参数的来说可能没问题……但是如果我们有一大堆参数呢?!我们使用 PyTorch 的优化器**之一,比如 SGD 或者 Adam******

一个优化器接受我们想要更新的参数,我们想要使用的学习率(可能还有许多其他超参数!)和执行通过其[**step()**](https://pytorch.org/docs/stable/optim.html#torch.optim.Optimizer.step)方法更新

此外,我们也不再需要一个接一个地将梯度归零。我们只需调用优化器的[**zero_grad()**](https://pytorch.org/docs/stable/optim.html#torch.optim.Optimizer.zero_grad)方法,仅此而已!

在下面的代码中,我们创建一个随机梯度下降 (SGD)优化器来更新我们的参数 ab

不要被优化器的名字所迷惑:如果我们一次使用所有训练数据进行更新——正如我们在代码中实际做的那样——优化器正在执行一个批处理梯度下降,尽管它的名字如此。

PyTorch’s optimizer in action — no more manual update of parameters!

让我们检查我们的两个参数,之前和之后,只是为了确保一切仍然工作正常:

# BEFORE: a, b
tensor([0.6226], device='cuda:0', requires_grad=True) tensor([1.4505], device='cuda:0', requires_grad=True)
# AFTER: a, b
tensor([1.0235], device='cuda:0', requires_grad=True) tensor([1.9690], device='cuda:0', requires_grad=True)

酷!我们已经优化了优化流程:-)还剩下什么?

失败

我们现在处理损失计算。不出所料,PyTorch 又一次掩护了我们。根据手头的任务,有许多损失函数可供选择。由于我们的是回归,我们使用的是均方误差(MSE)损失

注意*nn.MSELoss*实际上为我们创建了一个损失函数它不是损失函数本身。此外,您可以指定一个要应用的归约方法,即您希望如何合计单个点的结果** —您可以将它们平均(归约= '均值')或简单地将它们相加(归约= '总和')。**

然后我们使用创建的损失函数,在第 20 行,计算给定我们的预测和我们的标签的损失。

我们的代码现在看起来像这样:

PyTorch’s loss in action — no more manual loss computation!

此时,只剩下一段代码需要修改:预测。然后是时候介绍 PyTorch 实现一个…****

模型

在 PyTorch 中,一个模型由一个从 模块 类继承的常规 Python 类表示。

它需要实现的最基本的方法是:

  • **__init__(self)** : 它定义了组成模型的部件——在我们的例子中,是两个参数ab**

您不局限于定义参数,尽管……模型也可以包含其他模型(或层)作为其属性,因此您可以轻松地嵌套它们。我们很快也会看到这样的例子。

  • [**forward(self, x)**](https://pytorch.org/docs/stable/nn.html#torch.nn.Module.forward):在给定输入 x 的情况下,执行实际计算,即输出预测

不过,你不应该把叫做 ***forward(x)***方法。你应该调用整个模型本身,就像在***model(x)***中执行正向传递和输出预测一样。

让我们为我们的回归任务建立一个合适的(然而简单的)模型。它应该是这样的:

Building our “Manual” model, creating parameter by parameter!

__init__方法中,我们定义了我们的两个参数ab ,使用[**Parameter()**](https://pytorch.org/docs/stable/nn.html#torch.nn.Parameter)类告诉 PyTorch 这些张量应该被认为是模型的参数,它们是的一个属性。

我们为什么要关心这个?通过这样做,我们可以使用我们模型的[**parameters()**](https://pytorch.org/docs/stable/nn.html#torch.nn.Module.parameters)方法来检索所有模型参数甚至嵌套模型的那些参数的迭代器,我们可以使用这些参数来馈送我们的优化器(而不是我们自己构建一个参数列表!).

此外,我们可以使用我们模型的[**state_dict()**](https://pytorch.org/docs/stable/nn.html#torch.nn.Module.state_dict)方法获得所有参数的当前值。

重要的:我们需要将我们的模型发送到数据所在的同一个设备。如果我们的数据是由 GPU 张量构成的,那么我们的模型也必须“生活”在 GPU 中。****

我们可以使用所有这些方便的方法来更改我们的代码,代码应该是这样的:

PyTorch’s model in action — no more manual prediction/forward step!

现在,打印出来的语句看起来像这样——参数 ab 的最终值仍然相同,所以一切正常:-)

**OrderedDict([('a', tensor([0.3367], device='cuda:0')), ('b', tensor([0.1288], device='cuda:0'))])
OrderedDict([('a', tensor([1.0235], device='cuda:0')), ('b', tensor([1.9690], device='cuda:0'))])**

我希望你注意到了代码中的一个特殊语句,我给它分配了一个注释“这是什么?!?"— **model.train()**

在 PyTorch 中,模型有一个[***train()***](https://pytorch.org/docs/stable/nn.html#torch.nn.Module.train)方法,有点令人失望的是,没有执行训练步骤。其唯一目的是将模型设置为训练模式。为什么这很重要?例如,一些模型可能使用类似 退出 的机制,这些机制在培训和评估阶段具有不同的行为。

嵌套模型

在我们的模型中,我们手动创建了两个参数来执行线性回归。让我们使用 PyTorch 的 线性 模型作为我们自己的属性,从而创建一个嵌套模型。

尽管这显然是一个虚构的例子,因为我们几乎包装了底层模型,而没有添加任何有用的东西(或者根本没有!)对它来说,它很好地说明了这个概念。

**__init__**方法中,我们创建了一个属性,它包含了我们的嵌套 **Linear** 模型

**forward()**方法中,我们调用嵌套模型本身来执行正向传递(注意,我们是 而不是 调用 *self.linear.forward(x)* )。**

Building a model using PyTorch’s Linear layer

现在,如果我们调用这个模型的**parameters()**方法, PyTorch 将以递归的方式计算其属性的参数。您可以自己尝试使用类似于:[*LayerLinearRegression().parameters()]的代码来获得所有参数的列表。你也可以添加新的Linear属性,即使你在向前传球中根本不使用它们,它们也会仍然列在parameters()下。

序列模型

我们的模型足够简单…您可能会想:“为什么还要费心为它构建一个类呢?!"嗯,你说得有道理…**

对于使用普通层简单模型,其中一层的输出作为输入被顺序地馈送到下一层,我们可以使用一个,呃… 顺序 模型:-)

在我们的例子中,我们将建立一个带有单个参数的序列模型,也就是我们用来训练线性回归的Linear层。该模型将如下所示:

**# Alternatively, you can use a Sequential model
model = nn.Sequential(nn.Linear(1, 1)).to(device)**

很简单,对吧?

训练步骤

到目前为止,我们已经定义了一个优化器,一个损失函数和一个模型。向上滚动一点,快速查看循环中的代码。如果我们使用不同的优化器,或者损失,甚至模型,会不会改变?如果不是,我们如何使更通用**

嗯,我想我们可以说所有这些代码行执行一个训练步骤,给定那些三个元素 ( 优化器、损耗和模型)特性标签

那么,编写一个函数,将这三个元素作为参数,返回另一个执行训练步骤的函数,并返回相应的损失,这样如何?

然后我们可以使用这个通用函数构建一个**train_step()** 函数,在我们的训练循环中调用。现在我们的代码应该看起来像这样…看看训练循环现在有多小?

Building a function to perform one step of training!

让我们休息一下我们的训练循环,暂时关注一下我们的数据…到目前为止,我们只是简单地使用了我们的 Numpy 数组PyTorch 张量。但是我们可以做得更好,我们可以建立一个…

资料组

在 PyTorch 中,数据集由从 数据集 类继承的常规 Python 类表示。你可以把它想象成一种 Python 元组列表,每个元组对应一个点(特性,标签)

它需要实现的最基本的方法是:

  • **__init__(self)** :它采用构建一个元组列表所需的任何参数——它可能是将要加载和处理的 CSV 文件的名称;可能是两个张量,一个是特征,一个是标签;或者其他什么,取决于手头的任务。**

在构造函数方法 ( __init__)中不需要加载整个数据集。如果您的数据集很大(例如,成千上万的图像文件),一次加载它将不会是内存高效的。建议按需加载(每当__get_item__被调用时)。****

  • **__get_item__(self, index)**:它允许数据集被索引,因此它可以像列表 ( dataset[i])一样工作——它必须返回一个对应于所请求数据点的元组(特征,标签)。我们可以返回我们的预加载的数据集或张量的对应切片,或者如上所述,按需加载 它们(就像这个示例)。****
  • **__len__(self)**:它应该简单地返回整个数据集的大小,这样,无论何时对它进行采样,它的索引都被限制为实际大小。

让我们构建一个简单的自定义数据集,它采用两个张量作为参数:一个用于要素,一个用于标注。对于任何给定的索引,我们的数据集类将返回每个张量的相应切片。它应该是这样的:

Creating datasets using train tensors

再一次,你可能会想"为什么要大费周章地在一个类中包含几个张量呢?”。而且,再一次,你确实有一个观点…如果一个数据集只是一对张量的,我们可以使用 PyTorch 的 TensorDataset 类,它将做我们在上面的自定义数据集中所做的事情。****

你是否注意到我们用 Numpy 数组构建了我们的训练张量,但是我们没有将它们发送到设备?所以,他们现在是 CPU 张量!为什么是

我们不希望我们的整个训练数据被加载到 GPU 张量中,就像我们到目前为止在我们的示例中所做的那样,因为会占用我们宝贵的显卡 RAM 中的空间。****

好吧,好吧,但是话说回来,我们为什么要建立数据集呢?我们这样做是因为我们想用一种…****

数据加载器

到目前为止,我们在每个训练步骤中都使用了整体训练数据。一直是批次梯度下降。当然,这对我们小得可笑的数据集来说没问题,但是如果我们想要认真对待这一切,我们必须使用小批量梯度下降。因此,我们需要小批量。因此,我们需要相应地分割我们的数据集。要不要手动?!我也没有!

所以我们使用 PyTorch 的 DataLoader 类来完成这项工作。我们告诉它使用哪个数据集(我们刚刚在上一节中构建的那个),期望的小批量以及我们是否想要洗牌。就是这样!

我们的加载器将表现得像一个迭代器,所以我们可以循环遍历它并且每次获取一个不同的小批量

Building a data loader for our training data

要检索小批量样本,只需运行下面的命令,它将返回包含两个张量的列表,一个用于要素,另一个用于标注。

next(iter(train_loader))

这如何改变我们的训练循环?我们去看看吧!

Using mini-batch gradient descent!

现在有两件事情不同了:不仅我们有一个内循环来从我们的DataLoader加载每个小批量,更重要的是,我们现在只发送一个小批量到设备

对于更大的数据集,使用数据集的 **__get_item__**逐个样本地加载数据** (到 CPU 张量中),然后将属于同一小批量的所有样本一次发送到您的 GPU** (设备)是为了让最好地利用您的显卡 RAM 。****

此外,如果您有许多 GPU 来训练您的模型,最好保持您的数据集“不可知”,并在训练期间将批处理分配给不同的 GPU。

到目前为止,我们只关注了训练 数据。我们为它构建了一个数据集和一个数据加载器。我们可以对验证数据做同样的事情,使用我们在这篇文章开始时执行的分割…或者我们可以使用random_split来代替。

随机分裂

PyTorch 的[**random_split()**](https://pytorch.org/docs/stable/data.html#torch.utils.data.random_split)方法是执行训练-验证分割的一种简单而熟悉的方式。请记住,在我们的示例中,我们需要将它应用到整个数据集 ( 不是我们在前面两节中构建的训练数据集)。

然后,对于每个数据子集,我们构建一个相应的DataLoader,因此我们的代码看起来像这样:

Splitting the dataset into training and validation sets, the PyTorch way!

现在我们有了一个数据加载器用于我们的验证集,所以,用它来…

估价

这是我们旅程的最后部分——我们需要改变训练循环,以包括对我们的模型评估,即计算验证损失。第一步是包括另一个内部循环来处理来自验证加载器小批量,将它们发送到与我们的模型相同的设备。接下来,我们使用我们的模型(第 23 行)进行预测,并计算相应的损失(第 24 行)。

这就差不多了,但是还有两个小一个大,要考虑的事情:

  • [**torch.no_grad()**](https://pytorch.org/docs/stable/autograd.html#torch.autograd.no_grad):尽管在我们的简单模型中不会有什么不同,但是用这个上下文管理器包装验证内部循环来禁用您可能无意中触发的任何梯度计算是一个良好实践,因为梯度属于训练,而不属于验证步骤;
  • [**eval()**](https://pytorch.org/docs/stable/nn.html#torch.nn.Module.eval):它唯一做的事情就是将模型设置为评估模式(就像它的train()对应的那样),这样模型就可以调整它关于一些操作的行为,比如

现在,我们的训练循环应该是这样的:

Computing validation loss

T21,我们还有什么可以改进或改变的吗?当然,总会有其他东西添加到你的模型中——例如,使用 学习速率调度器 。但是这个帖子已经太长了,所以我就停在这里。****

包含所有附加功能的完整工作代码在哪里?“你问什么?你可以在这里 找到

最后的想法

虽然这篇文章比我开始写它时预期的长得多,但我不会让它有任何不同——我相信它有大多数必要的步骤,以一种结构化的方式学习 T42,如何使用 PyTorch 开发深度学习模型。

希望在完成这篇文章中的所有代码后,你能够更好地理解 PyTorch 的官方教程

更新(2021 年 5 月 18 日):今天我已经完成了**我的书: 深度学习用 PyTorch 循序渐进:入门指南 **

更新(2022 年 2 月 23 日):平装版现已上市(三册)。更多详情请查看pytorchstepbystep.com

更新(2022 年 7 月 19 日):第一卷《基础》的西班牙语版现已在 Leanpub 上发布。

Deep Learning with PyTorch Step-by-Step

如果您有任何想法、意见或问题,请在下方留言或联系我 推特

理解量子计算机

原文:https://towardsdatascience.com/understanding-quantum-computers-ecb9d375b46f?source=collection_archive---------26-----------------------

随着我们寻求探索未知领域,并将人类的影响范围从亚原子粒子扩大到遥远的星球,对计算能力的渴望与日俱增。量子计算机可能是这些需求的答案。

尽管没有必要去研究经典计算机来理解量子计算机是如何工作的,但是计算机是如何进化的以及围绕量子计算机有如此多的误解是非常有趣的,我发现有必要去研究经典计算机是如何变成今天的样子以及它们与量子计算机有什么关系。

“电脑”。这个词现在可能看起来不那么特别了,见鬼,它变得如此流行,以至于当人们说他们不知道如何使用计算机时,这看起来很奇怪。电脑无处不在,它们几乎可以放在任何地方——从你的膝盖到你的手(或者在你的手里!!!)但情况并非总是如此。坐在你腿上的电脑在 19 世纪可能无法适应整个世界,在 20 世纪下半叶也只能勉强适应足球场。这种变化是如何发生的,这很有趣。让我们简要地看一下计算机的发展历程,但在此之前,让我们先定义一下什么是计算机。

大多数人都知道什么是计算机,但对他们来说很难定义它。从这个词最基本的意义上来说,计算机是任何可以计算的东西,也就是说,可以做简单的算术计算,下面是来自维基百科的一个更正式的定义:

计算机是一种可以通过计算机编程指令自动执行一系列算术或逻辑运算的装置。现代计算机有能力遵循被称为程序的广义操作集。这些程序使计算机能够执行非常广泛的任务。包括硬件、操作系统(主软件)和用于“完整”操作所需的外围设备的“完整”计算机可称为计算机系统。该术语也可用于连接并一起工作的一组计算机,特别是计算机网络或计算机集群。

The Difference Engine

尽管现代计算机的旅程始于 20 世纪,但早在 19 世纪人们就感受到了对这种机器的需求,伟大的发明家/科学家们也尝试着制造这种机器。机械计算机就是在那个时候设计出来的(最著名的是由查尔斯·巴贝奇,第一个程序是由包括阿达·洛芙莱斯女士在内的许多人编写的。但是一些计算机仅仅是在设计中构思出来的,因为它们远远超出了当时的技术水平,而且非常昂贵,我们最好使用人类来代替。巴贝奇的计算机是在 20 世纪 90 年代由美国加州山景城的历史博物馆建造的,这里有一个好视频展示了巴贝奇设计的实际差分机。

然后重点转移到机电计算机和电线,水银用于穿孔卡和 IBM(国际商业机器)的出现,计算机变得越来越好,现在可以执行非常复杂的计算,这进一步加速了两次世界大战,军事上需要计算机来获得战略优势。但是这些仍然不足以满足不断增长的计算需求,因此计算机变得越来越大。更大的计算机意味着更复杂的结构,管理它们变得越来越困难。(有趣的事实:正是在这个时候,bug 会飞入这些计算机,导致结果出现问题,因此在现代计算机科学中使用了单词“ bugs ”。

Alan Turing help build an electro-mechanical device, “The Bombe” to help decipher German Enigma-machine-encrypted secret messages during World War II.

随着电子晶体管的引入,这一切都改变了,现在计算机开始缩小,它们的潜力现在已经为人所知,大量的激烈竞争(加上许多科幻小说)导致了越来越小的计算机的发展,这都归功于晶体管尺寸的缩小。每个人都注意到了这一点,但戈登·摩尔浓缩了这一观察,并将其公式化——“密集集成电路上的晶体管数量每两年翻一番”。

被称为摩尔定律的定律多年来都是正确的(现在仍然如此),但摩尔定律有一个问题:晶体管不能一直缩小,它们必然会遇到量子效应,当量子物理出现时,就会有大量的不确定性(明白吗!).计算机需要对答案有绝对的把握,否则计算机就不会很有用。

摩尔定律是指在密集集成电路中,晶体管的数量大约每两年翻一番。这一观察结果是以飞兆半导体(Fairchild Semiconductor)联合创始人兼英特尔(Intel)首席执行官戈登·摩尔的名字命名的,他在 1965 年的论文中描述了每个集成电路的组件数量每年翻一番,并预测这一增长速度将至少再持续十年。1975 年,展望下一个十年,他将预测修改为每两年翻一番。由于英特尔高管大卫·豪斯(David House)的预测(更多晶体管和更快晶体管的综合效应),这一时期通常被称为 18 个月。

根据目前的估计,晶体管将在 2024 年左右停止变得更小。由于在此期间,单个晶体管将足够小,量子效应将非常显著,如果我们要制造晶体管,任何更小的量子效应都将发挥作用,因此传统(或经典)计算方法将停止其在性能改善方面的指数增长。

为了克服性能增强中的这一障碍,我们可以使用新型计算,也称为量子计算。量子计算可以帮助我们在几秒钟内完成大量的计算。这有助于解决传统计算机以前无法解决的问题。许多人以此为论据,说这是量子计算机是必要的原因之一,它们可以帮助取代经典计算机,但这是完全错误的。我们将会看到,它们存在和需要的原因要复杂得多,也更令人着迷。

以上信息(以及许多其他东西)可以在这个 YouTube 课程中以更详细、更结构化的方式找到。

进入量子世界

量子计算机不是来取代经典计算的,这不是它们的本意。它们与经典计算机非常不同,有自己的计算方式。在我们用经典计算机解决的大多数问题上,它们可能永远无法打败普通计算机。那为什么需要他们?

原因是量子计算机是为了解决一些更大的问题而不是为了在网上看猫视频()。量子计算机可以用来解决经典计算机无法解决的问题。像破解 RSA 加密这样的问题,以及像量子建模这样需要量子解决方案的问题。实际上,(伟大的物理学家理查德·费曼)构想的量子计算机的第一个应用是研究量子粒子。因为,如果我们可以用数学方法模拟一个量子粒子,然后在计算机中创建它的模拟,那么我们就可以对它们进行各种实验,否则这是不可能的。

那么这些问题是什么呢?为什么我们的普通电脑不能帮上忙呢?有些问题需要极大的计算能力和空间,例如寻找超大素数的因子、模拟分子、模拟量子现象等。在计算机科学中,我们将问题分成不同的类别,这取决于当我们增加输入值的数量时,它们是如何增长的(例如,需要多少计算)。这些被称为多项式时间,不确定多项式时间和 np 难问题。对于很少的输入,经典计算机可以解决 NP 问题,但是对于大的 N 值,计算时间变得很长,因此计算变得不可行。但是有些问题是 NP 级别的,但是仍然可以在有限的时间内通过量子计算机解决。这些问题被称为 B 舍入误差 Q 量子 P 奥林匹克时间问题。但是到目前为止,这类问题是有限的,你最好在经典计算机上解决这些问题,而不是在量子计算机上。但是有些问题(比如大数的质因数分解)只能由量子计算机解决(尽管是非常强大的)。

The Problem Hierarchy

为了理解计算机,我们首先看一下它的构成材料,即硅,然后我们从二极管到门到寄存器,再到更复杂的体系结构,如可以执行更复杂计算的 alu 和 CPU,然后我们在它上面放一个抽象层,为它编写程序,指导它执行我们希望它执行的任务。我们将用类似的方法来理解量子计算机的内部工作原理。但在此之前,我们需要了解量子计算机利用的一些奇怪的物理现象。

先决物理学

量子物理学本身是一门极其庞大和有趣的学科,但要理解量子计算机我们不需要完全理解它,我们只需要看看一些量子现象(即量子纠缠和量子叠加),并对概念进行抽象理解,以理解量子计算机的工作。

量子叠加是一种非常反直觉的物理现象,它表明电子等量子粒子可以同时出现在一个以上的状态,即一个电子可以同时处于两个地方,也可以同时具有不同的动量或能量。这在我们的日常生活中是观察不到的,因为一个东西应该只在一个地方,如果它同时出现在许多地方,那就违反了经典物理定律。但是这对于量子粒子来说确实是可能的,因为它们具有双重性,即类波性和类粒子性。量子粒子据说同时是波和粒子(需要注意的是,“同时”只是为了理解,因为在量子世界中没有时间或现实的概念),因此具有双重性质。现在波有这个叠加原理,你可能知道,也就是说,两个波可以相互叠加产生另一个波。这是根据维基百科对量子叠加的定义:

它指出,就像经典物理学中的波一样,任何两个(或更多)量子态可以加在一起(“叠加”),结果将是另一个有效的量子态;相反,每个量子态都可以表示为两个或更多不同态的总和。数学上是指薛定谔方程解的一个性质;由于薛定谔方程是线性的,任何解的线性组合也将是一个解。

这里有一个来自狄拉克的书【1】的关于量子叠加的更数学的解释:

  1. 考虑两个状态 A 和 B 的叠加,通过观察得到结果 A 和 B。
  2. 根据叠加过程中 A 和 B 的相对权重的概率定律,对处于叠加状态的系统进行的观察有时是 A,有时是 B。

为了更好地理解量子叠加,你可能想看看量子叠加 wiki 页面的附带视频,我发现那个视频对理解量子叠加很有帮助。如果你仍然有困难,这里有一个很棒的视频解释了量子叠加,或者看看这个 quora 线程来进一步理清你的理解

Quantum Effects

量子纠缠是最令人着迷的量子现象之一,这也是爱因斯坦对量子力学持怀疑态度并将其称为“幽灵般的超距作用”的原因之一。

假设你有两个粒子在一个孤立的宇宙中创造出能量,现在让我们考虑它们的角动量,它们的角动量之和应该是常数(角动量守恒定律)。假设它们相距很远,那么它们的角动量之和应该是相同的(因为角动量是守恒的)。例如,如果一个粒子向上,那么另一个粒子应该在相反的方向。现在让我们考虑一下,我们测量第一个粒子的自旋,发现它是向上的,那么其他粒子的自旋一定是向下的(角动量守恒),借助于一些未知的通道相互接触(假设),或者它们正在用比光更快的东西进行通信(因为物理学这是不可能的)。

Quantum Entanglement gif

我发现上面的思想实验对于理解为什么量子纠缠如此怪异非常有用,但是这里有一个关于量子纠缠的更的正式定义:

量子纠缠是一种物理现象,当成对或成组的粒子以某种方式产生、相互作用或共享空间接近度时,即使粒子相距很远,每个粒子的量子状态也无法独立于其他粒子的状态来描述。

量子纠缠已经用光子、中微子、电子、像巴基球一样大的分子,甚至小钻石进行了实验演示。纠缠在通信和计算中的应用是一个非常活跃的研究领域。这里有一个好视频把量子纠缠和量子叠加都解释的很清楚。

尽管量子纠缠看起来很奇怪,但它仍然有效,这是量子计算机的关键所在,已经有许多实验证明量子纠缠确实存在,中国在 2011 年发射了一颗卫星(名为 Micius ),以促进使用量子纠缠进行通信,并在 2017 年进行了一次视频会议。

了解了上述信息,我们现在可以进一步了解量子计算机的内部工作原理。我们将从信息存储和检索开始,看看如何利用量子效应进行计算。然后我们看看这些工具是如何组合在一起制造量子逻辑门的。然后,这些门可以组合起来进行更复杂的计算。然后我们可以将抽象层层叠加,最终得到量子计算机的最终模型。

量子位

在传统的计算机中,信息是以比特的形式存储的,这些二进制二进制 T2 三进制 T4 可以代表 0 或 1 的状态,我们已经开发了相当复杂的系统,仅仅通过使用这种简单的存储形式,但是我们仍然可以用一个比特做得更好,不像比特只能存储 0 和 1,量子比特可以存储第三种也是非常重要的状态,即 0 和 1 的叠加。这种状态的叠加有助于量子计算机做经典计算机可能做不到的事情。当一个量子位处于其中一个叠加态时,可以说它同时处于 0 和 1 两种状态,但实际情况并非如此。例如,假设你向北移动了 3 米,然后向西移动了 4 米,现在你在西北方向上 5 米,或者你在北方和西方的叠加上。换个说法——“你同时在北和西!”听起来不再那么美味了,是吗?量子态的叠加也是如此。即使一个量子位不处于 1 或 0 状态中的任何一个,但是它处于例如 80% 1 状态和 40% 0 状态。因此,它同时处于两种状态的叠加。

这里有一个很好的答案解释了量子比特如何同时持有 0 和 1?

一个量子位通常是由硅和磷组成的,有时是由光子组成的!人们还试图利用原子核的自旋来制造量子位。但是,是什么让量子位不同于经典位呢?答案在于量子叠加原理。让我们考虑一个例子

假设你现在有两个比特,它们可以是00, 01, 10, 11,也就是说,它们可以是四种状态中的一种。现在考虑两个量子比特,它们可以是- (↑,↑),(↓,↓),((↓,↓) + (↓,↓))或者((↓,↓)-(↓,↓),其中,+和-表示要么相干要么消相干叠加如图所示。

现在假设上述每个状态的概率由α,β,γ,δ给出。现在有趣的部分来了,量子位不在这些状态中的任何一个,而是在这些状态的叠加中。即,它的状态是

α(↑,↑) + β((↓,↑)-(↑,↓)) + γ((↓,↑)+(↑,↓)) + δ(↑,↑)

因此,如果我们现在执行计算,我们实际上将同时对所有这些状态执行计算,而不是单独对每个状态执行计算,从而显著提高某些算法的性能。

States of a two qubit system

量子位最令人印象深刻的一点是,增加计算能力并不需要太多。因此,举例来说,你想要将上述系统的计算能力加倍以表示 8 个状态,现在要做到这一点,我们只需要再增加一个量子位,从而使所表示的状态的数量加倍。现在,假设我们需要用经典比特来表示上述系统,为此我们需要四个单独的状态(由比特组成),现在要加倍它,即表示 8 个状态,我们需要加倍状态,即 4 个以上的表示。因此,为了让经典计算机的计算能力翻倍,我们需要让它的体积翻倍。但是对于已经很庞大的超级计算机来说,这是不切实际的。但是有了量子计算机,你只需增加一个量子位就可以逃脱。

即使原则上我们可以同时进行这些操作,我们也不可能测量这些状态,因为一旦我们测量了这些状态,叠加态就被破坏了。因此,实际上,我们只能得到一个答案,如果我们测量一个量子位,我们很可能会得到一个无用的随机答案。为了解决这个问题,我们设计了这样一种算法,即错误的状态相互干扰并相互抵消,而正确的答案通过干扰得到提升(正如在 shor 的算法中所做的)。最后,留给我们的答案是正确的可能性大于错误的可能性。这可以通过量子傅立叶变换来实现。这里有一个很棒的视频来理解量子算法是如何工作的。

信息存储和检索

计算机做的最重要的事情之一是读取和写入数据,因为如果可能的话,它可以做任何事情,如艾伦·图灵所示。图灵机的概念在量子计算机中得到了进一步的发展,已经提出了量子图灵机。让我们了解一下量子计算机是如何读写数据的。

States of a two qubit system

量子位嵌入在晶体管中。现在所有的量子位都有能量,假设我们有一个处于向下状态的电子,那么它会有低能量,现在用一个精确的微波(精确的意思是在正确的位置以正确的频率)我们可以给那个电子足够的能量使它向上旋转。这将导致晶体管中电压的变化,我们现在可以说,在此基础上,它确实增加了。因此,我们已经将一个量子位的状态从 0 改变为 1,并且我们现在已经成功地写入了一个量子位。

从一个量子位中读取也是类似的,但是我们必须记住,这并不容易,我们不能仅仅有一个好的微波发生器和从/向量子位中读取/写入。由于在室温下,量子粒子有太多的能量,它会产生随机的模式,但我们需要非常精确的模式,所以我们需要将物质冷却到几乎零开尔文,这样我们就可以记录量子位数据。这里有一个由 veritasium 制作的精彩视频,非常详细地说明了上述内容。

大局

已经了解了量子位的读写等基本操作,我们现在可以理解量子计算机如何执行逻辑运算了。这是借助量子门完成的。量子逻辑门是在少量量子位上运行的基本量子电路。它们是量子电路的组成部分,就像传统数字电路中的经典逻辑门一样。但与经典门不同的是,量子门有一个奇特的性质——它们是可逆的。这意味着输入可以产生输出,反之亦然。例如,知道一个非门的输出是 1,我们就知道输入必须是 0。类似地,如果我们知道输出是 0,那么输入一定是 1。因此,非门是可逆的。

量子门必须是可逆的,因为量子力学要求量子系统永远不会随时间丢失信息,并且它必须总是能够重建过去。有许多可用的量子门,完整的列表可以在这里找到。这里我们将简要介绍一些最重要的量子门:

  • CNOT 门: or Controlled NOT 是量子计算机最基本的门之一。结合使用 CNOT 门和单量子位旋转,任何量子电路都可以被模拟到任意的精确度。它可以用来纠缠和解开 EPR 态。CNOT 门在一个由两个量子位组成的量子寄存器上运行。当且仅当第一个量子位(控制量子位)为 1 时,CNOT 门翻转第二个量子位(目标量子位)。
  • 托夫里门:托夫里门是一种通用的可逆逻辑门,也就是说任何可逆电路都可以由托夫里门构成。它也被称为“受控-受控-非”门。它有 3 位输入和输出;如果前两位都设为 1,则反转第三位,否则所有位保持不变。
  • 哈达玛门:哈达玛门是一种单量子位操作,它将基态∣0 >映射到(∣0 > +∣1 > )/√2,∣1 >映射到(∣0 > −∣1 > )/√2,从而创建两个基态的相等叠加。哈达玛门也可以表示为绕 Y 轴旋转 90°,然后绕 X 轴旋转 180°。

有了量子计算机内部工作的上述知识,我们可以将这些结合起来,形成计算机更大、更有用的部分(就像在经典计算机中一样)。这些组成了我们的量子计算机。现在我们需要经典计算机中所有可用的东西,从编译器、操作系统、编程语言等等开始。由于经典计算机有丰富的历史,我们可以利用这一点,不需要太多的工作,就可以构建一个工作量子计算软件。目前,大多数公司都有自己的架构,但如果我们想提高这一领域的研究速度,这需要尽快改变。我们需要标准化的架构,所以研究人员很容易开发和测试新事物。这是建议的架构之一。

States of a two qubit system

正如我们所看到的,这似乎是一个经典的计算机体系结构,量子这个术语与之相关联,的确如此。现在我们能够理解如何使用这些组件,并利用它们做一些有用的事情。已经提出了许多量子算法:

  • Shor 的算法可以用于整数因式分解,它利用数论来实现这一点,它理论上可以破解 RSA 加密。
  • 格罗弗算法是一种量子算法,仅使用函数的 O ( N)次评估,以高概率找到产生特定输出值的黑盒函数的唯一输入,其中 N 是函数域的大小。它是由 Lov Grover 在 1996 年发明的。
  • Deutsch-Jozsa 问题将 n 位二进制值作为输入,并为每个这样的值产生 0 或 1 作为输出。我们被承诺函数要么是常数(所有输出为 0 或所有输出为 1)要么是平衡的,那么任务是通过使用 oracle(黑盒量子计算机)来确定 f 是常数还是平衡的。

这些算法非常复杂,已经有非常好的资源可以详细解释它们,因此在这个博客中解释它们没有什么意义。这里有一个斯科特·阿伦森的关于肖尔算法的博客,还有一个 T2 的关于格罗弗算法的博客

挑战和缺点

量子计算机非常容易出错。的确,我们从来没有从量子计算机中得到准确的结果。我们有时得到正确的结果,有时得到错误的结果,当我们得到正确的结果多于错误的结果时,我们说我们的量子计算机给了我们好的答案。量子纠错本身就是一个领域。降低结果的不确定性是非常必要的,因为只有在这之后,我们才能使量子计算机可用。

量子计算机的另一个问题是,一旦你观察到一个状态,它就会失去所有的信息,因为它必须坍缩到只有一个状态。现在,观察并不意味着人类的观察,它意味着任何可能导致光子交换的与量子粒子的相互作用。现在,这可以通过与几乎任何东西的相互作用来实现,这被称为量子退相干。这里有一个来自维基百科的更正式的定义

量子退相干是量子相干性的丧失。在量子力学中,电子等粒子由波函数描述,波函数是系统量子态的数学表示;波函数的概率解释被用来解释各种量子效应。只要不同状态之间存在确定的相位关系,就说系统是相干的。相干性在量子物理定律下得以保留,这对量子计算机的运行是必要的。然而,当量子系统不是完全孤立的(在这种情况下,不可能操纵或研究它),相干性与环境共享,并随着时间的推移而消失,这一过程称为量子退相干。这个过程的结果是,量子行为显然消失了,就像经典力学中能量似乎因摩擦而消失一样。

退相干导致了另一个问题——只有当多个量子比特可以相互纠缠时,它们在量子计算机中才有用。在今天的量子计算机中,当你试图纠缠 10 个量子比特时,它们已经失去了相干性。今天的量子阱的相干寿命只有几微秒,远低于执行有意义的计算任务所需的时间。因此,退相干限制了量子计算机计算能力的增长。

为了克服退相干,我们需要非常复杂且非常绝缘(甚至与空气中存在的波(信号)绝缘)的系统来保护量子位不受任何外部影响。不用说,这是极其困难的,需要大量的资源和巧妙的工程,导致巨额资金的投资。再加上安装它的难度和危险性,你就可以告别在家里拥有一台量子计算机的梦想了。

前方的路

即使量子计算机为我们提供了一个伟大的视角,但围绕它们有很多虚假的炒作,有一些阴谋论认为量子计算机是通往其他维度的通道(lol!!!),鉴于任何新技术和大量围绕量子物理的科幻小说,这种炒作是很自然的。但我们需要对量子计算机持现实态度,因为我们甚至不知道我们是否会有可用于实际目的(如模拟分子)的量子计算机。由于退相干,增加量子计算机中的量子比特数量非常困难,即使量子比特的质量在过去十年中有所提高,但在我们可以期待量子计算机的一些结果之前,仍然需要对量子计算机进行大量的研究和关注,并需要教育人们。

大多数量子计算研究都集中在破解密码术上(由于它的影响),这是由于 Shor 的算法,但是期望量子计算机在不久的将来破解密码术是不现实的,因为我们需要成千上万的量子位来破解密码术,而这些天我们几乎没有两位数。随着时间的推移,量子计算机的许多新应用已经出现,从量子互联网到量子力学系统的模拟,这可能导致新材料的形成,这些新材料可用于抗癌、制造纳米粒子、制造超导材料等。量子密码术正在成为量子效应应用的更先进的领域之一。

中国科技大学的简希望,到 2030 年,量子通信将跨越多个国家。在 10 年左右,你可以期待量子互联网。英特尔最近宣布了一台名为“Tangle Lake”的 49 位量子计算机,据报道,谷歌已经建造了一个名为“Bristlecone”的 72 位量子计算机芯片,IBM 推出了世界上第一台商用量子计算机,名为 IBM Q System One。阿里巴巴在这一领域也取得了长足的进步。

总而言之,量子计算机的前景似乎是光明的,再加上大公司之间的激烈竞争,你就有了生活在即将成为伟大历史的时代的秘诀。

[1] P.A.M .狄拉克(1947)。量子力学原理(第二版)。克拉伦登出版社。第 12 页。

原载于 2019 年 4 月 8 日https://khansaadbinhasan . github . io

了解随机森林

原文:https://towardsdatascience.com/understanding-random-forest-58381e0602d2?source=collection_archive---------0-----------------------

Photo by Skitterphoto from Pexels

该算法如何工作以及为什么如此有效

机器学习的很大一部分是分类——我们想知道一个观察值属于哪个类(也叫组)。对观察结果进行精确分类的能力对于各种业务应用程序非常有价值,例如预测特定用户是否会购买产品,或者预测给定的贷款是否会违约。

数据科学提供了大量的分类算法,如逻辑回归、支持向量机、朴素贝叶斯分类器和决策树。但是靠近分类器层次结构顶端的是随机森林分类器(也有随机森林回归器,但那是另一天的主题)。

在这篇文章中,我们将研究基本决策树是如何工作的,单个决策树是如何组合成随机森林的,并最终发现为什么随机森林如此擅长它们的工作。

决策树

让我们快速浏览一下决策树,因为它们是随机森林模型的构建模块。幸运的是,它们非常直观。我敢打赌,大多数人在生活中的某个阶段都有意无意地使用过决策树。

Simple Decision Tree Example

通过一个例子可能更容易理解决策树是如何工作的。

假设我们的数据集由左图顶部的数字组成。我们有两个 1 和五个 0(1 和 0 是我们的类),并希望使用它们的特性来区分这些类。这些特征是颜色(红色对蓝色)以及观察值是否带下划线。那么我们如何做到这一点呢?

颜色似乎是一个非常明显的特征,因为除了一个 0 以外,所有的 0 都是蓝色的。所以我们可以用这个问题,“它是红色的吗?”分割我们的第一个节点。您可以将树中的一个节点看作是路径分成两部分的点——符合标准的观察值沿着“是”分支前进,不符合标准的观察值沿着“否”分支前进。

No 分支(蓝色)现在都是 0,所以我们已经完成了,但是我们的 Yes 分支仍然可以进一步分裂。现在我们可以使用第二个特征,并询问“它是否加了下划线?”进行第二次分裂。

带下划线的两个 1 进入 Yes 子分支,不带下划线的 0 进入右边的子分支,我们就完成了。我们的决策树能够使用这两个特征完美地分割数据。胜利!

显然,在现实生活中,我们的数据不会如此清晰,但决策树采用的逻辑是相同的。在每个节点,它会问—

什么特征允许我以一种方式分割手头的观察结果,使得结果组尽可能地彼此不同(并且每个结果子组的成员尽可能地彼此相似)?

随机森林分类器

随机森林,顾名思义,由大量个体决策树组成,作为一个集合体运行。随机森林中的每棵树都给出一个类别预测,拥有最多票数的类别成为我们模型的预测(见下图)。

Visualization of a Random Forest Model Making a Prediction

随机森林背后的基本概念简单而强大——群体的智慧。用数据科学的话说,随机森林模型如此有效的原因是:

作为一个委员会运作的大量相对不相关的模型(树)将胜过任何单个的组成模型。

模型之间的低相关性是关键。就像低相关性投资(如股票和债券)组合在一起形成的投资组合大于其各部分之和一样,不相关模型可以产生比任何单个预测都更准确的整体预测。产生这种奇妙效果的原因是这些树相互保护,避免各自的错误(只要它们不总是朝着同一个方向犯错)。虽然有些树可能是错误的,但许多其他的树将是正确的,因此作为一个群体,这些树能够朝着正确的方向移动。因此,随机森林运行良好的先决条件是:

  1. 我们的特征中需要有一些实际的信号,以便使用这些特征建立的模型比随机猜测做得更好。
  2. 由单个树做出的预测(以及因此产生的误差)需要彼此具有低相关性。

为什么不相关的结果如此巨大的一个例子

拥有许多不相关模型的奇妙效果是一个如此重要的概念,我想给你看一个例子来帮助你真正理解它。想象我们正在玩下面的游戏:

  • 我使用一个均匀分布的随机数生成器来产生一个数。
  • 如果我生成的数字大于或等于 40,你就赢了(所以你有 60%的胜算),我付给你一些钱。如果低于 40,我赢了,你付给我同样的钱。
  • 现在我给你以下选择。我们可以:
  1. 游戏 1 —玩 100 次,每次下注 1 美元。
  2. 游戏 2 —玩 10 次,每次下注 10 美元。
  3. 第三场 —玩一次,下注$100。

你会选哪个?每场比赛的期望值是一样的:

期望值游戏 1 = (0.601 + 0.40-1)*100 = 20

期望值游戏 2= (0.6010 + 0.40-10)*10 = 20

期望值游戏 3= 0.60100 + 0.40-100 = 20

Outcome Distribution of 10,000 Simulations for each Game

发行版呢?让我们用蒙特卡洛模拟来可视化结果(我们将对每种游戏类型运行 10,000 次模拟;比如我们会模拟 10000 次第一场的 100 次打法。看看左边的图表,现在你会选择哪种游戏?即使期望值相同,结果分布也有很大不同,从正的、窄的(蓝色)到二进制的(粉色)。

游戏 1(我们玩 100 次)提供了赚钱的最好机会——在我运行的 10,000 次模拟中,你在 97%的模拟中都赚钱了!对于第二场游戏(我们玩了 10 次),你在 63%的模拟中赚钱,这是一个急剧的下降(你输钱的概率也急剧增加)。而我们只玩一次的游戏 3,你在 60%的模拟中赚钱,正如预期的那样。

Probability of Making Money for Each Game

因此,即使这些游戏有着相同的期望值,它们的结果分布却完全不同。我们越是将 100 美元的赌注分成不同的游戏,我们就越有信心赚钱。如前所述,这是可行的,因为每个剧本都是独立于其他剧本的。

随机森林也是一样——每棵树就像我们之前游戏中的一个游戏。我们只是看到我们赚钱的机会随着我们玩的次数越来越多而增加。同样,对于随机森林模型,我们做出正确预测的机会随着模型中不相关树木的数量而增加。

如果你想自己运行模拟游戏的代码,你可以在我的 GitHub 这里找到它。

确保模型相互多样化

那么随机森林如何确保每棵树的行为与模型中任何其他树的行为不太相关呢?它使用以下两种方法:

Bagging(Bootstrap Aggregation)——决策树对它们接受训练的数据非常敏感——训练集的微小变化会导致明显不同的树结构。 Random forest 利用了这一点,它允许每棵单独的树通过替换从数据集中随机采样,从而产生不同的树。这个过程被称为装袋。

注意,使用 bagging,我们不是将训练数据分成更小的块,而是在不同的块上训练每棵树。相反,如果我们有一个大小为 N 的样本,我们仍然为每棵树提供一个大小为 N 的训练集(除非另有说明)。但是代替原始的训练数据,我们用替换取一个大小为 N 的随机样本。例如,如果我们的训练数据是[1,2,3,4,5,6],那么我们可以给我们的树一个下面的列表[1,2,2,3,6,6]。请注意,这两个列表的长度都是 6,并且“2”和“6”都在我们提供给我们的树的随机选择的训练数据中重复出现(因为我们使用替换进行采样)。

Node splitting in a random forest model is based on a random subset of features for each tree.

特征随机性— 在正常的决策树中,当需要分割一个节点时,我们会考虑每一个可能的特征,并选择一个在左节点和右节点的观察值之间产生最大分离的特征。相比之下,随机森林中的每棵树只能从随机要素子集中选取。这迫使模型中的树之间有更多的变化,并最终导致树之间更低的相关性和更多的多样化。

让我们来看一个直观的例子——在上图中,传统的决策树(蓝色)在决定如何拆分节点时,可以从所有四个特征中进行选择。它决定使用特性 1(黑色加下划线),因为它将数据分成尽可能独立的组。

现在让我们来看看我们的随机森林。在本例中,我们将只检查森林中的两棵树。当我们检查随机森林树 1 时,我们发现它只能考虑特征 2 和 3(随机选择)来进行节点分裂决策。我们从传统的决策树(蓝色)中知道,特征 1 是最好的分割特征,但是树 1 看不到特征 1,所以它被迫使用特征 2(黑色并带下划线)。另一方面,树 2 只能看到特征 1 和 3,因此它能够选择特征 1。

所以在我们的随机森林中,我们最终得到的树不仅在不同的数据集上进行了训练(多亏了 bagging ),而且还使用不同的特征来做决策。

我亲爱的读者,这就创造了不相关的树,它们缓冲并保护彼此免受错误的影响。

结论

随机森林是我个人的最爱。来自金融和投资领域的圣杯总是建立一系列不相关的模型,每个模型都有正的预期回报,然后将它们放在一个投资组合中,以赚取巨大的阿尔法(阿尔法=市场回报)。说起来容易做起来难!

随机森林是数据科学的等价物。我们最后复习一遍。什么是随机森林分类器?

随机森林是一种由许多决策树组成的分类算法。它在构建每棵树时使用 bagging 和特征随机性,试图创建一个不相关的树木森林,其委员会的预测比任何单棵树都更准确。

为了让我们的随机森林做出准确的类别预测,我们需要什么?

  1. 我们需要至少有一些预测能力的功能。毕竟,如果我们把垃圾放进去,我们就会把垃圾弄出来。
  2. 森林中的树木,更重要的是它们的预测需要不相关(或者至少彼此之间的相关性很低)。虽然算法本身通过特征随机性试图为我们设计这些低相关性,但我们选择的特征和超参数也会影响最终的相关性。

感谢阅读。我希望你从阅读这篇文章中学到的和我写这篇文章时学到的一样多。干杯!

如果你总体上喜欢这篇文章和我的写作,请考虑通过我的推荐链接注册 Medium 来支持我的写作。谢谢!

通过示例了解 RNNs

原文:https://towardsdatascience.com/understanding-rnns-by-example-c8cd52b13059?source=collection_archive---------28-----------------------

训练你的 PyTorch 模型计数

成为机器学习实践者最艰难的任务之一是直观地理解模型背后的魔力。人们普遍认为你需要成为一名数学专家才能完全掌握底层的机制,但你真正需要的只是浏览几个基本的例子。掌握简单的模型会给你在复杂性增加时所需要的基础。

有很多精彩的文章从较高的层面讲述了 RNN 是如何工作的,所以我将本课的内容提供给那些对自己实现一个具体示例感兴趣的人。

这篇文章中的很多想法和插图都来源于 fast.ai 以及他们在 NLP 中的课程。

RNNs 入门:

传统的前馈网络接收固定大小的输入,并产生固定大小的输出。当您的表格数据具有恒定的列数时,这非常有用,但是当您具有可变长度的序列(如音频、时间序列或我们示例中的文本)时,这就没什么用了。

RNN 的魔力在于它将当前输入与先前或隐藏状态相结合的方式。这种隐藏状态可以简单地认为是模型的内存上下文。如果我让你预测一个句子中的下一个单词,如果当前单词是“hot ”,那就不可能做出准确的猜测。如果你有一些比当前输入更多的记忆,比如“我吃了一个热的”,你可以更好地猜测下一个单词是“狗”。

鉴于其简单性,rnn 的能力令人惊叹。rnn 只是一个循环,将它们的内存与当前输入相加,并通过线性层发送该组合值,以计算下一步的内存。在为每一步输入计算隐藏状态后,隐藏状态通过输出层发送,以进行最终预测。下面是这个循环的伪代码:

h = hidden_state_init()
for word in words:
   h += embedding(h)
   h = linear(h)
out = linear_output(h)
return out

在本教程中,我们将用英语教我们的 RNN 数数。例如,如果我们的输入是:

['one', 'thousand', 'three', 'hundred', 'tweleve', ',' , 'one']

那么序列中的下一个单词将是‘千’

设置数据管道:

加载数据和构建词汇表:

首先,我们需要加载 train.txtvalid.txt 文件,它们的数字分别从 1 到 8000 和 8000 到 9999。我们将把这些文件加载到一个字符串列表中,通过制作一组字符串来构建我们的词汇表,然后构造一个从每个字符串到一个整数的映射。

创建批处理迭代器:

当训练我们的模型时,我们希望输出比输入快一步。例如,如果当前输入是“二”,那么输出应该是“,”。

x = ['one', ',', 'two', ',', 'three', ',', 'four', ',', 'five', ','] 
y = [',', 'two', ',', 'three', ',', 'four', ',', 'five', ',', 'six']

这个迭代器将首先生成形状的 2d 列表(bs,bptt ),其中 bs 代表批量大小,bptt 代表时间上的反向传播,或者基本上是序列中的字数。一旦我们生成了这些列表,我们就使用我们在上一步中构建的字典将令牌映射到它对应的整数。最后,我们将 2d 列表转换为 torch 张量,以便我们的模型可以处理它们。

训练第一个模型:

虽然 PyTorch 有一个专用的 RNN 层,但我们实际上将使用我们的循环来重新创建该层,这样我们可以更直观地掌握我们的层的顺序。我们的模型将由 4 个独特的层构成:

  • i_h(隐藏的输入):将输入(表示特定令牌的数字)映射到一个嵌入,其大小是我们定义的隐藏状态的 64
  • h_h (hidden to hidden): 线性层将先前的隐藏状态+当前输入作为输入,并向前传播这些组合值以生成当前隐藏状态
  • h_o(隐藏到输出):线性层,正向传播当前隐藏状态,生成预测输出
  • bn(批量标准化):移动和缩放激活以使优化场景明显更平滑(不要担心这个!).

一旦我们建立了模型,训练模型就相当于样板代码。然而,我将讨论一些关于我们的训练循环的细节。

  • 我们使用 Adam 作为我们的优化器,它和学习率一起决定在随机梯度下降(SGD)过程中减去梯度时的步长。
  • 我们使用交叉熵损失,这是任何分类任务中最常见的损失函数,并且通过对不正确答案的高概率猜测(假阳性)和正确答案的低概率猜测(假阴性)进行惩罚来工作。
  • 我们迭代 10 个时期,这意味着我们将暴露所有的输入 10 次。在每个时期内,我们使用 DataLM 迭代器通过迭代整个输入来构建批处理。
  • 我们记录每一步的损失和准确性。注意,损失是为每个标记计算的,而准确度只是模型正确获得第 71 个标记的能力的度量。我会让你想想,如果我们为每个记号计算,精度会有什么变化。
plt.plot(pd.Series(losses).rolling(4).mean())
plt.plot(pd.Series(accuracy).rolling(4).mean())

改进模型:

我们可以使用 PyTorch 的原生 RNN 层重构上面的模型,以获得与上面相同的结果。在实践中,您应该使用本机层,因为它更容易使用,并且由于一些 GPU 优化,运行速度更快。

虽然我们上面的演示表明,RNNs 可以有效地处理序列数据,但它们与长期依赖性作斗争。gru(门控循环单元)的功能与 rnn 非常相似,但在决定当前输入对当前状态的影响程度方面更智能。我很快会写一篇关于 GRUs 的文章,但与此同时,我会推荐这个由 fast.ai 做的讲座。

通过使用 GRU 而不是 RNN,我们可以将准确率从略高于 50%提高到 95%。

测试模型:

我们使用由数字 8001–9999 组成的验证列表,随机选择 20 个令牌。当我运行代码时,我对以下输入序列进行了采样:

seven , nine thousand three hundred eight , nine thousand three hundred nine , nine thousand three hundred ten ,

我们将此输入运行到我们的模型中,以预测下一个令牌。在预测了那个记号之后,我们把它附加到输入中来预测另一个记号。我们重复这个输入→预测→连接→输入序列 20 步。

使用与上面相同的输入字符串,我们得到以下输出:

nine thousand three hundred eight , nine thousand three hundred nine , nine thousand three hundred ten , nine thousand nine hundred eleven , nine thousand nine hundred twelve , nine thousand nine hundred thirteen , nine thousand

现在,当以 95%的准确率预测 20 个令牌时,我们只会在 36%的时间内得到正确的输出。根据经验,使用训练集,我在 80%的情况下得到正确的输出,在 45%的情况下使用验证得到正确的输出

总结:

希望现在你对 RNN 的工作原理有了更好的理解,但是我不期望你完全掌握所有的细节。说到这里,我对如何加强你的理解有很多建议:

  • 如果你喜欢自上而下的结账方式
  • 如果你想深入了解数学,请访问关于序列模型的 deeplearning.ai 课程。
  • 如果你是动手型的,那么把 RNN 应用到另一个应用程序中。

参考文献:

J.霍华德,r .托马斯,自然语言处理的代码优先介绍 (2019), fast.ai

了解 rnn、LSTMs 和 gru

原文:https://towardsdatascience.com/understanding-rnns-lstms-and-grus-ed62eb584d90?source=collection_archive---------16-----------------------

一个递归神经网络 (RNN)是一个基本神经网络的变体。rnn 适用于处理序列数据,如自然语言处理和音频识别。直到最近,他们还饱受短期记忆问题的困扰。在这篇文章中,我将尝试解释什么是(1) RNN,(2)消失梯度问题,(3)这个问题的解决方案被称为长短期记忆 (LSTM)和门控循环单元 (GRU)。

什么是 RNN?

首先,让我们介绍基本的神经网络架构,神经网络通过 3 个基本步骤进行训练:

(1)进行预测的向前传球。

(2)使用损失函数将预测与地面真实情况进行比较。损失函数输出一个误差值

(3)使用该误差值,执行反向传播,其计算网络中每个节点的梯度。

相比之下,RNN 包含一个隐藏状态,它从先前的状态中获取信息:

隐藏状态的概念类似于为了做出更准确的预测而对顺序数据进行整合。考虑一下,如果您的数据仍然是运动中的球的照片,预测球的运动会容易得多:

没有序列信息,就不可能预测它的移动方向,相反,如果你知道以前的位置:

预测会更准确。同样的逻辑也适用于估计句子中的下一个单词,或者歌曲中的下一段音频。这个信息是隐藏状态,它是先前输入的表示。

消失梯度问题

然而,这变得有问题,为了训练一个 RNN,你使用一个叫做通过时间 (BPTT)的反向传播的应用。由于每一层的权重通过链规则进行调整,它们的梯度值将随着其在每个时间步长的传播而呈指数缩小,最终“消失”:

为了在 NLP 应用程序中说明这一现象:

Vanishing Gradient

通过输出 5,您可以看到来自“什么”和“时间”的信息几乎都消失了,如果没有这些信息,您认为您能多好地预测“是”和“它”之后的内容呢?

LSTM 和 GRU 作为解决方案

LSTMs 和 GRUs 是作为消失梯度问题的解决方案而创建的。它们内部有一种叫做的机制,可以调节信息的流动。

对于 LSTM,有一个主单元状态,或传送带,以及几个控制新信息是否可以进入传送带的门:

在上面的问题中,假设我们要确定新句子中说话人的性别。我们将不得不选择性地忘记关于先前状态的某些事情,即,关于鲍勃是谁,他是否喜欢苹果,并记住其他事情,爱丽丝是一个女人,她喜欢桔子。

放大来看,LSTM 中的门通过三个步骤来完成这一过程:

(1)决定忘记什么(状态)
(2)决定记住什么(状态)
(3)状态的实际“遗忘”和更新
(4)输出的产生

总结一下,在 LSTM 中,遗忘门(1)决定哪些相关内容要从前面的步骤中保留。输入(2)门决定从当前步骤添加什么相关信息。输出门(4)决定下一个隐藏状态应该是什么。

对于作为新一代 rnn 的 GRU,它与 LSTM 非常相似,只是 GRUs 摆脱了小区状态,使用隐藏状态来传递信息。它也只有两个门,一个复位门更新门:

(1)更新门的作用类似于 LSTM 的遗忘和输入门,它决定保留什么信息和丢弃什么信息,以及添加什么新信息。

候选隐藏状态的实现方式与 LSTM 相同,不同之处在于,在候选计算内部,它将重置一些先前的门(0-1 之间的向量,由线性变换定义)。

(2)重置门用于决定忘记多少过去的信息。

插图摘自
1。麻省理工 6。s094:Lex frid man
2 在 2017 年冬季
讲授的自动驾驶汽车深度学习。LSTM 和 GRU 的图解指南:一步步的解释

了解 RNNs(递归神经网络)

原文:https://towardsdatascience.com/understanding-rnns-recurrent-neural-networks-479cd0da9760?source=collection_archive---------15-----------------------

Photo by Gemma Evans on Unsplash

能够记住过去的神经网络

第一次听说 RNN(递归神经网络)时,我有些不知所措。我读过的一篇文章声称,RNN 是一个具有记忆的神经网络——它可以记住数据的连续起伏,以便做出更明智的预测。

当时我的第一个想法是——RNN 与有许多滞后的线性回归(自回归模型)有什么不同?事实证明,RNN 不仅与众不同,而且更灵活、更强大。

但是,在我们将它添加到我们的预测工具包之前,我们应该尽最大努力对它的工作原理有一个直观的理解——从 RNN 如何能够记住过去开始。让我们找出答案。

顺序数据

RNN 是一种最适合处理序列数据的神经网络。如果你对神经网络不熟悉,那么你应该从我的理解神经网络帖子开始。在本文中,我将假设读者对什么是神经网络以及如何工作有一个基本的了解。

什么是顺序数据——顺序很重要的数据。序列数据的一些示例包括股票价格和利率(按时间排序)、博客文章中的文字(文字的顺序传达上下文和含义)或每天的平均温度(按时间排序)。

An example of sequential data (Apple stock price)

通常,对于序列数据,我们希望预测接下来会发生什么。例如,我们可能想要预测明天的温度,或者下个月股票的价格是高还是低。

简单线性回归预测

我能想到的最简单的预测是 AR(1)模型(一种具有单一滞后的自回归模型),在这种模型中,您只需使用前一个观察值来尝试预测下一个观察值。让我们以股票回报为例:

  • 我们想预测 Ret、苹果下个月的回归。这是我们的目标变量。
  • 我们唯一的特征变量是最近一个月的回报。
  • 我们的数据集由 20 年的苹果月度股票回报时间序列组成(计算为从上个月最后一天到本月最后一天苹果股票价格的百分比变化)。

AR(1)模型将具有以下等式:

预测 _Ret(t) = m*Ret(t-1) + B

这应该看起来很熟悉,因为这是一条线的方程(Y = mX + B)。下图更详细地描绘了我们的 AR(1)模型。让我们一点一点来看:

  • 我们使用我们的数据来估计绿色参数的最佳值——m 是我们直线的斜率,B 是截距。
  • 请注意,左边的等式产生了一个带有帽子符号(^).)的输出帽子表示输出仅仅是我们的目标变量的一个估计,实际的股票回报。
  • 我们的目标是最小化预测回报(^)和实际回报之间的差异。
  • 请注意,第一个月返回的横向 Ret(0) 与第二个月返回的 Ret(1) 对齐, Ret(1)Ret(2) 对齐,以此类推。这就是我们所说的使用前一个观察值(我们的特征)来预测下一个观察值(我们的目标)的含义——给定上个月的收益和我们的估计值 mB ,我们可以预测下个月的收益。

AR(1) model

你不需要在市场上待很久就知道这不是一个好的模式。股票价格会因为各种原因波动(公司基本面、经济冲击、投资者恐惧/兴奋),有时甚至没有任何原因。所以我们不应该指望一个简单的 AR(1)模型就能做好。

相反,我们应该超越最近的观察,考虑整个序列(实际上,我们应该考虑价格变动之外的数据,但那是另一个故事了)。RNNs 允许我们这样做。

使用 RNNs 考虑整个序列

在我们深入研究 RNNs 之前,读者可能会问一个问题:“为什么不增加自回归模型中的滞后数?”也就是说,与其使用单一滞后,为什么不使用 AR(20)之类的东西,它使用最近 20 个月的月度回报来预测下个月的回报。答案是双重的:

  1. 用于我们的模型的月回报率实际上是我们需要调整的一个重要参数。选择错误的数字可能会导致糟糕的性能。此外,根据经济体制的不同,月度回报的最佳使用次数可能会有很大差异。RNN 绕过了这一点,因为它可以看到整个可用的历史回报,更重要的是,它自动决定在每个时间点给历史回报多少权重。所以我们不需要告诉 RNN 查看之前的 5、10 或 20 个回报,因为它天生就知道要这么做。
  2. 自回归模型是线性模型,因此假设我们的特征和目标之间存在线性关系。在存在非线性的情况下,这可能会导致性能问题。 RNNs,尤其是当堆叠在更多 RNNs 或者密集层(一个密集层就是一层正常的神经网络神经元)上时,可以检测和捕获我们数据中的所有非线性关系。事实上,对于 RNNs(以及一般的神经网络),我们应该更担心过拟合而不是欠拟合。

模特有记忆意味着什么?

让我们使用神经网络神经元重新创建 AR(1)模型。这里没有什么复杂的——回想一下,一个单一的神经元(如果你不熟悉神经元,请花点时间阅读我之前关于神经网络的博客)接受一个输入,将其乘以一个权重( m ,并向其添加一个偏差( B )。这些正是单变量线性回归的操作,这就是 AR(1)模型。 注意,为了简化说明,我们在这里忽略了激活功能。

AR(1) via a neural net neuron

现在让我们考虑一下如何给这个模型增加内存。在数量模型的情况下,记忆是什么?没有 100%正确的答案,但在我看来,记忆是从相关的过去经历中提取信息以帮助决策的能力。在建模方面,我们希望模型是动态的——换句话说,我们希望它能够根据它对情况的理解(基于它过去的经验)而变化。

我们的 AR(1)模型可能会用历史数据进行训练(回想一下,我们给它输入了苹果过去 20 年的月度股票回报),但它肯定没有记忆。在估计回归参数 mB 时,AR(1)模型对我们给定的每个数据点进行同等加权。因此,它不能决定哪些数据点更相关,哪些数据点不相关(回归参数是静态的,一旦估计)。它是静态的,不是动态的。

记忆从何而来?

最后,是时候给我们的模型记忆了。它实际上只需要一个简单的技巧。请注意下图底部的附加内容:

Super simple RNN with memory

关键的添加是我们现在接受先前的输出,输出(t-1) ,将其与新的参数 u,相乘,并将其添加到先前的输出中。所以我们更新后的等式看起来像:

预测 _ Ret(t)=*u 预测 _Ret(t-1) + m*Ret(t-1) + B

或者用更一般的符号来表示:

输出(t)=*u 输出(t-1) + m*Ret(t-1) + B

那么这到底为什么构成记忆呢?要了解原因,我们需要向前跳一点,首先了解 RNN 是如何分析数据的。以下是 RNN 如何生成预测的 Python 伪代码:

# Our input data is 20 years of Apple's monthly returns
inputs = appl_monthy_returns
time_steps = range(inputs.shape[0])# List to store outputs
predictions = []# Initialize state to 0 (state is output[t-1] from above)
state = 0# Initialize u, m, and B
u = 1
m = 1
B = 1for t in time_steps:
    input_t = inputs[t]
    current_prediction = (u * state) + (m * input_t) + B
    predictions.append(current_prediction)
    state = current_prediction

    # Function that updates m and B via backpropagation through time
    u, m, B = BPTT(state, predictions, inputs)

好了,现在让我们浏览一下代码:

  1. 首先我们将状态,也就是我所说的输出(t-1) 初始化为 0,因为在 t=0 时没有先前的状态
  2. 然后我们开始循环。输入多少,循环就运行多少次——在我们的例子中,我们有 20 年的月回报,所以它将运行 20*12 = 240 次。
  3. 在循环的每次迭代中,我们计算当前预测。然后,我们将计算出的预测附加到我们的输出列表中,预测——该列表是我们对下个月收益的预测。
  4. 接下来,我们设置状态等于当前预测,以便我们可以在下一个循环中使用它——也就是说,我们需要从 t=0 的预测来计算在 t=1 的预测。
  5. 最后,我们使用时间反向传播(超出了本文的范围)来更新 RNN 的参数 umB

请注意几个关键事项:

  • 状态是记忆的来源。时间 t 的状态是先前的输出(从时间 t-1 开始),该先前的输出包括先前的模型参数(时间 t-1 的 umB )以及时间 t-2 的输出。当 RNN 的当前时间步长(每个时间步长都是 for 循环的一次迭代)查看前一个时间步长的输出(状态)时,它实际上是在查看过去的自己。之前的输出是 RNN 对过去的自己进行快照并将其向前传递的方式。这就是为什么我在伪代码中称之为状态的原因——这只是总结(非常粗略地)模型决策过程的最新状态的一种方式。
  • 我们用参数 u 乘以状态。这允许 RNN 决定使用多少内存(自身过去的快照)。
  • 我们在 for 循环的每次迭代中做的最后一件事是更新 RNN 的参数( umB )。这意味着在循环的每次迭代中,我们可能会看到 umB 的不同值。
  • for 循环的目的是让 RNN 在时间中向前移动。与一次性估计模型的线性回归不同,RNN 通过一次一个时间步长增量检查序列数据而逐渐收敛。

让我们写出这个等式(使用更简单的符号),以确保我们理解了所有内容。我将调用 t 时刻的输出, O(t),和输入, X(t)。让我们写出 O(3):

O(3) = u * O(2) + m * X (3) + B

我们也可以写出 O(2) :

O(2) = u_2 * O(1) + m_2* X (2) + B_2

代入 O(2) ,我们得到:

O(3)= u *(u _ 2 * O(1)+m _ 2 * X(2)+B _ 2)+m * X(3)+B

看看时间 t=3 时的输出如何包括先前的参数( u_2m_2B_2 ) — 这些参数是 RNN 如何在时间 t=2 时做出决定的,并且它们现在已经被传递到模型的当前迭代。如果我们愿意,我们也可以展开 O(1) 来查看从时间 t=1 开始的参数也包括在内。

回想一下,我们将模型记忆定义为动态的,能够根据情况变化。RNN 现在可以做到这一点——通过以前的输出包括过去的快照,RNN 可以访问其历史参数,并可以根据情况需要决定是否将它们纳入其决策过程。

结论

写这篇文章让我学到了很多。以前我很清楚 RNNs 是如何工作的,但我一直想更好地理解人们说 RNNs 有记忆是什么意思。我希望你现在也能更好地理解它。

但是我们的工作还没有完成。理论上,rnn 应该能够熟练地利用过去的经验来做决策。但在现实中,他们遭遇了所谓的消失梯度问题。在未来的帖子中,我们将探索为什么会这样,以及一个称为 LSTM 的增强 RNN 如何帮助我们解决这个问题。在那之前,干杯!

更多数据科学与商业相关岗位由我:

数据科学家的商业战略

多少分析才算过分

用 Python 进行业务模拟

了解 PCA

理解贝叶斯定理

理解朴素贝叶斯分类器

理解得分倾向:评估 NBA 球员的混合模型方法

原文:https://towardsdatascience.com/understanding-scoring-propensity-a-mixed-model-approach-to-evaluating-nba-players-d749a7e453a7?source=collection_archive---------21-----------------------

"谁是 NBA 的最佳得分手?"是我和朋友交谈时经常提到的一个问题。像勒布朗·詹姆斯、詹姆斯·哈登和斯蒂芬·库里这样的名字总是会出现。

通常很难找到一个单一的答案;当计分员之间存在差异时,这个问题变得更加微妙。当考虑到球员得分的不同情况时,我们如何区分天赋?

例如,我们如何像这样比较两个玩家:

Steph Curry

LeBron James

两位球员都是高产射手,但他们得分的方式不同。我们怎样才能让它们有共同点呢?

注意:在这个分析中,我不会使用罚球命中率和/或百分比。如果他们没有犯规,这个更好的头衔应该是“最佳射手”。

一个简单的方法:每杆得分

天真地说,我们对“最佳得分手”的第一个论点可能取决于使用每杆得分(PPS)作为一种分析手段。毕竟,谁每次尝试得分最多,理论上就应该是最佳得分手。这种方法有缺点,但是我们将在后面解决这些问题。

从 kaggle.com 收集 2014-2015 赛季的数据,我们可以开始一些初步的分析。如果我们聚集球员,取他们每次投篮的平均得分,我们可以看到谁是最成功和最不成功的投篮手。

Top 10 PPS (2014–2015)

从左边的列表中,我们可以看到最有效率的得分手是抓高球的大个子(乔丹/钱德勒)。混合在一起的,是像科弗和巴比特这样精准的三分球投手。

如果我们太天真,我们会简单地认为他们是联盟中最好的“投篮手”。然而,从我们的篮球知识来看,我们知道靠近篮筐的投篮(例如乔丹/钱德勒接到的扣篮和高球)比远一点的投篮容易得多。此外,我们也知道更多的空位投篮比高度争议的投篮更容易。让我们用数据验证来测试我们的直觉,以确保我们是在正确的轨道上。

Shot Distance vs Def Distance (yellow indicates make, purple indicates miss)

如果我们看上面的散点图,我们可以看到球员离篮筐越远,就越容易失误。当他们离篮筐更近而防守队员离得更远时,他们很少会失手。我们可以把这想象成一个过渡上篮/扣篮的机会。我们的直觉是正确的,我们可以进行更细致的分析。

稍微好一点的方法:逻辑回归

为了说明这些不同的因素(投篮距离,防守距离),我们可以建立一个简单的逻辑回归模型来预测投篮是否进了。特征包括截击项、射门距离和防守距离。逻辑回归假设每个样本的误差产生过程是相同的。在我们采用这种方法时,请记住这个假设。

Model Generation

仅仅建立一个简单的模型,我们可以看到,盲目猜测镜头转换会给我们大约 55%的准确性。该模型提高了约 5%。随着更多的超参数调整,我相信我们可以做得更好,但不是令人难以置信的。

检查残差显示,模型并不完全拟合(不以 0 为中心,并且略有偏斜)。这可能表明违反了前面提到的 i.i.d .假设。

Residuals of Fit

这种违反可能是由于模型对玩家是盲目的。也许每个玩家都有不同的出错过程。从本质上来说,基于一些隐含的潜在技能水平,每个球员对投篮是否会有不同的影响。

为了解决这个问题,我们可以做三件事之一:

  • 在现有的逻辑回归模型中添加使用一次性编码表示的玩家
  • 为每个玩家建立一个单独的模型
  • 以某种方式结合上述策略

在第一种方法中,我们并没有真正以他们自己独特的方式对待不同球员的每一次投篮尝试。我们仍然假设每个镜头来自相同的数据生成过程,所以我们的假设仍然会被违反,尽管我们的准确性可能会提高。

在第二种方法中,我们当然会考虑不同玩家的不同错误,但是我们最终会建立很多模型!

第三种方法是我的首选方法,它将上述策略结合到一个模型中。这就是所谓的分层线性建模。

一个不完美但改进很多的模型:HLMMs

分层线性混合模型(HLMMs)是指处理具有清晰分层结构的分组数据的模型。例如,这些模型已被用于研究不同学区对学生 SAT 成绩的效应

在我们的例子中,我们希望看到不同球员对击球结果的影响。我们的数据(投篮次数)可以按以下方式分组:

  • 通过游戏
  • 按团队
  • 按玩家
  • 由最近的防守队员防守
  • 按季度

这些不同的分组都是为了解释数据中的一些差异。另一种思考方式是,上述每一组对击球结果都有不同的影响。例如,也许数据中的大多数差异(即成功或失败)是由“玩家”组决定的。这些类型的分组被称为“随机效应”。

HLMMs 由固定效果和随机效果组成(因此得名“混合”)。固定效应是被认为同等影响所有群体的变量。例如,在我们的例子中,镜头的距离可以被认为是一个固定的效果。

这些模型也解释了分组中的不平衡。例如,让我们说在 10000 次投篮中,我们只有一个板凳球员的 6 个数据点,因为这个球员通常不怎么上场。如果我们使用我们的第一种方法,这 6 个数据点在决定这个玩家的价值时会稍微不重要。如果我们使用我们的第二种方法,为每个玩家建立一个单独的模型,这个玩家的影响将会严重过度拟合。想象一下,如果这个球员 6 投全中;这位模特会对他评价很高,但可能无法解释他的运气。

HLMMs 在这两种方法之间找到了一个折中的办法。简单来说,如果一个群体的成员没有太多的数据,他的效果会更接近群体所有成员的均值。如果他这样做了,他的效果会更远。这就是所谓的“缩水”。如果你有兴趣了解更多关于混合模型的信息,这个链接会给你一个很好的起点。

将 HLMMs 应用于拍摄数据

让我们重温一下我们的每次投篮得分分析。之前,我们只显示了球员的每次投篮得分,但没有显示他们的投篮次数。包含这些信息可以显示玩家是否“不走运”。

在左边,我们可以看到球员之间投篮次数的巨大差异。以斯蒂芬·库里和希度·特克格鲁的差异为例。两者的 PPS 都一样,但是 Steph 的尝试次数多了 9 倍!直觉告诉我们,斯蒂芬的信息更可信,但我们能肯定地说,斯蒂芬是一个比特科格鲁单独使用这些信息更好的投篮手吗?

事实证明,我们可以尝试使用假设检验,但这是假设斯蒂芬和赫多拍摄了完全相同类型的照片。因为这是极不可能的,我们将忽略这条路线。

我们能做的是建立一个 HLMM 并解释模型的系数。

HLMM Specification

以上是如何指定混合模型的。贝塔项是固定效应“X”的系数,“u”是随机效应“Z”的系数。请注意,模型是线性的;系数的正值表示相关预测值的增加(当其他值保持不变时),与预测值“y”的适当增加相一致。

在篮球方面,我们可以看到一个球员的系数如何与预测值,投篮结果相关联。一个更好的射手会有更大的正系数。

构建 HLMM:使用贝叶斯方法

让我们重温一下我们的数据。

Data Frame for Shot Data

让我们在数据中寻找可能引入差异的分组。我想到了一些:

  • 运动员
  • 球员的防守队员
  • 游戏 ID
  • 玩家的团队
  • 玩家的对手
  • 四分之一

现在,我们可以寻找可能在人群中固定的影响:

  • 主场/客场比赛
  • 射击距离
  • 防守距离
  • 运球次数
  • 触摸时间
  • 季度剩余时间
  • 计时器

通常,当使用贝叶斯方法时,人们希望拟合“最大模型”。这意味着,如果一个人想要在我们的情况下,确认或否认一个假设(即谁是最好的射手),我们应该指定最大随机效应结构。那是什么意思?

考虑我们上面的功能。我们可以这样设置固定效果,并为每个组指定一个随机截距。然而,直觉上我们知道射门距离、防守距离和射门前运球对每个球员的影响是不同的。因此,我们可以假设一种结构,它包括上述每个特征的随机斜率以及随机截距。此外,我们可以假设防守者的距离对每个防守者的影响不同,并包括一个随机斜率。

使用 R 的 brms 软件包,我可以拟合一个具有“最大结构”的模型,并解释结果。请注意,这将需要一段时间,取决于您运行的迭代和链的数量。

分析模型结果

我最终拟合的模型在 r 中有这个公式。

FGM ~拦截+位置+ CLOSE_DEF_DIST + (1 +射门 _DIST +运球|球员)+(1 |最近的 _ 后卫)

这意味着,响应(FGM)是固定效应(主队/客场和后卫距离)+最近的后卫和球员的截距+球员的随机坡度效应乘以射门距离和运球次数的函数。响应 FGM 是二进制 0/1 响应;这意味着系数必须以对数标度进行解释,因为影响是使用 logit 链接函数进行转换的。

为了捕捉某个玩家相对于其他玩家的影响,我们需要做一点数学计算。回想一下,如果其他预测因子保持不变,系数测量的是反应。在我们指定的模型中,我们有几个变量保持不变:

  • 位置(家庭/外出)
  • 防守距离
  • 射击距离
  • 运球
  • 拥护者

因为我换算了防守距离、射门距离和运球次数的值,它们的中间值应该是 0。我们将用它作为我们的常数,使我们的计算更容易。为了简单起见,我们假设每个玩家都在家。接下来,我们必须固定一个防御者值;我们将使用中间值。随机效应用一个正态(均值=0,方差=sigma)来指定,所以中值应该是 0!这使得我们的最终计算相当容易。

计算玩家效果

logit 链接执行以下转换:

ln(p/(1-p)) = βX + Zu

回想一下,“Z”和“ β 分别是随机效应和固定效应的系数。“P”是成功结果的概率值(在我们的例子中是命中)。

在我们的例子中(因为我们使用中值 0),这分解为:

ln(p/(1-p)) =拦截+主场+球员

我称方程的 RHS 为线性预测值。现在,求解 p,我们得到:

e(linear_predictor)/(1+e(linear_predictor)

我们现在可以用概率来比较球员对射门转换的影响了!

因为我们去贝叶斯,这不是我们能做的。我们实际上可以使用生成的样本来查看每个玩家效果的概率分布。这比使用单一值要好得多,因为我们可以比较估计中的不确定性。

我将在下面用一个例子来说明,重温斯蒂芬·库里和希度·特克格鲁的例子。回想一下,斯蒂芬和海多的得分相当,但是斯蒂芬的出手次数是他的 9 倍。

Player Effects

橙色的是特科格鲁的投篮转换值分布,蓝色的是库里的。x 轴代表转换的概率,而 y 轴代表相应 x 值的非归一化频率。

一些要带走的东西:

  • 特科格鲁的分布更加分散。这意味着我们对他的影响不太确定。这是有道理的,因为我们只有 100 次投篮机会。因此,库里的分布更紧密,这意味着模型对他的效果更确定。
  • 特科格鲁的分布峰值向库里的左移。这表明,模型估计库里更有可能比特科格鲁对投篮命中率有更大的影响!然而,我们可以看看分布的交叉点,看看库里拥有更高效果的频率。我们简单取一下库里的“x”值比特科格鲁大多少倍的平均值。从上面的分布来看,由样本确定为 91.875%。斯蒂芬比特科格鲁有 92%的可能拥有更好的转化能力。

我们可以对球员的所有组合重复这个过程,并进行比较,但更有用的是考虑一个球员如何比其他人增加投篮的概率。我不会在发布会上发言。相反,我将只使用样本的中间值。

然后,我们可以从每个玩家的效果中减去所有玩家的转换中值,并查看每个玩家的转换高于替换的概率。

Top 20 Shot Converters

我们可以在左侧看到 2014-2015 赛季前 20 名和后 20 名击球手的名单。我们注意到了什么?有什么突出的?我们如何用我们建立的模型来解释这些结果?为什么我们会看到某些玩家凌驾于其他人之上?

Bottom 20 Shot Converters

结束语

数据有些嘈杂。最近的防守者可能只是一个帮忙的球员,而不是一个真正争球的球员。这些数据缺少球员投篮的类型(跳投、扣篮、勾手)。数据还缺乏球员投篮时周围的密度(球道是否拥挤,或者只有一个防守队员时是否相当清晰)。我们注意到大人物受到相当重的惩罚;它们经常位于替换级别图表的底部。这可能是因为这些玩家经常参与提示,而这些提示通常在第一次尝试时不会完全转化。同样,拥有更精细的数据(包括分数差异以剔除“关键”球员)将是有益的。请在下面留下您的评论。请记住,这仅适用于 2014-2015 赛季,但该流程也适用于今天的数据。

承认

我要感谢 Alex Hayes 帮助我理解贝叶斯环境下混合模型的方差-协方差结构。我还要感谢我的朋友们,他们不断地参与激烈的辩论,给了我分析性地解决辩论的灵感。

用 UNET 理解语义分割

原文:https://towardsdatascience.com/understanding-semantic-segmentation-with-unet-6be4f42d4b47?source=collection_archive---------0-----------------------

盐鉴定案例研究

目录:

  1. 介绍
  2. 先决条件
  3. 什么是语义切分?
  4. 应用程序
  5. 商业问题
  6. 理解数据
  7. 了解卷积、最大汇集和转置卷积
  8. UNET 建筑与培训
  9. 推理
  10. 结论
  11. 参考

1.介绍

计算机视觉是一个跨学科的科学领域,研究如何让计算机从数字图像或视频中获得高层次的理解。从工程的角度来看,它寻求将人类视觉系统可以完成的任务自动化。(维基百科)

CV is a very interdisciplinary field

深度学习使得计算机视觉领域在过去几年中迅速发展。在这篇文章中,我想讨论一下计算机视觉中的一个特殊任务,叫做语义分割。尽管研究人员已经提出了许多方法来解决这个问题,但我将谈论一种特殊的架构,即 UNET ,它使用完全卷积的网络模型来完成任务。

我们将使用 UNET 为 Kaggle 主办的 TGS 盐鉴定 挑战赛构建第一套解决方案。

除此之外,我写这篇博客的目的还在于为图像理解提供一些关于卷积网络中常用运算和术语的直观见解。其中一些包括卷积、最大池、感受野、上采样、转置卷积、跳过连接等。

2.先决条件

我将假设读者已经熟悉机器学习和卷积网络的基本概念。此外,你必须有一些与 Python 和 Keras 库 ConvNets 的工作知识。

3.什么是语义切分?

计算机理解图像有不同的粒度级别。对于这些级别中的每一个,都有一个在计算机视觉领域中定义的问题。从粗粒度到更细粒度的理解开始,让我们在下面描述这些问题:

a .图像分类

Image Classification

计算机视觉中最基本的构建模块是图像分类问题,其中给定一幅图像,我们期望计算机输出一个离散的标签,它是图像中的主要对象。在图像分类中,我们假设图像中只有一个(而不是多个)对象。

b .本地化分类

Classification with localization

在与离散标签一起定位时,我们还期望计算机准确定位图像中对象的位置。这种定位通常使用边界框来实现,该边界框可以由相对于图像边界的一些数值参数来标识。即使在这种情况下,假设每个图像只有一个对象。

c.目标检测

Object Detection

对象检测将定位扩展到下一个级别,现在图像不再局限于只有一个对象,而是可以包含多个对象。任务是对图像中的所有对象进行分类和定位。这里同样使用边界框的概念来完成定位。

d.语义分割

Semantic Segmentation

语义图像分割的目标是给图像的每个像素标上所表示内容的相应类别。因为我们对图像中的每个像素进行预测,这项任务通常被称为密集预测

注意,与前面的任务不同,语义分割的预期输出不仅仅是标签和边界框参数。输出本身是高分辨率图像(通常与输入图像大小相同),其中每个像素都被分类到特定的类别。因此,这是一个像素级的图像分类。

e.实例分割

Instance Segmentation

实例分割比语义分割领先一步,在语义分割中,除了像素级分类,我们还希望计算机能够分别对一个类的每个实例进行分类。例如,在上面的图像中有 3 个人,从技术上讲,是类“Person”的 3 个实例。所有这 3 个都是单独分类的(用不同的颜色)。但是语义分割并不区分特定类的实例。

如果您仍然对对象检测、语义分割和实例分割的区别感到困惑,下图将有助于澄清这一点:

Object Detection vs Semantic Segmentation vs Instance Segmentation

在这篇文章中,我们将学习使用全卷积网络(FCN)UNET 来解决语义分割问题。

4.应用程序

如果你想知道语义分割是否有用,你的疑问是合理的。然而,事实证明,视觉中的许多复杂任务都需要对图像有这种精细的理解。例如:

a.自动驾驶汽车

自动驾驶是一项复杂的机器人任务,需要在不断进化的环境中进行感知、规划和执行。这项任务也需要极其精确地完成,因为安全是最重要的。语义分割提供关于道路上自由空间的信息,以及检测车道标记和交通标志。

Source: https://www.youtube.com/watch?v=ATlcEDSPWXY

b.生物医学图像诊断

机器可以增强放射科医生进行的分析,大大减少运行诊断测试所需的时间。

Source: https://arxiv.org/abs/1701.08816

c.地理传感

语义分割问题也可以被认为是分类问题,其中每个像素被分类为一系列对象类中的一个。因此,有一个卫星图像土地利用制图的用例。土地覆盖信息对于各种应用都很重要,例如监测森林砍伐和城市化地区。

识别土地覆盖的类型(例如,城市、农业、水等区域)。)对于卫星图像上的每个像素,土地覆盖分类可以被视为多类语义分割任务。道路和建筑物检测也是交通管理、城市规划和道路监控的重要研究课题。

大规模公开可用数据集很少(如:SpaceNet),数据标注一直是分割任务的瓶颈。

Source: https://blog.playment.io/semantic-segmentation/

d.精准农业

精准农业机器人可以减少农田中需要喷洒的除草剂数量,作物和杂草的语义分割可以实时帮助它们触发除草行动。这种先进的农业图像视觉技术可以减少对农业的人工监控。

Source: https://blog.playment.io/semantic-segmentation/

我们还将考虑一个实际的真实世界案例研究,以理解语义分割的重要性。问题陈述和数据集将在以下章节中介绍。

5.商业问题

在任何机器学习任务中,总是建议花相当多的时间来恰当地理解我们旨在解决的业务问题。这不仅有助于有效地应用技术工具,还能激励开发人员使用他/她的技能来解决现实世界的问题。

TGS 是一家领先的地球科学和数据公司,该公司使用地震图像和 3D 渲染来了解地球表面下哪些区域含有大量石油和天然气。

有趣的是,含有石油和天然气的地表也含有大量的盐。因此,在 T4 地震技术的帮助下,他们试图预测地球表面的哪些区域含有大量的盐。

不幸的是,专业地震成像需要专业的人类视觉来准确识别盐体。这导致高度主观和可变的渲染。此外,如果人类预测不正确,可能会给石油和天然气公司的钻探人员造成巨大损失。

因此,TGS 举办了一场 Kaggle 比赛,利用机器视觉以更高的效率和精确度来解决这个问题。

要了解更多挑战信息,请点击 此处

阅读更多关于地震技术的内容,点击 此处

6.理解数据

这里 下载数据文件。

为简单起见,我们将只使用包含图像及其相应遮罩的 train.zip 文件。

在图像目录中,有 4000 张地震图像被人类专家用来预测该地区是否有盐层。

在 masks 目录中,有 4000 幅灰度图像,它们是相应图像的实际地面真实值,表示地震图像是否包含盐沉积,如果包含,在哪里。这些将用于建立监督学习模型。

让我们将给出的数据形象化,以便更好地理解:

Sample data point and corresponding label

左边的图像是地震图像。画黑色边界只是为了便于理解,表示哪个部分含盐,哪个部分不含盐。(当然这个边界不是原始图像的一部分)

右边的图像被称为遮罩,它是地面真实标签。对于给定的地震图像,这是我们的模型必须预测的。白色区域表示盐沉积,黑色区域表示没有盐。

让我们再看几张图片:

Sample data point and corresponding label

Sample data point and corresponding label

Sample data point and corresponding label

请注意,如果蒙版完全是黑色的,这意味着在给定的地震图像中没有盐沉积。

从上面的几幅图像可以清楚地推断出,对于人类专家来说,对地震图像进行准确的屏蔽预测是不容易的。

7.了解卷积、最大汇集和转置卷积

在深入研究 UNET 模型之前,了解卷积网络中常用的不同运算非常重要。请记下所用的术语。

一、卷积运算

卷积运算有两个输入

I)尺寸为(nin×nin×通道)的 3D 体积(输入图像)

ii)一组“k”个过滤器(也称为内核或特征提取器),每个过滤器的大小为(f×f×通道),其中 f 通常为 3 或 5。

卷积运算的输出也是大小为(nout x nout x k)的 3D 体(也称为输出图像或特征图)。

nin 和 nout 之间的关系如下:

Convolution Arithmetic

卷积运算可以如下所示:

Source: http://cs231n.github.io/convolutional-networks/

在上面的 GIF 中,我们有一个大小为 7x7x3 的输入体积。两个过滤器,每个尺寸为 3x3x3。填充=0,步幅= 2。因此输出体积是 3x3x2。如果你对这种算法感到不舒服,那么在继续下一步之前,你需要先修改卷积网络的概念。

经常使用的一个重要术语叫做感受野。这只是输入体积中特定特征提取器(滤波器)正在查看的区域。在上面的 GIF 中,过滤器在任何给定情况下覆盖的输入体积中的 3x3 蓝色区域是感受野。这有时也被称为语境

简单来说,感受野(context)就是 滤波器在任意给定时间点覆盖的输入图像区域。

ii)最大汇集操作

简单来说,池化的作用就是减少特征图的大小,使我们在网络中的参数更少。

例如:

Source: https://www.quora.com/What-is-max-pooling-in-convolutional-neural-networks#

基本上,从输入特征图的每个 2×2 块中,我们选择最大像素值,从而获得汇集的特征图。请注意,过滤器的大小和跨度是最大池操作中的两个重要的超参数。

其思想是只保留每个区域的重要特征(最大值像素),并丢弃不重要的信息。所谓重要,我指的是最能描述图像上下文的信息。

这里要注意的非常重要的一点是,卷积运算,特别是合并运算,都会减小图像的大小。这被称为下采样。在上面的示例中,合并前图像的大小是 4x4,合并后是 2x2。事实上,下采样基本上意味着将高分辨率图像转换成低分辨率图像。

因此,在汇集之前,存在于 4×4 图像中的信息,在汇集之后,(几乎)相同的信息现在存在于 2×2 图像中。

现在,当我们再次应用卷积运算时,下一层中的滤波器将能够看到更大的上下文,即,随着我们深入网络,图像的尺寸减小,然而感受野增大。

例如,下面是 LeNet 5 架构:

LeNet 5

请注意,在典型的卷积网络中,图像的高度和宽度逐渐减小(由于汇集,向下采样),这有助于更深层中的滤波器聚焦于更大的感受域(上下文)。然而,通道/深度的数量(使用的过滤器数量)逐渐增加,这有助于从图像中提取更复杂的特征。

凭直觉,我们可以对联营作业作出如下结论。通过下采样,模型更好地理解了图像中存在的是什么,但是它丢失了其存在的的信息。****

iii)上采样的需要

如前所述,语义分割的输出不仅仅是一个类标签或一些边界框参数。事实上,输出是一个完整的高分辨率图像,其中所有像素都被分类。

因此,如果我们使用具有池层和密集层的常规卷积网络,我们将丢失“在哪里”的信息,而只保留“是什么”的信息,这不是我们想要的。在细分的情况下,我们既需要“什么”也需要“哪里”的信息。

因此,需要对图像进行上采样,即将低分辨率图像转换为高分辨率图像,以恢复“在哪里”的信息。

在文献中,有许多对图像进行上采样的技术。其中一些是双线性插值、三次插值、最近邻插值、解卷积、转置卷积等。然而,在大多数先进的网络中,转置卷积是对图像进行上采样的首选。

iv)转置卷积

转置卷积(有时也称为去卷积或分数步长卷积)是一种使用可学习参数对图像进行上采样的技术。

我不会描述转置卷积是如何工作的,因为 Naoki Shibuya 已经在他的博客 中用转置卷积 进行了出色的采样。我强烈建议你通读这篇博客(如果需要的话可以多次通读)以了解转置卷积的过程。

然而,在高级别上,转置卷积是与正常卷积完全相反的过程,即,输入体积是低分辨率图像,而输出体积是高分辨率图像。

在博客中,很好地解释了如何将正常卷积表示为输入图像和滤波器的矩阵乘法,以产生输出图像。通过对滤波器矩阵进行转置,我们可以反转卷积过程,因此称为转置卷积。

v)本节概述

阅读本节后,您必须熟悉以下概念:

  • 感受领域或环境
  • 卷积和汇集操作对图像进行下采样,即将高分辨率图像转换为低分辨率图像
  • 最大池操作通过增加感受野来帮助理解图像中有“什么”。然而,它往往会丢失对象“在哪里”的信息。
  • 在语义分割中,不仅重要的是知道图像中存在“什么”,同样重要的是知道它存在于“哪里”。因此,我们需要一种方法来将图像从低分辨率向上采样到高分辨率,这将帮助我们恢复“在哪里”的信息。
  • 转置卷积是执行上采样的最优选选择,上采样基本上是通过反向传播来学习参数,以将低分辨率图像转换为高分辨率图像。

如果您对本节中解释的任何术语或概念感到困惑,请随意再读一遍,直到您熟悉为止。

8.UNET 建筑与培训

UNET 由 Olaf Ronneberger 等人开发,用于生物医学图像分割。该架构包含两条路径。第一条路径是收缩路径(也称为编码器),用于捕获图像中的上下文。编码器只是一个传统的卷积和最大池层堆栈。第二条路径是对称扩展路径(也称为解码器),用于使用转置卷积实现精确定位。因此,它是一个端到端的完全卷积网络(FCN),即它只包含卷积层,不包含任何密集层,因此它可以接受任何大小的图像。

在原始论文中,UNET 是这样描述的:

如果你不明白,没关系。我将尝试更直观地描述这个架构。请注意,在原始纸张中,输入图像的大小是 572x572x3,但是,我们将使用大小为 128x128x3 的输入图像。因此,不同位置的尺寸将与原始纸张中的尺寸不同,但核心组件保持不变。

下面是架构的详细说明:

Detailed UNET Architecture

注意事项:

  • 2@Conv 层意味着应用两个连续的卷积层
  • c1,c2,…c9 是卷积层的输出张量
  • p1、p2、p3 和 p4 是最大池层的输出张量
  • u6、u7、u8 和 u9 是上采样(转置卷积)层的输出张量
  • 左手边是收缩路径(编码器),在这里我们应用常规卷积和最大池层。
  • 在编码器中,图像的尺寸逐渐减小,而深度逐渐增加。从 128x128x3 到 8x8x256
  • 这基本上意味着网络学习了图像中的“什么”信息,然而它丢失了“在哪里”的信息
  • 右手边是扩展路径(解码器),在这里我们应用转置卷积和常规卷积
  • 在解码器中,图像的尺寸逐渐增大,深度逐渐减小。从 8x8x256 到 128x128x1
  • 直观上,解码器通过逐渐应用上采样来恢复“在哪里”的信息(精确定位)
  • 为了获得更精确的位置,在解码器的每一步,我们通过将转置卷积层的输出与来自同一级别的编码器的特征图连接来使用跳过连接:
    U6 = U6+C4
    u7 = u7+C3
    u8 = u8+C2
    u9 = u9+C1
    在每次连接之后,我们再次应用两个连续的常规卷积,以便模型可以学习组装更精确的输出
  • 这使得该建筑呈对称的 U 形,因此得名 UNET
  • 在高层次上,我们有以下关系:
    输入(128x128x1) = >编码器= > (8x8x256) = >解码器= >输出(128x128x1)

下面是定义上述模型的 Keras 代码:

培养

模型用 Adam 优化器编译,我们使用二元交叉熵损失函数,因为只有两个类(盐和无盐)。

我们使用 Keras 回调来实现:

  • 如果验证损失在 5 个连续时期内没有改善,则学习率衰减。
  • 如果验证损失在 10 个连续时期内没有改善,则提前停止。
  • 仅当验证损失有所改善时,才保存权重。

我们使用的批量大小为 32。

请注意,可能有很大的余地来调整这些超参数,并进一步提高模型性能。

该模型在 P4000 GPU 上训练,训练时间不到 20 分钟。

9.推理

注意,对于每个像素,我们得到一个 0 到 1 之间的值。
0 代表无盐,1 代表盐。
我们以 0.5 为阈值来决定一个像素是归类为 0 还是 1。

然而,决定阈值是棘手的,可以被视为另一个超参数。

让我们看看训练集和验证集的一些结果:

训练集的结果

********

验证集的结果

训练集上的结果相对好于验证集上的结果,这意味着模型遭受过拟合。一个明显的原因可能是用于训练模型的图像数量较少。

10.结论

感谢您对博客的兴趣。如果您有任何意见、反馈和建议,请留下。

完整代码在我的 GitHub 回购T3 这里

11.参考

从不同的角度理解随机梯度下降

原文:https://towardsdatascience.com/understanding-stochastic-gradient-descent-in-a-different-perspective-e4e54d47e26c?source=collection_archive---------18-----------------------

gradient descent path in a contour line with 2D feature space (from Genevieve B. Orr)

随机优化 [1]是训练神经网络时常用的方法。在此基础上,还有像 SGD with Momentum、Adagrad、RMSProp、这样的方法可以给出不错的训练结果。上图显示了 2D 等高线中的之字形梯度下降路径。人们相信使用随机梯度下降法,因为它被认为是计算友好的,因为模型有大量的参数。也就是说,SGD 可以达到的最好结果相当于具有相同超参数设置的普通梯度下降法。然而,我们会发现,在很多情况下,SGD 在测试集上提供了更好的性能。最近在高级深度学习课程中,我被教导从不同的角度来看待 SGD 方法,它认为它类似于正则化。

香草梯度下降

假设我们的损失函数看起来像这样:

似乎 B 点是我们通过执行梯度下降想要到达的地方,因为 B 处于全局最小值。但是,如果参数有很小的偏移,损失的值会有很大的变化。我们应该注意到,这个损失函数仅仅是基于我们可以看到的训练集绘制的。通常,测试数据会有很小的变化。所以我们想要达到的理想点实际上是 D,因为它给出了我们模型的最佳概括能力。

在香草梯度下降的情况下,如果我们在点 A 初始化模型,它将一直下降到点 B。并且它没有办法从 B 周围的凹区域逃脱(具有合理的学习速率)。解决这个问题的直接方法是引入随机采样噪声。然而,与训练数据的学习分布相比,随机采样的噪声通常是微不足道的。

随机梯度下降

随机梯度下降方法是这个问题的完美解决方案。SGD 使用 MAP 估计值计算的梯度如下所示:

在每次迭代中,我们将随机对数据进行采样,并将梯度计算为整个数据集上真实梯度的近似值。

由于在一次迭代中用于训练的所有数据都是从训练集中随机采样的,因此它们将具有不同的分布,从而给我们更多的自由来探索损失函数的空间。所以更有可能达到我们想要的最小值(如上图)。迷你浴池的尺寸越小,损失功能空间越大。在我看来,随机梯度下降方法与交叉验证、方法具有相同的高级精神,因为两种方法都一次性使用部分训练数据,并尝试不同的可能分布,以增加模型的泛化能力。

随机梯度朗之万动力学

在[2]中,上述思想得到了进一步发展。通过随机梯度朗之万动力学(SGLD) 计算的梯度为:

SGLD 方法将高斯噪声引入到梯度中,这确保了最终探索整个支持。它被看作是随机微分方程的离散化。通过遵循马尔可夫链蒙特卡罗(MCMC)技术,SGLD 方法使模型能够捕捉参数不确定性,这是一种流行的贝叶斯方法来执行不确定性估计。

参考

[1] Robbins H,Monro S .一种随机逼近方法[J].数理统计年鉴,1951:400–407。

[2] Welling M,Y W .通过随机梯度朗之万动力学进行贝叶斯学习[C]//第 28 届国际机器学习会议(ICML-11)论文集。2011: 681–688.

理解流处理和 Apache Kafka

原文:https://towardsdatascience.com/understanding-stream-processing-and-apache-kafka-5610bc2d6fa3?source=collection_archive---------16-----------------------

观看节目时被称为 Torrenting,包括下载整个 mp4 文件并在本地观看。相比之下,流式传输意味着当数据包到达时,您正在观看节目。流处理是处理连续的输入数据流的行为。

活动采购

假设我们负责一个社交媒体平台。在传统方法中,我们将所有用户数据存储在某种持久存储中,比如关系数据库。每当其中一个用户更新他们的状态时,数据库中的值就会被覆盖。Event sourcing 认为这不是存储数据的好方法,因为我们可能希望使用以前的值进行业务分析。相反,我们应该单独记录数据库发生的每个变化。回到我们的例子,每次用户改变他们的状态,我们会创建一个单独的条目,而不是覆盖以前的值。每当数据库收到读取数据的请求时,我们都返回最新的值。

原始事件的形式非常适合写入,因为您不需要搜索条目并更新它。相反,您可以将事件附加到日志的末尾。另一方面,聚合数据的形式非常适合读取。如果用户正在查看某人的状态,他们不会对导致当前状态的所有修改历史感兴趣。因此,将写入系统的方式与读取系统的方式分开是有意义的。我们会回来的。

现在,假设一个用户试图查看他们的朋友列表。为了将这些信息呈现给用户,我们必须对数据库执行读取查询。假设活跃用户的数量从 10,000 增加到 100,000。这意味着我们必须将与这 90,000 个额外用户中的每一个相对应的信息存储到我们的数据库中。一些非常聪明的人已经想出了可以达到 O(log n)量级性能的搜索算法。然而,随着条目数量的增加,搜索某个值所花费的时间仍然会增加。因此,在扩展时实现一致的低延迟要求您利用缓存。缓存将只保存全部数据的一个子集。因此,查询花费的时间更少,因为它们不必遍历那么多的元素。

双重写入

缓存和其他形式的冗余数据(如索引)通常对于获得良好的读取性能至关重要。然而,保持不同系统之间的数据同步成为一个真正的挑战。在双写方法中,更新所有适当位置的数据是应用程序代码的责任。

假设我们有一个用户可以互相发送消息的应用程序。当发送新消息时,我们要做两件事:

  • 将邮件添加到用户的收件箱
  • 增加用户未读邮件的数量

我们保留一个单独的计数器,因为我们一直在用户界面上显示它,如果每次需要显示未读邮件数时都要扫描邮件列表来查询未读邮件数,会太慢。该计数来自收件箱中的实际邮件。因此,每当未读消息的数量发生变化时,我们需要相应地更新计数器。

假设我们有以下场景:

客户端向另一个用户发送消息,将其插入收件人的收件箱。然后,客户端请求增加未读计数器。然而,就在那一刻,出现了问题,可能是数据库宕机,或者某个进程崩溃,或者网络中断。不管什么原因,对未读计数器的更新都会失败。

现在,我们的数据库不一致。我们不一定知道哪些计数器与哪些收件箱不一致。因此,解决这个问题的唯一方法是定期重新计算值,如果我们有很多用户,这可能会非常昂贵。

即使一切运行顺利,我们仍然会遇到像比赛条件这样的问题。

假设我们有以下场景:

第一数据存储中的 x 值由第一客户端设置为 y,然后由第二客户端设置为 z。

在第二个数据存储中,请求以不同的顺序到达,值首先被设置为 z,然后是 y。

现在,两个数据存储区再次不一致。

分布式流媒体平台

很多时候,我们希望将应用程序数据用于其他目的,例如训练机器学习模型或可视化趋势。但是,我们不能直接从数据库中读取值,因为那样会占用资源,而这些资源本来可以用来处理用户对数据的请求。因此,我们必须在其他地方复制数据,这不可避免地会导致前面讨论过的相同问题。

那么,我们如何在几个不同的系统中获得相同数据的副本,并在数据变化时保持它们一致的同步呢?有多种可能的解决方案,但在本文中,我们将介绍分布式流媒体平台 Apache Kafka。

在大多数应用程序中,日志是对用户隐藏的实现细节。例如,大多数关系数据库使用预写日志。实际上,每当数据库必须对底层数据进行更改时,它都会将这些更改附加到预写日志中。如果数据库在执行写操作时崩溃,它可以重置为已知状态。

在卡夫卡那里,木头成了一等公民。换句话说,主要的存储机制是日志本身。为了使 Kafka 具有水平可伸缩性,日志被分割成多个分区。每个分区都存储在磁盘上,并在几台机器上复制,因此它可以承受机器故障而不会丢失数据。

回到我们的社交媒体应用程序的例子,用户所做的任何更改都将被发送到后端服务器。然后,服务器可以将这些更改作为事件添加到日志中。数据库、索引、缓存和所有其他存储系统都可以通过顺序读取日志来构建。

回想一下,在事件源的上下文中,日志是写入的理想选择,因为它们只需将数据附加到末尾,而数据库是读取的理想选择,因为它们只包含当前状态。

卡夫卡之所以能够解决竞争条件的问题,是因为它实施了严格的事件排序。每个消费者从日志的开头开始,读取每个事件,更新其内容,直到它被赶上。在数据库崩溃的情况下,它能够从它停止的地方继续读取日志,直到它被赶上。

最后的想法

流处理指的是我们如何处理新的输入数据。Kafka 是一个开源的分布式流媒体平台,它提供了一种跨不同存储系统可靠获取数据的机制。

理解种族划分的研究

原文:https://towardsdatascience.com/understanding-studies-of-racial-demarcations-4f239d7f8a28?source=collection_archive---------20-----------------------

种族划分的研究通常是在回归分析的背景下进行的。简而言之,回归能够评估某些感兴趣的变量(比如学生的考试成绩)与定义所述学生的变量(比如种族、家庭收入、父母的职业、父母的教育程度等)之间的关系。

形象地说,用 x 表示定义学生的变量,用 y 表示学生的考试成绩,回归表明:

Y=f(x_1,x_2,x_3,…,x_n)。

这被解释为,“y 独立地与 x_1、x_2、x_3 中的每一个相关,直到 x_n。”

虽然解释为“y 独立地是 x_1、x_2、x_3 中的每一个的函数(等效地,受其影响),直到 x_n”是可接受的,但这通常是可接受的夸张,并不总是正确的。

在不接受夸大的情况下,决策的条件化,包括政府内部发生的政策决策,对回归结果的条件化是不可能的。

S uppose a 回归显示' 学生考试成绩 ,以考试成绩为数据(y) '受' 父母财富 (x_1),以收入或净资产为数据',并认为'白人学生分数高于黑人学生, 白人= '是',而黑人= '否'

缺少任何额外的信息,综合起来,结果,

测试分数随着财富的增加而增加,

白人孩子的考试分数更高

不要暗示白人父母比黑人父母有钱。只有对人口统计学数据的研究才能揭示白人父母比黑人父母更富有。

解释回归的规范性原则一:

综合起来,y 和 x_1 之间的关系以及 y 和 x_2 之间的关系本身并不意味着 x_1 和 x_2 之间的关系。

S uppose ' 白人父母为他们的孩子提供更好的早餐 ,将不同选择的营养价值不同的早餐标识为数据',但这并没有在回归模型的上下文中明确探讨。假设,正如已经假设的那样,白人孩子在测试中比黑人孩子得分高。

人们可以假设,鉴于白人孩子通常在考试中得分较高,部分原因可能是白人父母给孩子提供的早餐比黑人父母好。虽然这一假设事实上可能是正确的,但它不能从考试成绩和种族界限之间的关系中推导出来。回归只对显式包含为变量的数据进行陈述,不对可能与该数据相关的因素进行任何显式陈述。

为了进一步探索这一点,假设 白人父母比黑人父母 更有可能为他们的孩子雇佣家教,以‘雇佣家教=‘是’或‘否’作为数据,而 白人更有可能在家庭作业 的背景下与他们的孩子互动,以‘参与家庭作业=‘是’或‘否’作为数据。虽然这些因素可能与种族相关,但如果没有将“父母为子女聘请家教”、“是”或“否”以及“父母在家庭作业背景下与子女互动”、“是”或“否”作为变量纳入回归,则不能假设回归对这些因素做出任何明确的陈述。

如果研究人员试图对额外的相关因素做出明确的陈述,这些因素必须明确地包含在回归中。

解释回归的规范原则二:

假设 x_2 和 x_3 与 x_1 相关,但不包括在 y 对 x_1 的一个回归中[y=f(x_1)]。虽然可以说 x_2 和 x_3 是 y 和 x_1 相关的来源,但不能说 y 与 x_2 或 x_3 相关。

Y 你可能想知道,“为什么不把 x_2 和 x_3 包括在 Y 对 x 的回归中,这样研究者就可以得出 Y 和 x_2 之间的关系,以及 Y 和 x_3 之间的关系和 Y 和 x_1 之间的关系?”

形象地说,为什么不具体说明:

y=f(x_1,x_2,x_3),与 y=f(x_1)相对?

问题?

给定 x_2 和 x_3 中的每一个都与 y 相关,在同一个回归中包含 x_1、x_2 和 x_3 使得从回归中获得的任何结果都不太可信。在规定的条件下,结果可信度的下降是回归分析的一个典型事实。在专家中,这个问题被称为由'x1,x2,x3 '多重共线性引起的问题。

如果研究人员真的相信 x_2 和 x_3 是重要的,他或她将不得不分别探索 y 和 x_2y 和 x_3 之间的关系,或者找到一种方法将 x_2 和 x_3 用“”、x_2 和 x_3 用“正交化”

但是这变得很专业,对于不熟悉回归分析的普通读者来说很难理解。

事实是什么?研究人员有时对事物有先入为主的看法,结果他们做出的推论与我概述的解释回归的两个规范性原则相矛盾。读者有责任意识到这些原则,因此能够不理会任何与概述的原则相矛盾的解释。

在种族划分的背景下,回归分析的正确使用是为了更好地理解种族之间的差异,了解可以通过教育或财富调节的显著差异。

例如,提高早餐的营养价值可以提高小学生的学习成绩,这一发现导致了一些旨在帮助相对贫困家庭的孩子吃更好的早餐的倡议。鉴于营养早餐的重要性随着儿童年龄的增长而下降,营养早餐的益处在以后的生活中是无法获得的。如果一个孩子在小学没有得到营养早餐的好处,那么失去的好处在以后的生活中是无法弥补的。

一个胎儿不能在第四个三月发育成它应该在第三个三月发育成的样子。这就是为什么每当分娩的持续时间莫名其妙地超过妊娠晚期时,分娩就会被诱发。

在医疗健康方面,非裔美国人比白人更易患糖尿病的发现导致了对针对非裔美国人的治疗和预防性饮食的开发的更多关注。

正确地组织和使用,对不同种族间明显分界线的研究可以成为一种有益于社会的力量。

假定不同种族的智力分布是相同的,那么试图推断智力界限的种族界限研究违反了事实和矛盾的数据。

事实呢?

有高中辍学的白人和黑人。

有从大学辍学的白人和黑人。

有白人也有黑人毕业生。

在科学、工程、商业等领域,有来自顶尖大学的白人和黑人博士。

获得诺贝尔经济学奖的白人越来越多,但已经有一个黑人了。

诚然,财富、收入水平和父母的教育水平等因素会影响孩子在学校的表现,但这些因素只是将考试分数的分布向左或向右移动,保持相同的分布。然后,我们有了正确的解释,对种族分界的研究探索了将相同的“钟形曲线”智力分布从白人或黑人的分布中向左或向右移动的因素。

如果智力在不同种族间的分布是相同的,那么对不同种族间智力系统性差异的研究与事实证据相矛盾。与事实证据相矛盾的研究证据永远不会可靠。遗传学领域的研究一致认为,没有任何可靠的证据表明,在不同种族的天生智力方面存在系统性的遗传差异。

如果研究论文的读者和研究人员在不违反解释原则的情况下,以负责任的态度解释回归分析的结果,那么对研究结果的讨论不存在偏见的可能性就会提高,从而有利于社会。

透过 Grab 数据透视打车供需

原文:https://towardsdatascience.com/understanding-supply-demand-in-ride-hailing-through-the-lens-of-grab-data-23e24224547f?source=collection_archive---------11-----------------------

阿尤什·加尔格拉拉·普鲁姆·伊姆春凯·潘合著

打车第一目标:分配

Grab 的打车业务最简单的形式就是撮合寻找舒适交通方式的乘客和寻找灵活赚钱机会的司机。

在过去的 6 年里,Grab 反复微调其机器学习算法,目标是确保乘客在他们想要的时候搭车,并将他们与离他们最近的司机匹配。

但是司机们总是在移动,在任何一个时间点都可能有数百名乘客在同一个区域内要求搭车。这意味着有时,最近的可用司机可能仍然太远。

Grab 的分析团队试图通过明确定义的指标来大规模分析这些实例。我们研究差距,以便我们可以确定潜在的产品和运营解决方案,这些解决方案可能会引导供应和需求朝着地理时间一致和更好的体验的方向发展。

在本文中,我们将向您介绍我们的一项分析计划——测量任何给定地区和时间的供需比率。

定义供需

供应的单个单元被认为是在 x 秒时段开始时在线且空闲(当前未在工作)的驱动器,其中 x 是极小的时间单元。驾驶员在这个 x 秒时段开始时的 GPS ping 被认为是他或她的位置。

需求的单个单位被视为在相同的 x 秒时段内通过我们的应用程序查询乘车费用的乘客。我们认为乘客的位置就是输入的上车地址。

映射供需

出于分析的目的,每个位置被聚合为 geohash(编码为字母和数字字符串的地理位置),精度为 y ,其中 y 表示地图上一个非常小的面空间维度。然后,每个供应单位被映射到供应的相邻地理散列内的所有需求单位,如图图 1 所示。

Figure 1: Illustration depicting a supply unit distributed among the demand units in its neighbouring geohashes

每个供应单元的一部分被分配给相邻地理哈希中的每个需求单元,地理哈希按距离反向加权。本质上,这意味着与较远的乘客相比,较近的乘客更容易找到司机。

为了简化本文,我们使用直线距离代替路径距离作为代理,以降低算法的复杂性。

每位乘客的可用驾驶员分数的总和将给出每位乘客的有效供给。这在图 1 中描述,其中每个乘客分享一小部分供应。

对于此分析,我们汇总了每个地理哈希 i 和时隙 j 组合的需求和有效供给,从而得出两个简单的汇总指标:供需比供需差 ( 图 2 )

Figure 2: The metrics aggregated for any area and time slot

处理数据

虽然由此产生的指标看起来像是简单的比率和差异,但计算有效供应量需要绘制相邻空间中每个司机和乘客的地图,这是一项相当繁重的计算。

在整个地区,在任何给定的时间点,都可能有成千上万的乘客在寻找搭车机会。我们的算法不仅识别每个需求和供应单元及其位置,还将每个供应单元映射到同一邻域中的所有需求单元,以输出每个乘客可用的部分供应。

简而言之,复杂性可以总结如下:每一个额外的供应或需求单位都会以指数方式增加算法的计算能力。

这只是分析团队每天处理的许多高计算问题之一。因此,问题的解决不一定要以开发一个代表网络的算法或度量标准为结束,而是要能够使它具有高性能和可用性,即使在业务扩展时也是如此。

在地图上可视化度量

利用我们上面讨论的指标,我们可以绘制出需求和供给之间的差距如何在一天中演变。下面的 GIF 展示了新加坡典型一天的供需缺口。

每个气泡表示地图上的一个微小区域。每个泡沫的大小表明了该地区的供需差异——泡沫越大,缺口越大。我们还用彩色气泡来表示供求比率,红色表示供应不足,绿色表示供应过剩。

为了实现我们的目标,确保乘客随时都能找到他们想要的交通工具,我们需要平衡需求和供给。在 Grab,我们通过多种方式做到这一点,包括一方面想办法将供应过剩转移到需求更高的地区,另一方面将对时间不太敏感的需求从高峰时段转移出去。

确定位置供应的空间机会

Figure 3: Supply Demand Distribution in Singapore on a typical weekday

在一天中的任何给定时间,一个地区的驾驶员可能供过于求,而另一个地区则供不应求。

如图图 3* 所示,这种情况在新加坡很常见,因为早高峰过后,大多数出行都在 CBD 结束,导致该地区供过于求。这种情况在樟宜机场等排队点也很常见。*

为了解决这种地理时间错位,Grab 最近更新了 Grab Driver 应用程序上的热图,以鼓励司机从供应过剩的地区转移到需求更高的地区。

识别移动需求的时间机会

Figure 4: Typical Supply Demand Distribution in a small residential area in Singapore across the day.

图 4 是新加坡一个小型住宅区典型工作日的供需汇总图。

图 4 中突出显示的区域描绘了需求和供应不匹配的时间段。根据历史数据,我们知道需求会因各种因素而达到峰值,包括预期的(通常的高峰时段)和意外的(突然的暴雨)。然而,供给的增加会延迟一段时间,通常是在需求已经下降的时候。

Figure 5: Travel Trends Widget on the Passenger App showing best times to book in River Valley (Singapore)

为了解决这种不平衡,Grab 最近在乘客应用程序上推出了一个出行趋势小工具 ( 图 5 ),让我们的乘客了解几个小时内的预测需求分布。

此小部件根据乘客特定位置的历史数据总和,向您显示需求趋势。这里的目标是鼓励对时间不敏感的需求(不需要立即乘车的乘客)稍晚预订,帮助有更紧急需求的乘客更容易获得分配。

作为其有用性的证明,旅行趋势窗口小部件现在在 Grab 的所有窗口小部件中排名第一!通过最高的点击率,我们观察到成千上万的人发现它对他们的日常使用很有用!请关注下一个升级版本,我们将继续改进它,使其更具上下文相关性和智能性!

敬请期待更多!

考虑到不断变化的现实,即不断波动的供应和需求,Grab 运输团队的最终目标可以归结为一件事:确保我们的乘客能够在他们需要的时间和地点尽可能快和容易地搭车;同时通过奖励体验为我们的司机提供更好的生活。

要做到这一点,平衡需求和供给至关重要。我们有许多方法做这件事。我们在这篇文章中分享了一些,但另一个重要的因素是动态定价——票价根据供求关系的变化而变化。

我们将在另一篇文章中进一步探讨这个话题。敬请关注!

感兴趣?加入我们吧!

Grab 的分析团队为 Grab 的所有服务和产品提供整体支持。

这只是分析团队努力深入理解我们的数据、使用它评估平台性能并不断迭代以构建更好的数据驱动产品的一瞥。

如果你有兴趣解决这样的问题,加入我们吧!我们在招人!访问我们的职业网站查看职位空缺!

回执

我们要感谢对上述工作做出贡献的许多人:Ashwin Madelil(产品经理)、Shrey Jain(产品经理)、Brahmasta Adipradana(产品经理)、Prashant Kumar(产品经理)和 Ajmal Jamal(设计师)。

还发表在 Grab 旗下的中型刊物&Grab 旗下的工程博客

了解机器学习回归的 3 种最常见损失函数

原文:https://towardsdatascience.com/understanding-the-3-most-common-loss-functions-for-machine-learning-regression-23e0ef3e14d3?source=collection_archive---------0-----------------------

想获得灵感?快来加入我的 超级行情快讯 。😎

机器学习中的损失函数是对你的 ML 模型能够多准确地预测预期结果(即基本事实)的一种度量。

损失函数将两个项目作为输入:我们的模型的输出值和地面真实期望值。损失函数的输出被称为损失,这是我们的模型在预测结果方面做得有多好的一个度量。

高损失值意味着我们的模型表现很差。较低的损失值意味着我们的模型表现得非常好。

选择合适的损失函数对于训练精确的模型是至关重要的。某些损失函数将具有某些属性,并帮助您的模型以特定的方式学习。有些人可能更看重离群值,有些人则更看重多数值。

在这篇文章中,我们将看看机器学习回归的 3 个最常见的损失函数。我将解释它们是如何工作的,它们的优缺点,以及在训练回归模型时如何最有效地应用它们。

(1)均方误差

均方差(MSE)可能是最简单和最常见的损失函数,经常在机器学习入门课程中讲授。要计算 MSE,您需要获取模型预测值和地面真实值之间的差值,对其求平方,然后在整个数据集内取平均值。

MSE 永远不会是负的,因为我们总是在平方误差。MSE 由下式正式定义:

其中 N 是我们测试的样本数。代码非常简单,我们可以用普通的 numpy 编写它,并使用 matplotlib 绘制它:

MSE Loss Function

优势:MSE 非常有助于确保我们训练的模型没有具有巨大误差的异常值预测,因为 MSE 由于函数的平方部分而对这些误差赋予了更大的权重。

缺点:如果我们的模型做出一个非常糟糕的预测,函数的平方部分会放大误差。然而,在许多实际情况下,我们并不太关心这些异常值,我们的目标是更全面的模型,在大多数情况下表现足够好。

(2)平均绝对误差

平均绝对误差(MAE)在定义上与 MSE 略有不同,但有趣的是,它提供了几乎完全相反的性质!要计算 MAE,您需要获取模型预测和地面实况之间的差异,将绝对值应用于该差异,然后在整个数据集内进行平均。

MAE 和 MSE 一样,永远不会是负值,因为在这种情况下,我们总是取误差的绝对值。MAE 由以下等式正式定义:

我们的代码在 Python 中再次变得超级简单!我们可以用普通的 numpy 编写它,并用 matplotlib 绘制它。这一次,我们将在 MSE 的正上方用红色标出,看看它们是如何比较的。

MAE (red) and MSE (blue) loss functions

优势:MAE 的妙处在于它的优势直接覆盖了 MSE 的劣势。因为我们取绝对值,所有的误差将在相同的线性标度上加权。因此,与 MSE 不同,我们不会将太多的权重放在异常值上,我们的损失函数提供了一个通用的甚至是衡量我们的模型表现如何的标准。

缺点:如果我们真的关心模型的异常预测,那么 MAE 就不会那么有效。来自异常值的较大误差最终与较低误差一样被加权。这可能导致我们的模型在大多数时候都很好,但偶尔会做出一些非常糟糕的预测。

(3)胡伯损失

现在我们知道 MSE 非常适合学习异常值,而 MAE 非常适合忽略它们。但是中间的东西呢?

考虑一个例子,我们有一个 100 个值的数据集,我们希望我们的模型被训练来预测。在所有这些数据中,25%的预期值是 5,而另外 75%是 10。

一个 MSE 损失并不能完全解决问题,因为我们并没有真正的“异常值”;25%绝不是一个小分数。另一方面,我们不一定要用 MAE 来衡量太低的 25%。这些值 5 并不接近中值(10——因为 75%的点的值为 10 ),但它们也不是真正的异常值。

我们的解决方案?

胡贝尔损失函数

Huber Loss 通过同时平衡 MSE 和 MAE 提供了两个世界的最佳选择。我们可以使用以下分段函数来定义它:

这个等式本质上说的是:对于小于δ的损失值,使用 MSE 对于大于 delta 的损失值,使用 MAE。这有效地结合了两个损失函数的优点!

对较大的损失值使用 MAE 减轻了我们对异常值的重视,因此我们仍然可以得到一个全面的模型。同时,我们使用较小损失值的 MSE 来保持中心附近的二次函数。

只要损失值大于 1,这就具有放大损失值的效果。一旦这些数据点的损失下降到 1 以下,二次函数就降低它们的权重,以将训练集中在更高误差的数据点上。

查看以下 Huber 损失函数的代码。我们还在 MSE 和 MAE 旁边绘制了 Huber 损失,以比较差异。

MSE

MAE (red), MSE (blue), and Huber (green) loss functions

请注意,我们是如何在 MSE 和 MAE 之间得到 Huber 损失的。

两全其美!

当你觉得需要在给异常值一些权重,但不要太多之间取得平衡时,你会想要使用 Huber 损失。对于异常值对您非常重要的情况,使用 MSE!对于您根本不关心异常值的情况,请使用 MAE!

喜欢学习?

在 twitter 上关注我,我会在这里发布所有最新最棒的人工智能、技术和科学!也在 LinkedIn 上和我联系吧!

了解数据科学的基础知识

原文:https://towardsdatascience.com/understanding-the-basics-of-data-science-883b0ebbf5e0?source=collection_archive---------18-----------------------

在这篇博客中,我将讲述在尝试任何类型的数据科学问题之前应该知道的基础知识。我认为,在开始解决任何数据科学问题之前,您应该了解两件关键事情:

1.您将使用什么数据集?

2.机器学习算法的主要类型有哪些?

让我们来详细看看每个问题。

1.您将使用什么数据集?

数据集是手头问题的支柱。在解决任何数据科学问题时,选择具有正确数据量的正确数据集至关重要。数据集应该满足的一些基本要求是:

a.相关数据:

请记住,您不能使用任何数据集来解决特定的问题。那么,‘相关’数据集是什么样子的呢?

在上面的例子中,左边的表数据集列彼此完全不相关。患者标识符与当前股票价格和不同保险计划的保费金额无关。

而在右边的表格中,每一行都可以与一个特定的患者相关联。不同的列实际上限定了患者,并被称为数据集的‘特征’

b.数据大小:

在解决数据科学问题时,估计所需的正确数据量至关重要。经验法则是,例如,如果您有 20 个分类变量,每个变量有 15 个级别/类别,18 个连续变量(对于连续变量,假设有 10 个级别/类别),那么所需的最小行数是:(20 * 15 + 18 * 10) * 100 = 48,000 行。(100 只是一个乘数,可以根据可用数据量和考虑的应用领域而变化)

还有一个很重要的概念就是‘稀疏数据’。如果数据集有许多缺失值,那么该数据称为稀疏数据。有多种方法(如 KNN 插补、平均值/中值插补等)。)中,我们可以根据应用领域来处理缺失值。(我在这篇博客中不涉及数据插补部分。)

2.机器学习算法的主要类型有哪些?

因此,一旦你有了正确的结构和数据量,让我们看看不同类型的机器学习算法可用于解决问题。首先你需要理解一个算法到底是做什么的。给定一个适当的数据集,算法会给出用户所提问题的答案。为了简单起见,我用算法帮助我们回答的一个问题来表示每种类型的算法。

我相信任何机器学习算法都有助于回答以下 5 个问题:

a.多少/多少?

b.哪一类?

c.哪个组?

d.行为不正常吗?

e.什么行动?

让我们深入其中的每一个,探索其中的奥秘。

a.多少/多少?

线性回归、多项式回归等。是从本质上帮助我们回答一些问题的算法,比如:

  • 未来 12 个月每个销售代表的销售额是多少?
  • 这种新上市的药物销量如何?
  • 每个账户持有人的保险费金额是多少?

b.哪一类?

分类算法使我们能够回答必须预测类别的问题。分类算法是那些当你知道你必须把每个实体分成固定数量的类或类别时抛出一个类别的算法。这些也被称为‘监督分类器’。

  • 确定每位医生的类别,他是早期采用者/中期采用者/后期采用者?(多类分类器)
  • 在多适应症市场中,将每个患者与特定的适应症/诊断对应起来。
  • 病人患了癌症吗?—是/否(二元分类器)

c.哪个组?

那么如果你不知道数据需要分成多少个类别呢?别担心,也有算法为你服务。这样的算法叫做‘无监督算法’:聚类,推荐引擎。

  • 识别具有相似药物处方模式的医师群。
  • 哪些网上购物者有类似的购物模式?
  • 应该向网飞上的每个用户推荐哪些电影?

e.行为不正常吗?

这种问题一开始可能看起来很模糊,但它有很多实际的例子。这些算法被称为“异常检测器”

  • 欺诈检测取决于在线时间长度/登录位置/消费模式和频率。
  • 在计算机群集中,确定参数以确定计算机是否会出现故障。

e.什么行动?

在最后一个类别中,有些系统需要实时做出决策,没有大量的数据要处理,但有数据流要处理。此外,环境变量的变化会改变前面场景中应用的整个规则集。学习代理通过与其环境交互并观察这些交互的结果来学习。这模仿了人类(和动物一样)学习的基本方式。

一种这样的算法被称为强化学习’。这个想法通常被称为‘因’‘果’

  • 玩游戏:让电脑决定游戏中的最佳走法。
  • 控制问题:在自动驾驶汽车中,系统必须持续监控实时环境变量,并做出决定,例如刹车或加速。

所有 5 大类的机器学习算法几乎涵盖了整个机器学习领域,并以非常简单的方式和通俗易懂的语言进行了讨论(不可能在一篇博客中涵盖详细的解释)。我将在接下来的博客中详细介绍这些算法。

我想用一句话来结束这篇博客:“机器学习其实并不复杂,但它是一门外语。”

如果您有任何问题或建议,请在下面评论。

这篇内容最初发表在我的个人博客网站上:【http://datascienceninja.com/。点击此处查看并订阅,即时接收最新博客更新。

理解中心极限定理

原文:https://towardsdatascience.com/understanding-the-central-limit-theorem-e598158cc5da?source=collection_archive---------11-----------------------

深入研究统计学中最重要的定理之一

在这篇文章中,我想谈谈中心极限定理及其在统计学中的应用。中心极限定理指出,如果数据独立地从任何分布中抽取,并且样本大小足够大,样本均值总是呈现正态分布。目前这可能有点难以理解,所以让我们来看看样本均值及其属性。让我们试着计算样本均值和样本方差的期望值,这并不十分困难。这里,我们假设我们的数据是完全相同且独立分布的,并从样本均值的定义开始:

现在我们可以从期望值中取出常数 1/n:

接下来,我们将期望值包含在总和中:

这里,每个观测值的期望值是𝜇:

右边的项是 n 次𝜇之和除以 n,得到样本均值的期望值,即𝜇本身:

接下来,我们尝试计算样本均值的方差,这有点复杂但很重要。我们像以前一样对数据进行相同的假设,并从方差的定义开始:

我们可以看到等式中的样本均值,这非常好,因为我们已经在上面计算过了:

现在,我们将样本均值项扩展为单个数据点,并将其与𝜇:相结合

然后我们将平方项分成两项:

这与寻找 x i 和 x j 之间的协方差相同:

现在,我们知道,当 I 不等于 j 时,协方差为 0,因为根据我们最初的假设,它们是独立的观测值。所以,我们只剩下 i = j 的项,其中 n 项等于 x 的方差I:

请注意,当 n → ∞时,样本均值的方差趋近于 0。

既然我们知道了样本均值和方差的期望值,我们就能更好地讨论中心极限定理了。但是首先,我们应该讨论一种叫做分布收敛的收敛类型,它表明一个统计量将收敛到一个具有某种内在随机性的整个分布。这意味着当我们采用足够大的样本量时,统计量的概率密度函数应该收敛于特定分布的 pdf。中心极限定理是同样的一个应用,它说,如果我们取足够大的样本,任何分布的样本均值应该收敛于一个正态分布。一旦我们将样本均值标准化,我们就可以将其近似为标准的正态分布。标准化尤其意味着从变量中减去平均值,然后除以标准差。中心极限定理可以用数学方法表示如下:

这里,z 是样本均值的标准化形式,也称为 z 统计量,𝜇是总体均值,𝜎是总体标准差。我们得到一个根 n 项,因为正如我们之前推导的,样本均值的标准差等于总体的标准差除以 n。

既然对中心极限定理有了了解,那就用一些数据来检验一下吧。为此,我用 R 写了一个函数,使用它我们可以从我们选择的分布中抽取不同大小的样本。

simulate 函数接受两个输入: nsim ,模拟的数量和 nvec ,要使用的 n 个样本的数量,并为我们稍后生成的数据返回一个正确形状的 data.table 类。然后,我们使用 simulate 函数创建一个表来存储 100,000 个大小分别为 1、2、3、5 的样本。然后我们从 1 到-1 之间的均匀分布中抽取样本。然后,我们计算所有样本的平均值,并分别绘制每个样本大小的 pdf。

对于 n=1,我们看到 z 和我们的数据一样遵循均匀分布。

对于 n=2,z 遵循一种三角形形状。

对于 n=3,事情开始变得有趣,z 开始看起来像一个钟形曲线。

对于 n=5,z 变得几乎完全正常。因此,对于小至 5 的样本量,我们能够观察到中心极限定理,这使得它在真实数据中更加有效。

当我们不想对数据的分布进行建模,并且我们只需要关心统计分析的平均值和方差时,我们使用中心极限定理。这是统计学中最重要和最有用的定理之一。

理解中心极限定理、标准误差和置信区间

原文:https://towardsdatascience.com/understanding-the-central-limit-theorem-standard-error-and-confidence-intervals-7e20c674a51a?source=collection_archive---------10-----------------------

理解上述概念的工作示例

在本帖中,我们将建立对描述性统计(包括均值和标准差)和推断性统计(包括均值的标准差和置信区间)的直观理解。在这个过程中,我们还将加深对中心极限定理的理解。本文中用于生成示例的 R 代码可从这里获得。

让我们从假设一个国家有 N = 10,000 名学生在 10 年级学习物理开始我们的旅程。我们记录了他们在期末考试后获得的分数(满分为 100 分),这些分数的直方图(间隔为 10)如图 1 所示。这个直方图代表了我们的人口分布。

Figure 1 Histogram of the marks obtained by all 10th grade students in Physics across the country (population distribution).

现在,我们可以使用以下公式计算总体均值(μ)和标准差(σ):

其中 xᵢ代表 iᵗʰ学生的分数,n 代表全国学生总数。对于图 1 所示的人口分布,μ = 71.52,σ = 16.15。这两者都是描述性统计,因为它们描述了手头数据的一些特征。平均值代表数据的中心性(中心是中值),标准差代表每个点与平均值的差异程度。较小的σ表示数据集中的值接近数据的平均值,而较大的σ表示数据集中的值远离平均值。我们可以看到,我们的人口分布在左边有一个比右边更长的尾巴,这种分布被称为左偏。

需要注意的是,我们的人口分布需要全国所有学生的数据。这一要求实际上很难满足,我们通常无法获得人口分布(以及相关的描述性统计数据:μ和σ)。在这种情况下,我们求助于随机抽样,以从样本分布的描述性统计中推断出潜在人口分布的描述性统计——让我们来理解这一点!

随机抽样意味着我们不是从所有学生,即整个人口中收集数据,而是在全国范围内随机选择几个有代表性的学生来做我们的分析。假设在我们的第一次随机抽样尝试 s1 中,我们在全国范围内选择了 n₁= 50 名有代表性的学生,并记下了他们的分数。让我们将 s₁的描述性统计数据表示为μ₁和σ₁,并将我们的第一个随机抽样事件表示为 s₁: n₁,μ₁,σ₁.按照这个符号和随机抽样程序,我们可以从人口分布中随机选择多组有代表性的学生。请记住,人口分布包括全国的所有学生,样本分布仅包含随机选择的 50 名学生,每个样本分布都是人口分布的子集。

样本分布的描述性统计如何与人口分布的描述性统计相关联?答案由中心极限定理给出,简单来说就是

对于独立随机变量,样本分布的均值分布趋于正态分布(非正式地为“钟形曲线”),与总体分布的形状无关。

现在,让我们把这个定理应用到我们的例子中,看看通过这个练习我们能理解什么。在我们的例子中,随机变量是每个学生得到的分数,这些确实是独立的随机变量,因为一个学生的分数独立于另一个学生的分数。更进一步,假设我们从人口分布中获得 r = 20 个随机样本,每个样本有 n = 50 名学生,这些样本分布可以写成:

这里,n₁ = n₂ = … nᵣ = 50,r = 20。20 个样本平均值的平均值可计算如下:

现在让我们画出 20 个样本分布的平均值,看看它们的分布是什么样的。从图 2 中可以明显看出,无论我们的人口分布(实际上是 Beta 分布,详见代码)的形状如何,该分布看起来确实像一条钟形曲线。

Figure 2 Distribution of the means of 20 random samples (μ₁, μ₂,…,μ₂₀). Mean of the sample means (μ₂₀means = 72.26) yellow dashed vertical line, and actual population mean (μ = 71.52), green vertical line, are also plotted for comparison.

如图 3 所示,如果我们获得(r=) 80 个随机样本(每个样本大小 n = 50),而不是(r=) 20 个,样本均值分布的正态性会更强。80 个样本平均值的计算如下

Figure 3 Distribution of the means of 80 random samples (μ₁, μ₂,…,μ₈₀). Mean of the sample means (μ₈₀means = 71.66) yellow dashed vertical line, and actual population mean (μ = 71.52), green vertical line, are also plotted for comparison.

从图 2 和图 3 中还可以明显看出,当我们抽取更多的随机样本时,样本均值越来越接近总体均值。请注意,只有 rn = 8050 = 4000 个学生成绩,我们才能得到 N = 10,000 个学生成绩的总体均值(μ = 71.52)的足够精确的估计值(μ₈₀means = 71.66)。这意味着,如果我们有足够数量的随机样本,那么我们实际上不需要整个人口分布进行分析。

问:对于一个实际的数据分析问题,我们应该使用多个随机样本(每个样本的观察值较少)还是单个随机样本(观察值较多)?

我们刚刚看到,使用 80 个随机样本,每个样本有 50 个观察值(学生分数),我们可以非常接近基本总体分布的平均值。然而,在实践中,我们通常使用一个包含足够大数量(n)的数据点(学生分数)的随机样本,使得 n ≪ N,这里,n 表示我们随机样本中的学生数量,n 表示全国学生的总体数量。

现在开始,我们将使用一个包含 n 名学生的随机样本,让我们将这个随机样本的标准差和均值分别表示为 s 和μₑ (e 表示估计值)。图 4 显示了中心极限定理的原理仍然成立——对于 n = 4000,我们的随机样本的分布是钟形的,其均值μₑ = 71.58,是对总体均值(μ = 71.52)的一个很好的估计。

Figure 4 Distribution of a random sample containing n = 4000 observations. Sample mean (μₑ = 71.58), yellow dashed vertical line, and actual population mean (μ = 71.52), green vertical line, are also shown for comparison.

值得注意的是,μₑ和 s 本身都是随机变量,因为它们的值取决于随机抽样的策略。

推断统计

上述观察结果对数据分析有很大的意义,因为我们通常无法获得整个人口,因此人口分布的描述性统计通常是未知的。在这种情况下,中心极限定理为我们提供了一种用随机选择的数据点进行数据分析的方法,这种分析的精确度可以使用推断统计进行量化,包括均值和置信区间的标准误差,这将在下面讨论。这些统计数据是推断性的,因为我们使用随机抽样分布来推断潜在总体分布的特征。

平均值的标准误差(SEM) :根据中心极限定理,我们知道我们的样本分布是正态的,具有均值=μₑ.但是μₑ本身是一个随机变量,因为它取决于我们随机样本的选择。换句话说,样本分布的任何变化都会改变我们的μₑ.平均值的标准误差通过计算潜在总体平均值(μ)的估计值μₑ的标准偏差来量化这种变化。形式上,它可以计算如下:

取上述等式两边的平方根,我们得到平均值的期望标准误差:

请注意,我们可以使用样本量(n)足够大的单个随机样本来计算总体均值的标准误差估计。如果 n 足够大,我们可以得到几乎为零的标准误差。这意味着,如果我们有一个大的数据点随机样本,那么我们的样本分布的平均值精确地接近于潜在的未知总体分布的平均值。因此,在各种机器学习和统计问题中,为了更好地推广,通常需要更高的 n。

置信区间:置信区间是估计均值(μₑ)附近的一个区间,很可能包含未知总体均值(μ)。让我们理解这一点-我们想要估计潜在总体分布的平均值μ,并且我们可以访问包含 n 个具有标准偏差 s 和平均μₑ.的观察值的随机样本置信区间以用户选择的置信水平构建,例如 95%。置信水平描述了与采样方法相关的不确定性。假设我们使用相同的抽样方法选择多个随机样本,并使用每个随机样本的μₑ计算置信区间。我们自然会有多个置信区间(每个μₑ).周围一个这些区间估计中有些会包括总体均值μ,而有些则不会。95%的置信水平意味着我们预期 95%的区间估计将包括总体均值。通常,我们只处理一个包含大量数据点的随机样本,在这种情况下,我们只有一个置信区间估计值,对于 95%的置信水平,可以计算如下:

请注意,上述等式右侧的加号--减号后的项根据样本平均值(μₑ).)量化了总体平均值(μ)估计值的不确定性 1.96 乘以平均值的标准误差,因为对于标准正态分布 N(0,1),95%的数据位于平均值的 1.96 标准偏差范围内,如图 5 所示。

Figure 5 Standard normal distribution with mean 0 and standard deviation 1, N(0,1) [Image from Wikipedia]

有时,出于计算目的,1.96 会向上舍入到 2。最后,更高的标准误差导致更宽的置信区间,这表明我们的随机样本的均值μₑ不是潜在总体分布的均值μ的良好近似。

用混淆矩阵优化机器学习模型

原文:https://towardsdatascience.com/understanding-the-confusion-matrix-and-its-business-applications-c4e8aaf37f42?source=collection_archive---------10-----------------------

Photo by Thomas Thompson on Unsplash

如何根据您的用例调整分类器,包括 python 中的演练

机器学习中的混淆矩阵是一个数值网格,有助于评估监督分类模型的性能。从这个网格中,您还可以计算一些指标来为模型打分,包括精确度、召回率和 F1 值。虽然从表面上看这个网格相当简单,而且措施只需要高中水平的数学计算,但矩阵背后的概念却很难掌握。

在下面的帖子中,我将简单介绍以下内容:

  1. 混乱矩阵
  2. 精确度、召回率和 F1 分数
  3. python 中的演练演示了如何选择正确的指标并优化模型性能以最大化该指标

混淆矩阵

为了这个解释,让我们假设我们正在处理一个二元分类问题,以检测一个交易是否是欺诈性的。我们的模型使用用户和交易的特征,如果预测交易是欺诈性的,则返回 1,否则返回 0。

鉴于机器学习模型很少 100%准确,部署这种模型会有一定程度的风险。如果我们错误地将非欺诈交易归类为欺诈,那么我们很可能会失去该交易,甚至可能失去未来的客户业务。另一方面,如果我们错误地将欺诈性交易检测为非欺诈性交易,那么我们可能会损失该交易的价值。

混淆矩阵实质上将结果预测分为四组。它们如下:

真阳性(TP): 模型预测欺诈,交易确实欺诈。

误报(FP): 模型预测欺诈,但交易不是欺诈。

真阴性(TN): 模型预测不存在欺诈,交易不存在欺诈。

假阴性(FN): 模型预测不是欺诈,但交易实际上是欺诈。

为了说明混淆矩阵的样子,我将使用一些人造数据。

有几个 python 库使得构建混淆矩阵相当简单,下面是几个例子;

创建一个非常简单的网格。

from sklearn.metrics import confusion_matrixy_true = [0,1,1,0,1,0,0,0,1,1]
y_pred = [0,1,0,0,1,0,0,1,0,1]confusion_matrix(y_true, y_pred, labels=[0,1])

Output from sklearn confusion_matrix

pandas_ml 库产生了一个可读性更好的输出。

from pandas_ml import ConfusionMatrixConfusionMatrix(y_true, y_pred)

Output from panda_ml ConfusionMatrix

让我们使用网格来确定我们上面讨论的 4 个组中每个组的数字。

有 3 个样本,其中模型预测欺诈,并且交易是欺诈性的,因此 TP = 3。这是右下角的数字,其中行和列都为真。

有 1 个样本,其中模型预测欺诈,但交易不是欺诈性的,因此 FP = 1。

有 2 个样本,模型预测不是欺诈,但交易是欺诈的,所以 FN = 2。

有 4 个样本,其中模型正确预测了非欺诈,而交易是欺诈性的,因此 TN = 4。

如果我们在一个企业中,像这样的模型将被部署并用于推动价值成果,混淆矩阵可以帮助确定一些事情。其中包括:

该模型在确定欺诈交易方面有多好?

该模型区分欺诈性交易和非欺诈性交易的能力如何?

模型有多少次错误地预测欺诈性交易不是欺诈性的?

我之前提到的你可以从混淆矩阵中得到的方法可以帮助回答这些问题。

精确度、召回率和 F1 分数

从混淆矩阵中可以得出许多度量标准,这些标准都用于衡量模型的性能。我将介绍三种最常用的解释。

Precision: 这基本上是对所有被预测为欺诈的样本中有多少是正确的测量。因此,计算是:

TP / (TP + FP)

回忆(敏感度):这是对那些欺诈性的样本中有多少被正确预测为欺诈性的度量。

TP /(TP + FN)

这两个指标之间的差异很微妙,但非常重要。如果我们优化精确度,那么我们将得到更少的假阳性(更少的非欺诈交易被归类为欺诈),0 假阳性将给出满分 1。如果我们对召回进行优化,那么我们会得到更少的假阴性,因此我们会捕获更多的欺诈交易,但这可能会有损于将更多的非欺诈交易错误地归类为欺诈。

F1 分:是精确度和召回率的“调和平均值”。

因此,F1 分数很好地指示了分类器的整体准确性,而精确度和召回率提供了关于模型在哪些方面表现良好或不太好的信息。最大化 F1 分数将创建一个平衡的模型,该模型具有精确度和召回率的最佳分数。您选择优化哪个指标将在很大程度上取决于用例。

针对给定指标进行调整

有几种方法可以针对适合您的特定用例的特定指标来调整机器学习模型。一个例子是 scikit-learn GridSearchCV,它有一个scoring 参数,允许您选择一个给定的指标。该函数在参数网格上执行交叉验证网格搜索,并根据您提供的评分标准返回模型的最佳参数。

在这篇文章的下一部分,我将介绍一个使用GridSearchCV优化模型的例子。首先导入相关的库。

import wget
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from pandas_ml import ConfusionMatrix
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import GridSearchCV
from pandas_ml import ConfusionMatrix

在这个例子中,我将使用一个简单的数据集,它由患者样本的属性和一个描述他们是否患有乳腺癌的指标组成。这可以使用下面的代码直接从 scikit-learn 获得。

X, y = load_breast_cancer(return_X_y=True)

在这个数据集中,恶性类实际上是负类。为了使产生的混淆矩阵更容易解释,我将重新标记它们,使恶性类为阳性。

for i in range(len(y)):
    if y[i] > 0:
        y[i] = 0
    elif y[i] < 1:
        y[i] = 1

接下来,我将数据分为测试集和训练集。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33)

然后,我将训练一个简单的逻辑回归模型,并使用该模型进行一些预测。

rf = LogisticRegression()
model = rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
ConfusionMatrix(y_test, y_pred)

混乱矩阵是这样的。

让我们来计算一下指标。

print('Precision is:'+str(round(precision_score(y_test, y_pred),2)))
print('Recall is:'+str(round(recall_score(y_test, y_pred, average='binary'),2)))
print('F1 score is:'+str(round(f1_score(y_test, y_pred, average='binary'),2)))

该模型在所有指标上都表现良好。然而,如果我们要用这个模型代替医生对乳腺癌的诊断,那么 8 个假阴性就太多了。因此,对于这个用例,我们希望最大限度地减少假阴性,因此希望优化召回模型。现在,我们将实施GridSearchCV并针对该指标优化模型。

首先,我们为两个选择的LogisticRegression参数创建超参数搜索空间。

penalty = ['l1', 'l2']
C = np.logspace(0, 4, 10)
hyperparameters = dict(C=C, penalty=penalty)

然后,我们调用逻辑回归模型并调用GridSearchCV,选择scoring参数作为召回。

lr = LogisticRegression()
clf = GridSearchCV(lr, hyperparameters, cv=5, verbose=0, scoring='recall')

现在,我们安装GridSearchCV并打印最佳参数以供调用。

best_model = clf.fit(X_train, y_train)
print('Best Penalty:', best_model.best_estimator_.get_params()['penalty'])
print('Best C:', round(best_model.best_estimator_.get_params()['C'],2))

现在让我们打印最佳模型的混淆矩阵和度量标准。

y_pred_gs = best_model.predict(X_test)
cm_gs = ConfusionMatrix(y_test, y_pred_gs)
print(cm_gs)print('Precision is:'+str(round(precision_score(y_test, y_pred_gs),2)))
print('Recall is:'+str(round(recall_score(y_test, y_pred_gs, average='binary'),2)))
print('F1 score is:'+str(round(f1_score(y_test, y_pred_gs, average='binary'),2)))

您可以从这些结果中看到,召回分数现在更高了,我们还提高了精确度和召回率。该模型现在能够更好地预测恶性和良性病例的正确标签。

有许多其他指标对全面评估分类模型的性能很重要,包括特异性、AUC 和 ROC。然而,我认为这些需要一篇自己的文章——这是一篇好文章。

感谢阅读!

XLNet 如何结合 GPT 和伯特的精华

原文:https://towardsdatascience.com/understanding-the-difference-of-gpt-bert-and-xlnet-in-2-min-8aa917330ad1?source=collection_archive---------11-----------------------

在 3 分钟内理解 GPT、伯特和 XLNet 的概念差异

Centre Pompidou, Paris, France

XLNet 是一个新的预训练模型,它在 20 个任务上持续优于 BERT,通常是大幅度优于 BERT。

什么?!为什么呢?

如果不了解机器学习,就不难认为我们捕捉到的上下文越多,预测就越准确。因此,一个模型能够最深入、最有效地捕捉上下文的能力就是制胜的秘诀。

让我们来玩一个游戏——在下面的语境中【猜测 1】【猜测 2】是什么?

['自然','语言','处理','是','一','婚姻','的',【guess 1】【guess 2】,'和','语言学']

考虑到 3 分钟的时间限制,让我来揭晓答案,相反,我会问你:你认为哪个模型(GPT、伯特、XLNet)最有助于找到答案。

回答: ['自然','语言','处理','是','婚姻','的',,'机器',,'学习',,'和','语言学']

我们将继续使用 Pr(Guess|Context)符号。字面意思是根据上下文猜测的概率。

GPT——我们从左向右阅读,所以我们不知道“机器”、“学习”之后的上下文:

Pr('机器' |['自然','语言','处理','是','婚姻','的'])

Pr('学习' |['自然','语言','处理','是','婚姻','的','机器'])

知道“机器”实际上有助于你猜测“学习”,因为随着机器学习的流行,“学习”经常跟在“机器”后面。

伯特——我们知道与 GPT 相反的两个方面,但我们是基于相同的上下文猜测“机器”和“学习”:

Pr('机器' |['自然','语言','处理','是','婚姻','的','和','语言学'])

Pr('学习' |['自然','语言','处理','是','婚姻','的','和','语言学'])

拥有“语言学”实际上可以帮助你猜测“机器”的“学习”,因为你知道自然语言处理是机器学习和语言学的完美结合。即使你不知道,有了“语言学”的存在,你至少知道它不是“语言学”。

你可以看到 BERT 的明显缺点是,它不能说明“机器”和“学习”是一个相当常见的术语。

我们如何结合 GPT 和伯特的优点?

XLNet——两者之长:

排列!排列的力量在于,即使我们只从左向右阅读,排列也能让我们捕捉到两边的上下文(从左向右阅读,从右向左阅读)。

允许我们捕捉双方语境的排列之一:['自然','语言','处理','是','婚姻','的','和','语言学',,'机器','学习' ]

Pr('机器' |['自然','语言','处理','是','婚姻','的','和','语言学'])

Pr('学习' |['自然','语言','处理','是','婚姻','的','和','语言学','机器'])

这一次,你有了完整的上下文,在猜测“机器”之后,你可以立即猜测“学习”。你可以清楚地看到 XLNet 结合了 GPT 和伯特的优点。

仅此而已,希望这只是一个 3 分钟的阅读。如果你喜欢这篇文章,请鼓掌并分享!当然,如果你想知道更多,请阅读 XLNet 的论文

了解不同类型的机器学习模型

原文:https://towardsdatascience.com/understanding-the-different-types-of-machine-learning-models-9c47350bb68a?source=collection_archive---------8-----------------------

监督、半监督和非监督机器学习方法

Photo by Franck V. on Unsplash

概观

在机器学习领域,有三种主要类型的任务:监督的、半监督的和无监督的。

这些类型之间的主要区别在于地面实况数据的可用性水平,即对于给定的输入,模型的输出应该是什么的先验知识。

监督学习旨在学习一个函数,在给定数据样本和期望输出的情况下,近似一个将输入映射到输出的函数。

半监督学习旨在利用从少量已标记数据点学习到的知识来标记未标记数据点。

无监督学习没有(或不需要)任何标记输出,所以它的目标是推断一组数据点中存在的自然结构。

监督学习

监督学习模型将输入映射到输出。

概观

当我们想要将输入映射到输出标签时,监督学习通常在分类的上下文中完成,或者当我们想要将输入映射到连续输出时,监督学习通常在回归的上下文中完成。监督学习中的常见算法包括逻辑回归、朴素贝叶斯、支持向量机、人工神经网络和随机森林。在回归和分类中,目标是在输入数据中找到特定的关系或结构,使我们能够有效地产生正确的输出数据。

请注意,“正确的”输出完全是由训练数据决定的,因此,虽然我们确实有一个我们的模型将假设为正确的基本事实,但这并不是说数据标签在现实世界中总是正确的。嘈杂或不正确的数据标签将明显降低模型的有效性。

复杂性

模型复杂性指的是您试图学习的函数的复杂性,类似于多项式的次数。模型复杂性的适当级别通常由训练数据的性质决定。

如果您有少量的数据,或者如果您的数据没有均匀地分布在不同的可能场景中,那么您应该选择低复杂度的模型。这是因为如果在少量数据点上使用,高复杂性模型会过度拟合

过度拟合指的是学习一个非常适合你的训练数据的函数,但不推广到其他数据点——换句话说,你严格地学习产生你的训练数据,而没有学习导致这个输出的数据中的实际趋势或结构。想象一下试图拟合两点之间的曲线。理论上,你可以使用任何次数的函数,但在实践中,你会吝啬地增加复杂性,并使用线性函数。

偏差-方差权衡

偏差-方差权衡也与模型泛化有关。在任何模型中,在作为恒定误差项的偏差和作为不同数据集之间误差变化量的方差之间存在平衡。因此,高偏差和低方差的模型在 20%的时间里都是错误的,而低偏差和高方差的模型在 5%-50%的时间里都是错误的,这取决于用来训练它的数据。

请注意,偏差和方差通常彼此反向移动;增加偏差通常会导致较低的方差,反之亦然。在制作模型时,您的具体问题和数据的性质应该允许您在偏差-方差谱的哪个位置做出明智的决定。

通常,增加偏差(和减少方差)会导致模型具有相对保证的基线性能水平,这在某些任务中可能是至关重要的。此外,为了生成具有良好泛化能力的模型,模型的方差应该随训练数据的大小和复杂程度而变化。小而简单的数据集通常应该用低方差模型来学习,而大而复杂的数据集通常需要高方差模型来全面学习数据的结构。

半监督学习

利用未标记和标记的数据点进行学习。

概观

半监督学习介于监督学习和非监督学习之间。半监督模型旨在使用少量已标记的训练数据以及大量未标记的训练数据。这种情况经常发生在现实世界中,在现实世界中,标注数据非常昂贵,并且/或者您有稳定的数据流。

例如,如果我们试图在社交网络中检测不适当的消息,就没有办法获得每条消息的手工标记信息,因为消息太多了,成本太高。相反,我们可以手动标记其中的一个子集,并利用半监督技术来使用这个小的标记数据集来帮助我们理解其余的消息内容。

一些常见的半监督方法是直推式支持向量机和基于图的方法,如标签传播。

假设

半监督方法必须对数据做出一些假设,以证明使用一小组标记数据来对未标记数据点做出结论是合理的。这些可以分为三类。

第一个是连续性假设。这假设彼此“接近”的数据点更有可能具有共同的标签。

第二个是集群假设。这假设数据自然地形成离散的聚类,并且同一聚类中的点更有可能共享一个标签。

第三个是流形假设。这假设数据大致位于比输入空间更低维度的空间(或流形)中。当一个不可观察或难以观察的具有少量参数的系统产生高维可观察输出时,这种情况是相关的。

无监督学习

无监督模型发现数据中的固有模式。

概观

无监督学习中最常见的任务是聚类、表示学习和密度估计。在所有这些情况下,我们希望了解数据的内在结构,而不使用显式提供的标签。一些常见的算法包括 k 均值聚类、主成分分析和自动编码器。由于没有提供标签,所以在大多数无监督学习方法中,没有特定的方法来比较模型性能。

探索性数据分析

无监督学习在探索性分析中非常有用,因为它可以自动识别数据中的结构。例如,如果分析师试图对消费者进行细分,无监督聚类方法将是他们分析的一个很好的起点。在人类不可能或不切实际地提出数据趋势的情况下,无监督学习可以提供最初的见解,然后可以用于测试个人假设。

降维

降维是指使用较少的列或特征来表示数据的方法,可以通过无监督的方法来实现。在表征学习中,我们希望学习个体特征之间的关系,允许我们使用与初始特征相关的潜在特征来表示我们的数据。这种稀疏潜在结构通常使用比我们开始时少得多的特征来表示,因此它可以使进一步的数据处理不那么密集,并且可以消除冗余特征。在其他情况下,降维可用于将数据从一种模态转换为另一种模态。例如,可以使用循环自动编码器将序列转换为固定长度的表示形式。

直观理解装袋对方差和偏差的影响

原文:https://towardsdatascience.com/understanding-the-effect-of-bagging-on-variance-and-bias-visually-6131e6ff1385?source=collection_archive---------3-----------------------

给出为什么 bagging 算法实际工作的直觉,并以简单易懂的方式展示它们的效果

© by my lovely wife Tinati Kübler

这里有大量优秀的文章描述了像随机森林这样的打包方法在算法层面上是如何工作的,以及为什么打包是一件好事。通常,本质是这样的:

“你在训练集的不同部分训练许多决策树,然后将它们的预测平均化为最终预测。预测变得更好,因为随机森林的方差与单个决策树的方差相比更小。(dartboard.png)"

—一些文章

当然,我在这里是转述。这些文章包括很棒的图片、代码和更多的想法。但我经常错过的是对为什么装袋是一个好主意以及如何使用真实数据集看到方差减少的良好直觉。

因此,在这篇文章中,我想解决这两个缺点,并给出直观的推理,为什么随机森林算法的工作,以及如何可以看到方差的图形改善。你可以把这篇文章看作是对这两个主题的探索,它比一般的关于偏差-方差困境的文章更深入,但不像一篇成熟的研究论文那样深入。尽管如此,我还是会提供一些我认为有用的资源的链接,这样你就可以在需要的时候更深入地了解。

我试图让数学水平非常容易理解,让没有数学专业的人也能理解,同时也给出一些高水平的想法和插图,也让数学相关的人能喜欢。

尽管如此,我还是不会详细解释决策树、随机森林和所有其他提到的模型是如何工作的,因为正如所描述的,这已经被讨论过无数次了。我将只解释非常高级的想法,从决策树开始。

决策树

免责声明:我在这里只谈论普通的决策树。在本文的其余部分,我们不考虑修剪。这些树可以长得任意深。

输出描述

带有 k 个叶子的决策树就是这种形式的模型

这意味着决策树是在特征空间的区域 R 中具有实值 w 的分段常数函数。这里 x 来自特征空间 X 并且 y 是来自输出空间 Y 的相应标签。对 R 的约束是

Property 1 and 2 for a 2-dimensional feature space.

  1. 它们是边界平行于特征空间坐标轴的矩形
  2. 所有矩形的集合是特征空间的一个划分,即,如果你取两个不相交的矩形,并且所有矩形的并集是完整的特征空间。

现在,我们已经确定了这一点,让我们检查一下为什么决策树被称为高方差算法,而例如线性回归被认为是低方差算法

与线性回归的比较

简单回顾一下,线性回归模型具有以下形式:

其中权重 w 是实数,而 d 是样本的维度,即特征的数量。

为了比较这些模型的方差,我们必须后退一步,思考学习问题实际上是什么。

通常,我们会得到固定数量的样本(学习集,训练样本),让我们的算法变变魔术,拟合所有必要的参数,最终,我们可以预测未知样本的值。但是,这是一种相当僵化的看待事物的观点。

在学习理论中,我们将训练集建模为来自空间 X×Y,上的分布 D ,其中 X 是特征空间, Y 是输出空间我们从分布中抽取大小为 n 的训练集 L (以及验证和测试集):

n data samples from the distribution D. Here each of the x’s is a vector of some dimension d coming from the feature space X and the y’s are the corresponding labels from the output space Y.

想象一个发行版是一个有按钮的黑盒;如果你点击按钮一次,你会从分布中得到一个随机样本(x₁,y₁)。再次点击它,你会得到另一个样本(x₂,y₂),独立于之前的样本。重复,直到你有足够的样本。

然后我们可以使用来自 Ln 数据点来训练我们的模型。这为样本 L 中的所有 (xᵢ,yᵢ) (如果我们的模型是好的)输出一个函数 ff(xᵢ)≈yᵢ这种方法确保模型在训练集上的表现良好

但是现在想象一下,我们从分布 D 中查询 n 个新样本,并将这些样本用作训练集L’。让我们把在这个新集合上训练产生的模型称为 g. 这个新模型 g 也将满足l’中所有【xᵢ'】【yᵢ'】的条件 g(xᵢ')≈yᵢ'

现在,由于l’由不同的点 (xᵢ',yᵢ') 组成,新型号 g 将具有与f不同的输出形状。型号 fg**可能会有很大的不同,这取决于 L的不同程度**

如果对于一个固定的算法(例如“决策树”),不同训练集 L 和 L’的模型往往相差很大,我们称这个算法为高方差算法。

当然,这没有精确的定义,但这对于本文来说也是不必要的。在下文中,我们将使用图形来确定一种算法是否比另一种算法具有更高的方差。

如果你对数学感兴趣(干杯!),我可以推荐 Gilles Louppe 的论文[1],以及 Shai Shalev-Shwartz 和 T2 Shai Ben-David 的书[2],这本书非常详细地解释了机器学习的理论基础。

让我们回到决策树和线性回归的比较。我们将使用以下运行示例: X=[0,10]Y=ℝ,特征空间的维度为 1 ,并且这一个特征可以取 0 到 10 之间的实数值,而标签可以取任何实数值。

在我们的例子中,我们定义一个分布 D 做如下事情:从 0 到 10 均匀地选择特征 x ,并且通过隐藏函数显式地计算标签 y

y is computed deterministically via 3sin(x)+x and then standard normally distributed noise is added.

y without the noise.

函数 h 描述了标签的底层结构,这是我们想要了解标签的真相。我们称之为隐藏,因为我们不会给算法这个信息。他们必须自己想办法。😃

按照上面的推理,如果我们对我们的分布 D 查询三次,每次 10 个样本,我们可能会得到以下三个训练集:

Sampling from the distribution three times yields 3 different results. Each time 10 training samples were generated.

让我们使用最右边的训练集,并在应用决策树和线性回归后绘制结果。

We can see that the decision tree fits the training data perfectly, which is not a reason to celebrate, however. The problem is that the algorithm also captures the noise, which we do not want. We are only interested in capturing the underlying structure of the labels (namely 3sin(x)+x), instead.

决策树的偏差和方差与线性回归

让我们对 3000 个独立采样的训练集进行 3000 次相同的实验,每个训练集的大小也是 10。在左侧,我们可以看到决策树的结果,在右侧,线性回归结果相互叠加。

Each trial gives one curve in transparent black. The more lines stack, the darker the intersections get. The dashed blue line is 3sin(x)+x again, the underlying truth.

在这里,我们可以看到决策树(左侧)平均来说非常适合数据。人们也称这种属性为决策树具有低偏差。同时,对于右侧的线性回归,该模型显然不能捕捉底层标签结构的复杂模式。我们说线性回归高偏差 在这种情况下,是不能够得知真相的。

然而,如果你考虑这些黑管的垂直宽度,源自决策树的黑管比右边的线性回归黑管更宽。这意味着,当对训练数据集进行重新采样时,决策树预测附近摆动的幅度比线性回归预测更大,我们称之为具有高方差决策树和具有低方差线性回归

Summary of the algorithm properties.

我们实际上想要的是具有低偏差(它们平均符合事实)和低方差(它们不会过多地偏离事实)的算法。幸运的是,有许多方法可以降低偏差(例如,使用一种称为Boosting的技术),还有其他方法可以降低方差后者可以通过所谓的装袋来实现。装袋的好处是,它也不会再次增加偏差,这一点我们将在下一节讨论。

这就是为什么 Bagging 和线性回归一起使用的效果很低:你不能通过 Bagging 来减少偏差,但可以通过 Boosting 来减少偏差。有趣的是,将决策树与 Boosting 结合使用也被证明是有用的。在这种情况下,使用大量修剪的决策树,它也具有较低的偏差。

制袋材料

在这一节中,我们将看到 Bagging 做什么,为什么它工作,以及如何看到方差的减少。

简单的动机

假设我们有标准正态分布,特别是,一个观察值的均值为 0,方差为 1。让我们假设我们喜欢看到 0 附近的值(就像我们喜欢看到 3sin(x)+x* 附近的预测函数一样)。但是 1 的方差对于我们的口味来说太大了(就像黑色灯管的宽度),我们正在寻找减小它的方法。一种简单的方法是从标准正态分布中抽取更多的值,然后取它们的平均值。以下结果是众所周知且易于验证的:*

The average of standard normal random variables is also normally distributed. The new mean is just the sum of the means and the new variance can be computed with the Bienaymé Formula. ρ is a term that reflects the dependencies between random variables. If they are all independent, then ρ=0. If the covariances between the random variables are all less than a bound K, then ρ is also less than K.

因此,通过平均,我们模拟从另一个正态分布中提取,具有相同的平均值,但是具有较小的方差,如果ρ不太大。这很好,因为我们得到的值比以前更接近零,而的概率比以前更高!

在独立随机变量( ρ=0 )和 b=100 的特殊情况下,比如方差从 1 下降到 0.01。结果如下:

The normal distribution is with a variance of 0.01 is much narrower than the standard normal distribution with a variance of 1. In the shaded regions, one can see where 99% of the probability of each distribution lies.

注意:如果随机变量 X 都与值 1 相关,这意味着 ρ=(b-1)/b ,即平均值的方差又会是 1。这对应于每个样本实际上是相同数量的情况。对许多相同的数字进行平均并不能给我们任何新的信息,所以这相当于只画一个值。

在最好的情况下,我们可以平均独立样本。它们越相关,在平均过程中就越无用。

装袋的核心理念

现在,有用的见解是我们可以用预测模型做同样的事情。在随机抽取的训练数据集上运行决策树算法为我们提供了一个模型,它本质上是从分布中对函数进行采样。对这些模型进行平均得到了另一个模型(如随机森林),具有相同的偏差,但方差较低。平均而言,这种集成模型比单个决策树更接近事实。

但问题是:这些功能的相关性有多差?考虑以下情况:如果我们遇到一个数据集,我们可以在它上面安装一个决策树。到目前为止,一切顺利。但是,如果我们再做一次,在决策树的情况下,结果将(几乎)相同。这意味着我们以这种方式采样的函数是高度相关的 (ρ≈1) ,并且不会改进单个决策树。

它不一定正好是 1,因为决策树算法偶尔必须打破束缚,这可以以随机方式进行,但是因为这是随机性的唯一来源,所以它不会产生彼此根本不同的树。

不管怎样,我们必须去相关这些树,我们将在下一节看到如何去做。

走向随机森林

随机森林是 Leo Breiman 发明的[3]。这里的想法是以一种特殊的方式在训练集上安装许多决策树,给出同样多的树模型(=函数)。之后,这些树被组合成单个模型,例如,通过对任何给定输入 x,的输出进行平均,使其成为一种特殊的打包方法。这导致了一个具有较低方差的模型,类似于我们之前看到的正态分布随机变量。

获得许多非最大相关树的想法如下:

  1. 对每棵树使用训练样本的随机子集。
  2. 在生长每棵树的每个步骤中使用随机的特征子集。

拥有两个随机化源比只使用其中一个更有助于减少不同树之间的相关性。如果你碰巧设计了一个新的装袋算法,请随意添加更多!还有各种其他方法来组合单个决策树,例如 Geurts 等人[4]的极度随机化的树。

一维决策树和随机森林的方差比较

让我们再次从我们的分布中抽取 10 个样本,并拟合一个决策树和一个包含 100 个决策树的随机森林。我们重复这个过程 1000 次,得到下面的图片:

我们看到由随机森林形成的红管的垂直宽度小于决策树的黑管。因此,正如所料,随机森林比决策树具有更低的方差。此外,似乎两个管的平均值(中间)是相同的,这意味着平均的过程没有改变偏差。我们仍然很好地实现了底层的真实函数 3sin(x)+x

请注意,随机森林算法在这里无法显示其全部潜力,因为我们使用的数据集只有一个特征,每个决策树都必须使用这个特征。因此,随机森林中的 100 棵决策树只能在被选择来生长每棵树的训练样本之间有所不同。在这种情况下,随机森林算法就变成了更简单的 Bagging 算法,只对每棵树使用不同的训练样本。

如果我们想扩大方差的差距,同时仍然能够直观地解释结果,我们必须转移到二维特征空间。这允许随机森林算法在算法的每一步从两个可用特征中随机选择恰好一个

二维决策树和随机森林的方差比较

让我们为训练数据定义一个分布,它类似于我们在一维情况下使用的分布。我们选择x =【0,10】Y=ℝ,其中 D 从顶点在 (0,0),(0,10),(10,0)(10,10) 的正方形中均匀采样一个 (x,x’)

Similar to what we have seen before, y is computed deterministically via 3sin(x+x’)+x-x’ and then standard normally distributed noise is added.

包含 50 个点的随机数据集可能如下所示:

50 random points from the distribution. We can see that there are higher values in the bottom right corner and lower values in the top left corner. The diagonal region separating these two corners is filled with values around zero.

现在,让我们看看在这种情况下,决策树和随机森林的方差是如何表现的。享受成果!

让我们首先从决策树的例子开始。我们使用 9 个不同的训练数据集来种植 9 棵不同的树。

We see that each of these nine pictures differ quite a lot. The bottom right is always bright (indicating high values) and the top left is dark (indicating low values), but the size and shape of all the rectangles vary significantly.

看着眼熟?;)

现在,让我们对随机森林做同样的事情。这里,我们在样本的不同子集上再次训练每个随机森林的 100 个决策树,并且随机使用两个给定特征 **中的仅一个!每个模型在 50 个随机样本点上进行训练。

Not only can we see the high values in the bottom right and the low values in the top left again, but the pictures look very similar. There is a nice and smooth gradient that looks similar in each picture.

结论

很明显,当训练集改变时,高方差算法会迅速改变它们的结果(模型)。这很糟糕,因为我们永远不知道我们的具体模型离事实有多远,即使我们的模型的偏差为零。

但是我们学会了如何通过装袋来增加获得好模型的机会。我们也有一个直觉,为什么装袋降低了方差,而保持偏差不变,我们已经在很多例子中看到了这些结果。

参考

[1] G. Louppe,理解随机森林—从理论到实践 (2014),学位论文

[2] S. Shalev-Shwartz 和 S. Ben-David,理解机器学习:从理论到算法 (2014),剑桥大学出版社

[3] L .布雷曼,随机森林 (2001),机器学习 45.1(2001):5–32

[4] P. Geurts,D. Ernst 和 L. Wehenkel,极度随机化的树 (2005),机器学习 63.1(2006):3–42

我用乳胶创造了所有的配方。对于其他图形,我使用了 Pythonmatplotlibnumpy 。对于模型训练,我使用了 scikit-learn

承认

我要感谢帕特里克·鲍曼博士的校对工作,并为改进我的文章提供了许多有益的建议。也感谢安德烈·埃塞的帮助!

奖励:马赛克的代码

当你开始用这种决策树马赛克艺术赚钱时,请想起我。😀

***import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor
import numpy as np

# Sample from the distribution with a true function f.
def generate_data_2d(f, n_samples):
    x1 = np.random.uniform(0, 10, n_samples)
    x2 = np.random.uniform(0, 10, n_samples)
    y = f(x1, x2) + np.random.randn(n_samples)
    return np.vstack([x1, x2]).transpose(), y

# Parameters to play round with.
f = lambda x1, x2: 3 * np.sin(x1 + x2) + x1 - x2
n_samples = 50
n_rows = 3
n_cols = 3

# Increase numbers to remove white spaces in the pictures.
n_points = 100
size_points = 6

# Prepare the plotting.
fig = plt.figure(constrained_layout=True, figsize=(12, 12))
all_points = np.array([(x1, x2) for x1 in np.linspace(0, 10, n_points) for x2 in np.linspace(0, 10, n_points)])

# Start plotting.
for i in range(1, n_rows * n_cols + 1):
    # Get a random training set.
    x, y = generate_data_2d(f, n_samples)

    # Train a decision tree.
    dt = DecisionTreeRegressor()
    dt.fit(x, y)
    predictions = dt.predict(all_points)

    # Create one mosaic picture.
    ax = fig.add_subplot(n_rows, n_cols, i)
    ax.axis('off')
    ax.scatter(all_points[:, 0], all_points[:, 1], c=predictions, s=size_points)***

我希望你今天学到了新的、有趣的、有用的东西。感谢阅读!

作为最后一点,如果你

  1. 想支持我多写点机器学习和
  2. 无论如何,计划获得一个中等订阅,

为什么不做 通过这个环节 ?这将对我帮助很大!😊

说白了,给你的价格不变,但是大约一半的订阅费直接归我。

非常感谢,如果你考虑支持我的话!

如果您有任何问题,请在 LinkedIn 上给我写信!

理解无限猴子定理

原文:https://towardsdatascience.com/understanding-the-infinite-monkey-theorem-ea743d703daa?source=collection_archive---------13-----------------------

概率论的荒谬之处,以及为什么在猜测概率时不能相信自己的直觉

想象你有无限多的猴子。现在你给每只猴子一台笔记本电脑,让它们无限长时间地随机打字。在某个时候,这个故事会出现在任何一台笔记本电脑上,因为任何一只猴子偶然输入了它,这种可能性有多大?

Not infinitely many monkeys, but still a few! Drawing by Author (excuse my Art skills!)

或者让场景更真实一点,用一只猴子代替无限多的猴子。(说真的,让一只猴子永远打字可能已经是一个足够的挑战了,即使你没有考虑到猴子最终会死)。

还是那句话,如果我们让这只猴子,姑且称它为 Charly,永远打字的话,它打这篇文章的几率有多大?

把这个问题问给任何没学过概率的人,我向你保证(至少有 50 %的几率),他们会把你当疯子一样看待。他们也会告诉你概率为零,或者至少接近于 0。

但令人惊讶的答案是:不是。在猴子无限的打字旅程中的某个时刻,它打出这篇文章(或任何其他文章)的概率是 1。

为什么你会想知道?让我们来看看背后的数学核心!

理解概率

首先,我们需要了解概率来理解定理。让我们假设(为了简单起见),猴子只有 40 个键可供选择,包括字母(a,b,c,…z),一些标点符号(",","。"、":"、…)和空格。

我们还假设猴子随机打字,并且每个键都以相同的概率被按下。这意味着每个键的概率是相同的。

打字母“a”的概率有多大?嗯,我们总共有 40 个可能的键,“a”是其中之一,所以“a”被按下的概率是 1/40。这同样适用于每隔一个键,因此键入“p”的概率也是 1/40,以此类推。

The probability of pressing “a” is 1/40.

我们已经说过查理随机按键。我们的意思是,无论他接下来键入什么,都与他之前键入的内容无关。数学上,我们说这些事件是随机独立的。

因此,如果我们想计算 Charly 先输入“a”然后输入“p”的概率,我们将这些概率相乘。因此,猴子先输入“a ”,然后输入“p”的概率是 1/40 * 1/40 = 1/1600——这是非常小的。

The probability of pressing “a” and then “p”, i.e. “ap” is 1/3600.

为什么乘而不加?有数学上的解释,也有直观的解释。为了直观的解释,请记住,猴子先输入“a”然后输入“p”的事件比先输入“a”然后再输入任何东西的概率要小。由于概率是介于 0 和 1 之间的数字,通过将它们相乘,我们使这些数字变小。如果我们把概率相加,结果会是一个更大的数字——这没有意义。如果你想知道如果你把概率相加会发生什么,你会得到猴子输入“a”或“p”的概率。

现在,猴子输入“苹果”的概率是多少?

The probability of typing “apple” is surprisingly small!

哦,那真是小得令人难以置信。其实应该小于彩票中奖的几率(至少有所收获)。我可能会在未来的另一篇文章中再次确认这一说法。

那么不输入数学的概率会是多少?就是 TR:互补概率,所以我们可以用 1 减去输入“苹果”的概率来计算。

Conversely, the probability of not typing “apple” is quite high.

这是在前 5 个字母中没有输入“苹果”的概率。我们现在可以计算前 n * 5 块内不输入的概率!

This is the probability of not typing apple within the first n blocks of size 5 each.

这是一个概率,意味着它取 0 到 1 之间的值。对于小 n,该值接近 1,但是随着 n 变大,不键入“apple”的概率也变得越来越小,最终接近 0。这意味着最终输入“苹果”的概率也接近 1。

完成了。经过验证。最终,我们的猴子 Charly 会键入“apple ”,同样,它也会键入这篇文章。

等等,重点在哪里?

这个结果太棒了!因为这也意味着如果我们继续玩彩票,最终我们会赢。

那为什么没有一个理智的数学家会利用彩票来发财呢?

因为:

a)平均而言,你总是会入不敷出(我们将在以后的另一篇文章中讨论这一点)。

b)在你达到正确的数字之前,你很可能会死或者没钱。

因为即使输入“苹果”的概率最终会趋近于 1,这也要花费难以置信的大量时间。

假设 Charly 以每秒一个键的速度打字,他大概需要 11.25 年才能打出“苹果”,概率至少是 0.5 或 50%。在这 11.25 年里,查理不允许做任何其他事情,甚至不允许睡觉或吃饭。

所以,不,我永远不会建议你去玩彩票,或者去赌一只在现实生活中打字的猴子。我永远不会向你推荐它,除非你没什么可输的,而且赢的机会微乎其微,总比什么都没有好。

但是——我会一直建议你和你的朋友打赌,你假想的猴子最终会打你最喜欢的书。

理解梯度下降背后的数学。

原文:https://towardsdatascience.com/understanding-the-mathematics-behind-gradient-descent-dde5dc9be06e?source=collection_archive---------0-----------------------

机器学习中一种常用优化算法背后的简单数学直觉。

PC: Pexels/Pixabay

"过早优化是万恶之源."
――高德纳

敏捷 是软件开发过程中一个相当知名的术语。背后的基本思想很简单:快速建立一些东西,➡️把它拿出来,➡️得到一些反馈,➡️根据反馈做出改变,➡️重复这个过程。的目标是让产品靠近用户,并通过反馈引导你获得误差最小的最佳产品。同样,为改进而采取的步骤需要很小,并且应该不断地让用户参与进来。在某种程度上,敏捷软件开发过程包括快速迭代。尽快从解决方案开始,尽可能频繁地度量和迭代的想法是引擎盖下的梯度递减 t。

目标

梯度下降算法是一个迭代过程,将我们带到一个函数的最小值(除了一些警告)。下面的公式在一行中总结了整个梯度下降算法。

https://www.coursehero.com/file/27927651/Gradient-Descentpdf/

但是我们如何得出这个公式呢?嗯,它很简单,包括一些高中数学。通过这篇文章,我们将尝试在线性回归模型的背景下理解并重新创建这个公式。

本文改编自《编码列车 》视频 梯度下降的数学——智能与学习。这篇文章最初是作为笔记来补充我的理解。我也强烈推荐看这个视频。

机器学习模型

  • 考虑二维空间中的一组数据点。假设数据与一组学生的身高体重有关。我们试图预测这些量之间的一些关系,以预测一些新生的体重。这本质上是监督机器学习技术的一个简单例子。
  • 现在让我们在空间中画一条穿过这些数据点的任意线。这条直线的方程式是**Y = mX + b**,其中 m 是斜率,而 b 是它在 Y 轴上的截距。

预言

给定一组已知的输入及其相应的输出,机器学习模型试图对一组新的输入进行一些预测。

ML process

误差将是两个预测之间的差异。

这涉及到成本函数或损失函数的概念。

价值函数

一个成本函数/损失函数评估我们的机器学习算法的性能。损失函数计算单个训练示例的误差,而成本函数是所有训练示例的损失函数的平均值。从今以后,我将交替使用这两个术语。

成本函数基本上告诉我们,我们的模型在预测给定的 m 和 b 值时有多好。

假设数据集中总共有“N”个点,对于所有这“N”个数据点,我们希望最小化误差。因此,成本函数将是总平方误差,即

The cost function for N data points

为什么我们要平方差,而不是绝对差?因为平方差更容易得出回归线。事实上,为了找到这条线,我们需要计算成本函数的一阶导数,而计算绝对值的导数比计算平方值要困难得多。此外,平方差增加了误差距离,从而使坏的预测比好的预测更明显。

最小化成本函数

任何机器学习算法的目标都是最小化成本函数。

这是因为实际值和预测值之间的误差越小,表示该算法已经完成了出色的学习工作。因为我们想要最低的误差值,所以我们想要给出最小可能误差的那些' m' 和' b' 值。

我们如何最小化任何函数?

如果我们仔细观察,我们的成本函数的形式是**Y = X²** 。在笛卡尔坐标系中,这是一个抛物线方程,可以用图形表示为:

Parabola

为了最小化上面的函数,我们需要找到 **X** 中产生 **Y** 最小值的,也就是红点。因为这是一个 2D 图,所以很容易在这里找到最小值,但是情况可能不总是这样,尤其是在更高维度的情况下。对于这些情况,我们需要设计一个算法来定位最小值,这个算法叫做梯度下降。****

梯度下降

梯度下降是最流行的优化算法之一,也是优化神经网络最常用的方法。这是一种迭代优化算法,用于寻找一个函数的最小值。

直觉

假设你正沿着下图走,并且你现在在“绿色点。你的目标是到达最小值,即“红色”点,但从你的位置,你无法查看它。

Figure 2

可能的行动有:

  • 你可能向上或向下
  • 如果你决定走哪条路,你可能会迈出一大步或一小步来到达你的目的地。

本质上,有两件事你应该知道以达到最小值,即走哪条路,走多大的一步。

梯度下降算法有助于我们利用导数高效和有效地做出这些决定。一个导数是一个来自微积分的术语,计算为图形在特定点的斜率。斜率是通过在该点画一条切线来描述的。所以,如果我们可以计算这条切线,我们就可以计算出达到最小值的方向。我们将在文章的后半部分更详细地讨论这一点。

最小值

在同一个图中,如果我们在绿点画一条切线,我们知道如果我们向上移动,我们就远离最小值,反之亦然。此外,切线给我们一种斜率陡度的感觉。

蓝点处的斜率没有绿点处的斜率陡,这意味着从蓝点处到达最小值所需的步数比从绿点处到达最小值所需的步数少得多。

成本函数的数学解释

现在让我们把所有这些知识放进一个数学公式。方程中,y = mX+b‘m’和‘b’是它的参数。在训练过程中,他们的价值观会有一个小的变化。让这个小变化用δ 表示。参数值将分别更新为m = m-δmT1 和 b=b-δb,。我们的目标是在y = mx+b中找到误差最小的 m 和 b 的值,即最小化成本函数的值。

重写成本函数:

这个想法是,通过计算函数的导数/斜率,我们可以找到函数的最小值。

学习率

达到最小值或底部所需的步长称为学习速率。我们可以用更大的步长/更高的学习率覆盖更多的区域,但是有超过最小值的风险。另一方面,小步/更小的学习率会消耗大量时间到达最低点。

下面的形象化展示了学习率的概念。请看第三张图,我们如何用最少的步数到达最小的点。这是这个问题的最佳学习率。

Source

我们看到,当学习率太低时,需要很多步才能收敛。另一方面,当学习率太高时,梯度下降无法达到最小值,如下图所示。

Source

访问下面的链接,尝试不同的学习速度。

[## 优化学习速度|机器学习速成班|谷歌开发者

能否以更高的学习率更快地达到最小值?将学习率设置为 1,并持续按步骤…

developers.google.com](https://developers.google.com/machine-learning/crash-course/fitter/graph)

派生物

机器学习在最优化问题中使用导数。像梯度下降这样的优化算法使用导数来决定是否增加或减少权重来增加或减少任何目标函数。

如果我们能够计算一个函数的导数,我们就知道朝哪个方向去最小化它。

主要我们将处理微积分中的两个概念:

  • 权力法则

幂规则计算变量的幂的导数。

  • 链式法则

链式法则用于计算复合函数的导数。链式法则也可以用莱布尼茨的符号表示如下:

如果一个变量 z 依赖于变量 y ,而后者又依赖于变量 x ,那么 yz 都是因变量,那么 z 通过中间变量 y 也依赖于 x 。这被称为链式法则,数学上写为:

让我们通过一个例子来理解它:

  • 使用导数的规则,让我们计算成本函数相对于 m 和 c 如何变化。这涉及到偏导数的概念,它说,如果有一个两个变量的函数,那么要找到该函数对一个变量的偏导数,将另一个变量视为常数。这将通过一个例子变得更加清楚:

计算梯度下降

现在让我们将这些微积分规则的知识应用到我们的原始方程中,并找到成本函数 w.r.t 对‘m’‘b’的导数。修改成本函数方程:

为了简单起见,让我们去掉求和符号。求和部分很重要,尤其是对于随机梯度下降(SGD )批量梯度下降的概念。在批次梯度下降期间,我们一次查看所有训练样本的误差,而在 SGD、中,我们一次查看每个误差。然而,为了简单起见,我们将假设我们一次查看一个错误。

现在让我们计算误差 w.r.t 对 m 和 b 的梯度:

将值插回到成本函数中,并将其乘以学习率:

这个等式中的这个 2 并不那么重要,因为它只是说我们的学习率是它的两倍或一半。所以让我们也摆脱它。所以,最终,整篇文章归结为两个简单的方程,代表梯度下降的方程。

m,b =下一个位置参数;m⁰,b⁰ =当前位置参数

因此,为了求解梯度,我们使用新的 m 和 b 值迭代我们的数据点,并计算偏导数。这个新的梯度告诉我们在当前位置的成本函数的斜率,以及我们应该移动以更新参数的方向。我们更新的大小是由学习率控制的。

结论

本文的重点是演示梯度下降的概念。我们使用梯度下降作为线性回归的优化策略。通过绘制最佳拟合线来衡量学生身高和体重之间的关系。然而,这里需要注意的是,线性回归示例是为了简单起见而选择的,但是也可以与其他机器学习技术一起使用。

了解朴素贝叶斯分类器

原文:https://towardsdatascience.com/understanding-the-naive-bayes-classifier-16b6ee03ff7b?source=collection_archive---------6-----------------------

用这个经典的分类算法对猫、仓鼠、垃圾邮件等进行分类

现在,我们已经充分探索了贝叶斯定理,让我们来看看利用它的分类算法——朴素贝叶斯分类器。

分类是定量计算给定观察值应被分配到哪个类别(也称为组)的过程,是数据科学中的一个重要过程。分类的一些示例应用包括弄清楚患者是否特别有患病风险,识别可能流失的客户,或者将电子邮件标记为垃圾邮件。

有许多分类算法,每一种都有各自的优缺点。例如,如果您只想获得预测能力,您可以考虑 XGBoost 或神经网络。如果您对了解哪些因素以及这些因素如何驱动您的类之间的差异更感兴趣,您可以考虑使用逻辑回归。

朴素贝叶斯是一种已经存在了一段时间的算法(根据维基百科的说法,从 20 世纪 60 年代开始)。虽然它可能缺乏一些最近开发的算法的宣传和火力,但它是一个强大而通用的工具,经受住了时间的考验()而且它的缺点也很好理解,这在构建模型时往往一样有用,甚至更有用 ) —所以它绝对值得更多地了解。

它是做什么的?

让我们先退后一步,用贝叶斯术语来构建我们的分类问题——我们有一组先验信念,并在观察和收集证据时更新我们的信念。

在统计学中,一切都围绕着假设。我们对世界如何运转做出一个假设(一个有根据的猜测),然后我们着手收集证据来检验这个假设(如果你想知道细节,我在这里写了一篇关于假设检验的文章)。

分类模型也可以被框定为一种假设。让我们首先写出分类问题的目标和变量:

  • 目标是在给定其特征的情况下,预测给定观察值属于哪一类。例如,给定一个描述,我们可能试图预测某个动物是猫、狗还是仓鼠。
  • Y =我们试图预测的类标签。在我们的例子中,类别标签是猫、狗和仓鼠。
  • X1,X2,X3 等。 =我们试图进行预测的观察特征。我们可能用来区分猫、狗和仓鼠的一些特征是大小和灵活性(喵喵叫、吠叫、沉默类别会使这太容易了)。

好了,这就是分类——现在让我们通过贝叶斯透镜来检查分类。大多数分类算法通过估计(对于每个类别)观察值属于该类别的概率来进行预测。那么估计概率最高的类就是我们的预测:

P(Y = Cat) = 0.20

P(Y =狗)= 0.60

P(Y =仓鼠)= 0.20

预言被观察的动物是狗!

但是我们如何计算这些类概率呢?救援的条件概率!条件概率 P(H|E)(其中 H 是我们的假设,E 是我们的证据)是在给定证据的情况下我们的假设为真的概率。对于猫的例子,我们的假设 H 是观察对象是一只猫。我们的证据 E 是它是中等规模的,不敏捷。给定我们的证据,我们可以将它是猫的条件概率写为(等式读作“给定它是中等大小且不敏捷的观察是猫的概率”):

P(Y=Cat | Size=Medium,Agile=No)

好的,这很酷,但是我们实际上如何解决它呢?这就是贝叶斯定理的用武之地——利用它我们可以写出:

我在这里再次使用了我在上一篇文章中描述的一些术语,但是让我快速回顾一下:

  • 先验是随机选择的观察结果是猫的未缩放概率。对于我们的模型,估计 P(IsCat)的合理方法是通过计算我们的数据集由猫组成的百分比(假设我们的样本合理地代表了总体)。
  • 缩放器的工作是根据证据放大或缩小我们的先验。它试图定量地回答这个问题— “既然我已经观察到这个证据,我应该如何调整我的信念?”在我们的例子中,缩放器会调整我们的先验,以考虑到所讨论的动物是中等大小且不灵活的事实。它通过计算出中等体型和不敏捷的猫的比例来做到这一点。如果它很多,那么它有助于提高我们的信念,我们的观察是一只猫。如果只有一小部分是,那么它有助于降低我们的信念,我们正在处理一只猫。
  • 规格化器用于调整分子——调整证据稀有度的计算概率。
  • 理解缩放器和规格化器之间的比例非常重要。当定标器大于规格化器时,我们增加先验——证据增加了我们对它是一只猫的信念。实际上,比率执行以下分析链:
  1. 中等体型且不敏捷的动物占多大比例?
  2. 中等体型且不敏捷的猫占多大比例?
  3. 如果中型而敏捷的猫的比例大于中型而敏捷的动物的比例,那么就有理由相信我们正在和一只猫打交道。我们应该相应地修改我们的先验知识来反映这一点。

贝叶斯定理的问题在于,它迫使我们计算许多概率,包括一些很难估计的概率。但是在下一节中,我们将看到朴素贝叶斯如何通过一些巧妙的假设,帮助我们大大简化事情。

转到朴素贝叶斯的简化世界

让我们从规格化器开始。我们不需要它来分类。要了解原因,让我写出所有三个公式:

注意规格化项(绿色方框)在所有三类概率方程中是相同的。所以基本上它是一个常数,我们可以安全地忽略它。让我们看看我们是如何做到的——在分类中,我们更关心亲戚而不是绝对。回想一下,我们通过找到最可能的类(具有最大可能性的类)来进行预测。为了做到这一点,我们做了这样的比较:

因为分母 P(Medium|NotAgile)在不等式的两边是相同的,所以我们可以将等式简化为:

所以(暂时忘记仓鼠)如果左边的值更大,那么我们预测猫,否则我们预测狗。

天真(但聪明)的关键假设

现在到了算法的幼稚部分,我认为它实际上非常聪明,一点也不幼稚。朴素贝叶斯做出了一个关键的简化假设,即对于给定的类,我们的所有特征(X 个变量,如大小和灵活性)都是相互独立的。在概率中,独立性的概念意味着无论 B 是否发生,事件 A 发生的概率是相同的——或者如果你像我一样更熟悉统计学术语,我们可以说 A 和 B 彼此之间的相关性为零。如果 A 和 B 是独立的,那么它们的条件概率简化为:

P(A|B) = P(A)和 P(B|A) = P(B)

警告:数学传入

让我们看看这个假设如何帮助我们。但在此之前,我们需要先介绍一些有用的数学知识(为所有的方程道歉)。

简评 — P(A,B,C)表示 A 和 B,C 都同时发生的概率(又名联合概率)。P(A|B,C)是在 B 和 C 已经发生的情况下,A 发生的概率。

从贝叶斯定理和一般概率我们知道:

P(A,B) = P(A|B) * P(B) = P(B|A) * P(A)

所以贝叶斯定理的分子(定标器和先验的乘积)是一个联合概率。因为我们取消了规格化器,所以我们只关心分子。回到我们的动物示例,回想一下我们将可能性计算中的猫部分简化为:

第一个概率 P(IsCat)是先验概率,第二个概率是比例因子,正如我们刚刚了解到的,先验概率和比例因子的乘积是一个联合概率:

的概率链规则中,我们知道:

P(A,B,C) = P(A|B,C) * P(B|C) * P(C)

所以我们可以把联合概率改写为:

快到了!这就是朴素贝叶斯的简化假设拯救世界的地方。因为我们可以假设特征、规模和敏捷性是独立的(在一个类中),所以我们知道:

P(Medium|NotAgile,IsCat) = P(Medium|IsCat)

我们的等式最终简化为:

那很酷。这意味着我们可以通过用与特征一样多的定标器对先验进行定标来估计属于特定类别 C 的观察的可能性:

Y 是类 C 的可能性= P(X1|C) * P(X2|C) * … * P(Xn|C) * P(C)

请用英语

对这一切的简单英语解释是:

  • 我们从先验 P(IsCat)开始——随机选择的观测值属于 Cat 类的概率。我们可以基于我们的训练数据来估计这个先验,或者如果我们认为我们的训练数据有偏差,甚至可以假设所有的先验都是相等的。
  • 对于给定观察的每个特征/类别组合,我们计算一个定标器(或者查找一个定标器,因为定标器通常已经被计算)。这用于根据观察特征中的信息信号调整先验。例如,假设我们的观察是微小的。参考我们的训练数据,我们发现 P(Tiny |仓鼠)真的很高——换句话说,很大一部分仓鼠都很小。同时 P(Tiny|Dog)真的很小——很少有狗是小的。在这种情况下,仓鼠类的大小特征的缩放器会相对于狗(受到其缩放器的惩罚)向有利于仓鼠的方向移动模型。
  • 每个类的可能性只是该类的先验和标度的乘积。继续前面的例子,假设观察是微小的,也是笨拙的。我们的训练数据告诉我们很大比例的仓鼠很小,中等数量的仓鼠很笨拙。同时极少数的狗很小,中等数量的狗很笨拙。最后,中等数量的猫很小,几乎没有猫是笨拙的

可能性(仓鼠)= P(小仓鼠)* P(笨拙仓鼠)

可能性(仓鼠)=高*中=有点可能

可能性(狗)= P(小|狗)* P(笨|狗)

可能性(狗)=低*中=有点低

可能性(猫)= P(小|猫)* P(笨拙|猫)

可能性(Cat) =中等*几乎为零=不太可能

所以在这种情况下,朴素贝叶斯会预测仓鼠,因为它有最高的可能性。简而言之,这就是朴素贝叶斯——在高层次上,朴素贝叶斯只是基于其特征将简化版本的贝叶斯定理应用于每个观察值(以及每个潜在的类)。这不是火箭科学,但在我看来,它以自己简单的方式强大。

Photo by Ricky Kharawala on Unsplash

结论

进一步探索的主题是朴素贝叶斯分类器的特征独立性假设是否(以及如何)损害其相对于其他算法的性能。但独立性假设也是其关键优势之一,因为它允许快速训练和预测,即使是在非常大的数据集上。此外,朴素贝叶斯几乎没有要调整的超参数,所以它通常概括得很好。

需要注意的一点是,由于特征独立性假设,朴素贝叶斯输出的分类概率可能非常不准确。因此,如果您的最终应用需要对概率进行精确的估计,您将需要使用另一种算法。

另一方面,尽管天真,朴素贝叶斯在选择正确的类别方面通常做得相当好——它可能不擅长估计绝对概率,但它非常擅长测量相对可能性。

感谢阅读,干杯!

更多数据科学与分析相关帖子由我:

数据科学家是做什么的?

理解贝叶斯定理

二项分布

了解 PCA

维度的诅咒

理解神经网络

理解使用熊猫时的优化需求

原文:https://towardsdatascience.com/understanding-the-need-for-optimization-when-using-pandas-8ce23b83330c?source=collection_archive---------16-----------------------

People waiting in a queue, for their turn (Source: travel.jumia)

你知道在大量数据处理中优化算法的重要性吗?根据实现方式的不同,一个简单的代码可以运行几秒钟到几个小时。Python 作为一种解释型语言,在编写需要大量处理的算法时需要特别小心。您可能想知道解释高级代码会如何影响性能。正如您已经知道的,在编译时,您的代码在运行程序之前被优化并翻译成机器码。但是,当解释时,它是在运行时翻译的,你的程序的总运行时间是“执行时间+解释时间”,这是你可能从来没有想到的。

python 代码的执行过程

Execution process of python code (drawn in draw.io)

一旦我们运行 python 代码,首先它被 CPython 编译成 python 字节码。下一步,在 CPython 虚拟机上逐行解释和执行字节代码。同时,各个机器代码(指令)在 CPU 上执行。相比 C 之类的纯编译语言,由于 python 中的动态类型化,在执行之前需要花费如此多的时间进行解释。此外,在执行循环时,每次迭代都会解释相同的行。此外,在每次迭代中提取并解码相同的指令,而仅改变操作数。因此,当您处理大量数据时,减少 python 解释器和 CPU 的开销工作非常重要。

使用熊猫

当您拥有大量原始数据,并且您可能需要从中获取有用的信息或生成要素时。为此,您需要检查、处理、清理、分析和可视化数据集。为此,您可能需要使用最流行的用于数据分析的 python 库之一,Pandas。使用导入库的函数时,在选择它们时需要额外小心。Pandas 库中用于索引的一些常用函数有 df.loc、df.iloc、df.at、df.iloc。此处链接的这个文档给出了每个函数的清晰概念以及何时何地使用它们的示例。在这里,让我们看看每个函数在使用时会产生的不同。

让我们举一个例子,数据帧的新列 C 需要填充使用我们自己定义的函数计算的值。这里,A 列中的值作为参数传递,用于计算目的。

注:这里的所有运行时测试都是在英特尔酷睿 i3、2.60 GHz 时钟速度的四核处理器和 Ubuntu 18.04.1 LTS 操作系统上进行的。

使用 df.loc

%%time
for i in range(0,1000000):
    x = df_A.loc[i,'A']
    df_A.loc[i,'C']=my_function(x)

运行时间:6 小时 2 分 3 秒

“df.loc”功能非常强大,它可以用来访问使用索引的行,使用索引和列名的单元格,切片数据帧,甚至用于布尔索引。这可以被认为是一个优点和缺点。它让你的工作变得容易,也让翻译的工作变得困难。因为参数的多样性,它可以接受,python 解释器需要解码被传递的参数的类型。当这在一百万次迭代循环中完成时,它需要解码一百万次。这就是口译的工作方式。

使用 df.iloc

%%time
for i in range(0,1000000):
    x = df_A.iloc[i,'A']
    df_A.iloc[i,'C']=my_function(x)

运行时间:5 小时 33 分 36 秒

与 df.loc 相比,df.iloc 的唯一区别是 df.iloc 知道参数是整数索引。因此,在解释时解码论点的开销时间仍然存在。问题是我们使用的函数是一个通用函数,我们需要一个专用函数来访问单个单元格。

使用 df.at

%%time
for i in range(0,1000000):
    x = df_A.at[i,'A']
    df_A.at[i,'C']=my_function(x)

运行时间:52.1 秒

这看起来与前面的实现非常相似。但是使用 df.at 函数的区别在于解释器不需要解码参数。这是因为它只接受一种方式的参数,即[index,column_name]。执行代码时这种差异的影响是,它只花了 52.1 秒。现在很清楚为什么我们需要一个更专用的函数,当它花费的时间非常大的时候。

使用 df.iat

%%time
for i in range(0,1000000):
    x = df_A.iat[i,'A']
    df_A.iat[i,'C']=my_function(x)

运行时间:20.1 秒

df.at 和 df.iat 的区别和 df.loc 和 df.iloc 的区别是一样的,所以这里不需要把列名转换成列索引。现在 python 解释器消耗的开销时间几乎被消除了,但是同一行仍然被解释了一百万次。为了解决这个问题,我们需要使用一个没有循环的函数。CPU 消耗的开销时间也仍然存在(即获取和解码相同的指令/机器代码一百万次)。如果你想知道我们如何克服这两个问题,这是你应该已经知道的“向量化”。

…向量化…

英特尔 x84 指令集架构(ISA)的 SIMD 扩展(SSE)的引入,使得对多个数据并行执行相同操作成为可能。这是通过使用 128 位寄存器实现的,该寄存器可以保存四个单精度浮点数据(32 位数据)。被称为 AVX(高级向量扩展)的 SSE 的最新版本引入了 512 位寄存器。这一版本在采用 Intel-64 ISA 的现代处理器中可用。因此,现在可以同时处理多达 8 个双精度浮点数据(64 位数据)。

很少有像 MATLAB、Octave 和 R 这样用于数值和统计计算的语言支持数组编程。数组编程让我们可以直接编写高级向量化代码。在 python 中,矢量化是由第三方库实现的,如 NumPy 和 Pandas,其中 Pandas 实际上是构建在 NumPy 之上的。用 NumPy 编写矢量化代码来处理数据比 Pandas 简单得多,也快得多。但是要对数据进行分析、可视化和预处理,熊猫提供的数据结构“DataFrame”使用起来更舒服。下面显示的代码是 Pandas 中矢量化实现的一个简单示例。

df_A['columnC'] = df_A['columnA'] + df_A['columnB']

因为这只是一行没有任何循环的代码,所以只解释一次,现在开销就完全消除了。因为 Pandas 使用 SIMD 指令集来执行这个操作,所以几个数据也同时被处理。因此,CPU 的开销也大大减少。

df.apply 是 Pandas 中的一个函数,可用于向量化复杂算法。下面给出的代码显示了我们如何使用 df.loc 和 df.at 对开始尝试的同一个示例进行矢量化。

使用 df.apply

df_A['C']=df_A['A'].apply(lambda x : my_function(x))

运行时间:7.27 秒

矢量化之后,这里所有的 100 万个数据现在被分组为多个向量,每个向量中的数据在 CPU 中并行处理。这就是为什么我们能够看到这种差异。

当需要传递多个参数时,可以修改上述代码,如下所示

df_A['columnC'] = df_A[['columnA','columnB']].apply(lambda x : my_fucntion(x['columnA'],x['columnB']) )

A summary of the above experiment

结论

与 df.iat 相比,使用 df.apply 只花费了 36.2%的时间,与 df.loc 相比,只花费了 0.03%的时间。向量化不仅仅是为了缩短算法,也是为了让它们运行得更快。这样,分析数据集和预处理它们就容易多了。

浏览这个文档将会给我们更多关于如何使用其他函数如 df.isin、df.where 来对基于循环的索引进行矢量化的想法。

理解正态分布(使用 Python)

原文:https://towardsdatascience.com/understanding-the-normal-distribution-with-python-e70bb855b027?source=collection_archive---------2-----------------------

Photo by Luís Perdigão on Unsplash

了解如何使用它,以及为什么它对数据科学和统计学如此重要

我写数据科学已经有一段时间了,我意识到虽然我已经触及了许多主题,但我还没有涵盖正态分布——统计学的基本概念之一。这是一个疏忽,我打算用这篇文章来弥补。

不管你是否在定量领域工作,你可能在某个时候听说过正态分布。它通常被称为钟形曲线,因为它看起来像一个钟。

什么是统计分布?

在我们深入研究正态分布之前,让我们先来看看什么是统计分布。借用我之前关于二项分布的帖子:

概率和统计的新手可能会遇到的一个问题是概率分布的概念。我们倾向于确定性地思考,比如“我将一枚硬币抛 10 次,产生了 6 个头”。所以结果是 6,那么分布在哪里呢?

概率分布来源于方差。如果你和我都掷 10 枚硬币,很可能我们会得到不同的结果(你可能得到 5 个正面,而我得到 7 个)。这种方差,也就是围绕结果的不确定性,产生了一种概率分布,它基本上告诉我们哪些结果相对更有可能(比如 5 个头),哪些结果相对不太可能(比如 10 个头)。

所以每组 10 次抛硬币就像一个随机变量。我们事先不知道会有多少头。但是如果我们知道它的分布,那么我们就知道哪些结果是可能的,哪些是不可能的。这基本上是任何统计分布告诉我们的——它是一个图表,告诉我们得到每个可能结果的可能性有多大。

或者换一种方式来思考这个问题,如果我们一次又一次地运行一个不确定结果的实验(每次都收集结果),结果的分布将会收敛到什么程度。

正态分布

现在让我们回到正态分布。正态分布的随机变量可能具有平均值 0 和标准差 1。那是什么意思?这意味着我们期望该值为 0(平均而言),但我们的随机变量的实际实现值在 0 附近波动。它摆动的量是 1。我在下面画了一个正态分布图。蓝线在图中越高,在 x 轴上看到它下面的值的频率就越高。请注意,3 或更大的值是非常不可能的。这是因为我们的正态分布随机变量的波动量(标准差)为 1,3 距离均值 0 有三个标准差(真的很远!).

The Normal Distribution

因此,组合成正态分布的各个实例就像随机数生成器的结果一样— 一个随机数生成器,它理论上可以采用负无穷大和正无穷大之间的任何值,但已经预设为以 0 为中心,并且大多数值出现在-1 和 1 之间(因为标准偏差为 1)。

为什么有用?

看起来很简单,对吗?正态分布只是告诉我们运行一个随机数发生器(具有上面提到的预设特征)很多很多次的结果会是什么样子。

那么这为什么有用呢?那是因为现实世界的很多现象都符合正态分布。例如,人们的身高是众所周知的正态分布。如果你测量你 5 个朋友的身高,你会得到一个看起来不稳定的分布。但是,随着你取样的朋友数量的增加(例如,你在脸书的所有朋友,假设你相当社会化),分布将开始看起来越来越像正态分布。

在企业界,制造缺陷严重程度的分布被发现是正态分布(这是有道理的:通常你会做对,有几次你会做错,偶尔你会完全搞砸)——事实上,过程改进框架六适马基本上是围绕这一观察建立的。

在投资领域,股票和债券等资产的定期(每日、每月甚至每年)回报被假定为服从正态分布。做出这个假设可能低估了厚尾的可能性和风险(严重的市场崩溃比模型告诉我们的更频繁发生),但这是另一天的讨论。

在数据科学和统计学中,统计推断(和假设检验)非常依赖于正态分布。因为我们喜欢数据科学,所以让我们更深入地探索这一特殊应用。

平均值的波动性

刚学统计学的时候,被标准差搞糊涂了。我想,“为什么他们有时称之为标准差,有时称之为标准差?”后来才知道标准差其实是指均值的波动率(标准差)。

为什么均值会有变化?我们习惯于把均值,即某事物的期望值,看作一个静态值。你取所有的高度,除以高度数,就得到平均高度。这是预期值。如果有人让你在没有任何先验信息的情况下猜测一个人的身高(你不能给出你的猜测范围),你会猜测平均值(这就是为什么我们称之为期望值)。

但是平均值本身实际上是一个随机变量。这是因为我们的平均身高是基于一个样本——不可能对整个人口(世界上的每个人)进行采样,所以无论我们的身高研究规模有多大,它仍然是一个样本。

因此,即使我们努力做到不偏不倚,以代表总体的方式选取每个样本,每次我们选取一个新样本,从该样本计算出的平均值都会与之前的略有不同。真烦人。如果我们不能确定它的价值,那么我们又如何利用它呢?例如,假设我们的朋友问我们:

"一个人的平均身高是否大于 6 英尺?"

因此,我们开始工作并获得一些数据(通过对站在我们周围的 10 个人进行快速调查),并计算出样本的平均值为 5 英尺 9 英寸。但是然后我们告诉我们的朋友,“我不知道,我的样本均值低于 6 英尺,但最终它可能会更高或更低。均值本身会随着样本而波动,所以没人真正知道。”那不是很有帮助(而且极其优柔寡断)。过了一段时间,没有人会再问我们的洞察力。

这就是正态分布的用武之地——我们样本均值的均值本身就是一个正态分布的随机变量。也就是说,如果我们选取足够多的样本,并计算每个样本的平均值,这些平均值的分布就像正态分布一样。这使得我们甚至可以从相对较小的样本中对总体人口做出推断——也就是说,通过少量的观察,我们可以了解到总体人口的大量统计特征。

在前面的例子中,正态分布的随机变量的平均值为 0,标准差为 1。但是均值和标准差可以是我们需要的任何值。让我们使用一些 Python 代码来检查正态分布如何帮助我们向我们的朋友提供更好的答案。

Python 中的正态分布

(完整代码, 请查看我的 GitHub 这里 )

首先,让我们把我们的输入放在一边:

import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt
import seaborn as sns

现在让我们生成一些数据。我们将假设一个人的真实平均身高是 5 英尺 6 英寸,真实标准偏差是 1 英尺(12 英寸)。我们还定义了一个名为“target”的变量 6 英尺,这是我们的朋友询问的高度。为了使生活更容易,我们将把一切都转换成英寸。

mean_height = 5.5*12
stdev_height = 1*12
target = 6*12

有了这些参数,我们现在可以编造一些高度数据。我们将创建一个 10,000 乘 10 的数组来保存我们的调查结果,其中每一行都是一个调查。然后我们会用一个正态分布的随机变量填充数组的每个元素。您可以给随机变量函数一个平均值和一个标准差,但我想向您展示如何手动定制随机变量的平均值和标准差(更直观):

  • 您可以通过向您的正态分布随机变量添加一个常数来改变平均值(其中常数是您想要的平均值)。它将随机变量的中心位置从 0 改变为你添加的任何数字。
  • 您可以通过将常数乘以您的随机变量来修改您的正态分布随机变量的标准偏差(其中常数是您想要的标准偏差)。

在下面的代码中,np.random.normal()生成一个正态分布的随机数,平均值为 0,标准差为 1。然后,我们将它乘以“stdev_height ”,得到我们想要的 12 英寸的波动性,并加上“mean_height ”,以便将中心位置移动 66 英寸。

mean_height + np.random.normal()*stdev_height

我们可以使用嵌套的 for 循环来填充我们的调查数据,然后检查输出是否符合我们的预期:

height_surveys = np.zeros((10000,10))
for i in range(height_surveys.shape[0]):
    for j in range(height_surveys.shape[1]):
        height_surveys[i,j] = mean_height +\
                              np.random.normal()*stdev_heightprint('Mean Height:', round(np.mean(height_surveys)/12,1), 'feet')
print('Standard Deviation of Height:', 
      round(np.var(height_surveys)**0.5/12,1), 'foot')

当我运行代码时,它打印出平均身高为 5.5 英尺,人的身高标准偏差为 1 英尺——这些与我们的输入相匹配。好的,我们有调查数据了。现在我们来做一些统计推断。

假设我们只有时间和资源进行一次身高调查(10 个人)。我们得到了以下结果:

Single Survey Histogram

一半的人身高超过 6 英尺,一半的人更矮(红线表示 6 英尺)——没有太多信息。我们样本中的平均高度是 69 英寸,略低于 6 英尺。

尽管如此,我们还记得,因为我们的样本量很小(只有 10 人参与调查),我们应该预料到我们的结果会有很大的差异。最酷的事情是,即使只有一个调查,我们也能对平均值的变化做出相当不错的估计。而且我们知道分布的形状——它是正态分布(铁杆统计学家会说我需要说它大致是正态分布)!

标准误差=样本标准差/ sqrt(N)

其中 N 是观察值的数量(本例中为 10),sqrt 表示取平方根。

标准误差是平均值的标准偏差(如果我们继续进行 10 个人的调查,并计算每个人的平均值,这些平均值的标准偏差将最终收敛到标准误差)。就像我们提到的,样本均值的分布是正态分布。这意味着,如果我们进行大量的调查,并从总体上看它们各自的平均值,我们会看到一条钟形曲线。我们来看看这个。

回想一下,之前我们创建了一个 10,000 乘 10 的调查结果数组。我们的 10,000 行中的每一行都是一个调查。让我们计算 10,000 次调查的平均值,并通过以下代码行绘制直方图:

# Histogram that shows the distribution for the mean of all surveys
fig, ax = plt.subplots(figsize=(12,8))
sns.distplot(np.mean(height_surveys,axis=1), 
             kde=False, label='Height')ax.set_xlabel("Height in Inches",fontsize=16)
ax.set_ylabel("Frequency",fontsize=16)
plt.axvline(target, color='red')
plt.legend()
plt.tight_layout()

这给了我们下面的直方图——这是一个钟形曲线,如果我曾经见过的话:

Histogram of the Sample Means

现在让我们使用我们最初的调查(我展示的第一个看起来不可靠的直方图)来计算分布。只有一个 10 人的样本,我们别无选择,只能猜测样本均值是真实均值(统计学中所说的总体均值)。所以我们猜测平均值是 69 英寸。

现在我们来计算标准误差。我们样本的标准偏差是 12.5 英寸:

# I picked sample number 35 at random to plot earlier
np.var(height_surveys[35])**0.5)    # = 12.5

让我们覆盖我们的推断分布,一个平均值为 69 英寸、标准偏差为 12.5 英寸的正态分布在真实分布上(来自我们的 10,000 个模拟调查,我们假设这是真实的)。我们可以通过下面几行代码来实现,其中

# Compare mean of all surveys with inferred distribution
fig, ax = plt.subplots(figsize=(12,8))# Plot histogram of 10,000 sample means
sns.distplot(np.mean(height_surveys,axis=1), 
             kde=False, label='True')# Calculate stats using single sample
sample_mean = np.mean(height_surveys[35])
sample_stdev = np.var(height_surveys[35])**0.5
# Calculate standard error
std_error = sample_stdev/(height_surveys[35].shape[0])**0.5# Infer distribution using single sample
inferred_dist = [sample_mean + np.random.normal()*\
                 std_error for i in range(10000)]# Plot histogram of inferred distribution
sns.distplot(inferred_dist, kde=False, 
             label='Inferred', color='red')ax.set_xlabel("Height in Inches",fontsize=16)
ax.set_ylabel("Frequency",fontsize=16)
plt.legend()
plt.tight_layout()

我们得到了下面一组直方图:

我们有点偏离,但老实说,这还不算太糟糕,因为我们只用 10 次观察就生成了推断分布(红色)。我们之所以能够做到这一点,是因为样本均值的分布呈正态分布。

我们对标准差的估计也有方差

出于好奇,样本标准差的分布也大致是正态的(其中样本标准差是 10 人单次调查的标准差):

# Check out the distribution of the sample standard deviations
vol_dist = np.var(height_surveys, axis=1)**0.5# Histogram that shows the distribution of sample stdev
fig, ax = plt.subplots(figsize=(12,8))
sns.distplot(vol_dist, kde=False, 
             label='Sample Stdev Distribution')ax.set_xlabel("Inches",fontsize=16)
ax.set_ylabel("Frequency",fontsize=16)
plt.legend()
plt.tight_layout()

这给了我们下面的情节。这是一个相当大的标准差范围。这是否意味着我们对标准误差的估计并不像我们最初认为的那样可靠?

The Distribution of the Sample Standard Deviations (Pretty Normal!)

让我们将标准误差分布(红色)添加到上面的图中(回想一下,标准误差是标准差的函数)。它更低(因为标准误差是标准偏差除以每次调查中观察次数的平方根)。出于同样的原因,标准误差波动也较小。即便如此,这仍然比我们所能接受的要大得多——但是有一个简单的解决方法。

The Variance of the Standard Error Looks High

通过纳入更多的观察数据,我们可以很容易地减少标准误差分布的波动。让我们把它增加一倍,达到 20 人,看看会发生什么——在我们的调查中,只增加了 10 个人,红色直方图就变得明显更细了。酷!

We Can Reduce the Variance of Standard Error By Taking More Observations

最后,我们可以给我们的朋友一个更好的答案(他想知道人口的平均身高是否大于 6 英尺)。我们有两种方法可以做到这一点。首先,我们可以通过产生一堆随机变量(当然是正态分布的)来模拟它。当我运行下面的代码时,我得到 23%的观察值是 6 英尺或更高。

# Simulation method for answering the question# Generate 10,000 random variables
inferred_dist = [sample_mean + np.random.normal()*\
                 std_error for i in range(10000)]# Figure out how many are > than target
sum([1 for i in inferred_dist if i>=target])/len(inferred_dist)

或者因为我们知道它是正态分布的,我们可以使用累积密度函数来计算出 6 英尺或更长的曲线下的面积(曲线下的面积告诉我们概率)。下面的单行代码告诉我们,身高 6 英尺或更高的概率是 23%,同上。

1 - norm.cdf(target, loc=sample_mean, scale=std_error)

因此,我们应该告诉我们的朋友,尽管鉴于我们的样本是如此不正式和小,存在不确定性,但人们的平均身高仍很有可能低于 6 英尺(我们也可以进行更正式的假设检验,但那是另一个故事了)。我希望你记住三点:

  1. 正态分布及其有用的性质使我们能够推断出大量关于潜在人口的统计性质。然而,如果我们的均值和/或标准差的正确性有很多不确定性,那么我们就有垃圾进垃圾出的风险。当我们的样本非常小(粗略的经验法则是 30 或更少,但这个数字在很大程度上取决于数据)或不具有代表性(在某些方面有偏差)时,我们应该特别小心。
  2. 可能的话,总是进行更多的观察。当然,可能会有成本限制你这样做的能力。但是在可能的情况下,更多的数据会大大提高你做出正确推断的能力。
  3. 更一般地说,从分布的角度考虑是有帮助的。不管结果如何出现,结果很少是确定的。当你看到一个值时,你不仅要关心这个值是多少,还要关心它如何变化(比如旧金山的温度)。对结果变化的预期让我们为意外做好准备(我知道这是老生常谈)。

结论

我们刚才遵循的思维过程和假设检验(或者 A/B 检验)非常相似。你可以在这篇博文中了解更多。

但更普遍的是,因为世界上有这么多东西遵循它,所以正态分布允许我们对各种现象建模,只要我们对均值和标准差有一个合理的估计。如果你想了解更多关于它的用法,你可以看看下面的文章:

感谢阅读。干杯!

如果你总体上喜欢这篇文章和我的写作,请考虑通过我的推荐链接注册 Medium 来支持我的写作。谢谢!

简化 ROC 和 AUC 指标。

原文:https://towardsdatascience.com/understanding-the-roc-and-auc-curves-a05b68550b69?source=collection_archive---------1-----------------------

消除分类标准的混乱。

Photo by Daniele Levis Pelusi on Unsplash

"天才的定义是化繁为简."―阿尔伯特·爱因斯坦

ROC 和 AUC 曲线是计算任何分类模型性能的重要评估指标。这些定义和术语在机器学习社区中非常常见,当我们开始学习分类模型时,我们每个人都会遇到。然而,大多数时候它们并没有被完全理解或者被误解,它们的真正本质无法被利用。在引擎盖下,这些是非常简单的计算参数,只需要一点点说明。

ROC 和 AUC 的概念建立在混淆矩阵、特异性和敏感性的基础上。此外,我将在本文中使用的例子是基于逻辑回归算法,但是,重要的是要记住,ROC 和 AUC 的概念可以适用于不仅仅是逻辑回归。

参考

本文改编自 Josh Starmer 在 ROC 和 AUC 上的这段 优秀视频 。我会推荐你看这个视频更清晰。Josh 还有许多其他关于各种统计和机器学习概念的视频。

考虑一个假设的例子包含一群人。y 轴有两类,即红色的人代表的**Has Heart Disease**和绿色圆圈代表的**does not have Heart Disease**沿着 x 轴的,我们有胆固醇水平,分类器试图根据胆固醇水平将人分为两类。

需要注意的事项:

  • 绿色圈圈的人胆固醇水平高,但没有心脏病。这可能是由于现在的人正在观察更好的生活方式和定期锻炼的原因。
  • 圈出的红色表示胆固醇水平低的人仍有心脏病。这可能是因为他有其他与心脏相关的问题。

这是一个假设的例子,所以原因也是假设的😃

逻辑回归

现在,如果我们对数据拟合逻辑回归曲线,Y 轴将根据胆固醇水平转换为患心脏病的概率。

白点代表比黑点代表的人患心脏病的可能性低的人。

然而,如果我们想将人分为两类,我们需要一种方法将概率转化为分类。一种方法是将阈值设置为 0.5。接下来,将患心脏病的概率> 0.5 的人分类为“患心脏病”,将患心脏病的概率< 0.5 的人分类为“未患心脏病”。

现在让我们用分类阈值设置为 0.5,用一些我们已经知道他们是否患有心脏病的新人来评估这种逻辑回归的有效性。

我们的逻辑回归模型正确地将除了人 1 和 2 之外的所有人分类。

  • 我们知道人 1 患有心脏病,但我们的模型将其归类为其他类型。
  • 我们也知道第二个人没有心脏病,但我们的模型再次将其分类错误。

混淆矩阵

让我们创建一个混淆矩阵来总结分类。

一旦混淆矩阵被填充,我们可以计算灵敏度特异性来评估 0.5 阈值的逻辑回归。

特异性和敏感性

在上面的混淆矩阵中,我们用数字实际代表的东西来代替数字。

  • 真阳性(TP):有心脏病的人,也被预测有心脏病。
  • 真阴性(TN): 没有**有心脏病的人,也被预测没有心脏病。
  • 假阴性(FN): 患有心脏病但预测说他们没有的人。
  • 假阳性(FP): 没有心脏病*但预测说他们有。*

我们现在可以根据混淆矩阵计算两个有用的指标:

灵敏度

敏感度告诉我们有多少患有心脏病的人被正确地识别出来。

结果是:3/3+1 = 0.75

这告诉我们,75%的心脏病患者被我们的模型正确地识别出来。

特征

特异性告诉我们没有心脏病的人实际上被正确识别的百分比。

结果是:3/3+1 = 0.75

这告诉我们,我们的模型再次正确识别了 75%没有心脏病的人。

如果正确识别阳性对我们来说很重要,那么我们应该选择灵敏度更高的模型。然而,如果正确识别阴性更重要,那么我们应该选择特异性作为度量标准。

确定正确的阈值

现在,让我们来谈谈当我们使用不同的阈值来决定一个人是否患有心脏病时会发生什么。

  • 将阈值设置为 0.1

这将正确地识别所有患有心脏病的人。标记为 1 的人也被正确地分类为心脏病患者。

然而,这也将增加假阳性的数量,因为现在人 2 和 3 将被错误地分类为患有心脏病。

因此,阈值较低:

  • 增加误报的数量
  • 减少假阴性的数量。

重新计算混淆矩阵:

在这种情况下,正确识别患有心脏病的人变得很重要,以便采取纠正措施,否则心脏病会导致严重的并发症。这意味着降低阈值是一个好主意,即使这会导致更多的假阳性病例。

  • 将阈值设置为 0.9

这将正确识别所有没有心脏病的人。然而,被标记为人 1 的人将被错误地分类为没有心脏病。

因此,阈值较低:

  • 减少误报的数量
  • 增加了假阴性的数量。

重新计算混淆矩阵:

阈值可以设置为 0 到 1 之间的任何值。那么我们如何确定哪个阈值是最好的呢?我们需要试验所有的阈值吗?每个阈值产生不同的混淆矩阵,多个阈值将产生大量的混淆矩阵,这不是最好的工作方式。

ROC 图

ROC(受试者操作者特征曲线)有助于确定最佳阈值。它是通过绘制真阳性率(y 轴)对假阳性率(x 轴)而产生的。

****

真实阳性率表明患有心脏病的人被正确分类的比例。

假阳性率表示被归类为“没有心脏病”的人的比例,即假阳性。

为了更好地了解大鹏鸟,我们从头画一个。

  • 将所有人分类为患有心脏病的阈值。

混淆矩阵将是:

这意味着当阈值如此之低以至于每个人都被归类为患有心脏病时,真正的阳性率是 1。这意味着每一个患有心脏病的人都被正确分类。

此外,当阈值太低以至于每个人都被归类为患有心脏病时,假阳性率也是 1。这意味着每一个没有心脏病的人都被错误地分类了。

在 ROC 图上绘制这一点:

蓝色对角线上的任何一点表示正确分类样本的比例等于错误分类样本的比例。

  • 略微提高阈值,以便只有胆固醇值最低的两个人低于阈值。

混淆矩阵将是:

让我们在 ROC 图上画出这个点(0.5,1)。

这意味着这个阈值比前一个更好。

  • 现在如果继续增加阈值,达到一个点,我们得到下面的混淆矩阵:

让我们在 ROC 图上画出这一点(0,0.75)。

到目前为止,这是我们得到的最好的阈值,因为它预测没有假阳性。

  • 最后,我们选择一个阈值,将所有人分类为没有心脏病,即阈值为 1。

在这种情况下,图表将位于(0,0):

然后,我们可以将这些点连接起来,得到 ROC 图。ROC 图总结了每个阈值产生的混淆矩阵,而不必实际计算它们。

只要浏览一下图表,我们就可以得出结论,阈值 C 比阈值 B 更好,根据我们愿意接受的误报数量,我们可以选择最佳阈值。

罗马纪元

AUC 代表曲线下的面积。AUC 给出了通过逻辑模型成功分类的比率。AUC 使得比较一个模型与另一个模型的 ROC 曲线变得容易。****

红色 ROC 曲线的 AUC 大于蓝色 RO C 曲线的 AUC 。这意味着红色曲线更好。如果红色 ROC 曲线由随机森林生成,蓝色 ROC 曲线由逻辑回归生成,我们可以得出结论,随机分类器在对患者进行分类方面做得更好。

结论

AUC 和 ROC 是计算任何分类模型性能的重要评估指标。因此,了解它们是如何计算的和使用它们一样重要。希望下次当你遇到这些术语时,你能够在你的问题的背景下很容易地解释它们。

理解搜索查询—第一部分

原文:https://towardsdatascience.com/understanding-the-search-query-part-i-632d1b323b50?source=collection_archive---------22-----------------------

介绍

终极搜索引擎基本上能理解世界上的一切,并且总是给你正确的信息。我们离那还有很长很长的路要走。—拉里·佩奇

我们称之为查询理解。我们先通过一个问题来了解用例。我认为自己是一个非常注重健康的人,想买一种非常健康的食品。我最终找到了一块不应该含有坚果作为营养的巧克力。

Normal Search Response

于是,我搜索了一下:“无坚果巧克力”。

但是,等等,我在这里看到的是饼干、咖啡包、姜果等等。除了巧克力。这种混乱都是因为搜索引擎无法理解查询的意图。为了解决这个问题,我们必须首先对查询进行规范化,然后向搜索引擎发送一个经过重写和增强的查询。

Post QU, Response

对于当前的场景,如果我们要求搜索引擎查找搜索词“巧克力”,并使用“无坚果”作为过滤器来提升结果。此后,结果将看起来像这样,我很乐意在我的购物车中添加一些商品。

因此,这里的任务是识别查询中的营养意图。

听起来很有趣,但是除了营养领域,我们还需要确定用户希望该营养在搜索的产品中存在还是不存在,因为我们有两种类型的营养过滤器:一种过滤含有该营养的产品[例如,素食者、纯素食者等。]另一种不含该营养成分[如 NoNut、NoGluten、NoSoya 等。].例如,我们来看一些查询:

  1. 无坚果巧克力/无坚果巧克力—过滤器:“无坚果”
  2. 素食蛋糕—过滤器:“素食”
  3. 混合蔬菜:查询中没有营养信息

到目前为止,我们只考虑了营养属性以获得更好的精确度,我们期待着实施品牌和其他产品属性。

了解查询了解:

QU: Complete Flow

从上图可以明显看出,查询理解是关于在搜索引擎对结果进行评分和排名之前发生的事情——也就是说,搜索者将意图表达为查询的过程,以及搜索引擎确定该意图的过程。查询理解栈从字符级技术的底部开始,然后到标记级,在顶部到实体级或查询级本身,称为查询重写。

让我们从堆栈的底部开始,逐一讨论这三个问题:

1.字符级技术(字符过滤) :

a) Unicode 标准化——优选地通过转换成 UTF-8 编码来标准化字符。

b)去除重音符号:Unicode 标准化将字符串转换成标准的字符编码,但是保留了重音符号。例如咖啡馆。在 python 中,有一个 Unidecode 模块。

c)忽略大写:将所有字符串转换为小写。

2.令牌级技术:

a)拼写纠正——这尚未实施。算法可以在这里找到:【https://norvig.com/spell-correct.html】T4

b)词干化和词干化:对于词干化,波特斯特梅尔和 K 词干是最常用的。通过词汇化,K-Stem 将是一个很好的选择,因为我之前也使用过它来通过对结果重新排序来提高搜索相关性。在每次去除屈折后缀后,我们可以在字典中查找并停止进一步的屈折操作。更多选项:https://pdfs . semantic scholar . org/1c0c/0fa 35d 4 ff 8 a2 f 925 EB 955 e 48d 655494 BD 167 . pdf

3.查询重写:最强大的技术,自动转换搜索查询,以便更好地表达搜索者的意图。为了提高查全率,两种主要的查询重写策略是查询松弛查询扩展

为了提高精确度,主要策略是查询分段查询范围

查询分割将搜索查询分割或分割成一系列语义单元。例如没有牛奶巧克力。这里的顺序可以是" {无牛奶" "巧克力" }和{ "无" "牛奶巧克力" }。识别最相关的语义单元的任务被称为分割。

查询范围是另一种重写技术,它通过将上面的每个查询片段匹配到正确的属性来提高精确度。可以通过查询标注来实现,这是命名实体识别(NER)的一个特例。

我们实现了一个基于机器学习的先进的基于命名实体识别的深度学习模型,以实现查询分割和查询范围的目标,并改善搜索者的体验。现在,让我们来看看整个系统的架构:

QUS Architecture

该架构由以下组件组成:

  1. NGINX: 主要用于负载均衡、反向代理、缓存和提供静态内容。在这里,它存在于每个 pod(实例/节点)中,与作为后端服务器代理的应用服务器相关联,并路由请求。它缓存映射到特定 URI 的结果,并返回响应,而不需要访问后端服务器。也可用于快速故障。它还记录访问和错误日志。
  2. uWSGI: 它运行符合 WSGI 的 web 应用程序,并以生产级的方式运行。处理并发请求、流程管理、日志记录、配置等。这里,它打开一个基于 uwsgi 协议的 unix 套接字,并在其上监听请求。
  3. Flask Application: 它公开了一个使用 flask-resplus、marshmallow 等的 RESTFul API。它像一个编排器一样读取 ML 模型响应,找到对应于特定营养属性的维度 id,并最终在 JSON 中返回响应。该服务将接收作为查询参数的搜索词,然后,在执行任何与编排相关的任务之前,应用上面描述的令牌级和字符级技术。单元测试可以使用 pytest (unittest)编写,覆盖率工具用于覆盖率,autopep8 用于格式化代码,pylint 用于代码质量。

这是因为:“ 未经检验的东西坏了。”

Swagger UI 也可以暴露。JSON 的输出如下所示:

对于查询=“无坚果巧克力”

4.机器学习模型即服务:基于深度学习 NLP 技术的鳄鱼模型。这个模型也可以扩展到其他产品属性。JSON 的输出如下所示:

对于查询=“无坚果巧克力”

标签:

我们将在第二部分中单独讨论该部分的其余部分,即 ML 模型和部署。

非专家神经网络建模中涉及的概念

原文:https://towardsdatascience.com/understanding-the-set-up-of-a-simple-neural-network-to-predict-an-output-ff4d108d8f8d?source=collection_archive---------7-----------------------

到了解神经网络,我们试着把它比作人类的学习过程。

想想当我们还在蹒跚学步时,我们是如何学会球的。当我们看着圆形的东西时,我们可以听到一个成年人说“球”这个词。这种情况发生了几次,使得一个圆形物体(图像是输入)对应于单词“球”(声音是输出)。随着时间的推移,我们同时看到了许多其他东西,不同颜色、大小的球,或者是静止的或者是运动的,直到我们最终发现(或者预测下一次我们看到的球!)那一个圆形物体就是大概叫做球。

同样,人工神经网络会用每批数据更新自己,一步一步地学习,通常需要大量数据来正确学习底层机制。因此,这对于了解人类不易察觉的情况是有价值的。它可能会失败(而且确实会失败)——不仅是因为模型的局限性或数据的稀缺,还因为数据的本质没有预测能力。例如,添加机组人员的平均年龄或航班上小吃菜单的细节,都不太可能让我们预测航班延误!

随着人工智能(AI)或深度学习等如此多的流行词汇四处飞舞,如果不熟悉这些术语,而只是对智能机器和魔法般的算法的大黑匣子保持敬畏,可能会令人生畏。虽然该领域的研究人员继续跨越现有的发展,并以惊人的聪明方式探索新的范式,但重要的是要注意到,归根结底,这一切都可以归结为数学——人们不需要任何专业知识来理解基本原理。事实上,许多人工智能数据科学家或软件工程师来自不同的背景,他们在该领域提高了自己的技能。

这篇文章的意图是双重的。这是对那些不是数据科学家,但热衷于通过复制大脑中神经元的基本行为来了解计算系统如何学习的人的介绍。其次,它是对初级程序员关于所涉及的基本概念的讨论,这些概念往往是在不理解其背后的推理的情况下实现的。

神经网络是由什么构成的?

可以把它想象成相互连接的节点图,如图 1 所示。在其最简单的形式中,两端的层构成了主要的输入和输出,而中间的所有层都被链接,使得它们的输出成为下一层的输入。正如我们将在后面看到的,这些节点被称为神经元,因为它们的行为就是如此。

Figure 1: Illustration of a simple neural network

在实践中,可能会有许多层和每层的许多节点,例如在 2017 年击败围棋世界冠军的 deep mind 'alpha Go仅输入就有超过 17,000 个神经元。也有不同的方式来连接各层,例如,递归神经网络(处理顺序信息)具有节点,其中一个阶段的输出作为下一阶段的输入被馈送到相同的节点。

节点上发生了什么?

简单地说,一个节点的输出取决于输入的线性组合。这是输入加上常数的加权和,其中权重和常数项的值是未知的(即,它们形成神经网络模型的参数)。下面的等式和图 2 显示了只有两个输入的情况:

y = f(w1 * x1+w2 * x2+c)

其中 f 代表“的函数”,x_n 是第 n 个输入,w_n 是该输入的第 n 个权重,c 是输出为 y 的节点的常数。

Figure 2: Example of a node with only two inputs

神经元被激活意味着什么?

本质上,如果神经元的输出为正,那么它就是活跃的。再次使用简单的力量,神经元的激活可以借助于截止值或阈值的概念来解释。如果上述等式的右侧产生负值,则输出被削波为零,如图 3(a)所示。

Figure 3: (a) Example of an activation function of a neuron

从另一个角度来看,如果我们将常数放在等式的另一边,我们需要输入信号的加权和高于某个阈值,以使输出非零,即被激活。

w_1x_1 + w_2x_2 + … ≤ -c →节点不活动

w_1x_1 + w_2x_2 + …> -c →节点处于活动状态

图 3(b)展示了这如何复制大脑中神经元活动的机制,在大脑中,数十亿个带电细胞通过电化学信号传输信息。

Figure 3(b): Depiction of neuronal activity in a network

请注意,我上面描述的是一个 ReLU 或整流线性单位激活函数。其他功能包括 sigmoid 和 tanh,但遵循类似的神经元激活概念。

投入和产出在实践中会是什么样的?

让我们考虑这样一个例子,目标是预测航班延误。以下过去的信息可能有助于确定特定航班的延迟,因此可以用作学习系统的输入。

  • 机场(出发和到达);
  • 航空公司;
  • 一周中的某一天;
  • 预定的出发时间;
  • 预定到达时间;
  • 天气条件:温度、风速、降雨量、降雪量等。在起飞和降落时各自机场的情况;
  • 飞行路线的天气条件;
  • 机场交通信息等等。

使用实际出发和到达时间,可以计算出输出。

出发延误=实际出发时间-计划出发时间

附加延误=到达延误-离开延误

与任何数学公式一样,在人工智能环境中设置问题时需要小心。例如,注意出发延误(=实际-计划)将是到达延误的一部分。为了使输出独立,额外的到达延迟将是更适合使用的输出。

为什么我们必须缩放数字信息?

除了清理数据的一般做法,如使单位一致或删除异常值,许多人工智能问题需要某些预处理步骤来生成有效的结果-这涉及到转换输入和输出数据。

当不同类型的数据字段同时使用时,它们都必须标准化以避免任何偏差。为了了解这意味着什么,让我们回到第一部分的等式。以我们的航班延误为例,无论我们使用摄氏度还是华氏度作为温度单位都没有关系(比如x1,但是很明显,如果直接输入这个数字,使用 25 摄氏度或相当于 77 华氏度会得到不同的结果。正如我们将在后面看到的,建立模型意味着确定该等式中的相对权重,如果处理不当,这可能会使一个输入变量的重要性超过另一个输入变量。

因此,要让它成为一个公平的竞争环境,每个输入都需要进行调整。有许多方法可以做到这一点,例如,通过将其归一化到 0 和 1 之间,或者通过将其转换为均值为零且标准偏差为 1 的标准正态分布。

我们如何对非数字信息进行编码?

任何定性或分类信息自然需要转换成数字形式,以便在上述设置中使用。例如,在我们的预测中添加的一条重要信息是每个航班的关联航空公司(假设航空公司在不考虑外部因素的情况下在准时性或效率方面存在差异)。

假设有三家航空公司 ABC 。例如,我们不能只给它们编号 1、2、3,这是因为它们之间存在差异。如果我们这样做,我们将告诉系统,与 AC(3–1 = 2)相比,航空公司 AB 是相似的实体(2–1 = 1)。它们可能实际上是相似的,但是在这种情况下,我们使用相似性的度量(例如航空公司的规模)作为一个单独的变量。

然而,在这里,我们对他们的身份进行编码,这是独一无二的,并且同样不同于所有其他人。这样做的一个正确方法是使用虚拟变量进行热编码,其中每个类别与所有其他类别相差相同的量,即两位的变化(即一个变量从 0 变到 1,另一个从 1 变到 0)。

… d1 d2 d3

答:0 0 1

乙:0 1 0

丙:1 0 0

其中 d1、d2 和 d3 是代表三家航空公司的虚拟变量。

例如,从 A 变为 B ,虚拟变量 d2d3 翻转它们的值。本质上,这些信息已经被转换成二进制格式。

如果航空公司是 A,d1 为 1,否则为 0。

如果航线是 B,则 d2 为 1,否则为 0。

如果航空公司是 C,d3 为 1,否则为 0。

另一种掌握的方式是通过观想,如图 4 所示。如果距离定义为位数的变化,那么 ABC 将形成一个每边等于两个单位的等边三角形。如果有第四个航空公司 D ,结果将是一个金字塔状的结构,像以前一样有一个三角形的底座,高度为 2/sqrt(2)。

Figure 4: Visualising the conversion of categorical information into numerical code

系统是如何学习和预测的?

简单地说,学习过程如下。

对于每个数据子集(例如,一组航班的所有信息),神经网络使用前一个数据点的权重计算其所有节点的输出(我们可以随机初始化这些值),并将其输出与实际输出进行比较(因为这是过去的数据,所以我们已经知道航班延误了多少)。然后,它会执行一种称为反向传播的操作,重新调整权重,使其输出与真实值相匹配,或者换句话说,它会解决权重的优化问题,以减少这种误差。这个过程如图 5 所示。

Figure 5: Schematic diagram of the learning process using a neural network

如果它有大量有意义的数据,它可能能够找到最能代表真实情况的网络的权重和常数(例如,在现实世界中决定航班延误的复杂的多因素系统)。为了检查这一点,将实际输出与以前尚未输入的一部分过去数据的预测输出进行比较。如果这是令人满意的,那么它可以用来预测未来的结果。

最后的想法

当在实践中应用人工智能方法时,我们对我们试图解决的问题的假设是至关重要的——没有魔杖,也没有算命的地球仪。在实际案例中,我们假设有许多因素共同对感兴趣的结果负责,但是它们相互作用的方式是复杂的,不容易辨别。因此,我们决定使用像神经网络这样的人工智能技术进行研究。然后,我们对输入做出明智的选择,测试我们的假设,并根据需要进行迭代。这不是一种被动的、不干涉的、全盘接受的方法,它需要批判性思维和积极的决策。****

这是我在业余时间进行的原创工作。请让我知道任何错误,遗漏或改进。

了解 Spark 插入功能

原文:https://towardsdatascience.com/understanding-the-spark-insertinto-function-1870175c3ee9?source=collection_archive---------4-----------------------

Photo by @marcusloke on Unsplash

使用 spark 将原始数据吸收到数据湖中是目前常用的 ETL 方法。在某些情况下,原始数据被清理、序列化并作为分析团队用来执行 SQL 类操作的配置单元表公开。因此,spark 为表的创建提供了两种选择: 托管外部 表。这两者的区别在于,与 spark 控制存储和元数据的管理表不同,在外部表上,spark 不控制数据位置,只管理元数据。

此外,通常需要一种重试策略来覆盖一些失败的分区。例如,分区 22/10/2019 的批处理作业(时间戳分区)失败,我们需要重新运行作业,写入正确的数据。因此有两种选择: a) 重新生成并覆盖所有数据,或者 b) 处理并覆盖所需分区的数据。由于性能问题,第二种方法被放弃了,想象一下,您必须处理整整一个月的数据。

因此,使用了选项 first 选项,幸运的是 spark 有选项dynamic****partitionOverwriteMode,即仅对当前批处理中存在的分区覆盖数据。当将数据写入外部数据存储时,如 HDFSS3,这个选项非常有效;的情况下,可以通过一个简单的重载外部表元数据,创建外部表命令

然而,对于存储在具有动态分区的元存储中的配置单元表,为了保持数据质量和一致性,我们需要理解一些行为。首先,即使 spark 提供了两个函数来存储表中的数据 saveAsTableinsertInto,它们之间也有一个重要的区别:

  • SaveAsTable: 创建表格结构并存储数据的第一个版本。然而,覆盖保存模式适用于所有分区,即使配置了动态。
  • insertInto: 不创建表结构,但是,当配置了动态时,覆盖保存模式只对需要的分区起作用。

因此,可以使用 SaveAsTable 从原始数据帧定义创建表,然后在创建表之后,使用 insertInto 函数以简单的方式进行覆盖。尽管如此,insertInto 在写入分区数据时表现出一些没有很好记录的行为,在处理包含模式更改的数据时也存在一些挑战。

列的顺序问题

让我们编写一个简单的单元测试,从数据帧中创建一个表。

***it* should** "Store table and insert into new record on new partitions" in {
  val spark = ss
  import spark.implicits._
  **val targetTable** = "companies_table" **val companiesDF** = *Seq*(("A", "Company1"), ("B", "Company2")).toDF("id", "company")
     companiesDF.write.mode(SaveMode.*Overwrite*).**partitionBy**("id").**saveAsTable**(targetTable)

  **val companiesHiveDF** = ss.sql(s"SELECT * FROM **$**{targetTable}")

到目前为止,该表创建正确。然后,让我们使用 insertInto 覆盖一些数据,并执行一些断言。

 **val secondCompaniesDF** = *Seq*(("C", "Company3"), ("D", "Company4"))
    .toDF("id", "company")

secondCompaniesDF.write.mode(SaveMode.*Append*).**insertInto**(targetTable) **val companiesHiveAfterInsertDF** = ss.sql(s"SELECT * FROM **$**{targetTable}")

  companiesDF.count() should equal(2)
  companiesHiveAfterInsertDF.count() should equal(4)
  companiesHiveDF.select("id").collect().map(_.get(0)) should *contain* **allOf("A", "B")**
  companiesHiveAfterInsertDF.select("id").collect() should *contain* **allOf("A", "B", "C", "D")**

}

这应该可以正常工作。但是,请看下面的数据打印:

如您所见,由于列的位置,断言失败了。原因有二: a) saveAsTable 使用分区列,并在末尾添加。 b) insertInto 使用列的顺序(就像调用 SQL insertInto 一样)而不是列名。因此,在末尾添加分区列可以解决这个问题,如下所示:

 **//partition column should be at the end to match table schema.**
  **val secondCompaniesDF** = *Seq*(("Company3", "C"), ("Company4", "D"))
    .toDF("company", **"id"**)

  secondCompaniesDF.write.mode(SaveMode.*Append*).**insertInto**(targetTable) **val companiesHiveAfterInsertDF** = ss.sql(s"SELECT * FROM **$**{targetTable}") companiesHiveAfterInsertDF.printSchema()
  companiesHiveAfterInsertDF.show(false)

  companiesDF.count() should equal(2)
  companiesHiveAfterInsertDF.count() should equal(4)
  companiesHiveDF.select("id").collect().map(_.get(0)) **should** *contain* **allOf("A", "B")**
  companiesHiveAfterInsertDF.select("id").collect().map(_.get(0)) **should** *contain* **allOf("A", "B", "C", "D")**

}

现在测试通过了,数据被正确地覆盖了。

匹配表模式

如前所述,列的顺序对于 insertInto 函数很重要。此外,假设您正在接收模式不断变化的数据,并且您收到了一批具有不同列数的新数据。

带有额外列的新批次

让我们首先测试添加更多列的情况。

**//again adding the partition column at the end and trying to overwrite partition C.**
**val thirdCompaniesDF** = *Seq*(("Company4", 10, "C"), ("Company5", 20,  "F"))
  .toDF("company", "size", "id")

thirdCompaniesDF.write.mode(**SaveMode.*Overwrite***).**insertInto**(targetTable)

尝试调用 insertInto 时,显示以下错误:

因此,需要一个返回表中缺失列的函数:

**def** **getMissingTableColumnsAgainstDataFrameSchema**(**df**: DataFrame, **tableDF**: DataFrame): Set[String] = {
  **val dfSchema** = df.schema.fields.map(v => (v.name, v.dataType)).toMap
  **val tableSchema** = tableDF.schema.fields.map(v => (v.name, v.dataType)).toMap
  **val columnsMissingInTable** = dfSchema.keys.toSet.diff(tableSchema.keys.toSet).map(x => x.concat(s" **$**{dfSchema.get(x).get.sql}"))

  **columnsMissingInTable**
}

然后,执行 SQL ALTER TABLE 命令。此后, insertInto 函数正常工作,表模式被合并,如下所示:

**val tableFlatDF** = ss.sql(s"SELECT * FROM **$**targetTable limit 1")

**val columnsMissingInTable =** DataFrameSchemaUtils.*getMissingTableColumnsAgainstDataFrameSchema*(thirdCompaniesDF, tableFlatDF)

if (columnsMissingInTable.size > 0) {
  ss.sql((s"ALTER TABLE **$**targetTable " +
    s"ADD COLUMNS (**$**{columnsMissingInTable.mkString(" , ")})"))
}

**thirdCompaniesDF**.write.mode(SaveMode.*Overwrite*).insertInto(targetTable)

**val companiesHiveAfterInsertNewSchemaDF** = ss.sql(s"SELECT * FROM **$**targetTable")

**companiesHiveAfterInsertNewSchemaDF**.printSchema()
**companiesHiveAfterInsertNewSchemaDF**.show(false)

列数更少的新批次

现在让我们测试接收到较少列的情况。

**val fourthCompaniesDF** = *Seq*("G", "H")
  .toDF("id")

fourthCompaniesDF.write.mode(SaveMode.*Overwrite*).**insertInto**(targetTable)

将显示以下错误:

因此,需要一个向数据框添加缺失列的函数:

**def mergeDataFrameSchemaAgainstTable**(**tableDF**: DataFrame)(**df**: DataFrame): DataFrame = {
  **val dfSchema** = df.schema.fields.map(v => (v.name, v.dataType)).toMap
  **val tableSchema** = tableDF.schema.fields.map(v => (v.name, v.dataType)).toMap

  **val columnMissingInDF** = tableSchema.keys.toSet.diff(dfSchema.keys.toSet).toList

  **val mergedDFWithNewColumns** = columnMissingInDF.foldLeft(df) { (currentDF, colName) =>
    currentDF.**withColumn**(
      colName,
      *lit*(null).cast(tableSchema.get(colName).get.typeName)
    )
  }

  **mergedDFWithNewColumns**
}

然后,合并的数据框被写入并正常工作,如下所示:

val **mergedFlatDF** = **fourthCompaniesDF**.transform(DataFrameSchemaUtils.***mergeDataFrameSchemaAgainstTable***(companiesHiveDF))
mergedFlatDF.write.mode(SaveMode.*Overwrite*).**insertInto**(targetTable)mergedFlatDF.printSchema()
mergedFlatDF.show(false)

结论

Spark 提供了多种功能来集成我们的数据管道和 Hive。然而,需要很好地理解它们是如何工作的,以避免在写数据时出错。具体来说,在使用动态分区时, insertInto 函数有两个应该考虑的重要特性:

  1. 分区列应该总是在末尾,以匹配配置单元表模式定义。
  2. InsertInto 使用列的顺序而不是名称。因此,您应该保证始终具有相同的列数,并保持它们相同的插入顺序。

了解企业/组织中的数据类型

原文:https://towardsdatascience.com/understanding-the-types-of-data-in-a-business-organization-67d7cb9914bd?source=collection_archive---------8-----------------------

尝试谷歌一下,你会保证找到各种来源,每一个都有自己的版本(有的说 3 种数据,有的说 5 种,有的甚至说 13 种)。我们通过总结让你更容易理解,并让你的理解进入下一个层次

B 在您开始推出您的数据管理计划之前,无论是主数据管理、企业数据仓库、大数据分析还是其他什么,您都需要首先了解最基本的要素:数据。只有彻底认识到他们的特点,你才会知道如何正确对待他们。

“数据是一种珍贵的东西,将比系统本身持续更久”

蒂姆·伯纳斯·李

所以让我们开始吧!

交易数据

这类数据描述了您的核心业务活动。如果你是一家贸易公司,这可能包括你的采购和销售活动的数据。如果你是一家制造公司,这将是你的生产活动数据。如果你是打车或出租车公司,这将是行程数据。在一个非常基本的组织运作中,与雇佣和解雇员工的活动相关的数据也可以归类为事务性数据。因此,与其他类型的数据相比,这种类型的数据具有非常大的容量,并且通常在诸如 ERP 系统的操作应用中创建、存储和维护。

主数据

它由构成事务数据的关键信息组成。例如,出租车公司的行程数据可能包含司机、乘客、路线和费用数据。司机、乘客、位置和基本票价数据是主数据。驾驶员数据可以包括驾驶员的姓名和所有相关信息。乘客数据也是如此。它们一起构成了事务数据。

主数据通常包含地点(地址、邮政编码、城市、国家)、当事人(客户、供应商、员工)和事物(产品、资产、项目等)。).它是特定于应用程序的,这意味着它的用途是特定于具有相关业务流程的应用程序的,例如:在 HR 应用程序中创建、存储和维护员工主数据。

到目前为止,您应该对主数据相对恒定有所了解。虽然交易数据是以闪电般的速度创建的,但主数据在某种程度上是恒定的。行程数据随时都会被创建,但是司机的列表将保持不变,除非车上有新的司机或者被踢出去。

如今,组织内的过程通常是相互依赖的,这意味着在一个系统中进行的过程与在另一个系统中进行的过程相关。它们可以使用相同的主数据。如果每个系统管理自己主数据,可能会出现重复和不一致的情况。例如,客户在系统 A 中可能被存储为 Rendy,但在系统 B 中被列为 Randy,尽管 Rendy 和 Randy 实际上是同一个实体。但是没必要担心,有一个规则来处理这种情况。叫做主数据管理。

参考数据

参考数据是主数据的子集。它通常是由特定编码管理的标准化数据(例如,国家列表由 ISO 3166-1 管理。有一种简单的方法来区分参考数据和主数据。永远记住,参考数据比主数据更不稳定。让我们回到我们的出租车公司。明天,后天,或者下周,每当有新人加入或者被踢出去,车手名单可能会改变。但我可以向你保证,即使 20 年后,这个国家名单也不会变,除非有一小块土地宣布独立。

报告数据

这是出于分析和报告目的的汇总数据汇编。这些数据包括交易数据、主数据和参考数据。比如:T rip 数据(交易+主)大伦敦地区 7 月 13 日(参考)。报告数据非常具有战略性,通常作为决策过程的组成部分。

[计]元数据

这是一个关于数据的数据。听起来很困惑?确实如此。这是我第一次进入数据管理领域时让我头晕目眩的数据类型。谢天谢地,这张漂亮图片让我很容易理解什么是元数据。

Data & its metadata

如果我问你一个问题:猫是什么颜色的?只要看一下数据,你马上就能自信地回答我的问题。它是灰色的。但是如果我想出另一个问题:这张照片是在何时何地拍摄的呢?你很有可能无法通过只看数据来给我正确的答案。这就是元数据的用武之地。它为您提供了有关数据的完整信息,包括数据拍摄的时间和地点。

所以元数据给了你任何问题的答案,而你仅仅通过数据是无法回答的。所以才说:关于数据的数据

这就是你需要知道的关于数据类型的全部内容。再说一次,这并不是一个令人疲惫的解释,我可以保证,仅仅通过阅读这篇文章,你还不能接受数据科学家的工作邀请。但是无论何时你在街上遇到有人问你组织中常见的数据类型,你仍然可以带着所有这些解释自信地回答。

通过 Python 示例理解时间复杂性

原文:https://towardsdatascience.com/understanding-time-complexity-with-python-examples-2bda6e8158a7?source=collection_archive---------0-----------------------

Big-O Complexity Chart: http://bigocheatsheet.com/

如今,面对我们每天消耗和生成的所有这些数据,算法必须足以处理大量数据的运算。

在这篇文章中,我们将了解更多关于时间复杂性,Big-O 符号以及为什么我们在开发算法时需要关注它。

这个故事中展示的例子是用 Python 开发的,所以如果你至少有 Python 的基础知识,会更容易理解,但这不是先决条件。

让我们开始理解什么是计算复杂性。

计算的复杂性

计算复杂性是计算机科学的一个领域,根据运行算法所需的资源量来分析算法。所需资源的数量根据输入大小而变化,因此复杂性通常表示为 n 的函数,其中 n 是输入的大小。

值得注意的是,当分析一个算法时,我们可以考虑时间复杂度和空间复杂度。空间复杂度基本上是解决与输入大小相关的问题所需的内存空间量。尽管空间复杂度在分析算法时很重要,但在这个故事中,我们将只关注时间复杂度。

时间复杂度

当你现在正在读这个故事的时候,你可能对什么是时间复杂性有一个概念,但是为了确保我们都在同一页上,让我们从维基百科的一个简短描述开始理解时间复杂性意味着什么。

在计算机科学中,时间复杂度是计算复杂度,它描述了运行一个算法所需的时间。时间复杂度通常通过计算算法执行的基本操作的数量来估计,假设每个基本操作花费固定的时间来执行。

在分析算法的时间复杂度时,我们可能会发现三种情况:最佳情况一般情况最坏情况。让我们来理解它的含义。

假设我们有下面这个未排序的列表【1,5,3,9,2,4,6,7,8】,我们需要使用线性搜索找到这个列表中某个值的索引。

  • 最佳情况:这是解决最佳输入问题的复杂度。在我们的例子中,最好的情况是搜索值 1。因为这是列表的第一个值,所以它将在第一次迭代中被找到。
  • 平均案例:这是解决问题的平均复杂度。这种复杂性是相对于输入数据中值的分布来定义的。也许这不是最好的例子,但是根据我们的例子,我们可以说,一般情况下,当我们在列表的“中间”搜索某个值时,例如,值 2。
  • 最差情况:这是解决大小为 n 的最差输入问题的复杂性。在我们的例子中,最差情况是搜索值 8,这是列表中的最后一个元素。

通常,当描述一个算法的时间复杂度时,我们谈论的是最坏的情况。

好的,但是我们如何描述算法的时间复杂度呢?

我们使用一种叫做 Big-O 的数学符号。

大 O 符号

Big-O 符号,有时也称为“渐近符号”,是一种数学符号,描述了函数在自变量趋向特定值或无穷大时的极限行为。

在计算机科学中,Big-O 符号用于根据算法的运行时间或空间需求如何随着输入大小( n )的增长而增长来对算法进行分类。这种符号根据函数的增长率来表征函数:具有相同增长率的不同函数可以用相同的 O 符号来表示。

让我们看看 Big-O 符号中描述的一些常见的时间复杂性。

常见时间复杂性表

以下是使用 Big-O 符号表示的最常见的时间复杂性:

╔══════════════════╦═════════════════╗
║       **Name**       ║ **Time Complexity** ║
╠══════════════════╬═════════════════╣
║ Constant Time    ║       O(1)      ║
╠══════════════════╬═════════════════╣
║ Logarithmic Time ║     O(log n)    ║
╠══════════════════╬═════════════════╣
║ Linear Time      ║       O(n)      ║
╠══════════════════╬═════════════════╣
║ Quasilinear Time ║    O(n log n)   ║
╠══════════════════╬═════════════════╣
║ Quadratic Time   ║      O(n^2)     ║
╠══════════════════╬═════════════════╣
║ Exponential Time ║      O(2^n)     ║
╠══════════════════╬═════════════════╣
║ Factorial Time   ║       O(n!)     ║
╚══════════════════╩═════════════════╝

请注意,我们将重点研究这些常见的时间复杂性,但还有其他一些时间复杂性,您可以稍后再研究。

正如已经说过的,我们通常使用 Big-O 符号来描述算法的时间复杂度。在符号的正式定义中涉及到很多数学,但是非正式地,我们可以假设 Big-O 符号给出了算法在最坏情况下的大概运行时间。当使用 Big-O 符号时,我们根据输入数据大小的增加来描述算法的效率( n )。例如,如果输入是一个字符串,则 n 将是该字符串的长度。如果是列表,则 n 将是列表的长度,以此类推。

现在,让我们看看这些常见的时间复杂性,并看看一些算法的例子。请注意,我试图遵循以下方法:给出一点描述,展示一个简单易懂的例子,展示一个更复杂的例子(通常来自现实世界的问题)。

时间复杂性

常数时间— O(1)

当一个算法不依赖于输入数据时,该算法被称为具有恒定时间( n )。不管输入数据的大小,运行时间总是一样的。例如:

if a > b:
    return True
else:
    return False

现在,让我们看看函数 get_first ,它返回列表的第一个元素:

def get_first(data):
    return data[0]

if __name__ == '__main__':
    data = [1, 2, 9, 8, 3, 4, 7, 6, 5]
    print(get_first(data))

不管输入数据大小如何,它总是有相同的运行时间,因为它只从列表中获取第一个值。

具有恒定时间复杂度的算法是极好的,因为我们不需要担心输入大小。

对数时间— O(log n)

当一个算法在每一步中减少输入数据的大小时(它不需要查看输入数据的所有值),该算法被认为具有对数时间复杂度,例如:

for index in range(0, len(data), 3):
    print(data[index])

具有对数时间复杂度的算法通常出现在对二叉树的运算中,或者使用二分搜索法时。让我们来看一个二分搜索法的例子,我们需要找到一个元素在一个排序列表中的位置:

def binary_search(data, value):
    n = len(data)
    left = 0
    right = n - 1
    while left <= right:
        middle = (left + right) // 2
        if value < data[middle]:
            right = middle - 1
        elif value > data[middle]:
            left = middle + 1
        else:
            return middle
    raise ValueError('Value is not in the list')

if __name__ == '__main__':
    data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    print(binary_search(data, 8))

二分搜索法的步骤:

  • 计算列表的中间。
  • 如果搜索的值低于列表中间的值,则设置一个新的右边界。
  • 如果搜索的值高于列表中间的值,则设置一个新的左边界。
  • 如果搜索值等于列表中间的值,则返回中间值(索引)。
  • 重复上述步骤,直到找到值,或者左边界等于或高于右边界。

理解必须访问其输入数据的所有元素的算法不能花费对数时间是很重要的,因为读取大小为 n 的输入所花费的时间是 n 的数量级。

线性时间— O(n)

当运行时间最多随着输入数据的大小线性增加时,算法被认为具有线性时间复杂度。当算法必须检查输入数据中的所有值时,这是可能的最佳时间复杂度。例如:

for value in data:
    print(value)

让我们来看一个线性搜索的例子,我们需要在一个未排序的列表中找到一个元素的位置:

def linear_search(data, value):
    for index in range(len(data)):
        if value == data[index]:
            return index
    raise ValueError('Value not found in the list')

if __name__ == '__main__':
    data = [1, 2, 9, 8, 3, 4, 7, 6, 5]
    print(linear_search(data, 7))

注意,在这个例子中,我们需要查看列表中的所有值,以找到我们要寻找的值。

准线性时间— O(n log n)

当输入数据中的每个操作都具有对数时间复杂度时,称算法具有准线性时间复杂度。常见于排序算法中(如 mergesorttimsortheapsort )。

例如:对于数据 1 中的每个值( O(n) )使用二分搜索法( O(log n) )在数据 2 中搜索相同的值。

for value in data1:
    result.append(binary_search(data2, value))

另一个更复杂的例子,可以在合并排序算法中找到。Mergesort 是一种高效、通用、基于比较的排序算法,具有准线性时间复杂度,让我们看一个例子:

def merge_sort(data):
    if len(data) <= 1:
        return

    mid = len(data) // 2
    left_data = data[:mid]
    right_data = data[mid:]

    merge_sort(left_data)
    merge_sort(right_data)

    left_index = 0
    right_index = 0
    data_index = 0

    while left_index < len(left_data) and right_index < len(right_data):
        if left_data[left_index] < right_data[right_index]:
            data[data_index] = left_data[left_index]
            left_index += 1
        else:
            data[data_index] = right_data[right_index]
            right_index += 1
        data_index += 1

    if left_index < len(left_data):
        del data[data_index:]
        data += left_data[left_index:]
    elif right_index < len(right_data):
        del data[data_index:]
        data += right_data[right_index:]

if __name__ == '__main__':
    data = [9, 1, 7, 6, 2, 8, 5, 3, 4, 0]
    merge_sort(data)
    print(data)

下图举例说明了 mergesort 算法所采取的步骤。

Mergesort example: https://en.wikipedia.org/wiki/Merge_sort

注意,在这个例子中,排序是就地执行的。

二次时间— O(n)

当一个算法需要对输入数据中的每个值执行线性时间运算时,该算法被称为具有二次时间复杂度,例如:

for x in data:
    for y in data:
        print(x, y)

冒泡排序是二次时间复杂度的一个很好的例子,因为对于每个值,它需要与列表中的所有其他值进行比较,让我们来看一个例子:

def bubble_sort(data):
    swapped = True
    while swapped:
        swapped = False
        for i in range(len(data)-1):
            if data[i] > data[i+1]:
                data[i], data[i+1] = data[i+1], data[i]
                swapped = True

if __name__ == '__main__':
    data = [9, 1, 7, 6, 2, 8, 5, 3, 4, 0]
    bubble_sort(data)
    print(data)

指数时间— O(2^n)

当输入数据集每增加一次,增长就加倍时,算法被认为具有指数时间复杂度。这种时间复杂度通常见于蛮力算法。

正如赖薇所举的例子:

在密码学中,强力攻击可以通过迭代子集来系统地检查密码的所有可能元素。使用指数算法来做到这一点,暴力破解长密码和短密码会变得非常耗费资源。这就是长密码被认为比短密码更安全的原因之一。

指数时间算法的另一个例子是斐波那契数的递归计算:

def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

如果你不知道什么是递归函数,那就赶紧说清楚:递归函数可能被描述为在特定条件下调用自身的函数。您可能已经注意到,递归函数的时间复杂度有点难以定义,因为它取决于函数被调用的次数和单次函数调用的时间复杂度。

当我们看递归树时更有意义。下面的递归树是使用 n = 4 通过斐波那契算法生成的:

Recursion tree of Fibonacci(4): https://visualgo.net/bn/recursion

请注意,它会呼叫自己,直到它到达树叶。当到达树叶时,它返回值本身。

现在,看看递归树是如何增长的,只是将 n 增加到 6:

Recursion tree of Fibonacci(6): https://visualgo.net/bn/recursion

你可以在 StackOverflow 的这里找到关于递归斐波那契算法时间复杂度的更完整的解释。

阶乘— O(n!)

当一个算法根据输入数据的大小以阶乘方式增长时,该算法被称为具有阶乘时间复杂度,例如:

2! = 2 x 1 = 2
3! = 3 x 2 x 1 = 6
4! = 4 x 3 x 2 x 1 = 24
5! = 5 x 4 x 3 x 2 x 1 = 120
6! = 6 x 5 x 4 x 3 x 2 x 1 = 720
7! = 7 x 6 x 5 x 4 x 3 x 2 x 1 = 5.040
8! = 8 x 7 x 6 x 5 x 4 x 3 x 2 x 1 = 40.320

正如你可以看到的,它增长非常快,即使是一个小尺寸的输入。

具有阶乘时间复杂度的算法的一个很好的例子是堆算法,它用于生成所有可能的 n 对象的排列。

维基百科:

希普发现了一种系统的方法,在每一步选择一对元素进行切换,以便恰好一次产生这些元素的每一种可能的排列。

让我们来看看这个例子:

def heap_permutation(data, n):
    if n == 1:
        print(data)
        return

    for i in range(n):
        heap_permutation(data, n - 1)
        if n % 2 == 0:
            data[i], data[n-1] = data[n-1], data[i]
        else:
            data[0], data[n-1] = data[n-1], data[0]

if __name__ == '__main__':
    data = [1, 2, 3]
    heap_permutation(data, len(data))

结果将是:

[1, 2, 3]
[2, 1, 3]
[3, 1, 2]
[1, 3, 2]
[2, 3, 1]
[3, 2, 1]

请注意,它将根据输入数据的大小以阶乘的方式增长,因此我们可以说该算法的阶乘时间复杂度为 O(n!).

另一个很好的例子是旅行推销员问题

重要注意事项

值得注意的是,当分析一个算法的时间复杂度时,我们需要根据所有操作中最大的复杂度来描述算法。例如:

def my_function(data):
    first_element = data[0]

    for value in data:
        print(value)

    for x in data:
        for y in data:
            print(x, y)

即使‘my _ function’中的操作没有意义,我们也可以看到它有多个时间复杂度:O(1) + O(n) + O(n)。因此,当增加输入数据的大小时,该算法的瓶颈将是需要 O(n)的运算。基于此,我们可以把这个算法的时间复杂度描述为 O(n)。

Big-O 备忘单

为了让您的生活更轻松,您可以在这里找到一个表格,其中列出了最常见的数据结构中操作的时间复杂度。

Common Data Structure Operations: http://bigocheatsheet.com/

这是另一张关于最常见排序算法的时间复杂度的表格。

Array Sorting Algorithms: http://bigocheatsheet.com/

为什么了解所有这些很重要?

如果在读完所有这些故事后,你仍然对了解时间复杂性和 Big-O 符号的重要性有所怀疑,让我们澄清一些观点。

即使在使用现代语言时,比如 Python,它提供了内置函数,比如排序算法,有一天你可能需要实现一个算法来对一定数量的数据执行某种操作。通过学习时间复杂性,你将理解效率的重要概念,并且能够发现你的代码中应该改进的瓶颈,主要是在处理巨大的数据集时。

除此之外,如果你打算申请谷歌、脸书、推特和亚马逊这样的大公司的软件工程师职位,你需要准备好使用 Big-O 符号回答关于时间复杂性的问题。

最终注释

感谢您阅读这个故事。我希望你已经学到了更多关于时间复杂性和 Big-O 符号的知识。如果你喜欢它,请鼓掌并分享它。如果您有任何疑问或建议,请随时评论或给我发电子邮件。另外,你也可以在 TwitterLinkedinGithub 上随时关注我。

参考

posted @ 2024-10-13 15:24  绝不原创的飞龙  阅读(297)  评论(0)    收藏  举报