Tensorflow 中的迁移学习(CIFAR-10 上的 VGG19):第 1 部分
简介
这个故事介绍了如何用预训练的 VGG19 模型训练 CIFAR-10 数据集。我将使用 tensornets 中包含的 VGG19。本文的主要目标是理解迁移学习的概念,以及在这个过程中应该关注哪些步骤。你可以在这里找到这个故事的笔记本。
我之前写过一个笔记本和一个故事关于建立经典 CNN 模型来训练 CIFAR-10 数据集。这样,我可以比较最先进的 CNN 模型和基本的 CNN 模型之间的性能。
迁移学习
Winners of ILSVRC since ‘10
自 2012 年 AlexNet 出现以来,基于深度学习的图像分类任务得到了极大的改善。一路走来,已经提出了很多 CNN 模型。即使其中一些没有赢得 ILSVRC,但它们如 VGG16 因其简单和低损失率而受到欢迎。
即使使用高端 GPU,针对整个 ImageNet 数据库训练模型也需要几周时间。如果我们能够重用来自 ILSVRC 的经过验证的模型,这将是理想的,这样我们就不需要在训练和验证上花费大量时间。迁移学习正是我们想要的。
迁移学习就是从别人那里借用 CNN 架构及其预先训练好的参数。当我们在预训练参数的基础上训练我们自己的数据时,我们可以很容易地达到目标精度。
型号选择
在潜入之前,你必须选择选择哪种型号。这完全与你的物理环境和你的团队的目标有关。
由于 ILSVRC 要求模型对 1000 种图像进行分类,因此一些建议的模型无法显示出超强的性能。然而,如果你的目标是对 10 到 100 类图像进行分类,这些模型可能适合你的情况。
随着 CNN 模型的发展,最近的模型显示出相当复杂的结构。如果我们想要改变/修改整个层的某些部分,或者如果我们想要解决哪个部分是我们问题的瓶颈,理解模型在幕后如何工作是至关重要的。
from AN ANALYSIS OF DEEP NEURAL NETWORK MODELS FOR PRACTICAL APPLICATIONS
模型有多大?这通常与参数数量或层数有关。他们会提示你需要花多长时间进行训练。特别是,当你使用 GPU 硬件时,应该充分考虑参数的数量,因为 GPU 的内存资源有限。
对于我来说,出于某些原因,我选择了 VGG19 型号。第一名,尽管它没有赢得 ILSVRC,但它取得了第二名的好成绩。我只需要 10 类图像,所以我认为 VGG19 对于 CIFAR-10 已经足够了。第二,VGG19 架构很简单。如果你了解基本的 CNN 模型,你会立刻注意到 VGG19 看起来很相似。第三个,我有 11GB 内存的英伟达 GTX 1080Ti。这不是最好的选择,但我认为即使 VGG19 的尺寸很大,运行 VGG19 也足够了。最后,由于很多人使用 VGG16,我想尝试一下 VGG19。
模型实现的选择
实际上,您可以为所选的 CNN 模型使用自己的实现。因为来自 ILSVRC 的模型在他们的网页上分享他们的成果,包括权重,你可以下载(像 VGG )并把权重注入到你的实现中。
然而,不实现模型本身,而是从文件和验证任务中转换/注入权重,这需要相当长的时间。幸运的是,Github 中有一些开源的实现。只需要在搜索你想要哪个 CNN 模型,你要像 Tensorflow 或者 PyTorch 一样达到哪个平台(框架)就可以了。
对于我来说,我用的是 Tensorflow,碰巧选择了 VGG19。我发现了两个开源实现, tensornets 和 vgg-tensorflow 。有趣的是,tensornets 提供了几乎所有流行的 CNN 模型,包括像 YOLO 这样的本地化模型。我想我将来可能会经常使用它们中的一些,所以这就是为什么我选择 tensornets 来熟悉它。
知道如何创建模型
没有比仔细阅读 README 文档更简单的方法来了解所选实现的用法。一般来说,第一步是知道如何创建/构建模型图。建立模型后,您可以将预先训练的参数(权重)加载到模型中。不用说,没有预先训练好的参数,就不是迁移学习而只是借用架构。
具体来说,对于张量网,VGG19()创建模型。你只需要指定两个自定义参数, is_training ,和 classes 。当您要针对 ImageNet 以外的数据集训练模型时,应将 is_training 设置为 True 。 classes 是要预测的图像的类别数,因此设置为 10,因为数据集来自 CIFAR-10。
需要记住的一点是,输入张量的形状应该始终是 【无,224,224,3】。因为来自 ILSVRC 的每个模型都是在 ImageNet 提供的形状为(224,224,3)的图像上训练的,所以即使您自己的数据具有不同大小的图像,这也不应该改变。
了解最后一层
您选择的模型的实际实现通常会有所不同。您应该知道模型的最后一层是什么,以便应用损失函数、优化器和执行准确性测试。通过代码本身,你可以很容易地发现模型是如何构建的。以下截图摘自 tensornets github repo。
*可以看到,tensornets 的 VGG19 返回最后一层作为 softmax 激活函数。稍微了解 Tensorflow 的话,***TF . nn . soft max _ cross _ entropy _ with _ logits()函数用的有些重。然而,这个函数是为了同时应用 softmax 函数和交叉熵损失函数,所以这里不应该用于张量网。相反,可以使用仅提供交叉熵损失函数的TF . losses . soft max _ cross _ entropy()**函数。除了应用内部 softmax 函数之外,这一个与前一个等效。
这是第一部分的全部内容。在下一部分中,我会解释以下问题。
- 如何进行预训练的负重?
- 如何重新缩放图像大小以适合?
- 怎么训练?如何衡量准确度?
- 表演
我的深度学习背景是uda city { Deep Learning ND&AI-ndwith contentrations(CV, NLP ,VUI)},Coursera Deep Learning . AI Specialization(AI-ND 被拆分成了 4 个不同的部分,我是和之前版本的 ND 一起完成的)。还有,我目前正在服用 Udacity 数据分析师 ND ,已经 80%完成。
最近在 neptune.ai 上发现了一篇非常有用的关于迁移学习的博文。由于我的帖子有些过时,如果你有机会,请查看更多最新技术,更深入的解释。
迁移学习:利用大数据集的洞察力
在这篇博文中,您将了解什么是迁移学习,它的一些应用是什么,以及为什么它是数据科学家的关键技能。
迁移学习不是机器学习模型或技术;它更像是机器学习中的一种“设计方法论”。例如,另一种“设计方法”是主动学习。
Originally published at https://www.datacamp.com/community/tutorials/transfer-learning
这篇博文是迁移学习系列的第一篇。你可以在这里找到第二篇博文,讨论迁移学习的两个应用。
在后续的博客文章中,我将解释如何将主动学习与迁移学习结合起来,以最佳方式利用现有的(和新的)数据。从广义上讲,当机器学习应用利用外部信息来提高性能或泛化能力时,它们使用迁移学习。
迁移学习:一个定义
迁移学习的一般思想是在只有少量标记数据的环境中,使用从有大量标记数据的任务中学到的知识。创建带标签的数据非常昂贵,因此最大限度地利用现有数据集是关键。
在传统的机器学习模型中,主要目标是基于从训练数据中学习到的模式来概括看不见的数据。在迁移学习中,你试图从已经学习的不同任务的模式开始启动这一概括过程。本质上,你不是从一张白纸(通常是随机初始化的)开始学习过程,而是从已经学会的解决不同任务的模式开始。
Being able to distinguish lines and shapes (left) from an image makes it easier to determine if something is a ‘car’ than having to start from the raw pixel values. Transfer learning allows you to leverage learned patterns from other computer vision models.
Different approaches exist to represent words in NLP (a word embedding like representation on the left and a BoW like representation on the right). With transfer learning a machine learning model can leverage the relationships that exist between different words.
知识和模式的转移在许多领域都是可能的。今天的帖子将通过查看这些不同领域的几个例子来说明迁移学习。目标是激励数据科学家在他们的机器学习项目中尝试迁移学习,并让他们意识到优势和劣势。
我认为对迁移学习的良好理解是数据科学家的一项关键技能,原因有三:
- 迁移学习在任何学习中都是必不可少的。人类并不是为了成功完成每一项任务或问题而被教会的。每个人都会遇到从未遇到过的情况,而我们仍然能够以临时的方式解决问题。从大量经验中学习并将“知识”输出到新环境中的能力正是迁移学习的意义所在。从这个角度来看,迁移学习和概括在概念层面上非常相似。主要区别在于迁移学习通常用于“跨任务转移知识,而不是在特定任务内概括”。因此,迁移学习本质上与所有机器学习模型中必需的一般化思想相关联。
- 迁移学习是确保深度学习技术在大量小数据设置中取得突破的关键。深度学习在研究中几乎无处不在,但许多现实生活中的场景通常没有数百万个带标签的数据点来训练模型。深度学习技术需要大量数据来调整神经网络中的数百万个参数。特别是在监督学习的情况下,这意味着你需要大量(非常昂贵的)标记数据。给图像加标签听起来微不足道,但例如在自然语言处理(NLP)中,需要专业知识来创建一个大的带标签的数据集。例如,Penn treebank,一个词性标注语料库,历时 7 年,需要许多训练有素的语言学家的密切合作。为了使神经网络成为可行的选择,迁移学习是减少所需数据集大小的一种方式。其他可行的选择正在转向更受概率启发的模型,这些模型通常更适合处理有限的数据集。
- 迁移学习有明显的优点也有缺点。理解这些缺点对于成功的机器学习应用至关重要。知识的转移只有在“适当”的时候才是可能的。在这种情况下,准确定义适当的含义并不容易,通常需要进行实验。你不应该相信一个开着玩具车到处跑的小孩会开法拉利。同样的原则也适用于迁移学习:虽然很难量化,但迁移学习是有上限的。这不是一个适合所有问题的解决方案。
迁移学习的一般概念
迁移学习的要求
迁移学习,顾名思义,需要将知识从一个领域转移到另一个领域的能力。迁移学习可以从较高的层面来解释。一个例子是 NLP 中的体系结构可以在序列预测问题中重用,因为许多 NLP 问题可以固有地简化为序列预测问题。迁移学习也可以从一个较低的层面来理解,你实际上是在一个不同的模型中重复使用一个模型的参数(跳格,连续单词袋,等等。).迁移学习的要求一方面是问题特定的,另一方面是模型特定的。接下来的两节将分别讨论迁移学习的高级和低级方法。尽管在文献中你会发现这些概念有不同的名称,迁移学习的总体概念仍然存在。
多任务学习
在多任务学习中,你同时在不同的任务上训练一个模型。通常,使用深度学习模型是因为它们可以灵活地适应。
网络体系结构以这样的方式进行调整,即第一层用于不同的任务,随后是不同的任务专用层和不同任务的输出。总的想法是,通过在不同的任务上训练网络,网络将更好地一般化,因为模型需要在需要类似“知识”或“处理”的任务上表现良好。
自然语言处理的一个例子是最终目标是执行实体识别的模型。除了纯粹在实体识别任务上训练模型,您还可以使用它来执行词性分类、下一个单词预测……因此,模型将受益于从这些任务和不同数据集学习到的结构。我强烈推荐 Sebastian Ruder 关于多任务学习的博客来了解更多关于多任务学习的内容。
特瑞
深度学习模型的一大优势是特征提取是‘自动’的。基于标记的数据和反向传播,网络能够确定任务的有用特征。网络“计算出”输入的哪一部分是重要的,以便例如对图像进行分类。这意味着特征定义的手动工作被抽象掉了。深度学习网络可以在其他问题中重用,因为提取的特征类型通常对其他问题也很有用。本质上,在特征化器中,你使用网络的第一层来确定有用的特征,但是你不使用网络的输出,因为它太特定于任务。
鉴于深度学习系统擅长特征提取,如何重用现有网络来执行其他任务的特征提取?可以将数据样本输入网络,并将网络中的一个中间层作为输出。这个中间层可以被解释为原始数据的固定长度、经过处理的表示。通常,特征的概念用于计算机视觉的上下文中。图像然后被输入到预先训练好的网络(例如,VGG 或 AlexNet)中,并对新的数据表示使用不同的机器学习方法。提取中间层作为图像的表示大大减少了原始数据的大小,使它们更适合于传统的机器学习技术(例如,与原始数据相比,例如,128×128 = 16384 维,逻辑回归或 SVM 在图像的小表示(如 128 维)下工作得更好)。
在下一篇博文中,我将更深入地讨论迁移学习的两个应用,它们都有具体的例子!
如果你有任何问题,我很乐意在评论中阅读。如果你想收到我博客上的更新,请在 Medium 或 Twitter 上关注我!
迁移学习—第一部分
什么是迁移学习(TL),它与经典机器学习(ML)有什么不同?
ML 的大谎言是训练数据的分布与模型将要使用的数据的分布相同。如果违反了这个假设,即数据在不同的特征空间上有不同的分布,会怎么样呢?
当有足够的数据可用时,可以简单地根据新数据重新训练模型,并完全丢弃旧数据。这并不总是可能的。但是,有一种方法可以改善。如果已知训练数据和其他数据之间存在关系,则将从训练数据获得的知识转移(或转移学习)到其他数据的模型会有所帮助。
迁移学习不同于经典的 ML 设置:不是在一个设置中学习,而是在一个设置中学习的知识被重用来提高在另一个设置中的学习。迁移学习受到人类学习者利用现有知识和技能的方式的启发:知道如何阅读文献的人比根本不知道如何阅读的人更有可能成功阅读科学论文。在监督学习的背景下,迁移学习意味着能够重用在一个设置中学习的特征和标签之间的依赖结构的知识,以改进在另一个设置中的依赖结构的推断。在 Dataswati,我们对这种迁移学习特别感兴趣,我个人也花了相当一部分时间研究这些问题。
在这篇文章中,我将回顾迁移学习的不同方面,但首先,谈谈经典的监督机器学习设置。
我们有一个数据集 D ,包含特征向量的样本( x ∈ 𝒳)和相应的标签(y∈𝒴):d= {(Xi,伊 ) : i = 1 ,…,m }。 D 由训练实例集D|X= {Xi:I= 1*,…,m* },以及对应标签集 D | Y = { 伊 : i = 1 ,…,组成这里的 m 是样本大小。所有的配对( x , y )都被假设为从同一个联合分布 P ( X , Y )(独立同分布假设)中独立采样,反映了随机变量 X 和 Y 之间的相关性。换句话说,(,易)是对所有 i 的一个实现( X ,Y)∽P(X, Y )。我们的目标是用 D 学习一个函数 h : 𝒳 → 𝒴 ( h 为“假设”),使 h 逼近 x 和 y 之间的真实关系,这是对p(y|x=【的一些总结当我们在寻找一个好的 h 时,我们将我们的搜索限制在某类函数ℋ(例如线性模型), h ∈ ℋ.如果ℋ不太复杂,样本量 m 足够大,我们可以学习“好” h (例如使用经验风险最小化😗*
ERM algorithm
其中 l 是某个损失函数)使得 h 不仅在( x 、 y ) ∈ D )上,而且在其他数据( x 、上提供了 x 和 y 之间真实关系的良好近似
如果我们没有足够的数据或者没有标签怎么办?有希望吗?
如果…会怎样
- …我们有几个不同的数据集,但具有相似的 X-Y 依赖结构?
- …我们只有其中一些数据集的标签,而没有其他数据集的标签,我们希望在没有标签可用时进行预测?
- …当我们有另一个具有大样本量和相似但不同的依赖结构的数据集时,我们想要学习对一个小样本量数据集的依赖?
- …我们有所有这些的组合?
的确,有一种希望,叫做……
……转移学习。
Pan,Yang 等人(2010)和 Weiss,Khoshgoftaar 和 Wang (2016)对深度学习热之前的迁移学习进行了概述。潘、杨等(2010)将领域定义为一个特征空间,并结合该空间上的概率分布=(, P ( X ))。一个任务被正式定义为𝒯 = (𝒴, f ,这里 f 为真,但未知(可能是随机的)函数 f : 𝒳 → 𝒴,我们试图用 h ∈ ℋ.来近似
为了定义迁移学习(TL)的基本类型,让我们考虑一个简化的设置,此时我们只有两个域,每个域一个任务:源域𝒟 S 和任务𝒯 S ,目标域𝒟 T 和任务𝒯 T 。在这个简单的设定中,TL 旨在通过使用𝒯 S 、𝒟 S 中的知识以及𝒯 T 、𝒟 T 、𝒯 S ≠ 𝒯 T 或𝒟 S ≠ 𝒟 T 来提高 fT 的学习。
下表总结了与传统 ML 相比的 TL 类型。
Types of transfer learning: inductive, transductive, and unsupervised
可以基于特征空间进行额外的分类:
Homogeneous and heterogeneous transfer learning
迁移学习最常见的情况是当特征空间和分布都不同时,任务也不同时。
潘、杨等人(2010)根据“传递什么”的问题对翻译策略进行了分类:
- 基于实例的迁移学习。假设来自源域的一些数据可以在目标域中重用。这里使用了重要性抽样和实例重新加权。
- 特征表示转移。学习特征表示 r 以便于对 r(X) 和 Y 之间的相关性进行建模。然后用它来提高目标任务的性能。在神经网络的上下文中,可以在源域中训练监督模型,然后从最后一层中的一层获取表示,以转换目标域中的数据,然后在该转换的数据上训练另一个模型。
- 参数传递。假设源任务和目标任务共享一些参数或先验。简单情况下当 hS 、 hT ∈ ℋ、hs=f(x; θS ),hT=f(x; θT ,表示 θS 与 θT 部分相似。在神经网络的背景下,人们可以采用像 VGG 这样的预训练模型,并根据自己的特定任务数据重新训练最后几层(重新训练一小部分 θS )。
在这一系列的文章中,我将回顾一下目标语言的一些最新发展,包括领域适应、少量学习和多领域迁移学习的最一般的设置。
在同质直推 TL (𝒳 S = 𝒳 T = 𝒳)的框架中,领域适应(在来自一个联合分布的数据上训练一个模型,并在来自另一个联合分布的数据上使用它)在过去十年中受到了极大的关注,特别是在深度学习的背景下。
人们经常希望找到变换 ϕS 、 ϕT : 𝒳 → 𝒳̃,以便变换后的目标数据的分布与变换后的源数据的分布相同,即p*(ϕs(x)=p(ϕt(x)对于 X ∈这里的希望是,我们可以有效地将在转换后的源数据上训练的模型应用于转换后的目标数据。*
在分类(Ben-David 等人,2007 年,2010 年)和回归(Cortes 和 Mohri,2011 年)问题的背景下,从理论上研究了领域适应。Ben-David 等人(2007 年)研究了在源领域数据上训练的分类器可用于目标领域的条件。他们证明了目标域中误差的上限,该上限被表示为源域中误差的函数。他们在 Ben-David 等人(2010)中进一步扩展了他们的分析。总之,该理论表明,对于有效的域适应,需要在数据表示上训练模型,根据该数据表示不可能区分源域和目标域。
我首先提到一些通用方法。
Daumé III (2009)提出了一种非常简单的领域适应方法。Daumé III (2009)通过对源域和目标域应用简单的数据扩充(复制特征或填充零),然后在从两个域收集的扩充数据上训练模型,将域适应问题转化为监督学习问题。然而,他们的方法需要目标域中的标记数据( DT ∣ Y ≠ ∅).)
在目标域中没有标记数据的情况下,可以找到对齐源和目标分布的转换。Sun,Feng 和 Saenko (2016)提出了相关对齐(CORAL)算法,该算法对齐源和目标分布的二阶统计量。Sun,Feng 和 Saenko (2016)表明,CORAL 可以优于一些基于现代深度学习的方法。
Si、Tao 和 Geng (2010)使用基于 Bregman 散度的正则化进行跨域无监督降维,并提出了迁移学习感知版本的 PCA、Fisher 线性判别分析()、局部保持投影()、边际 Fisher 分析(MFA)和判别局部对齐()。Bregman 散度用于最小化源域和目标域中投影数据分布之间的差异。
潘等人(2011)在其转移成分分析()中使用最大平均差异()作为分布距离的度量。MMD 用于学习数据集的变换(传递分量),以便最小化分布距离。Long 等人(2013)提出了联合分布适应(JDA),通过包括条件分布最小化的目标来推广 TCA。
最近,最优传输被成功地用于领域适应(Courty,Flamary,和 Tuia 2014Courty,Flamary,Tuia 等 2017;Courty,Flamary,Habrard 等人 2017)。最佳传输通过最小化分布之间的 Wasserstein 距离,找到一个域中的数据到另一个域的转换(Peyré,Cuturi 等,2017)。
在基于混合模型的学习环境中,Beninel 等人(2012 年)提出了一种映射源数据的方法,以便模拟转换数据的分布等于模拟目标的分布。
Glorot、Bordes 和 Bengio (2011)在情感分类的上下文中使用了基于特征表示的领域适应。使用包含四个不同领域数据的简化版亚马逊数据集,他们首先从所有领域收集数据,并使用堆叠去噪 Autoencoder (Vincent et al. 2008)对数据的词袋表示学习无监督的特征表示。然后,对于每个源-目标域对,他们在源数据的表示上训练二进制 SVM 分类器,并将其用于目标数据的表示。
Ganin 和 Lempitsky (2014)提出了一种神经网络架构,该架构将领域适应和深度特征学习结合在一个训练过程中。类似于对抗性训练(Goodfellow 等人,2014 年),他们同时训练了两个模型:I)域分类器网络,用于区分转换后的源数据和目标数据;以及 ii)预测器网络,用于预测源域中的标签以及“愚弄”域分类器(通过其损失函数中的正则化项实现)。然而,他们引入了允许端到端训练的梯度反转层,而不是域分类器和预测器的交替训练。他们在一系列计算机视觉数据集上展示了他们方法的效率:SVHN、MNIST 和交通标志数据集。Ajakan 等人(2014 年)有效地将一个非常相似的模型应用于亚马逊评论情感分析数据集。Ganin 等人(2016)提出了对这种神经网络的扩展分析,即所谓的域对抗适应神经网络。
如需继续,请点击此处。你会发现第二部分复习零/少投学习。在即将到来的第三部分,我还将回顾多域迁移学习,所以如果你不想错过这个故事,请确保关注我们。
阿贾坎、哈娜、帕斯卡尔·日尔曼、雨果·拉罗歇尔、弗朗索瓦·拉维奥莱特和马里奥·马尔尚。2014.“领域对抗性神经网络.” arXiv 预印本 arXiv:1412.4446 。
本-大卫、沙伊、约翰-布利泽、科比-克拉默、亚历克斯-库勒萨、费尔南多-佩雷拉和詹妮弗-沃特曼-沃恩。2010."从不同领域学习的理论."机器学习79(1–2):151–75。
本-大卫,夏伊,约翰-布利泽,科比-克莱默和费尔南多-佩雷拉。2007."分析领域适应的表现."在神经信息处理系统的进展*,137–44。*
贝尼内尔、法里德、克里斯托夫·比尔纳奇、查尔斯·布维龙、朱利安·雅克和亚历山大·卢尔梅。2012.统计学习中知识转移的参数链接模型。新星出版社。
科尔特斯,科琳娜,和梅尔亚尔·莫赫利。2011."回归中的领域适应."在算法学习理论国际会议中,308–23。斯普林格。
库蒂、尼古拉斯、雷米·弗拉芒里、阿毛里·哈布拉和阿兰·拉科托马莫尼。2017."领域适应的联合分配最佳运输."在神经信息处理系统的进展*,3730–9。*
库蒂、尼古拉斯、雷米·弗拉芒里和德维斯·图伊亚。2014."正则化最佳传输的域适应."在关于数据库中的机器学习和知识发现的欧洲联合会议*,274–89。斯普林格。*
库蒂、尼古拉斯、雷米·弗拉芒里、德维斯·图伊亚和阿兰·拉科托马莫尼。2017."领域适应的最佳传输."IEEE 模式分析和机器智能汇刊 39(9):1853–65。
多梅三世,哈尔。2009.“令人沮丧的简单领域适应。” arXiv 预印本 arXiv:0907.1815 。
加宁,雅罗斯拉夫和维克多·兰皮茨基。2014.“无监督领域适应反向传播.” arXiv 预印本 arXiv:1409.7495 。
加宁、雅罗斯拉夫、叶夫根尼娅·乌斯季诺娃、哈娜·阿贾坎、帕斯卡尔·热尔曼、雨果·拉罗歇尔、弗朗索瓦·拉维奥莱特、马里奥·马尔尚和维克多·兰皮茨基。2016.“神经网络的领域对抗训练.”《机器学习研究杂志》17(1):2096–30。
格洛特,泽维尔,安托万·博德斯,约舒阿·本吉奥。2011."大规模情感分类的领域适应:一种深度学习方法."在第 28 届机器学习国际会议(ICML-11)的会议录*,513–20 页。*
古德菲勒、伊恩、让·普吉-阿巴迪、迈赫迪·米尔扎、徐炳、戴维·沃德-法利、谢尔吉尔·奥泽尔、亚伦·库维尔和约舒阿·本吉奥。2014."生成性对抗网络。"在神经信息处理系统的进展*,2672–80。*
龙、、、丁桂光、、孙、俞。2013."具有联合分布适应的转移特征学习."IEEE 计算机视觉国际会议论文集,2200–2207。**
潘、辛诺佳林、曾伟华、郭炳湘、杨强。2011."通过转移成分分析的领域适应."IEEE 神经网络汇刊 22(2):199–210。
潘、辛诺佳林、杨强等。2010."迁移学习综述."IEEE 知识与数据工程汇刊 22(10):1345–59。
佩雷、加布里埃尔、马尔科·库图里和其他人。2017.“计算最优运输。”
斯,斯,大成道,伯更。2010."转移子空间学习的基于 Bregman 散度的正则化."IEEE 知识与数据工程汇刊 22:929–42。
孙、、冯嘉实和凯特·桑科。2016."令人沮丧的简单领域适应的回归."在 AAAI ,6:8。
文森特、帕斯卡尔、雨果·拉罗歇尔、约舒阿·本吉奥和皮埃尔·安托万·曼扎戈尔。2008."用去噪自动编码器提取和合成鲁棒特征."第 25 届机器学习国际会议论文集,1096–1103。ACM。
魏斯、卡尔、塔希·科什戈夫塔尔和汪丁丁。2016."迁移学习综述."大数据杂志 3 (1): 9。
原载于 2018 年 11 月 19 日medium.com*。*
迁移学习—第二部分
零/一/少量学习
这个故事的第一部分,请导航至https://medium . com/dataswati-garage/transfer-learning-part-1-C2 f 87 de 8df 38。
当数据丰富时,很容易训练模型。通常情况并非如此,人们只能从几个例子中学习。一种极端形式的迁移学习在这里会有所帮助。
想象一下,训练一个学习区分狗和狼的分类器,并且训练集中的所有狗都是牧羊犬。现在,你想对一张吉娃娃的图片进行分类。如果你有一些标记的吉娃娃图片,你可以试着用它们来适应你的模型。这是一个很少发生的学习问题。你的情况会变得更糟。想象一下,只有一个例子(一次性学习)或者根本没有标记的吉娃娃(零次学习)。如果有人试图使用你的狗/狼分类器对卡车进行分类,情况会变得更糟。你能调整你的模型来分类他的卡车吗?
乍一看,少射/零射学习的最坏情况似乎几乎是不可解的。但是,有一个解决方案。想想 k 近邻(kNN)。如果我们有一个提取输入的最相关特征的数据表示,并使分类变得容易,我们可以将一个新的无标签示例映射到这个表示,并使用 kNN 来确定标签。你可以告诉我:但是,等等,你不是受限于你训练数据中的标签吗?如果所有最近的邻居都不在附近呢?你是对的。这还不是零镜头学习,但是这种方案可以用于少镜头学习。在观察了几个新类的例子之后,你可以希望学会用 kNN 来识别新类。当然,如果你只在牧羊犬/狼的图像上学习你的特征映射,并且吉娃娃相关的特征被从表示中排除,这可能会出错。
零射击学习
想象一下,现在我们有了一个很好的映射,它映射输入的空间的所有点都被标记了。在这种情况下,基于 kNN 的方法将起作用。这里的问题是构造这样一个标记空间以及从特征空间到这个空间的映射。
我们可以采取更一般的方法来寻找一个好的代表。我们可以为标签和训练样本构建一个向量空间嵌入,使得训练样本和它的标签在这样一个公共空间中尽可能地相互靠近。
这种方法在图像分类中被积极地使用:为图像和单词学习公共空间嵌入,并且单词用作标签。如果我们有一个嵌入多个标签的向量空间,反映单词标签之间的语义关系,使得单词标签“狗”、“猫”和“哺乳动物”彼此之间比“桌子”更接近,而“桌子”比“猫”更接近“椅子”,这不是很好吗?我们将能够将新图像映射到该空间,然后获取最近邻的标签,即使它不在训练图像集中。幸运的是,可以从大量的文本数据中以无监督的方式学习这样的单词嵌入,参见 word2vec (Mikolov 等人 2013 年)、 fastText (Bojanowski 等人 2017 年)、 GloVe (Pennington、Socher 和 Manning 2014 年),或最近的 Poincare 嵌入(Nickel 和 Kiela 2017 年)。使用标记的数据,可以学习狗/狼的图像到单词嵌入空间的嵌入,使得狗的图像被映射到“狗”单词向量的邻域。当一个新的例子被给出时,它被映射到嵌入空间,并且最近的词向量(最近邻居)被作为这个例子的预测标签。
Socher 等人(2013 年)使用在维基百科文本上训练的预训练嵌入,他们学习了基于神经网络的图像到单词嵌入向量空间的映射。
Taken from Socher et al. (2013)
诺鲁齐等人(2013)提出了一种非常简单的方法来将图像嵌入到预训练的词向量嵌入空间中。在训练了多类别图像分类器之后,他们使用类别的预测概率来执行对应于类别标签的单词嵌入向量的概率加权平均。
Romera-Paredes 和 Torr (2015 年)开发了一种基于线性变换的零炮学习方法,但该方法需要根据属性对标签和训练样本进行表征。然后,他们学习矩阵,当矩阵与属性向量结合时,给出了到公共空间的线性映射。这与其他方法类似,但更具限制性,因为到公共空间的映射不是从端到端的数据中学习的,而是需要辅助信息进行训练。
关于零投学习的不同方法的比较,请参见冼等人(2018)。
少量学习
少量学习与元学习(学习如何学习)领域相关,需要一个模型从少量新数据中快速学习新任务。
Lake 等人(2011)提出了一种受人类学习简单视觉概念(手写字符)启发的一次性学习方法。在他们的模型中,手写字符是人们在绘图时使用的笔画的嘈杂组合。他们提出了一个生成模型,该模型学习一个笔画库,并将该库中的笔画组合起来生成字符。给定一个用于一次性学习的新字符和一个用于评估的候选字符,两个字符都被建模为笔画的叠加,Lake 等人(2011)估计了候选字符由与新字符相同的笔画组成并且这些笔画以类似方式混合的概率。
深度学习呢?首先,让我回到我们的 kNN 例子。是什么让 kNN 实现了少拍学习?这是记忆。记忆新的训练样本,然后当类似的新测试样本到达时,kNN 在其存储器中搜索类似的样本,并找到记忆的训练样本及其标签。然而,标准的深度学习架构不允许快速吸收(记忆)新数据,而是需要大量的训练。
为了解决这个问题,可以将 kNN 与通过深度学习(深度学习+基于 kNN 的记忆)获得的数据表示相结合。或者,人们可以尝试以更直接的方式用记忆来增强深度神经网络,从而实现端到端的训练。
Koch、Zemel 和 Salakhutdinov (2015)开发了基于最近邻分类的少镜头学习方法,通过连体神经网络学习相似性度量。连体神经网络是在 90 年代开发的(Bromley 等人,1994 年),用于学习两个输入之间的相似性度量。暹罗网络由两个相同的子网(共享权重)组成,它们的输出端相连。每个子网接收自己的输入,整个网络的输出决定了两个输入之间的相似性。在 Koch、Zemel 和 Salakhutdinov (2015)了解了该指标后,使用了简单的最近邻分类器。
桑托罗等人(2016 年)开发了一种使用记忆增强神经网络(MANN)的少量学习方法。他们模型的想法类似于神经图灵机(Graves,Wayne 和 Danihelka,2014 年):一个用外部存储模块扩展的神经网络,因此模型是可微分的,可以进行端到端的训练。由于他们的训练程序,他们迫使网络学习一般知识,而快速的内存访问允许将这些一般知识快速绑定到新数据。
Vinyals 等人(2016 年)提出了一个神经网络模型,该模型实现了一个端到端的训练过程,该过程结合了特征提取和具有余弦相似性的可微分 kNN。他们使用一个网络来嵌入一小组已标记的图像(支持集),使用另一个网络来嵌入一个未标记的图像到同一空间。然后,他们计算在支持集中的每个嵌入图像和嵌入的未标记图像之间计算的余弦相似性的 softmax 变换。这被用作来自支持集的标签的概率分布的近似值。然后,他们提出了一个改进方案,即使用整个支持集(上下文)来嵌入支持集中的每个示例以及未标记的测试示例(他们使用 LSTM 来实现这一点)。
Taken from Vinyals et al. (2016)
Ravi 和 Larochelle (2016)提出修改基于梯度的优化,以允许少量学习。在基于梯度的优化的一般观点中,在优化算法的每一步,优化器(比如 SGD)使用梯度信息来基于它们先前的值提出下一个参数。Ravi 和 Larochelle (2016)用参数更新历史、当前经验风险及其梯度的非线性函数取代了 SGD 更新规则(相对于梯度的线性)。具体来说,他们使用长短期记忆(LSTM)网络(Hochreiter 和 Schmidhuber 1997)来学习非线性更新规则,以训练神经网络。
在他们的模型不可知元学习算法(MAML)论文中,Finn,Abbeel 和 Levine (2017)提出了适用于任何可以用梯度下降训练的模型的少镜头学习方法。引用作者的话:“实际上,我们的目标是找到对任务变化敏感的模型参数,这样,当在损失梯度方向上改变时,参数的小变化将对从任务分布中提取的任何任务的损失函数产生大的改进”。目标是为所有任务学习一个模型,以便它的内部表示很好地适合所有任务(可转移)。为了实现这一点,首先,在几个训练示例上,为单个任务上的一个或多个梯度下降步骤训练通用模型。这产生了一个稍微更适合特定任务的模型,一个特定于任务的模型。第二,特定任务模型用于评估其他任务的累积损失。该多任务损失然后被用于执行元优化步骤:用梯度下降来更新通用模型的参数。
Taken from Wu et al. (2018)
Wu 等人(2018)提出了用于少镜头预测(MeLA)的元学习自动编码器。该模型由元识别模型组成,它以新数据的特征和标签作为输入,并返回一个潜在代码。该代码被用作元生成模型的输入,该元生成模型生成特定于任务的模型的参数。也就是说,特定于任务的模型不是通过梯度下降来训练的,而是从对应于一个任务的几个例子中生成的。此外,生成的模型可以用几个梯度步骤来改进。从对应于任务的几个例子中生成模型的能力可以被解释为模型空间中的插值。为了使它成功,用于训练 MeLA 的任务应该足够相似。
今天到此为止。感谢阅读。请关注我们,以免错过我们下一篇关于多领域/多任务迁移学习的文章。
参考
博雅诺斯基,皮奥特,爱德华·格雷夫,阿曼德·朱林和托马斯·米科洛夫。2017."用子词信息丰富词向量."计算语言学协会汇刊 5:135–46。
Bromley、Jane、Isabelle Guyon、Yann LeCun、Eduard Sä ckinger 和 Roopak Shah。1994."使用“连体”时间延迟神经网络的签名验证."在神经信息处理系统的进展,737–44。
芬恩,切尔西,彼得·阿贝耳和谢尔盖·莱文。2017."用于深度网络快速适应的模型不可知元学习."在 ICML 。
格雷夫斯,亚历克斯,格雷格韦恩和伊沃丹尼尔卡。2014.“神经图灵机。” arXiv 预印本 arXiv:1410.5401 。
Hochreiter,Sepp 和 Jürgen Schmidhuber。1997."长短期记忆"神经计算9(8):1735–80。
科赫、格雷戈里、理查德·泽梅尔和鲁斯兰·萨拉胡季诺夫。2015."用于一次性图像识别的连体神经网络."在 ICML 深度学习工场。第二卷。
莱克、布伦登、鲁斯兰·萨拉赫丁诺夫、杰森·格罗斯和约书亚·特南鲍姆。2011."简单视觉概念的一次性学习."在认知科学学会年会的会议录中。第 33 卷。
米科洛夫、托马斯、伊利亚·苏茨基弗、程凯、格雷戈·S·科拉多和杰夫·迪恩。2013."单词和短语的分布式表示及其组合性."在神经信息处理系统的进展,3111–9。
尼克尔、马克西米利安和杜韦·凯拉。2017."学习分层表示的庞加莱嵌入."在由 I. Guyon、U. V. Luxburg、S. Bengio、H. Wallach、R. Fergus、S. Vishwanathan 和 R. Garnett 编辑的《神经信息处理系统进展》30 中,6341–50。Curran Associates,Inc .http://papers . nips . cc/paper/7213-poincare-embeddings-for-learning-hierarchical-presentations . pdf。
诺鲁齐、穆罕默德、托马斯·米科洛夫、萨米·本吉奥、约拉姆·辛格、黄邦贤·施伦斯、安德里亚·弗洛姆、格雷戈里·科拉多和杰弗里·迪恩。2013."语义嵌入的凸组合零镜头学习."abs/1312.5650。
彭宁顿,杰弗里,理查德·索彻和克里斯托弗·曼宁。2014."手套:单词表示的全局向量."在2014 年自然语言处理经验方法会议录,1532–43。
拉维,沙钦和雨果·拉罗彻尔。2016."作为少量学习模型的最优化."英寸
罗梅拉-帕雷德斯,贝纳迪诺和菲利普·托尔。2015."一种简单得令人尴尬的零起点学习方法."在机器学习国际会议,2152–61。
桑托罗、亚当、谢尔盖·巴图诺夫、马修·博特文尼克、金奎大·威斯特拉和蒂莫西·p·莉莉卡普。2016."记忆增强神经网络的元学习."在 ICML 。
索彻、理查德、米林德·甘朱、克里斯托弗·曼宁和吴恩达。2013."通过跨模态迁移进行零射击学习."在神经信息处理系统的进展,935–43。
Vinyals、Oriol、Charles Blundell、Timothy P. Lillicrap、Koray Kavukcuoglu 和金奎大·威斯特拉。2016."一次性学习的匹配网络."在辊隙中。
吴、泰林、约翰·波利福伊、艾萨克·L·庄和马克斯·泰格马克。2018.“用于少量预测的元学习自动编码器.” arXiv 预印本 arXiv:1807.09912 。
冼、、Christoph H. Lampert、Bernt Schiele 和 Zeynep Akata。2018."零起点学习——对好、坏、丑的综合评价."IEEE 模式分析与机器智能汇刊*。*
原载于 2018 年 12 月 7 日medium.com。
使用不同学习率的迁移学习
在这篇文章中,我将分享如何使用迁移学习将流行的深度学习模型用于自己的特定任务。我们将涵盖一些概念,如差异学习率,这甚至不是目前在一些深度学习库中实现的。这些是我作为国际研究员从 fast.ai 深度学习课程 2017 中了解到的。该课程内容将于 2018 年初作为 MOOC 向公众开放。
那么什么是迁移学习呢?
它是使用在一个过程/活动中学到的知识并将其应用于不同任务的过程。让我们举一个小例子,一个擅长 carroms 的玩家可以将该知识应用于学习如何玩台球游戏。
因此,进入我们的机器学习/深度学习视角…
这同样适用于我们的机器学习世界。让我们看看下面的图片。
Transfer Learning Example
比方说,模型 A 的任务是识别 1000 种物体,比如帽子、猫、垫子,我们手头就有这样一个训练有素的模型。现在让我们假设我们想要创建一个模型 B 来检测一个猫/狗分类器。即使我们有一个小数据集,我们也可以在模型 B 的训练过程中使用模型 A 的知识,并产生最先进的结果。
但是为什么要使用迁移学习呢?
每当我们想要使用机器学习来解决一个独特的问题时,我们很可能无法为我们的模型找到足够的数据。用较少的数据进行训练,结果不会太好。即使我们有大量数据,也有可能没有足够的资源(如 GPU)来获得高质量的结果。因此,迁移学习通过使用预先训练好的模型形式的知识来解决这些问题,这种模型是有人用大型数据集和资源创建的。
好吧,那你是怎么做的?
我们用 CNN 的一个网络图样本来理解一下。尽管实际上网络很大、很复杂并且包含各种其他单元。
Sample CNN diagram
最常用的方法是修改密集层,使网络输出适合我们手头的任务,并且只训练新增加的层。当任务相互关联,并且您有少量数据时,这种方法非常有效。例如,如果我们使用一个已经知道如何检测猫的预训练模型,如果我们想用少量数据创建一个猫/狗分类器,这种方法将会起作用。
第二种方法是在训练中甚至包括更接近密集块(图中的蓝色块)的卷积块。如果我们有一个中等大小的数据集,并且任务之间没有那么紧密的联系,那么这就更理想了。
第三种方法是使用预训练模型,但使用数据集训练所有层。这种方法效果很好,但是需要相对较大的数据集和 GPU 资源。如果我们选择这个选项,有几个很酷的技巧,我们将在下面介绍。
混合第一种和第三种方法。
如果我们决定使用第三种方法,最好将第一种方法应用于一些时期的训练,以使新添加的层权重达到更好的点。然后我们可以解冻所有的层,并遵循我们的第三种方法。
不同的学习率:
短语“不同的学习率”是指在我们的培训中,网络的不同部分有不同的学习率。其思想是将各层划分为不同的层组,并为每组设置不同的学习速率,以便获得理想的结果。简而言之,我们控制训练过程中网络各部分的权重变化率。
为什么?有什么帮助?
如果我们考虑上面的第三种方法,有一个小但重要的点值得注意。为了理解这一点,让我们回到 CNN 的示例图。
Sample CNN with differential learning rate
一般而言,红色图层学习边缘、形状等一般特征,中间的蓝色图层学习与数据集相关的特定细节。
鉴于上面的陈述,过多地改变初始层的学习权重不是一个好主意,因为它们已经擅长于它们应该做的事情(检测像边缘等特征)。中间层将了解复杂的特性,如果我们稍微修改它们,这些特性可能在某种程度上有助于我们的任务。所以,我们想稍微调整一下。
在这方面,不同的学习率有助于我们。我们现在可以把样本网络想象成三层组(红、蓝、绿)并设置不同的学习速率。最初的红色层将具有较小的学习率,因为我们不想过多地干扰它们,中间的蓝色层将具有比初始层更高的学习率,而最终的绿色层将具有最佳的最高学习率。
初始层和中间层的学习率的多少取决于预训练模型和我们需要的模型之间的数据相关性。例如,如果任务是创建一个狗/猫分类器,并且我们的预训练模型已经擅长识别猫,那么我们可以使用较小数量级的学习率。但是如果我们的任务是在卫星图像/医学图像上创建一些模型,那么我们的学习率会稍微高一些。
请注意,目前大部分深度学习库都不支持差异学习率。
好吧,给我看看代码…
无论我们讨论什么,我都会写一篇关于编码部分的详细文章。
结论:
根据手头的任务和资源,人们应该选择一种适当的迁移学习方法。一般来说,如果我们有大量的数据和资源,差异学习率的迁移学习会产生更好的结果。
使用 Mobilenet 和 Keras 进行迁移学习
在这本笔记本中,我将向你展示一个使用 Mobilenet 对狗的图像进行分类的例子。然后我会给你看一个例子,当它巧妙地错误分类一个蓝色山雀的图像。然后,我将重新训练 Mobilenet 并使用迁移学习,这样它就可以正确地分类相同的输入图像。只使用了两个分类器。但是这可以扩展到您想要的任何数量,受限于您可用的硬件数量和时间。
Mobilenet 的源文件位于此处:https://arxiv.org/pdf/1704.04861.pdf
MobileNets:面向移动视觉应用的高效卷积神经网络,Howard 等, 2017 。
我们将使用 Mobilenet,因为它的架构是轻量级的。它使用深度方向可分离卷积,这基本上意味着它在每个颜色通道上执行单个卷积,而不是组合所有三个并将其展平。这具有过滤输入通道的效果。或者正如论文作者清楚解释的那样:“对于 MobileNets,深度方向卷积对每个输入通道应用单个滤波器。逐点卷积然后应用 1×1 卷积来组合深度卷积的输出。标准卷积在一个步骤中将输入滤波并组合成一组新的输出。深度方向可分离卷积将其分为两层,一层用于滤波,另一层用于合并。这种因式分解具有显著减少计算和模型大小的效果。
Difference between pointwise and depth wise convolutions
因此,Mobilenet 的总体架构如下,有 30 层
- 步幅为 2 的卷积层
- 深度方向层
- 逐点层,通道数量加倍
- 跨距为 2 的深度方向层
- 逐点层,通道数量加倍
等等。
Mobilenet full architecture
这也是非常低的维护,因此表现相当好,高速。还有许多预训练模型,内存和磁盘中网络的大小与使用的参数数量成比例。网络的速度和功耗与 MAC(乘法累加)的数量成比例,MAC 是融合乘法和加法运算数量的度量。
现在让我们进入代码!
我的代码位于这里:https://github . com/fer hat 00/Deep-Learning/tree/master/Transfer % 20 Learning % 20 CNN
让我们加载必要的包和库。
让我们输入来自 Keras 的预训练模型。
让我们对不同品种的狗的图像进行一些测试。
Photo by Jana Ohajdova on Unsplash
输出:
[[('n02106662', 'German_shepherd', 0.9796372),
('n02105162', 'malinois', 0.020184083),
('n02091467', 'Norwegian_elkhound', 0.00015799515),
('n02116738', 'African_hunting_dog', 5.2901587e-06),
('n02105251', 'briard', 3.9127376e-06)]]
Photo by Vincent van Zalinge on Unsplash
输出:
[[(‘n02099712’, ‘Labrador_retriever’, 0.73073703),
(‘n02087394’, ‘Rhodesian_ridgeback’, 0.03984367),
(‘n02092339’, ‘Weimaraner’, 0.03359009),
(‘n02109047’, ‘Great_Dane’, 0.028944707),
(‘n02110341’, ‘dalmatian’, 0.022403581)]]
Photo by Hans Ole Benonisen on Unsplash
输出:
[[('n02113799', 'standard_poodle', 0.5650911),
('n02113712', 'miniature_poodle', 0.37279922),
('n02102973', 'Irish_water_spaniel', 0.053150617),
('n02113624', 'toy_poodle', 0.0072146286),
('n02093859', 'Kerry_blue_terrier', 0.0013652634)]]
到目前为止一切顺利。它能很好地对每一种狗进行分类。但是让我们在一种鸟身上试试,蓝山雀。
Photo by Bob Brewer on Unsplash
输出:
[[('n01592084', 'chickadee', 0.95554715),
('n01530575', 'brambling', 0.012973112),
('n01828970', 'bee_eater', 0.012916375),
('n01532829', 'house_finch', 0.010978725),
('n01580077', 'jay', 0.0020677084)]]
你可以看到它认不出蓝山雀。它错误地将图像归类为山雀。这是一种原产于北美的鸟,与众不同:
Photo by Patrice Bouchard on Unsplash
现在让我们来操作 Mobilenet 架构,重新培训最上面的几层,并采用迁移学习。为此,我们需要在一些图像上训练它。我将在蓝山雀和乌鸦上训练它。但是,与其手动下载它们的图片,不如使用谷歌图片搜索来获取图片。为此,我们可以导入一个很好的包。
看看 https://github.com/hardikvasa/google-images-download
现在让我们重用 MobileNet,因为它是非常轻量级的(17Mb),冻结基础层,让我们添加和训练顶部的几层。注意,我将只训练两个分类器,蓝山雀和乌鸦。
让我们检查模型架构
我们将使用预训练的权重,因为该模型已经在 Imagenet 数据集上进行了训练。我们确保所有的重量都是不可训练的。我们将只训练最后几个密集层。
现在让我们将训练数据加载到 ImageDataGenerator 中。指定路径,它自动批量发送训练数据,简化代码。
编译模型。现在让我们训练它。在 GTX1070 GPU 上应该不到两分钟。
Epoch 1/10
5/5 [==============================] - 5s 952ms/step - loss: 0.9098 - acc: 0.6562
Epoch 2/10
5/5 [==============================] - 3s 563ms/step - loss: 0.0503 - acc: 0.9686
Epoch 3/10
5/5 [==============================] - 3s 687ms/step - loss: 0.0236 - acc: 0.9930
Epoch 4/10
5/5 [==============================] - 4s 716ms/step - loss: 7.5358e-04 - acc: 1.0000
Epoch 5/10
5/5 [==============================] - 3s 522ms/step - loss: 0.0021 - acc: 1.0000
Epoch 6/10
5/5 [==============================] - 4s 780ms/step - loss: 0.0353 - acc: 0.9937
Epoch 7/10
5/5 [==============================] - 3s 654ms/step - loss: 0.0905 - acc: 0.9938
Epoch 8/10
5/5 [==============================] - 4s 890ms/step - loss: 0.0047 - acc: 1.0000
Epoch 9/10
5/5 [==============================] - 3s 649ms/step - loss: 0.0377 - acc: 0.9867
Epoch 10/10
5/5 [==============================] - 5s 929ms/step - loss: 0.0125 - acc: 1.0000
模型现在已经训练好了。现在让我们测试一些独立的输入图像来检查预测。
输出:
array([[4.5191143e-15, 1.0000000e+00]], dtype=float32)
正如你所看到的,它正确地预测了乌鸦,因为蓝色山雀图像被注释掉了。
Photo by Jaime Dantas on Unsplash
这可以进一步扩展到更多的图像,以使更多的分类器更好地概括,但这是实现 CNN 的迁移学习的最简单的方法和最快的方式。这当然取决于多快,多准确,你想在什么硬件上实现你的模型,以及你有多少时间。
使用 pytorch 迁移学习—第 1 部分
有没有想过为什么 ML 模特每次都要从头学起?如果模型可以利用从识别猫、狗、鱼、汽车、公共汽车和许多其他事物中学到的知识来识别分心的汽车司机或识别植物疾病,会怎么样?在迁移学习中,我们使用预训练的神经网络来提取特征,并为特定用例训练新模型。不确定是什么…等到博客结束就好了。
为什么是 PyTorch
有很多框架像 Keras,Tensoflow,Theano,Torch,Deeplearning.4J 等都可以用于深度学习。在所有这些中,我最喜欢的是 Tensorflow 上的 Keras。Keras 适用于许多成熟的架构,如 CNN、前馈神经网络、用于时间序列的 Lstm,但当您试图实现本质上复杂的新架构时,它会变得有点棘手。由于 Keras 是以良好的模块化方式构建的,因此缺乏灵活性。Pytorch 是一个新成员,它为我们提供了以面向对象的方式构建各种深度学习模型的工具,因此提供了很大的灵活性。最近 PyTorch 正在实现许多复杂的架构。所以我开始探索 PyTorch,在这篇博客中,我们将介绍用很小的数据集和几行代码构建一个最先进的分类器是多么容易。
我们将使用以下步骤构建一个用于检测蚂蚁和蜜蜂的分类器。
- 从这里下载数据集。
2.数据增强。
3.下载预训练的 resnet 模型(迁移学习)。
4.在数据集上训练模型。
5.如何衰减每第 n 个时期的学习率。
下载数据集:
从上面的链接下载数据集。它包含训练数据集中的 224 幅图像和验证数据集中的 153 幅图像。
数据扩充:
数据扩充是对现有照片进行更改的过程,如调整颜色、水平或垂直翻转、缩放、裁剪等。Pytorch 提供了一个非常有用的名为 torchvision.transforms 的库,它提供了许多有助于应用数据扩充的方法。transforms 附带了一个 compose 方法,它接受一个转换列表。
data_transforms **=** { 'train': transforms**.**Compose([
transforms**.**RandomSizedCrop(224),
transforms**.**RandomHorizontalFlip(),
transforms**.**ToTensor(),
transforms**.**Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms**.**Compose([
transforms**.**Scale(256),
transforms**.**CenterCrop(224),
transforms**.**ToTensor(),
transforms**.**Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
迁移学习:
我们将使用微软的 ResNet 模型,该模型在 2015 年赢得了 ImageNet 竞赛。它展示了深层网络是如何成为可能的。让我们不要进入 ResNet 的复杂性。我们将下载模型,大多数现代深度学习框架使加载模型更容易。ResNet 模型包括一组 ResNet 块(卷积和单位块的组合)和一个完全连接的层。该模型在 1000 个类别的 Imagenet 数据集上进行训练,我们将移除最后一个完全连接的层,并添加一个新的完全连接的层,该层输出 2 个类别,这表明图像是蚂蚁或蜜蜂的概率。
model_conv **=** torchvision**.**models**.**resnet18(pretrained**=**True)
**for** param **in** model_conv**.**parameters(): ----> 1
param**.**requires_grad **=** False
*# Parameters of newly constructed modules have requires_grad=True by default*
num_ftrs **=** model_conv**.**fc**.**in_features
model_conv**.**fc **=** nn**.**Linear(num_ftrs, 2) ----> 2**if** use_gpu:
model_conv **=** model_conv**.**cuda() ----> 3
- 我们告诉模型不要学习或修改模型的权重/参数。
- 然后,我们向现有模型添加一个新的全连接层,以训练我们的模型对 2 个类别进行分类。
- 如果你有 gpu 的话。cuda()在 GPU 中执行模型。
我们的模型已经准备好了,我们需要将数据传递给训练。
培训模式:
对于培训模型,除了模型之外,我们还需要几样东西,例如:
- PyTorch 变量:包装 pytorch 张量的变量。它包含数据和与数据相关的梯度。
- 损失函数:它有助于计算我们的模型有多好。我们将在这里使用分类交叉熵。
- 优化器:我们将使用 SGD 来优化我们的梯度权重。在我们的例子中,我们只更新最后一层的权重。
- 正向传播:这是我们通过模型传递数据的最简单的部分。
- 反向传播:这是现代深度学习网络的关键,所有神奇的事情都发生在这里。其中优化器开始计算需要更新多少权重以减少损失或提高准确性。在大多数现代框架中,这是自动化的,因此我们可以专注于构建由深度学习支持的酷应用程序。
if use_gpu:
inputs, labels = Variable(inputs.cuda()), Variable(labels.cuda()) --> 1
else:
inputs, labels = Variable(inputs), Variable(labels)criterion = nn.CrossEntropyLoss() --> 2# Observe that all parameters are being optimized
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9) -->3# zero the parameter gradients
optimizer.zero_grad()# forward
outputs = model(inputs) --> 4
loss = criterion(outputs, labels)# backward + optimize only if in training phase
if phase == 'train': --> 5
loss.backward()
optimizer.step()
衰减学习率:
大多数情况下,我们以较高的学习速率开始,这样我们可以更快地减少损失,然后在几个时期后,你想减少它,这样学习变得更慢。我发现 pytorch 教程中的这个函数非常有用。
**def** **lr_scheduler**(optimizer, epoch, init_lr**=**0.001, lr_decay_epoch**=**7):
"""Decay learning rate by a factor of 0.1 every lr_decay_epoch epochs."""
lr **=** init_lr ***** (0.1******(epoch **//** lr_decay_epoch))
**if** epoch **%** lr_decay_epoch **==** 0:
**print**('LR is set to {}'**.**format(lr))
**for** param_group **in** optimizer**.**param_groups:
param_group['lr'] **=** lr
**return** optimizer
我们将每第 n 个时段的学习率降低,在上面的示例 7 中为 0.1。decay_rate 是可配置的。即使在较小的数据集上,我们也可以使用这种方法获得最先进的结果。
想用 pytorch 在你的数据集上尝试迁移学习,代码驻留在这里。
对学习深度学习感兴趣的人,不要忘了看看令人惊叹的 MOOC 深度学习,作者是杰瑞米·霍华德的程序员。
在的下一部分中,我们将讨论如何使用 VGG 更快地进行迁移学习的不同技巧。并比较它在 PyTorch 和 Tensorflow 中的表现。
使用 PyTorch 进行迁移学习—第二部分
在之前的博客中,我们讨论了神经网络如何使用迁移学习来完成各种计算机视觉任务。在这篇博客中,我们将探讨以下内容。
- VGG 建筑
- 使用预卷积特征微调 VGG
- 准确(性)
- PyTorch 和 Keras 在 Tensorflow 上的性能比较
VGG 建筑:
迁移学习中研究最多的深度学习模型之一是 VGG。我们将对 VGG 进行一个高层次的概述,以了解它是如何在迁移学习中得到最佳应用的。
VGG 模型可以分为两种逻辑块
- 卷积块:
预训练的 VGG 模型在超过 1000 个类别的图像网络数据集上被训练。卷积块包含多个卷积层。初始层包含低级特征,如直线、曲线。这个模块中的最后卷积层包含更复杂的图像特征,比如手、腿、眼睛等等。下图捕捉了不同图层中捕捉的特征类型。
从上面的图像中可以看出,预训练模型的卷积层捕捉到的特征可以用于大多数类型的图像问题。上述功能可能不适用于卡通动画、医学图像等问题,因为它们需要完全不同的功能。
卷积层表现出两个重要的特性
- 与全连接层相比,所需的参数数量要少得多。例如,具有 3 * 3 * 64 大小过滤器的卷积层仅需要 576 个参数。
- 卷积图层的计算开销很大,计算输出需要更长时间。
2。全连接块:
该区块包含密集(在 Keras 中)/线性(在 PyTorch 中)层,并有缺失。FC 层中要学习的参数数量巨大,但计算时间却少得多。
因此,我们通常最终按原样从 VGG 模型的卷积块中提取预卷积特征,并且仅训练通常来自全连接块的 VGG 模型的最后几层。
使用预卷积功能微调 VGG:
正如我们所知,卷积层的计算成本很高,因此计算一次卷积层的输出并使用它们来训练完全连接的层是有意义的。这种方法加快了使用迁移学习训练新模型的过程。例如,如果 1 次迭代需要 3 分钟来训练模型,则通过预先计算卷积层输出(假设需要 2 分钟),而对于 FC 块中的其余迭代,每次迭代只需要几秒钟。
预卷积特性:
我使用的是来自 kaggle 的 猫狗数据集,包含 25000 张图片。我保留了 2000 张图片用于验证,剩下的 23000 张用于训练。
硬件基准测试于:
我在上面提到的实验中使用了英特尔 i7 处理器、64 gb 内存和 Titan X GPU。
My Monster playing with NN weights 😃
为了计算卷积特征,我们让所有图像通过卷积层。幸运的是 pytorch 将 VGG 实现为两个逻辑块,由特征(卷积块)和分类器块(FC)组成。在下面的代码中,我们将使用 features 块来计算卷积层的输出。我们将它存储到 bcolz 数组中,以便进一步处理。Bcolz 数组提供了一个压缩和更快的方法来处理数组。
model_vgg = models.vgg16(pretrained=True)
for param in model_vgg.parameters():
param.requires_grad = False
def preconvfeat(dataset):
conv_features = []
labels_list = []
for data in dataset:
inputs,labels = datainputs , labels = Variable(inputs.cuda()),Variable(labels.cuda())
x = model_vgg.features(inputs)
conv_features.extend(x.data.cpu().numpy())
labels_list.extend(labels.data.cpu().numpy())
conv_features = np.concatenate([[feat] for feat in conv_features])
return (conv_features,labels_list)
我花了 1 分 8 秒来计算 23000 幅图像的训练数据集的特征。大小大约是 600 mb。
微调:
我们可以使用处理过的特征来训练完全连接的层。对于 10 次迭代,花费了 25 秒。使用 VGG 分类器块的代码段。
for param in model_vgg.classifier[6].parameters():
param.requires_grad = True
train_model(model=model_vgg.classifier,size=dset_sizes['train'],conv_feat=conv_feat_train,labels=labels_train,epochs=10,optimizer=optimizer,train=True,shuffle=True)
精确度:
在运行该模型大约 30 个时期之后,即在不到几分钟的时间内,验证准确度达到 97%。通过增加批次归一化和降低压差值,可以进一步提高精度。在这个笔记本里,我已经包括了我尝试过的其他实验。
PyTorch VGG 和 Keras 在 Tensorflow VGG 上的性能比较;
我在 Tensorflow 上使用 Keras 已经有一段时间了。所以我很想看看他们在时间方面的表现。我使用 PyTorch 版本 0.1.11 和 Tensorflow 版本 1.0.1 进行实验。
进行的实验:在卷积层权重不变的情况下运行预训练的 VGG 模型。未计算任何卷积特征。运行了 10 个时期的 23000 幅图像。下面是我的结果。
PyTorch — 15 分 19 秒
Tensoflow 上的 keras—31 分 29 秒
PyTorch 有数据加载器,可以一次使用多个线程来加载数据。当使用 6 个线程时,VGG 模型的性能提高到 11 分钟。
更新:根据下面的推文,我已经尝试使用 keras 和 6 个工人进行预处理,每个时期的性能从 3 分 21 秒提高到 1 分 40 秒。PyTorch 花了 6 个工人 1 分 11 秒。
结论:我在使用 Keras 和 pytorch 时所做的一些观察。Keras 太抽象,好上手,快速建立标准模型。预计性能将优于 PyTorch,但看起来并非如此,尽管 TensorFlow 有许多改进。另一方面,PyTorch 提供了类似于 Python NumPy 的 API 以及在 GPU 上操作的能力。学习曲线比 tensorflow 小得多,比 Keras 灵活得多。因此,如果你对深度学习充满热情,那么你绝对应该看看 PyTorch。
除了框架,我们还讨论了如何使用预卷积特性更快地训练模型。事实上,杰瑞米·霍华德在他的第二部分课程中,即将推出的 MOOC 讨论了脸书如何使用这些预先令人费解的特性的一种有趣的方法。该方法指出,“当不同的团队在同一数据集上工作时,计算这些卷积特征并使其对所有团队可用是很有意义的。”。这种方法将在建立模型时节省大量时间。事实上,脸书也在用类似的方式处理这个问题。
你可以在这里找到与实验相关的代码。
你可以在 LinkedIn 上找到我
使用新的 fastai 库实现世界级的结果
一个温和的介绍转移学习和 FastAI 图书馆的真实世界的例子,植物病害检测使用叶片图像。
动机
我目前正在做一个名为“程序员实用深度学习”的 fast.ai Live MOOC,将于 2019 年 1 月在 fast.ai 网站上公开。以下代码基于该课程的第 1 课。我将使用位于 Pytorch 1.0 之上的 fastai V1 库。fastai 库提供了许多有用的功能,使我们能够快速轻松地构建神经网络并训练我们的模型。我写这篇博客是为了在一个结构和复杂性都不同的数据集上实验课程示例,并展示使用 fastai 库是多么容易。
在下面的例子中,你会看到在 PlantVintage 数据集上进行迁移学习并获得世界级的结果是多么的简单。PlantVintage 数据包含植物叶片的图像,这些图像由作物上常见的 38 种疾病类别和一个来自斯坦福背景图像开放数据集的背景类别组成— DAGS 。我从 Github Repo 上的链接下载了数据。我对这个例子特别感兴趣,因为在我写这篇博客的时候,我为一个组织工作,该组织通过提供产品和技术解决方案来帮助农民发展他们的业务,以实现更好的农场管理。我们开始吧!
PS:这个博客也作为 jupyter 笔记本发布在我的 GitHub 个人资料上。
样板命令
用下面三行开始笔记本是一个标准的做法;它们确保您对库所做的任何编辑都会自动重新加载到此处,并且显示的任何图表或图像都会显示在此笔记本中。
%**reload_ext** autoreload
%**autoreload** 2
%**matplotlib** inline
导入快速人工智能库
让我们导入 fastai 库,并将 batch_size 参数定义为 64。通常,图像数据库是巨大的,所以我们需要使用批处理将这些图像馈送到 GPU 中,批处理大小 64 意味着我们将一次馈送 64 个图像,以更新我们的深度学习模型的参数。如果由于 GPU RAM 较小而导致内存不足,可以将批处理大小减少到 32 或 16。
**from** **fastai** **import** *
**from** **fastai.vision** **import** *
bs =64
看着这些数据
当我们处理一个问题时,我们做的第一件事就是看一看数据。我们总是需要非常好地理解问题是什么,数据看起来是什么样的,然后才能想出如何解决它。查看数据意味着了解数据目录的结构,标签是什么,以及一些示例图像是什么样子。我们的数据已经在 train 和 validation 文件夹中进行了拆分,在每个子目录中,我们的文件夹名称表示该子文件夹中所有图像的类名。幸运的是,fastai 库有一个专门为此设计的方便函数,imagedata bunch . from _ folder自动从文件夹名称中获取标签名称。fastai library 有棒极了的文档来浏览他们的库函数,并附有如何使用它们的实例。一旦加载了数据,我们还可以通过使用。标准化为 ImageNet 参数。
*## Declaring path of dataset*
path_img = Path('/home/jupyter/fastai_v3_experimentation/data/PlantVillage/')*## Loading data*
data = ImageDataBunch.from_folder(path=path_img, train='train', valid='valid', ds_tfms=get_transforms(),size=224, bs=bs, check_ext=**False**)*## Normalizing data based on Image net parameters*
data.normalize(imagenet_stats)
为了查看图像的随机样本,我们可以使用。show_batch()函数 ImageDataBunch 类。正如我们在下面看到的,我们有一些不同作物上的病害案例,加上一些来自 DAGS 数据集的背景噪声图像,这些图像将充当噪声。
data.show_batch(rows=3, figsize=(10,8))
让我们打印数据库中存在的所有数据类。总的来说,我们有 39 个类的图像,如上面在动机部分提到的。
print(data.classes)
len(data.classes),data.c
使用预训练模型进行迁移学习:ResNet 50
现在我们将开始训练我们的模型。我们将使用一个卷积神经网络主干 ResNet 50 和一个具有单个隐藏层的全连接头作为分类器。如果你想了解所有的架构细节,你也可以阅读 ResNet 论文。要创建迁移学习模型,我们需要使用 Learner 类中的函数 create_cnn,并从 models 类中输入一个预先训练好的模型。
*## To create a ResNET 50 with pretrained weights*
learn = create_cnn(data, models.resnet50, metrics=error_rate)
create_cnn 函数创建的 ResNet50 模型冻结了初始层,我们将学习最后完全连接的层的权重。
learn.fit_one_cycle(5)
正如我们在上面看到的,通过使用默认设置运行五个时期,我们在验证数据集上的细粒度分类任务的准确度大约为 99.64%。让我们保存模型,因为我们稍后将对其进行微调。如果你想知道这个结果有多好,已经从这个 Github 页面击败了浅层学习(只训练最后一层)基准 96.53%。
learn.save('plant_vintage_stage1')
FastAI 库还提供了一些功能来更快地探索结果,并发现我们的模型是否正在学习它应该学习的内容。我们将首先看到模型最容易混淆的类别。我们将尝试使用 ClassificationInterpretation 类来查看模型预测是否合理。
interp = ClassificationInterpretation.from_learner(learn)interp.plot_top_losses(4, figsize=(20,25))
在这种情况下,该模型在从玉米植株上的灰色叶斑中检测北方叶枯病和在视觉上看起来非常相似的番茄叶中的早期/晚期叶枯病时变得混乱。这表明我们的分类器工作正常。此外,当我们绘制混淆矩阵时,我们可以看到大多数东西都被正确分类,这几乎是一个近乎完美的模型。
interp.plot_confusion_matrix(figsize=(20,20), dpi=60)
因此,到目前为止,我们只训练了最后的分类层,但如果我们想优化更早的层。在迁移学习中,调整初始层应该谨慎,学习速度应该保持在相当低的水平。FastAI 库提供了一个函数来查看训练的理想学习率,所以让我们来画一个图。lr_find 函数以多种学习速率运行数据子集的模型,以确定哪种学习速率最好。
learn.lr_find()
learn.recorder.plot()
看起来我们应该保持我们的学习率低于 10e-4。对于网络中的不同层,我们可以使用切片函数在 10e-6 到 10e-4 之间对数分布学习速率。保持初始层的最低学习速率,并增加后续层的学习速率。让我们解冻所有层,以便我们可以使用 unfreeze()函数训练整个模型。
learn.unfreeze()
learn.fit_one_cycle(2, max_lr=slice(1e-7,1e-5))
正如我们通过训练所有层所看到的,我们将准确率提高到了 99.7%,与使用 Inception-v3 模型的 Github 基准测试的 99.76%相当。
结论
Fast.ai 是杰瑞米·霍华德和他的团队的一个很好的倡议,我相信 fastai library 可以通过让构建深度学习模型变得超级简单来真正实现将深度学习民主化到每个人的动机。
我希望你喜欢阅读,并随时使用我的代码来尝试它为您的目的。此外,如果对代码或博客帖子有任何反馈,请随时联系 LinkedIn 或给我发电子邮件,地址是 aayushmnit@gmail.com。
PyTorch 中卷积神经网络的迁移学习
(Source)
如何用 PyTorch 使用预训练的卷积神经网络进行对象识别
虽然 Keras 是一个很棒的库,有一个简单的 API 来构建神经网络,但是最近关于 PyTorch 的兴奋终于让我有兴趣探索这个库。虽然我是一个盲目跟风炒作的人,但研究人员采用和将纳入 fast.ai 库让我相信,深度学习的这个新条目背后一定有什么东西。
由于学习新技术的最好方式是用它来解决问题,我学习 PyTorch 的努力从一个简单的项目开始:使用一个预先训练好的卷积神经网络来完成物体识别任务。在本文中,我们将看到如何使用 PyTorch 来实现这个目标,同时了解一些关于库和迁移学习的重要概念。
虽然 PyTorch 可能不适合所有人,但在这一点上,还不能说哪个深度学习库会胜出,能够快速学习和使用不同的工具对于数据科学家的成功至关重要。
这个项目的完整代码可以从 GitHub 上的 Jupyter 笔记本中获得。这个项目诞生于我参与的 Udacity PyTorch 奖学金挑战赛。
Predicted from trained network
迁移学习方法
我们的任务将是训练一个卷积神经网络(CNN),它可以识别图像中的对象。我们将使用加州理工学院 101 数据集,它包含 101 个类别的图像。大多数类别只有 50 幅图像,这通常不足以让神经网络学习到高精度。因此,我们将使用应用迁移学习的预先构建和训练的模型,而不是从头开始构建和训练 CNN。
转移学习的基本前提很简单:取一个在大数据集上训练的模型,将其知识转移到一个更小的数据集。对于 CNN 的物体识别,我们冻结了网络的早期卷积层,只训练最后几层进行预测。这个想法是,卷积层提取适用于图像的一般、低级特征,如边缘、图案、梯度,后面的层识别图像中的特定特征,如眼睛或车轮。
因此,我们可以使用在大规模数据集(通常是 Imagenet)中的不相关类别上训练的网络,并将其应用于我们自己的问题,因为图像之间存在通用的低级特征。加州理工学院 101 数据集中的图像与 Imagenet 数据集中的图像非常相似,模型在 Imagenet 上学习的知识应该很容易转移到这项任务中。
Idea behind Transfer Learning (source).
以下是用于对象识别的迁移学习的一般概述:
- 加载在大型数据集上训练的预训练 CNN 模型
- 冻结模型较低卷积层中的参数(权重)
- 向模型添加带有多层可训练参数的自定义分类器
- 根据任务可用的训练数据训练分类器层
- 微调超参数并根据需要解冻更多层
这种方法已被证明在许多领域取得了成功。这是一个很好的工具,并且通常是当遇到新的图像识别问题时应该尝试的第一种方法。
数据设置
对于所有的数据科学问题,正确格式化数据将决定项目的成败。幸运的是,加州理工学院 101 数据集图像是干净的,并以正确的格式存储。如果我们正确地设置了数据目录,PyTorch 可以很容易地将正确的标签与每个类关联起来。我将数据分成 50%、25%、25%的培训、验证和测试集,然后将目录构建如下:
/datadir
/train
/class1
/class2
.
.
/valid
/class1
/class2
.
.
/test
/class1
/class2
.
.
按类别分类的训练图像的数量如下(我交替使用术语类别和种类):
Number of training images by category.
我们期望模型在有更多例子的类上做得更好,因为它可以更好地学习将特征映射到标签。为了处理数量有限的训练示例,我们将在训练过程中使用数据扩充(稍后将详细介绍)。
作为另一个数据探索,我们还可以看看大小分布。
Distribution of average image sizes (in pixels) by category.
Imagenet 模型需要 224 x 224 的输入尺寸,因此预处理步骤之一就是调整图像的大小。预处理也是我们为训练数据实现数据扩充的地方。
数据扩充
数据扩充的想法是通过对图像进行随机变换,人为增加我们的模型看到的训练图像的数量。例如,我们可以随机旋转或裁剪图像,或者水平翻转它们。我们希望我们的模型能够区分对象,而不考虑方向,数据扩充也可以使模型对输入数据的变换不变。
不管面向哪个方向,大象还是大象!
Image transformations of training data.
增强通常仅在训练期间完成(尽管测试时间增强在 [fast.ai](https://blog.floydhub.com/ten-techniques-from-fast-ai/)
库中是可能的)。每个历元(通过所有训练图像的一次迭代)对每个训练图像应用不同的随机变换。这意味着,如果我们迭代数据 20 次,我们的模型将看到每幅图像的 20 个略有不同的版本。总的结果应该是一个学习对象本身的模型,而不是它们如何呈现或图像中的伪像。
图像预处理
这是处理图像数据最重要的一步。在图像预处理过程中,我们同时为我们的网络准备图像,并对训练集应用数据扩充。每个模型都有不同的输入要求,,但是如果我们通读 Imagenet 的要求,我们会发现我们的图像需要是 224x224,并标准化到一个范围。
为了在 PyTorch 中处理图像,我们使用了transforms
,这是应用于数组的简单操作。验证(和测试)转换如下:
- 调整大小
- 居中裁剪至 224 x 224
- 转换成张量
- 用平均值和标准偏差标准化
通过这些变换的最终结果,是可以进入我们网络的张量。训练变换是相似的,但是增加了随机增强。
首先,我们定义培训和验证转换:
然后,我们创建datasets
和DataLoaders
。通过使用datasets.ImageFolder
制作数据集,PyTorch 将自动将图像与正确的标签关联起来,前提是我们的目录如上所述设置。然后数据集被传递给一个DataLoader
,一个迭代器,产生一批图像和标签。
我们可以看到DataLoader
的迭代行为,如下所示:
# Iterate through the dataloader once
trainiter = iter(dataloaders['train'])
features, labels = next(trainiter)
features.shape, labels.shape**(torch.Size([128, 3, 224, 224]), torch.Size([128]))**
一批的形状是(batch_size, color_channels, height, width)
。在训练、验证和最终测试期间,我们将遍历DataLoaders
,一次遍历包含一个时期的完整数据集。每个时期,训练DataLoader
将对图像应用稍微不同的随机变换,用于训练数据扩充。
用于图像识别的预训练模型
有了我们的数据,我们接下来将注意力转向模型。为此,我们将使用预训练的卷积神经网络。PyTorch 拥有许多模型,这些模型已经在 Imagenet 的 1000 个类的数百万张图像上进行了训练。完整的型号列表可以在这里看到。这些模型在 Imagenet 上的性能如下所示:
Pretrained models in PyTorch and performance on Imagenet (Source).
对于这个实现,我们将使用VGG-16
。虽然它没有记录最低的错误,但我发现它很适合这项任务,并且比其他模型训练起来更快。使用预先训练好的模型的过程已经建立:
- 从在大型数据集上训练的网络中加载预先训练的权重
- 冻结较低(卷积)层中的所有权重:根据新任务与原始数据集的相似性来调整要冻结的层
- 用一个定制的分类器代替网络的上层:输出的数量必须设置成等于类的数量
- 仅为任务训练自定义分类器层,从而为较小的数据集优化模型
在 PyTorch 中加载预先训练好的模型非常简单:
from torchvision import models
model = model.vgg16(pretrained=True)
这个模型有超过 1.3 亿个参数,但我们将只训练最后几个完全连接的层。最初,我们冻结模型的所有权重:
# Freeze model weights
for param in model.parameters():
param.requires_grad = False
然后,我们添加我们自己的自定义分类器,包含以下层:
- 与 ReLU 激活完全连接,shape = (n_inputs,256)
- 辍学几率为 40%
- 与 log softmax 输出完全连接,shape = (256,n_classes)
import torch.nn as nn# Add on classifier
model.classifier[6] = nn.Sequential(
nn.Linear(n_inputs, 256),
nn.ReLU(),
nn.Dropout(0.4),
nn.Linear(256, n_classes),
nn.LogSoftmax(dim=1))
当额外的层被添加到模型中时,它们被默认设置为可训练的(require_grad=True
)。对于 VGG-16,我们只改变了最后一个原始的全连接层。卷积层和前 5 个全连接层中的所有权重都是不可训练的。
# Only training classifier[6]
model.classifier**Sequential(
(0): Linear(in_features=25088, out_features=4096, bias=True)
(1): ReLU(inplace)
(2): Dropout(p=0.5)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): ReLU(inplace)
(5): Dropout(p=0.5)
(6): Sequential(
(0): Linear(in_features=4096, out_features=256, bias=True)
(1): ReLU()
(2): Dropout(p=0.4)
(3): Linear(in_features=256, out_features=100, bias=True)
(4): LogSoftmax()
)
)**
网络的最终输出是我们数据集中 100 个类别中每个类别的对数概率。该模型共有 1.35 亿个参数,其中仅超过 100 万个将被训练。
# Find total parameters and trainable parameters
total_params = sum(p.numel() for p in model.parameters())
print(f'{total_params:,} total parameters.')
total_trainable_params = sum(
p.numel() for p in model.parameters() if p.requires_grad)
print(f'{total_trainable_params:,} training parameters.')**135,335,076 total parameters.
1,074,532 training parameters.**
将模型移动到 GPU
PyTorch 最好的一个方面是可以轻松地将模型的不同部分移动到一个或多个 GPU 上,这样你就可以充分利用你的硬件。由于我使用 2 个 GPU 进行训练,我首先将模型移动到cuda
,然后创建一个分布在 GPU 上的DataParallel
模型:
# Move to gpu
model = model.to('cuda')
# Distribute across 2 gpus
model = nn.DataParallel(model)
(此笔记本应在 gpu 上运行,以便在合理的时间内完成。cpu 的加速比可以轻松提高 10 倍甚至更多。)
培训损失和优化
训练损失(预测值和真实值之间的误差或差异)是负对数似然 (NLL)。(PyTorch 中的 NLL 损失预期对数概率,因此我们从模型的最终层传入原始输出。) PyTorch 使用自动微分这意味着张量不仅记录它们的值,还记录每一次运算(乘法、加法、激活等)。)对价值有贡献。这意味着我们可以计算网络中任何张量相对于任何先前张量的梯度。
这实际上意味着损失不仅跟踪误差,还跟踪在模型中每个权重和偏差对误差的贡献。计算损耗后,我们可以找到损耗相对于每个模型参数的梯度,这个过程称为反向传播。一旦我们有了梯度,我们就用它们来更新优化器的参数。(如果一开始没有理解,不要担心,需要一点时间来掌握!这张幻灯片有助于澄清一些观点。)
优化器是 Adam ,它是梯度下降的有效变体,通常不需要手动调整学习速率。在训练期间,优化器使用损失的梯度来尝试通过调整参数来减少模型输出的误差(“优化”)。只有我们在自定义分类器中添加的参数才会被优化。
损失和优化程序初始化如下:
from torch import optim# Loss and optimizer
criteration = nn.NLLLoss()
optimizer = optim.Adam(model.parameters())
有了预先训练好的模型、自定义分类器、损耗、优化器以及最重要的数据,我们就可以开始训练了。
培养
PyTorch 中的模型训练比 Keras 中的模型训练需要更多的动手操作,因为我们必须自己完成反向传播和参数更新步骤。主循环在多个时期上迭代,并且在每个时期上我们迭代通过火车DataLoader
。DataLoader
产生我们通过模型传递的一批数据和目标。在每个训练批次之后,我们计算损失,反向传播损失相对于模型参数的梯度,然后用优化器更新参数。
我建议您查看笔记本了解完整的培训细节,但基本伪代码如下:
我们可以继续迭代数据,直到达到给定的历元数。然而,这种方法的一个问题是,我们的模型最终会开始过度适应训练数据。为了防止这种情况,我们使用我们的验证数据和提前停止。
提前停止
提前停止表示当验证损失在多个时期内没有减少时,停止训练。随着我们继续培训,培训损失只会减少,但验证损失最终会达到最小值,并趋于平稳或开始增加。理想情况下,我们希望在验证损失最小的时候停止训练,希望这个模型能够最好地概括测试数据。当使用早期停止时,在验证损失减少的每个时期,我们保存参数,以便我们可以稍后检索具有最佳验证性能的参数。
我们通过在每个训练时期结束时迭代验证DataLoader
来实现早期停止。我们计算验证损失,并将其与最低验证损失进行比较。如果损失是目前为止最低的,我们保存模型。如果损失在一定数量的时期内没有改善,我们停止训练并返回已经保存到磁盘的最佳模型。
同样,完整的代码在笔记本上,但伪代码是:
要了解提前停止的好处,我们可以查看显示训练和验证损失以及准确性的训练曲线:
Negative log likelihood and accuracy training curves
不出所料,随着进一步的培训,培训损失只会继续减少。另一方面,验证损失达到最小值并处于平稳状态。在某个时期,进一步训练是没有回报的(甚至是负回报)。我们的模型将只开始记忆训练数据,而不能推广到测试数据。
如果不提前停止,我们的模型将训练超过必要的时间和将过度适应训练数据。
我们可以从训练曲线中看到的另一点是,我们的模型没有过度拟合。总会有一些过拟合,但是第一个可训练全连接层之后的下降防止训练和验证损失偏离太多。
做出预测:推理
在笔记本中,我处理了一些无聊但必要的保存和加载 PyTorch 模型的细节,但这里我们将直接进入最精彩的部分:对新图像进行预测。我们知道我们的模型在训练甚至验证数据方面做得很好,但最终的测试是它在以前从未见过的测试集上的表现。我们保存了 25%的数据,目的是确定我们的模型是否可以推广到新数据。
用经过训练的模型进行预测非常简单。我们使用与训练和验证相同的语法:
for data, targets in testloader:
log_ps = model(data)
# Convert to probabilities
ps = torch.exp(log_ps)ps.shape()**(128, 100)**
我们概率的形状是(batch_size
,n_classes
),因为我们对每一类都有一个概率。我们可以通过找到每个示例的最高概率来确定准确性,并将这些概率与标签进行比较:
# Find predictions and correct
pred = torch.max(ps, dim=1)
equals = pred == targets# Calculate accuracy
accuracy = torch.mean(equals)
当诊断用于对象识别的网络时,查看测试集的整体性能和单个预测会很有帮助。
模型结果
这是模型钉子的两个预测:
这些都很简单,所以我很高兴这个模型没有问题!
我们不想只关注正确的预测,我们很快就会看到一些错误的输出。现在,让我们评估整个测试集的性能。为此,我们想要迭代测试DataLoader
并计算每个例子的损失和准确性。
用于对象识别的卷积神经网络一般用 topk 精度来衡量。这指的是真实的类是否在 k 个最可能预测的类中。例如,前 5 名准确率是指正确的类别在 5 个最高概率预测中所占的百分比。您可以从 PyTorch 张量中获得 topk 个最可能的概率和类,如下所示:
top_5_ps, top_5_classes = ps.topk(5, dim=1)
top_5_ps.shape**(128, 5)**
在整个测试集上评估模型,我们计算指标:
**Final test top 1 weighted accuracy = 88.65%
Final test top 5 weighted accuracy = 98.00%
Final test cross entropy per image = 0.3772.**
与验证数据上接近 90%的前 1 名准确度相比,这是有利的。总的来说,我们得出结论,我们的预训练模型能够成功地将其知识从 Imagenet 转移到我们更小的数据集。
模型调查
虽然这个模型做得很好,但可能还需要采取一些措施来使它变得更好。通常,找出如何改进模型的最佳方法是调查其错误(注意:这也是一种有效的自我改进方法。)
我们的模型不擅长识别鳄鱼,所以让我们来看看这一类别的一些测试预测:
鉴于crocodile
和crocodile_head
之间的微妙区别,以及第二幅图像的难度,我要说我们的模型在这些预测中并非完全不合理。图像识别的最终目标是超越人类的能力,我们的模型就快实现了!
最后,我们希望该模型在包含更多图像的类别中表现更好,因此我们可以查看给定类别的准确性与该类别中训练图像数量的关系图:
在训练图像的数量和前 1 名测试准确度之间确实存在正相关。这表明更多的训练数据增加可能是有帮助的 l,或者,甚至我们应该使用测试时间增加。我们还可以尝试不同的预训练模型,或者构建另一个自定义分类器。目前,深度学习仍然是一个经验领域,这意味着经常需要实验!
结论
虽然有更容易使用的深度学习库,但 PyTorch 的优势是速度,对模型架构/训练的每个方面的控制,使用张量自动微分的反向传播的有效实现,以及由于 PyTorch 图形的动态特性而易于调试代码。对于生产代码或您自己的项目,我不确定是否有令人信服的理由使用 PyTorch 而不是学习曲线较平缓的库,如 Keras,但是知道如何使用不同的选项是有帮助的。
通过这个项目,我们能够看到使用 PyTorch 的基础知识以及迁移学习的概念,这是一种有效的对象识别方法。我们可以使用已经在大型数据集上训练过的现有架构,然后针对我们的任务调整它们,而不是从头开始训练模型。这减少了训练的时间,通常会带来更好的整体表现。这个项目的成果是迁移学习和 PyTorch 的一些知识,我们可以在此基础上构建更复杂的应用程序。
我们确实生活在一个令人难以置信的深度学习时代,任何人都可以利用容易获得的资源建立深度学习模型!现在,走出去,通过构建自己的项目来利用这些资源。
一如既往,我欢迎反馈和建设性的批评。可以通过推特 @koehrsen_will 或者通过我的个人网站 willk.online 找到我。
用 PyTorch 迁移学习
机器学习的未来如此光明,因为激励措施是全面一致的:大玩家急切地开源工具并投资更快的硬件以摆脱他们基于广告的商业模式。修补匠发现小众应用前所未闻。数据变得更加可替代,用于私人、公共、科学、休闲和不利用途。我可以就未来的完美风暴谈上几个小时(也许还有一些逆向思维),但让我们坚持一件实际的事情:如何利用最近可用的预训练机器学习模型的上升。
迁移学习
相关的任务需要一小部分潜在能力来辨别看不见的数据。例如,无论你是弹吉他还是弹钢琴,你都会比不习惯弹吉他的人更擅长弹奏和弦。用机器学习的术语来说,这意味着你可以复制其他人的训练成果,并对其进行调整,以快速分类热狗和非热狗的图片,或者让其生成相当新颖的产品评论。
Sebastian Ruder 很好地概括了模型重用的复合收益。
特别是,迁移学习改善了决定机器学习项目技术方面的所有维度:
- 人的效率。如果你想挤出最后一点信号,让模型变得可解释、易处理和健壮,你需要专家。多亏了学术研究,在相关任务中经过实战检验的架构应运而生。
- 计算效率。最先进的论文通常在 2 到 8 个 GPU 的集群上训练大约两周。虽然,真的没有限制。有了迁移学习,你可以通过部分地或更少地改变内部参数来节省时间。
- 数据效率。如果其他人在大型数据集上受过训练(他或她甚至不需要透露),那么在大多数情况下需要的领域特定数据就更少。事实上,在不到 5MB 的下载中,你如何能够重新利用一个型号是令人难以置信的。
地标建筑
迁移学习被广泛用于更好地区分特定的图像类别。 Canziani 等人(2016) 在 imagenet 数据集上比较了主要架构的计算效率。
具体来说,根据您的设备限制,您可以将计算成本进一步划分为训练时间、推理时间和内存需求。在最近的一次兼职中,考虑到非常具体的限制,我需要更深入地挖掘。
首先,新数据经常出现。第二,这些图像也是潜在的专利。因此,再培训必须在本地中间层 GPU 上可靠地进行,而不需要外部专家的纵容。从用户的角度来看,如果再培训能在一致的时间内给出一致的结果,那么它就是可靠的,就像你点击要完成的打印任务一样。因此,基准测试将使用一种简单的优化方法,这种方法比数据效率更有利于收敛。第三,对于一批大约四幅图像,每个预测需要接近实时地发生。因此,我们关心推理次数。最后,我们关心作为业务决策输入的图像(或图像的一部分)的确切类别。因此,我们将最高精度考虑在内。
现在,为了通过不断发展的数据集将专家的成本降低到几乎为零,并使计算时间符合硬约束,让我们来看看业界最令人垂涎的工具之一的模型动物园:PyTorch。
结果
PyTorch 如今大受欢迎有几个原因。
够公平:该框架相当完整、简洁,用代码动态定义了整个计算图,并且易于调试。torchvision 软件包中的一行代码可以加载六个原型:AlexNet、DenseNets、Inception、SqueezeNet 和 VGG。为了了解它们是如何产生的,我推荐阅读。
不幸的是,API 不允许用自定义数量的类加载预先训练好的模型,而不用手动重新实现最终层。因此,我写了一个函数,从原理上解决了这个问题。它合并预先训练的参数,使它们不会干扰自定义输出层。因此,我们可以系统地比较所有可用架构中我们关心的性能指标。
SGD with same momentum and learning rate for each model and 15 epochs on 2xK80
图表中的模型仅在最终层(浅层)、针对整个参数集(深层)或从其初始化状态(从头开始)被重新训练。在所有运行中,双 K80 GPUs 运行了大约 75%。
如数据所示,SqueezeNet 1.1 兑现了成为高效计算架构的承诺。因为再训练层和静态层的划分有些武断,仅仅基于浅再训练模型的结论太牵强。例如,VGG13 的最终分类器有 8194 个参数,而 ResNet34 的最终层更窄,有 1026 个参数。因此,只有对学习策略的超参数搜索才能使给定目标的比较真正有效。然而,对于这个数据集中的少量类(准确地说是二进制),SqueezeNet 学习的速度快得令人难以置信。
结论
需要注意的一点是,在相同的训练时间内,深度再训练比浅度再训练产生的准确度要低。在其他任务中,我和其他模特也遇到过这种情况。我对此的理论是,从先前的局部最优解中拧出更深的卷积平均来说发生得很慢(小误差梯度),并且是在随机初始化后的不太平滑的流形上。因此,参数在转换阶段结束并列。如果看不见的特征与原始数据相比在规模上有所不同,这种间歇性的混乱应该是特别真实的,这就是今天的玩具数据集的情况:有时近距离有蚂蚁,有时你观察到整个群体。
所以事实上,你可能会被很好地建议选择更高的学习率,你调整的层数越多,或者在某个时候使用而不是比例不变网络。
为了评估由推理和重新训练时间组成的计算效率,这是一个很好的开始。如果你想进一步提高再训练的效率,你可以跳过数据扩充,缓存来自未训练层的结果。当然,结论会随着类的数量、前面提到的其他因素和特定的约束而不同。这就是为什么你想自己到达。为此,我在 github 上发布了原始指标和附带代码。
重新训练快乐!
熊猫中堆栈、融化、数据透视表的转换
改变数据表示和恢复的 3 种方法
Photo by Outer Digit on Unsplash
完整笔记本在https://gist . github . com/git githan/0ba 595 e 3e F9 cf 8 fab 7 deeb 7 b 8 b 533 ba 3
或者,点击这个可滚动框右下角的“查看原始数据”并将 json 保存为。ipynb 文件
在本文中,我将探索 python 的 pandas 数据操作库的 dataframe.stack()、dataframe.melt()、dataframe.pivot_table 如何在转换管道中相互交互,以重塑数据帧并恢复原始数据帧,同时通过遵循代码来了解许多注意事项。
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = “all”import pandas as pd
默认情况下,jupyter 笔记本只显示每个单元格的最后一行。前两行让 jupyter 显示所有变量的输出,以方便避免将 print()放在我希望看到的每个变量周围。接下来,我们导入 pandas 库,在这里我们从。
方法一:df→栈→reset_index →pivot →df
Figure 1
df= pd.DataFrame([[0, 1], [2, 3]],index=['cat', 'dog'],columns=['weight', 'height'])print('{:*^80}'.format('dataframe'))
dfprint('{:*^80}'.format('stacked dataframe'))
df.stack()
在这里,我们创建数据帧。然后,df.stack()将我们的单级列 df 转换为具有多索引索引的数据序列,方法是将这些列放入一个新的内部索引(索引级别 1 ),用于旧的外部索引(索引级别 0)中的每个值。外层看起来只有 2 个值[猫,狗],但这只是为了整齐显示,实际上是 4 个值[猫,猫,狗,狗]。有用的注意事项来自:https://pandas . pydata . org/pandas-docs/stable/generated/pandas。DataFrame.stack.html
**如果列有多个级别,则新的索引级别取自指定的级别,并且输出是数据帧。**所以最好记住转换输出是数据序列还是数据帧。
print('{:*^80}'.format('stacked dataframe with index in column'))
df.stack().reset_index(level = 1) #AttributeError: 'Series' object has no attribute 'pivot_table' , so must convert to dataframe before pivot_table
stacked = df.stack().reset_index(level = 1)
这些值根据索引对齐,将数据帧从宽格式转换为长格式数据序列。因为 pivot_table 是一个 dataframe 方法,并不适用于 dataseries,所以我们可以使用 reset_index(level = 1)提取多索引的第 1 级,以准备转回。指定 level = 0 会将外部索引提取到列中。请注意,在 reset_index()之后会自动添加“level_1”作为列名。这将是额外的信息,可以在以后使用或清除并忽略。值上方的 0 列也会自动添加。
在此阶段提取 0 级还是 1 级并不重要。您可以稍后简单地将输入切换到 pivot_table 的 index 和 columns 参数,以获得相同的输出(除了微小的 df.columns.name 差异)并恢复原始数据帧。
print('{:*^80}'.format('pivot_table recovered original dataframe (with extra name for columns)'))
recovered_df1 = df.stack().reset_index(level = 1).pivot_table(index = stacked.index, columns = 'level_1',values = 0) #pivot_table orders columns alphabetically,specifying values parameter prevents creation of useless multiindex column
recovered_df1.columns.name = None #remove 'level_1' column.name
recovered_df1
最后,我们通过从当前列名中选择来指定 pivot_table 中的索引和列参数,以描述最终的透视数据帧应该是什么样子。values 参数是可选的,但不指定它会将尚未在 index 或 columns 参数中指定的列名添加到当前列的外层,从而创建看起来很难看的多索引列,并使数据访问变得不必要的困难。
方法 2:df→堆栈→转换为数据帧→透视→df
Figure 2
print('{:*^80}'.format('dataframe'))
df
print('{:*^80}'.format('stack and convert to dataframe to expose pivot_table'))
stacked_df = pd.DataFrame(df.stack())
stacked_df
请记住,pivot_table 是一个 dataframe 方法,并不适用于数据序列,因此,我们可以使用 pd 从数据序列中直接构造一个 dataframe,而不是像第 1 部分那样使用 reset_index。DataFrame(df.stack())创建一个多索引的 DataFrame,使 pivot_table 方法可用,并更加努力地正确指定其参数。
print('{:*^80}'.format('rather than unstack, pivot_table achieves the same'))
idx_lvl0, idx_lvl1 = stacked_df.index.get_level_values(0), stacked_df.index.get_level_values(1)
recovered_df2 = stacked_df.pivot_table(index=idx_lvl0,columns = idx_lvl1,values = 0)
recovered_df2
index.get_level_values(0)是一种以 pandas.core.indexes.base.Index 对象的形式获取指定多索引级别(在本例中为 0)的索引值的方法,接受序列/列表的函数可以方便地使用该对象。在第 2 部分中,我们将每个级别的正确索引信息匹配到数据透视表的索引和列参数中,以恢复原始数据帧。第 2 部分比第 1 部分更清晰,因为没有 reset_index 来在 df.columns.name 中创建额外的“level_0”或“level_1 ”,我们在第 1 部分中将其设置为 None。
方法三:df→融→加指数→支点→df
Figure 3
print('{:*^80}'.format('dataframe'))
df
print('{:*^80}'.format('melting loses index information'))
melted = df.melt() #melt appends columns into new "variable" column, while stack adds columns to new inner index layer (same information end up different places)
melted
与堆栈类似,melt 通过将压缩列放入单个列表中,将宽格式数据转换为长格式数据。不同的是,stack 将这个列表插入到内部索引中,而 melt 将这个列表作为一个名为’ variable '(可以重命名)的新列插入。
print('{:*^80}'.format('manually enrich index')) # until this is solved: [https://github.com/pandas-dev/pandas/issues/17440](https://github.com/pandas-dev/pandas/issues/17440)
melted.index = ['cat','dog']*2 #list(df.index)*len(df.columns) for more generalizable index generation
melted
注意,melt 已经让索引中的猫狗信息消失了。这使得无法恢复原始数据帧。在这个问题(https://github.com/pandas-dev/pandas/issues/17440)解决之前,我们必须手动添加回索引。
print('{:*^80}'.format('pivot_table recovered original dataframe (with extra name for columns)'))
recovered_df3 = melted.pivot_table(index = melted.index, columns = 'variable',values = 'value')
recovered_df3.columns.name=None #remove 'variable' column.name
recovered_df3
最后,带有正确参数的 pivot_table 将恢复我们的原始数据帧。与第 1 部分一样,为了精确恢复,从 df.columns.name 中删除了“variable”。
结论
我希望这些转换能让这些函数的初学者更好地理解 pandas 有多灵活。可以使用 set_index 和 reset_index 将相同的信息放在索引或列中,这取决于它们在何处发挥最大作用。例如,当信息在列中时,不使用 df.loc[df.col == value]进行筛选,而是将 col 设置为索引,然后使用 df.loc[value]就简单多了。信息是在索引中还是在列中也会极大地影响 pd.merge、pd.concat、dataframe.join 如何处理这样的数据系列/数据帧,但那将是另一篇完整的文章。
Stack 允许信息从列到索引,反之亦然(使用 unstack())。Melt 将列组合成 id_vars,variable,value 的标准 3 列格式,以允许在用编辑的列值旋转回来之前对变量进行列处理。Pivot_table 是 3 个参数中最强大的,其他参数如 aggfunc(聚合)允许自定义函数,因此可能性是无限的。
最后,这里有一个对我帮助很大的实际例子:http://pbpython.com/pandas-pivot-table-explained.html
用熊猫融化在 Python 中转换数据
世界银行拥有互联网上最丰富的数据来源之一。这些数据有许多实际应用,如预测经济增长或用机器学习预测贫困。我最近用这些数据制作了一些撒哈拉以南非洲人均 GDP 增长的可视化表格(年化增长、累积增长)。
然而,前进的道路上有一个巨大的路障。我的世界银行数据无法在 Tableau 上使用。Tableau 更适合数据库样式的格式,而不是您在 Excel 中看到的金融和经济数据的典型格式。
我必须转换数据,使其在 Tableau 中工作。用 Python 来做这件事的一个方法是用熊猫融化。Pd.melt 允许您将数据从“宽格式”转换为“长格式”,非常适合我的任务:获取“宽格式”经济数据,每列代表一年,然后将其转换为“长格式”数据,每行代表一个数据点。
获取数据
在我开始编码之前,我想向您展示如何访问数据。如果您只想了解 pandas.melt,请随意跳到下一部分(“用 Pandas Melt 进行改造”)。如果想做完整教程(取世行数据,做 Tableau 动画),第一步是去世行公开数据网站。
有许多不同的方法来获取人均国内生产总值数据。你可以点击主页上的“按指标浏览”(见下图中的橙色框),然后向下滚动到“经济和增长”部分,在那里你会找到一些人均 GDP 指标。
或者,您可以开始在搜索栏中键入您想要的度量。
对于我的分析,我做了年化和累积人均 GDP 增长;这两个指标都需要稍微复杂一点,所以让我们简化一下,把重点放在“人均 GDP 增长率(年%)”上。一旦你选择了你的类别,你将得到世界数据。你可以点击“地图”查看国家和年份的数据。我们需要去“数据库”直接研究这些数据。
我们将得到一个复杂的屏幕,看起来像下面的图片:
在处理世界银行的数据时有一些挫折。如果你正在跟进,我建议尝试做一些比撒哈拉以南非洲增长更简单的事情。而是关注国家更少的南美。
首先,我们需要“取消全选”然后我们将选择几个南美国家:阿根廷、巴西、智利、秘鲁和委内瑞拉。如果您想要更全面的演示,也可以随意将其他国家添加到您的数据集中(巴拉圭、乌拉圭、玻利维亚、厄瓜多尔、哥伦比亚、圭亚那、苏里南)。现在查看“时间”,确保检查了 2000 年至 2016 年的所有年份。
在屏幕右上角找到“下载选项”并下载 Excel 文件。我们有一大堆看起来像这样的数据:
问题是 Tableau 想要一种数据库风格的格式。我们需要我们的数据看起来更像这样:
请注意,不同之处在于,数据库样式的格式为每个国家和日期提供了单独的一行,而不是为每个单独的年份提供列。
在我们使用 pandas.melt 之前,我们需要先清理一下我们的数据。让我们删除无用的列,如“系列名称”、“系列代码”和“国家代码”我们还需要将日期更改为 mm/dd/yyyy 格式。我们可以在 Python 中做到这一点,但通常情况下,更简单的方法是只输入前两年的 12/31/yyyy(输入“yyyy”的年份),然后使用 Excel 的 fill 命令来完成剩下的工作。最后,删除底部的源数据(“数据库中的数据”,“上次更新”)。现在我们准备用 Python 来转换数据。
变身熊猫融化
首先,我们需要导入熊猫和数据集。这将取决于您的文件位置,但您的代码应该看起来像这样。
import pandas as pddf = pd.read_excel('C:\PlaceYourDataComesFrom\data.xlsx', sheetname='data')print(df.head())
使用 df.head()确保数据正确加载。现在,我们将使用 pd.melt 来重新格式化它。
d = pd.melt(df, 'Country Name', var_name='Date', value_name='GDPperCapGrowth%')print(d.head())
最后一步是用我们转换后的输出生成一个新的 Excel 文件。
d.to_excel(r'C:\PlaceYouWantYourDataToGo\output.xlsx', sheet_name='GDPperCapGr', index=False)
现在,转换后的数据在 Tableau 中应该工作得很好。
一点点 o’ Tableau
由于这是一个熊猫融化教程,我不会花太多时间在 Tableau 上,但如果你想看看你的地图会是什么样子,你首先需要在你的电脑上 Tableau。你可以在 Tableau 公共网站下载免费版本。
公开展示画面。连接到 Excel 文件。加载转换后的 Excel 数据。单击 Tableau 底部的“Sheet 1 ”,您应该会看到您的数据。
在“维度”部分,您会看到“国家名称”将它拖到屏幕中间的大框中(“拖放到此处”)。向下浏览“Measures”部分,您会看到“GDPperCapGr%”。将它拖到“颜色”框中。在“维度”部分找到“日期”,并将其拖动到“过滤器”框中。选择“全部”表示年份。
现在,再次转到“日期”并将其拖动到“过滤器”上方的“页面”框中你会看到一个新的框出现在屏幕的最右边(我在下图中突出显示了它,被一个黑色的框包围着。)按下前进按钮,你会得到一个漂亮的人均 GDP 逐年增长的动画。在“标签”框中添加“国家名称”和“GDPperCapGr%”以添加标签。
现在你有一个简单的(虽然还不优雅)Tableau 动画来玩。
结论
熊猫融化是一个非常强大的数据转换工具。如果你要处理大量广泛的经济和金融数据,它会特别有用;并且需要一种对数据库更友好的长格式。
转换扭曲的数据
友好函数综述
注:以下代码用 Python 编写,摘自各种 Jupyter 笔记本。为了使文章更具可读性,行内注释被删除了。
扭曲的数据既麻烦又常见。通常需要转换倾斜的数据,并将其转换为 0 到 1 之间的值。
用于这种转换的标准函数包括归一化、Sigmoid、对数、立方根和双曲正切。这完全取决于一个人试图完成什么。
这里有一个我从 890 万行亚马逊图书评论数据集中生成的倾斜列的例子。df。Helpful _ Votes 给出每篇书评收到的有用投票(相对于无用投票)的总数。
df _ helper _ Votes 原始数据
**IN** df.Helpful_Votes.describe()**OUT** count 4.756338e+06
mean 5.625667e+00
std 2.663631e+01
min 0.000000e+00
25% 1.000000e+00
50% 2.000000e+00
75% 4.000000e+00
max 2.331100e+04
0, 1, 2, 4, 23311.那是相当大的一跳!
删除异常值是一个选项,但不是我想在这里使用的。我的最终目标是建立一个机器学习算法来预测给定的评论是否有帮助,因此拥有最有帮助投票的评论是必不可少的。
我将使用上面列出的函数来转换数据,并解释其优缺点。和大多数数据科学一样,没有正确的函数。这取决于数据和分析师的目标。
规范化将所有数据点转换为 0 到 1 之间的小数。如果最小值为 0,只需将每个点除以最大值。
如果最小值不为 0,则从每个点中减去最小值,然后除以最小值-最大值差。
以下函数包括这两种情况。
归一化功能
**IN**
def normalize(column):
upper = column.max()
lower = column.min()
y = (column - lower)/(upper-lower)
return yhelpful_normalized = normalize(df.Helpful_Votes)
helpful_normalized.describe()**OUT**
count 4.756338e+06
mean 2.413310e-04
std 1.142650e-03
min 0.000000e+00
25% 4.289820e-05
50% 8.579641e-05
75% 1.715928e-04
max 1.000000e+00
归一化后,数据还是和以前一样偏斜。如果目标只是简单地将数据转换成 0 到 1 之间的点,那么规范化是一条可行的途径。否则,规范化应该与其他函数结合使用。
接下来是 Sigmoid 函数。如果你以前没有见过乙状结肠,值得看一看。
这是一条非常平滑的曲线,保证了 0 到 1 的范围。我们来看看它在 df 上的表现如何。有帮助的 _ 投票。
Sigmoid 函数
**IN**
def sigmoid(x):
e = np.exp(1)
y = 1/(1+e**(-x))
return yhelpful_sigmoid = sigmoid(df.Helpful_Votes)
helpful_sigmoid.describe()**OUT**
count 4.756338e+06
mean 8.237590e-01
std 1.598215e-01
min 5.000000e-01
25% 7.310586e-01
50% 8.807971e-01
75% 9.820138e-01
max 1.000000e+00
明显的进步。新数据在预期的 0 和 1 之间,但最小值是 0.5。这在查看图表时是有意义的,因为在统计投票时没有负值。
另一个需要考虑的问题是价差。这里,第 75 百分位在第 100 百分位的 0.2 以内,与其他四分位相当。但是在原始数据中,第 75 个百分位数与第 100 个百分位数相差 20,000 多,与其他四分位数相差甚远。在这种情况下,数据被扭曲了。
sigmoid 函数可以调整以改善结果,但现在,让我们探索其他选项。
接下来,对数。减少数据失真的绝佳选择。在 Python 中使用 log 时,默认基数通常是 e 。
对数函数
**IN**
helpful_log = np.log(df.Helpful_Votes)
helpful_log.describe()**OUT**
RuntimeWarning: divide by zero encountered in log
哎呦!被零除!这是怎么发生的?也许一个视觉会澄清事情。
对数图
Af Adrian Neumann — Eget arbejde, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=1834287
啊,是的。日志的域严格大于 0。这是一条沿着 y 轴的垂直渐近线。当 x 接近 0 时,y 接近负无穷大。换句话说,0 被排除在域之外。
我的很多数据点都是 0,因为很多评论没有收到有用的投票。为了快速解决问题,我可以在每个数据点上加 1。因为 1 的对数是 0,所以这样做很好。此外,由于所有的点都增加 1,所以保持了相同的分布。
对数函数+ 1
**IN**
helpful_log = np.log(df.Helpful_Votes + 1)
helpful_log.describe()**OUT**
count 4.756338e+06
mean 1.230977e+00
std 9.189495e-01
min 0.000000e+00
25% 6.931472e-01
50% 1.098612e+00
75% 1.609438e+00
max 1.005672e+01
Name: Helpful_Votes, dtype: float64
非常好。新的范围是从 0 到 10,四分位数反映了原始数据。
是时候正常化了。
对数函数+ 1 标准化
**IN**
helpful_log_normalized = normalize(helpful_log)
helpful_log_normalized.describe()**OUT**
count 4.756338e+06
mean 1.224034e-01
std 9.137663e-02
min 0.000000e+00
25% 6.892376e-02
50% 1.092416e-01
75% 1.600360e-01
max 1.000000e+00
Name: Helpful_Votes, dtype: float64
这看起来很有道理。如果结果仍然有偏差,对数函数加归一化是转换有偏差数据的一种很好的方法。然而,这种情况有一个主要的缺点。
为什么首先要将数据转换为 0 到 1 之间的值?通常百分比和概率会起作用。就我而言,我希望中位数在 50%左右。这里归一化后,中位数在 0.1。
当数字太大时,可以尝试用分数指数作为变换的手段。考虑立方根。
立方根
**IN**
helpful_cube_root = df.Helpful_Votes**(1/3)
helpful_cube_root.describe()**OUT**
count 4.756338e+06
mean 1.321149e+00
std 8.024150e-01
min 0.000000e+00
25% 1.000000e+00
50% 1.259921e+00
75% 1.587401e+00
max 2.856628e+01
这与 log 非常相似,但是这里的范围更大,从 0 到 28。
立方根归一化
**IN**
helpful_cube_root_normalized = normalize(helpful_cube_root)
helpful_cube_root_normalized.describe()**OUT**
count 4.756338e+06
mean 4.624857e-02
std 2.808959e-02
min 0.000000e+00
25% 3.500631e-02
50% 4.410519e-02
75% 5.556906e-02
max 1.000000e+00
不出所料,新数据归一化后问题更多。现在中位数是 0.04,离 50%相差甚远。
我喜欢玩数字游戏,所以我尝试了一些超能力。有趣的结果来自 1/log_max。我定义 log_max 为最大值的对数。(23311 的对数是 10.06。)
对数最大根
**IN**
log_max = np.log(df.Helpful_Votes.max())
helpful_log_max_root = df.Helpful_Votes**(1/log_max)
helpful_log_max_root.describe()**OUT**
count 4.756338e+06
mean 9.824853e-01
std 3.712224e-01
min 0.000000e+00
25% 1.000000e+00
50% 1.071355e+00
75% 1.147801e+00
max 2.718282e+00
从 0 到 2.7 的范围非常吸引人。
对数最大根归一化
**IN**
helpful_log_max_root_normalized = normalize(helpful_log_max_root)
helpful_log_max_root_normalized.describe()**OUT**
count 4.756338e+06
mean 3.614362e-01
std 1.365651e-01
min 0.000000e+00
25% 3.678794e-01
50% 3.941294e-01
75% 4.222525e-01
max 1.000000e+00
这看起来不错,但是数据非常集中在 25–75%的范围内,这个范围可能会延伸得更远。因此,尽管整体传播更令人满意,但在这里还不够。
现在是我们最后一个标准函数,双曲正切函数。先来个图。
这看起来很像乙状结肠。一个主要的区别是范围。双曲正切的范围是从-1 到 1,而 sigmoid 的范围是从 0 到 1。
在我的资料里,从 df 开始。有帮助的 _ 投票都是非负的,我的输出会从 0 到 1。
双曲正切
**IN**
helpful_hyperbolic_tangent = np.tanh(df.Helpful_Votes)
helpful_hyperbolic_tangent.describe()**OUT**
count 4.756338e+06
mean 7.953343e-01
std 3.033794e-01
min 0.000000e+00
25% 7.615942e-01
50% 9.640276e-01
75% 9.993293e-01
max 1.000000e+00
没有必要标准化,但没有突出的问题。
双曲正切比 sigmoid 更扭曲数据。第 75 个和第 100 个百分位数之间有 0.001 的差异,比其他任何四分位数都要接近。在原始数据中,这一差异比其他四分位数之间的差异大 23,307,1000 倍。
差远了。
百分位数提供了另一种选择。每个数据点都可以根据其百分位数进行排序,pandas 提供了一个很好的内置方法。兰克,来处理这件事。
一般的想法是,每个点接收其百分位数的值。在我的例子中,因为有许多数据点的有用票数很低,所以有不同的方法来选择这些百分点。我喜欢“最小”方法,在这种方法中,所有的数据点都接受给予组中第一个成员的百分位数。默认方法是“平均”,其中具有相同值的所有数据点取该组的平均百分位数。
百分位线性化
**IN**
size = len(df.Helpful_Votes)-1
helpful_percentile_linearization = df.Helpful_Votes.rank(method=’min’).apply(lambda x: (x-1)/size)
helpful_percentile_linearization.describe()**OUT** count 4.756338e+06
mean 4.111921e-01
std 3.351097e-01
min 0.000000e+00
25% 1.133505e-01
50% 4.719447e-01
75% 7.059382e-01
max 1.000000e+00
很有趣。百分位数线性化基本上与排名系统相同。如果第一个数据点和第二个数据点之间的差异应该与作为一个单位部分的所有数据点相同,则可以采用百分点线性化。
不利的一面是,百分位数线性化消除了关键的偏斜迹象。这个数据看起来有点倾斜,因为有成千上万的 1 票和 2 票的评论,而不是因为有几个评论的投票数高得惊人。
因为我主要是在处理一个排名系统,所以我把百分位数线性化和我自己的分段线性化函数结合起来。原木也发挥了作用。
无论你的选择或风格如何,永远不要局限于标准选项。数学函数极其丰富,它们与数据科学的交集值得更多的认可和灵活性。
我很想听听人们用来转换扭曲数据的其他函数。我听说过 boxcox 函数,尽管我还没有详细研究过它。
更多关于 Wade 的亚马逊书评项目的详情可以在他的 Github 页面查看,helified _ Reviews。
通过一些想法将文本转化为句子嵌入
“man standing on mountain peak” by Sammie Vasquez on Unsplash
学习一个通用的分布式嵌入层是 NLP 问题中的一个重要步骤。从 Mikolov 等人(2013)开始,引入了许多监督学习和非监督学习方法来检索高质量的文本表示。
Kiros 等人在 2015 年引入了 skip-thinks,其目标是提供句子级向量。看完这篇文章,你会明白:
- 跳跃式设计
- 体系结构
- 履行
- 拿走
跳跃式设计
如果您不熟悉构建单词嵌入的跳格方法,您可以查看这个博客了解更多细节。
“women’s white tank top on top of the hill” by Cristina Gottardi on Unsplash
Skip-thoughts 将 skip-grams 模型从单词嵌入扩展到句子嵌入。跳跃思维不是通过周围的词来预测上下文,而是通过周围的句子来预测目标句子。典型的例子是用上一句和下一句来预测当前句。
Kiros et al. (2015)
从上面的例子中,
- 上一句:我回到了家。
- 我能看见台阶上的猫。
- 下一句:这很奇怪。
第二,单词嵌入提供了更好的单词表示,而不考虑句子中的顺序。递归神经网络(RNN)可以处理句子中的单词顺序,但 skip-thoughts 也会考虑这个问题。
作者证明了该模型能够捕获句子的语义和句法,从而可以将高质量的嵌入结果转移到下游问题。
体系结构
该模型遵循编码器-解码器框架架构来计算矢量。在神经网络层,它可以是 GRU(门控循环单元),LSTM(长短期记忆)或注意机制。
编码器 :输入的是每句话的词向量序列,传递给 RNN (GRU 或 LSTM)。经过训练的模型,将用于下游任务,如分类问题。
解码器 :解码器的架构与编码器类似,只是引入了一些矩阵。此外,有两个解码器而不是一个。第一个是为了消耗上一个句子而决定的,而第二个是为了消耗下一个句子。不同之处在于它们彼此之间不共享解码器权重(隐藏状态),但是它们共享词汇向量。解码器帮助训练编码器,之后就不再使用了。
“gray concrete post on seashore under gray sky” by Perminder Klair on Unsplash
其思想是使用预先训练的嵌入(例如 word2vec)作为输入(即 x 或特征)和输出(即 y 或标签)是嵌入层的另一个维度。以便它可以“预测”每个单词的嵌入,即使它从未在训练数据中出现过。
Kiros et al. (2015). Showing the nearest neighbors of words after vocabulary expansion. For example, “chorepgraph” is OOV and the the nearest neighbors of words are “choreography“, “choreographs”.
文中没有详细的解释,所以我进一步研究了源代码,以了解它是如何工作的。你也可以参考源代码 (train_regresso 函数)来浏览它。
根据 Kiros 等人的设计,有两种方法,即单跳和双跳。Uni-skip 指使用单向神经网络来构建句子嵌入,而 bi-skip 使用双向 RNN (LSTM 或 GRU)来构建句子嵌入。单跳(或双跳)的输出是句子的 2400 维(如果使用组合跳过方法,则是 4800 维)。我们可以通过给定下游任务(例如分类)输出来训练模型。
履行
最初的作者是 Kiros 等人,他们通过 Theano 实现了跳过思想。有 Pytorch,Tensorflow 和 Keras 版本可用。我将使用 Pytorch 版本来演示我们如何将数据转换成句子向量。对于其他人,您可以查看参考资料部分提到的 githubs。
给定预先训练好的模型、词汇文件和输入(句子),你将得到 2400 维向量的输出(对于 uni-skip)。
拿走
要访问所有代码,你可以访问我的 github repo。
- skip-thoughts 和 skip-gram 都是无监督学习。
- Skip-thoughts 的目标是学习一个句子级向量而不是单词向量。
- 由于它是固定的句子表示,如果你的“句子”很长,它将消耗大量的内存。它不应该用于段落或文档嵌入。
参考
- Ryan Kiros、Yukun Zhu、Ruslan Salakhutdinov、Richard S. Zemel、Antonio Torralba、Raquel Urtasun 和 Sanja Fidler。跳过思维向量
- skip-thinks the ano github
- Skip-thought py torch github
- Skip-Thoughts tensor flow github
- Skip-Thoughts Keras github
转变数据驱动的文化从顶层开始:如何让你的 CTO 接受数据驱动的战略
Teamwork makes the (Data) Dream work
在之前的一篇文章中,我讨论了为什么公司需要数据战略,而不仅仅是更多的数据人员,在这篇文章中,我想分解一下头号原因,为什么大多数想要成为数据驱动的公司都在为之奋斗,以及如何克服它。
正如我在之前的帖子中所描述的那样,“要么成为数据驱动,要么灭亡”,在开始实施您的战略之前,任何组织都需要经历四个步骤。即;
— 第一,让专人负责数据,
— 第二,将组织的关键抱负与数据价值链结合起来,第三,根据这些抱负制定战略,
— 第四,吸引实现战略所需的人才。
技术驱动还是数据驱动
每当我讨论为什么有人需要对公司的数据负责时,我经常会注意到,首席技术官或开发部门的负责人对为什么有必要这样做最为关键。他们批评的原因不是来自对数据的不信任,而是来自这样一种观念,即大多数首席技术官看不到成为数据驱动的投资回报,更不用说引入一个完全负责数据的新高管了。
大多数首席技术官将检查组织的短期和长期技术需求视为自己的责任,并利用资本进行旨在帮助组织实现其目标的投资,但直到现在,大多数公司尚未证明在分析、数据科学、大数据、机器学习和人工智能方面的资本投资,以说服大多数首席技术官做出这一决定。
因此,当讨论作为驱动因素的数据时,CTO 的第一反应通常是技术不应该由数据战略决定,而是开发解决方案所需的技术应该是其他人可以获得数据并将结果用于决策的基础。
举例来说,如果你正在建立一家科技公司,创始人处于发展的早期阶段,首席执行官将为客户的需求列出案例,他或她可能充当产品所有者(在没有 CPO 的情况下),并列出需要建立什么来解决客户的问题。然后由 CTO 决定并创建构建它所必需的基础设施。
大多数 CTO 会根据他们以前的经验来构建产品,使用他们最熟悉的堆栈,通常不会担心未来的需求。他们正在构建的最低可行产品需要解决最初的问题,随着公司的发展,首席技术官的工作将发生变化,寻找新的方法来扩展平台的基础设施和功能。
因此,当你引入首席数据官、数据主管或其他任何负责数据的人时,就会带来看待基础设施和已构建内容的不同方式,这导致大多数首席技术官的本能反应。
例如,一家正在开发应用程序的公司(想象下一个优步、 Tinder 或 WhatsApp )可以决定使用 Apache Tomcat 作为应用程序服务器,使用 JAVA 应用程序编写代码,使用 PostgreSQL 作为数据库,所有这些都在 Linux 服务器上运行。这听起来是一个很好的开始,但随着成功和增长的到来,引入数据驱动的工作方式和可扩展性,将需要对平台的核心进行重大改变,以允许真正实现数据驱动所需的分析和数据科学功能。
如何对付一个有抵抗力的 CTO?
就在不久前,CTO 的角色被引入。在 20 世纪 90 年代末和 21 世纪初,首席信息官(CIO)负责监管 IT,但随着信息技术复杂性的不断升级,许多公司将 CIO 的部分职责分配给了 CTO。
现在大多数新公司都是技术驱动的,所以首席信息官的角色已经完全被首席技术官取代了。在以信息技术为关键的大多数网络公司或其他技术导向型公司中,首席技术官负责确定如何利用技术来实施业务战略,但随后,首席技术官负责实际集成和运行技术,即“运营经理”的角色。
随着大数据、机器学习和人工智能为公司提供了真正实现数据驱动的机会,首席技术官需要知道,CDO 或数据主管的角色不是取代或威胁首席技术官,而是成为在技术堆栈中实施新的数据驱动技术的合作伙伴。
提供数据驱动型公司将新技术融入现有体系的例子 通过真正了解公司当前的基础设施、底层技术并研究哪些产品符合已构建的体系,CTO 数据主管可以将首席技术官转变为拥护者而不是反对者。通过展示核心基础架构如何保持不变,但数据是位于技术基础架构之上的层,CTO 可以看到,即使是非常小的投资也可以使技术变得更好。
从 MVP 开始,让结果自己说话 幸运的是,在过去二十年中,设备的处理能力显著增强,以至于数据分析师/数据科学家可以使用像 RStudio 或 Python 这样的应用来创建一个最小的可行产品。如果可以通过命令行访问数据库,有一些简单的方法可以将数据直接导入 RStudio 或 Python。使用不同的包,数据分析师可以创建仪表板,以显示分析如何为企业提供对存储在数据库中的数据的洞察。
数据科学家可以更进一步,展示如何清理、处理和组织(大)数据,从而产生新产品或服务或增强现有产品或服务。在本地展示这一点,可以为可以与现有技术集成的生产版本打开大门。
创建一个非技术性用例来阐述您的观点 随着业务从非数字化向数字化的转变,我们能够访问公司外部生成的数据。从营销、销售到人力资源,一切都产生数据,这些数据提供了改进和构建用例的机会,以展示数据驱动的潜力。
该网站采用了 Google Analytics ,使公司能够改善网站性能,增加销售线索或销售更多产品。通过 Mailchimp 进行的电子邮件营销,通过 HubSpot 进行的客户关系管理,或者通过 ADP 进行的人力资源管理,都提供了大量的数据,这些数据可用于提高转化率、交付周期或揭示对员工行为的洞察。通过使用非核心数据来改善业务,可以向董事会成员展示成为数据驱动型企业的好处,并为首席技术官的参与提供依据。
不要勉强
最终,这一切都归结于改变一个组织的文化,不是通过推动或自上而下的执行,而是通过建立一个案例,说明为什么数据应该得到高管的充分关注。就像二十年前,当公司开始雇佣首席技术官时,因为技术驱动的方法创造了世界上最大的一些公司。信息时代的最新阶段,让那些真正接受数据驱动的工作方式的公司,有能力使自己与众不同,抢占市场份额和利润,而那些不愿意适应的公司则被搁置一旁。
感谢阅读;),如果你喜欢它,请点击下面的掌声按钮,这对我意义重大,也有助于其他人了解这个故事。通过联系 Twitter 或 Linkedin 让我知道你的想法。
将 SQL 翻译成熊猫
Photo by Aaron Burden on Unsplash
两者都做相似或相同的事情,但方式不同
就像一个有 SQL 背景的人和一个经常使用 SQL 的人一样,熊猫的第一步对我来说有点困难。我总是从 SQL 的角度思考,然后想知道为什么 pandas 如此不直观。但是随着时间的推移,我习惯了一种语法,并发现了这两者之间的联系。所以我决定创建一个翻译成熊猫语言的基本 SQL 命令的备忘单。
挑选
最简单的 SQL 语句如下所示:
# Select everything from table1
SELECT *
FROM table1
在 2010 年,熊猫看起来会像:
df.head()
尽管在默认情况下,pandas 将只显示前 5 行,但是 SQL 中的内容相当于 LIMIT 5 或 TOP (5)(取决于 DBMS)。同样,只需在终端中输入df
,就会显示数据帧的第一行和最后 15 行。
为了选择 SQL 中的特定列,我们将编写下一个查询:
SELECT column1, column2
FROM table1
在熊猫身上会这样写:
df[['column1', 'column2']]
在哪里
通常,我们希望选择具有特定标准的数据,在 SQL 中,这将使用 WHERE 子句来完成:
SELECT column1, column2
FROM table1
WHERE column1 = 2
在熊猫中,相同的查询看起来略有不同:
df[['column1', 'column2']].loc[df['column1'] == 2]
WHERE 子句接受逻辑运算符——pandas 也是如此。所以这个 SQL 查询:
SELECT *
FROM table1
WHERE column1 > 1 AND column2 < 25
在熊猫中采用以下形式:
df.loc[(df['column1'] > 1) & (df['column2'] < 25)]
pandas 中的 or 运算符是“|”,而不是—“~”。注意括号——它是强制的。
df.loc[(df['column1'] > 1) | ~(df['column2'] < 25)]
SQL WHERE 子句还接受更复杂的比较,例如:LIKE、IN 和 BETWEEN 熊猫也有能力做到这一点——只是方式不同。让我们创建一个使用所有这些运算符的查询:
SELECT *
FROM table1
WHERE column1 BETWEEN 1 and 5 AND column2 IN (20,30,40,50) AND column3 LIKE '%arcelona%'
pandas 中的相同查询(都是一行):
df.loc[(df['colum1'].between(1,5)) & (df['column2'].isin([20,30,40,50])) & (df['column3'].str.contains('arcelona'))]
加入
在数据科学家的日常工作中,连接表是一种常见的做法,在 SQL 中,我们使用 4 种不同类型的连接来连接表:内连接、左连接、右连接和全连接。该查询如下所示:
SELECT t1.column1, t2.column1
FROM table1 t1
INNER JOIN table2 t2 ON t1.column_id = t2.column_id
对于所有的连接,语法都是相同的,所以我们只需将 INNER 更改为剩下的 3 种类型中的任意一种。在 pandas 中,这个操作最好分两步完成——首先执行 join,然后选择我们需要的数据(尽管它可以在一行中完成):
df_joined = df1.join(df2, on='column_id', how='inner')
df_joined.loc[['column1_df1', 'column1_df2']]
如果没有指定参数on
和how
,pandas 将使用索引作为键列来执行左连接。
分组依据
分组使我们能够获得关于数据的一些聚合信息:计数、总和、AVG、最小值、最大值等等:
SELECT column1, count(*)
FROM table1
GROUP BY column1
熊猫也有这种灵活性:
df.groupby('column1')['column1'].count()
我们必须在方括号中指定列名,以便在结果中只包含该列,否则我们将得到给定数据帧中每列的计数。
如果我们想要得到按列 1 分组的列 2 中所有值的总和(例如,每个商店的总销售额),并且只显示那些已经达到某个级别的值,比如说超过 1000 个单位,我们将在 SQL 中执行以下操作:
SELECT store, sum(sales)
FROM table1
GROUP BY store
HAVING sum(sales) > 1000
在 pandas 中,我们没有 HAVING 子句的特权,但我们仍然可以通过两个步骤做到这一点:首先对数据进行分组,然后进行过滤:
df_grouped = df.groupby('store')['sales'].sum()
df_grouped.loc[df_grouped > 1000]
以…排序
为了在 SQL 中对结果进行排序,我们使用 ORDER BY 子句,它总是最后一个从数据库中获取结果。为了选择表中的所有值并按列 1 降序排序,我们编写了下一个查询:
SELECT *
FROM table1
ORDER BY column1 DESC
在 pandas 中,同样的查询看起来像:
df.sort_values(by=['column1'], ascending=False)
这个对我来说是最直观最清晰的。虽然,当你练习更多的时候,所有这些语法差异不再困扰你。
我们可以用 SQL 和 pandas 编写更复杂的查询,但是这种基本的对齐对我帮助很大,我相信对其他 SQL server 也有帮助。Pandas 是一个非常强大的库,让你以一种非常有效的方式提取、转换、清理你的数据。更多信息可以在我的文章“在 Python 中提取和转换数据”和“在 Python 中清理和准备数据”中找到
感谢您的阅读,祝您有美好的一天!
原载于 2018 年 11 月 25 日sergilehkyi.com。
大数据和小数据的透明数据挖掘
我和塔妮娅(@塔妮娅 _ 托里诺)和弗兰克(@弗兰克帕斯夸莱)合编的书现在出了!长话短说,这里有一个总结。算法正在越来越多地影响我们的生活,然而它们背后的过程是隐藏的——它们通常像黑盒一样工作。这本书为更好的算法提供了设计原则。世界知名专家介绍了各种旨在提高透明度的解决方案,这些方案不仅是算法上的,也是监管上的。
前言(说来话长)
算法正越来越多地影响着我们的生活。他们通过推荐最小化风险的活动来促进健康习惯,通过从多个来源估计信用评分来促进金融交易,并通过描述购买模式来推荐购买什么。他们所做的一切不仅基于人们直接披露的数据,还基于从行为模式和社交网络中推断出来的数据。
算法影响着我们,然而它们背后的过程却是隐藏的。他们经常作为黑盒工作。由于缺乏透明度,不道德行为是可能的。由于有偏见的训练数据,算法可以只为人口的子集推荐最小化健康风险的活动。他们可能会基于与种族不完全相关的因素拒绝抵押贷款,从而延续种族歧视。他们可能通过向有支付能力的人提供更高的网上购物价格来促进不公平的价格歧视。在秘密和复杂性的笼罩下,算法决策很可能会延续偏见和成见。
这本书为更好的算法提供了设计原则。为了便于阅读,本书分为三个部分,分别针对不同背景的读者。为确保透明采矿,解决方案首先应增加透明度(第一部分),此外,它们不仅应是算法性的(第二部分),还应是监管性的(第三部分)。
首先从第一部分开始,算法越来越多地被用于对公共产品(如健康、安全、金融、就业)做出更好的决策,透明度和问责制等要求也是急需的。章节“数据的暴政?《数据驱动的社会公益决策的光明面和黑暗面》(pdf 预印本)、Lepri 等人( @brulepri 、@ dsango 、@ brulepri@ stja co@ nuriaoliver@ ManuLetouze*)*提出了一些关键观点在“后真相”政治时代——政治上使用“感觉真实”但没有事实依据的断言——新闻媒体也可能受益于透明度。如今,算法被用于制作、分发和过滤新闻文章。在“启用算法媒体的责任:作为建设性和批判性透镜的透明性一章中,Diakopoulos(@ ndiakopoulos)介绍了一个模型,该模型列举了可能被披露的关于这种算法的不同类型的信息。通过这样做,该模式实现了透明度和媒体问责制。更一般地说,为了支持整个网络的透明度,普林斯顿网络透明度和问责制项目(第"章普林斯顿网络透明度和问责制项目 ") ( pdf 预印本)持续监控了数千个网站,以揭示用户数据是如何被收集和使用的,潜在地减少了信息不对称(更多更新来自 @random_walker )。
更好算法的设计原则也是算法的本质,这就是为什么第二部分关注算法解决方案。达塔等人引入了一系列量化不同输入数据对输出的影响程度的方法(章节“通过量化输入影响实现算法透明”)。这些措施被称为定量输入影响(QII)措施,有助于确定各种算法中的歧视和偏见,包括黑箱算法(只需要完全控制输入和完全观察输出)。但并不是所有的算法都是黑盒。基于规则的分类器可以很容易地被人类理解,但是它们已经被证明不如最先进的算法准确。这也是因为无效的传统训练方法。为了部分解决这个问题,Malioutov 等人在章节用布尔压缩感知学习可解释分类规则中提出了训练基于布尔规则的分类器的新方法。这些方法不仅在理论上有充分的依据,而且在实践中也证明是准确的。尽管如此,深度神经网络所达到的精确度迄今为止还是无人能敌。大量的训练数据被输入到神经元的输入层,信息被处理到几个(中间)隐藏层,结果从输出层出来。为了揭示这些隐藏层,最近提出了神经网络内部功能的可视化方法。Seifert 等人提供了这些方法的综合概述,并且他们是在计算机视觉的背景下这样做的(第“章计算机视觉中深度神经网络的可视化:调查”)。
最后,第三部分详细介绍了与数据发布和处理相关的监管解决方案——在私有数据的基础上,创建模型,这些模型反过来又产生算法决策。这里有三个步骤。第一个问题涉及数据发布。当前的隐私法规(包括“最终用户许可协议”)没有为个人提供足够的保护。Hutton 和 Henderson (@ tnhh )介绍了获得持续和有意义的同意的新方法(章节“超越 EULA:改善数据挖掘的同意”)。第二步涉及数据模型。尽管从私人数据中生成,但算法生成的模型在严格的法律意义上并不是个人数据。为了将隐私保护扩展到这些新兴模型,Giovanni Comandè提出了一种新的监管方法(第"章)监管算法的监管?第一伦理——算法的法律原则、问题和机遇)。最后,第三步涉及算法决策。在章节“中,一个监督组织在确保算法问责中能扮演什么角色?",算法手表呈现(作者 @spielkamp )。这是一个监督和倡导倡议,分析算法决策对人类行为的影响,并使它们更加透明和可理解。
在我们的社会中,数据挖掘有着巨大的潜力,但需要更多的透明度和问责制。这本书只介绍了一些开始出现的令人鼓舞的倡议。
垃圾还是宝藏——如何判断分类算法是否有用
这是一系列文章中的第四篇,旨在使机器学习对那些没有受过技术培训的人来说更容易理解。以前的文章介绍了机器学习的概念,展示了学习的一般过程,并描述了常用的算法。你可以在这里开始系列。
在本系列的这一部分中,我们回顾了在评估分类算法的有效性和价值时的一些常见度量和注意事项。
首先,让我们假设已经在训练集上开发了一个算法,并且该算法具有良好的泛化能力。我们现在考虑如何在测试集上测量算法的性能。如果你没有理解我刚才说的话,你需要回到这一期。
混乱矩阵
让我们假设我们的算法是一个简单的离散分类器,如果实例被预测为感兴趣的类的一部分(肯定),则返回 p,否则返回 n(否定)。我们还假设,在测试集中的实际数据中,p '代表正实例,n '代表负实例。回想一下以前的一篇文章中关于真阳性(TP)、真阴性(TN)、假阳性(FP)和假阴性(FN)的定义:
TP = p 和 p ’
TN = n 和 n ’
FP = p 和 n ’
FN = n 和 p ’
在一个矩阵中显示其中每一个的总实例是有用的,该矩阵被称为混淆矩阵*(或误差矩阵或列联表),例如:*
从混淆矩阵中可以计算出许多有价值的度量,如下所示:
- 精度 = (TP + TN)/(P + N)。准确度是所有被正确预测的实例的比例。**
- 精度 = TP/P,精度是准确预测阳性的比例。**
- TP 速率或召回或灵敏度= TP/P’。TP 率是准确预测的阳性样本的比例。**
- FP 率= FP/N’。FP 率是被错误预测为阳性的阴性样本的比例。
- 特异性= TN/N’= 1-FP 率。特异性是正确预测的阴性样本的比例。**
根据具体情况,数据科学家对所有这些指标都感兴趣。然而,特别令人感兴趣的是 TP 率和 FP 率之间的权衡。对于一个有价值的算法,它需要正确地分类正例(好处),同时确保被错误地分类为正例(代价)的负例的数量保持在可接受的水平。
混淆矩阵示例
让我们回到我们最初的例子从分期付款 2 。让我们假设我们开发了一种算法,可以预测哪些工作申请是“高潜力”的。
该算法只返回“HP”或“Not HP”。我们通过 500 份以前的工作申请测试集运行我们的算法,并生成这个混淆矩阵:
因此,对于该算法,我们可以计算:
- 准确率= 80%。五分之四的测试集实例被正确预测。
- 精度= 50%。一半的正面预测是准确的。
- TP 率= 75%。四分之三的正面例子被正确预测。
- FP 率= 19%。大约五分之一的负面例子被错误地预测为正面。
- 特异性= 81%。大约五分之四的负面例子被正确预测。
虽然 75%的 TP 率本身可能被认为是非常好的,但它是以 19%的 FP 率为代价实现的。这个 FP 率可能高得不可接受。假设可以实现 TP 速率和 FP 速率的可接受平衡,这取决于人类决策者与数据科学家的合作。通常有必要将数量作为决策的一部分。如果公司收到 5000 份申请,这意味着几乎有 1000 份会被错误地归类为“高潜力”,公司可能没有能力处理这些。
ROC 图
考虑到 TP 速率和 FP 速率之间的折衷如此令人感兴趣,通过在二维图上绘制 TP 速率和 FP 速率来可视化和比较算法是很自然的。这样的图叫做 ROC 图。(接收机工作特性,这个术语源于第二次世界大战期间的工程和雷达发展)。
使用我们上面的“高潜力”示例,并假设数据科学家开发了其他四种具有不同 TP 和 FP 速率的算法,我们可以使用 ROC 图来比较这些算法,下面绘制的算法 A 与上一节中讨论的算法 A 相同。我们可以立即确定算法 C 是性能最好的算法。算法 E 是一个完全随机的算法,它选择相同比率的真阳性和假阳性。算法 B 比真阳性更能识别假阳性。
ROC 曲线
现在让我们假设我们的算法是一个概率分类器,并返回实例落入某一类的概率。在这种情况下,混淆矩阵只能基于“截止”概率来确定。
使用我们的示例,我们可以想象算法可能已经为测试集中的每个应用程序计算了一个概率,并且公司可能已经决定尝试将截止值 0.8 作为被视为“高潜力”的最小概率。
因此,这种概率分类器对于不同的截止点将具有不同的混淆矩阵,因此 TP 率和 FP 率将根据所应用的截止点而变化。
在这种情况下,画出算法的 ROC 曲线是有帮助的,也就是画出当使用不同的截断点时 TP 率和 FP 率如何相对于彼此变化。随着截止点的降低,TP 率保持不变或增加。
因此,FP 率也必须保持不变或增加。这种曲线被称为洛伦兹曲线。
下面给出了我们的概率“高潜力”算法的 ROC 曲线的一个例子,给出了我们前面的例子中用 x 标记的具体截止点。
ROC 曲线可以与体积因素结合使用,以确定概率分类器的最佳截止点。如果数量是一个问题,例如如果组织的资源是有限的,那么就需要尽量减少误报。否则,更高水平的假阳性可以被接受为高 TP 率的折衷。
什么是“好的”ROC 曲线?
想象一下,我们开发了一个完全随机的概率分类算法,在每个截止点,以相同的速度识别真阳性和假阳性。如果我们在 ROC 图上绘制这样一个分类器,它看起来就像一条连接点(0,0)和点(100,100)的对角线。这种算法对我们没有价值,因为我们还不如用盲目的运气来分类我们的数据集。
通常,如果我们正在测量一个已经在测试集上开发并具有良好泛化能力的算法,该算法将明显优于随机分类器,其 ROC 曲线将采取凸形式,如这里所示的两个算法 A 和 B。
很明显,ROC 图上的“黄金区域”是左上角,这里有高 TP 率和低 FP 率。因此,数据科学家喜欢看到 ROC 曲线的顶点尽可能深入 ROC 图的这个角落。
在这种情况下,数据科学家可能会根据 ROC 曲线的比较,认为算法 B 比算法 A“更好”。
曲线下面积
假设观察到“好的”ROC 曲线的顶点尽可能位于 ROC 图的左上方,ROC 曲线下方的面积可以作为算法强度的一般指标。曲线占据的面积越大,曲线占据 ROC 图左上方“黄金区域”的可能性就越大。
因此,曲线下的面积,或 AUC ,通常被用作概率分类器强度的一般指标。注意,随机分类器的 AUC 是 50%,因此理想情况下,一种有前途的算法将显示出显著高于此的 AUC,并且通常大于 80%。这是一个例子。
请注意,AUC 与基尼系数是线性等价的,基尼系数是衡量财富分配的一个常用宏观经济指标。具体来说,
基尼= 2 × AUC — 1 。
AUC 作为概率分类器强度的一般度量表现得非常好。但是,应该谨慎使用。完全有可能产生高 AUC 的算法在 ROC 图上感兴趣的特定点表现不佳。下面举例说明了具有相似 AUC 的两种算法,但是这些算法的性能根据 ROC 图上的兴趣点而有很大不同。
摘要
总结这一期的观察结果:
- 可以使用简单的混淆矩阵以及诸如准确度、TP 率、FP 率等度量来评估离散分类器。这些措施,结合对容量的考虑,可以帮助确定算法是否满足操作要求。
- 概率分类器可以使用 ROC 曲线绘制。曲线下面积(AUC)是算法预测效用的良好通用指标,AUC 大于 80%应为目标。然而,即使 AUC 很高,也有必要更深入地观察 ROC 图中感兴趣的特定点,并考虑体积因素,以确定是否存在符合操作要求的临界值。
下一次,为了结束这个系列,我将提供一个与机器学习相关的关键术语的词汇表‘备忘单’。找到它 这里 。
基于机器学习和遗传算法的行程时间优化
机器学习和优化有什么关系?—一方面,在模型训练期间,当我们试图最小化模型和数据点之间的错误成本时,数学优化被用于机器学习。另一方面,用机器学习解决优化问题会怎么样?
考虑一下:一个有 25 个包裹的 UPS 司机有 15 万亿条可能的路线可供选择。如果每个司机每天多开一英里,公司每年将损失 3000 万美元。
虽然 UPS 拥有他们卡车和路线的所有数据,但他们不可能在每个司机带着 25 个包裹的情况下运行 15 万亿次计算。然而,这个旅行推销员问题可以用一种叫做“遗传算法”的东西来解决这里的问题是,这种算法需要一些输入,比如每对位置之间的旅行时间,而 UPS 没有这些信息,因为地址的组合甚至超过万亿。但是如果我们使用机器学习的预测能力来增强遗传算法呢?
想法
简单来说,我们可以使用机器学习的力量来预测每两个位置之间的旅行时间,并使用遗传算法来为我们的送货卡车找到最佳的旅行路线。
我们遇到的第一个问题是,没有商业公司会与陌生人分享他们的数据。那么,在没有数据的情况下,我们如何进行这样一个项目——其目标是帮助像 UPS 这样的服务?我们可以使用哪些数据集来很好地代表我们的送货卡车?那么,出租车呢?—就像送货车一样,是机动车辆,运送的是……人。幸运的是,出租车数据集是公开的,因为它们是提供给市政府的。
下图说明了项目的设计:我们从出租车数据开始,使用这些数据来预测位置之间的行程时间,然后运行遗传算法来优化总行程时间。我们也可以倒着看图表:为了优化旅行时间,我们需要知道每对点从一个点到另一个点需要多长时间,为了获得这些信息,我们使用基于出租车数据的预测建模。
数据和特征工程
为了便于说明,让我们坚持使用这个 Kaggle 数据集,它是纽约市提供的完整出租车数据集的样本。Kaggle 上的数据集通常处理得很好,并不总是需要很多工作(如果您想练习数据清理,这是一个缺点),但查看数据以检查错误并考虑特征选择总是很重要的。
既然我们得到了每个位置的坐标,让我们计算每对点之间的曼哈顿距离,并计算经度和纬度的差异,以获得方向感(从东到西,从北到南)。我们可以稍微清理一下时间戳,保留最初的特性,这些特性乍一看可能对我们没有用。
当处理地理空间数据时,Tableau 是在 pandas 中映射数据点的一个非常有用的替代方法。在地图上快速初步检查显示,一些下车地点在加拿大,在太平洋,或在爱丽丝岛(自由女神像),在那里汽车根本不去。如果没有内置的面向地理的包,删除这些点是一项非常困难的任务,但我们也可以将它们留在数据中,因为一些机器学习模型可以很好地处理离群值。
In Tableau, we can quickly get a sense of our drop off locations and their density, as well as outliers.
作为奖励,Kaggle 方便地为提供了 2016 年纽约市天气的数据。这是我们在分析中可能要考虑的事情。但是,因为有许多相似的天气条件——部分多云或大部分多云——让我们把它们分成几个主要的天气条件,以便对这些特定的特征有一个较小的变化。我们可以在熊猫身上这样做:
sample_df["Conditions"] = sample_df["Conditions"].fillna('Unknown')
weather_dict = {'Overcast' : 0,
'Haze' : 0,
'Partly Cloudy' : 0,
'Mostly Cloudy' : 0,
'Scattered Clouds' : 0,
'Light Freezing Fog' : 0,
'Unknown' : 1,
'Clear' : 2,
'Heavy Rain' : 3,
'Rain' : 3,
'Light Freezing Rain' : 3,
'Light Rain' : 3,
'Heavy Snow' : 4,
'Light Snow' : 4,
'Snow' : 4}sample_df["Conditions"] = sample_df["Conditions"].apply(**lambda** x: weather_dict[x])
选择正确的模型
有了我们的数据和目标,简单的线性回归就不行了。我们不仅希望有一个低方差模型,我们还知道坐标虽然是数字,但对于给定的目标变量并不携带数值。此外,我们希望将路线的方向添加为正或负的数值,并尝试用天气数据集补充模型,这几乎是完全明确的。
在一个巨大的数据集中有一些随机的异常值,可能有一些无关的特征,以及一些可能的分类特征,我们需要一个基于树的模型。具体来说,提升树将在这个特定的数据集上表现得非常好,并且能够容易地捕捉非线性关系,适应复杂性,并处理分类特征。
除了标准的 XGBoost 模型,我们还可以尝试 LightGBM 模型,因为它速度更快,对分类特性的编码也更好。将这些特征编码为整数后,只需用分类变量指定列,模型就会相应地处理:
bst = lgb.train(params,
dtrain,
num_boost_round = nrounds,
valid_sets = [dtrain, dval],
valid_names = ['train', 'valid'],
categorical_feature = [20, 24]
)
这些模型很容易建立,但是很难微调和解释。Kaggle 方便地提供均方根对数误差(RMSLE)作为评估指标,因为它降低了误差幅度。使用 RMSLE,我们可以运行不同的树深度和学习率参数,并比较结果。让我们还创建一个验证“观察列表”集,以便在模型迭代时跟踪错误:
dtrain = xgb.DMatrix(X_train, np.log(y_train+1))
dval = xgb.DMatrix(X_val, np.log(y_val+1))
watchlist = [(dval, 'eval'), (dtrain, 'train')]gbm = xgb.train(params,
dtrain,
num_boost_round = nrounds,
evals = watchlist,
verbose_eval = **True**
)
遗传算法优化
现在,机器学习部分只是项目的第一步。一旦模型被训练和保存,我们就可以开始遗传算法。对于那些不知道的人来说,在遗传算法中,一个优化问题的候选解群体朝着更好的解进化,每个候选解都有一组可以变异和改变的属性。基本上,我们从问题的随机解决方案开始,并尝试基于一些适合度来“进化”解决方案。结果不能保证是可能的最佳解决方案,但应该足够接近。
假设我们在地图上有 11 个点。我们希望我们的送货卡车在同一天访问所有这些地点,我们想知道最佳路线。然而,我们不知道司机在每个点之间要花多长时间,因为我们没有所有地址组合的数据。
这就是机器学习部分的用武之地。通过我们的预测模型,我们可以找出卡车从一个地点到另一个地点需要多长时间,并且我们可以对每一对点进行预测。
当我们使用我们的模型作为遗传算法的一部分时,我们从每个点的随机访问顺序开始。然后,基于总旅行时间最短的适应度分数,该算法试图找到更好的访问顺序,从机器学习模型中获得预测。这个过程不断重复,直到我们找到一个接近理想的解决方案。
结果
在测试了这两个预测模型后,我惊讶地发现,没有天气数据的更基本的 XGBoost 比 LightGBM 表现略好,与 LightGBM 的 4.9 分钟相比,平均绝对误差为 4.8 分钟。
在选择 XGBoost 并保存模型后,我将其传递给我的遗传算法,以生成一个样本解决方案并进行演示。这是最终结果的可视化:我们从一个给定的位置开始,遗传算法和机器学习可以为我们的送货卡车规划出最佳路线。
请注意,在点 3–4–5–6 之间有一个小循环。如果你仔细看地图,你会看到建议的路线穿过高速公路,这是一个比住宅区更快更短的车程。此外,请注意,该演示并不是确切的路线规划,它只是建议访问顺序。
后续步骤
路线规划将是这个项目的下一个逻辑步骤。例如,可以整合 Google Maps API 并规划出每一对点之间的精确路径。此外,遗传算法假设一天中的静态时间。计算一天中的时间虽然重要,但要解决的问题要复杂得多,可能需要一种不同的方法来构建输入空间。
如果您有任何问题、想法或建议,请随时通过 LinkedIn 联系我。代码和项目描述可以在 GitHub 上找到。
感谢阅读!
趋势,季节性,移动平均,自回归模型:我的时间序列数据之旅
GIF from this website
最近我一直在处理时间序列数据。我想回顾什么是时间序列,并使我对时间序列数据的理解更加一致。
请注意,这篇文章是为了我未来的自己,也是为了让我对时间序列有更深入的了解。
定义
Image from this website
有多种不同的来源来定义术语“时间序列”,所以在这里我将尝试给出一个我自己容易理解的一般定义。
Image from this website
一个时间序列是一系列按照时间顺序索引的数据点。
如上所述,wiki 给出了非常直截了当的定义,即按时间顺序排列的任何数据。现在让我们看看来自 investopedia 的定义。
Image from this website
时间序列是按连续顺序排列的数字数据点序列。
如上所述,我们可以对时间序列数据有一个大概的了解。它可以是按顺序随时间记录的任何数据。一开始我们可以想到股票价格,但是视频、语言、歌曲和核磁共振扫描也可以想到时间序列数据。
时间序列数据的类型
Image from this website
上面是一个股票价格的示例图像,我们可以观察到,x 轴上是时间指数,y 轴上是不同市场的股票价格。
Image from this website
计算机视觉世界中时间序列数据的另一个很好的例子是视频(上面是 GIF),因为我们在一个时间序列中一帧一帧地捕捉。我们可以清楚地看到 fMRI 扫描可以被命名为时间序列数据。
时序目标
Image from this website
时间序列的一个明显的用例是预测股票价格。(如果这很容易,许多数据科学家将会很富有。)但我想添加一些不同的用例,我们甚至可以使用 GAN 来预测给定视频的下一帧,或 MRI 扫描。想象一下,如果你体内有癌症,GAN 接收你的 MRI 扫描的几个序列并生成 MRI 扫描。(那会很酷。).所以一般来说,我们希望预测时间序列的下一个值。
趋势/季节性/噪音
Image from this website
在我们继续之前,我们需要讨论一些重要的东西,大多数时间序列数据可以由三个部分来描述。那就是趋势、季节性和偏差。
趋势 →随时间变化且不重复的一般系统线性或(最常见的)非线性成分
季节性 →随时间变化且不重复的一般系统线性或(最常见的)非线性成分
噪声 →在数据内非趋势/季节性的非系统成分
右图 → Python 代码创建可视化
红线→1985 年以来的苹果股价
蓝线→ 苹果股价趋势
绿线→ 苹果股价残差(噪声)
橙线 →苹果股价季节性(年度)趋势
通过简单的代码和 statsmodel 库,我们可以很容易地看到每个组件是如何相互关联的。我们可以观察到每年都有季节性的上涨,苹果股票价格的总趋势也是上涨的。
预测/预报方法
左/右图像 →标准窗口平均值/指数移动平均值
当我们想要进行预测时,有许多不同的方法可以使用。我将提到我在研究中发现的方法。
标准/指数移动平均 →通过创建完整数据集不同子集的一系列平均值来分析数据点的计算
自动回归 →是一类随机过程的代表;因此,在自然、经济等中,它被用来描述某些时变过程
线性 / 多项式回归 → 回归分析其中自变量 x 与因变量 y 之间的关系被建模为一个 n 次 p 多项式(或 1 次线性)
ARMA→用两个多项式对(弱)平稳随机过程进行简洁描述的模型,一个用于自回归,另一个用于移动平均。
【ARIMA】→是一个自回归移动平均 (ARMA)模型的推广。这两个模型都符合时间序列数据,以便更好地理解数据或预测序列中的未来点(预测)
季节性 ARIMA →季节性 AR 和 MA 术语预测 xt 使用滞后时间为 S (季节性跨度)倍数的数据值和误差
ARIMAX →右手边有协变量的 ARIMA 模型
递归神经网络(LSTM) →一类人工神经网络其中节点之间的连接沿着一个序列形成一个有向图,在该图中允许它展示一个时间序列的动态时间行为。
********
如上所述,即使简单的自回归模型也能很好地拟合股票价格。请点击此处阅读 ARMA、ARIMA 和 ARIMAX 之间的区别。
交互代码
对于 Google Colab,你需要一个 Google 帐户来查看代码,而且你不能在 Google Colab 中运行只读脚本,所以在你的操场上复制一份。最后,我永远不会请求允许访问你在 Google Drive 上的文件,仅供参考。编码快乐!
要获取这篇文章使用的代码,请点击这里。
最后的话
我希望继续我的研究,对时间序列有更深入的了解。因为我认为这是每个行业都存在的问题。
如果发现任何错误,请发电子邮件到 jae.duk.seo@gmail.com 给我,如果你希望看到我所有写作的列表,请在这里查看我的网站。
同时,在我的 twitter 上关注我这里,访问我的网站,或者我的 Youtube 频道了解更多内容。我还实现了广残网,请点击这里查看博文 t。
参考
- 时间序列。(2018).En.wikipedia.org。检索于 2018 年 6 月 2 日,来自https://en.wikipedia.org/wiki/Time_series
- 工作人员,I. (2006 年)。时间序列。Investopedia。检索于 2018 年 6 月 2 日,来自https://www.investopedia.com/terms/t/timeseries.asp
- 如何识别时间序列数据中的模式:时间序列分析?(2018).Statsoft.com。检索于 2018 年 6 月 2 日,来自http://www.statsoft.com/Textbook/Time-Series-Analysis
- stats models . TSA . seasonal . seasonal _ decompose-stats models 0 . 9 . 0 文档。(2018).Statsmodels.org。检索于 2018 年 6 月 2 日,来自http://www . stats models . org/dev/generated/stats models . TSA . seasonal . seasonal _ decompose . html
- stats models:Python 中的统计数据— statsmodels 0.9.0 文档。(2018).Statsmodels.org。检索于 2018 年 6 月 2 日,来自https://www.statsmodels.org/stable/index.html
- b . desh pande(2018)。时间序列预测:理解趋势和季节性。Simafore.com。检索于 2018 年 6 月 2 日,来自http://www . simafore . com/blog/bid/205420/Time-series-forecasting-understanding-trend-and-seasonity
- 移动平均线。(2018).En.wikipedia.org。检索于 2018 年 6 月 2 日,来自https://en.wikipedia.org/wiki/Moving_average
- 线性回归。(2018).En.wikipedia.org。检索于 2018 年 6 月 2 日,来自https://en.wikipedia.org/wiki/Linear_regression
- 多项式回归。(2018).En.wikipedia.org。检索于 2018 年 6 月 2 日,来自https://en.wikipedia.org/wiki/Polynomial_regression
- 自回归-移动平均模型。(2018).En.wikipedia.org。检索于 2018 年 6 月 2 日,来自https://en . Wikipedia . org/wiki/auto regressive % E2 % 80% 93 moving-average _ model
- 递归神经网络。(2018).En.wikipedia.org。检索于 2018 年 6 月 2 日,来自 https://en.wikipedia.org/wiki/Recurrent_neural_network
- 自回归模型。(2018).En.wikipedia.org。检索于 2018 年 6 月 2 日,来自https://en.wikipedia.org/wiki/Autoregressive_model
- ARIMAX 模型的混乱。(2010).Robjhyndman.com。检索于 2018 年 6 月 2 日,来自https://robjhyndman.com/hyndsight/arimax/
- 4.1 季节性 ARIMA 车型| STAT 510。(2018).Newonlinecourses.science.psu.edu。检索于 2018 年 6 月 2 日,来自https://newonlinecourses.science.psu.edu/stat510/node/67/
- statsmodels.tsa.ar_model。ar . predict-stats models 0 . 9 . 0 文档。(2018).Statsmodels.org。检索于 2018 年 6 月 2 日,来自http://www . stats models . org/dev/generated/stats models . TSA . ar _ model。ar . predict . html # stats models . TSA . ar _ model。AR.predict
- Python,A. (2018)。Python 中使用 statsmodels 的自回归模型。堆栈溢出。检索于 2018 年 6 月 2 日,来自https://stack overflow . com/questions/28094538/auto regressive-model-using-stats models-in-python
- Anon,(2018)。[在线]见:https://www . research gate . net/figure/Raman-spectra-of-the-the-MCC-101-raw-material-with-123-water-content-top-and-of-the-the-MCC _ fig 11 _ 8508180【2018 年 6 月 2 日获取】。