TowardsDataScience 博客中文翻译 2016~2018(二百九十七)
通过食物理解机器学习的工作流程
Photo by Cel Lisboa on Unsplash
穿越美食?!
是的,没错,通过美食!:-)
想象一下,你点了一份披萨,过了一会儿,那份好吃的、热的和美味的披萨就送到了你家。
你有没有想过让这样一个比萨饼送到你家背后的工作流程?我的意思是,完整的工作流程,从播种番茄种子到骑自行车的人在你家门口嗡嗡作响!事实证明,与机器学习工作流程并无太大不同。****
真的!我们去看看吧!
这篇文章的灵感来自于谷歌首席决策科学家 Cassie Kozyrkov 在柏林举行的 Data Natives 会议上的一次演讲。
Photo by SwapnIl Dwivedi on Unsplash
1.播种
农民播下种子,这些种子会成长为我们比萨饼的配料,就像西红柿一样。
这相当于数据生成过程**,可以是用户动作,例如触发传感器的运动、热量或噪声。**
Photo by no one cares on Unsplash
2.收获
然后是收获的时候,也就是蔬菜或水果成熟的时候。
这相当于数据收集**,意味着浏览器或传感器会将用户动作或触发传感器的事件转化为实际数据。**
Photo by Matthew T Rader on Unsplash
3.运送
收获后,产品必须运输到目的地,用作我们披萨的配料。
这相当于将数据接收到一个存储库中,稍后将从那里获取数据,比如数据库或数据湖。
Photo by Nicolas Gras on Unsplash
4.选择器具和器皿
对于每一种配料**,都有最合适的器具来处理。如果需要切片,使用刀。如果需要搅拌,一把勺子。同样的道理也适用于器具:如果你需要烘烤,使用烤箱。如果需要炒,一个灶。你也可以使用更复杂的设备,如微波炉,有更多的设置选项。**
有时候,使用更简单的设备甚至会更好——你见过餐馆做广告说“微波披萨”吗?!我没有!****
在机器学习中,器具是预处理数据的技术,而器具是算法,就像线性回归或随机森林。还可以用一个微波,我是说深度学习。可用的不同选项是超参数。在简单的电器里只有几个,我是说算法。但是在一个复杂的世界里还有很多很多。此外,无法保证复杂的算法会带来更好的性能(或者你更喜欢微波披萨?!).所以,明智地选择你的算法。****
Photo by S O C I A L . C U T on Unsplash
5.选择食谱
光有食材和器具是不够的。你还需要一份食谱**,里面有你准备菜肴需要遵循的所有步骤。**
这是你的型号**。而没有,你的型号是不是跟你的算法一样。该模型包括您的算法所需的所有前置 -后置*--加工。并且,说到预处理* …**
Photo by Caroline Attwood on Unsplash
6.准备配料
我敢打赌,大多数食谱中的第一个说明是这样的:“切这个”,“削那个”等等。他们不会告诉你去洗蔬菜,因为这是理所当然的——没人想吃脏的蔬菜,对吧?
数据也是如此。没人想要脏数据。你要清理它,也就是处理缺失值和离群值**。然后你要剥和切片,我的意思是预处理,就像编码分类变量(男或女)成数值( 0 或 1 )。**
没人喜欢那部分。数据科学家和厨师都不是(我猜)。
Photo by Bonnie Kittle on Unsplash
7.特殊准备
有时候,你可以用你的配料获得创意**,以获得更好的口味或更精致的 呈现。**
你可以将牛排风干以获得不同的味道,或者将胡萝卜雕刻成玫瑰的形状,然后放在你的盘子上:-)。
这是特色工程**!这是一个重要的步骤,如果用一种巧妙的方式,可能会大大提高你的模型的性能。**
几乎每个数据科学家都喜欢这一部分。我猜厨师也喜欢它。
Photo by Clem Onojeghuo on Unsplash
8.烹饪
最基本的一步——没有真正的烹饪**,就没有菜肴。很明显。你把准备好的配料放入器具,调整热度,等一会儿再检查。**
这是你模型的训练**。您将数据输入到您的算法,调整其超参数并等待一段时间,然后再次检查。**
Photo by Icons8 team on Unsplash
9.品尝
即使你严格按照菜谱做,你也不能保证一切都是正确的。那么,你怎么知道你是否做对了呢?你尝尝吧!如果不好吃,可以多加盐尝试修复。您也可以改变温度。但是你继续做饭!
不幸的是,有时你的披萨会被烧焦,或者不管你怎么做都难以下咽。你把它扔进垃圾桶,从错误中吸取教训,重新开始。
但愿,坚持和一点点运气能做出美味** 披萨 :-)**
品鉴就是评价。你需要评估你的模型,检查它是否运行良好。如果没有,您可能需要添加更多功能。您也可以更改一个超参数。但是你要坚持训练!
不幸的是,有时你的模型不会收敛到一个解决方案,或者做出可怕的预测,不管你做什么来试图挽救它。你抛弃了你的模型,从你的错误中吸取教训,重新开始。
希望,坚持和一点点运气会产生一个高性能模型** :-)**
Photo by Kai Pilger on Unsplash
10.递送
从厨师的角度来看,他/她的工作已经完成了。他/她做了美味的比萨饼。句号。
但是如果比萨饼没有很好地送到顾客手中,及时送到顾客手中,比萨饼店就会倒闭,厨师也会失业。
比萨饼做好之后,必须立即包装好以保温,并小心地处理好,以免在送到饥饿的顾客手中时看起来湿漉漉的。如果骑车人没有到达他/她的目的地,在路上丢失了比萨饼或者把它摇得面目全非,所有的烹饪努力都是徒劳的。
交付就是部署。不是披萨,而是预测。预测就像披萨一样,必须包装**,不是装在盒子里,而是作为数据产品,这样才能送到热切的顾客手中。如果管道出现故障、中途断裂或以任何方式修改预测,所有的模型训练和评估都是徒劳的。**
就是这样!机器学习就像烹饪食物——过程中有几个人参与,需要付出很多努力**,但最后的结果却可以好吃!**
只有几个要点:
- 如果食材是坏的**,那菜就要坏了——没有菜谱能搞定 那当然,没有器具,也没有;**
- 如果你是厨师**,千万不要忘记,不送,烹饪就毫无意义,因为永远不会有人品尝你的美味;**
- 如果你是一个餐馆老板**,不要试图把电器强加给你的厨师——有时候 微波炉 并不是最好的选择——如果他/她把所有的时间花在洗碗和切片 配料上,你会得到一个非常不开心的厨师…**
我不知道你怎么样,但是我现在想要订购一个比萨饼!:-)
如果你有什么想法、评论或者问题,请在下方留言或者联系我 推特 。
了解用于移动应用程序开发的人工智能和 ML
Photo by Rock'n Roll Monkey on Unsplah
上次我发表了这篇博客,其中我解释了 AI 和 ML 的一个应用——“视觉”,还简要解释了在移动开发中使用 ML kit,这是谷歌提供的云平台,用于集成 Android 和 iOS 应用中的 ML 功能。这篇文章是那篇文章的前传,在这篇文章中,我将解释人工智能和机器学习的基础知识。我将阐明什么是不同类型的机器学习,以及当我们看到谷歌照片应用程序检测我们的面部时,或者当 Gmail 建议我们用完整的句子作为回复时,这一切是如何发生的。
AI vs ML
人工智能和 ML 是计算机科学的一个分支,一个单独的博客无法对这些主题做出公正的评价,我也不自称是这些领域的专家,但是为了我们在移动应用程序中开始使用 ML 的目标,我们必须对这些术语有一些基本的理解。
人工智能被定义为——机器或计算机对人类行为的模仿。人工智能研究的是科学的一个分支,其目标是使机器或计算机表现出与人类同等水平的智力、聪明、表达能力和艺术特征。人工智能的水平和应用各不相同。现在,例如,如果有一个假设的人形机器人可以洗碗、洗车和做饭,我们将把它称为人工智能的产品,但也将是一个能够理解语音并识别语音语气是愤怒、羡慕还是高兴的软件。人工智能是巨大的,涉及许多方面——有帮助收集、分类和处理数据的数据科学,有帮助理解和应用智能特征的算法,还有机器学习。ML 是人工智能的一部分,它实现了学习和训练能够做出决策的程序的目标。这些程序被输入了大量的数据,使用算法来处理这些数据,并根据这些数据进行训练,这样当它得到一个新的输入时,它就能够做出决定。
Cat or Dog — Using neural network for vision
人工智能在最近几年变得越来越热门,但它不是新概念,自 70 年代以来就一直存在。但直到现在,由于高处理能力、硬件和所需的大量数据的可用性,它才变得切实可行地用于解决问题。为了训练模型并给出可靠的输出,ML 需要处理的数据项不是几千而是几百万。
ML 解释道
ML 可以分为三种方式:
- 监督学习——我们向 ML 算法输入大量数据,这些数据被标记,即标有结果。该数据具有附在条目上的段或标签。在这种类型的学习中,我们教系统如何根据我们已经输入的数据来识别新的输入。
- 无监督学习——数据没有被标记或分类。在这种情况下,系统不知道成功或失败终点,因为它没有任何可用的指导。在这种情况下,系统会尝试对可用数据进行分类,并用给定的信息创建模式,并存储这些模式。现在,当一个新的输入到达时,它会尝试将输入与存储的模式进行匹配,并将选择的模式分配给它。
- 强化学习——这是一种无监督学习。在这种学习中,输入数据也没有标记。当获得成功时,它被反馈给系统以指示推断成功。这改善了未来的结果。
理解 ML 需要我们经历以下术语:
- 数据
- 模型
- 培养
- 决定
- 经验
ML 程序被输入大量的数据训练它。从训练中,它学习问题的规则,并积累经验。有了经验,当新问题出现时,它就有能力做出决定。此外,在处理新的数据和问题陈述时,它使适应新的情况。所以和人类一样,它“边工作边学习”。例如,如果我们必须使用机器学习来创建一个国际象棋解算器,我们将不会编写大量的 if/else 来对每一步做出决定,而是我们将为 ML 程序提供一些非常基本的规则以及大量以前的国际象棋游戏数据。有了这些数据,它将学习并最终能够决定下一步该做什么。
创建“模型”
创建和训练模型是创建您的 ML 系统的非常重要的部分。模型是预处理数据和选定算法的集合,这些算法对数据进行处理以推断输出。创建模型是一个复杂的过程,本质上是迭代的。对于我们的用例,我们从一些基本规则和选择的算法开始,并开始向我们的系统提供大量的使用数据。这些数据是我们以前在系统中收集的条目。例如,在银行欺诈检测系统的情况下,数据将是所有用户的信用和借记交易的历史。使用这些数据,我们首先创建不同的“候选模型”,然后在新的数据集上使用和尝试这些模型,并观察它们的性能。在成功率的基础上,选择和部署最佳的模型来提供新的用例。有了新的输入数据,选定的模型做出决策,并在此过程中收集更多的经验,使自己适应不断扩展的用例。
Training and using ML model
Creating ML model — iterative nature of the process
ML 的应用
- 图像处理——这是最典型的 ML 用例。在这个 ML 中,算法被用于检测给定图像中的各种对象。这属于“监督学习”,其中 ML 系统被输入大量包含不同对象的标记图像。因此,ML 模型被训练来识别对象。谷歌助手和谷歌照片就是很好的例子。AWS Rekognition 和 Firebase ML kit 为此功能提供了 API。
- 自然语言处理和语音识别——自然语言处理和语音识别是 ML 的另一个非常著名且不断发展的用例。检测书面文本并推断其脚本和含义是非常有用的。有各种解决方案可用于集成这一点,包括 Google Cloud ML 和 AWS 的不同产品——Amazon transcripte、Translate 和 Lex。
- 诊断学——医学诊断学是人工智能和人工智能领域的一个衍生因素。医疗部门和人工智能科学家开发了一些系统,可以使用细胞视觉和包括病历在内的其他数据来检测癌症和其他疾病的可能性。
- 预测—使用历史数据 ML 模型可以推断未来事件,如商业欺诈检测、客户行为预测或自然事件预测。
First painting created by an AI program
如何在应用中使用人工智能/人工智能——何去何从
有几个方向可供选择,这取决于开发人员想要多少功能、灵活性,以及他们的用例有多具体。我们可以从谷歌云或 AWS 平台的现成、完全成熟的人工智能产品中进行选择,也可以部署我们自己的定制模型。
ML 框架
- TensorFlow/Keras 模型——Tensor Flow 是谷歌的开源机器学习框架。张量流是一个通用的 ML 框架,涵盖了广泛的用例。这是最广泛用于开发和部署 ML 模型。Keras 是一个高级 Python API,用于构建和训练深度学习模型。它是独立开发的,但在谷歌收购后,现在是张量流的一部分。
- 来自脸书的 PyTorch 这个来自脸书的库是基于 Python 的深度学习库。这主要用于像自然语言处理这样的应用。这也是开源的。PyTorch 的主要优势在于它利用 GPU 的能力来解决复杂的数学问题。它被深度学习研究人员用作首选库。它可以说是早期著名的 Python 数学库的高级版本,是 numPy,但它更好更快,因为它使用了 GPU。
- Google Cloud ML/Cloud Vision——Google Cloud Vision 框架是 Google ML 产品的一部分,专门处理计算机视觉或“图像分析”。在这种情况下,有几种功能可用于图像分析,如文本检测、人脸检测、内容调节等。
Google Cloud Vision home
Cloud vision API demo
- Firebase ML kit with tensor flow Lite—Firebase ML kit 是 Cloud Vision API 的新成员,主要面向移动开发者。ML 工具包提供易于使用的云 API 的图像处理,如文本检测,人脸检测,条形码扫描,对象检测和标志检测。它提供了在设备上或云处理的选项。
- AWS 套件——AWS 还提供了大量现成的 ML 特性。这些功能包括图像分析(AWS Rekognition)、语音转文本(AWS Transcribe)、翻译(AWS Translate)、聊天机器人(AWS Lex)、文本转语音(AWS Polly)和许多其他功能。在这些 AWS 中,Rekognition 涵盖了与图像分析相关的最广泛的使用案例,如文本和对象识别、人脸检测和识别等。
AWS rekognition
- OpenCV —这是迄今为止最著名的计算机视觉和机器学习库,它非常强大,易于使用,并且是开源的。它适用于包括 Android 在内的不同平台。这个库非常容易使用,开发人员正在使用它来制作非常酷的计算机视觉相关应用程序,如检测人脸或特定对象,并在此基础上做出决定。
- kag gel——对于人工智能开发人员来说,这是一个非常有用的地方,可以为他们的特定用例获取数据集/模型。拥有超过 10,000 个数据集,以满足不同的需求和领域。例如,如果你想创建一个实时微笑检测器,你会想检查一个检测到的脸是否在微笑。您需要一个成熟的数据集来创建和准备您的模型。你会从卡格尔那里得到这个。Kaggle 于 2017 年被谷歌收购。
Kaggle datasets (www.kaggle.com)
TL;灾难恢复—如果您的需求属于图像分析、文本或识别或视频分析等一般使用情形,那么您可以使用 AWS 或 Google Cloud 提供的现成解决方案。如果您需要对现有模型进行一些调整,或者您想要部署现有模型,您可以使用 TensorFlow/Keras,如果您想要用自己的定制解决方案解决一个新问题,您可以使用 PyTorch 或 TF 创建和训练您的模型,并使用任何云解决方案部署它。Kaggel 是一个非常好的存储库,可以存储大量用例的数据。
了解和优化 gan(回到基本原则)
Fig 1. Improvement of fake image generation of faces over training using basic GAN algorithm
自从 Ian Goodfellow 首次提出生成性对抗网络(GANs)架构以来,围绕该架构的宣传一直在增长,并且大量的进步和应用每天都变得越来越令人着迷。但是对于任何想开始使用 GANs 的人来说,想知道从哪里开始是相当棘手的。不要惊慌。这篇文章将指导你。
和许多事情一样,完全理解一个概念的最好方法是触及根本。抓住首要原则。对于甘斯来说,这里是原文->(arxiv.org/abs/1406.26…)。要理解这类论文,有两种方法,理论的和实践的。我通常更喜欢后者,但如果你喜欢深入研究数学,这里的是我的好友 Sameera 的一篇很棒的帖子,从理论上分解了整个算法。与此同时,本帖将使用 Keras 以最纯粹的形式呈现该算法的简单实现。让我们开始吧。
在 GAN 的基础设置中有两个模型,即生成器和鉴别器,其中生成器不断地与鉴别器竞争,鉴别器是正在学习区分模型分布(例如生成的假图像)和数据分布(例如真实图像)的对手。这个概念被一个伪造者对警察的场景形象化了,在这个场景中,生成模型被认为是伪造者生成假币,而鉴别模型被认为是警察试图检测假币。这个想法是,随着彼此之间的不断竞争,伪造者和警察都在彼此的角色中改进,但最终伪造者达到了生产与真钞难以区分的假钞的阶段。简单。现在让我们把它写成代码。
本文提供的示例脚本用于生成虚假的人脸图像。我们试图用该算法实现的最终结果如图 1 所示。
建立发电机模型
因此,发电机模型应该吸收一些噪声,并输出一个令人满意的图像。这里我们使用 Keras 序列模型以及密集和批量标准化层。使用的激活函数是 Leaky Relu。请参考下面的代码片段。发电机模型可以分为几个模块。由密集层->活化->批量归一化组成的一个块。添加了三个这样的块,最后一个块将像素转换成我们期望输出的图像的形状。该模型的输入将是形状为(100)的噪声向量,并且该模型在最后被返回。注意每个密集层中的节点是如何随着模型的进展而增加的。
建立鉴别器模型
鉴别器接收一个图像输入,将其展平并通过两个密集->激活模块,最终输出一个介于 1 和 0 之间的标量。输出 1 应该表示输入图像是真实的,否则为 0。就这么简单。参考下面的代码。
注意:- 你可以在以后修改这些模型,增加更多的模块,更多的批量标准层,不同的激活等等。根据这个例子,这些模型足以理解 GANs 背后的概念。
发现损失并训练
我们计算三个损失,在本例中全部使用二元交叉熵来训练两个模型。
首先是鉴别器。它被训练成两种方式,如下面的代码所示。首先为真实图像(数组“img”)输出 1,然后为生成的图像(数组“gen_img”)输出 0。随着训练的进行,鉴别器在这项任务上有所提高。但是我们的最终目标在理论上达到了,此时鉴别器对两种类型的输入都输出 0.5(即,不确定是假还是真)。
接下来是训练发电机,这是一个棘手的问题。为了做到这一点,我们首先公式化一个给定发电机输出的鉴别器的组合模型。记住!理想情况下,我们希望这个值为 1,这意味着鉴别器将生成的假图像识别为真实图像。所以我们针对 1 训练组合模型的输出。参见下面的代码。
现在我们来玩吧!这是代码的要点,可以简单地理解 GANs 的工作方式。
完整代码可以在我的 GitHub 上 这里 找到。您可以参考所有用于导入 RGB 图像、初始化模型并将结果记录在代码中的附加代码。还要注意,在训练期间,小批量被设置为 Hi32 图像,以便能够在 CPU 上运行。 此外,示例中使用的真实图像是来自 CelebA 数据集的 5000 幅图像。这是一个开源的数据集,我已经把它上传到我的 Floydhub 上以便于下载,你可以在这里找到。***
有许多方法可以优化代码以获得更好的结果,并了解算法的不同组件如何影响结果的效率。观察结果,同时调整不同的组件,如优化器,激活器,规格化,损失计算器,超参数等,是增强你对算法理解的最好方法。我选择改变优化。
因此,我以 32 个为一批,训练了 5000 个纪元,用三种优化算法进行了测试。使用 Keras,这个过程就像导入和替换优化器函数的名称一样简单。所有 Keras 内置的优化器都可以在这里找到。 还绘制了每种情况下的损失,以了解模型的行为。
- 使用 SGD(随机梯度下降优化器)。输出和损耗变化分别如图 2 和图 3 所示。
Fig 2. Output of the GAN using SGD as the optimizer
Fig 3. Plot showing the variation of losses while training the GAN using SGD
注释——虽然收敛有噪声,但我们可以看到,发生器损耗随着时间的推移而下降,这意味着鉴别器倾向于将假图像检测为真图像。
2.使用 RMSProp 优化器。输出和损耗变化分别如图 4 和图 5 所示。
Fig 4. Output of the GAN using RMSProp as the optimizer
损失:
Fig 5. Plot showing the variation of losses while training the GAN using RMSProp
注释—这里我们还可以看到发电机损耗在下降,这是一件好事。令人惊讶的是,真实图像上的鉴别器损耗增加了,这非常有趣。
3.使用亚当优化器。输出和损耗变化分别如图 6 和图 7 所示。
Fig 6. Output of the GAN using Adam as the optimizer
Fig 7. Plot showing the variation of losses while training the GAN using Adam
注释 adam 优化器产生了迄今为止最好的结果。请注意鉴别器对假图像的损失如何保持较大的值,这意味着鉴别器倾向于将假图像检测为真图像。
评论
我希望这篇文章从实用的角度传达了对 GANs 内部工作的基本看法,以理解和了解如何改进基本模型。在不同的应用程序上,开源社区中有许多 GANs 的实现,对基本原则有一个良好的理解将极大地帮助你理解这些进步。此外,GANs 对于深度学习来说相对较新,有许多研究途径对任何感兴趣的人开放。
所以你可以探索无限的可能性!
了解和可视化 DenseNets
这篇文章可以在 PDF 这里下载。
这是关于 CNN 架构的系列教程的一部分。
主要目的是深入了解 DenseNet,并深入研究针对 ImageNet 数据集的 DenseNet-121。
- 对于适用于 CIFAR10 的 DenseNets,这里还有另外一个教程。
索引
- 背景
- 动机
- DenseNets 解决什么问题?
- 体系结构
- 摘要
背景
密集连接的卷积网络[1],DenseNets,是继续增加深度卷积网络的下一步。
我们已经看到我们是如何从 5 层的 LeNet 发展到 19 层的 VGG 和超过 100 层甚至 1000 层的 ResNets。
动机
当 CNN 更深入时,问题就出现了。这是因为 路径 对于从输入层直到输出层的信息(对于反方向的渐变) 变得如此之大 ,以至于它们可以在到达另一边之前 消失 。
DenseNets 简化了其他架构中引入的层之间的连接模式:
- 高速公路网[2]
- 剩余网络[3]
- 分形网络[4]
作者解决了确保最大信息(和梯度)流的问题。为此,他们只需将每一层直接相互连接。
DenseNets 没有从极深或极宽的架构中汲取代表力量,而是通过功能重用来挖掘网络的潜力。
DenseNets 解决什么问题?
反直觉地,通过这种方式连接,densentes比等效的传统 CNN 需要更少的参数 ,因为不需要学习冗余的特征映射 。
此外,ResNets 的一些变体已经证明许多层几乎不起作用,并且可以被丢弃。事实上,ResNets 的参数数量很大,因为每一层都有其要学习的权重。相反, DenseNets 图层很窄 (例如 12 个滤镜),它们只是 增加了一小组新的特征贴图 。
非常深的网络的另一个问题是训练的问题,因为提到了信息流和梯度。DenseNets 解决了这个问题,因为 每一层都可以从损失函数 和原始输入图像直接访问梯度。
结构
Figure 1. DenseNet with 5 layers with expansion of 4. [1]
传统的前馈神经网络在应用操作 的 组合后,将该层的输出连接到下一层。
我们已经看到,通常这个组合包括一个卷积运算或池层、一个批处理规范化和一个激活函数。
这个等式是:
ResNets 扩展了这种行为,包括跳过连接,将该等式重新表述为:
DenseNets 与 ResNets 的第一个区别就在这里。 DenseNets 不将该层的输出特征图与输入特征图相加,而是将它们连接起来。
因此,该等式再次变形为:
我们在 ResNets 上的工作面临着同样的问题,当它们的尺寸不同时,这种特征地图的分组就不能完成。不管分组是相加还是串联。因此,和我们用于 ResNets 的方法一样,DenseNets 被分成 DenseBlocks,其中特征映射的尺寸在一个块内保持不变,但是过滤器的数量在它们之间变化。它们之间的这些层被称为 过渡层 ,并负责应用批量归一化、1x1 卷积和 2x2 合并层的下采样。
现在我们可以开始讨论增长率了。由于我们正在连接特征图,该信道维度在每一层都在增加。如果我们使 H_l 每次产生 k 个特征图,那么我们可以对第 l 层进行推广:
这个超参数 k 就是增长率。增长率决定了每层网络中增加的信息量。为什么
我们可以把特征图看作是网络的信息。 每一层都可以访问其前面的特征图 ,因此,对 集合知识 。然后,每一层都向这一集体知识添加新的信息,具体表现为信息的 k 特征图
DenseNets-B
DenseNets-B 只是常规 DenseNets,它利用 1x1 卷积来减少 3x3 卷积之前的特征映射大小,并提高计算效率。B 出现在瓶颈层之后,你已经熟悉这个名字了,来自ResNets的工作。
丹麦-公元前
DenseNets-C 是 DenseNets-B 的另一个小增量步骤,用于我们想要 减少输出特征映射 的情况。 ***压缩因子(θ)**决定了这个减少量。我们将拥有 thetam,而不是某一层的 m 个特征地图。当然,在范围[0–1]内。所以当θ= 1时,DenseNets 将保持不变,否则将是 DenseNets-B。
为了与resnet 上的工作保持一致,我们将详细讨论 ImageNet 数据集上的案例。然而,CIFAR-10 或 SVHN 的结构更简单,因为输入量更小。
Figure 2. Sizes of outputs and convolutional kernels for different DenseNets [1] architectures on ImageNet.
正如您从之前关于其他体系结构的工作中了解到的,我更喜欢观察模型中的卷实际上是如何改变其大小的。这种方式更容易理解特定模型的机制,能够根据我们的特定需求对其进行调整。我将尝试遵循接近于 PyTorch 官方实现的符号,以便于稍后在 PyTorch 上实现它。
密集和过渡块
然而,由于 DenseNets 上的高密度连接,可视化变得比 VGG 和雷斯内特更复杂一些。图 3 显示了 DenseNet-121 架构的一个非常简单的方案,这将是我们在这项工作中重点关注的 DenseNet。这是因为它是在 ImageNet 数据集上设计的最简单的 DenseNet。
我们可以在 DenseNet-121 上比较图 3 和图 2。每个体积下的尺寸代表宽度和深度的大小,而顶部的数字代表特征地图的尺寸。我介绍了它们是如何派生出来的,以帮助我们更好地理解即将到来的步骤。
Figure 3. Another look at Dense-121. Dx: Dense Block x. Tx: Transition Block x.
您可能想知道整个 DenseNet 的旁路连接在哪里,您问对了!然而,我只是想先画一个最简单的方案,以便更深入地了解 DenseNet 的整个结构。但是出于好奇,您可以注意到计算每个新卷的特征映射的加法的第一个数字是如何与前一卷的特征映射维度相匹配的。这将解释旁路连接,因为它确切地意味着我们正在将串联(串联意味着添加维度,但不是添加值!)新信息到上一卷,也就是被重用的。
请注意, 32 正是我们在本节开始时提到的增长率。那么,从上图我们能得到什么呢?
—每个密集块之后的体积增加了增长率乘以该密集块内的密集层数
在图 4 中,我们现在更深入地了解了每个块中实际发生的事情。
Figure 4. One level deeper look at DenseNet-121. Dense Block and Transition Block. DLx: Dense Layer x
致密层
现在,我们可以理解上面的说法了。每一层都在前一卷的基础上增加了 32 张新的特征地图。这就是我们在 6 层之后从 64 到 256 的原因。此外,过渡块执行 128 个滤波器的 1x1 卷积。随后是步长为 2 的 2×2 池,导致将体积的大小和特征图的数量对半分割。我们可以从这种模式观察中得出新的结论。
—致密块内的体积保持不变—
—在每个过渡块之后,体积和特征图减半—
不过,我们还可以再深入一层!我们需要了解每个密集块中的每个密集层内部发生了什么,因为这还不是小事。让我们一起去看全图吧!
Figure 5. 2 level deep. Full schematic representation of ResNet-121
在表示第一个密集块中的第一个密集层的新的更深层次中,我们可以看到添加 32 倍层数的行为实际上是如何实现的。我们执行作者建议的 128 个滤波器的 1×1 卷积,以减小*特征图的大小,并执行更昂贵的 3×3 卷积(记得包括填充以确保尺寸保持不变),具有选择的 32 个增长率特征图。
然后,在向网络的公共知识添加新信息的动作中,输入量和两个操作的结果(对于每个密集块内的每个密集层是相同的)被连接。
引用的作品
[1] G .黄,z .刘,l .范德马腾,“密集连接卷积网络”,2018 .
[2] R. Kumar,K. Gredd 和 J. Schmidhuber,“高速公路网络”,2015 年。
[3]何国光,张,任,孙健,“深度残差学习在图像识别中的应用”,2015 .
[4] G. Larsson,M. Maire 和 G. Shakhnarovich,“FractalNet:无残差的超深度神经网络”,2017 年。
理解和可视化资源
这篇文章可以在 PDF 这里下载。
这是关于 CNN 架构的系列教程的一部分。
主要目的是深入了解 ResNet,并深入研究 ResNet34 for ImageNet 数据集。
- 对于应用于 CIFAR10 的 ResNets,这里还有另外一个教程。
- 还有 PyTorch 实现详细教程这里。
索引
- 背景
- 动机
- ResNets 解决什么问题?
- 体系结构
- 摘要
背景
研究人员观察到,当涉及到卷积神经网络时,肯定“*越深越好”*是有意义的。这是有意义的,因为模型应该更有能力(它们适应任何空间增加的灵活性,因为它们有更大的参数空间来探索)。然而,已经注意到,在一定深度之后,性能会下降。
这是 VGG 的瓶颈之一。他们不能达到预期的深度,因为他们开始失去归纳能力。
动机
由于神经网络是良好的函数逼近器,它们应该能够容易地求解识别函数,其中函数的输出成为输入本身。
按照同样的逻辑,如果我们绕过模型第一层的输入,作为模型最后一层的输出,网络应该能够预测它之前学习的函数和添加的输入。
直觉告诉我们,学习 f(x) = 0 对网络来说一定很容易。
ResNets 解决什么问题?
ResNets 解决的问题之一就是著名的已知 消失渐变 。这是因为当网络太深时,在链规则的几次应用之后,计算损失函数的梯度容易收缩到零。这导致权重永远不会更新其值,因此没有学习被执行。
有了 ResNets,渐变可以直接通过跳过连接从后面的层向后流到初始过滤器。
体系结构
Figure 1. ResNet 34 from original paper [1]
由于 ResNet 可以具有可变的大小,这取决于模型的每一层有多大,以及它有多少层,我们将遵循作者在论文[1] — ResNet 34 中描述的,以便解释这些网络之后的结构。
如果你看了一下这篇论文,你可能会看到一些如下的图表,你很难理解。让我们通过研究每一步的细节来描绘这些数字。
在这里,我们可以看到 ResNet(右边的那个)由一个卷积和合并步骤(在 orange 上)组成,后面是 4 层类似的行为。
每一层都遵循相同的模式。它们分别与固定的特征映射维度(F) [64,128,256,512]执行 3×3 卷积,每两次卷积绕过输入。此外,宽度(W)和高度(H)尺寸在整个层中保持不变。
虚线在那里,正是因为输入体积的维度发生了变化(当然是因为卷积而减少)。注意,层与层之间的这种减少是通过在每层的第一个回旋处将步幅从 1 增加到 2 来实现的;而不是像我们习惯看到的下采样器那样通过汇集操作。
在该表中,总结了每一层的输出大小以及该结构中每一点的卷积核的维数。
Figure 2. Sizes of outputs and convolutional kernels for ResNet 34
但这是不可见的。我们想要图像!一张图片胜过千言万语!
图 3 是我更喜欢看到卷积模型的方式,从这里我将解释每一层。
我更喜欢观察通过模型的体积是如何改变它们的大小的。这种方式更容易理解特定模型的机制,能够根据我们的特定需求进行调整——我们将看到仅仅改变数据集如何迫使改变整个模型的架构。此外,我将尝试遵循接近于 PyTorch 官方实现的符号,以便稍后在 PyTorch 上实现它时更容易。
例如,论文中的 ResNet 主要针对 ImageNet 数据集进行解释。但是我第一次想用 ResNets 的集合做实验时,我不得不在 CIFAR10 上做。显然,由于 CIFAR10 输入图像是(32x32)而不是(224x224),因此需要修改 ResNets 的结构。如果您想控制应用到您的 ResNet 的修改,您需要了解细节。这另一个教程是当前应用于 CIFAR10 的一个简化版。
所以,我们一层一层来!
Figure 3. Another look at ResNet 34
卷积 1
在进入公共层行为之前,ResNet 上的第一步是一个块(此处称为 Conv1 ),由卷积+批处理规范化+最大池操作组成。
如果你不记得卷积和池操作是如何执行的,快速看一下我画的这个图来解释它们,因为我在这里重用了它们的一部分。
首先有一个卷积运算。在图 1 中,我们可以看到他们使用的内核大小为 7,特征映射大小为 64。您需要推断它们在每个维度上用零填充了 3 次——并在 PyTorch 文档中进行检查。考虑到这一点,从图 4 中可以看出,该操作的输出大小将是一个(112x122)卷。由于(64 个中的)每个卷积滤波器在输出音量中提供一个通道,因此我们最终得到(112x112x64)的输出音量——注意,为了简化说明,这不包括批次维度。
Figure 4. Conv1 — Convolution
下一步是批处理规范化,这是一个基于元素的操作,因此不会改变卷的大小。最后,我们有一个跨度为 2 的(3x3)最大池操作。我们还可以推断,他们首先填充输入体积,因此最终体积具有所需的尺寸。
Figure 5. Conv1 — Max Pooling
ResNet 层
所以,我们来解释一下这个重复的名字,block。一个 ResNet 的每一层都由几个块组成。这是因为当 ResNets 更深入时,它们通常通过增加块内的操作数量来实现,但总层数保持不变,即 4 层。 这里的运算是指对一个输入进行卷积、批量归一化和 ReLU 激活,除了最后一个没有 ReLU 的块的运算。
因此,在 PyTorch 实现中,他们区分包含 2 个操作的块基本块和包含 3 个操作的块瓶颈块。注意,通常这些操作中的每一个都被称为层,但是我们已经为一组块使用了层。
我们现在面临一个基本问题。输入音量是 Conv1 的最后一个输出音量。让我们看看图 6,看看这个模块内部发生了什么。
第一区
1 卷积
我们正在复制纸上每一层的简化操作。
Figure 6. Layer 1, block 1, operation 1
我们现在可以仔细检查我们使用的[3x3,64]内核和输出大小为[56x56]的论文中的表格。我们可以看到,正如我们前面提到的,在一个数据块中,卷的大小是如何保持不变的。这是因为使用了填充= 1,并且跨距也是 1。让我们看看这如何扩展到整个块,以覆盖表中出现的 2 [3x3,64]。
Figure 7. Layer 1, block 1
相同的过程可以扩展到整个层,如图 8 所示。现在, 我们可以完整的读取 表格的整个单元格了(只是重述一下我们在 Conv2_x 层的 34 层 ResNet 中。
我们可以看到如何在层 中使用***【3x 3,64】x 3 次。***
Figure 8. Layer 1
模式
下一步是从整个块升级到整个层。在图 1 中,我们可以看到这些层是如何通过颜色区分的。但是,如果我们观察每一层的第一个操作,我们会发现第一层使用的步幅是 2,而不是其他层使用的 1。
这意味着通过网络的音量的 下采样是通过增加步幅来实现的,而不是像通常的 CNN 那样的汇集操作 。事实上,在我们的 Conv1 层中只执行了一次最大池化操作,在 ResNet 的末尾,就在图 1 中完全连接的密集层之前,执行了一次平均池化操作。
我们还可以看到 ResNet 层上的另一个重复图案,点层代表维度的变化。这和我们刚才说的一致。每一层的第一个操作是减少维度,因此我们还需要调整通过跳过连接的卷的大小,这样我们就可以像图 7 中那样添加它们。
这种跳过连接上的差异在文中被称为 恒等式快捷方式 和 投影快捷方式 。恒等快捷方式是我们已经讨论过的,简单地绕过加法运算符的输入量。投影快捷方式执行卷积运算,以确保此加法运算中的体积大小相同。从纸上我们可以看到 匹配 输出尺寸有两种选择。或者 填充输入音量 或者执行 1x1 卷积 。这里显示了第二个选项。
Figure 9. Layer2, Block 1, operation 1
图 9 显示了通过将跨距增加到 2 来执行的下采样。滤波器的数量被加倍,以试图保持每个操作的时间复杂度( 5664 = 28128 )。另外,请注意,由于卷被修改,现在无法执行添加操作。在捷径中,我们需要应用一种下采样策略。1x1 卷积方法如图 10 所示。
Figure 10. Projection Shortcut
最终的图片如图 11 所示,其中每个线程的 2 个输出卷大小相同,可以相加。
Figure 11. Layer 2, Block 1
在图 12 中,我们可以看到整个第二层的全局情况。下面的第 3 层和第 4 层的行为完全相同,只是改变了引入体积的尺寸。
Figure 12.Layer 2
摘要
遵循作者建立的解释规则的结果产生了如图 2 所示的以下结构:
Table 1. ResNets architectures for ImageNet
文献学
[1]何国光,张,任,孙,“深度残差学习在图像识别中的应用”,,,2016。
理解和可视化 SE-net
这篇文章可以在 PDF 这里下载。
这是 CNN 架构系列文章的一部分。
主要目的是提供理解 SE-Nets 的洞察力。
指数
(1)有哪些创新点?
- 新数据块与新网络
- 解决什么问题?
- 什么是 SE 块?
(2)结构
- 转换
- 挤压
- 激发,兴奋
- 缩放比例
(3)SE 模块的应用
(4)结果和结论
(5)全球图景
有哪些创新?
新块而不是新网络
首先,本文作者并没有试图通过开发一种新颖的 CNN 架构来提高经典计算机视觉竞赛的艺术水平。然而,非常有趣的是,作者创建了一个可以与现有模型一起使用的模块来增强它们的性能。
这个新的模块在完成两个主要操作后被命名为 SE 模块:挤压和激励
动机——这些积木解决了什么问题?
作者声称卷积的输出导致与滤波器捕获的空间相关性纠缠的信道依赖性。哇,这听起来太疯狂了!但是不要担心,在一些想象之后,这变得非常简单。
那么作者想用这些积木做什么来解决这个问题呢?
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
他们的目标是通过利用选通网络对通道相互依赖性进行显式建模来提高网络的灵敏度,选通网络出现在 se 模块中
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
那么什么是 SE 块呢?
简而言之,SE 模块是通道关系中的轻量级门控机制。
简而言之,网络现在能够学习如何理解在卷积运算【1】之后提取的所有特征图的堆栈中的每个特征图的重要性,并且在将卷传递到下一层之前重新校准该输出以反映该重要性。
所有这些都将在结构部分详细介绍,所以如果您现在没有看到某些内容,也不必担心!
但是等一下,为了学习,我们需要更多的参数,对吗?
没错。门控机制或门控网络只不过是完全连接的层。这种技术在注意机制中被大量使用。我强烈推荐这篇文章来更好地理解注意力机制和门控网络。
结构
让我们首先来看看图 1 中的图。我们可以称这个图为简化图,因为我们总是想要更多的细节!
Figure 1. The SE Block from the paper.
它显示了所提供的插图,我在上面分离了它的三个主要部分。重要的是要看到,挤压和激励步骤只发生在中间模块,而第一个和最后一个模块执行不同的操作。
在一次展示详细的图片之前,让我们一部分一部分地阐述它。
1 —转换
该转换简单地对应于将要实现 SE 模块的网络在其自然方案中执行的操作。例如,如果你在一个 ResNet 内的一个块中, F tr 项将对应于整个残差块的处理(卷积、批量归一化、ReLU…)。因此:
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
SE 块应用于变换操作的输出体,通过校准提取的特征来丰富它。
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
因此,如果 ResNet 在某个点将输出卷 X,则 SE 块丰富它包含的信息,并传递到下一层,成为 X`。(不能包含上面带~的 X)。
为了简化可视化,让我们假设变换是一个简单的卷积运算。我们已经在之前的文章中描述了卷积运算,但是,让我们试着稍微详细一点,以便更好地理解接下来会发生什么。
我之所以声称这第一步很重要,是因为作者构建 se 块的动机就在于此。
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
对于常规卷积层,是一组滤波器**被学习来表达沿着输入通道的局部空间连通性模式* X 因此卷积滤波器是局部感受域 内的 通道方式信息的组合。*
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
如果我们看一下对应于图 2 的符号,我们有:
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
他们所说的 局部感受野 恰恰是每个通道 2 的空间**Vc,s 在每个过滤器c .
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
为什么信息是渠道方面的?
嗯,请注意滤波器 V 1 的标记 V 1,s 将仅在输入音量 X s 的通道 s 上卷积。
Figure 2. Step1: Transformation
我们也可以按通道来表示卷积运算,以进行双重检查:
在体积 X 中卷积 1 个单个滤波器 Vc 的结果在单个特征图上, U c:
换句话说,一个滤波器在体积 X 上的卷积是输入体积 X s 的每个通道与其在滤波器 V c,s 中的对应通道的所有通道卷积的总和
2 —挤压
挤压步骤可能是最简单的一步。它基本上在每个通道上执行平均汇集,以创建一个 1x1 压缩的卷 U 表示。****
Figure 3. Squeezing
3 —激发
这是 SE 模块整个成功的关键部分,所以请注意。这确实是一个文字游戏,我们将使用一个使用门控网络的注意力机制: )
作者引入了一个称为缩减比** r 的新参数,在 sigmoid 激活的选通网络之前,引入第一个具有 ReLU 激活的全连接(FC)层。**
这样做的原因是引入一个瓶颈,它允许我们在引入新的非线性的同时降低维度。
此外,我们可以更好地控制模型的复杂性和辅助网络的泛化性能。
具有两个 FC 层将导致具有两个权重矩阵,这两个权重矩阵将由网络在训练期间以端到端的方式学习(所有权重矩阵都与卷积核一起反向传播)。
该函数的数学表达式得出:
我们已经让我们的压缩特征地图兴奋了!
看看这些激励只不过是一对经过训练的神经网络,以便在训练过程中更好地校准这些激励。
3.规模
最后一步,缩放,确实是重新缩放操作。我们将赋予压缩矢量其原始形状,保持在激发步骤中获得的信息。
Figure 5. Rescaling
在数学上,缩放是通过输入体积上的每个通道与激活的 1x1 压缩向量上的相应通道的简单标量积来实现的。
对于 1 个频道:
作者讨论:
激活充当适应于输入特定描述符 z 的通道权重。
硒块的应用
如作为创新之一介绍的,SE 块不是新的神经网络架构。它试图通过使现有模型对渠道关系更加敏感来改进现有模型。
Figure 6. SE block applied to Inception (left) and ResNets (right) modules
图 6 显示了如何在卷积层的输出音量之后应用相同的 SE 块,以在将其移动到下一层之前丰富其表示。在这种情况下,显示了 Inception 和 ResNets 模块。
结果和结论
结果证实,在最先进的网络中引入 SE 块提高了它们在不同计算机视觉应用中的性能:图像网络分类、场景分类(Places365-Challenge 数据集)和对象检测(COCO 数据集)。这些结果太宽泛了,不包括在这个总结中,我建议在原始论文中查看它们。
****折减系数的经验研究值带来了一个有趣的观察结果。事实证明,16 是一个很好的值,超过这个值,性能不会随着模型容量的增加而单调地提高。
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
SE 块可能会过度拟合通道相关性
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
最后,作者在每个阶段(或层)对 50 个均匀采样的通道执行平均激活,其中为 5 个显著不同的类别引入了 SE 块。已经观察到,跨不同类别的分布在较低层中几乎相同,而每个通道的值在更大深度处变得更加类别特定。****
全球图片
将所有东西放回一起,SE 块: )
理解并使用 R 编写您的第一个文本挖掘脚本
介绍
数据科学变得流行的原因之一是因为它能够在瞬间或仅仅一个查询中揭示大量数据集的信息。
仔细想想,每天我们以文本的形式给出了多少信息?所有这些信息包含了我们的情感、我们的观点、我们的计划、建议、我们最喜欢的短语等等。
然而,揭示其中的每一个看起来就像是大海捞针,直到我们使用像文本挖掘/分析这样的技术。
文本挖掘考虑了信息检索、词频分析和研究以及模式识别,以帮助可视化和预测分析。
在本文中,我们将经历数据集为进一步分析做准备的主要步骤。我们将使用 R 编写脚本,代码将在 R studio 中编写。
为了实现我们的目标,我们将使用一个名为“tm”的 R 包。这个软件包支持所有的文本挖掘功能,如加载数据,清理数据和建立一个术语矩阵。它在 CRAN 上有售。
让我们首先在我们的工作空间中安装并加载这个包。
#downloading and installing the package from CRAN
install.packages("tm")#loading tm
library(tm)
加载数据
要挖掘的文本可以从不同的源格式加载到 R 中。它可以来自文本文件(。txt)、pdf(。pdf)、csv 文件(。csv) e.t.c,但不管源格式如何,要在 tm 包中使用它,就要把它变成一个“语料库”。
语料库被定义为“书面文本的集合,尤其是特定作者的全部作品或关于特定主题的写作主体”。
tm 包使用 Corpus()函数创建一个语料库。
#loading a text file from local computer
newdata<- readlines(filepath)#Load data as corpus
#VectorSource() creates character vectorsmydata <- Corpus(VectorSource(newdata))
参考本指南了解更多关于导入文件到 r。
正在清理数据。
一旦我们成功地将数据加载到工作空间中,就该清理这些数据了。我们在这一步的目标是从数据文件中创建独立的术语(单词),然后才能开始计算它们出现的频率。
因为 R 是区分大小写的,我们应该首先将整个文本转换成小写,以避免认为相同的单词“write”和“Write”不同。
我们将删除:网址,表情符号,非英语单词,标点符号,数字,空白和停用词。
停用词:tm 包中常用的英文单词如“a”、“is”、“The”都称为停用词。为了使结果更准确,必须去掉这些词。也可以创建自己的自定义停用词。
# convert to lower case
mydata <- tm_map(mydata, content_transformer(tolower))#remove ������ what would be emojis
mydata<-tm_map(mydata, content_transformer(gsub), pattern="\\W",replace=" ")# remove URLs
removeURL <- function(x) gsub("http[^[:space:]]*", "", x)
mydata <- tm_map(mydata, content_transformer(removeURL)
)
# remove anything other than English letters or space
removeNumPunct <- function(x) gsub("[^[:alpha:][:space:]]*", "", x)
mydata <- tm_map(mydata, content_transformer(removeNumPunct))# remove stopwords
mydata <- tm_map(mydata, removeWords, stopwords("english"))#u can create custom stop words using the code below.
#myStopwords <- c(setdiff(stopwords('english'), c("r", "big")),"use", "see", "used", "via", "amp")
#mydata <- tm_map(mydata, removeWords, myStopwords)# remove extra whitespace
mydata <- tm_map(mydata, stripWhitespace)# Remove numbers
mydata <- tm_map(mydata, removeNumbers)# Remove punctuations
mydata <- tm_map(mydata, removePunctuation)
词干
词干提取是将相似来源的单词聚集成一个单词的过程,例如“通信”、“交流”、“沟通”。词干分析通过删除后缀和将单词简化为基本形式来帮助我们提高挖掘文本的准确性。我们将使用雪球图书馆。
library(SnowballC)mydata <- tm_map(mydata, stemDocument)
构建术语矩阵并揭示词频
在清理过程之后,我们剩下的是存在于整个文档中的独立术语。这些都存储在一个矩阵中,显示它们的每一次出现。这个矩阵记录了术语在我们的干净数据集中出现的次数,因此被称为术语矩阵。
#create a term matrix and store it as dtm
dtm <- TermDocumentMatrix(mydata)
词频:词在数据集中出现的次数。使用术语矩阵中出现的汇编,词频将向我们指示从数据集中最频繁使用的词到最少使用的词。
结论
我们刚刚写了一个基本的文本挖掘脚本,然而这只是文本挖掘的开始。获取原始格式的文本并将其清理到这一点的能力将为我们提供方向,如构建单词云、情感分析和构建模型。
保留这个脚本,因为当我们开始进行情感分析时,它会派上用场。
有任何问题都可以联系我> @lornamariak 。
使用 Valenbisi(瓦伦西亚自行车共享系统)了解 ARIMA 车型
我杰出的同事 Nicole Eickhoff 和我一起去西班牙,我们希望在那里见到数据科学家。因为我们会在那里参加 Fallas,一个为期一个月的社区和传统庆祝活动,我们收集了 Valenbisi 在 Crida Fallas 前一周的数据。Crida Fallas 是为期一个月的活动的第一天。我们想看看瀑布如何影响自行车共享活动。在这里,我详细介绍了我们在 2018 年 3 月 13 日星期二与巴伦西亚大数据会议上介绍和讨论的项目。
As part of the celebration of Fallas, each neighborhood in Valencia creates fantastic street light displays.
在这篇博客中,我简要描述了我使用刮刀收集数据、进行 ARIMA 分析、仔细考虑结果以及提出构建模型的后续步骤的过程,该模型可以预测瓦伦西亚每个 Valenbisi 站的自行车和码头可用性。关于这些的更深入的报道,请继续关注这个博客和我的 Github 上的 Jupyter 笔记本中提供的链接。
收集数据
Nicole 于 2018 年 2 月 16 日请求 Valenbisi 的 API 密钥访问。在发现 API 只提供两年前的数据后,她向我寻求建议。鉴于网站提供了一个实时下载的 CSV 文件,而且当时它的使用条款中也没有禁止抓取,我知道我们可以制作一个抓取器并尝试一下。除了 python 库‘requests’之外,我只用了很少的东西就能构建一个 scraper,并在去西班牙之前的 10 天里,在一个 AWS web 实例上托管它。
这里有一个链接指向我的 Github 托管的 Jupyter 笔记本,在那里我浏览了我在 AWS 上托管的 scraper 的主干。
我每 15 分钟收集实时数据 1001 次。csv 包括“自行车可用”、“加油站空闲”、“总计、 X 和 Y 的信息。
这是 10 天多一点的数据。这使得我们无法观察一年中的季节,而只能观察一周中的季节。由于我们的数据如此之少,这将是一个大规模的例子,可能会更直观地解释。我们将能够关注每周和每小时的趋势。
我们的数据不包括关于哪个活动是重新平衡工作的信息。
我们的数据不包括具体的乘坐数据,这使得这些数据不适合网络分析。
x 和 Y 是 UTF 坐标,可以使用 UTM 图书馆转换成经度和纬度坐标。西班牙的国家代码是“30”和“S”,如下例所示。
[Input]: **import** **utm** utm.to_latlon(725755.944, 4372972.613, 30, 'S')[Output]:
(39.47674728414135, -0.37534073558984327)
并且使用散景,我能够绘制出每个 Valenbisi 站(蓝色)和为第一天安排的主要活动的每个位置(红色),开始为期一个月的活动:Crida Fallas。2018 年 2 月 25 日。
#Plaza Ayuntamiento @39.4697661,-0.4113992 #圣胡安德尔医院教堂@39.4743981,-0.3814647 #托雷斯·德洛斯·塞拉诺斯@39.4791963,-0.378187
探索性数据分析
首先,我们预计 Crida Fallas 周围的整个系统会出现“尖峰”或一些不规则行为。以下所有车站所有可用自行车的图表显示,还有其他冲击发生,不一定与坠落有关。竖线表示 Crida Fallas,2018 年 2 月 25 日。
We presented to Valencia’s Big Data Meetup. Suggestions for such frequent and unrelated-to-commute-times plummets were system power outages. For this analysis, I retained all datapoints.
接下来,我绘制了三个单独的 Valenbisi 站。也许靠近 Crida Fallas 活动与车站受到的影响有关。首先,我们来看看位于 Crida 活动地点附近或地图上红点附近的车站是什么样的。
Wow, we see a big spike for Crida Fallas, and another later in the week! This station is, as we expected, very close to the city center, the Ayuntamiento. Over all, apparent return to normal behavior after Crida Fallas seems to happen pretty quickly.
对位于市中心附近的车站 Ayuntamiento 的视觉观察。
- Crida Fallas 期间可用自行车的大高峰
- 本周晚些时候又一次飙升
- 总的来说,在 Crida Fallas 之后,相对较快地恢复到“正常”行为
现在,以下车站更靠近巴伦西亚的城市边界。
I see very little recognizable pattern here. Whatever occurred on February 25th looks as if it could have occured any day for this station.
对位于城市西南边界的车站的视觉观察:
- 这里几乎没有可辨认的图案。
- 无论这个站在 2 月 25 日表现出什么样的行为,看起来都像是发生在其他任何一天。
位于城市边缘附近的一个站的视觉观察。
- 没有查一下这个车站附近有什么(也许是医院?),很明显这里的自行车是用来通勤的。
- 我们看到,Crida 不仅在当天影响该站,而且在行为恢复“正常”的前一天和后两天也影响该站。
我们看到,无论我们提出什么样的解决方案,都需要适用于具有多种不同行为的电视台。出于我们的目的,让我们对所有数据进行 ARIMA 分析。我选择首先查看所有数据来开始分析,因为它在 Crida Fallas 附近没有表现出不稳定的行为,并且将是 ARIMA 建模的一个很好的学习示例。 ARIMA 模型依赖于这样一种假设,即自行车站点最近所处的州会影响未来可用自行车/码头的数量。此外,ARIMA 模型可以捕捉我们的时间序列数据中的季节关系。
ARIMA 分析
- 将时间序列分解为趋势、季节性和残差
- 平稳性检验(迪基-富勒检验)
- 创建 ARIMA 模型
- 结果解释
1.分解
视觉观察:
- 在 10 天的过程中,我们看到了一个略微向上的趋势。这种上升趋势仅涉及 100 辆自行车。
- 在季节分解中,我们观察到重复。试图解释每个裂缝是徒劳的,但这个特征中的重复模式表明了一种日常行为模式。(我们有 10 天,可以数 10 次重复。)
- 我们的残差图显示,正如预期的那样:6 次暴跌中只有 5 次出现了重大暴跌,这 6 次暴跌被巴伦西亚 Meetup 观众认为是“可能的断电”。
2.我们的数据是静态的吗?——扩展的迪基-富勒测试
首先,我测试我们的数据是平稳的。重要的是,你的时间序列在预测之前是平稳的,否则你的模型将是一个糟糕的预测器,因为 ARIMA 依赖于平稳性的假设。
An example of non-stationary data, stationized. Provided by www.itl.nist.gov/div898/hand…
这可以是它自己的博客帖子,非常有趣。更定量的解释,我推荐这个来源。
出于我们谈话的目的,重要的是要知道,在进行 Dickey-Fuller 检验时,我们是在进行假设检验:
H0:数据是非平稳的
H1:数据是静止的
我使用下面的代码对数据执行 Dickey-Fuller 测试。它是作为我的数据科学训练营的学习练习提供的:
输出:
Our p-value is definitely below .05, meaning we can reject the null hypothesis; our data is stationary!
我们将stats models . TSA . stat tools . ad fuller用于以下输入:
- maxlag : None (因为我们指定 autolag =‘AIC’,所以在我们的例子中不会用到它。)
- 回归:‘c’:仅常量(默认)
- 自动标记:‘AIC’:如果‘AIC’(默认)或‘BIC’,那么选择标记的数量以最小化相应的信息标准。这将选择具有最佳 AIC 分数的模型。
AIC 是一个常数加上数据的未知真实似然函数和模型的拟合似然函数之间的相对距离的估计值,因此 AIC 越小,模型越接近真实值。
BIC 是在特定的贝叶斯设置下,对模型为真的后验概率的函数的估计,因此较低的 BIC 意味着模型被认为更有可能是真实的模型。
……尽管存在各种微妙的理论差异,但它们在实践中的唯一区别是处罚的大小;BIC 对模型复杂性的惩罚更重。他们应该不同意的唯一方式是当 AIC 选择一个比 BIC 更大的模型
我们的 Dickey-Fuller 检验的 p 值肯定低于 0.05,这意味着我们可以拒绝零假设。我们的数据是稳定的,因此可以插入 ARIMA 模型。
3.ARIMA 模型
现在开始在这个博客中,你会发现与我们瓦伦西亚大数据会议演示的原始对话有偏差。我希望这篇博客能推动关于方法论的进一步讨论,以及我在 ARIMA 模型和我的数据中遇到的一些不确定性。我对如何提高我的理解和我的模型的谈话和对话持开放态度。
我发现 ARIMA 模型相当不确定,原因如下:
- 在我们的 statsmodels SARIMAX 模型中使用的发现季节性指标的经验方法( ACF/PACF 图)并没有产生一个有效的模型。(详见 github。)
- (在我运行的多个模型中)预测最好的模型是一个几乎没有统计显著滞后变量的模型。
这是我看到的最适合预测的模型的代码。你可以在我的 Github 上找到(几乎)我所有的其他模型。
mod = sm.tsa.statespace.SARIMAX(df[0:960].available,
trend='n',
order=(1,0,1),
seasonal_order=(4,0,7,24),
enforce_stationarity =False,
enforce_invertibility = False)results = mod.fit()
results.summary()
Wow, why does a model with nearly no significant lags produce the best predictions? Perhaps it’s not so bad. Discussion below.
With no other independent variables besides its own behavior, our ARIMA model can predict pretty well, I’d say.
提醒一下:我们只有 10 天的数据,每小时 4 个点的数据。这使得我们无法测试年度季节性关系。出于我们的目的,我打算说一个赛季持续 6 个小时。这意味着每天有四个季节。这应该包括高峰时间、中午和晚上。最直观的是,这使得数据点/季节变量的数量 m = 4*6 = 24。
选择我的(pdq)(PDQ)m 价值观的动机:
非季节性的,对模型当前状态最有影响的滞后是在它之前的滞后期间发生的。p =1,q = 1,(以及 d = 0,因为我们的数据是平稳的)。
p,季节性 AR 订单。我怀疑日期之间有季节性,所以我想看看前一天发生了什么。(24 个数据点的 4 个滞后)
d,季节性差异为 0,因为我们的数据是稳定的。
q,季节移动平均订单。现在我承认,乍一看这似乎是最不直观的。我通过反复试验发现了它,但是如果我们考虑 7 个 24 点的滞后,意味着 42 小时之前,它似乎是可预测性最好的;不到两整天。如果你把一周看成 168 个小时,这些数字会清晰地分开:168/42 = 4。这表明一周有 4 个不同的行为时间。我们希望我们的模型相应地使用 1/4 周作为它的移动平均窗口。
请随意参考我的 github 查看(几乎)我尝试过的所有机型,并在评论中留下任何对机型参数改进的建议。
4.结果解释:
首先,我要承认,虽然存在极少数具有统计显著性的滞后,但移除一个因其 p>|z|值而被认为在统计上无关紧要的变量会对模型的预测能力产生不利影响。 ARIMA(1,0,0)(4,0,7,24),绿色=预测,蓝色=实际。
An example of what happens when you remove the ma.L1 with p>|z| value .993. ARIMA(1,0,0)(4,0,7,24).
ARIMA(1,0,1)(4,0,7,24)模型确实有整体最低的 AIC 和 BIC 分数*。这些指标不是对模型质量的评分,而是提供了与其他模型进行比较的手段;越低越好。
其次,我想深入了解 Statespace 模型结果提供的一些其他结果:
进行 Ljung-Box (Q) 测试以确认残差是独立的。这意味着我们的误差彼此不相关,我们已经成功地用我们的模型解释了数据中的模式。
我们对 Ljung-Box 进行的假设检验如下:
H0: 数据是独立分布的(即样本总体的相关性为 0,因此数据中任何观察到的相关性都是由抽样过程的随机性造成的)。
H1: 数据不是独立分布的;它们表现出序列相关性。
Ljung-Box(Q)给出的测试统计量遵循 X 分布,具有( h-p-q) 个自由度,其中 h 为测试滞后的数量。
如果 p 值(Prob(Q)) 大于 0.05,那么我们不能拒绝零假设;残差是独立的,这表明模型为数据提供了足够的拟合。我们看到我们的问题(Q)是. 62。太好了。因此,尽管没有很多统计上显著的滞后变量,我们的模型已经设法解释了足够多的方差,即残差是随机的。
**异方差:**线性回归的一个假设是残差不存在异方差。这意味着残差的方差不应随着响应变量的拟合值而增加;我们更喜欢我们的残差是同伦的。
H0: 残差的方差是常数;没有异性。
H1: 异方差存在。
这里我们不能在 95%的置信水平上拒绝零假设,因为我们的 p 值是 0.07。我们可以假设残差中的同质性。好吧,还不错。我们的模型设法通过的另一个测试。
Jarque-Bera 和峰度度量是关于正态性的。我们的数据不是正态分布的,所以现在我将跳过这些度量。
可能的后续步骤
- 扩大规模,这意味着收集更长时间的数据,并将模型应用于各个站点。考虑一个递归神经网络来模拟时间序列排序。
- 考虑一个泊松点过程模型来预测可用自行车和码头开放,使用建立时间优先级。shift() 像这样的 DSSG 项目做了。
- 请求关于再平衡工作的数据。
- 考虑主要城市活动的特征工程附加变量以及与特定活动的距离。
- 考虑对受影响的自行车站进行冲击建模。
#数据假期
这是我和妮可为我们的西班牙之行准备的两个演示文稿之一。它被分享给了巴伦西亚数据科学会议。
我们的另一项工作是在巴伦西亚大学商学院的本科生市场营销课上进行的 CRM 数据研讨会。请关注妮可即将发表的关于此事的博客。
数据源:
Github 资源库:
巴伦西亚-数据-项目-数据炸弹
github.com](github.com/nmolivo/val…)
附加资源: https://www . data camp . com/courses/introduction-to-time-series-analysis-in-python
理解 AUC - ROC 曲线
Understanding AUC - ROC Curve [Image 1] (Image courtesy: My Photoshopped Collection)
在机器学习中,性能测量是一项基本任务。所以当涉及到分类问题时,我们可以依靠 AUC - ROC 曲线。当我们需要检查或可视化多类分类问题的性能时,我们使用 AUC ( 曲线下的面积 ) ROC ( 接收器操作特性)曲线。它是检验任何分类模型性能的最重要的评价指标之一。也可以写成 AUROC(接收器工作特性下的区域)
注:为了更好的理解,我建议你看一下我写的关于混淆矩阵的文章。
本博客旨在回答以下问题:
1.什么是 AUC - ROC 曲线?
2.定义 AUC 和 ROC 曲线中使用的术语。
3.如何推测模型的性能?
4.敏感性、特异性、FPR 和阈值之间的关系。
5.多类模型如何使用 AUC - ROC 曲线?
什么是 AUC - ROC 曲线?
AUC - ROC 曲线是在各种阈值设置下对分类问题的性能测量。ROC 是概率曲线,AUC 代表可分性的程度或度量。它告诉我们这个模型在多大程度上能够区分不同的类。AUC 越高,模型预测 0 类为 0 和 1 类为 1 的能力越强。以此类推,AUC 越高,模型在区分患病和未患病患者方面就越好。
用 TPR 对 FPR 绘制 ROC 曲线,其中 TPR 在 y 轴上,FPR 在 x 轴上。
AUC - ROC Curve [Image 2] (Image courtesy: My Photoshopped Collection)
定义 AUC 和 ROC 曲线中使用的术语。
TPR(真阳性率)/召回/灵敏度
Image 3
特异性
Image 4
定期用量法(Fixed Period Requirements)
Image 5
如何推测车型的性能?
一个优秀的模型具有接近 1 的 AUC,这意味着它具有良好的可分性度量。差模型的 AUC 接近 0,这意味着它具有最差的可分性度量。事实上,这意味着它在往复结果。它预测 0 是 1,1 是 0。当 AUC 为 0.5 时,这意味着该模型没有任何类别分离能力。
我们来解读一下上面的说法。
我们知道,ROC 是一条概率曲线。让我们画出这些概率的分布:
注:红色分布曲线为阳性类别(患病患者),绿色分布曲线为阴性类别(未患病患者)。
[Image 6 and 7] (Image courtesy: My Photoshopped Collection)
这是一种理想的情况。当两条曲线完全不重叠时,意味着模型具有理想的可分性度量。它完全能够区分积极类和消极类。
[Image 8 and 9] (Image courtesy: My Photoshopped Collection)
当两个分布重叠时,我们引入类型 1 和类型 2 误差。根据阈值,我们可以最小化或最大化它们。当 AUC 为 0.7 时,这意味着模型有 70%的机会能够区分正类和负类。
[Image 10 and 11] (Image courtesy: My Photoshopped Collection)
这是最坏的情况。当 AUC 约为 0.5 时,该模型没有区分阳性类别和阴性类别的区分能力。
[Image 12 and 13] (Image courtesy: My Photoshopped Collection)
当 AUC 大约为 0 时,模型实际上是在往复类。这意味着模型将一个负类预测为正类,反之亦然。
灵敏度、特异性、FPR 和阈值之间的关系。
灵敏度和特异性是成反比的。所以当我们提高敏感度时,特异性就会降低,反之亦然。
Specificity⬇️的 Sensitivity⬆️和 Specificity⬆️的 Sensitivity⬇️
当我们降低阈值时,我们得到更多的正值,从而增加了灵敏度,降低了特异性。
类似地,当我们增加阈值时,我们得到更多的负值,因此我们得到更高的特异性和更低的敏感性。
正如我们所知,FPR 是 1 -特异性。因此,当我们提高 TPR 时,FPR 也会提高,反之亦然。
FPR⬆️的 TPR⬆️和 FPR⬇️的 TPR⬇️
多类模型如何使用 AUC ROC 曲线?
在一个多类模型中,我们可以使用一个对所有方法为 N 个类绘制 N 个 AUC ROC 曲线。例如,如果您有三个名为 X,Y,和 Z 的类,您将有一个针对 X 和 Z 分类的 ROC,另一个针对 Y 和 Z 分类的 ROC,以及针对 Y 和 X 分类的第三个 ROC
感谢阅读。
我希望我已经让你对什么是 AUC - ROC 曲线有了一些了解。如果你喜欢这篇文章,给这篇文章一些掌声会对你有所帮助👏。我随时欢迎你的问题和建议。你可以在脸书、推特、Linkedin 上分享这个,这样有需要的人可能会偶然发现这个。
您可以通过以下方式联系到我:
领英:www.linkedin.com/in/narkhede…
github:github.com/TheSarang
用 Python 理解基本的机器学习——感知器和人工神经元
基本功能的完整代码演练
如果你正在学习机器学习,很可能你的目标是应用前沿算法和“深度学习”来创建强大的应用程序。随着直观的 API 的广泛使用,这是可以实现的,只需要对正在发生的事情或深层底层实际上是如何工作的理解很少。
然而,在做这件事之前,浅显的架构基础知识和对底层的洞察是有益的。如果没有这一点,构建偏离盲目跟随教程的模型将变得困难(猴子见猴子做综合症)。
在这篇文章中,我们将讨论人工神经元和分类的起点,包括感知器和 Adaline 模型。对于每个模型,我们将讨论主要组件,然后将它们组合成完整的 Python 类实现。
Image 1. Neuron Cell, taken from Pixabay.
感知器模型
机器学习最根本的起点是人工神经元。第一个简化的脑细胞模型发表于 1943 年,被称为麦卡洛克-皮茨(MCP) 神经元。本质上,这是一个具有二进制输出(“0”或“1”)的基本逻辑门。如果到达神经元的输入的总和超过给定的阈值,则产生“1 ”,其中每个输入乘以相应的权重系数以产生这个总和。因此,神经元的放电很大程度上取决于输入集和相应的权重系数值。
弗兰克·罗森布拉特在 MCP 神经元的基本概念发表后不久就采用了这一概念,并提出了**感知器规则算法。**该允许自动学习神经元模型的最佳权重系数。通过这样的模型,我们可以预测给定的输入是属于一个类还是另一个类(二元分类)。
Figure 1. Simplified Perceptron Model. Diagram by Author.
感知器模型可能有任意数量的输入,也称为特征。因为我们通常有多个特征,所以用向量和矩阵来表示我们的输入和权重是有帮助的。不要混淆输入样本和输入特征;每个数据样本都有许多特征, n,,这些特征通过我们的模型输入,一次处理一个(按顺序)。例如,如果我们有 100 个汽车数据样本,其中每个样本都有 m 个特征(代表最高速度、bhp、成本等)。),那么数据的每个样本 x 将具有一个 m 个特征的向量。每个输入特征都有一个相应的权重,经过训练后,权重将根据我们训练的数据进行优化。
Figure 2. Vectors for our input features and weights.
对于每个数据样本,我们的输入特征和权重作为一个加权和在感知器中被接受,这就是通常所说的网络输入函数, z *。*对上面的 x 和 w 使用向量的好处是,我们可以使用线性代数来简洁地表示它,就像这样:
Figure 3. Perceptron Net Input Function.
我们转置权重向量 w ,然后与我们的输入向量x相乘,这形成了我们需要的和。还应注意,我们还使用了一个偏差项来允许我们的感知器模型中有一个阈值,它等于我们向量中的第一个权重项。为了方便起见,输入矩阵中的第一个 x 项总是设置为 1。这意味着我们需要在输入向量中加入偏差项,然后再将它放入模型中。
如果你对这种数学符号完全陌生,我强烈推荐一些线性代数入门。几乎你在进一步的机器学习中所涉及的所有内容都将大量基于线性代数。
在净输入求和之后,我们的值被传递给感知器阈值,或决策函数。在这种情况下,该功能是一个单位步进功能。如果输入高于给定值,则输出“1”,否则输出“0”。
那么我们的感知机实际上是如何从一组数据中学习的呢?整个感知器过程如下:
- 将重量参数初始化为初始值(通常是小的随机值,而不是零)。
- 从每个训练样本输入的给定特征预测二进制输出。
- 通过感知器学习规则更新权重。
Figure 4. Model for the Perceptron, including weight optimisation using the error. Diagram by Author.
感知器的成本函数非常简单,被称为**感知器学习规则。**每次训练迭代后,我们的权重向量中的每个权重都会有一个小的变化,如下所示:
Figure 5. Perceptron Learning Rule for updating of weights.
:=符号意味着我们同时更新权重向量中的所有权重,而不是迭代地更新。因此,进行输出预测,然后更新所有权重参数,作为一个训练周期的一部分。上面的 alpha 项也等于学习率,它决定了我们的模型在每个训练周期中学习的速度。
假设我们用于训练的数据是线性可分的,如果经过足够的训练周期(时期),感知器会将权重更新为最佳值。
Python 中的感知器
我们将从用 Python 编写感知器的每个组件开始,然后在最后将它们组合成一个更大的感知器类。对于这个基本模型,我们唯一需要的 Python 包是 numpy 和 matplotlib 。
抽样资料
为此,我们将生成一个简单的数据集,其中包含两个不同的输出类,供我们的感知器进行训练。注意:该随机训练数据是通过随机函数生成的,并不完全可复制。
为了帮助理解我们正在努力做的事情,可视化我们的数据是有帮助的。在这种情况下,我们的输入样本只有两个特征,因此使用散点图来可视化我们的数据很容易。下面显示了数据生成,然后绘制成散点图。
Figure 6. Sample code for generating bird data and plotting on a scatter graph.
Figure 7. Visualisation of our generated data.
初始权重的生成
我们希望将我们的权重初始化为小的随机数字,而不是将它们初始化为零。我们需要这样做,否则我们的学习率将会降低训练过程中对分类结果的影响。这背后的理由将不被涵盖,然而,这是因为学习率只影响权重向量的规模,而不是方向,如果权重初始化为零。
这些权重可以以不同的方式生成。使用 numpy.random 的一个例子是:
向 X 添加偏差项
对于偏置项,我们只需在输入数据 x 中添加一列 1,在 numpy 中,这可以通过使用one和 hstack numpy 函数来实现。
加权求和函数(净输入)
如上所述,由于我们对每个样本的输入特征及其相关权重使用向量,因此我们可以非常容易地计算净输入和。在 Python 中使用带有 numpy 的矢量化,根据我们是否向训练数据添加了 1 的偏差列,网络输入函数变为:
Figure 8. Implementing the net input sum in numpy.
预测用单位阶跃函数
如果我们的净输入总和大于或等于零,我们希望返回 1,否则返回 0。
Figure 9. Implementing the step input function in numpy.
感知器学习规则
使用之前在图 6 中定义的学习规则,我们可以执行一个完整的训练周期。这包括遍历所有训练样本,并根据感知器学习规则更新权重,如下所示:
Figure 10. Perceptron training cycle implementation.
把所有的放在一起
有了使用 numpy 形成的感知器的基本组件,我们可以将它们拼凑在一起,实现一个完整的感知器二进制分类器。使用分类器,我们可以在训练周期中可视化我们的错误,并且(希望如此!)随着权重的优化,错误数量会随着时间的推移而减少。
Figure 11. Code for a Perceptron class in Python for binary classification.
Figure 12. Visualisation of the errors and decision boundaries made by our Perceptron classifier.
从误差与训练周期(时期)的关系图中可以看出,我们得到的误差数量随着时间的推移而减少。大约 7 个周期后,我们的模型将错误数量减少到零。我们的感知器分类器训练后做出的决策边界如右图所示,有效地区分了金雕和角枭。我们可以通过使用一组新输入 x 调用分类器预测函数,使用我们训练的模型对新数据进行预测。
感知器的一个问题是,如果所提供的数据是完全线性可分的,它们只会正确地优化权重。对于上面使用的数据,它是线性可分的。然而,如果我们使用更现实的数据,这些数据通常不能用直线分开,那么我们的感知器分类器将永远不会停止优化权重,并将不断出现错误。这是一个巨大的缺点,也是不使用感知机的原因之一。然而,它们确实是对基本神经元和更复杂模型的良好介绍。
Adaline——自适应线性神经元
对原始感知器模型的改进是 Adaline,它增加了一个用于优化权重的线性激活函数。通过这种添加,使用连续成本函数而不是单位步长。Adaline 很重要,因为它为更高级的机器学习模型奠定了基础。
Figure 13. Model for Adaline, which includes the additional activation function. Diagram by Author.
正如您在上面看到的,单位步骤仍然存在,但是它仅用于模型末尾的输出分类(“1”或“0”)。线性激活模型的连续输出值用于成本(或目标)函数。这表明我们的算法在我们的训练数据上做得有多差(或多好),并且可以通过众所周知的算法(如梯度下降)将其最小化。
价值函数
在这种情况下,我们将使用误差平方和作为我们的成本函数,可以这样实现:
Figure 14. Sum of Squared Errors implementation in Python.
梯度下降
为了应用梯度下降,我们需要确定成本函数相对于每个权重的偏导数。利用微分,我们发现这个偏导数等于:
Figure 15. Partial derivative of our cost function with respect to each weight.
为了优化我们的权重,我们希望以我们的学习速率参数所选择的速率,在梯度的相反方向上迈出一步。这背后的逻辑是最小化成本并最终达到全局最小值。因此,对于每次重量优化,我们需要应用:
Figure 16. Optimisation updates for our weights in the Adaline model.
我们可以将权重优化步骤和成本计算步骤合并到一个训练周期代码片段中,如下所示:
Figure 17. One training cycle for our Adaline model.
特征标准化
除了激活功能和梯度下降优化,我们还将通过 F 功能标准化增强我们模型的性能。这是机器学习中的一种常见做法,对于给定数量的时期,这种做法使优化过程更快、更有效。为此,我们将从训练数据中的每个相关特征值中减去每个特征的平均值,然后将特征值除以它们各自的标准偏差。
Figure 18. Feature standardisation in Python.
把所有的放在一起
有了 Adaline 模型的附加组件,我们就可以用 Python 生成一个最终的实现,就像我们用感知器一样。这个 Adaline 实现如下所示:
Figure 19. Adaline Classifier implemented in Python.
从下图中的基本 Adaline 示例中,我们可以看到为我们的模型设置超参数是多么重要;如果我们选择 0.1 的学习率,成本趋于无穷大并且不收敛,而如果我们选择 0.001 的学习率,我们的模型成功地收敛到成本函数的全局最小值。迭代的次数也很重要,应该足够高以充分降低成本。机器学习模型的这些可调方面被称为超参数,这些优化对于我们创建的任何模型都是一个重要方面。
Figure 20. Comparison of different choices of learning rate for our Adaline classifier.
进一步改进和结束语
有很多方法可以进一步改进这个模型,包括随机梯度下降,它可以更频繁地优化,而不是像上述模型那样使用整批训练数据。我们还可以将它扩展到不仅仅是二元分类,使用一元对多元分类。
此外,还有比 Adaline 好得多的分类器可用。Adaline 是一个起点,可以用作理解更复杂的分类模型(如逻辑回归和神经网络)的基础。
在这篇文章中,我们研究了基本神经元的特性,然后使用 Python 和 numpy 构建了一个基本的 Rosenblatt 感知器模型。然后,我们构建了一个工作 Adaline 分类器,它通过激活函数和优化成本函数,在许多方面改进了感知器。在此期间,我们还应用了一些有价值的特征处理,包括标准化以使梯度下降更快更有效。
虽然这些模型不能替代通过 Sci-kit Learn 和其他软件包获得的专业构建和优化的模型,但它们应该能够让人们了解基本分类器的工作原理。我希望我们遵循的过程有助于您理解基本的机器学习分类,并为您提供使用 Python 实现这些模型的洞察力。
通过超级马里奥了解机器学习的基础
Super Mario Land for gameboy
有很多关于神经网络和机器学习的文章,因为这个主题在过去几年里非常受欢迎。这个领域似乎非常难以接近和理解,许多人可能认为必须是数学家或统计学家才能掌握机器学习的概念。然而,机器学习和神经网络的基本概念不一定像人们想象的那样复杂。
本文的目的是通过一个任何人都能理解的简单例子来解释机器学习如何工作的高级概念。希望它能给你兴趣和信心,让你继续阅读和学习更多关于这个主题的知识,打破让它看起来如此不可接近的令人生畏的障碍。
强化学习
机器学习程序与常规程序的不同之处在于,程序员没有明确定义逻辑。程序员创造了一个程序,它有能力自学如何成功地完成手头的任务。我要举的例子很可能会被认为是一个强化学习的机器学习程序。这个程序接受输入,做出自己的决定并产生一个输出,然后从输出产生的回报中学习,一遍又一遍地重复整个过程。这听起来可能很抽象,但这和我们人类学习如何做事的方式非常相似。下面我将把它分解成人类能够理解的步骤。还有什么比超级马里奥更好的表达方式呢?
要开始我们的思维实验,你必须想象你对电脑游戏完全陌生。你甚至从未听说过它们,更不用说以前玩过了。然后有人给你一个超级马里奥的游戏。
投入
你看着屏幕,看到简单的 2D 风景。这被认为是您的输入;你开始看这个小图形,这是马里奥,然后是风景中的所有其他物体。
输出
你有四种可能的方式与游戏互动。你可以左,右,蹲,跳。这些是你的输出。您可以根据输入来决定应该选择哪个输出。
报酬
你目前不知道游戏中有什么潜在的奖励,但是很快你就会亲身体验到。每个输出的奖励在游戏中会有所不同。如果你只是向左或向右走,回报是相当低的。如果你走进一枚硬币,奖励会稍微高一点。如果你跳进一个神秘的盒子,奖励会更高。然而,如果你被敌人击中,你的奖励是负的——不用说,负奖励更像是一种惩罚。
你学习如何玩超级马里奥
完全新手如何玩游戏,你开始按下右箭头。马里奥向右移动,你会得到奖励。然而,当你继续按右箭头时,马里奥最终击中了一个古姆巴,在这个古姆巴上你得到了死亡的奖励!
Mario got rewarded by death for hitting the Goomba
别担心,你可以重新开始。这一次,当你记录向你走来的古姆巴的输入时,你尝试其他的输出来获得不同的回报。经过几次尝试后,你意识到在那次遭遇中获得最高奖励的输出是跳到古姆巴上面,或者跳过它。你现在开始学习如何玩超级马里奥。
Mario is rewarded by staying alive for jumping over the Goomba
这就是强化学习的概念在现实生活中的工作方式。机器学习程序一开始是一张白纸,对它应该做的任务一无所知。然后,它接受一个输入,即它所处的环境,并开始试图找出哪个输出给它最高的回报。这个概念非常符合人类如何通过试错来学习做新的事情。我们尝试一种方式,然后是不同的方式,直到我们得到我们想要或期望的回报。
但是每个人都已经知道如何玩超级马里奥了…
的确,没有人真的需要学习如何玩超级马里奥,因为它是一个非常直观的游戏。甚至小孩子也能成功地玩这个游戏。
这样做的原因是,我们在游戏中加入了以前的经验,因此可以更好地掌握游戏规则,更快地获得更高的奖励。在机器学习中,这将被视为训练。
培养
如前所述,每当机器学习程序开始试图找出如何成功完成一项任务时,它都会从头开始。因此,给程序一些训练数据是很重要的,这样它就有了一些开始的基础,这样它就不会一遍又一遍地犯小错误,直到它最终知道任务是什么。
当然,如果有足够的时间,机器学习算法将能够训练自己成功完成给定的任务。这可能需要很长时间,因此为您的程序提供高质量的训练数据以获得更准确的结果是非常重要的。
结论
他们从这篇阅读中得到的关键是理解机器学习算法如何比程序性程序更类似于人类如何学习完成任务。在过程程序中,决策是通过条件语句硬编码到程序中的。例如,这将是程序员识别超级马里奥游戏中的威胁,并输入如下语句:如果检测到威胁,则执行该特定动作,否则继续执行。这种过程方法和机器学习方法之间的主要区别是,最终,计算机程序有自主权做出自己的决定。理解这一点很重要,因为机器学习程序可以用于其他类似的任务,而不必重新编程。我们的示例程序可以在学习玩超级马里奥后很好地学习如何玩任何其他游戏,并且成功率很高,并且玩的游戏越多,玩的游戏越好。这种行为非常类似于一个人在玩不同的游戏时会变得越来越好,尽管每个游戏并不完全相同。我们利用以前的经验学得更快。
这篇文章只是对一个更深入的主题的一个非常简短的概述。如果你对深入研究人工智能和机器学习感兴趣,我会推荐这个文章系列。
如果你喜欢这篇文章,请鼓掌和评论!
使用交互代码的 Numpy 和 Tensorflow 中的示例了解批处理规范化
Gif from here
所以今天我就来探讨一下批量规格化( 批量规格化:通过减少内部协变 ShiftbySergey io FFE,以及Christian Szegedy)。然而,为了加强我对数据预处理的理解,我将讨论 3 种情况,
案例 1 — 归一化:全数据(Numpy) 案例 2 — 标准化:全数据(Numpy) 案例 3 — 批量归一化:小批量(Numpy / Tensorflow)
注 本帖不涉及反向传播!
实验设置
这个实验的设置非常简单。为了模拟真实世界的用例,让我们从随机正态分布创建一个 32*32 的图像,并添加一些噪声。以上是我们的形象看起来像。
红框 →(图像数量,图像宽度,图像高度,通道数量)现在我们将使用 32*32 灰度图像。 左图 →我们图像数据的直方图
正如你在上面看到的,我们的图像平均值为 26,方差为 306。在左边,我们可以看到图像数据的直方图。
情况 1:归一化—全部数据
对于我们的第一个例子,让我们对整个数据集进行归一化。视觉上我们看不出有什么不同。
然而,一旦我们绘制直方图或查看平均值和标准差,我们可以清楚地看到我们的数据在 0 和 1 的范围内。
案例 2:标准化—全部数据
同样,视觉上我看不出彼此有什么太大的不同。
然而,当我们看到直方图的轴时,我们可以清楚地看到,我们的数据的平均值已经移动到 0(几乎),方差为 1。
标准化/规范化方程
Image from this website
左→ 标准化方程 右 →标准化方程
以防万一,如果有人想知道,让我们回顾一下标准化和规范化两种情况下的等式。请注意 μ 是平均值, σ 是标准差。
批量归一化方程
红框→ 标准化方程 蓝线→ 将要学习的参数
现在我们已经讨论了标准化和规范化,我们可以看到,批量标准化的等式与规范化的过程完全相同。唯一的区别是伽玛和贝塔项,用蓝色下划线标出。我们可以将这些项想象成权重,我们将从地面真实数据中计算误差,并使用反向传播来学习这些参数。
但是有一点我希望注意!如果我们把 gamma(谢谢 洛阳方 纠正我 ) 设为 1,beta 设为 0 整个过程只是标准化而已。对于 Tensorflow 的实现,我们将滥用该属性。
案例三:批量归一化——纯实现
红线 →小批量,从我们的图像数据 中取出前 10 张图像,蓝框 →数据标准化
这里有一点需要注意,对于批量标准化,我们将从测试数据中提取前 10 幅图像,并应用批量标准化。
同样,我们可以看到均值在 0 左右,方差为 1。现在让我们看看 tensorflow 的实现。
案例三:批量归一化—张量流
红线 → Mini Batch,来自我们图像数据 的前 10 张图像蓝线→ Offset (Beta)为 0,Scale (Gamma)为 1
还是那句话,视觉上,我们看不出任何区别。
但是,如果我们看一下数据的平均值和方差,我们可以看到这与应用标准化完全相同。
交互代码(谷歌 Collab/ Replit/微软 Azure 笔记本)
对于谷歌 Colab,你需要一个谷歌帐户来查看代码,而且你不能在谷歌 Colab 中运行只读脚本,所以在你的操场上做一个副本。最后,我永远不会请求允许访问你在 Google Drive 上的文件,仅供参考。编码快乐!
要访问 Google Colab 上的代码,请点击此处。 要访问 Repl it 上的代码,请点击这里。 要访问 Microsoft Azure 笔记本上的代码,请单击此处。
遗言
最近 Face book AI 研究组发布了群组规范化。( 分组规格化n by吴雨欣 ,以及 明凯何 )我会尽量涵盖这一点。
如果发现任何错误,请发电子邮件到 jae.duk.seo@gmail.com 给我,如果你想看我所有写作的列表,请在这里查看我的网站。
同时,在我的 twitter 这里关注我,并访问我的网站,或我的 Youtube 频道了解更多内容。如果你感兴趣,我还在这里做了解耦神经网络的比较。
参考
- CS231n 冬季:第五讲:神经网络第二部分。(2018).YouTube。检索于 2018 年 3 月 19 日,来自www.youtube.com/watch?v=gYp…
- thorey,C. (2016 年)。流过批量归一化的渐变是什么样子的?。cthorey . github . io . 2018 年 3 月 19 日检索,来自cthorey.github.io/backpropaga…
- 推导批量范数反投影方程。(2018).chrisyeh 96 . github . io . 2018 年 3 月 19 日检索,来自https://chrisyeh 96 . github . io/2017/08/28/derivating-batch norm-back prop . html
- 推导批次标准化的后向传递的梯度。(2018).kevinzakka . github . io . 2018 年 3 月 19 日检索,来自https://kevinzakka . github . io/2016/09/14/batch _ normalization/
- 克拉泽特,F. (2018)。了解反向传递批处理规范化层。krat zert . github . io . 2018 年 3 月 19 日检索,来自https://krat zert . github . io/2016/02/12/understanding-the gradient-flow-through-the-batch-normalization-layer . html
- (2018).Arxiv.org。检索于 2018 年 3 月 19 日,来自arxiv.org/pdf/1502.03…
- NumPy . histogram—NumPy 1.13 版手册。(2018).Docs.scipy.org。检索于 2018 年 3 月 19 日,来自https://docs . scipy . org/doc/numpy-1 . 13 . 0/reference/generated/numpy . histogram . html
- NumPy . random . Weibull—NumPy v 1.13 手册。(2018).Docs.scipy.org。检索于 2018 年 3 月 19 日,来自https://docs . scipy . org/doc/numpy-1 . 13 . 0/reference/generated/numpy . random . Weibull . html # numpy . random . Weibull
- numpy.var — NumPy v1.14 手册。(2018).Docs.scipy.org。检索于 2018 年 3 月 26 日,来自https://docs . scipy . org/doc/numpy/reference/generated/numpy . var . html
- 数据?,H. (2018)。如何用 Python 中的 Matplotlib 绘制一个带有数据列表的直方图?。Stackoverflow.com。检索于 2018 年 3 月 26 日,来自https://stack overflow . com/questions/33203645/how-to-plot-a-histogram-using-matplotlib-in-python-with-a-list-of-data
- numpy.random.randn — NumPy v1.14 手册。(2018).Docs.scipy.org。检索于 2018 年 3 月 27 日,来自https://docs . scipy . org/doc/numpy/reference/generated/numpy . random . randn . html
- 吴,杨,何,王(2018)。群体规范化。Arxiv.org。检索于 2018 年 3 月 27 日,来自 arxiv.org/abs/1803.08…
- 标准化与规范化|数据挖掘博客—【www.dataminingblog.com 。(2007).Dataminingblog.com。检索于 2018 年 3 月 27 日,来自http://www . dataminingblog . com/standardization-vs-normalization/
- 约夫和塞格迪(2015 年)。批量标准化:通过减少内部协变量转移加速深度网络训练。Arxiv.org。检索于 2018 年 3 月 27 日,来自arxiv.org/abs/1502.03…
- 正态分布。(2018).Mathsisfun.com。检索于 2018 年 3 月 27 日,来自https://www . mathsisfun . com/data/standard-normal-distribution . html
理解 PyTorch 中的双向 RNN
快速回顾
Fig 1: General Structure of Bidirectional Recurrent Neural Networks. Source: colah’s blog
双向递归神经网络(RNN)实际上只是将两个独立的递归神经网络放在一起。对于一个网络,输入序列以正常的时间顺序馈送,而对于另一个网络,输入序列以相反的时间顺序馈送。两个网络的输出通常在每个时间步被连接,尽管还有其他选择,例如求和。
这种结构允许网络在每个时间步都具有关于序列的前向和后向信息。这个概念似乎很简单。但是当实际实现一个利用双向结构的神经网络时,就出现了混淆…
困惑
第一个困惑是关于将双向 RNN 的输出转发到密集神经网络的方式。对于普通的 RNNs,我们可以只转发最后一个时间步的输出,下面的图片是我通过谷歌找到的,展示了双向 RNN 的类似技术。
Fig 2: A confusing formulation. Image Source
但是等等…如果我们选择最后一个时间步的输出,反向 RNN 只会看到最后一个输入(图中的 x_3)。它几乎不会提供任何预测能力。
第二个困惑是关于返回隐藏状态。在 seq2seq 模型中,我们需要编码器的隐藏状态来初始化解码器的隐藏状态。直观地说,如果我们只能在一个时间步选择隐藏状态(如 PyTorch ),我们会选择 RNN 刚刚消耗完序列中最后一个输入的状态。但是如果返回时间步长 n (最后一个)的隐藏状态,和以前一样,我们将得到反转 RNN 的隐藏状态,只看到一步输入。
查看 Keras 实现
Keras 为双向 rnn 提供了一个包装器。如果您查看 wrappers.py 中的第 292 行:
用于 Python 的深度学习库。在 TensorFlow、Theano 或 CNTK 上运行。
github.com](github.com/fchollet/ke…)
你会发现,默认情况下,反向 RNN 的输出按时间步长向后排序( n…1 )。当return_sequences为真(默认为假)时,Keras 将反转它。因此,如果我们采用一个时间步长输出,Keras 将在正常 RNN 的时间步长 n 采用一个,在反向 RNN 的时间步长 1 采用一个。这很好地证实了图 2 显示了有缺陷的结构。
在 PyTorch 中它是如何工作的
随着第一个困惑的解决。我们现在感兴趣的是如何在 PyTorch 中正确使用双向 rnn:
上面的笔记本回答了我们遇到的两个困惑(假设batch_first为假):
- 我们要取
output[-1, :, :hidden_size](正常的 RNN)和output[0, :, hidden_size:](反向的 RNN),把它们串联起来,把结果反馈给后续的密集神经网络。 - 返回的隐藏状态是消耗完整个序列后的状态。它们可以被安全地传递给解码器。
(边注)batch_first为假时 PyTorch 中 GRU 的输出形状:
输出(序列长度,批次,隐藏尺寸*数量方向)
h_n (层数*方向数,批次,隐藏大小)
LSTM 的方法类似,但是返回一个附加的单元格状态变量,形状与 h_n. 相同
理解二元交叉熵/对数损失:一个直观的解释
Photo by G. Crescoli on Unsplash
介绍
如果你正在训练一个二进制分类器,很可能你正在使用二进制交叉熵 / 对数损失作为你的损失函数。
有没有想过用这个损失函数到底是什么意思?问题是,考虑到今天的库和框架的易用性,很容易忽略所使用的损失函数的真正含义。
动机
我在寻找一篇博客文章,以一种视觉上清晰简洁的方式解释二元交叉熵 / 日志损失背后的概念,这样我就可以在数据科学务虚会上向我的学生展示它。因为我找不到任何适合我的目的的,所以我自己承担了写它的任务:-)
一个简单的分类问题
让我们从 10 个随机点开始:
x = [-2.2, -1.4, -0.8, 0.2, 0.4, 0.8, 1.2, 2.2, 2.9, 4.6]
这是我们唯一的特色 : x 。
Figure 0: the feature
现在,让我们给我们的点分配一些颜色:红色和绿色。这些是我们的标签。
Figure 1: the data
所以,我们的分类问题非常简单:给定我们的特征x,我们需要预测它的标签** : 红色或者绿色。**
既然这是一个二元分类,我们也可以把这个问题提出来:“点是绿色的”或者更好一点,“点是绿色的的概率是多少”?理想情况下,绿点的概率为 1.0 (绿色),而红点的概率为 0.0 (绿色)。
在此设置中,绿点属于正类 ( 是,为绿色),而红点属于负类 ( 否,为非绿色)。
如果我们拟合一个模型来执行这个分类,它将预测我们每一个点都是绿色的概率。给定我们所知道的点的颜色,我们如何评估预测的概率有多好(或多差)?这就是损失函数的全部目的!对于不良预测,它应该返回高值,对于良好预测,它应该返回低值。
对于像我们的例子一样的二元分类,典型的损失函数是二元交叉熵 / 对数损失。
损失函数:二元交叉熵/对数损失
如果你查找这个损失函数,你会发现:
Binary Cross-Entropy / Log Loss
其中 y 为的标号(对于 绿色点为 1 ,对于 红色点为0****)p(y)为所有 N 点为绿色的预测概率。
阅读这个公式,它告诉你,对于每一个绿色点( y=1 ),它将 log(p(y)) 加到损失上,即它是绿色的的 log 概率。反之,它为每个红色点( y=0 )加上 log(1-p(y)) ,即它为红色的 log 概率。当然,不一定很难,但也没有那么直观…
况且熵跟这一切有什么关系?为什么我们首先采用概率对数?这些都是有效的问题,我希望在下面的“展示数学”部分回答它们。
但是,在进入更多公式之前,让我给你看一个上面公式的可视化表示…
计算损失——可视化方法
首先,让我们将分门别类,正或负,如下图:
Figure 2: splitting the data!
现在,让我们训练一个逻辑回归来对我们的点进行分类。拟合回归是一条s 形曲线,代表对于任何给定的x点为绿色的概率。看起来是这样的:
Figure 3: fitting a Logistic Regression
那么,对于所有属于正类 ( 绿)的点,我们的分类器给出的预测概率是多少?这些是下的绿色条s 形曲线,在 x 坐标处对应的点。
Figure 4: probabilities of classifying points in the POSITIVE class correctly
好的,到目前为止,一切顺利!负类中的点呢?记住, 下的绿色条s 形曲线代表给定点为绿色的概率。那么,给定点红的概率是多少?上方的**红色条s 形曲线*,当然:-)***
Figure 5: probabilities of classifying points in the NEGATIVE class correctly
将所有这些放在一起,我们最终会得到这样的结果:
Figure 6: all probabilities put together!
条形代表与每个点的相应真实类别相关的预测概率!
好了,我们有了预测的概率…是时候通过计算二元交叉熵* / 日志损失来评估**了!*
这些概率就是我们所需要的全部,所以,让我们去掉 x 轴并使棒条彼此相邻:
Figure 7: probabilities of all points
嗯,挂杆已经没有多大意义了,所以让我们重新定位它们:
Figure 8: probabilities of all points — much better :-)
因为我们试图计算一个损失,我们需要惩罚坏的预测,对吗?如果真类关联的概率为 1.0 ,我们需要它的损失为零。反之,如果那个概率是 低,比如说 0.01 ,我们需要它的损失是巨大!
事实证明,采用概率的*(负)对数非常适合我们的目的(由于 0.0 和 1.0 之间的值的对数是负的,我们采用负对数来获得损失的正值)。***
实际上,我们使用 log 的原因来自于交叉熵的定义,请查看下面的“展示数学”部分了解更多细节。
下面的图给了我们一个清晰的画面——随着真实等级的预测概率变得更接近零,损失呈指数增长:
Figure 9: Log Loss for different probabilities
很公平!让我们取概率的(负)对数——这些是每个点对应的损失。
最后,我们计算所有这些损失的平均值。
Figure 10: finally, the loss!
瞧!我们已经成功计算出这个玩具例子的二元交叉熵 / 对数损失。是 0.3329!
给我看看代码
如果您想再次检查我们找到的值,只需运行下面的代码并自己查看:-)
给我看看数学(真的?!)
玩笑归玩笑,这篇文章不是旨在非常数学化…但是对于那些想要理解熵、对数在所有这些中的作用的读者,我们开始吧:-)
如果你想更深入地了解信息论,包括所有这些概念——熵、交叉熵以及更多更多——请查看克里斯·奥拉的 帖子 查看,它非常详细!
分配
先说我们的积分分布。由于 y 代表我们点的类(我们有 3 个红点和 7 个绿点,这就是它的分布,姑且称之为 q(y) ,看起来像是:
Figure 11: q(y), the distribution of our points
熵
熵是与给定分布 q(y) 相关的不确定性的度量。
如果我们所有的点都是绿色会怎么样?的不确定性会是什么样的分布?零对吧?毕竟,一个点的颜色是毫无疑问的:它总是绿色!所以,熵为零!
另一方面,如果我们确切地知道一半的点是绿色而的另一半是、红色会怎么样?这是最糟糕的情况,对吗?我们在猜测一个点的颜色上绝对没有优势:这完全是随机的!在这种情况下,熵由下面的公式给出(我们有两类(颜色)——红色或绿色——因此, 2 ):
Entropy for a half-half distribution
对于在之间的每隔一种情况,我们可以计算分布的熵,就像我们的 q(y) 一样,使用下面的公式,其中 C 是类的数量:
Entropy
所以,如果我们知道一个随机变量的真实分布,我们就可以计算出它的熵。但是,如果是这样的话,为什么首先要费心训练一个分类器?毕竟,我们知道真实的分布…
但是,如果我们不呢?我们能否尝试用一些其他分布来近似真实分布,比如说 p(y) ?我们当然可以!:-)
交叉熵
让我们假设我们的分 跟随这个其他分布 p(y) 。但是我们知道他们是从真 ( 未知)分布 q(y) 实际上来的对吧?
如果我们像这样计算熵,我们实际上是在计算两个分布之间的交叉熵:
Cross-Entropy
如果我们奇迹般地将与* p(y) 到 q(y) 完美匹配,那么交叉熵 和 熵 的计算值也将与匹配。*
因为这很可能永远不会发生,交叉熵的值将大于对真实分布计算的熵。
Cross-Entropy minus Entropy
原来,交叉熵和熵之间的差异有一个名字…
库尔贝克-莱布勒散度
Kullback-Leibler 散度,或简称为“ KL 散度 ,是两个分布之间相异度的度量:
KL Divergence
这意味着,p(y)越接近 q(y) ,越低,散度,因此,交叉熵,将是。
所以,我们需要找一个好的 p(y) 来用……但是,这是我们分类器应该做的,不是吗?!的确如此!它寻找最可能的 p(y) ,也就是最小化交叉熵的那个。
损失函数
在其训练期间,分类器使用其训练集中的 N 个点中的每一个来计算交叉熵损失,有效地拟合分布 p(y) !由于每个点的概率是 1/N,交叉熵由下式给出:
Cross-Entropy —point by point
还记得上面的图 6 到 10 吗?我们需要在与每个点的真实类别相关联的概率之上计算交叉熵。这意味着使用绿色条用于正级 ( y=1 )中的点,使用红色悬挂条用于负级 级 ( y=0 )中的点,或者从数学上来说:**
Mathematical expression corresponding to Figure 10 :-)
最后一步是计算两个类别中所有点的平均值,正值和负值:
Binary Cross-Entropy — computed over positive and negative classes
最后,通过一点点操作,我们可以从正类或负类中取任意一点,在相同的公式下:
Binary Cross-Entropy — the usual formula
瞧吧!我们回到了原始公式用于二元交叉熵/对数损失 :-)
最后的想法
我真心希望这篇文章能够在一个经常被认为是理所当然的概念上闪耀一些新的光芒,这个概念就是二元交叉熵作为损失函数。此外,我也希望它能向你展示一点点机器学习和信息论是如何联系在一起的。
2022 年 7 月 10 日更新:我刚刚在 YouTube 上发布了一个视频,里面有这篇文章的动画版本——来看看吧!
Understanding Binary Cross-Entropy / Log Loss in 5 Minutes!
如果你有什么想法、意见或问题,欢迎在下方留言评论或联系我 推特 。
如何理解您的聚类结果
我正与全球许多客户合作实施各种数据科学项目。有时,客户希望进行群集,而我试图避免这种情况。我遵循一个简单的经验法则:
如果你能被监督,那就去被监督。
原因很简单。每个分析都有超参数。这些都需要确定。在有监督的情况下,优化什么是相当直接的:商业价值。在无人监督的情况下,你常常很难找到正确的衡量标准。当然,有很多方法可以衡量你的聚类质量,比如戴维斯-波尔丁指数或者轮廓系数。但是它们与我的业务目标不一致,因此不好。
原来很多分割问题都可以转化为分类问题。这样做总是更可取的。只有在极少数情况下你不能。在这种情况下,您需要使结果易于理解,以符合您的业务目标。以下是我让聚类结果易于解释的技巧。
技巧 1——把它变成一个特征选择问题
通常在数据分析中,您需要能够将业务问题映射到方法。在您的案例中,问题是:*什么最能描述 cluster_0?*或者换句话说:【cluster _ 0 与其他所有产品的区别是什么?这其实可以解释为一个特征选择问题。您想知道哪些特征具有区分聚类的能力。我建议以一对一的方式来做这件事,因为这回答了直接的问题。
Data on two dimensions grouped. A feature selection technique would identify that both dimensions are important to distinguish the classes.
通常的特征选择技术,如包装器或过滤器方法,提供了一系列特征及其重要性。那已经相当不错了!
在众所周知的泰坦尼克号数据集上,我们可以得到“年龄、性别和乘客级别”作为最重要的属性。这使得我们可以将 cluster_0 重命名为:“年龄-性别-乘客级别”。这里的问题是,虽然你发现了重要的因素,但你没有指明方向。这是一群老人吗?或者说是年轻女性?我们可以通过查看质心坐标来更深入地挖掘,并将它们放入透视图中。但是有一个更简单的方法:决策树!
诀窍 2——决策树!
决策树是最容易理解的机器学习模型之一。通常它们用于解决分类问题。我们将使用它们来首先区分我们的 cluster_0 和所有其他聚类。
The Decision Tree can distinguish between the classes and also tell you on the exact values to look at.
第二步是分析决策树分支。所有预测我们的 cluster_0 的分支都可以作为描述。我们可以得到像这样的分支:
年龄< 20,乘客阶级=第一,性别=女。
这很好地描述了我们 cluster_0!
你也可以看看我们的描述有多精确,通过看树的训练精度。你需要平衡结果的质量和可解释性。您可以通过使用修剪来实现这一点。我建议在树的深处进行硬切割。根据我的经验,最多 4 到 5 次就能得到好的结果。人类经常高估他们解释模型的能力。对于决策树,他们通常把所有割的重要性等同起来,而他们需要在上下文和层次结构中进行解释。
理解编译器——面向人类(第 2 版)
编程语言如何工作
从内部理解你的编译器可以让你有效地使用它。在这个按时间顺序排列的大纲中,浏览编程语言和编译器是如何工作的。许多链接、示例代码和图表有助于您的理解。
作者说明
*理解编译器——人类版(第 2 版)*是我第二篇关于 Medium 的文章的后续,有超过 21,000 的浏览量。我很高兴我能对人们的教育产生积极的影响,并且我很高兴能根据我从最初的文章中得到的信息给带来一个完整的重写。
你是否点击了绿色的运行按钮,但并不真正知道引擎下面发生了什么?你想知道一个…
medium.com](medium.com/@CanHasComm…)
我选择了铁锈作为这部作品的主要语言。它冗长、高效、现代,而且从设计上看,对于编译器来说非常简单。我喜欢使用它。【www.rust-lang.org/
这篇文章的目的是保持读者的注意力,而不是有 20 页令人麻木的阅读。文本中有许多链接,将引导您找到更深入了解您感兴趣的主题的资源。大多数链接会将你引向维基百科。
欢迎在底部的评论区提出任何问题或建议。感谢您的关注,希望您喜欢。
介绍
什么是编译器
总之,你所谓的编程语言实际上只是一种叫做编译器的软件,它可以读取文本文件,对其进行大量处理,并生成二进制文件。由于计算机只能读取 1 和 0,而人类比二进制写得更好,编译器被设计成将人类可读的文本转换成计算机可读的机器码。
编译器可以是将一种文本翻译成另一种文本的任何程序。例如,这里有一个用 Rust 编写的编译器,它把 0 变成 1,把 1 变成 0:
While this compiler doesn’t read a file, doesn’t generate an AST, and doesn’t produce binary, it is still considered a compiler for the simple reason that it translates an input.
编译器做什么
简而言之,编译器获取源代码并生成二进制代码。因为从复杂的、人类可读的代码直接转换成 1 和 0 是相当复杂的,所以编译器在程序运行之前有几个处理步骤要做:
- 读取你给它的源代码的单个字符。
- 将字符分类为单词、数字、符号和运算符。
- 获取排序后的字符,通过将它们与模式进行匹配来确定它们试图执行的操作,并生成操作树。
- 迭代上一步中在树中进行的每个操作,并生成等效的二进制文件。
虽然我说编译器立即从操作树进入二进制,但它实际上生成汇编代码,然后汇编/编译成二进制。汇编就像一个更高级的、人类可读的二进制文件。更多了解什么是 这里是 。
什么是口译员
解释器很像编译器,因为它们阅读并处理语言。不过,解释器跳过代码生成,执行 AST 实时 。对解释器来说,最大的好处是在调试期间开始运行程序所花费的时间。编译器在程序执行前可能要花几秒到几分钟的时间来编译程序,而解释器不编译就立即开始执行。解释器最大的缺点是它需要安装在用户的计算机上,然后程序才能执行。
本文主要指的是编译器,但是应该清楚它们之间的区别以及编译器之间的关系。
1.词汇分析
第一步是一个字符一个字符地分割输入。这一步被称为词法分析,或标记化。主要的想法是,我们将字符组合在一起,形成我们的单词、标识符、符号等等。词法分析大多不处理像求解2+2这样的逻辑问题——它只会说有三个记号:一个数字:2,一个加号,然后是另一个数字:2。
假设您正在编写一个类似于12+3的字符串:它将读取字符1、2、+和3。我们有各自独立的角色,但我们必须把它们组合在一起;分词器的主要任务之一。例如,我们将1和2作为单独的字母,但是我们需要将它们放在一起,并作为单个整数进行解析。+也需要被识别为加号,而不是它的文字字符值——字符代码43。
如果您可以看到代码,并以这种方式使其更有意义,那么下面的 Rust tokenizer 可以将数字分组为 32 位整数,并将加号作为Token值Plus。
[## 铁锈操场
play.rust-lang.org](play.rust-lang.org/?gist=070c3…)
您可以点击 Rust Playground 左上角的“运行”按钮,在您的浏览器中编译并执行代码。
在编程语言的编译器中,词法分析器可能需要几种不同类型的标记。例如:符号、数字、标识符、字符串、运算符等。知道需要从源代码中提取哪种单独的标记完全取决于语言本身。
Example of C source code that has been lexically analyzed, and its tokens printed.
2.从语法上分析
解析器确实是语法的核心。**解析器获取由词法分析器生成的标记,尝试查看它们是否符合特定的模式,然后将这些模式与像调用函数、调用变量或数学运算这样的表达式相关联。**解析器是真正定义语言语法的东西。
说int a = 3和a: int = 3的区别在于解析器。解析器决定语法应该是什么样子。它确保括号和花括号是平衡的,每个语句都以分号结束,并且每个函数都有一个名称。当标记不符合预期模式时,解析器知道什么时候事情没有按照正确的顺序进行。
你可以编写几种不同类型的 解析器 。其中最常见的是自上而下,递归下降解析器。递归下降解析是最容易使用和理解的解析之一。我创建的所有解析器例子都是基于递归下降的。
解析器解析的语法可以用语法来概括。像 EBNF 这样的语法可以描述像12+3这样的简单数学运算的解析器:
EBNF grammar for simple addition and subtraction expressions.
记住语法文件是 而不是 解析器,而是解析器工作的概要。你可以围绕这样的语法构建一个解析器。它将由人类使用,比直接查看解析器的代码更容易阅读和理解。
该语法的解析器将是expr解析器,因为它是基本上所有内容都与之相关的顶级项目。唯一有效的输入必须是任何数字,加或减,任何数字。expr期待一个additive_expr,这是大加减法出现的地方。additive_expr先预计一个term(一个数字),然后加减,再一个term。
Example AST generated for parsing 12+3.
*解析器在解析时生成的树称为 抽象语法树 **,简称 AST。*AST 包含所有的操作。解析器不计算操作,它只是按照正确的顺序收集它们。
我添加了之前的 lexer 代码,这样它就能匹配我们的语法,并能生成如图所示的 ASTs。我用注释// BEGIN PARSER //和// END PARSER //标记了新解析器代码的开头和结尾。
*[## 铁锈操场
play.rust-lang.org](play.rust-lang.org/?gist=205de…)*
我们实际上可以走得更远。比方说,我们希望支持没有运算的数字输入,或者添加乘法和除法,甚至添加优先级。通过快速修改语法文件,并在解析器代码中反映出来,这一切都是可能的。
The new grammar.
*[## 铁锈操场
play.rust-lang.org](play.rust-lang.org/?gist=1587a…)*
Scanner (a.k.a. lexer) and parser example for C. Starting from the sequence of characters "if(net>0.0)total+=net*(1.0+tax/100.0);", the scanner composes a sequence of tokens, and categorizes each of them, e.g. as identifier, reserved word, number literal, or operator. The latter sequence is transformed by the parser into a syntax tree, which is then treated by the remaining compiler phases. The scanner and parser handles the regular and properly context-free parts of the grammar for C, respectively. Credit: Jochen Burghardt. Original.
3.生成代码
代码生成器接受一个 AST 并发出代码或汇编中的等价代码。代码生成器必须以递归下降的顺序遍历 AST 中的每一项——很像解析器的工作方式——然后发出等价的代码。
* [## 编译器资源管理器- Rust (rustc 1.29.0)
pub fn main(){ let a = 10 * 3;}
godbolt.org](godbolt.org/z/K8416_)
如果打开上面的链接,可以看到左边的示例代码生成的程序集。汇编代码的第 3 行和第 4 行显示了编译器在 AST 中遇到常量时是如何为它们生成代码的。
god bolt 编译器资源管理器是一款优秀的工具,允许你用高级编程语言编写代码,并查看其生成的汇编代码。您可以用它来看看应该生成什么样的代码,但是不要忘记在您的语言的编译器中添加优化标志,看看它有多聪明。( *-O* 为铁锈)
如果您对编译器如何将局部变量保存到 ASM 的内存中感兴趣,本文(“代码生成”一节)将详细解释堆栈。大多数情况下,当变量不在本地时,高级编译器会在堆上为变量分配内存,并将它们存储在堆上,而不是堆栈上。你可以在这个 StackOverflow 回答中阅读更多关于存储变量的内容。
因为组装是一个完全不同的复杂的主题,所以我不会详细讨论它。我只想强调代码生成器的重要性和作用。此外,代码生成器不仅仅可以生成汇编。 Haxe 编译器有一个 后端 可以生成超过六种不同的编程语言;包括 C++、Java 和 Python。
后端指编译器的代码生成器或评估器;因此,前端是词法分析器和语法分析器。还有一个中间端,它主要与优化和 IRs 有关,这将在本节后面解释。后端大多与前端无关,只关心自己收到的 AST。这意味着一个人可以为几个不同的前端或语言重用同一个后端。臭名昭著的 GNU 编译器合集 就是如此。
我没有比我的 C 编译器后端更好的代码生成器的例子了;你可以在这里找到。
生成汇编后,它将被写入一个新的汇编文件(.s或.asm)。然后,该文件将通过汇编器传递,汇编器是用于汇编的编译器,它将生成等价的二进制文件。然后,二进制代码将被写入一个名为目标文件的新文件中(.o)。
目标文件是机器代码,但不可执行。为了使它们成为可执行的,目标文件需要被链接在一起。链接器获取这个通用机器码,并使其成为可执行文件,一个共享库,或者一个静态库。更多关于联系人 这里 。
链接程序是根据操作系统而变化的实用程序。一个单独的第三方链接器应该能够编译后端生成的目标代码。在制作编译器时,应该不需要创建自己的链接器。
*一个编译器可能有一个中间表示,或者 IR。**IR 是为了优化或翻译成另一种语言而无损地表示原始指令。*IR 不是原始源代码;IR 是为了在代码中找到潜在的优化而进行的无损简化。循环展开和矢量化使用 IR 完成。更多与 IR 相关的优化示例可以在本 PDF 中找到。
结论
当你理解了编译器,你就能更有效地使用你的编程语言。也许有一天你会对制作自己的编程语言感兴趣?我希望这对你有帮助。
资源和延伸阅读
- craftinginterpreters.com/—指导你用 C 和 Java 创建一个解释器。
- norasandler.com/2017/11/29/…——可能是对我最有益的“编写编译器”教程。
- 我的 C 编译器和科学计算器解析器可以在这里和这里找到。
- 另一种类型的解析器的例子,称为优先攀爬解析器,可以在这里找到。致谢:韦斯利·诺里斯。*
理解合成模式产生网络(上)
全面解释 CPPNs 背后的理论
[3]
在过去的两年里,我一直在研究复合模式产生网络(CPPN),这是一种在[1]中提出的扩充拓扑神经网络。然而,在我的整个研究中,我总是对 CPPNs 背后的一些概念和理论感到困惑,我努力理解它们是如何工作的。虽然网上有一些 CPPN 的开源版本,但在我的研究中,我想为定制目的构建自己的实现,这比我最初预期的要复杂得多。因此,我想对 CPPN 背后的理论以及如何实现它们进行全面的解释,以便像我一样与 CPPN 斗争的每个人都可以获得这样的资源。这篇文章将分成两个独立的部分。您现在正在阅读的第一部分将关注 CPPN 背后的理论以及它们是如何在科学研究中使用的,而第二部分将关注用 Python 实际实现 CPPN。
这是什么鬼东西?CPPNs 理论
在[1]中提出,CPPNs 是对以前提出的神经网络的扩展,称为 NEAT [2]。这些类型的神经网络非常相似,所以我将概述 NEAT 背后的一些理论,然后快速说明 CPPNs 的不同之处(别担心,它们几乎是相同的)。首先,NEAT 是一个用遗传算法进化的扩充拓扑神经网络。对这意味着什么的解释可以分成两个相关的概念:进化/遗传算法和扩充拓扑网络。
遗传算法
进化/遗传算法(GA)用于训练和优化神经网络的参数,类似于反向传播或爬山。然而,GA 不是使用导数来总是朝着改善损失的方向调整网络的权重,而是通过计算机版本的自然选择来找到最优的权重集,从达尔文主义和适者生存中汲取灵感。通过创建一个巨大的可能权重矩阵“群体”(通常约 25–100,但这可以变化),g a 可以评估群体中每个“个体”的损失,每个个体由一个唯一的权重矩阵表示。使用该信息,最佳权重矩阵然后被变异,彼此交叉,并被选择以前进到下一个“代”。通过在选择过程的许多代或迭代中重复该过程,GA 可以创建最小化损失的权重矩阵的最终群体,从而产生许多可能的性能最优的权重矩阵。
变异是通过随机扰动单个网络的权重来执行的,而交叉是通过将一个网络的权重与另一个网络的权重部分交换来执行的。这些概念对我来说总是有点困惑,所以这里是两组权重交叉和变异的直观表示:
Crossing Over Weight Matrices (found at github.com/lagodiuk/ev…)
从上图中可以看出,在交叉过程中,很大一部分权重在权重矩阵之间交换,从而产生两个不同于原始“父”权重集的“子”权重集。在变异过程中,一些权重在随机方向上被扰动,以使“子”权重集与原始权重集略有不同。
这种变异、交叉和选择生存的最佳权重矩阵的过程重复许多代,直到你剩下最佳权重矩阵的最终群体。使用这种方法,只有最好的解决方案才能进入下一代,以便进一步变异、交叉和探索。因此,随着时间的推移,使用达尔文的适者生存原则来优化种群。如果你很好奇,想了解更多关于 GA 的知识,我鼓励你查看这个链接,它比我在这里给出的解释要深入得多。
扩充拓扑神经网络
通常,遗传算法在一组结构相同的网络上工作。扩充拓扑神经网络也利用 GA,但是它们允许 GA 在进化期间操纵神经网络的结构(不仅仅是权重),从而允许找到神经网络的最佳结构/拓扑。在进化之初,所有神经网络都是用完全连接到输出的输入来初始化的,没有隐藏节点——这是一个非常简单的最小结构。然而,随着拓扑的增加,随着神经网络的权重“进化”,网络的结构同时被优化——这在典型的 GA 优化中不会发生。为了探索可能的网络拓扑,当允许扩充拓扑时,GA 通过添加隐藏节点、添加更多的连接、甚至删除群体中某些拓扑内的现有连接来增加网络的复杂性。因此,虽然网络在进化之初结构简单,但它们的拓扑结构会进化到产生更高的性能,从而允许训练创建更复杂的网络结构。扩充拓扑的概念是 NEAT/CPPN 背后的核心思想,在我看来,这也是模型如此强大的原因。下图直观地展示了在进化过程中拓扑突变是如何应用于网络的:
Mutating Neural Network Structure [2]
在上图中,一个现有的连接被拆分为两个新的连接,并且在这两个连接之间添加了一个节点。除了这种类型的拓扑突变(称为节点突变),NEAT 还有向网络中添加连接的拓扑突变(连接添加突变)和从网络中删除连接的拓扑突变(连接删除突变)。这种拓扑扩充导致最终的网络群体在结构上非常多样化,但都完成类似的任务-群体中的每个网络可能具有不同的拓扑,以不同的方式解决问题。
CPPN 和 NEAT 的区别?
既然您对 NEAT 有了很高的理解,您可能会好奇为什么我要写一个与标题中提到的(CPPN)完全不同的网络类型,但是这两者之间的区别非常简单。CPPN 允许每个节点包含从可能的激活功能列表中选择的唯一激活功能,而不是在每个节点中使用相同的激活功能。该激活列表可能包括 sin、cos、tanh、sigmoid、relu 或您可能想要包括的任何其他激活函数。允许神经网络包含许多不同的激活函数,反过来,允许它对展示所有这些不同激活的属性的函数进行建模,并创建模式化的、对称的和独特的输出。由于 CPPN 能够创建如此复杂和有趣的几何图形,因此它的目的是生成各种 2D 和 3D 形状。CPPN 的输入是像素的 x 和 y(甚至可能是 z)位置,它输出该输入位置的像素值(在[0,1]或[白色、黑色]之间)。对 2D 或 3D 空间内的每个可能的像素位置重复这种激活,以产生完整的输出形状。下图显示了 CPPN 的典型激活:
2D CPPN Activation [1]
在该图像中,可以观察到像素的 x 和 y 位置被输入到 CPPN 中,并且在该 x 和 y 位置的像素的强度值被输出。CPPN 中的每个节点都包含一个独特的激活函数,该函数根据输入值以不同方式影响输出值。通过对 2D 或 3D 空间内的每个像素位置执行 CPPN 的激活,可以创建有趣的结构和图案,如下所示:
CPPN Black and White Output [1]
CPPN Color Output (found on picbreeder.com)
从上面的输出中可以看出,CPPN 产生规则和对称形状的能力非常适合于发展类似艺术品、活生物体和许多其他有趣几何形状的结构。在我看来,这样的应用和能力非常有趣,这也是为什么我觉得研究 CPPNs 如此有趣。
演进中的 CPPNs 的细节
在进化开始时,cppn 的群体以不包含隐藏节点的简单结构初始化,但是,由于 cppn 的扩充拓扑特征,随着进化的继续和拓扑突变的应用,群体变得越来越复杂。在每一代中,额外的节点和连接被添加到网络结构中,从而产生越来越复杂且更适于解决预期问题的网络。然而,认识到群体中的所有网络不会同时突变是非常重要的,因此,每个网络可能具有与群体中其他 CPPNs 不同的拓扑结构。网络拓扑之间缺乏一致性使得 cppn 的发展变得有些独特和困难,因此我认为有必要解释一些 cppn 通常如何发展以及如何处理这种缺乏结构一致性的细节。
历史标记
每次一个新的连接被添加到 CPPN 的拓扑结构中,它都会被赋予一个“历史标记”或“创新号”,这只是一个特定连接所特有的整数。添加到群体中每个 CPPN 的每个连接都被赋予一个唯一的历史标记。随着连接在整个进化过程中的增加,全局计数器被维护并递增,使得分配的每个历史标记都是唯一的。这样的历史标记允许你理解人口中每个联系的历史和血统。此外,当结构在进化过程中相互交叉时,人们可以使用历史标记来观察哪些连接具有相似的进化血统。通过对添加的连接执行这种简单的簿记,进化 CPPNs 的几个方面被大大简化。在下图中,你可以观察到一个连接列表及其对应的创新编号(创新编号和历史标记是一回事!).
List of Connections [2]
请注意,上图中的每个连接都被分配了一个创新号,并且每个连接的创新号都是唯一的。这允许您确定群体中的哪些网络共享共同的连接,从而从相同的结构中派生出来。
cppn 的交叉
如前所述,用遗传算法进化神经网络的一部分涉及交叉——在网络之间交换权重值以创建新的网络。对于遗传算法神经网络的典型进化,交叉是非常简单的。下图显示了相同拓扑网络之间常见的交叉类型:
Different Types of Crossover
对于扩充拓扑 CPPNs 的发展,由于两个网络之间的权重数目可能不相同,交叉变得稍微复杂。然而,创新数字的使用大大简化了这一过程。不是试图找到一种特殊的方法来决定哪些权重相互交叉,而是只交叉具有相同创新数的权重。因此,可以简单地通过在两个网络之间找到具有相等新息数的连接并交换它们的权重来执行交叉,从而产生 CPPNs 之间的伪一致交叉。
通过物种形成保护多样性
随着拓扑突变(新的连接和节点)被添加到群体中的 CPPNs 的拓扑中,这种突变通常会导致适应度的初始下降。这种适应度的降低是由这样的事实引起的,即在初始化时放入网络的新权重是随机的,并且尽管拓扑变化可以提供更优的结构,但是在网络实现其全部潜力之前必须训练这样的权重。网络中的这种新的随机权重通常会导致网络的适应性最初下降,然后在权重被训练后提高。如果我们不保护这样的网络不被选择,允许它们有时间训练并实现它们的最大适应度,它们将被 GA 立即从种群中淘汰,这将阻止 CPPNs 探索更复杂的结构。幸运的是,这样的新结构可以通过一个叫做“物种形成”的重要概念得以保存。
就个人而言,物种形成是我在研究 cppn 时最难理解的概念,但没有它,cppn 就无法有效进化。物种形成背后的基本概念是,当被选择用于下一代时,cppn 应该只与具有相似拓扑结构的 cppn 竞争。这样,如果通过变异创建了具有新的更复杂拓扑的网络,它将不必与已经达到其最大适应度的不太复杂的拓扑竞争,从而给更复杂的网络时间来训练和提高其适应度。拓扑的相似性通过比较网络之间的新息数来评估——如果网络有许多具有相同新息数的连接,则它们更相似,反之亦然。使用这样的信息,当执行选择时,基于新息数距离度量,CPPNs 被分成几个“种类”,或者具有相似拓扑的不同组。一旦这些物种形成,对每个物种分别进行选择,允许 CPPNs 只与它们物种的其他成员竞争。这种方法允许具有新的不同结构的 CPPNs 存在足够长的时间用于训练和优化,以发现这种拓扑是否是最佳的。
CPPN 演进总结
如果你理解了发展 cppn 的所有这些特殊细节,你就对 cppn 背后的理论有了很好的理解,并且可能理解使用 cppn 发表的大多数论文和项目。我相信这张图很好地总结了这些细节:
Evolution Details [2]
如上图所示,要进化的 CPPNs 的群体从最低限度开始——完全连接,在任何结构中都没有隐藏节点。随着进化的进行,拓扑和重量突变被应用于 CPPNs,这允许它们生长,在结构上变得更复杂,并优化它们的参数。当新的连接被添加到 CPPNs 中时,它们每个都被赋予一个唯一的历史标记(或创新号),允许识别相似的连接。然后,这些历史标记可以用于创建不同网络拓扑之间的距离/相似性度量,这允许基于它们的网络结构将 CPPNs 分成不同的物种。通过对每个物种分别进行选择,允许新的 CPPN 拓扑在选择和进化中存活足够长的时间,以探索它们的能力,从而允许找到并优化最佳网络结构。
涉及 CPPN 的项目/研究示例
既然你已经理解了 cppn 是如何工作的,以及它们能做的很酷的事情,那么看看一些用 cppn 完成的研究项目可能会有所帮助,其中一些项目在计算进化领域相当有影响力。
pic breader 网站
在研究 CPPNs 时面临的最初问题之一是,在许多情况下,很难确定某个网络的适合度。每个 CPPN 输出一个独特的形状或图像,给这样的输出分配一个适合度是非常主观的——用户必须根据他们的偏好来确定适合度。Picbreeder.com 是一个作为研究项目开发的网站,完全基于用户的偏好,大规模地众包 CPPNs 的演变。使用 CPPNs 编码许多不同的图像,该网站允许用户选择他们喜欢的图像,并通过不断选择图像的变异版本来进一步进化它们。进化甚至可以在以后由不同的用户在相同的图像上继续。这样一个平台允许 CPPNs 完全基于主观用户输入,进化了令人难以置信的多代,这导致了各种有趣输出的集体创造。以下是网站上一些图片的例子:
Top Images on picbreeder.com
正如上面所看到的,一些非常有趣和令人印象深刻的图像是通过这样的合作进化创造出来的。此外,这项研究中的进化结果有效地证明了 CPPNs 的许多有价值的特性,使它们变得有用和有趣。例如,考虑下面一组也是使用 picbreeder 开发的图像:
Living Organism Images from picbreeder.com
从上面的图像中可以清楚地看到,CPPNs 可以产生类似于活生物体的对称和规则的几何形状,这是它们产生的主要动机之一。因此,picbreeder.com 进化的结果巩固了 CPPNs 在实现这一目的方面的有效性。
软体机器人进化
已经发表了许多论文来探索具有图像的 CPPNs 的 2D 应用,但是我发现许多最有趣的应用涉及 3D 形状的产生。CPPNs 最突出的 3D 应用之一是研究由 CPPNs 间接编码以实现最大行驶距离的软机器人的进化。现在,你可能在想“等等,到底什么是软体机器人”,所以这里有一张本文中软体机器人的快速图片:
Soft Robot Example [3]
在这项研究中,软机器人是通过向 3D 空间添加材料来创建的,这些材料可以以不同的方式扩展和收缩(因此是“软”机器人),这使得机器人像生命体一样移动。这些软机器人是通过用不同类型的体素(3D 像素)填充 3D 空间(或者没有体素/空白空间)来创建结构而创建的。每种类型的体素(由不同的颜色表示)不同地收缩或松弛,从而当配对在一起时,体素的运动可以产生结构的整体运动。这种结构是通过查询输出空间中每个可能的体素位置处的 CPPN 以产生每个体素的类型和存在的输出来创建的。在这项研究中,该模型还使用距空间中心的距离(d)作为输入,但我发现对位置输入值进行归一化可以减少网络中的参数数量,并且表现类似。如果您仍然有一点困惑,这里是 CPPNs 如何在这个项目中用于创建软机器人输出的可视化:
Creating a Soft Robot with CPPN [3]
每个结构都通过模拟来评估,模拟确定了每个软机器人在给定时间内移动的距离。这项研究成功地进化出了能够移动最大距离的 CPPNs,有趣的是,这些进化的结构中有许多在移动中类似于活的有机体(如果你感兴趣,请查看这个视频)。).此外,当这个问题试图只使用软机器人的直接编码(直接存储结构中每个体素的值)并用 GA 进化时,它根本不起作用,从而证明了 CPPNs 在创建逼真的功能性生物方面的有用性和有效性。以下是这项研究中进化出的一些最好的软体机器人的图片:
Set of Results from Soft Robot Evolution [3]
其他论文/研究
有很多论文探讨了 CPPNs 的有效性和功能,但是写这些文章可能会花费很长时间(我相信您已经厌倦了阅读)。因此,以下是我在研究过程中发现的一些关于 CPPNs 的有用且有趣的额外论文:
结论
非常感谢你的阅读!我希望您现在对 CPPNs 以及如何使用它们有了更好的理解。如果你很好奇,想了解更多关于 CPPN 的知识,我真的鼓励你访问 NEAT 的网页,它是由 NEAT 的创建者创建的,允许研究人员分享关于 NEAT 的想法和方法(记住,NEAT 几乎与 CPPN 相同,所以大多数想法/技巧都适用于两者!).此外,请随时在 LinkedIn上联系我或者在 GitHub 上关注我。
引文
[1] K. O .斯坦利一种新的发展抽象。遗传编程和进化机器,2007。
[2] K. O .斯坦利和 r .米库拉宁。通过扩充拓扑进化神经网络。进化计算,2002。
[3] Cheney,n .,MacCurdy,r .,Clune,j .和 Lipson,h.《解开束缚的进化:用多种材料和强大的生成编码进化出柔软的机器人》。遗传和进化计算会议论文集。纽约计算机学会,2013 年。
理解混淆矩阵
Understanding Confusion Matrix [Image 1] (Image courtesy: My Photoshopped Collection)
当我们得到数据后,经过数据清理、预处理和争论,我们做的第一步是把它输入到一个优秀的模型中,当然,得到概率输出。但是坚持住!我们到底如何衡量我们模型的有效性。效果越好,性能越好,这正是我们想要的。这也是混淆矩阵引人注目的地方。混淆矩阵是机器学习分类的性能度量。
本博客旨在回答以下问题:
- 混淆矩阵是什么,为什么需要它?
- 如何计算二类分类问题的混淆矩阵?
今天我们就来一劳永逸的了解一下混淆矩阵。
什么是混淆矩阵,为什么你需要它?
嗯,这是对机器学习分类问题的性能测量,其中输出可以是两个或更多个类。这是一个包含预测值和实际值的 4 种不同组合的表格。
Confusion Matrix [Image 2] (Image courtesy: My Photoshopped Collection)
它对测量召回率、精确度、特异性、准确性以及最重要的 AUC-ROC 曲线非常有用。
我们从怀孕类比的角度来理解 TP,FP,FN,TN。
Confusion Matrix [Image 3] (Image courtesy: My Photoshopped Collection)
真阳性:
解读:你预测的是正的,这是真的。
你预言一个女人怀孕了,她真的怀孕了。
真否定:
解读:你预测的是负数,这是真的。
你预言一个男人不会怀孕,他实际上也没有。
假阳性:(1 型错误)
解读:你预测的是正的,是假的。
你预言一个男人怀孕了,但他实际上没有。
假阴性:(2 型错误)
解读:你预测的是负数,这是假的。
你预测一个女人不会怀孕,但她确实怀孕了。
请记住,我们将预测值描述为正和负,将实际值描述为真和假。
Actual vs Predicted values [Image 4] (Image courtesy: My Photoshopped Collection)
如何计算二类分类问题的混淆矩阵?
让我们通过数学来理解混淆矩阵。
Confusion Matrix [Image 5 and 6] (Image 5 courtesy: My Photoshopped Collection) (Image 6 courtesy: I can not find the source. If you know please comment. I will provide appropriate citations. :D)
召回
Recall [Image 7] (Image courtesy: My Photoshopped Collection)
上面的等式可以解释为,从所有的正类中,我们正确预测了多少。
召回率要尽可能高。
精度
Precision [Image 8] (Image courtesy: My Photoshopped Collection)
上面的等式可以解释为,从我们预测为正的所有类中,有多少实际上是正的。
精度要尽可能高。
和
精度
从所有的类(正类和负类)中,我们正确预测了多少。在这种情况下,它将是 4/7。
精确度应该尽可能高。
F-measure
F1 Score [Image 9] (Image courtesy: My Photoshopped Collection)
低精度和高召回率的两个模型很难比较,反之亦然。所以为了使它们具有可比性,我们使用 F-Score。F-score 有助于同时衡量查全率和查准率。它用调和平均值代替算术平均值,更多地惩罚极值。
我希望我已经让你对混淆矩阵有了一些基本的了解。如果你喜欢这篇文章,给这篇文章一些掌声会对你有所帮助👏。我随时欢迎你的问题和建议。你可以在脸书、推特、Linkedin 上分享这个,这样有需要的人可能会偶然发现这个。
您可以通过以下方式联系到我:
领英:www.linkedin.com/in/narkhede…
github:【github.com/TheSarang
感谢阅读!