利用高斯混合变分自动编码器抵抗对抗性攻击
深度神经网络太神奇了!他们能够通过查看 100 多万张图像来学习将图像分为不同的类别,在众多语言对之间进行翻译,将我们的语音转换为文本,制作艺术品(甚至可以在拍卖会上出售!),并擅长大量其他令人兴奋和有用的应用程序。人们很容易被深度学习的成功故事所陶醉,但它们不会犯错吗?
事实证明,他们实际上是极易被愚弄的!😦
针对深度神经网络的对抗性攻击的研究越来越多。已经提出了许多防御方法来保护模型免受这种攻击。不幸的是,几乎所有的方法都被证明是无效的。该领域的发展速度显而易见,因为在 ICLR 2018 年成果宣布后的几周内,一篇研究论文发表了,显示作者如何能够绕过被接受论文中提出的 8 种防御技术中的 7 种。2018 年 CVPR 奥运会上接受的关于防御对抗性攻击的论文遭遇了类似的命运!
We are all too familiar with this cute *gibbon…*errrr panda by now! Image courtesy: http://www.cleverhans.io/assets/adversarial-example.png
一项平行的研究表明,深度神经网络也可以很容易地被*【愚弄】样本欺骗,这些样本是分布外的样本,与模型训练的任何类别都不相似。事实上,已经表明,简单地提供随机高斯噪声作为输入足以欺骗深度网络以高置信度预测其中一个类作为输出。正如“GAN 之父”伊恩·古德菲勒所说,“深度神经网络几乎在任何地方都是错误的!”*
Each of these images are classified into the class mentioned with >99% confidence! Image courtesy: http://www.evolvingai.org/fooling
虽然这在一开始看起来非常令人惊讶,但让我们仔细检查一下。首先,我们来看看糊弄的样本。
基于深度神经网络的图像分类器的任务是学习将每个输入分类到 K 允许类的1 中。然而,有一个问题。当我们提供一个不属于任何允许的类的输入图像时,模型应该做什么?在典型的机器学习设置中,潜在的假设是,训练和测试样本是从原始数据分布 P(x,y) 中抽取的。然而,这个假设在当前场景中被打破。
理想情况下,我们希望网络预测类的均匀分布(当输出层是 softmax 层时),以及每个类的接近 0 的概率得分(当输出层由 sigmoid 激活组成时)。然而,我们需要在这里停下来,问问我们自己——考虑到我的培训目标,我应该期望网络以这种方式运行吗?
在训练阶段,模型应该优化的唯一目标是由训练样本的预测误差确定的经验风险函数,这意味着目标函数中没有迫使网络学习非分布样本的期望行为的项。因此,毫不奇怪,在模型的输入空间中很容易找到导致对某些类别标签的高置信度预测的样本,尽管事实上它们实际上不属于任何类别——我们根本没有为这样的任务训练模型!解决问题的办法似乎是引入一个**【拒绝类】**的概念。
接下来,我们将通过几个图像来分析愚弄样本和敌对样本同时存在的原因。
Let’s consider the simplistic scenario of an image in a 2-D space. If we randomly perturb the image in some direction, the classifier usually does a good job of handling the noise.
However, adversarial attacks find certain specific directions in the input space, such that the classifier is fooled into predicting an incorrect class label after perturbing the input in that direction.
Similarly, fooling images can be found much more easily, such that they do not belong to any of the classes, but lead to high confidence predictions when provided as inputs to the classifier.
If we try to analyze the reason for existence of such fooling samples more closely, it becomes clear that any input which does not lie in the region of the input space representing any of the classes, but lies sufficiently far away from the decision boundaries of the classifier, will lead to high confidence predictions corresponding to one of the classes. Further, if we look closely at the adversarial image depicted in the above figure, it becomes clear that unless the training data provides a very good representation of the true boundary of a given class, it might be possible to find certain adversarial directions for perturbing an input image. A 2-D depiction is provided here just for an idea - imagine how the possibility of finding such directions will increase as the input dimensionality increases! Now think of the input dimensionality in the case of image classifiers - it is probably not so surprising that adversarial samples exist!
如果我们可以为输入空间中的每个类设置某种信封,那么我们可以将属于该信封的每个输入分类为属于该类,并拒绝不属于任何信封的每个输入,这不是很好吗?我们可以使用任何所需形状的信封,或者如果需要的话,对每一类输入使用多个信封。但问题是,我们如何得到这样的信封?事实证明,这是一个在原始输入空间中很难解决的问题。
如果我们从概率论的角度来看,这个问题归结为给定训练数据的密度估计。如果我们知道 P(x) ,我们可以简单地拒绝任何输入样本 x ,对于这些样本 P(x) 可以忽略不计。但是,高维密度估计面临维数灾难!
在我们的建议中,我们使用变分自动编码器(VAE)来实现上述目标-同时降低维度并在较低的维度中执行密度估计。我们使用高斯混合分布作为潜在变量先验,混合分量的数量等于数据集中的类的数量。所提出的框架还允许我们在半监督场景中训练模型。请参考我们的论文了解如何修改 ELBO 以说明分类标签,从而获得用于训练模型的目标函数。
Training phase of our model is represented in this figure. f and g represent the encoder and decoder networks respectively, and they output the means of the two distributions Q(z|x) and P(x|z). ϵ represents the noise added corresponding to the reparameterization trick used for training VAEs.
一旦模型被训练,我们使用模型的潜在(编码器阈值)和输出(解码器阈值)空间中的阈值来拒绝输入样本。基于训练数据和训练模型来计算阈值,其中编码器阈值对应于不可忽略的 P(z) ,解码器阈值对应于不可忽略的 P(x|z) (在某些假设下)。这些阈值对应于我们之前讨论的使用信封的想法。这两个阈值的组合确保任何被分类的输入 x 在训练数据分布下具有不可忽略的概率 P(x) 。
Testing phase of the model is represented in this figure. The input image is passed through the encoder, and if the latent encoding lies within the encoder threshold from the mean of the predicted class, then the encoding is passed through the decoder network. If the reconstruction error is also within the the decoder threshold of the predicted class, then the predicted label is accepted. If any of the thresholds is not satisfied, then the input is rejected. It is important to note here that each of the circles in the latent space in the figure represent the Gaussian mixture component for the corresponding class.
由于我们已经在模型管道中引入了拒绝机制,现在让我们来看看使用和不使用阈值的模型的性能。鉴于现在这是一个选择性分类模型,我们必须确保引入拒绝机制后,测试数据的精度以及召回率都很高。
It is noteworthy here that although there is a certain drop in accuracy after thresholding, the error percentages go down in each of the cases. For example, for MNIST data, the error percentage goes down from 0.33% to 0.22%, while 1.81% samples now move into the reject class.
现在,让我们看看一些被我们的模型错误分类的样本。
The first label indicates the true label from the test dataset, and the second label indicates our model’s prediction. In most of the cases, it is clear that the labels predicted cannot be claimed to be “wrong”, since it is not clear even to a human which of the two labels should be “correct”.
接下来,我们将深入我们的模型,探索有助于拒绝敌对和愚弄输入的关键特征,而不是对它们进行错误分类。首先需要注意的是,该模型的编码器部分非常类似于通常的基于 CNN 的分类器。因此,我们可以使用现有的敌对/愚弄攻击来欺骗编码器,类似于对 CNN 的攻击。然而,解码器网络是模型鲁棒性的主要来源。重要的是要注意,解码器的输入维数明显小于编码器的输入维数(例如,对于 MNIST 数据,10 比 28×28 = 784)。此外,因为我们在潜在空间中执行阈值处理,所以我们只允许解码器接受来自该空间非常有限的部分的输入。在训练时,解码器输入空间的这个区域被密集采样,即,给定来自这个区域的输入,可以期望解码器仅生成有效的输出图像。这是我们的模型的对抗性鲁棒性的据点。
给定训练数据中的类在视觉上是不同的,在给定来自我们的模型的潜在空间中的两个不同高斯混合分量的两个输入的情况下,可以期望解码器生成具有高欧几里德距离的图像。只要该距离大于相应类别的解码器阈值,解码器将总是能够检测到对模型的对抗性攻击。
This figure represents the evolution of the latent space structure for the model for a single class. Existence of “holes” in the input space of the decoder is highly improbable, given the training objective. Image courtesy: https://arxiv.org/pdf/1711.01558.pdf
现在,让我们来看看如何通过阈值处理来抵御敌对样本。
Suppose the input image (from class 1) has been adversarially perturbed to fool the encoder into believing that it belongs to class 0. This implies that the latent encoding of the input image must lie within the cluster for 0’s. Although it is easy for an adversary to achieve this objective, the decoder is where it becomes tricky. Once the latent encoding is passed through the decoder network, the output image now resembles a 0, and thus, the reconstruction error is invariably high. This results in rejection of the input image!
接下来,我们提供在编码器网络上运行 FGSM 攻击的结果。随着我们增加噪声幅度,模型的精度持续下降,但是在整个ϵ值范围内(对于监督模型),误差百分比保持在 4%以下。如所期望的,随着ϵ的增加,拒绝百分比从 0%上升到 100%,而不是敌对输入被错误分类。对于半监督的情况也观察到类似的趋势,但是,如预期的,模型性能不如监督情况下的好。
Results corresponding to the FGSM attack with varying ϵ on the encoder of the model trained on MNIST dataset.
我们还使用 Cleverhans 库尝试了许多其他强攻击,如 PGD、BIM、MIM 等。使用默认参数,但是在每种情况下,所有生成的对立样本都被拒绝。由于这些攻击缺乏解码器网络的知识,我们接下来将注意力转移到完全白盒攻击,其中敌对目标是利用两个阈值的知识专门设计的。我们还设计了类似的白盒愚弄目标,并在随机选择的测试数据集子集上运行这些攻击(对抗性攻击),或在多个开始随机图像上运行这些攻击(愚弄攻击)。然而,在每种情况下,优化过程收敛的图像被我们的模型基于两个阈值成功地拒绝。有关这些敌对目标的详细信息,请参考我们的文件。
White-box adversarial attack objective
White-box fooling attack objective
最后,为了解决敌对样本进入拒绝类而不是被正确分类的问题,我们引入了仅基于解码器网络的重新分类方案。该方法背后的基本思想是找到最大化 P(x|z) 的 z ,即,我们对解码器网络的输入执行梯度下降,以最小化给定对抗图像的重建误差。然后,我们选择与最优 z 所在的集群相对应的标签。如果这个 z 超出相应类别均值的编码器阈值,我们再次将输入作为非分布样本拒绝。按照这种重新分类方案,我们在通过对具有变化ϵ.的编码器进行 FGSM 攻击而生成的敌对图像上获得了以下结果
这些结果意味着重新分类方案能够以非常高的准确度成功地将检测到的对抗性输入分类到正确的类别中。即使对于 0.3 的最高ϵ,解码器网络也能够正确地对 87%的样本进行分类,而所有这些样本先前都被拒绝。
有趣的是,在拒绝的测试数据样本上遵循相同的重新分类方案,我们也获得了先前报告的准确度值的改进。例如,对于 MNIST 数据集,精度值从 97.97%上升到 99.07%,因为 181 个被拒绝的样本中的 110 个被重新分类方案正确分类。因此,该方法进一步提高了测试数据集的召回率。然而,重要的是要注意,由于重分类方案涉及优化步骤,因此直接在所有输入样本上使用它是不实际的。因此,我们建议在通常情况下使用编码器网络进行分类,并且只对被拒绝的输入样本使用重新分类方案。
有趣的是,我们最近看到了一篇关于非常相似的想法的论文,该论文使用了 Geoffrey Hinton 教授团队的胶囊网络以及检测敌对样本,可以在这里找到。在贝斯吉实验室的这个链接上也可以找到另一个类似的工作。
再一次,这篇文章对应的论文可以在下面的链接找到。这项工作是由 MPI-IS 和 IBM Research AI 合作完成的。该论文已被第 33 届 AAAI 人工智能会议(2019 年,AAAI)接受发表。请在下面留下任何问题/建议/反馈,我们将很高兴与您联系!感谢您的时间和兴趣!
回应格式和登月
1969 年 7 月,阿波罗 11 号航天飞机发射并让人类登陆月球。五十年后,一些人认为登月并没有真正发生。
这篇文章着眼于两个最近的调查估计,认为登月是伪造的,以及这两个调查之间的差异。
真的还是假的?
回到 2019 年 2 月,YouGov 在互联网小组中询问了 2039 名英国成年人,为其与雅虎的播客:
如果有的话,你认为下面的陈述是对还是错?
登月上演了
人们可以从绝对正确到绝对错误或者他们不知道来回答。调查估计,16%的人认为登月可能(12%)或绝对是真的(4%)是有预谋的。
几周前,数字分析机构 Politics——它不是英国民意调查委员会的成员——就几起阴谋询问了 1000 名英国成年人。受访者可以勾选他们认为正确的所有选项。
以前,数字处理器政治混合使用互联网小组和互联网“河流采样”。河流采样包括通过在选定网站上的促销广告邀请人们回答问题。
在调查中,只有 5%的人选择了“1969 年至 1972 年的登月是伪造的,人类没有真正到过月球”。
It has been fifty years since the first Moon landings. (Photo: ABC News Australia)
那么,到底是 5%还是 16%?
差异
在措辞上有一些不同,比较了’伪造’和’上演’,并指明了多次登月的时间。
然而,关键的区别在于响应格式。
在 YouGov 的调查中,人们必须为每个陈述选择一个选项:绝对正确、可能正确、可能错误、绝对错误或不知道。这被称为强制选择格式。
正如文章所暗示的,数字分析政治调查是全选的形式。如果你在网上做过调查,你可能认识这种格式。人们被问到一个问题,可能会从列表中勾选多个选项。
Pew Research Center did a randomised experiment comparing the two.
每种格式都有优点和缺点。
选择所有适用问题很简洁,通常只占一个屏幕。强制选择问题占用更多的空间,需要回答者付出更大的努力来滚动或点击每个问题。
然而,全选问题要求回答的人同时考虑所有选项。强迫选择的形式鼓励对每个选项进行更多的思考。
这两种形式都存在问题:默认偏见可能意味着一些人由于受暗示或只是为了通过调查而点击“真”(或“同意”或“是”)选项。在全选问题中,回答满足调查需求意味着人们可能只选择一些适用的。
皮尤研究中心进行了一项随机试验,关于负面事件(比如你的身份被盗)的个人经历的问题以两种形式分配。
在所有的问题中,强迫选择的方式比全选的方式产生了更高的估计值,这是一致的。在六个选项中,差异从 2 分(被要求行贿)到 16 分(被多收)不等。两种格式的顺序几乎相同。
哪个更好?
虽然全选格式比强制选择格式产生的估计值低,但哪种格式更准确?Callegaro、Murakami、Tepman 和 Henderson 在 2014 年进行的一项荟萃分析发现,很少有研究涉及这一关键问题,而且没有定论。
响应格式的变化会产生不同的估计值。需要进一步的调查研究来了解哪种格式更可靠。
数据科学的隐患
Lise Getoor 在 IEEE 大数据大会上的主题演讲笔记
数据科学,机器学习,人工智能。这些都是我们社会出现的流行语。我们越来越依赖这些技术,但这种依赖也引发了我们完全信任这些技术的正当性问题。众所周知,机器学习和深度学习是一个黑箱——我们将数据输入模型,并得出一些我们认为理所当然的结果,而没有真正质疑这些结果是如何获得的,以及这个过程是否合理。这个问题构成了 Lise Getoor 教授在 2019 年 12 月 10 日在洛杉矶举行的 2019 年 IEEE 大数据大会上发表主题演讲的背景,我现在将概述她所做的启发性演讲。
Image by manfredsteger from Pixabay
背景
数据科学越来越多地成为人们关注的焦点,在全世界范围内受到越来越多的关注。但每当我们在新闻中看到数据科学,它大多是为了一些不好的东西。例如,我们许多人都熟悉剑桥分析公司的丑闻,该公司在未经同意的情况下收集了数百万人的脸书个人资料,并将其用于政治广告目的。另一个例子是科学家如何宣称已经创造了一个能够根据面部图像推断犯罪行为的模型。
在主题演讲中,Getoor 教授主要关注机器学习中的负责任的数据科学,我现在将概述一下。
机器学习——简介
机器学习经历了几次革命,过去一个世纪出现了几个主题,从概念学习、统计学习、基于优化的学习到深度学习。
Image taken from IEEE Big Data 2019 Keynote. Reposted with permission
概念学习围绕着机器如何学习逻辑上一致的假设,能够正确地标注正负样本。在 20 世纪 80 年代,机器学习转向统计学习,特别是概率方法,重点是学习最大化概率和数据可能性的假设。接下来,机器学习转向基于优化的,例如,支持向量机(SVM),其中假设最小化一些损失函数。现在我们处于深度学习的神经启发学习时代,它将假设表示为神经网络。
培训和测试
本质上,机器学习中训练的目标是最小化目标标签和预测标签之间的损失。这在数学上表述如下:
Image taken from IEEE Big Data 2019 Keynote. Reposted with permission
在测试阶段,对学习的模型进行测试,以确定它能够多好地预测预测的标签。然后,通过目标标签和预测标签之间的损失之和来计算误差,数学公式如下:
Image taken from IEEE Big Data 2019 Keynote. Reposted with permission
这看起来相当简单——训练一个模型来减少损失,你就可以通过计算误差来客观地量化它的性能。
那么可能会出什么问题呢?事实证明很多人。
可能出错的事情
总之,Getoor 教授涵盖了 7 个可能出错的问题:问题的形式化,处理高维数据,测量误差,深度学习中的可解释性,因果建模,偏见和数据尊严。这些是问题所在:
问题# 1——形式化
似乎提出训练目标很容易,但事实上,每次我们训练一个模型时,我们都在对数据、标签和损失函数做出一些参考框架承诺。
首先,原始数据到特征向量的转换需要我们做出一个参考框架的承诺,因为原始数据总是包含更多的社会和历史背景,而这些背景是特征向量所不能表示的。这意味着每当我们转换原始数据时,我们将会错过人类数据中的许多重要信息。
其次,标签的选择也有问题,因为谁来定义标签?标签只能代表真实数据,而不能真正替代真实数据。
最后,损失函数的选择也很重要,因为不同的损失函数对误差的惩罚是不同的,影响模型性能的因素之间的权衡常常被过分简化并强制拟合到这些损失函数中,而这些损失函数可能并不真正代表任务要求。
因此,需要一些标准来评估所选择的参照系是否合适,标准被称为“结构合理性”,即在输入特征和输出标签之间应该有合理的科学联系。如果不是,无论你的分类器表现得多好,你都应该拒绝这个假设。例如,基于面部图像的犯罪推断无法通过这一测试,因为面部图像(输入特征)和分类(输出标签)之间所谓的“科学联系”根本不科学。相反,它是基于选择图像的方法。实验者可能会手动选择非犯罪图像来传达积极的印象。相比之下,犯罪图像可能既不是由所描绘的个人选择的,也不是为了塑造一个人的正面形象。因此,该模型本质上是一个“微笑探测器”,而据称被发现的联系实际上并不是一个“看似合理的科学联系”。
问题#2 —高维数据
机器学习的下一个问题是对数据的巨大依赖,无论是训练还是测试。这个问题出现在高维数据中,因为过度拟合的危险要高得多。随之而来的还有无数的问题:
- 维数灾难意味着我们的直觉在高维空间中会失效,因此尽管我们在处理低维数据时仍然可以依靠直觉,但我们不能对高维数据做同样的事情。
- 仅仅由于数据的巨大维度,找到具有预测性但实际上没有相关性的特征的随机子集的可能性很高。
- 概化所需的样本量随维度成比例增长,因此高维数据所需的样本量呈指数增长。
一个例子是 NSA 如何尝试使用机器学习来预测恐怖分子的手机使用情况。这很成问题,因为他们对每个手机用户使用了 80 个变量,而已知的恐怖分子只有 7 个。当他们试图在野外测试该模型时,最终确定一名报道基地组织的半岛电视台记者是潜在的恐怖分子!这显示了高维数据如何使我们更容易出错,因为对样本大小的要求更高。
问题#3 —测量误差
下一个出现的问题是度量模型性能的问题。研究人员总是宣称他们新的最先进的模型已经达到 XX 精度或 F1,等等。然而,这种说法总是带有许多不言而喻的条件,即数据集具有定义明确的总体,训练和测试数据都是总体的代表性样本。然而,这在实践中几乎从未成立。下图很好地说明了这个问题:
Image taken from IEEE Big Data 2019 Keynote. Reposted with permission
上面用绿色表示的学习模型最初可能看起来符合真实模型。然而,在进一步的测试中,很明显,学习的模型实际上并不代表真实的模型。
问题#4 —深度学习中的可解释性
在过去的几年里,深度学习中的可解释性受到了越来越多的关注。这一点很重要,因为尽管深度学习模型可能会取得出色的结果,但我们无法确定这些结果是因为模型真的学习了重要的特征,还是因为模型实际上学习了错误的特征,而只是碰巧同一类别的图像的特征保持不变。当错误的特性被改变而重要的特性保持不变时,麻烦就来了。如果模型学习了错误的特征,那么它可能做出错误的预测。
一个例子是里贝罗等人在 2016 年发表的题为“我为什么要相信你”的论文“解释任何分类器的预测”。他们训练了一个模型来对哈士奇和狼进行分类,但结果是对图片背景中的雪和草进行分类。原来,图像中的雪被用来将图像分类为‘狼’,而图像中的草被用来将图像分类为‘哈士奇’。结果,当一只哈士奇以雪为背景拍照时,它被错误地归类为狼。
Image taken from Ribeiro, M. T., Singh, S., & Guestrin, C. (2016, August). " Why should i trust you?" Explaining the predictions of any classifier. In Proceedings of the 22nd ACM SIGKDD international conference on knowledge discovery and data mining (pp. 1135-1144).
问题# 5——因果建模:相关性与因果性
相关性与因果性的问题是另一个经常讨论的话题,尤其是在统计学中。这个想法是,相关性有助于预测;如果 X 和 Y 是正相关的,那么如果我们观察到一个高的 X,那么我们会期望看到高的 Y。如果 X 和 Y 有因果关系,那么如果我们在保持其他一切不变的情况下操纵 X 的值,那么 Y 的值肯定会改变。将相关性混淆为因果关系的问题在于混杂因素,其中相关性通常是由于一个或多个混杂的潜在变量,这些变量是 X 和 y 的隐藏原因。
例如,看起来好像冰淇淋销量的增加会导致鲨鱼袭击数量的增加。对于外行人来说,销售的增长似乎导致了攻击的增长。然而,实际上有一个混淆因素——天气。这可能是因为炎热的天气导致了冰淇淋销量的上升以及鲨鱼袭击事件的增加(因为天气好,更多的人去了海滩),冰淇淋销量和鲨鱼袭击事件的增加之间只有相关性而没有因果关系。
问题 6——偏见和公平
机器学习中的偏差可以分为三类——数据偏差、自动化偏差和算法歧视。
首先,数据偏差是指数据集的选择。数据集的内容受到许多因素的影响,包括选择偏差、机构偏差和社会偏差。俗话说,垃圾进,垃圾出。如果系统的输入有偏差,那么输出也会有偏差。例如,亚马逊因开发人工智能工具雇佣歧视女性的人而受到抨击。原因很简单——训练集主要包含男性简历,因此模型开始了解到,仅仅根据男性简历的数量,男性会比女性更好。
其次,自动化偏见是指我们人类对自动化决策系统的建议的偏好,并且经常忽略矛盾的信息。我们倾向于相信自动化系统所做的决策,仅仅因为它们是自动化的,而没有额外考虑这些决策的有效性和合理性。当决策者开始将决策责任交给算法时,危险就来了。依靠算法来做出艰难的决定尤其诱人,因此这将影响问责制。
最后,算法歧视是指算法可以放大、操作化并最终合法化制度偏见的现象。当算法使这些偏见合法化时,我们可能会达到这样一个点,即我们不再质疑这些我们过去以怀疑的眼光看待的偏见,而是接受它们。这对我们的社会极其危险。
这就给我们带来了公平的问题。首先,公平是为了谁?不同的度量对不同的利益相关者很重要。例如,法官希望在审判中尽量减少假阴性,而被告希望减少假阳性的可能性,即被错误定罪的可能性。在处理公平和偏见问题时,我们必须始终牢记,公平是一个社会和道德概念,而不是一个统计概念。偏见是主观的,因此必须相对于任务来考虑。
问题 7 —数据尊严
这是提出的最后一个问题。数据是新的货币,我们每个人产生的数据都非常有价值。然而,我们的数据经常在未经我们同意和知晓的情况下被滥用,例如在剑桥分析丑闻中。因此,有必要维护数据尊严,即了解和控制您的数据如何被使用的能力。还应该有一个“数据即劳动”的概念,这是使用你的数据获得报酬的能力。这是完全正确的,因为数据是世界的新货币。
结论
我们已经对机器学习进行了简要的概述,并且讨论了机器学习可能会出错的七个问题。当我们思考我们如何经常毫无疑问地信任机器学习算法以及这可能对我们的社会产生的影响时,这无疑是值得思考的。
非常感谢 Getoor 教授关于负责任的数据科学的精彩而有见地的主题演讲,这确实很有启发性。
gan 的恢复收益
在这篇博文中,我将讨论 GANs 以及如何使用它来恢复图像。我将使用 fastai 库进行实践。我建议读者也去探索一下 fastai 。我们开始吧。
Image by Thomas B. from Pixabay
什么是图像恢复?
图像恢复是从失真图像中恢复原始图像的过程。图像恢复有多种类型,例如:
- 拍摄低分辨率图像并将其转换为高分辨率图像
- 将黑白图像转换为彩色图像
- 恢复图像的破损部分
还有很多。
让我们来处理第一种,即将图像上带有一些不想要的文本的低分辨率图像转换成高分辨率的清晰图像。我们需要一个图像数据集来恢复,fastai 为我们提供了图像数据集。让我们使用它。
import fastai
from fastai.vision import *
from fastai.callbacks import *
from fastai.vision.gan import ***path** = untar_data(URLs.PETS)
**path_hr** = path/'images'
**path_lr** = path/'crappy'
path _ HR—POSIX path('/root/)。fastai/data/Oxford-iiit-pet/images ‘)
path _ lr—POSIX path(’/root/)。fastai/data/Oxford-iiit-pet/crappy’)
现在,我们需要扭曲图像,我们可以创建任何扭曲图像的函数。下面,我将使用一个函数,在这个函数中,我将图像扭曲到低分辨率,上面有文字。让我们来理解一下。
from fastai.vision import *
from PIL import Image, ImageDraw, ImageFontclass crappifier(object):
def __init__(self, path_lr, path_hr):
**self.path_lr** = path_lr
**self.path_hr** = path_hrdef __call__(self, fn, i):
**dest** = self.path_lr/fn.relative_to(self.path_hr)
dest.parent.mkdir(parents=True, exist_ok=True)
**img_open** = PIL.Image.open(fn)
**targ_sz** = resize_to(img_open, 96, use_min=True)
**img** = img.resize(targ_sz, resample=PIL.Image.BILINEAR).convert('RGB')
**w,h** = img.size
**q** = random.randint(10,70)
ImageDraw.
**Draw**(img).
**text**((random.randint(0,w//2),random.randint(0,h//2)), str(q), fill=(255,255,255))***img.save(dest, quality=q)***
- dest —我们正在初始化存储垃圾图像的目标路径。
- img_open —使用 PIL 库打开图像
- targ_sz —初始化蹩脚图像的大小。
- img —调整大小后的图像
- w,h —图像的宽度和高度
- 问——选择任意一个随机数显示在图像上
- Draw() — 在图像上绘制文本。
- text() — 查找要在图像上绘制的文本。第一个参数声明了放置文本的尺寸。第二个参数是显示在图像上的数字。
- 最后,我们将图像保存到目标文件夹,质量为 q。
这就是我们如何复制图像。你可以以任何方式扭曲图像。
记住一件事,任何你没有包括在
crappifier()
中的事,模型不会学习去修正它。
il = ImageList.from_folder(path_hr)
parallel(crappify, il.items)
复制图像的过程可能需要一段时间,但 fast.ai 有一个名为parallel
的功能。如果你给parallel
一个函数名和一个运行该函数的列表,它会并行地运行这些函数。所以,会节省很多时间。
现在让我们对发电机进行预训练。这是我们处理完数据后通常要做的事情。
**bs,size** = 32, 128
**arch** = models.resnet34
**src** = ImageImageList.from_folder(path_lr).split_by_rand_pct(0.1, seed=42)def get_data(bs,size):
**data** = (src.**label_from_func**(lambda x: path_hr/x.name)
.**transform**(get_transforms(max_zoom=2.), size=size, tfm_y=True)
.**databunch**(bs=bs).normalize(imagenet_stats, do_y=True))
**return data**
让我们将 get_data()用于预处理的图像数据集。
data_gen = **get_data**(bs,size)
data_gen.**show_batch**(2)
现在,我们已经创建了数据群,我们必须使用这个数据群来创建学习者。
在这里,我希望读者了解 UNets 以及我们为什么使用它们。如果你对此知之甚少或一无所知,请参考这里的。
我们所做的是通过学习原始图像来恢复图像,而恢复就是 UNet 所执行的。我们需要通过 UNet,我们的数据。让我们利用 UNets,建立对 GANs 的需求。
获得给我们的只是来自不同文件夹的图像列表,按照要求进行了标准化和转换。现在,我们在标准化方法normalize(imagenet_stats, do_y=True)
中使用上面的 ImageNet 统计数据,因为我们将使用预训练模型。现在,我们为什么要使用预训练模型呢?我们想恢复扭曲的图像。使用至少了解动物(不是全部,而是很多)的模型来训练模型总是比使用对动物一无所知的东西来训练模型更好。此外,我们希望恢复图像,即从图像中移除我们的模型通常应该移除的不需要的文本。
一个建议是,迁移学习对几乎所有类型的计算机视觉问题都有帮助。
让我们声明参数。
wd = 1e-3
y_range = (-3.,3.)
loss_gen = MSELossFlat()def **create_gen_learner**():
return **unet_learner**(**data_gen**,
**arch**, **wd**=wd,
**blur**=True,
**norm_type**=NormType.Weight,
**self_attention**=True,
**y_range**=y_range,
**loss_func**=loss_gen)**learn_gen** = create_gen_learner()
wd
—描述正则化的模型的权重衰减。y_range
—这是应用于上一步获得的激活的 sigmoid 函数。这些值是为这类问题定义的。loss_gen
—定义了损失函数。由于我们是从原始图像恢复,因此我们需要将输出与原始图像进行比较,MSE loss 非常适合它。MSE 损耗基本上是在两个输入向量之间寻找损耗。在我们的例子中,输入是图像。因此,我们需要在将图像放入损失函数之前对其进行展平。MSELossFlat()
基本上做同样的事情。- 如果你想了解更多,在这里学习。
因此,我们使用预定义和预训练的模型 ResNet34 创建了 UNet 学习器。这整个过程被称为 生成学习, 我们使用 unet 学习器生成图像。这不是确切的定义,而是更广泛的定义。现在让我们来拟合这个模型。
learn_gen.fit_one_cycle(2, pct_start=0.8)
pct_start
—代表单个历元内的迭代次数,学习率将上升,学习率将下降的迭代次数。让我们只用上面的例子来理解它。
假设每个时期的迭代次数= 100
每个时期学习率增加的迭代次数= (100 * 1) * 0.8 = 80
学习率减少的迭代次数= 100–80 = 20
模型的上述拟合发生在 UNet 部分,即 UNet 的 ResNet 部分中的编码器冻结的情况下。但是,由于我们使用的是迁移学习,所以我们可以解冻 UNet 的预训练部分()U-Net 的预训练部分是下采样部分。ResNet 就在那里。
learn_gen.unfreeze()learn_gen.fit_one_cycle(3, slice(1e-6,1e-3))**learn_gen.show_results(rows=2)**
- 我们已经获得了一个较好的预测模型。我们的图像越快越不清晰是由于损失函数。我们使用的是 MSE 损失,即获得的图像和实际图像之间的像素差异非常小。如果删除文本是唯一的任务,那么我们已经实现了我们的目标。但是,我们也在努力提高图像分辨率。
- 基本上,该模型在上采样中表现出色,但在下采样中表现不佳。
- 我们要改进的只是损失函数。一个更好的损失函数会给我们更好的结果。这就是神经网络的定义。这就确立了对 GANs 的需求。
生成对抗网络
image source — fastai
让我们理解 gan 背后的语义。
- 到目前为止,我们有一个模型,它适度地预测了与原始图像没有太大差别的图像。按照上面的图片,我们已经创建了蹩脚的图片,并且生成器也没有生成如此糟糕的图片。然后,我们使用像素 MSE 来比较预测图像和高分辨率图像。
- 想象一下,如果我们能得到一些东西,而不是比较图像之间的像素,实际上将预测图像分类在高分辨率图像和低分辨率图像之间。如果我们可以欺骗二进制分类器,让它开始将生成的图像分类到高分辨率图像,那就更有趣了。
- 一旦我们开始愚弄分类器,那么我们将训练分类器更多地预测图像的实际类别,即如果图像是生成的,那么它应该正确地预测它,如果图像是高分辨率图像,那么它应该预测它是高分辨率图像。
- 一旦分类器训练正确地预测预测图像的类别,这意味着我们不能再欺骗分类器。在这种情况下,我们将进一步训练生成器,使其能够生成更接近高分辨率图像的图像。一旦我们训练了足够多的生成器,我们就可以再次欺骗分类器。
- 一次,我们再次开始愚弄分类器,这次我们将开始更多地训练分类器。这个训练生成器和分类器的过程实际上越来越多地归结为 GANs。
- 因此,基本上,GANs 中的损失函数调用了我们的另一个模型,而这个模型本身已经达到了最先进的结果。所有的博弈都是为了得到越来越好的损失函数。
相信我!这都是干的。
我们已经创建了生成器。现在让我们创建分类器。但是在我们创建分类器之前,我们需要将我们的预测存储在某个地方,因为我们需要在预测图像和高分辨率图像之间进行分类。所以,让我们把预测的图像存储在某个地方。
name_gen = 'image_gen'
path_gen = path/name_genpath_gen.mkdir(exist_ok=True)
- 我们已经创建了一个路径
PosixPath(‘/root/.fastai/data/oxford-iiit-pet/image_gen’)]
,用于存储生成的图像。 - 我们已经有了存储高分辨率图像的路径
PosixPath(‘/root/.fastai/data/oxford-iiit-pet/images’)
。
def save_preds(dl):
i=0
names = dl.dataset.items
for b in dl:
preds = learn_gen.pred_batch(batch=b, reconstruct=True)
for o in preds:
o.save(path_gen/names[i].name)
i += 1save_preds(data_gen.fix_dl)
- 我们已将预测保存在文件夹中。
data_gen.fix_dl
将生成固定大小的数据加载器。- 然后,我们迭代数据加载器,提取特定大小的数据,并将其传递给
pred_batch
进行预测。 - 然后,我们将预测的图像存储到图像名称下的文件夹中。
现在,我们需要编码分类器。如果您需要了解更多关于分类器的信息,请阅读此处的。
def **get_crit_data**(classes, bs, size):
**src** = ImageList.**from_folder**(path, include=classes)
.**split_by_rand_pct**(0.1, seed=42)
**ll** = src.**label_from_folder**(classes=classes)
**data** = (ll.**transform**(get_transforms(max_zoom=2.), size=size)
.**databunch**(bs=bs).normalize(imagenet_stats))
return **data**data_crit = **get_crit_data**([name_gen, 'images'], bs=bs, size=size)
from_folder
—从位于path
的文件夹中提取图像。我们希望只包含那些名称在include=classes
中提到的文件夹的数据。label_from_folder
—使用基本上是文件夹名称本身的类来标记图像。- 然后,我们转换数据,创建数据串,最后将数据标准化。
data_crit.show_batch(rows=3, ds_type=DatasetType.Train, imgsize=3)
让我们为分类器定义学习者。
loss_critic = AdaptiveLoss(nn.BCEWithLogitsLoss())def **create_critic_learner**(data, metrics):
return **Learner**(data, gan_critic(), metrics=metrics, loss_func=loss_critic, wd=wd)learn_critic = **create_critic_learner**(data_crit, accuracy_thresh_expand)
- 如果你说
gan_critic
,fast.ai 会给你一个适合 GANs 的二元分类器。 - 因为我们有稍微不同的架构和稍微不同的损失函数,所以我们做了稍微不同的度量。
accuracy_thresh_expand
是相当于甘版的准确性对于评论家来说。 - 最后,我们调用
create_critic_learner
来为 GANs 创建学习器。Fastai 数据块 API 有利于创建学习者。
learn_critic.fit_one_cycle(6, 1e-3)
- 现在,我们有一个学习者,他非常擅长区分预测图像和高分辨率图像。
- 这也是预测的行为,因为我们已经有图像很好的区分。
现在,我们有了一个生成器、分类器/评论家。让我们转到这一节的最后一部分。
完成 GAN
learn_crit=None
learn_gen=None**data_crit** = **get_crit_data**(['crappy', 'images'], bs=bs, size=size)**learn_crit** = **create_critic_learner**(data_crit, metrics=None).load('critic-pre2')**learn_gen** = **create_gen_learner**().load('gen-pre2')
- 既然我们已经预先训练了发生器和批评家,我们现在需要让它在两者之间进行乒乓式的训练。
- 你在每一件事情上花费的时间和你使用的学习率仍然有点模糊,所以 fastai 提供了一个
GANLearner
,你只需传入你的生成器和你的批评家(我们刚刚从我们刚刚训练的生成器和批评家中加载的)它就会继续前进 - 当你进入
learn.fit
时,它会为你做这件事——它会计算出训练生成器需要多少时间,然后什么时候切换到训练鉴别器/批评家,它会前后移动。
**switcher** = **partial**(AdaptiveGANSwitcher, critic_thresh=0.65)
learn = **GANLearner**.from_learners(**learn_gen**,
**learn_crit**,
**weights_gen**=(1.,50.),
**show_img**=False,
**switcher**=switcher,
**opt_func**=partial(optim.Adam, betas=(0.,0.99)), wd=wd)**learn.callback_fns.append(partial(GANDiscriminativeLR, mult_lr=5.))**
- 甘人讨厌你训练他们时的冲劲。用动力训练他们是没有意义的,因为你一直在发电机和批评家之间切换,所以这有点困难。所以这个数字(
betas=(0.,...)
)当你创建一个亚当优化器的时候,就是动量去的地方,所以你应该把它设置为零。 - 基本上,上面定义的超参数通常适用于 GAns。每个 GAN 问题都可能用到这些参数。
lr = 1e-4
learn.fit(40,lr)
- 随着生成器变得更好,鉴别器(即批评家)变得更难,然后随着批评家变得更好,生成器变得更难。训练甘的困难之一是很难知道他们做得怎么样。了解他们做得如何的唯一方法是不时地看一看结果。
- 如果你把
show_img=True
放入 **GANLearner,**然后它实际上会在每个历元后打印出一个样本。
做完这些,你可以检查下面的结果。
learn.show_results(rows=1)
最后,您可以将以前的结果与现在的结果进行比较。这就是甘斯发挥作用的地方。
GANs 的缺点
我们使用了一个 critic,它没有使用任何预先训练好的模型,比如 ResNet34,而是使用了 gan_critic()。因此,我们需要一个预训练的分类器模型,它不仅在 ResNet34 上训练,而且与 GANs 兼容。
这是我对甘斯的看法。感谢阅读,并继续探索 fastai。
受限三次样条
拟合回归线的一种灵活方法
样条是一种用于绘制曲线的绘图工具。在统计学中,样条是变换变量的一大类方法。我首先通过线性样条来介绍这个概念,然后用我的方法来介绍我(和许多其他人)推荐的受限三次样条。你应该知道有大量不同的样条,每一种都有其支持者。途径如下:
1.虚拟变量
2.无限制线性样条
3.受限线性样条
4.受限三次样条
在的一篇早期文章中,我向展示了分类(虚拟变量方法)不是一个好方法。它有两个基本问题:关系在每个段内是平坦的,而在段之间是跳跃的。在样条术语中,让一条曲线跳跃被称为“无限制的”。第二步消除了平坦性(但是给我们留下了跳跃的直线)。第三步去掉跳跃(但保留直线)。第 4 步让每个部分的关系曲线。结果是一个非常灵活的曲线,没有跳跃。受限三次样条(RCS)有许多优点,但是它们有一个很大的缺点:结果输出并不总是容易解释。
样条的两个方面,我们还没有触及的是允许的结的数量以及如何放置它们。已经提出了各种建议,但 Frank Harrell 建议,如果 N < 100,则使用 4 个结,对于较大的数据集,使用 5 个结,对于 k = 4,将它们放置在第 5、35、65 和 95 个百分点,对于 k = 5,将它们放置在第 5、27.5、50、72.5 和 95 个百分点(其中 k 是结的数量)。
举例来说,这一切可能会更清楚。为了比较,我将从正弦回归开始(就像我以前的帖子一样),我们应该遵循上面关于虚拟变量图的结的建议。这会产生:
第一步是允许每条线之间的斜率不为零。有些混乱的代码(该死的吉姆,我是数据分析师,不是程序员!)是:
mUnresLin1 <- lm(y~x, subset = (x6int == 1))
mUnresLin2 <- lm(y~x, subset = (x6int == 2))
mUnresLin3 <- lm(y~x, subset = (x6int == 3))
mUnresLin4 <- lm(y~x, subset = (x6int == 4))
mUnresLin5 <- lm(y~x, subset = (x6int == 5))
mUnresLin6 <- lm(y~x, subset = (x6int == 6))
plot(x[x6int == 1],mUnresLin1$fitted.values,
las = 1,
xlab = "x",
ylab = "y",
col = "red",
xlim = c(min(x),max(x)),
ylim = c(min(y),max(y)))
points(x[x6int == 2],mUnresLin2$fitted.values,
col = "red")
points(x[x6int == 3],mUnresLin3$fitted.values,
col = "red")
points(x[x6int == 4],mUnresLin4$fitted.values,
col = "red")
points(x[x6int == 5],mUnresLin5$fitted.values,
col = "red")
points(x[x6int == 6],mUnresLin6$fitted.values,
col = "red")
points(x,y, pch = 20, cex = .5)
这产生了
这已经是一个重大的改进,但是有跳跃(其中一个相当大)和方向的突然转变,这可能与早期模型中的跳跃一样难以证明。
接下来,我们可以用一个受限的线性样条来强制这些线匹配。这里已经有一个 R 函数,所以代码很简单:
install.packages("lspline")
library(lspline)
mlinspline <- lm(y ~ lspline(x, quantile(x, c(0, .05, .275, .5, .775, .95, 1),
include.lowest = TRUE))) plot(x,mlinspline$fitted.values,
las = 1,
xlab = "x",
ylab = "y",
col = "red",
xlim = c(min(x),max(x)),
ylim = c(min(y),max(y)))points(x,y, pch = 20, cex = .5)
这会产生:
最后一步是让每一段内的线条弯曲。我们可以用受限制的三次样条来做到这一点;同样,有一个 R 包使这变得容易。
library(Hmisc)
library(rms)mRCS <- ols(y~rcs(x, quantile(x, c(0, .05, .275, .5, .775, .95, 1),
include.lowest = TRUE)))plot(x,mRCS$fitted.values,
col = "red",
xlim = c(min(x),max(x)),
ylim = c(min(y),max(y)))points(x,y)
它产生:
这与原始正弦曲线非常匹配。
高级 Keras —准确恢复训练过程
处理使用自定义回调的重要情况
Photo Credit: Eyal Zakkay
在这篇文章中,我将展示 Keras API 的一个用例,在这个用例中,从一个加载的检查点恢复一个训练过程需要以不同于平常的方式来处理。
TL;DR —如果您使用的自定义回调函数的内部变量在训练过程中会发生变化,那么您需要在恢复时通过不同的方式初始化这些回调函数来解决这个问题。
当使用 Keras 训练深度学习模型时,我们通常会保存该模型状态的检查点,以便我们可以恢复中断的训练过程,并从我们停止的地方重新开始。通常这是通过模型检查点回调来完成的。根据 Keras 的文档,保存的模型(用model.save(filepath)
保存)包含以下内容:
- 模型的架构,允许重新创建模型
- 模型的权重
- 培训配置(损失、优化器)
- 优化器的状态,允许从您停止的地方继续训练。
在某些用例中,最后一部分并不完全正确。
示例:
假设您正在训练一个具有自定义学习率调度器回调的模型,它会在每批之后更新 LR:
当回调被创建时,counter
变量被初始化为零,并与全局批处理索引保持一致(在on_batch_end
中的batch
参数将批处理索引保存在当前时期内)。
假设我们想从一个检查点恢复一个训练过程。通常的方法是:
The wrong way to do it
注意,LearningRateSchedulerPerBatch
回调用counter=0
初始化,即使在恢复时也是如此。当训练恢复时**,这将不会重现保存检查点时发生的相同情况。**学习率将从初始值重新开始,这可能不是我们想要的。
做这件事的正确方法
我们看到了一个例子,回调的错误初始化如何在恢复时导致不想要的结果。有几种方法可以实现这一点,这里我将描述两种方法:
解决方案 1:用正确的值更新变量
在处理简单的情况时,回调只有少量的更新变量,在恢复之前覆盖这些变量的值是相当简单的。在我们的例子中,如果我们想用正确的值count
来恢复,我们将做以下事情:
解决方案 2:用 Pickle 保存和加载回调
当我们的自定义回调有许多更新变量或包含复杂行为时,安全地覆盖每个变量可能会很困难。另一个解决方案是在每次保存检查点时清理回调实例,然后我们可以在恢复时加载这个清理,并用所有正确的值重建原始回调。
注意:为了清理你的回调函数,它们不能包含任何不可序列化的元素。此外,在 Keras 版本< 2.2.3 中,模型本身是不可序列化的。这防止了任何回调的酸洗,因为每个回调也持有对模型的引用。
在这种情况下,恢复将如下所示:
您可能已经注意到,我使用了一个名为ModelCheckpointEnhanced
的修改过的检查点回调。这是因为使用 pickless 方法意味着我们还需要ModelCheckpoint
回调来保存相关回调的 pickle。这种修改后的回调的示例实现可能如下所示:
上面的例子处理了你只需要处理一个回调的情况,如果你有多个回调需要保存,你将需要执行一些小的修改。
摘要
我们看到了在某些情况下,采取天真的方法来恢复训练过程会导致不希望的结果。我们看到了两种处理这种情况的方法,以便在重新开始中断的培训过程时获得一致的结果。
我使用的例子来自我的草图-RNN 算法的 Keras 实现,这是一个用于生成草图的序列到序列变分自动编码器模型。
零售定价:充分利用机器学习
内部 AI
机器学习旨在帮助零售商提高生产率和利润
如果你正在阅读这篇文章,你可能正在寻找优化定价的新方法。简单地说,传统的方法已经不够好了。诚然,它们仍然运行良好,足以让你生存下来,但它们不足以让你领先于精通技术的竞争对手。在这篇文章中,作为 Competera 的价格优化专家,我想介绍两件事:机器学习在零售动态定价中的巨大潜力,以及如何为采用这项技术做好准备,以利用它提供的每一个机会。
零售业中的机器学习
多年来,大牌公司一直在动态定价中使用机器学习。最聪明的例子是亚马逊,它是最早采用这项技术的公司之一。毫无疑问,这是促使该公司市值大幅增长的因素之一:从 2008 年的 300 亿美元增长到 2019 年的近 1 万亿美元。其他使用机器学习的公司包括沃尔玛、Jet 和新蛋。
是什么让这些算法如此高效和流行?是它们处理海量数据的能力,使人类能够做出实时精确的决策。如今,零售市场变得越来越活跃,这意味着零售商需要比以往更频繁地改变价格。与此同时,每个企业都希望为自己的每一件产品制定最优价格。两个主要问题使得在没有 ML 的情况下很难进行价格优化:
- 未来的不渗透性。在计算价格时,零售商不可避免地需要考虑需求对每件商品价格变化的反应。但是很难测量,因为它是非线性的、多因素的、延迟的(顾客有购物周期,并延迟接触新价格),并且严重受季节性、分销、广告和竞争行为等其他因素的影响。
- 每周甚至每天要监控和重新定价的产品数量,这对于人类管理者来说已经不可能了。此外,通过改变特定产品的价格,零售商不可避免地会影响产品组合中许多其他商品的销售。每一个定价决策都必须考虑到这种影响,而定价经理如果不使用技术,根本无法做到这一点。
解决这两个障碍对人类来说似乎是不屈不挠的——并且越来越多地外包给自学算法。这些算法处理无限数量的定价场景(等于宇宙中的原子数量),以实时选择最相关的一个。他们考虑了产品组合中成千上万的潜在关系,以推荐单个价格,从而最大化整个产品组合的销售和收入。
我收集了几个基于机器学习的价格优化案例,以更好地了解零售商如何利用它来增长。
案例一
*目标:*在 100 多个价格区域提高收入和销售额
部门: 快消品
*类型:*离线
*结果:*商品销售额增长 15.9%,收入增长 8.1%,毛利润增长 9.8%
案例二
*目标:*在不损失利润率的情况下实现收入最大化
部门: 消费电子
*类型:*离线
*结果:*收入增长 16%,销售额增长 14%
案例三
目标:提升所有销售 KPI
部门: 礼品
*类型:*在线
*结果:*商品销售增长 24.7%,收入增长 9.3%
因此,定价中的自学算法对你的 KPI 非常有益。你需要采取什么步骤为他们做好准备?
准备好在定价中拥抱机器学习
要部署基于算法的定价解决方案并充分利用它们,你必须经历四个阶段:准备所有必要的数据、选择提供商或建立内部定价系统、教导你的团队,以及在过程中的每一步都改进系统。
数据
令人惊讶的是,准备和收集数据可能是一个巨大的挑战,因为数据通常是非结构化的,存储在不同的源中,并且有许多错误。做好准备可能需要几周甚至几个月的时间。在某些情况下,雇佣一个擅长数据管理的承包商会更好。但是好消息是:你只需要做一次。即使你计划使用机器学习来自动化所有的业务流程,如物流、库存管理或动态定价,并将它们整合到一个单一的生态系统中,你也需要在开始时准备好数据,因为无论你是在定价还是物流中使用它来采用 ML,它都会有或多或少的相似结构。
外部或内部定价解决方案
想象一下,你拥有自己的核心竞争力——将你与竞争对手区分开来并增加利润/收入的东西。但除此之外,你还需要擅长其他几十种处于你核心竞争力外围的事情。例如,你设法向顾客提供低价,并且是有利购买价格的行家,然而,你的利润不仅取决于低购买价格,还取决于最佳货架价格。因此,你需要学会制定既不太低也不太高的价格。能够做到这一点是一项全新的技术,需要数百万美元的研发投入。
在这个场景中有两个选项可供选择:
- 雇佣一个核心业务是推荐最优价格的技术合作伙伴。
- 投入数百万在你的公司建立一个定价中心,成为定价大师。
谈到定价,零售商需要准确地知道哪些产品更适合使用机器学习算法或基于规则的定价。你怎么知道的?分析您的投资组合并指出三组项目至关重要:
- **草皮保护器或您与所有或大多数竞争对手共享的产品。**它们会增加你的客流量,因为顾客会因为这些商品来到你的商店。在大多数情况下,购物者寻求此类产品的最低价格——你必须提供最低价格才能从竞争对手中脱颖而出。在这里你可以不用机器学习。你需要的是持续的竞争性价格监控和基于规则的定价。
- **可以以更高价格出售的独家产品。**在这里,你应该使用机器学习算法以某种方式改变价格,影响需求反应,并达到一个允许产生最大收入的最优价格。
- 与竞争对手共享的产品,但不一定要有最低的价格来吸引顾客。由于购物者基于你的品牌影响力而非价格做出购买决定,你需要使用机器学习来计算你的品牌知名度可以让你提高这些特定商品的价格。
团队教育
一旦你的定价系统准备好了,是时候培训你的定价或品类经理了。他们需要了解自己在做什么,并接受算法提供的每一个价格建议背后的逻辑并不总是清晰的。基本上,他们需要学会信任算法,记住在使用算法之前,总有办法限制算法或测试他们的建议。与此同时,经理们需要意识到,算法通常会做出正确的决定:如果系统知道你的经理所知道的一切,它会表现得更好。因此,当与管理人员的专业知识相结合时,算法显示出更好的结果。
系统改进
你需要想出一个策略,并为定价系统提供一套在这个策略中需要达到的目标。您应该监视系统如何运行,并在运行过程中进行修正。如果你的目标和策略发生了变化,你需要相应地调整你的定价系统。
另外,你使用的定价系统必须尽可能的前沿。同样,你可以雇佣一个技术提供商来负责其解决方案的更新,或者创建一个专门的团队来监控机器学习中的所有技术进步,并将它们整合到你的系统中。
总而言之,我想在这篇长篇阅读中强调的是,对于不仅寻求生存,而且寻求繁荣的零售商来说,机器学习是一个真正有利的选择。要从中受益,你需要做四件事:
- 准备好你的资料。
- 构建内部解决方案或雇佣技术合作伙伴。
- 教育你的团队。
- 不断更新你的定价系统。
零售路径:使用空间数据提升零售
在实体零售业的世界里,获得竞争优势依赖于产品和商店管理。正确的轮班管理需要详细了解商店的占用率、顾客在商店中的时间和空间数量。历史上,商店会通过付钱给一名员工站在外面统计进出商店的顾客数量来收集入住数据。技术已经进步,现在商店可以在商店入口和出口安装定制摄像头,并自动统计顾客人数。不幸的是,安装这些摄像机仍然成本高昂。更糟糕的是,随着时间的推移,错过的顾客进出造成的误差会越来越大,使得计数变得不准确。下一代商店入住模型方法的时机已经成熟。
为了我的洞察数据科学项目,我咨询了商店大脑(BotS)。BotS 希望通过使用计算机视觉(CV)实时跟踪客户,为实体零售带来实时人工智能。大多数零售商店已经安装了监控摄像头来监视整个商店。BotS 通过与一家公司合作,分析商店员工和顾客的实时跟踪数据,该公司通过 CV 算法传递预先存在的监控摄像头镜头。合作公司输出链接到时间戳的坐标数据(x,y ),我在这篇文章中称之为轨迹。然后,机器人使用这些轨迹来建立商店占用的空间和时间模型。
我的目标是修复计算机视觉过程中产生的一些错误。CV 的第一个也是最明显的错误是轨迹不稳定。一个明显的例子是有人走在柱子后面(相对于摄像机视图)。当他们走在柱子后面时,他们不再被 CV 识别,当他们再次出现时,他们被给予一个新的识别号。虽然这可能不会对整体占用产生影响,但在项目的第二部分,单个轨道的长度变得很重要,特别是当两个摄像机两次识别同一个人时。
多重标识问题需要多一点解释。许多商店使用重叠覆盖的多个摄像机来获得完整的商店覆盖。如果一个人同时走过两个摄像头的视野,那么我们的 CV 数据集将会有重复的轨迹,从而夸大了对入住率的最终估计。
原入住模式
在深入研究我的项目之前,我想先做好准备,讨论一下原始的居住模型是什么样子的。所有这些数据都是从加利福尼亚的一家化妆品商店收集来的。
首先,为了理解 CV 对商店占有率的估计有多准确,我需要商店占有率的真实值。机器人从用于轨道建设的原始监控摄像机镜头中构建了这个真实值,并以 10 分钟为间隔计算商店中的人数。
The store opened at 9:00am and there seem to be clear signals of increased occupancy around 11am and after work around 6:00pm. With fluctuating signals throughout the rest of the day.
然后,机器人数据科学家之一单独创建了原始计算机视觉数据的占用时间序列模型。
The raw CV model plotted against the ground truth data
从上图中我们可以看出,原始 CV 模型在某些区域低估了入住率,而在其他区域高估了入住率。该模型的召回率和准确率分别为 0.793 和 0.793。我开始使用算法方法来提高这个模型的精确度和召回率。我希望我的算法可以通过移除重复的轨迹来减少假阳性,并通过在以前不存在轨迹的时间段(由于轨迹不稳定)将轨迹缝合在一起来减少假阴性。
一针及时
为了找出哪些曲目要缝合在一起,我对每个可能的曲目进行了成对比较。在开始解释之前,我需要定义两个术语:焦点轨迹和比较轨迹。焦点轨迹是我们两两比较的第一个轨迹,也是正在结束的轨迹。比较轨迹是我与焦点轨迹进行“比较”的轨迹。比较音轨是第二音轨,也就是开始的音轨。我的总体计划是将焦点轨迹的终点与一个(或多个)比较轨迹的起点进行比较。然而,我使用的 10 小时数据集足够大,导致一些计算问题。我不能只比较每首歌的结尾和起点,因为 30,776 首歌有超过 9 亿种可能的组合!
相反,我开始收集可能的候选曲目。首先,我加入了一个时间参数,该参数决定了任何在焦点轨迹之后超过 1s 才开始的轨迹都将被延迟太久,以至于无法匹配拼接。然后对于每个候选轨迹,我计算了焦点轨迹的最后一点和候选轨迹的第一点之间的距离。然后,我通过包括 0.6 米的最大距离参数来进一步细分数据,因为 76%的候选轨迹距离焦点轨迹不到 0.6 米。最后,我在做比较时结合了焦轨的一些特征。我计算了过去 5 秒内焦点轨迹的平均速度,然后估计了在焦点轨迹和候选轨迹之间的时间间隔内平均速度可能行进的距离。虽然有人可能会迅速改变他们的平均速度(想象一下从随意浏览清仓区到跑过商店),但这种可能性很小。
在使用上述过程缩减潜在候选数据集后,我对每个焦点/候选轨迹对进行了成对比较。对于每一对,我计算了焦点轨迹的最后一点和候选轨迹的第一点之间的时空距离。时空距离听起来像一个奇特的概念,但实际上它是一个三维距离公式,第三维是时间。
Equation 1: Spacetime distance formula given the differences in x-coordinates (x), y-coordinates (y) and time (t)
使用这个公式的优点是,它对更长的距离和更长的时间间隔都不利。任何使时空距离最小化的轨迹都被认为是最终的候选轨迹。一旦我有了最终候选轨迹,我就从焦点轨迹的最后一点线性插值到最终候选轨迹的第一点。然后我给所有的音轨分配了和焦点音轨相同的 ID。
Two tracks that I identified as belonging to the same track and identified for future stitching. The green track is the focal track and the blue track is the candidate track.
复视
一旦我把这些轨迹拼接在一起,我需要解决多重识别的问题。与 BotS 合作的化妆品店客户在店里安装了四个摄像头。这意味着每个人在数据集中最多可能被识别 4 次!
为了解决这个问题,我使用了另一种侧重于距离的方法。像拼接问题一样,我首先需要减少潜在的比较。
第一步是找出哪些轨迹在时间上重叠,因为我只对同时的共同识别感兴趣。然后,我通过只检查来自不同摄像机的轨迹来进一步细分数据。考虑来自同一个摄像机的两条轨迹。即使这两个轨迹非常接近,也完全有可能每个轨迹都是一个独特的人,例如,一个母亲和一个孩子会在同一个摄像机中显示为两个非常接近的轨迹。两条非常接近但来自不同摄像机的轨迹实际上不太可能是唯一的个体。
对于从不同相机拍摄的每个重叠轨迹,我计算了焦点轨迹和比较轨迹中每个重叠点之间的欧几里德距离。然后我计算了两条轨道的平均距离。我认为平均距离不超过 0.8 米的比较轨迹相当于焦点轨迹。我估计这个距离是不同相机之间的近似投影误差。
Three tracks that have an average distance of less than 0.8m along their overlap in time
一个以上的重叠轨道可以被标记为相同的,当这种情况下,我设置一个决策规则来选择最长的轨道。虽然我们可能会丢失其他轨迹的一些信息,但最长的轨迹将拥有占用模型所需的最大信息。
对比入住模型
这些处理步骤产生了什么影响?回想一下,BotS 最终感兴趣的是为这家化妆品店构建一个入住时间序列模型。
我通过对以地面真实时间点为中心的 5 分钟窗口内的轨迹数量求和,计算了数据集中每个时间点的商店预期占用率。
Time series of ground truth (blue), raw CV data (orange), and my processed output (green).
相对于原始的计算机视觉模型,找出我的加工输出的准确趋势有点困难。所以我也画出了两者之间的差异。
Time series of the difference between the calculated occupancy from the ground truth. Positive values represent areas where the models overpredicted, negative values represent underprediction.
在这里,我可以更清楚地看到与原始 CV 占用模型相比,我的处理模型的影响。相对于真实情况,原始输出倾向于低估,而我的处理模型倾向于高估。这个结果体现在我的模型的精度和召回率上,分别是 0.734 和 0.834。因此,虽然我在模型中减少了假阴性的发生率,但却增加了假阳性的发生率。因此,我认为对机器人来说,最好的方法是使用原始 CV 输出和我处理过的模型创建一个集合预测模型。通过这样做,我的模型更可能高估的区域将被原始模型更可能低估的区域所平衡,反之亦然。
接下来的步骤
我的算法中内置了一些参数,我可以在其中进行一些优化。在拼接步骤期间,可以通过找到局部稳定区域来优化作为数据集子集的各种参数,在局部稳定区域中,参数的增加/减少对找到的匹配数量没有影响。然而,优化这个参数将是一个耗时的过程,因此只能在增加计算能力之后才能完成。更有可能的优化候选是在多重识别步骤期间。在这种情况下,调整最大距离参数或者改变用于比较的时间阈值都是相对便宜的,并且可以针对候选匹配的数量没有局部变化的参数进行优化。
除了优化我的算法,我认为随着这个数据集的发展,还有很多非常有趣的分析可以完成。例如,机器人可以获取经过处理的数据集,并检查每个轨迹的特征,以自动识别员工和客户。理论上,员工的轨迹特征(速度、点与点之间的方向)会有所不同。顾客更有可能有一条在商店里游荡的轨迹,而雇员更有可能做定向运动,或者长时间保持静止(例如收银员)。
不管接下来的步骤是什么,采用我处理过的模型并开发一个更准确的商店占用率模型,将不仅为机器人,而且为许多实体零售店提供真正的价值。
人工智能咨询中的预聘协议
预聘服务是微妙但有用的
谷歌对预聘的定义是“预付给某人,尤其是律师的费用,以便在需要时获得或保留他们的服务。”在本文中,你将深入了解人工智能顾问如何考虑增加固定客户,而不是参与更标准的、有明确范围和持续时间的企业项目。
已经有一些很棒的文章介绍如何选择你作为顾问的时薪,我不会在这里重复。相反,我将专注于如何将引导和机会阶段的初始对话转变为客户维系或更标准的计时/固定费用项目。我认为,预聘是一种关系状态,而不是一种产品。
From this link
预聘谈话往往发生在一些初始项目之后,而不是第一天。原因很简单。在聘请顾问成为客户的一个重要选择之前,顾问真的需要在这种关系上投资。仅仅基于承包商的声誉签署聘用合同的风险太高了。
考虑到不同潜在客户的产品市场适合度是不同的,这是很有用的。鉴于人工智能咨询是一项服务业务,客户需要使服务符合他们的需求,承包商也需要确保他们处于良好的状态。
我喜欢把这个在聘用和定期聘用之间的决定看作是一个通用的服务行业难题,而不是人工智能行业特有的情况。让我们假设 AI 咨询是搜索引擎优化(SEO),一个聘约是 SEO 月费咨询,而开发的按小时或固定价格工作是标准工作(示例此处)。在这个类比中,客户每月向你支付 SEO 服务的佣金,因为你交付的是他们按月衡量的工作单位,比如流量、排名和销售额。此外,请注意,这是一个持续的努力,不会结束。没有所谓的“我们已经完成了搜索引擎优化”这个月费不是专业服务的小时,而是基于性能。另一方面,按小时或按天计费的东西,无论是人工智能、网络开发还是搜索引擎优化,都有固定的可交付成果,公司倾向于外包并支付费用,然后在内部管理。
From this link
这个内在与外在的思考过程让我想到了关于固定器的下一个观点。优秀的经理总是在进行“建造还是购买”的计算。在提案/RFP 阶段,经理正在考虑满足某些要求或改进某些 KPI,或解决某些棘手问题。正是在这个时候,他们考虑使用内部或外部资源。我们获得交易的原因是因为客户选择了购买而不是建造(除了一些例外,我将跳过,如培训和战略咨询和顾问委员会)。当一家公司考虑聘用协议时,同样的“建造与购买”思维过程也会发生。经理会考虑雇佣一个资源来填补职位空缺的成本和雇佣一个顾问来构建东西的成本。
有些客户就是不喜欢保持器。例如,根据我的经验,政府会保留供应商和供应商名单或专业服务合同,但通常不会指名道姓。我想这在高端法律工作和政治等其他领域是不同的,但在高端高科技领域,就我所见,这不是政府的事情。然而,这并不意味着政府不做家臣。相反,他们称之为固定成本的咨询服务。包括政府部门在内的一些客户可能有固定的小时工,这是无法确定的,而且他们还被分配了固定的年度或季度预算。在这种情况下,他们可能会聘请一名顾问,每年/每季度花 Y 小时做 X 量的工作。这是一个固定价格的项目,而不是预聘。不过,行话并不重要。事情就是这样。
From this link
一些客户更喜欢聘请顾问,因为他们期望在一个项目或一个部门中有不均衡的工作量,而他们确实需要做得更好。想想药物或医疗设备开发(大量的断断续续,遵循瀑布模型),或者安排一名顾问为现有的数据科学团队增加投入。
回头客对顾问来说是好事,因为它提供了更稳定的收入,对客户来说也是如此,因为他们不必不断地接触陌生人。有一些常见的安全问题会导致测试顾问可靠性的内部流程,避免一次又一次地这样做对客户有利。一个成功的聘请为双方提供了一些额外的好处。然而,如果每月聘用的价格太高,公司就简单地将工作安排到一个新的位置(如果他们可以的话),如果聘用的小时费率太低,那么顾问就简单地退出全价小时聘用。让我们深入研究一下这些数字,让您更具体地了解它是如何工作的。
对于咨询服务,我们收取 250 美元/小时或 2000 美元/天的费用。更多信息请点击。因此,10K/月 5 天/月的预聘听起来很聪明,但该公司也可以以 10K/月= 12 万/年的价格雇用一名员工来支付工资和福利,并获得一名全职员工而不是顾问。老实说,新员工和顾问一样容易被解雇,所以顾问需要从几个方面证明这种关系对公司来说是值得的。
**第一:质量。**咨询师牛逼。太棒了,以至于一个“普通”员工都无法增加同样的优秀、产出和洞察力。只有当关系增加了高质量时,保留才有意义。这是参加顾问委员会或参与管理规划会议的常见原因。有时(不总是)公司想宣传他们在和你合作。这基本上是顾问的免费营销,和公司的战略营销。其他时候有一英里长的 NDA 保持关系的秘密。
**第二:价值。**5 天的咨询提供的价值超过普通人 20 天的价值。这都是关于更好更快更强的代码和建议。
**第三:灵活性。**在合理的范围内,顾问将根据需要灵活调整工作规模,而不会修改预聘人员的价格。这种灵活性和规划为客户提供了价格一致性。如果客户突然需要大量的时间,额外的工作会有“数量折扣”,我们不需要为了提前交付客户需要的东西而签订合同。
第四:可用性。如果需要完成某件事,预聘客户会排在第一位。他们不会被其他一次性项目影响进度,事实上,他们的需求会影响其他项目,以最大化客户体验的服务质量。
第五:规模。顾问可以在关键时刻召集他们的团队。这有助于在不雇人的情况下扩大规模。
第六:小玩意。参差不齐的小工作真的很难包给外人。新来的家伙/女孩不知道小任务的背景,或者组织内的技术设置,因此将这些小任务推给圈内的顾问确实有助于消除公司内部团队的困难。很多律师搞 6 分钟计费时间增量。对于像电话这样的小项目,这种小额账单会被四舍五入。当咨询顾问这样做时,这是一个非常现实的问题,所以我不这样做。你也不应该。预聘使关系超越了一分一毫的追踪,进入了更有成效的工作领域,完成需要做的事情。
**第七:知识传递。**如果部署的系统由客户不断更新和维护,部署后支持可以融入到预聘协议中。他们可能想让顾问在兼职的基础上帮忙。通常情况并非如此,交接会结束契约,但有时情况确实需要这样做。从设计上来说,机构记忆永远不应由顾问掌握。保持合作的主要原因可能是随着时间的推移会有一些小的改进。这个迭代过程可能会给客户带来风险,他们希望通过让客户在产品开发的大推进之间做一些零星的工作来减轻风险。
**第八:理科!**ML/AI 中的很多东西 R & D 是 R 大于 D,R 真的不可能用固定大小的作用域来捕捉。相反,预聘协议有助于以固定的速度(消耗率)推进项目,顾问承诺推进项目的费用不超过每月 X 美元。这是一个典型的大公司或初创公司的研究单位。
**第九:体验。**引入与各种解决方案和客户需求互动的外部声音会有所不同。这就是拥有一个外部顾问委员会背后的想法。这种经验可以传递到企业的思维中,避免陷阱,并从企业泡沫之外的信息中发现机会。
**第十:原因。**非常明确地提出去做最有意义的事情。你不能追加销售预聘协议。相反,你提供它作为一个替代方案,继续你已经在按项目定价的关系。客户应该觉得预聘代表着双赢,而不是你想卖给他们的东西。
但是等等…
你应该而不是与某些客户做预聘有很多原因。到目前为止,我们一直在讨论预聘可能是一件好事。现在让我们来考虑一下为什么聘用合同的情况会出问题。我们的首席执行官马修·勒梅喜欢将警告信号称为“危险信号”。当谈到预聘协议时,一些客户挥舞着巨大的红旗。这些客户参与了一种特性蔓延、范围蔓延和重新协商策略的模式,您可以在非常严格的范围内针对每个项目进行处理,但您不希望在更加松散的保留关系中导航。把这个想象成一个晚餐伙伴。各付各的完全没问题。进入一个保持器就像轮流支付晚餐。如果你在情感上感觉到,当轮到你付钱时,客户想要一份 72 盎司的牛排,那么不要为了弄清楚这是否真的会发生而进入这种情况。在承诺这种更深层次的关系之前,咨询师需要对这种关系的良好基础有信心。从顾问的角度来看,如果你能持续地少赚一点钱,这是一笔公平的交易。如果假设不成立,那么坚持标准定价模型。
要点总结:
- 如何考虑提供一个保持器
- 有时候,一个保持器是适合客户的,但并不总是如此
- 预聘需要是双赢的局面
- 克服构建与购买的矛盾,以获得预聘
- 有助于促进人工智能咨询聘用协议需求的因素有:质量、价值、灵活性、可用性、大量小东西、知识转移、科学、经验和理性
- 不要轻易签订预聘协议
背景
我决定写这篇文章,因为我以前的文章引起了很多关注,也有一些戏剧性事件。巴黎 ML 学习小组为他们的讨论组“人工智能专业性:咨询、项目定价、交付结果”选择了我的文章“如何聘请人工智能顾问”和“如何为人工智能项目定价”。这部戏剧是关于抄袭其中一篇相同的文章,在LinkedIn 上的这篇文章和的后续文章中有最好的总结。事实上,同一周,我做了一个关于人工智能世界中的戏剧的网络研讨会(“人工智能:真相、谎言和彻头彻尾的谎言”)。我也在这个平台上接触到了 3K 的追随者(THX!),并伸手进行民调。这是我问的民意测验问题:
你喜欢读什么?
- 生意上的事。我想赚钱。别给我看代码了。
- 人工智能的应用。用代码做酷的东西。让我了解最新情况。
- 创业故事。说出你的故事。激励我。
- 一切。你做你的,伙计!
只有 52 人参加了投票。如果你没有收到邮件,并且想参与这样的事情,你可以加入简讯或者直接给我发邮件。我真的会看我的邮件。
以下是投票结果:
因此,似乎很大一部分观众最感兴趣的是看到酷的人工智能应用程序。我回应你的反馈。我的下一篇文章将会谈到这一点。我正在使用 2017 年我在上发表的一篇文章中的一些工作来制作 alpha 模型,根据公司的名称来解释小公司的类型。这里是库的代码。当我继续为这篇文章写东西的时候,你会注意到一些代码的提交。
马蒂厄·勒梅(Mathieu Lemay)和 T2 stallion . ai(T3)团队在迪拜的时候,我在渥太华经营商店,主要负责管理技术。Samuel 正在进行 AuditMap.ai 演示,我们通常只是在做我们该做的事情。
如果你喜欢这篇文章,那么看看我过去最常读的一些文章,比如“如何给人工智能项目定价”和“如何聘请人工智能顾问”还有嘿,加入快讯!
下次见!
——丹尼尔
lemay . ai
丹尼尔@lemay.ai
重新思考企业的人工智能/机器学习生命周期
企业对模型可再现性、可追溯性和可验证性的需求正在推动传统人工智能/机器学习交付生命周期的变化。这里有一些进化你的 AI/ML 生命周期的实用步骤。
Image by PublicDomainPictures from PixaBay
当前数据科学生命周期中存在显著差距
虽然数据科学家使用的技术和工具大幅增长,但数据科学的生命周期却停滞不前。事实上,从 20 多年前创建的最早版本的 CRISP-DM T1 到最近由领先供应商提供的生命周期,如 T2 谷歌 T3、T4 微软 T5 和 T6 数据机器人 T7,几乎没有什么变化。数据科学生命周期的大多数版本仍然处理相同的任务集:理解业务问题、理解领域数据、获取和工程数据、模型开发和培训,以及模型部署和监控(参见图 1)。
但是,随着数据科学深入大多数公司,企业需求也发生了变化。如今,模型的可再现性、可追溯性、可验证性已经成为大型企业对数据科学的基本要求。不幸的是,在领先的 AI/ML 生命周期中,这些需求被忽略或者被大大低估了。
Figure 1 — Current Data Science Lifecycles
为什么这些要求很重要?在金融服务中,可再现性、可追溯性和可验证性受到明确的监管(即:在欧盟、美国和加拿大)并且不容忽视。但是从医疗保健和生物技术到政府安全的许多其他行业也有类似的要求。事实上,现在即使是适度监管行业的企业也发现可重复性、可追溯性和可验证性的好处远远超过了它们的成本。
从许多方面来说,这并不令人惊讶:如果数据科学家可以轻松地修改几个月前最后一次工作的模型,而不必急于找到模型源代码和正确的训练文件,那么模型的更新速度和频率会提高多少?如果数据科学家能够确认训练数据血统,并始终如一地从原始来源重新创建训练文件,那么回答审计员和监管者的问题会更加容易和快捷?如果数据科学家可以轻松找到企业门控流程所需的生命周期输出,那么模型投入生产的速度会有多快?
大多数数据科学家都会一致认为,可再现性、可追溯性和可验证性的好处提高了他们的效率和敏捷性。
再现性、可追溯性和可验证性推动数据科学生命周期的成熟
考虑数据科学家经常经历的一些常见场景,以及当前数据科学生命周期中的缺点:
- **数据科学家必须解决导致模型性能下降的生产数据漂移:**具有成熟生命周期的企业可以通过获取模型源代码和训练文件来快速重建模型基线,然后再现结果,之后可以更新和重新训练模型。不幸的是,在许多企业中,这个简单的场景很难实现,因为没有维护模型源代码和训练数据之间的联系。
- **数据科学家必须向审计员或监管者证明模型基于原始业务事件获得了正确的结果:**在这种情况下,成熟企业中的数据科学家将能够展示原始数据文件是如何被正确地丰富、转换和/或聚合的,从而可以基于可追踪的数据谱系对模型进行可验证的训练。然而,大多数企业无法将培训数据谱系和相关的转换联系起来,而这些必须结合在一起才能形成可验证的模型。
- 在提升模型之前,数据科学家必须证明所有企业关口和检查都已成功完成:为了在成熟企业中促进这一结果,DEVOPS 和 MLOPS 流程将自动捕获关键工件和企业关口流程所需的 AI/ML 生命周期输出。不幸的是,很少有企业能够自动地(或者在某些不幸的情况下甚至是手动地)从 AI/ML 生命周期中捕获并保留关键的输出,这些输出是轻松快速地推广模型所必需的。
很明显,通过关注可再现性、可追溯性和可验证性,有很大的机会来提高企业数据科学生命周期的成熟度。真正的问题不是企业是否应该解决这些问题,而是企业必须以多快的速度解决这些问题。
新的数据科学生命周期推动者:生命周期目录
可再现性、可追溯性和可验证性是由几个简单的功能实现的:在数据科学生命周期中捕获关于模型的工件,存储这些工件,以及搜索和查看工件。这些功能是在当前数据科学生命周期的基础上稍微增加的,同时提供了一个工具,即“生命周期目录”,它提供了一个了解数据科学生命周期的窗口。
Figure 2 — Data Science Lifecycle Catalog
简而言之,生命周期目录是一个通向存储库的门户,该存储库包含模型源代码、模型培训文件、原始源数据和将数据转换为培训文件的程序的参考,以及在数据科学生命周期中捕获的其他工件:
- 为了解决可再现性问题,生命周期目录提供了对模型源代码(包括当前版本和以前版本)的引用,并且用于训练模型的数据被保存在清单中
- 为了解决可追溯性问题,生命周期目录维护对原始源系统数据和数据工程脚本的引用,这些数据工程脚本用于转换和丰富,从而提供对交付生命周期中所有数据更改的可见性。
- 为了解决可验证性问题,对训练输出、日志和相关工件的引用——包括与模型偏差和“道德”检查相关的输出日志——由生命周期目录管理,从而获取模型有效性的证据。
- 为了自动化信息捕获过程,生命周期目录将与 AI/OPS (DEVOPS for AI/ML)过程集成,以自动捕获上述工件。有趣的是,主要的云提供商、传统的 DEVOPS 供应商以及较新的 AI/OPS 初创公司正在提供工具和功能,这些工具和功能可以缝合在一起,以捕获许多所需的指标和元数据。
生命周期目录的门户允许企业的数据科学家在 AI/ML 生命周期中搜索、可视化和跟踪模型、相关数据和工件:
- 为了推动敏捷性,生命周期目录允许数据科学家:(a)查看和管理他们的模型库存,(b)查看 AI/ML 模型和版本的状态(已部署、正在开发等),查看和管理对用于创建每个 AI/ML 模型的培训资产和相关数据沿袭资产的引用,(d)查看和管理对在整个 AI/ML 生命周期中生成的工件的引用。
- 为了提高效率,生命周期目录提供了对所有受治理的 AI/ML 工件的访问。考虑一个这很关键的场景:首先,许多组织现在必须证明模型是无偏见的,并提供符合公司道德准则的结果——在这种情况下,保留偏见测试输出来提供这种证明。
- 为了解决安全性问题,只有经过身份验证和授权的个人才能访问生命周期目录,他们可以查看和/或管理 AI/ML 模型、部署或培训资产。
- 为了提高效率,生命周期目录提供了企业把关流程所需的所有证据,从而为“自助式” AI/ML 治理提供了潜力。
生命周期目录是数据科学生命周期的“记录簿”,允许数据科学家对企业的所有数据科学资产进行可视化、分类、分组、管理和治理。生命周期目录是数据科学生命周期中缺失的环节,可满足企业对可再现性、可追溯性和可验证性的基本需求。
重新思考人工智能/机器学习的云安全
旧的安全方法跟不上 AI/ML 对数据的需求。一个现代的云安全架构需要考虑什么?
Photo by Cederic X on Unsplash
为什么云原生 AI/机器学习在企业中停滞不前?
像之前的通用计算一样,人工智能/机器学习对数据的贪得无厌创造了对灵活容量和高级计算的巨大需求。看起来,人工智能/人工智能在云上的进军正在进行,早期采用者正在建立滩头阵地。
然而,最近的头条已经迫使企业非常谨慎地行动——以至于即使将少量敏感数据迁移到云中也是一项艰巨而耗时的工作。
毫不奇怪,AI/ML 的独特需求正日益与企业传统的谨慎安全策略产生严重冲突。
在我上一篇 文章 中,我证明了这种谨慎是绝对必要的——坦率地说,存在有效的数据安全和隐私问题。这些担忧是实质性的,也是严重的。这些问题——直到得到解决——将继续阻碍云原生 AI/ML 在企业中的采用,这似乎是很恰当的。
旧的安全方法不起作用
这个行业已经承认过去有效的方法今天可能不再有效。更具体地说,成功用于保护内部数据中心的老把戏需要重新设计,以适应云。
大多数人认为这种脱节是许多因素共同作用的结果——更聪明的黑客拥有更好的工具,加上许多企业的云安全实践相对不成熟。这显然是真的。然而,我认为事情远不止如此。
我的经验表明,企业可能需要重新思考他们如何在云上处理数据安全和隐私。我认为 McKinsey 最恰当地陈述了:“大多数传统 it 环境采用基于边界的‘城堡和护城河’安全方法”,宣称我们需要重新思考云的安全方法,因为它们“更像现代酒店,在那里,钥匙卡允许进入某些楼层和房间”。
旧城堡对现代酒店。护城河对钥匙卡。我们不再建造城堡和护城河是有原因的。更好的理由是考虑用更新的方法来解决数据安全和隐私问题。
在本文中,我将讨论所谓的“城堡和护城河”安全方法的缺点。然后,我将解释并建立麦肯锡倡导的“现代酒店房间”和“钥匙卡”概念,希望这将提供一个架构基础,以克服阻碍企业在云上采用 AI/ML 的有效安全和隐私问题。
Photo by Jerome Granados on Unsplash
城堡和护城河以及网络安全边界
许多企业仍然采用基于网络边界的安全方法。他们用更厚更坚固的网络墙建造数据中心“城堡”。他们用护城河来阻挡敌人,用吊桥来接纳朋友和客人。但这是基于一些有缺陷的假设。
第一个是墙壁并不那么好用。可能最好认为它们是必要的,但不是充分的。在过去,“城堡和护城河”的策略可能会赶走敌人。相对于今天,他们拥有更简单、效率更低的工具。但是敌人现在更聪明,有更好的武器。
有了这些新武器,敌人再也不用走前门了。相反,他们寻找砖块之间砂浆的裂缝——所需要的只是一个不为人知的小开口,让坏事发生。事实上,来自 Capital One 的头条暗示,即使是最好的“墙”也有裂缝。
第二个有缺陷的假设是,旧的数据中心“城堡”安全设计足够好,表明同样的方法可以应用于新的云环境。数据中心“城堡”几乎完全专注于其边界,认为数据中心内的资产在默认情况下是安全的。因此,重点主要是保护周边地区,而不是周边地区的资产。
另一方面,云安全原则是相反的。许多资源,除非明确受到保护,否则默认情况下是不安全的,无法通过互联网访问。是的,必须创建一个安全的边界,但是在许多情况下,边界内的资产也必须是安全的和锁定的。不幸的是,相对于保护云资产所需的深度和广度,许多企业的安全能力还不成熟。
最后,企业给了来宾(或员工)好处,一旦他们进入数据中心的“城堡墙”,通常可以访问他们想要的任何内容,或者至少是他们想要的大部分内容,而安全控制却少得多。但是,如果有人获得了对敏感数据的访问权,他们能够带着企业的资产离开“城堡”吗?
不幸的是,是的。在“城堡和护城河”战略中,重点通常是保护入口,较少关注一旦进入后会发生什么,更少关注保护出口。但是正如最近的头条新闻所暗示的,一旦被授权的个人——在这个特殊的例子中,是一个雇员——有权使用城堡的资产,那么把它们拿出来似乎相对简单。
为了解决这个问题,对云的关注必须是确保没有数据泄露的机会。即使有权访问敏感数据的个人也不得允许数据“泄露”到云安全边界之外。
然而,AI/ML 对数据的贪婪胃口大大增加了赌注。为了在云上实现“零泄漏”机会,必须考虑新的方法。
很明显,我们不再建造真实世界的城堡和护城河是有原因的。同样,我们也有理由避免构建数据安全和隐私“城堡和护城河”来保护我们在云上的企业数据资产。
基于身份的安全边界
过去,主要的安全边界是基于网络安全(“城堡和壕沟”策略),其目标是建立一个不可渗透的网络屏障。前提是有了安全的网络边界,网络中的所有系统和资源都是可信的。
当时,这是有意义的,因为大多数应用程序和资产几乎只存在于数据中心内部,或者只在数据中心内部协作。
然而,时过境迁。如今,人们期望资源(应用程序、数据等)。)将可通过互联网访问,无论您身在何处。设备(例如,BYOD)和云应用的爆炸式增长现在旨在利用这种位置中立性和开放网络。
但是旧的网络边界方法没有考虑到云的相对“开放性”,使企业容易受到攻击。这就造成了这样一种情况,一旦可信边界内的单个端点受到威胁,敌人就可以迅速在整个网络中扩大立足点。
更糟糕的是,敌人变得越来越聪明,获得了更好的工具,导致网络边界变得更加漏洞百出。
实际上,以网络为中心的思维变得不那么相关了。有人可能会说,现代云安全方法现在应该在网络边界可能被攻破的明确假设下进行设计。
这导致了一种新的安全模式:今天,身份成为新的安全边界。身份边界确保您是您所说的那个人,然后完全根据与您的身份相关联的授权来分配权限。
简而言之,资源可能被设计为利用云的“开放性”,但是如果没有适当的基于身份的认证和授权,任何资源都不能被访问或影响。
考虑到这一点,云数据安全和隐私设计原则的更好比喻可能是“现代酒店”,而不是“城堡和护城河”。
Photo by Jordan Pulmano on Unsplash
现代酒店
任何去过一点地方的人都能体会到现代酒店的体验。前门是敞开的,很受欢迎。在我们的“现代酒店”类比中,从数据安全和隐私的角度来看,企业的云租户就是酒店。
酒店的新客人会看到一个前台——在我们的比喻中是企业的互联网角色——它充当酒店的前门(图 1 中的“2 ”),可能对所有客人开放。
但是你需要登记才能走得更远。基于身份的安全边界(图 1 中的“1”)从这里开始。
在登记入住时,您的身份得到验证,一旦您付款,您将获得一张授权您进入指定房间的钥匙卡(图 1 中的“3”)。
但是,只有由您的酒店钥匙卡配置的房间和服务可供您使用。事实上,除了你自己的房间,所有其他房间都是关闭的,你可能会(礼貌地)拒绝未经你的钥匙卡授权的服务。
从这个意义上说,“酒店房间”和“钥匙卡”这两个术语似乎非常合适,它们表示以有利于需求的规模和方式消费服务的灵活性,以及按需容量,即服务可以在需要时消费。
继续类比,“房间”(图 1 中的“4”)有“墙”,这些墙提供了一个不可渗透的安全边界,允许在企业的云租户中有安全的处理区域。与酒店服务类似,默认情况下,企业的服务或房间不可用(关闭),只有在有效的身份验证和授权(由您的身份提供)后,服务才可用。
和现代酒店一样,这里有不同类型的房间,每种房间都有不同的配置以满足不同的需求。从 AI/ML 的角度来看,我们在企业的云租赁中有两种不同的房间类型,每种类型都可以满足特定的需求。
首先,我们需要专门设计的“数据存储室”(图 1 中的“5”),以确保敏感数据被安全地存储,并且仅被授权的实体(人或应用程序)访问。这些房间还可以配置为支持更强的安全控制,如静态数据加密,如果数据的敏感性需要这种功能。
其次,我们需要“数据处理室”(图 1 中的“6”),授权实体可以在这里安全地访问和处理敏感数据。
并总结我们的类比,像许多酒店房间一样,一个房间可以连接到另一个房间(图 1 中的“7”)。在我们的例子中,数据处理室将访问数据存储室,以允许 AI/ML 探索和训练活动。
顺便说一句,“房间”可能看起来类似于单个虚拟机。每个都有一个安全的边界,但相似之处可能就到此为止了。然而,与虚拟机不同,“房间”的功能是多样的、分布式的,并且实际上是由虚拟机集群部署的。
数据安全策略必须为云而发展
希望很明显,旧的数据安全方法需要重新考虑,以适应云。然而,这并不是说旧的方法应该完全抛弃。
仍然需要一个安全的边界。网络安全还是要落实的。
但是,旧的方法也必须不断发展,以应对云带来的独特的安全和隐私挑战。所谓的“城堡和护城河”变成了“有钥匙卡的酒店”,有基于身份的安全边界,定义了经认证和授权的客人可以执行的操作。
我们的新方法提供了“房间”,这些房间成为安全区域,是为云上的 AI/ML 特定需求定制的。它们既灵活又安全——可以按需创建(数据处理室),并支持安全的数据处理或安全的持久存储(数据存储室)。
最后,本文为理解云上 AI/ML 特有的安全挑战提供了基础。它还提供了一个类比——有房间、墙壁和钥匙卡的现代酒店——为云上的数据安全和隐私提供了一个新概念基础。
在本系列的下一篇也是最后一篇文章中,我将深入描述如何实现“酒店”、“房间”和“钥匙卡”来支持云上的安全 AI/ML。此外,下一篇文章还将讨论必须到位的云管理技术,以支持这些功能,并允许企业自信地启动和加速云原生 AI/ML 在企业中的采用。
反思工作中的思维
数据科学需要深入思考和多学科协作。现代办公环境对两者都是适得其反的
Rodin’s The Gates of Hell (AKA trying to work in open floor plan office on Halloween)
罗丹的预感:当我们大多数人想到罗丹最著名的雕塑《思想者》时,我们会想象出一个孤独的人站在基座上,陷入沉思。当然,这是因为这就是著名的 1888 年青铜雕塑及其复制品在博物馆和照片中呈现给我们的方式。但在《思想者》作为个人表演首次亮相之前,他是后来成为 37 年杰作《地狱之门》的合奏演员之一。仔细观察这幅作品,“思想者”若有所思地坐在一群暴民中间(见标题图片)。虽然艺术史学家会告诉我们,这件作品的灵感来自但丁的地狱,但我看到了时间旅行的证据——或者至少是未来的预感。否则,他怎么能如此清晰地想象出在 2019 年的万圣节,作为一名数据科学家,在与一家数字机构共享的 WeWork 开放式平面办公室中努力完成工作是什么感觉?对于关心生产力的“思考者”来说,现代办公环境真的感觉像是地狱之门。是时候重新思考我们被教导的如何管理团队以提高生产力和协作,并给人们时间和空间进行有计划的、不间断的思考。
**忙碌并不等同于高效:**我们一生都被告知,工作意味着积极参与一项活动。从每天的开始到结束,就好像我们在进行多任务耐力测试。当然,结果往往会得到回报——但让人们看起来持续活跃的行为也是如此,不管他们是否真的完成了什么。早在小学时,“举手者”就受到奖励,“白日梦者”受到嘲笑。在课间休息时独自阅读或凝视天空被认为是反社会的,或者充其量是一个令人担忧的理由。在以后的生活中,这些词会变成“冷漠”或“脱离”,但前提是一样的——工作是做的地方,而不是思考的地方。如果你是,比如说,一个酒保,这很有道理…但是如果你的职业依赖于你专注和深入思考的能力来完成你的工作呢?
**做作的合作扼杀了独立思考:**在当今的工作场所,找到一个专注的时间和地点是很难的,这对于创新和生产力来说是必不可少的,尤其是在需要不断在创造性和定量思维之间转换的职业中。人们不认为数据科学是一个创造性的职业,但我工作过的最有才华的数据科学家能够在定量和创造性世界的交叉领域出类拔萃。从规划数据结构,到选择正确的数学方法,再到解释现实生活中的含义,然后用非技术交流的方式表达出来,这些都需要数小时不间断的专注。今天的工作环境已经将如此多的努力集中在试图诱导协作上,以至于在许多情况下,一个人不得不在沉默中思考的唯一选择是完全避开办公室。对即时通信的需求、认为远程工作是“休息时间”的主管以及强迫人为协作的办公室布局加剧了这种困境,这是颠覆他们试图培养的生产力和协作的秘诀。
**反思协作思维:**如果我们真的想从团队中获得最大收益,我们需要让他们远离噪音和干扰,腾出时间进行深入思考。我们需要消除这样一种观念,即独处是一种奢侈品或特殊恩惠,只有仁慈的主管才能给予。与团队合作的时间对于团队的成功仍然至关重要,但当每个人带着他们的最佳想法来到谈判桌前时,这些时间会更有成效——而我们没有培养有利于实现我们最佳想法的工作环境和实践。
关于独处的好处,我强烈推荐艾特金·坦克的文章 独处:原创思维的秘密https://medium . com/swlh/Solitude-The-secret-to-original-thinking-c5ac 755184 EC
基于 U-Net 结构的视网膜血管分割
视网膜脉管系统所展示的结构推断出关于诸如早产儿(RoP)、糖尿病性视网膜病(DR)、青光眼、高血压和与年龄相关的黄斑变性(AMD)等广泛的视网膜病理的关键信息。这些病理是失明的主要原因。视网膜脉管系统的精确分割对于各种眼科诊断和治疗过程是重要的。
在过去的几十年里,许多研究都集中在开发用于视网膜血管分割的自动化和精确的技术上。随着近年来机器学习、深度学习和计算机视觉的兴起,研究人员已经找到了应用这些技术为医学、生物学和医疗保健中存在的问题提供解决方案的方法。
在这些技术中,U-Net 是一种有趣的深度学习网络架构。它是由 O. Ronneberger,P. Fischer 和 T. Brox 在 2015 年开发的,可以归类为用于生物医学图像分割的全卷积神经网络(CNN)。U-Net 论文的作者写了以下内容。
…在本文中,我们提出了一种网络和训练策略,它依赖于对数据扩充的大量使用,以更有效地使用可用的带注释的样本。该架构由一个捕获上下文的收缩路径和一个支持精确定位的对称扩展路径组成……
U-Net 不需要大量的训练数据,这使得它非常适合于生物医学图像分析,因为生物医学领域中的图像相对稀缺。在本文中,我们将讨论如何编写一个简单的 U-Net 架构来解决视网膜血管分割问题,以及如何评估算法的性能。
A Retinal Image
我已经使用了“驱动:用于血管提取的数字视网膜图像”数据集来训练网络。在数据集中,有两个文件夹,即“培训”和“测试”。“训练”文件夹包含 20 幅视网膜图像及其血管遮罩。“训练”文件夹中的 17 幅图像及其血管遮罩被用作训练集。剩余的 3 幅图像及其血管掩模作为验证集。测试文件夹包含 20 幅图像和两种类型的血管屏蔽(1st_manual 和 2nd_manual)。1st_manual vessel masks 被视为黄金标准,以便在评估性能时可以将人工注释(2nd_manual)与黄金标准进行比较。将 20 个图像及其血管掩模(1st_manual)作为测试数据。视网膜图像是 3 通道图像(RGB ),而它们的血管掩模是二进制图像。驱动器上的原始图像尺寸为 565 × 584。在将训练集、验证集和测试集保存在“. hdf5”文件中之前,它们的大小被调整为 512 × 512。
下图展示了我们将要考虑的 U-Net 架构。
The U-Net framework
以下要点包含了我们可以用来训练模型的 U-Net 架构。架构是用 keras 写的。
U-Net architecture coded in python (with Keras)
由于我们的训练集相当小,使用数据扩充技术来增加训练数据的大小是有帮助的。为此,我们可以使用 keras 的 ImageDataGenerator 类。它使您能够配置图像准备和增强。这个类的伟大之处在于它能够在模型拟合过程中创建扩充数据。数据生成器实际上是一个迭代器,当模型拟合算法请求时,它返回成批的增强图像。
为了准备用于训练的数据,我们必须首先在区间[0,1]内重新调整它们。当扩充我们的数据时,我们可以使用随机旋转。这些随机旋转的角度范围可以在数据生成器中指定。这将使我们的模型旋转不变,因为模型将看到不同方向的图像。此外,我们可以使用水平和垂直随机移动作为增强技术。通过在具有不同垂直和/或水平位移的图像上训练我们的模型,我们可以使我们的模型平移不变。缩放是我们可以使用的另一种增强技术。这将使我们的模型比例不变。我们可以如下配置上述图像数据准备和增强技术。
datagen_args = dict(
rescale=1./255,
rotation_range=90,
width_shift_range=0.1,
height_shift_range=0.1,
zoom_range=0.2
)
在数据准备和扩充期间,我们必须确保蒙版得到的变化与我们应用于图像的变化相同。下面的函数会解决这个问题。
def get_generator(self, images, masks):
image_datagen = ImageDataGenerator(**datagen_args)
mask_datagen = ImageDataGenerator(**datagen_args)
seed = 1
image_generator = image_datagen.flow(images, seed=seed)
mask_generator = mask_datagen.flow(masks, seed=seed)
return zip(image_generator, mask_generator)
现在,我们可以定义模型的训练例程。我们将使用学习率为 0.0001 的 Adam 优化器。损失函数将是二进制交叉熵,因为我们正在处理像素标记问题。(血管区域= 1,非血管区域= 0)。我们将训练 50 个时期的模型,同时每个时期有 200 个步骤,我们的批量大小是 32。这样,由于我们之前定义的图像增强配置,该模型在每个时期将看到 32 × 200 = 6400 幅图像。每当在给定时期结束时损失得到改善,我们就将我们的模型权重保存到“. hdf5”文件中。此外,我们将实现一个有 10 个周期的耐心(没有改善的周期数,在此之后训练将被停止)的早期停止。
compile_args = dict(
optimizer=Adam(lr=1e-4),
loss='binary_crossentropy',
metrics=['accuracy']
)earlystopper = EarlyStopping(
patience=10,
verbose=1
)model_checkpoint = ModelCheckpoint(
self.model_path,
monitor='loss',
verbose=1,
save_best_only=True
)model.compile(**self.compile_args)train_generator = self.get_generator(x_train, y_train)
val_generator = self.get_generator(x_val, y_val)model.fit_generator(
train_generator,
epochs=50,
steps_per_epoch=200,
verbose=1,
callbacks=[model_checkpoint, earlystopper],
validation_data=val_generator,
validation_steps=10
)
训练完成后,我们可以评估我们的模型。为了评估该模型,我们可以使用性能指标,如 F1 分数、准确度分数、受试者-操作者曲线(ROC) AUC 和精确度-召回率(PR)曲线 AUC。绘制 PR 和 ROC 曲线可以很好地了解模型性能。
我们还可以绘制一个选定的视网膜图像(来自测试集),它的血管掩模由人类注释者创建,它的血管掩模由我们的 U-Net 模型预测。
From the left : Original retinal image, vessel mask annotated by a human and the predicted vessel mask using the U-Net model
这篇文章到此结束。请在评论中告诉我你的问题。U 网快乐!
参考资料:
在 Python 中检索 OpenStreetMap 数据
关于如何使用 Google Colab 通过 Python 访问 OpenStreetMap 数据库的指南。
OpenStreetMap — Source
如果您想从 OpenStreetMap (OSM)中检索地理空间数据,您可以下载它,但这需要时间和存储空间。无需离开您的开发环境(Jupyter 笔记本),您就可以访问和检索 OpenStreetMap 数据。假设您正在进行分析,并想找出您感兴趣的区域内有多少娱乐设施或餐馆。
在本教程中,我们将学习使用 python 包 OSMNX 检索 OpenStreetMap 数据。
OSMnx 是一个 Python 包,允许您从 OpenStreetMap 的 API 下载空间几何图形并对街道网络和其他空间数据进行建模、投影、可视化和分析
在接下来的三个部分中,我们从 OpenStreetMap 中检索三种不同的数据:作为兴趣点的咖啡馆、建筑物和街道网络。我们还探索了使用 leav 的地理空间数据可视化。
街道
我们首先创建一个变量来保存我们感兴趣的区域。你可以随意探索任何你想去的地方,但是我在本教程中使用利物浦市(注意你的区域越大,计算时间就越长。)
place = “Liverpool, United Kingdom”graph = ox.graph_from_place(place, network_type=’drive’)
通过上面两行代码,OSMnx 允许我们快速检索城市的街道网络。结果是一个 Networkx 类,我们将其转换为 Geopandas 以进一步处理数据。让我们看看如何将它转化为 Geopandas 地理数据框架。OSMnx 自带的“graph_to_gdf”功能可以轻松做到这一点:
nodes, streets = ox.graph_to_gdfs(graph)streets.head()
现在,如果我们看数据,它被转换成熟悉的熊猫数据框的形式,具有额外的地理数据处理能力。
Retrieved streets
您可以使用您选择的任何工具(在我们的例子中是 Pandas)来处理检索到的数据,或者使用任何 Python 库来可视化您的数据。假设我们想要获得街道类型的条形图。下面的过程只是纯粹的熊猫功能与 seaborn 数据可视化。
street_types = pd.DataFrame(edges["highway"].apply(pd.Series)[0].value_counts().reset_index())street_types.columns = ["type", "count"]fig, ax = plt.subplots(figsize=(12,10))sns.barplot(y="type", x="count", data=street_types, ax=ax)plt.tight_layout()plt.savefig("barchart.png")
这是数据的输出条形图。住宅区街道在该数据集中出现频率最高。
Bar chart — Street types
我们还可以通过使用 Python 中您最喜欢的地理空间可视化工具,使用地图来可视化街道数据。我在这里用叶子。
style = {‘color’: ‘#F7DC6F’, ‘weight’:’1'}m = folium.Map([-2.914018, 53.366925],zoom_start=15,tiles=”CartoDb dark_matter”)folium.GeoJson(edges.sample(), style_function=lambda x: style).add_to(m)m.save(“edges.html”)m
输出是利物浦所有街道的美丽地图。不需要下载数据,上传,用熊猫看。
Streets Visualized in Folium
在下一部分中,我们将检索利物浦 OpenStreetMap 数据中所有可用的建筑。
建筑足迹
为了检索建筑占地面积,我们使用 OSMnx 的“footprints_from_place”功能。我们需要传递这个地方的名称。
buildings = ox.footprints_from_place(place)
buildings.shape
建筑物数据集有 27329 行和 185 列(请注意,随着 OSM 用户更新该区域的任何要素,这可能会发生变化)。让我们看看我们检索到的建筑物数据集的子集。
cols = [‘amenity’,’building’, ‘name’, ‘tourism’]buildings[cols].head()
Building table
我们还可以绘制建筑地图。由于较大的数据集,lyum 可能无法在笔记本中正确显示它,但您可以保存它并在浏览器中打开它。
style_buildings = {‘color’:’#6C3483 ‘, ‘fillColor’: ‘#6C3483 ‘, ‘weight’:’1', ‘fillOpacity’ : 1}m = folium.Map([ 57.70958, 11.96687],zoom_start=15,tiles=”Stamen Toner”)folium.GeoJson(buildings[:1000], style_function=lambda x: style_buildings).add_to(m)m
A subset of Building footprints in Liverpool.
兴趣点(咖啡馆)
我们还可以从 OpenStreetMap 数据集访问和检索其他一些基于点的数据集。OSMnx 还具有 ox.pois_from_place()功能,您可以在其中传递对舒适性参数感兴趣的变量。可用设施列表可从 OpenStreetMap Wiki 获得。
在这个例子中,我们检索利物浦的咖啡馆。
cafe = ox.pois_from_place(place, amenities=[“cafe”])
cafe.head()
这是咖啡馆数据集的一个子集,其中有一个名称、轮椅可用性和开放时间列。但是,有些列没有数据。
最后,让我们在地图上标出这些咖啡馆。
cafe_points = cafe[cafe.geom_type == “Point”]m = folium.Map([53.366925, -2.914018], zoom_start=10, tiles=”CartoDb dark_matter”)locs = zip(cafe_points.geometry.y, cafe_points.geometry.x)#folium.GeoJson(buildings, style_function=lambda x: style_buildings).add_to(m)for location in locs:folium.CircleMarker(location=location,color = “#F4F6F7”, radius=2).add_to(m)m.save(“cafes.html”)m
以下是利物浦 OpenStreetMap 数据库中所有咖啡馆的地图。
Cafes in Liverpool
检索 OSM 数据可以与你的任何其他数据分析或可视化项目相结合。尝试任何你感兴趣的地方。请注意,如果您发现您感兴趣的区域没有足够的数据,您可以贡献 OpenStreetMap 数据。
结论
在本教程中,我们使用 OSMnx 检索 OpenStreetMap 数据,并使用 Pandas 和 Geopandas 处理它。我们还了解了如何使用 leav 可视化地理空间数据。
本教程的笔记本是可用的。你可以直接在 Google Colab 中运行这个。
编辑描述
colab.research.google.com](https://colab.research.google.com/drive/1Rpg0uFFMRB8Im3c32lO6J5-821vIt5p5)
Python 中的反向地理编码
如何将原始的纬度/经度转换成带有地址的有洞察力的数据。
Photo by Devin Avery on Unsplash
许多数据集只有坐标——纬度和经度——与我们人类识别的地址、街道名称、建筑名称或邮政编码等可识别特征没有任何关联。反向地理编码是许多位置数据科学应用中的重要组成部分。将原始坐标转换为有洞察力的位置数据要素的过程称为反向地理编码。
反向地理编码是将一个点的位置(纬度、经度)反向(反向)编码为可读地址或地名的过程。— 维基百科
Reverse Geocoding
在本教程中,我们将介绍如何使用 Python 执行反向地理编码。我们使用 Pandas 和 Geopy 库来提供反向地理编码。在下一节中,我们将介绍一些基础知识,并将单点坐标转换为带有邮政编码和建筑物名称的地址。
反向地理编码单一示例
让我们先导入我们的库。
%load_ext autotime
import pandas as pd
import geopandas as gpd
import geopy
from geopy.geocoders import Nominatim
from geopy.extra.rate_limiter import RateLimiterimport matplotlib.pyplot as plt
import plotly_express as pximport tqdm
from tqdm._tqdm_notebook import tqdm_notebook
我们现在可以构建我们的地理编码器。我们首先需要指定地理编码服务。您可以访问不同的服务,包括'google'
、'bing'
、'yahoo'
和'openmapquest'
。其中一些服务在特定限制后收取少量免费费用,但在我们的示例中,我们将使用 Openstreetmap 的免费地理编码服务。
locator = Nominatim(user_agent=”myGeocoder”)coordinates = “53.480837, -2.244914”location = locator.reverse(coordinates)location.raw
一旦您使用我们选择的地理编码服务提供了坐标,结果就是您可以访问的不同要素的字典。如果你打印出location
的raw
元素,你将会看到几个源自坐标的激动人心的特征。
{‘address’: {‘building’: ‘Eagle Insurance Buildings’,
‘city’: ‘Manchester’,
‘country’: ‘United Kingdom’,
‘country_code’: ‘gb’,
‘county’: ‘Greater Manchester’,
‘house_number’: ‘68’,
‘postcode’: ‘M2 4JG’,
‘road’: ‘Cross Street’,
‘state’: ‘England’,
‘state_district’: ‘North West England’,
‘suburb’: ‘City Centre’},
‘boundingbox’: [‘53.480856’, ‘53.4810634’, ‘-2.2451761’, ‘-2.2449576’],
‘display_name’: ‘Eagle Insurance Buildings, 68, Cross Street, City Centre, Manchester, Greater Manchester, North West England, England, M2 4JG, United Kingdom’,
‘lat’: ‘53.4809597’,
‘licence’: ‘Data © OpenStreetMap contributors, ODbL 1.0\. [https://osm.org/copyright](https://osm.org/copyright)',
‘lon’: ‘-2.24506682746292’,
‘osm_id’: 37139875,
‘osm_type’: ‘way’,
‘place_id’: 86197794}
在这里,您有一个建筑物,邮政编码,地址,国家,道路名称和一堆其他深刻的属性,不可用的原始坐标。如果你只对打印地址感兴趣,你可以使用字典键,或者你可以直接这样做。
print(location.address)
它将打印出输出的地址部分。在下一节中,我们将了解如何在 Pandas 数据帧中使用反向地理编码。
使用熊猫数据框架进行反向地理编码
我们通常希望从纬度和经度(反向地理编码)而不是单个坐标获得地址的子集或完整数据集。在这一部分,我们将探索如何通过熊猫和地质公园做到这一点。
首先,我们从熊猫的 URL 中读取数据。数据存储在 Dropbox 中,如果我们有一个链接,我们可以很容易地使用熊猫。你只需要确保 URL 的最后几个字符设置为“dl=1”。
url = “https://www.dropbox.com/s/15gisj8hx218rn1/street-pole-sample.csv?dl=1"df = pd.read_csv(url)df.head()
数据具有 X 和 Y 列,其中的坐标与其他要素一起存储,如下表所示。
Street Poles in Philadelphia Data
我们还可以使用 Plotly Express 浏览数据并在地图中显示。只需一行代码,您就可以显示带有底图的地图。
import plotly_express as pxpx.scatter_mapbox(df, lat=”Y”, lon=”X”, zoom=15)
Philly Street Poles Map
地图显示了 Phillidelphia 街道杆的子集。现在,我们需要从 X 和 Y 列构造坐标列。我们只需将这两列(X & Y)映射为字符串,然后用逗号将它们连接起来,就可以实现这一点。
df[“geom”] = df[“Y”].map(str) + ‘,’ + df[‘X’].map(str)
df[“geom”][0]
下面是我们在上面创建的geom
列的第一行。
'39.9427660880249,-75.17009743393821'
我们创建一个服务提供者locator
这个时间通行证timeout
是 10 分钟,因为我们有许多行。这将防止您在此过程中可能遇到的超时错误。
locator = Nominatim(user_agent=”myGeocoder”, timeout=10)rgeocode = RateLimiter(locator.reverse, min_delay_seconds=0.001)
现在,我们可以通过应用上面创建的反向地理编码rgeocode
来进行反向地理编码。为了得到一个漂亮的进度条,我们使用了 tqdm 库。
tqdm.pandas()df[‘address’] = df[‘geom’].progress_apply(rgeocode)
df.head()
这可能需要一段时间,具体取决于数据集中的行数。但是一旦该过程完成,数据集中就会有一个额外的要素,其中每个点都有一个地址,如下所示。
数据现在有了与每个点相关的更有洞察力的属性,包括地址、邮政编码、建筑物等。…
仅用 150 个点进行反向地理编码,耗时 1 分 45 秒。计算时间可能不是一个好的选择,因为数据点的增加将需要大量的处理时间。如果您有一个大型数据集,您可以尝试减少延迟秒数。
结论
在本文中,我们探讨了如何将地理编码坐标转换为地址。您可以在这个 Google Colab 笔记本中访问本教程的笔记本。
编辑描述
colab.research.google.com](https://colab.research.google.com/github/shakasom/geocoding/blob/master/ReverseGeocoding.ipynb)
在 R 中反向地理编码
没有谷歌或必应 API 的免费
Photo by Lonely Planet on Unsplash
随着我继续写论文,我在执行 R 和 Python 中各种包的简单脚本时遇到了一些小故障。这个周末给自己的任务是反地理编码~ 100 万经纬度坐标。我在 R 中发现了一个名为 revgeo 的很棒的包,并认为这很容易实现。我只需要指定提供者和 API 键。谷歌和必应限制每天免费查询的数量,所以这不是一个可行的选择,但光子没有!唯一需要注意的是,像地址名称这样的详细位置并不总是可用的。以下是如何使用 revgeo 软件包的示例:
library(revgeo)revgeo(longitude=-77.0229529, latitude=38.89283435, provider = 'photon', output=’frame’)
那么问题出在哪里呢?嗯,正如光子网页上所说:
您可以在您的项目中使用 API,但是请注意公平——大量使用将会受到限制。我们不保证可用性和使用可能会在未来发生变化。
我不确定在 Photon API 变慢之前需要多少次查询,但重要的是要注意我们向他们的服务器发送了多少请求。我决定从 500,000 坐标开始逆向地理编码,但这并不奏效。我运行了代码,离开了一段时间,当我回来时,我看到节流已经开始,所以我需要调整代码。此外,R 抛出了一个错误cannot allocate vector of size x.x Gb
,这意味着我的可用内存已经耗尽。
在这一点上,我有两个问题:1)节流和 2)内存分配。对于第 1 期,我需要在代码中加入睡眠时间,并处理已经子集化的数据帧的较小子集。对于第 2 期,我在 stackoverflow 上找到了一个有用的建议:
[## 内存分配“错误:无法分配大小为 75.1 Mb 的向量”
在对一些模拟代码进行矢量化的过程中,我遇到了内存问题。我使用的是 32 位 R 版本 2.15.0(通过…
stackoverflow.com](https://stackoverflow.com/questions/10917532/memory-allocation-error-cannot-allocate-vector-of-size-75-1-mb)
帮助我的一个解决方案是运行memory.limit(size = _ _ _ _ _ _)
。此外,我使用rm()
命令删除代码中不再需要的数据帧,并使用gc()
命令进行垃圾收集。如下所示,我加载了名为main
的大约一百万坐标的数据帧。我将数据细分为只有 100,000 行。正如您稍后将看到的,我在 while 循环中进一步对数据进行了子集化,以避免内存分配问题。
library(revgeo)# the dataframe called 'main' is where the 1 million coordinate points reside.main <- readRDS("main.rds"))main_sub <- main[0:100000,] # Working with a smaller initial subsetrm(main)
gc()
下面是完整的代码。该脚本包含了与本文主题无关的其他操作,但我想在这里发布它,以便您可以看到全貌,并希望在反向地理编码中获得一些有用的提示。
# Step 1: Create a blank dataframe to store results.
data_all = data.frame()start <- Sys.time()# Step 2: Create a while loop to have the function running until the # dataframe with 100,000 rows is empty.
while (nrow(main_sub)>0) {# Step 3: Subset the data even further so that you are sending only # a small portion of requests to the Photon server. main_sub_t <- main_sub[1:200,]# Step 4: Extracting the lat/longs from the subsetted data from
# the previous step (Step 3). latlong <- main_sub_t %>%
select(latitude, longitude) %>%
unique() %>%
mutate(index=row_number()) # Step 5: Incorporate the revgeo package here. I left_joined the
# output with the latlong dataframe from the previous step to add
# the latitude/longitude information with the reverse geocoded data.cities <- revgeo(latlong$longitude, latlong$latitude, provider = 'photon', output = 'frame')) %>%
mutate(index = row_number(),country = as.character(country)) %>%
filter(country == 'United States of America') %>%
mutate(location = paste(city, state, sep = ", ")) %>%
select(index, location) %>%
left_join(latlong, by="index") %>%
select(-index) # Removing the latlong dataframe because I no longer need it. This
# helps with reducing memory in my global environment.
rm(latlong) # Step 6: Adding the information from the cities dataframe to
# main_sub_t dataframe (from Step 3).
data_new <- main_sub_t %>%
left_join(cities, by=c("latitude","longitude")) %>%
select(X, text, location, latitude, longitude) # Step 7: Adding data_new into the empty data_all dataframe where
# all subsetted reverse geocoded data will be combined.
data_all <- rbind(data_all,data_new) %>%
na.omit()
# Step 8: Remove the rows that were used in the first loop from the # main_sub frame so the next 200 rows can be read into the while # loop.
main_sub <- anti_join(main_sub, main_sub_t, by=c("X"))
print(nrow(main_sub))
# Remove dataframes that are not needed before the while loop closes # to free up space.
rm(data_sub_t)
rm(data_new)
rm(latlong_1)
rm(cities)
print('Sleeping for 10 seconds')
Sys.sleep(10)
}
end <- Sys.time()
实现这个代码后,大概花了 4 个小时反推地理编码 10 万坐标。在我看来,如果我有一百万个坐标要转换,这不是一个可行的选择。我可能不得不寻找另一种方法来实现我的目标,但我认为这对那些数据集较小的人会有所帮助。
感谢阅读和快乐编码!
使用自动编码器的反向图像搜索
你有没有想过谷歌反向图片搜索是如何工作的?他们如何快速扫描所有图像并返回合适的结果?在这篇博客中,我们将制作自己的轻量级反向搜索引擎。为此,我们将使用自动编码器。
什么是自动编码器?
自动编码器是一种特殊类型的前馈神经网络,其输入与输出相同。它们以无人监督的方式接受训练,以学习输入的低级特征。这些低级特征通常被称为潜在特征。然后,这些潜在特征被用于重构原始输入。
自动编码器由 3 个主要组件组成
- 编码器:用于压缩输入图像
- 潜在表征:保留大部分信息的输入的低层次特征
- 解码器:用于从潜在特征中重建原始输入。
在这种情况下,输入是一个图像。下图清楚地解释了自动编码器的工作原理。
我们将在这个博客中讨论什么?
- 我们将使用时尚 MNIST 数据集并对其进行预处理
- 训练自动编码器学习所有图像的潜在表示
- 使用骚扰索引潜在特征
- 查找给定图像的相似图像
让我们开始吧。
时尚 MNIST 数据集
在加载和处理数据之前,了解数据集、类的数量和数据集中的样本数量是一个很好的做法。
时尚 MNIST 数据库由时尚产品的 28*28 灰度图像的 60000 个训练样本和 10000 个测试样本组成。每个类别有 6000 个训练样本和 1000 个测试样本。你可以在这里阅读更多关于数据集的信息。
导入库
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow import keras
from annoy import AnnoyIndex
import os
下载数据
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
预处理和探索性数据分析
像素值介于 0 和 255 之间。我们将在 0 和 1 之间缩放像素值。
*# resize the pixel values between 0 and 255*
train_images = train_images/255
test_images = test_images/255
让我们将分类标签映射到适当的产品类别。
*# different product categories in the dataset*
labeldict = {
0: 'T-shirt/top',
1: 'Trouser',
2: 'Pullover',
3: 'Dress',
4: 'Coat',
5: 'Sandal',
6: 'Shirt',
7: 'Sneaker',
8: 'Bag',
9: 'Ankle boot'
}*# no of times each product category is present in the dataset*
category_counts = dict(zip(*np.unique(train_labels, return_counts=True)))
让我们展示一些样本图像。
plt.figure(figsize=(12,8))
for index in range(16):
rand_idx = np.random.randint(0,train_labels.shape[0])
plt.subplot(4,4,index+1)
plt.xticks([])
plt.yticks([])
plt.grid('off')
plt.imshow(train_images[rand_idx], cmap='Greys_r')
plt.xlabel(labeldict[train_labels[rand_idx]])
助手功能
让我们定义一个效用函数来绘制原始图像和重建图像。
def plot_images(original, reconstructed):
fig, axes = plt.subplots(nrows=2, ncols=10, sharex=True, sharey=True, figsize=(12,4))
for images, axes in zip([original, reconstructed], axes):
for image, ax in zip(images, axes):
ax.imshow(image.reshape(28,28), cmap="Greys_r")
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
fig.tight_layout(pad=0.1)
占位符
让我们为输入和目标定义占位符。在这种情况下,输入和目标是相等的。我们还将为批量大小定义一个占位符。
def placeholders(image_size, n_channels ):
inputs = tf.placeholder(dtype=tf.float32, shape=[None, image_size, image_size,n_channels], name='inputs') targets = tf.placeholder(dtype=tf.float32, shape=[None, image_size, image_size, n_channels], name='targets') batch_size = tf.placeholder(dtype=tf.int32, name='batch_size') return inputs, targets, batch_size
编码器和解码器网络
我们将使用卷积神经网络来训练我们的模型。编码器网络将 2828 图像转换成 448 的低级表示。解码器使用这种低级表示来重建 2828 的图像。网络参数取自这里的。
def encoder_decoder_network(X):
*#ENCODER NETOWRK*
*# X's shape - 28*28*1*
W1 = tf.get_variable("W1", shape=[3,3,1,16], initializer=tf.contrib.layers.xavier_initializer(seed=0))
*# 28*28*16*
conv1 = tf.nn.conv2d(X, W1, strides=[1,1,1,1], padding='SAME')
relu1 = tf.nn.relu(conv1)
*#14*14*16*
pool1 = tf.nn.max_pool(relu1, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
*#14*14*8*
W2 = tf.get_variable("W2", shape=[3,3,16,8], initializer=tf.contrib.layers.xavier_initializer(seed=0))
conv2 = tf.nn.conv2d(pool1, W2, strides=[1,1,1,1], padding='SAME')
relu2 = tf.nn.relu(conv2)
*#7*7*8*
pool2 = tf.nn.max_pool(relu2, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
*#7*7*8*
W3 = tf.get_variable("W3", shape=[3,3,8,8], initializer=tf.contrib.layers.xavier_initializer(seed=0))
conv3 = tf.nn.conv2d(pool2, W3, strides=[1,1,1,1], padding='SAME')
relu3 = tf.nn.relu(conv3)
*#4*4*8*
pool3 = tf.nn.max_pool(relu3, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME', name='encodings')
encoded = pool3
*# the image is now 4*4*8*
*# DECODER NETWORK*
upsample1 = tf.image.resize_nearest_neighbor(encoded, (7,7))
*#7*7*8*
W4 = tf.get_variable("W4", shape=[3,3,8,8], initializer=tf.contrib.layers.xavier_initializer(seed=0))
conv4 = tf.nn.conv2d(upsample1, W4, strides=[1,1,1,1], padding='SAME')
relu4 = tf.nn.relu(conv4)
upsample2 = tf.image.resize_nearest_neighbor(relu4, (14,14))
*# 14*14*8*
W5 = tf.get_variable("W5", shape=[3,3,8,8], initializer=tf.contrib.layers.xavier_initializer(seed=0))
conv5 = tf.nn.conv2d(upsample2, W5, strides=[1,1,1,1], padding='SAME')
relu5 = tf.nn.relu(conv5)
*# 28*28*8*
upsample3 = tf.image.resize_nearest_neighbor(relu5, (28,28))
W6 = tf.get_variable("W6", shape=[3,3,8,16], initializer=tf.contrib.layers.xavier_initializer(seed=0))
conv6 = tf.nn.conv2d(upsample3, W6, strides=[1,1,1,1], padding='SAME')
relu6 = tf.nn.relu(conv6)
W7 = tf.get_variable("W7", shape=[3,3,16,1], initializer=tf.contrib.layers.xavier_initializer(seed=0))
conv7 = tf.nn.conv2d(relu6, W7, strides=[1,1,1,1], padding='SAME')
logits = conv7
decoded = tf.nn.sigmoid(logits, name='decoded')
return encoded, decoded, logits
定义培训操作
然后,我们计算原始图像和重建图像之间的误差。由于目标是最小化误差,我们将使用 Adam 优化算法来学习误差最小的网络参数。
def train_operations(logits, targets, learning_rate): *# define the loss*
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=targets)) *# use adam optimizer for faster convergence*
training_op = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)
return loss, training_op
训练模型
接下来,我们将定义一个用于训练模型的函数。代替使用 feed_dict,我们将使用推荐的方式,使用数据集和迭代器向模型提供数据。如果你不知道数据集和迭代器,你可以参考这个博客。
一旦训练结束,我们还会保存模型,以便以后恢复。
def train_model(epochs, image_size, n_channels, batch_size, learning_rate, model_save_path):
*# reset the graphs*
tf.reset_default_graph()
*# get the placeholders*
inputs, targets, batch_op = placeholders(image_size, n_channels)
*# create a Dataset from the input data*
dataset = tf.data.Dataset.from_tensor_slices((inputs,targets))
*# create batches of data*
dataset = dataset.batch(batch_size)
*# define an iterator to consume the data*
iterator = tf.data.Iterator.from_structure(dataset.output_types,dataset.output_shapes)
train_initializer = iterator.make_initializer(dataset, name='init_iterator')
*# get the batch of data using get_next*
input_batch, target_batch = iterator.get_next()
encoded, decoded, logits = encoder_decoder_network(input_batch)
loss, training_op = train_operations(logits, target_batch, learning_rate)
saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for epoch in range(epochs):
epoch_loss = 0
*# run the initializer*
sess.run(train_initializer, feed_dict = {
inputs: train_images.reshape(-1, image_size, image_size, n_channels),
targets : train_images.reshape(-1, image_size, image_size, n_channels),
batch_op: batch_size
})
try:
while True:
batch_loss, _ = sess.run([loss, training_op])
epoch_loss += batch_loss
except tf.errors.OutOfRangeError:
pass
print("Epoch {}/{}: Loss is {:.3f}".format(epoch+1, epochs, epoch_loss))
print("Training over\n")
*# save the model*
saver.save(sess,model_save_path)
print("Model saved at {}".format(model_save_path))
模型参数
我们将以 400 个为一批,总共 20 个时期来训练模型。
epochs = 20
batch_size = 400
image_size = 28
n_channels = 1
learning_rate = 0.001
运行模型
在运行模型之前,我们将创建一个检查点目录来保存我们的模型。
if not os.path.exists('checkpoints'):
os.mkdir('checkpoints')
*# checpoint directory*
chkpt_dir = os.path.join(os.getcwd(), 'checkpoints')
*# path to save the model*
model_save_path = os.path.join(chkpt_dir, 'fashion-mnist.chkpt')
train_model(epochs=epochs,
batch_size=batch_size,
image_size=image_size,
n_channels= n_channels,
learning_rate = learning_rate,
model_save_path = model_save_path)
失败
Epoch 1/20: Loss is 64.375
Epoch 2/20: Loss is 48.220
Epoch 3/20: Loss is 46.779
Epoch 4/20: Loss is 46.140
Epoch 5/20: Loss is 45.726
Epoch 6/20: Loss is 45.435
Epoch 7/20: Loss is 45.215
Epoch 8/20: Loss is 45.031
Epoch 9/20: Loss is 44.868
Epoch 10/20: Loss is 44.724
Epoch 11/20: Loss is 44.593
Epoch 12/20: Loss is 44.470
Epoch 13/20: Loss is 44.357
Epoch 14/20: Loss is 44.251
Epoch 15/20: Loss is 44.152
Epoch 16/20: Loss is 44.060
Epoch 17/20: Loss is 43.975
Epoch 18/20: Loss is 43.894
Epoch 19/20: Loss is 43.820
Epoch 20/20: Loss is 43.750
可视化重建的图像
让我们定义一个函数,它接受保存模型的文件的路径和需要重建的图像列表。
def test_network(model_path, images):
with tf.Session() as sess:
saver = tf.train.Saver()
saver.restore(sess, model_path)
default_graph = tf.get_default_graph()
inputs = default_graph.get_tensor_by_name('inputs:0')
targets = default_graph.get_tensor_by_name('targets:0')
test_iterator_init = default_graph.get_operation_by_name('init_iterator')
decoded = default_graph.get_tensor_by_name('decoded:0')
reconstructed =[]
sess.run(test_iterator_init, feed_dict={
inputs:images,
targets:images
})
try:
while True:
reconstructed.append(sess.run(decoded))
except tf.errors.OutOfRangeError:
pass
return reconstructed
我们恢复了训练时定义的各种张量和运算。输入和目标张量用于将图像输入网络。运行解码后的张量以恢复重建图像。
让我们将测试数据集中的一些图像传递给模型,并可视化它们的重建图像。
test_sample_images = test_images[:10]
test_sample_images = test_sample_images.reshape(-1, image_size, image_size, n_channels)
reconstructed_images = test_network(model_save_path, test_sample_images)
reconstructed_images = np.array(reconstructed_images).reshape(10,28,28,1)
plot_images(test_sample_images, reconstructed_images)
这个模型在重建图像方面做得相当不错。
潜在特征
既然我们对训练模型感到满意,让我们计算所有训练样本的潜在表示。为此,我们将定义一个函数,它接受保存模型的文件的路径,一个我们想要获得潜在表示的图像列表和编码图像的大小。
def get_encodings(model_path, images, encoding_vector_length):
with tf.Session() as sess:
saver = tf.train.Saver()
saver.restore(sess, model_path)
default_graph = tf.get_default_graph()
inputs = default_graph.get_tensor_by_name('inputs:0')
targets = default_graph.get_tensor_by_name('targets:0')
iterator_init = default_graph.get_operation_by_name('init_iterator')
encoded = default_graph.get_tensor_by_name('encodings:0')
encoding_vectors =[]
sess.run(iterator_init, feed_dict={
inputs:images,
targets:images
})
try:
while True:
encoding_vectors.append(sess.run(encoded))
except tf.errors.OutOfRangeError:
pass
return np.array(encoding_vectors).reshape(-1, encoding_vector_length)
烦恼
近似最近邻(aroy)是一个库,用于搜索空间中更靠近给定查询点的点。我们将使用 Annoy 来保存所有训练样本的所有潜在表示。
接下来,给定一个查询图像,我们将计算给定图像的潜在表示,并将其与所有编码表示进行比较,以找到相似的图像。如果你想了解更多关于 Annoy 是如何工作的,请参考这篇精彩的博文。
让我们来定义构建烦恼指数所需的参数。
- 编码向量长度:图像的编码表示的大小
- 骚扰文件名称:骚扰索引将被保存的文件的名称
- num_trees:构建 n 个树的森林。树的数量越多,精度越高。
# our encoded image is of the shape 4*4*8, hence it's represted by a # vector of length 128
encoding_vector_length = 128
annoy_file_name = 'fashion-mnist.annoy.index'
num_trees = 10
创建骚扰指数
def build_annoy_index(encoding_dim, num_trees, annoy_index_file, encodings):
ann = AnnoyIndex(encoding_dim)
for index, encoding in enumerate(encodings):
ann.add_item(index, encoding) # builds a forest of num_trees, higher the number of trees, higher the precision
ann.build(num_trees)
#save the index to a file
ann.save(annoy_index_file)
print("Created Annoy Index Successfully") # resize the training images
train_images = train_images.reshape(train_images.shape[0], image_size, image_size, n_channels)# get the encoded representations of all the training samples
encodings = get_encodings(model_save_path, train_images, encoding_vector_length)# create the annoy index
build_annoy_index(encoding_vector_length, num_trees, annoy_file_name, encodings)
让我们定义一个函数来获取给定查询图像的相似图像。要搜索的相似图像的数量由参数n _ 相似表示
def get_similar_images(image, n_similar=10): # get the encoded representation of the image
encoding = get_encodings(model_save_path,image.reshape(-1, image_size, image_size,n_channels), encoding_vector_length) # Load the annoy index
saved_ann = AnnoyIndex(encoding_vector_length)
saved_ann.load(annoy_file_name) # get the nearest images
#get_nns_by_vector returns the indices of the most similar images
nn_indices = saved_ann.get_nns_by_vector(encoding[0], n_similar) print("Similar images are")
for i, index in enumerate(nn_indices,1):
image = train_images[index].reshape(28,28)
plt.subplot(2,5,i)
plt.xticks([])
plt.yticks([])
plt.imshow(image, cmap='Greys_r')
查询图像
sample_image = test_images[0]
print("Sample Image")
plt.imshow(sample_image, cmap='Greys_r')
相似的图像
get_similar_images(sample_image)
所有返回的图像都与查询图像属于同一类。
感谢阅读博客。完整的代码可以在这个 Jupyter 笔记本里找到。
如果你有任何问题或者你有任何改进这篇文章的建议,请在下面留下你的评论。
参考资料:
- https://github . com/uda city/deep-learning/tree/master/auto encoder
- https://github.com/zalandoresearch/fashion-mnist
- https://pypi.org/project/annoy/
- https://Erik Bern . com/2015/10/01/nearest-neighbors-and-vector-models-part-2-how-to-search-in-high-dimensional-spaces . html
反向指导共享——开源
Source: genesis_3g on Pixabay
最近,我参加了反向辅导计划,辅导我们的高管,他们在各自领域知识方面经验丰富,但对新技术趋势的理解有限。我们关注他们最感兴趣的四个领域:开源、人工智能、编码&原型和数字趋势。作为导师,我和学员们觉得我们从彼此身上学到了很多东西,值得与更多人分享,这就是我写这个系列的原因。
在这个系列中,每个主题有四篇文章:
在每个主题中,我会首先介绍什么是,以帮助学员对主题有基本的了解。一旦他们知道了这个话题,我会解释为什么这个话题对现在的人很重要。作为高管,他们更关心我们的公司如何从技术中获益,这将包括在第三部分中。
在每篇文章中,我将分享我的 PowerPoint 和我在每张幻灯片上提到的内容。此外,在我与高管们分享了他们的反馈后,我将总结我对每个主题的感受。一旦你理解了这个话题,你就可以去看最后一部分来了解主管们和我的意见。我将排除我们业务中任何敏感的东西,希望每个人,不管你是否熟悉这些话题,都能够从这些文章中学到一些东西。如果你有任何新的想法,请留下你的评论和我们讨论。我真的很感谢大家的回复,这是和人们一起学习的最好的事情。
指令中有三个部分:什么是开源?为什么开源很重要?我们的公司如何从开源中获益?在第一部分,它将从没有开源思想的世界开始,因此人们可以理解开源的重要性。之后,我将给出开源的定义和一些著名的开源项目。在第二部分,我将通过展示开源社区的人们是如何充满活力和积极的来证明我们为什么需要关心开源。最后,我将指出一个公司如何从开源中获益。
在开源之前,我们倾向于使用知识产权来保护提出新想法的人。我们相信,通过保护发明者的财产权并给予他们额外的奖励,我们可以激励更多的创造,这对我们的社会是有益的。
然而,知识产权制度也有一些不利之处。首先,用户将不再完全了解产品,因为开发者和公司需要隐藏他们的配方,并继续赚取超额回报。此外,用户作为对产品有真实体验并知道应该改进什么的人,因为他们没有权利而什么也做不了。最终,这个世界没有变得创新和合作,而是以自我为中心,充满了无尽的诉讼。
为了让人们能够一起工作,而不是互相争斗,开源的想法变得流行起来。它允许他人自由访问和分发最终产品,包括但不限于软件或程序。这样做,我们从智力上解决了逆境。值得一提的是,开源实际上正在很多领域发生。例如,开源可乐是一个公开的、可共享的软饮料配方。
不是任何项目都可以自己定义为开源的。从开源倡议开始,有 10 条开源项目需要遵循的原则。关于第五项原则,“不得歧视个人或群体”,这表明只能用于非商业目的的免费产品不能被定义为开放源码。它使得开源软件与传统的“自由软件”非常不同,更适合商业。此外,开源不仅是一个想法,而且是合法的许可。最流行的三种开源许可是:MIT 许可、GPLv2 许可和 Apache 许可。
开源与技术的成功密切相关,我们可以在身边看到它。从 Linux 和 Android 等操作系统、网络浏览器 Firefox、分析工具 Python 和 R、Hadoop 等数据库到隐藏在 TensorFlow 和 OpenCV 等许多应用程序背后的算法,我们真的无法想象没有它们的生活。
正如我们提到的,开源对于我们当前的技术是至关重要的,在这一部分我们将讨论为什么它会如此强大。一个成功的产品意味着它拥有大量的用户和提供商,所以我们可以从用户的角度来理解为什么公司和人们想要使用开源。
第一个也是最明显的原因,开源是成本优势。然而,另一个原因是,开源可以避免公司遇到令人烦恼的麻烦,如诉讼和兼容问题。有了大而活跃的社区,开源通常可以应用最新的技术,并且有来自许多网站和用户社区的易于阅读的说明和例子。如果你仍然面临一个非常定制化的问题,实际上有很多有经验的顾问为你提供有偿支持。因此,对于公司来说,使用开源软件是一个便宜而简单的解决方案。
很容易理解为什么公司要使用开源软件,但是很难解释为什么他们要提供开源软件。事实上,公司都愿意向公众开放他们的项目,谷歌托管 2000+项目就是一个例子。背后的原因是,开放他们的源代码也有利于公司。比如对他们来说是最好的广告,不仅是对他们的产品,也是对人才。此外,开源可以吸引合适的人加入他们的公司,花更少的时间来培训他们要做什么。
开源的另一个重要参与者是志愿者开发者。促使公司使用并向公众开放代码的是开源社区背后的人才群体。程序员和开发人员花费数小时为开源做贡献的原因有很多,我只给出五点作为实例。有了这些激励,我们可以相信会有越来越多的人继续热情地为开源做出贡献。
在我看来,开源不仅仅是法律文件,而是共享的文化。作为一家非科技公司,我们能从开源,或者说科技世界的快速成长中学到的,是**来自开放与合作的影响。**我们倾向于把学到的一切都当成秘密,不让别人知道。然而,为了有效地与他人合作,我们不应该害怕与他人分享我们的知识。我们需要相信开放的力量,让开放成为常态,让封闭成为例外。对于一个大公司来说,不是一定要对公众开放,而是对其他部门开放。如果你同意我们希望像科技公司一样快速发展,我们需要拥抱开放的心态。
反馈
作为一名技术布道者,我是开源的忠实粉丝。从我的角度来看,没有开源,我们就看不到新技术带来的便利,大数据和人工智能的想法也将不再可能。我们的进度会很慢,效率会很低,而且我无法以可承受的成本创造出任何有趣的东西(我是 Python 和 r 的忠实用户)。此外,我已经习惯了 GitHub 上每天都有成千上万的请求和问题发生的现象。我乐观地认为,一切都可以通过开放来解决。
H 然而,对于高管们来说,尽管他们对开源的想法印象深刻,但他们看到了比光明更大的挑战。他们指出,例如,特斯拉钥匙的缺陷可能与其开源文化有关。此外,作为一家拥有可靠品牌声誉的成熟企业,我们的客户不会像那些科技公司一样容忍错误。同时,我们需要更加谨慎地选择披露的内容,因为这可能会影响我们的合作伙伴,如供应商。这也可能包括在公司内部共享信息。
每个人都理解协作和共享的价值,这是开源背后的核心价值,与知识产权的理念相矛盾。尽管如此,作为处于不同位置的人,他们对应用开源概念会有不同的观点。或许不是每个人都能复制这些科技公司的做法,但我们应该永远记住分享的能力。我们永远无法知道你告诉别人你所知道的会产生什么影响,所以为了创造一个更好的世界,尽量不要保密。
参考
- 【维基百科】
- 【维基百科】
- 为什么开源对商业有好处【ruby garage】
- 贵公司应该开源更多代码的 5 个理由【Matt Asay】
- 【维基百科】
- 【维基百科】
- 为什么人们会为开源项目做贡献【Joel Lee】
综述:3D U-Net+ResNet —体积卷积+长短残差连接(生物医学图像分割)
胜过类似 V-Net 的网络
Example of prostate MR images displaying large variations (Only centre part)
在这个故事中,回顾了一篇论文“使用混合残差连接的体积转换,用于从 3D MR 图像中自动分割前列腺”。这是一个使用3D U-Net+ResNet概念的网络。对于 3D 磁共振(MR)图像,从 3D MR 图像中手动分割耗时且主观,可重复性有限。它严重依赖于经验,并且在观察者之间和观察者内部有很大的差异。另一方面,自动分段非常具有挑战性:
- 首先,由于不同的 MR 扫描协议,不同的 MR 图像具有全局的扫描间可变性和扫描内强度变化,例如有/没有直肠内线圈。
- 第二,缺乏清晰的前列腺边界由于前列腺和周围组织的外观相似。
- 第三,由于病变或图像分辨率不同,前列腺在不同受试者之间的大小和形状差异很大。
在这项工作中,混合使用长短剩余连接,提出了具有体积卷积的类 U-Net 网络。这是由 CUMED 团队在香港中文大学(CUHK) 的 MICCAI 前列腺 MR 图像分割(PROMISE12)挑战数据集上所做的工作。这是一篇 2017 AAAI 论文,引用次数超过 90 次。( Sik-Ho Tsang @中)
概述
- 网络架构
- 混合短长剩余连接
- 消融研究
- 与最先进方法的比较
1。网络架构和混合长短残留连接
(a) Network Structure, (b) ResBlock
1.1.基本体积转换网络
- 2D 完全转换网络(FCN)扩展为体积转换网络以实现体积到体积的预测。
- 从下采样路径中,我们只能获得粗略的预测,这对于一些检测和分类任务来说是足够的,但是不适用于基于体素的语义分割。
- 在 ResBlocks 之间应用三个 2×2×2 最大池层,跨距为 2 。
- 由去卷积和卷积层组成的上采样路径被实现为生成具有更高分辨率的密集预测。
- 通过 3D 方式的卷积、反卷积和汇集工作,网络可以在提取要素和进行预测时完全保留和利用 3D 空间信息。
1.2.深度监督机制
- 利用网络中的深度监督机制来加快收敛速度。
- 在网络末端增加一个卷积层(核大小 1×1×1),生成主预测。
- 此外,采用几个卷积层(核大小 1×1×1),然后在上采样路径中使用隐藏特征映射来获得辅助粗略预测,然后使用解卷积层来获得具有相同输入大小的辅助密集预测。
- 当训练体积 ConvNet 时,主预测和辅助预测的交叉熵损失的加权和被最小化。
- 原则上,深度监督机制可以在训练期间起到强有力的“规则化的作用,因此对于用有限的训练数据训练 ConvNet 是重要的。
2。混合短长剩余连接
- 长和短剩余连接的使用就像 U-Net+ResNet 一样。
2.1.短剩余连接
- 第一种残差连接用于构建局部残差块(ResBlocks) ,如图的(b)部分所示。
- 在 ResBlock 中,它由两个卷积层和两个校正线性单元(ReLUs)组成。
2.2.长剩余连接
- 长残差连接:第二种残差连接用于连接下采样和上采样路径中具有相同分辨率的残差块,如图(a)部分所示。
- 这些剩余连接可以在 ConvNet 中显式传播两种重要信息。
- 首先,它们可以将空间位置信息向前传播到上采样路径,以便恢复由下采样操作引起的空间信息丢失,从而进行更精确的分割。
- 第二,使用求和操作来构建剩余连接,该架构可以更平滑地将梯度流向后传播,从而提高训练效率和网络性能。
- 因此,这些连接可以在端到端训练过程期间有效地向前和向后传播上下文和梯度信息。
3.消融研究
3.1.资料组
- 使用 MICCAI 前列腺 MR 图像分割(PROMISE12)挑战数据集。
- 训练 数据集包含前列腺的 50 个横向 T2 加权 MR 图像和相应的分割基础事实。
- 测试 数据集由 30 幅 MR 图像组成,地面实况由组织者拿出进行独立评估。
- 将所有 MR 体积转换为 0.625×0.625×1.5 mm 的固定分辨率,然后将其归一化为零均值和单位方差。
- 增强操作包括旋转(90 度、180 度和 270 度)和轴向翻转。
3.2.培训和测试
- 用的是 Caffe。
- 使用 NVIDIA TITAN X GPU,由于有限的 GPU 内存,在训练网络时,从每个样本中随机裁剪 64×64×16 个子体积作为输入。
- 在测试过程中,重叠滑动窗口策略用于裁剪子体积。并且这些子体积的概率图的平均值被用于获得整个体积预测。
- 子体积大小也是 64×64×16,步距是 50×50×12。一般来说,训练网络大约需要 4 小时,处理一张 320×320×60 大小的 MR 图像大约需要 12 秒。
- 消融研究采用 10 倍交叉验证。
Training and validation loss of networks with and without mixed residual connections
Cross validation performance with different configurations.
- 当然,无论是长剩余连接还是短剩余连接,Dice 系数都是最高的。
4。与最先进方法的比较
Quantitative comparison between the proposed method and other methods
- PROMISE12 挑战中使用的评估指标包括 Dice 系数(DSC)、体积之间绝对差异的百分比(aRVD)、体积边界点之间最短距离的平均值(ABD)和 95% Hausdorff 距离(95HD)。然后主办方算了一个总分,如上图。
- 在论文提交之前,共有 21 个团队提交了他们的结果,只有前 10 个团队列在表格中。
- 前十名中的七个团队采用了各种手工制作的功能。除了 team (CUMED)之外,使用 ConvNet 的另外两个小组是 SIATMIDS 和 CAMP-TUM2。
- 团队 CAMP-TUM2 有一个 V 网般的网络。
- 再次,当然是 CUMED 队,凭借使用 3D U-Net 般的网络和 U-Net+ResNet 般的长短剩余连接,以 86.65 分的成绩遥遥领先。
Qualitative segmentation results of case 4 (first row) and case 22 (second row) at the apex(left), center (middle) and base (right) of the prostate in testing dataset.
参考
【2017 AAAI】【3D U-Net+ResNet】
具有混合残差连接的体积 ConvNets,用于从 3D MR 图像中自动分割前列腺
我以前的评论
)(他)(们)(都)(不)(在)(这)(些)(事)(上)(,)(我)(们)(还)(不)(在)(这)(些)(事)(上)(有)(什)(么)(情)(况)(?)(我)(们)(都)(不)(在)(这)(些)(情)(况)(上)(,)(我)(们)(还)(没)(有)(什)(么)(情)(况)(,)(我)(们)(还)(没)(有)(什)(么)(情)(况)(,)(我)(们)(还)(没)(有)(什)(么)(情)(况)(,)(我)(们)(还)(没)(有)(什)(么)(好)(好)(的)(情)(感)(。 )(他)(们)(都)(不)(在)(这)(些)(事)(上)(,)(她)(们)(还)(不)(在)(这)(些)(事)(上)(有)(什)(么)(情)(况)(呢)(?)(她)(们)(都)(不)(在)(这)(些)(情)(况)(下)(,)(她)(们)(还)(不)(在)(这)(些)(事)(上)(有)(什)(么)(情)(况)(吗)(?)(她)(们)(们)(都)(不)(在)(这)(些)(事)(上)(,)(她)(们)(们)(还)(不)(在)(这)(些)(事)(上)(,)(她)(们)(们)(还)(不)(在)(这)(些)(事)(上)(有)(什)(么)(好)(的)(情)(情)(况)(。 PyramidNet DRN DPN 残留注意网络 MSDNet ShuffleNet V1
物体检测 过食R-CNN快 R-CNN快 R-CNNMR-CNN&S-CNNDeepID-NetCRAFTR-FCN】 [G-RMI][TDM][SSD][DSSD][约洛夫 1 ] [ 约洛夫 2 /约洛 9000 ] [ 约洛夫 3[FPN[视网膜网[DCN
语义切分 FCNde convnetdeeplabv 1&deeplabv 2CRF-RNN】SegNet】parse netdilated netDRNRefineNet
生物医学图像分割 [cumed vision 1][cumed vision 2/DCAN][U-Net][CFS-FCN][U-Net+ResNet][多通道][V-Net][3D U-Net][M FCN
实例分割 [ SDS ] [ 超列 ] [ 深度掩码 ] [ 锐度掩码 ] [ 多路径网络 ] [ MNC ] [ 实例中心 ] [ FCIS
)(我)(们)(都)(不)(知)(道)(,)(我)(们)(还)(是)(不)(知)(道)(,)(我)(们)(还)(是)(不)(知)(道)(,)(我)(们)(还)(是)(不)(知)(道)(,)(我)(们)(还)(是)(不)(知)(道)(,)(我)(们)(还)(是)(不)(知)(道)(,)(我)(们)(还)(是)(不)(知)(道)(,)(我)(们)(还)(是)(不)(知)(道)(。
【DeepPose】【汤普森 NIPS’14】【汤普森 CVPR’15】
复习:3D U-Net —体积分割(医学图像分割)
用于从稀疏分割进行密集体积分割的 3D U-Net
Volumetric Segmentation
在这个故事中, 3D U-Net 被简要回顾。这是弗赖堡大学、生物信号研究 BIOSS 中心、弗赖堡大学医院、弗赖堡大学医学中心和谷歌 DeepMind 的一项工作。发布为 2016 MICCAI ,引用 600 余次。( Sik-Ho Tsang @中)
概述
- 3D U-Net 架构
- 结果
1。3D U-Net 架构
3D U-Net Architecture
- 3D U-Net 架构与 U-Net 非常相似。
- 它由分析路径(左)和合成路径(右)组成。
- 在分析路径中,每层包含两个 3×3×3 卷积,每个卷积后跟一个 ReLU,然后是一个 2×2×2 最大池,每个维度的步长为 2。
- 在合成路径中,每一层都包括一个 2×2×2 的上卷积,每个维度上的步长为 2,然后是两个 3×3×3 的卷积,每个卷积之后是一个 ReLU。
- 分析路径中相同分辨率层的快捷连接为合成路径提供了基本的高分辨率特征。
- 在最后一层,1×1×1 卷积将输出通道的数量减少到标签的数量 3。
- 每次 ReLU 前的批处理规范化(\BN”)。
- 总共 19069955 个参数。
2.结果
2.1.一些细节
- 不同的结构被赋予标签 0:“小管内”,1:“小管”,2:“背景”,和 3:“未标记”。
- 使用加权交叉熵损失,其中减少频繁出现的背景的权重,增加内部小管的权重,以达到小管和背景体素对损失的平衡影响。
- 标签为 3(“未标记”)的体素对损失计算没有贡献,即权重为 0。
- 使用原始分辨率的两倍的下采样版本。
- 仅使用了 3 个爪蟾肾样品。
- 对于样本 1、2 和 3,实验中使用的数据大小在 x×y×z 维度上分别为 248×244×64、245×244×56 和 246×244×59。
2.2.两个案例
Semi-Automatic segmentation (Top) Fully-Automatic Segmentation (Bottom)
- **a)第一种情况:半自动分割:**对于稀疏标注的数据集,即 3D 结构的一些切片被标注,网络可以帮助分割其余的。
- 对于样本 1、2 和 3,正交(yz、xz、xy)切片中人工注释的切片数量分别为(7、5、21)、(6、7、12)和(4、5、10)。
- b)第二种情况 : **全自动分割:**对训练数据进行训练后,网络可以推广到新的数据集。
2.3.半自动分割
Effect of # of slices for semi-automated segmentation (IoU)
- 从在每个正交方向上使用 1 个带注释的切片开始,逐渐增加带注释的切片的数量。
- 注释的切片越多,IoU 越高。
Cross validation results for semi-automated segmentation (IoU)
2.4.全自动分段
Cross validation results for fully-automated segmentation (IoU)
- 训练两个肾体积,分割第三个。
- BN 除了第三个设置外,改善结果。
- 作者认为,数据集的巨大差异是造成这种影响的原因。解决方案是有更大的样本量。
参考
【2016 MICCAI】【3D U-Net】
3D U-Net:从稀疏标注学习密集体积分割
我以前的评论
)(我)(们)(都)(不)(想)(到)(这)(些)(人)(,)(我)(们)(都)(不)(想)(要)(到)(这)(些)(人)(,)(但)(是)(这)(些)(人)(还)(不)(想)(到)(这)(些)(人)(,)(我)(们)(还)(没)(想)(到)(这)(些)(事)(,)(我)(们)(就)(想)(到)(了)(这)(些)(人)(们)(,)(我)(们)(们)(都)(不)(想)(要)(到)(这)(些)(人)(,)(但)(我)(们)(还)(没)(想)(到)(这)(些)(事)(,)(我)(们)(还)(没)(想)(想)(到)(这)(些)(事)(,)(我)(们)(还)(没)(想)(到)(这)(里)(去)(。 )(他)(们)(都)(不)(在)(这)(些)(事)(上)(,)(她)(们)(还)(不)(在)(这)(些)(事)(上)(有)(什)(么)(情)(况)(呢)(?)(她)(们)(都)(不)(在)(这)(些)(情)(况)(下)(,)(她)(们)(还)(不)(在)(这)(些)(事)(上)(有)(什)(么)(情)(况)(吗)(?)(她)(们)(们)(都)(不)(在)(这)(些)(事)(上)(,)(她)(们)(们)(还)(不)(在)(这)(些)(事)(上)(,)(她)(们)(们)(还)(没)(有)(什)(么)(好)(的)(情)(情)(感)(。
物体检测 过食R-CNN快 R-CNN快 R-CNNMR-CNN&S-CNNDeepID-NetCRAFTR-FCN】 [ DSSD ] [ 约洛夫 1 ] [ 约洛夫 2 /约洛 9000 ] [ 约洛夫 3 ] [ FPN ] [ 视网膜网 ] [ DCN ]
语义切分 FCNde convnetdeeplab v1&deeplab v2CRF-RNN】SegNet】parse netdilated netPSPNetdeeplab v3]
生物医学图像分割 [cumed vision 1][cumed vision 2/DCAN][U-Net][CFS-FCN][U-Net+ResNet][多通道[V-Net]
实例分割 [SDS[超列 ] [ 深度掩码 ] [ 锐度掩码 ] [ 多路径网络][MNC][Instance fcn][FCIS
超分辨率 [Sr CNN][fsr CNN][VDSR][ESPCN][红网][DRCN][DRRN][LapSRN&MS-LapSRN][srdensenenet
人体姿态估计
深度姿态汤普逊·尼普斯 14
回顾:吴恩达的机器学习课程
吴恩达教授的机器学习课程于 2011 年发布。出版 8 年后,吴恩达的课程仍然被列为顶级机器学习课程之一。这已经成为 Coursera 的一门主食,说实话,也是机器学习的一门主食。
截至本文发表时,已经有 2,632,122 名用户注册了该课程。那是刚刚入学,但不知道他们是否已经完成。据估计,开始学习的用户中有 1% — 15%完成了课程。因此,低端有 26,321 人,高端有 394,818 名注册用户全程观看了课程。
我于 2019 年 11 月 11 日完成课程,这将是对这门课程的诚实回顾。在开始之前,我已经搜索了一些常见问题以及我自己的问题。因此,让我们深入到我对吴恩达的机器学习课程的诚实评论中。
但是首先……
什么是 MOOCs?
大规模提供在线课程,简称 MOOCs,是在预算内获得自学教育的一个很好的方式。这些类型的课程自 2008 年第一门课程“连接主义和连接知识/2008”发布以来就一直存在。这是由加拿大曼尼托巴大学的教授斯蒂芬·道恩斯和乔治·西门子发明的。
这些课程的好处在于它们通常是免费的。然而,订阅托管平台或为完成证书付费已经变得很普遍。
好了,让我们进入课程提问吧!
谁是吴恩达?
Coursera headshot.
吴恩达是世界上最著名的人工智能专家之一。他是 2011 年谷歌大脑的创始人和负责人,同年他成为 Coursera 的联合创始人。他之前是百度的首席科学家。目前,他是人工智能基金的普通合伙人,也是 deeplearning.ai 和 Landing AI 的创始人。他还是斯坦福大学计算机科学的兼职教授。不用说,这家伙有相当的履历。
课程结构是怎样的?
这门为期 11 周的完全在线课程由视频和阅读讲座、测验和编程作业组成。不是所有的周都包含编程作业,但是每个周主题都有测验。
视频讲座和测验
视频讲座需要 10-15 分钟来完成,每个讲座至少包含一个测验问题,以便让学生明白他想要表达的意思。阅读课包含额外的笔记,如后期制作中发现的任何错误,所以如果你是一个听觉型学习者,请确保至少看一眼。
测验可能会很难,但他会在他的视频讲座中提供幻灯片,以及每周可以参考的阅读资源。
编码任务
编码作业是这门课程的重要组成部分。不过在我自己看来唯一的缺点就是用 Octave(免费)或者 Matlab(付费)完成。你确实得到了参加 Matlab 课程的 12 周许可证。
我很想用 Python 或 R 来完成这个课程,但是他用教和学的简单性验证了他的决定。他继续讲述了在这些语言中构建原型是多么容易,并且硅谷在进入 Python 或 r 之前大量使用它。Octave 语言很容易学习,并且有大量的文档和线程可用于计算任务。
吴恩达的机器学习课程到底涵盖了哪些内容?
吴恩达的机器学习课程可以分为 4 个不同的主题:
- 监督学习(线性回归、逻辑回归、神经网络、支持向量机)
- 无监督学习(K 均值、PCA、异常检测)
- 特殊应用/主题(推荐系统、大规模机器学习)
- 关于构建机器学习系统的建议(偏差/方差、正则化、学习算法评估、学习曲线、误差分析、上限分析)
他主要关注机器学习的理论和概念,而不是编码部分。如果你刚刚开始学习机器学习,这是一个很好的策略。
关于建立机器学习系统的建议是课程中非常重要的一部分。他将带您了解如何正确训练您的模型,以及在模型遇到问题时该如何处理。他为你提供了你在未来模型中需要的工具。
时间承诺是什么?
您预计每周将投入 5-7 个小时来完成该课程。尽管这是一个为期 11 周的课程,但你可以提前完成。2019 年 9 月 16 日开课,2019 年 11 月 11 日结束;不到两个月。前 2 周和后 2 周相当简单,可以捆绑在一起。
前提条件是什么?
接触线性代数和微积分将是有益的。吴恩达深入研究了机器学习的数学。这里有一个帮助你复习数学的列表:
他确实很快地完成了一些数学运算,所以暂停一下视频,让你的大脑思考一下他在说什么。我不得不这样做好几次。
这要花多少钱?
这门课程有免费、付费和经济资助三种选择。在免费版本中,你可以接触到一些材料,但不能接触到评分作业。然而,花 80 美元你就可以接触到整个课程,包括评分作业,并且会得到一个数字证书来炫耀。如果你愿意,可以选择将证书放在你的 LinkedIn 页面上,或者通过链接与任何人分享。
如果你有预算或者雇主愿意,一定要选择付费版本。分级作业是筛选主题和理解所涉及模型的数学运算的好方法。以及努力获得证书,并能够打印出来是一种有益的感觉。
学完这门课我能做什么?
继续你的机器学习教育。跳上 Kaggle,玩转泰坦尼克号数据集及其分类问题。一旦你掌握了这一点,就跳到其他数据集中展示你新开发的技能。很快,你就可以了解深度学习,并参加他的 deeplearning.ai 课程。
仅仅凭这个证书找工作是不可能的。明智地使用 GitHub 或任何存储库来存放您的代码,从长远来看会对您有帮助。绝对值得花时间记录你的学习成果,这样你就可以在职业生涯中以及潜在的雇主和客户面前参考它们。
我创造了 5 个学习机器学习的简单步骤来帮助你进行机器学习的自我教育。完成吴恩达课程后,您已经部分完成了几个步骤!
吴恩达的机器学习课程还有意义吗?
这个问题是我报名前突然想到的。随着机器学习发展如此之快,并接管了我们生活的每个领域,担心它不相关是有道理的。然而,这种担心可以打消了。吴恩达设计课程的方式是为了长远打算。他没有涉及任何外部图书馆,以便当他们改变课程时不会受到影响。他专注于机器学习的理论和概念,而不是编码基础。
欺骗的
与它的相关性有关的另一个问题是它在防止作弊方面的有效性。对于每个测验,您需要勾选一个方框,确认您回答的所有问题都来自您自己,而不是其他人。然而,由于它的流行,一些存储库包含测验的答案和完成的编码作业。如果你被发现作弊,你的 Coursera 账户将被停用,证书作废。
当你选择这门课程时,不要欺骗!如果你对机器学习很认真,那就接受挑战吧。他们确实有一个社区论坛,你可以访问并检查以前提出的问题及其答案。如果你的问题之前没人问过,可以发帖,会有人帮你的。
最后的想法
这个课程是一次很棒的经历,我非常喜欢这个主题。它的结构方式温和地帮助你度过每一周,这是令人惊讶的。我感到失望的是,它不是用一种通用的机器学习语言完成的,但你从中获得的东西超过了你想要的。对于刚刚开始机器学习之旅的人,我强烈推荐这个课程的付费版本。如果你有多年的经验,你可能会觉得课程有点无聊,所以如果你属于这一类,就去找免费版本。
非常感谢您阅读这篇评论。我祝你一路顺风。
在我们重新学习之前,