TowardsDataScience-博客中文翻译-2019-三十七-

TowardsDataScience 博客中文翻译 2019(三十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

使用 BERT 识别单词的正确含义

原文:https://towardsdatascience.com/identifying-the-right-meaning-of-the-words-using-bert-817eef2ac1f0?source=collection_archive---------16-----------------------

使用语境化单词嵌入的一个重要原因是,标准嵌入为单词的每个含义分配一个向量,然而,存在多个含义的单词。假设上下文的使用可以解决将多个意思的单词(同音异义词和同形异义词)分类到同一个嵌入向量中的问题。在这个故事中,我们将分析伯特嵌入是否可以用来对一个词的不同含义进行分类,以证明语境化的词嵌入解决了这个问题。

Duck or duck — based on images from Pixabay

构建数据集

使用“鸭子”这个词的想法来自我今天早些时候看到的一条推文。由于单词有多种含义,这种误解比较常见。根据韦氏词典,单词“duck”有 4 个意思。为了这个项目的简单,我把动词‘duck’和相应的名词归类为相同的意思:

  1. a)各种游禽(鸭科,鸭科),颈和腿短,足有蹼,喙通常宽而平,雌雄之间的羽毛通常不同
    ; b)这些鸟的肉可用作食物
  2. 突然低下头或身体
  3. a)一种耐用的紧密编织的通常是棉布的纤维
    b)鸭子复数 : 轻便的衣服尤其是鸭子做的裤子

Misunderstanding the meaning of ‘duck’ — Tweet by natsmama75 on Twitter

为了建立一个数据集,我使用了你的字典的句子数据库,搜索包括‘duck’的句子。从给出的例子中,我排除了那些我不能区分含义的名字、长句和案例。

最终数据集可在 GitHub 中获得。它包含 77 个句子,分布如下:50 个是指动物(类型 0),17 个是动词的一种形式(类型 1),10 个是指织物(类型 2)。

The duck dataset

伯特嵌入

对于这个故事的下一部分,我们将使用原始 BERT 基础无案例模型[1]中的 BERT 嵌入。这意味着使用最后一个隐藏层,我们为每个单词生成一个 768 大小的向量。

我们根据句子为每个单词生成上下文嵌入向量。然后,我们只保留“duck”单词标记的嵌入。这个故事的问题是,我们能否用这 768 个大小向量来对不同的意义进行分类。

主成分分析

PCA 是一种正交变换,我们将使用它来降低向量[2,3]的维数。PCA 以最大化降维数据的方差的方式为投影找到特殊的基向量(特征向量)。使用 PCA 有两个重要的好处。一方面,我们可以将 768 维向量投影到 2D 子空间,在那里我们可以将其绘制成数据。另一方面,它保持最大可能的方差(投影丢失信息),因此,它可能保持足够的方差,以便我们可以识别图片上的类别。

Maximising variance for the first principal component — Equation from Wikipedia

使用带有[sklearn.decomposition.PCA](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html)的 PCA 是一行程序:
duck_pca = PCA(n_components=2).fit_transform(duck_embs)

下图显示了使用前两个主成分的预测结果。这些类是手动注释的类型。正如我们所看到的,使用主成分分析,我们可以很容易地将动词类型与其他类型分开。

Duck meaning types. Projection using PCA

最近邻分类

由于数据集相对较小,我们将使用 k-NN 分类器,而不是神经网络[4]。k-NN 使用 k 个最接近的样本来预测新样本的类别。因为我们在第三类中只有 10 个样本,所以需要使用 k <20 as the k-NN selects the most represented class from the neighbourhood.

For the validation, we will use LOOCV (Leave One Out Cross-Validation) [5]. This means that for every sample, we build a model based on the other 76 samples and validate it with the single sample. Then, we calculate the accuracy of these 77 successful or unsuccessful prediction.

Using 【 , these steps are well prepared and easy to execute:

The evaluation of the LOOCV states精度为 92.208% 标准差为 26.805%。

与谷歌翻译的比较

我的母语匈牙利语用不同的词来表达“鸭子”的不同含义。因此,使用英匈翻译器,我们可以识别翻译器背后的神经网络(称为 GNMT [6]) 认为,‘鸭子’是哪个意思。

Google Translate English-Hungarian translation of the ‘duck’ sentences

上表显示,所有鸟型“鸭”字都使用正确的类型进行翻译,17 个动词型字中有 8 个被翻译,但是,所有织物“鸭”字都被识别为鸟。这个结果显示了 75.641% 的准确率。

摘要

在这个故事中,我们展示了使用语境化的单词嵌入可以成功地解决多义词的问题。实验支持假设,即当我们使用 k-NN 分类器重建类型时,BERT 嵌入存储单词的不同含义。

所有对应的代码都可以在 Google Colab 上找到。

参考

[1] Devlin,j .,Chang,M. W .,Lee,k .,& Toutanova,K. (2018 年)。 Bert:语言理解深度双向转换器的预训练。 arXiv 预印本 arXiv:1810.04805

[2]皮尔逊,K. (1901 年)。 LIII。在最接近空间点系统的直线和平面上。 《伦敦、爱丁堡和都柏林哲学杂志和科学杂志2 (11),559–572 页。

[3]h .霍特林(1933 年)。将复杂的统计变量分析成主要成分。 《教育心理学杂志》24 (6),417 页。

[4]盖,t .,&哈特,P. (1967 年)。最近邻模式分类。 IEEE 信息论汇刊13 (1),21–27。

[5]拉兴布鲁奇,P. A .,&米基,M. R. (1968 年)。判别分析中错误率的估计。 技术计量学10 (1),1–11。

[6]吴,m .舒斯特,陈,z .乐,Q. V .,m .马切里,w .,… &克林纳,J. (2016)。谷歌的神经机器翻译系统:弥合人类和机器翻译之间的鸿沟。 arXiv 预印本 arXiv:1609.08144

用伯特的故事学习 NMT

  1. BLEU-BERT-y:比较句子得分
  2. 嵌入关系可视化(word2vec,BERT)
  3. 机器翻译:一个简短的概述
  4. 使用 BERT 识别单词的正确含义
  5. 机器翻译:对比 SOTA
  6. 使用 TensorFlow 2.0 的简单 BERT】

确定曼谷冬季空气污染的来源第一部分

原文:https://towardsdatascience.com/identifying-the-sources-of-winter-air-pollution-in-bangkok-part-i-d4392ea608dc?source=collection_archive---------10-----------------------

Air Pollution Map near Bangkok in January 2019

在许多亚洲国家,空气污染是一个严重的环境威胁。在泰国,由于 2019 年冬季曼谷的空气污染程度较高,这个问题最近变得更加突出。空气污染通过空气质量指数(AQI)来报告,数值越高表明空气污染越严重。了解当前的室外空气质量可以帮助你保护自己。

游客和当地人可能会有这样的疑问:空气污染越来越严重了吗?是否存在一天中的某个时间或一周中的某天的依赖性?曼谷以外的省份呢?在这篇博文的第一部分,我将通过可视化公开的空气污染数据来回答这些问题。根据这些数据,我们可以对空气污染的来源提出一些假设。在这篇博文的第二部分,我将对空气污染数据进行建模。

用于生成这些图的代码可以在 GitHub 上我的笔记本中找到。这项工作的灵感来自于数据狂人在脸书的一篇帖子。看看我早先的博客的帖子,详细介绍了如何从政府网站上删除空气污染数据。

AQI 是如何计算的?

环境机构使用空气质量指数(AQI)报告空气污染测量值。如何将这些测量值转换成数字的细节取决于当地法律。一般来说,环境机构需要监测四种污染源:地面 ozone(O₃、颗粒污染(PM2.5 和 PM10)和有毒气体(NO₂、CO、SO₂).下面的快照显示了泰国环境署网站提供的 2019 年 2 月 2 日泰国各监测站的 CO,NO₂,O₃,SO₂,PM10 和 PM2.5 水平的报告。空气污染指数在大多数地方都是正常的,除了北部省份的高水平 PM2.5,以红色显示。

计算每种主要污染物的 AQI 值(每种都有自己的公式),并报告 24 小时内的最高平均 AQI 值 。由于上述数据表明 PM2.5 污染物较高,我们将重点分析 PM2.5 数据。

PM2.5 是对大气中小于 2.5 微米的颗粒的测量。在美国,PM2.5 浓度高于 35.4 g/m 相当于 AQI 为 100,对于普通人群来说被认为是中度污染,对于敏感人群(儿童、孕妇和老年人)来说是不健康的。高于 55.4 克/立方米的 PM2.5 对应的 AQI 为 150,被认为是不健康的。

是什么导致了去年冬天曼谷高度的空气污染?PM2.5 颗粒的主要来源是汽车发动机、发电厂和农业废物燃烧的废气,这导致了许多理论——停滞的气流、老旧的柴油车、燃煤电厂和邻近省份的农业燃烧。随着公众对这个问题关注的增加,人们也开始怀疑空气污染是否正在恶化。政府提出了一些短期措施来解决这个问题。但是为了最有效的缓解,我们需要了解污染的来源。

曼谷的冬季阴霾

PM 2.5 pollution in Bangkok over time( the gray vertical bands are guide to the eyes), and the corresponding google trend

让我们从寻找一般趋势开始。这些数据来自伯克利地球 T2 数据库 T3。曼谷的空气污染似乎是季节性的,在冬天会激增。这似乎不是一个新问题,但公众的认识只是最近才提高的。曼谷的空气质量实际上仍然比许多亚洲国家好。

空气污染越来越严重了吗?我取了每年年末(9 月—5 月)的平均值,并计算了 PM 2.5 AQI 较高的天数:

Yearly average PM 2.5 AQI and the number of bad air days

PM2.5 AQI 的年平均值在 2018-2019 年冬季似乎略有增加,而前几年的污染情况相当。这可能是由于测量次数较少,因为 2018-2019 年冬季剩余时间的数据尚未测量。对于天数图,我使用前几年同一时间的天数来估计缺失的数据。在空气不良天数方面,2017-2018 年冬季有 70 天空气质量指数非常高,比上一年多 10 天。在没有更多数据的情况下,很难从这张图表判断情况是否在恶化。

如果你担心空气质量,作为一名去曼谷旅游的游客,你应该避开哪几个月?作为一名居民,什么时候去慢跑最合适?放假大家都不在的时候空气污染好一些吗?为了回答这些问题,我使用 2017 年和 2018 年的数据绘制了不同月份的日平均值。

Daily average of PM2.5 pollution in 2017 and 2018

我们再次看到 PM2.5 污染的季节性趋势。2017 年和 2018 年,污染大约从 10 月下旬开始,持续到 4 月初。2017 年新年假期期间的空气质量似乎更好,但 2018 年的数据缺失,因此无法确定。平均来说,游客应该在 10 月底到 4 月初避开曼谷。你可能在想,“但那是我休假的时候!我还能去哪里?”我建议您去普吉岛或苏梅岛。泰国南部全年 AQI 较低,如下图所示。

当地居民呢?空气质量是早上好还是周末好?高峰时间污染会激增吗?要回答这些问题,让我们来看看冬季的每小时平均值。请注意,为了更好地进行比较,我绘制了标准化数据。

Normalized average PM 2.5 for different days

周末的空气污染并没有好转。这可能是因为交通同样糟糕(这是真的,周六交通非常糟糕)。或者高空气质量指数是由其他因素造成的。首先,让我们仔细看看空气污染与交通的关系。

Hourly average of PM2.5 pollution

在早高峰时段(早上 6-10 点)有一些高峰,但在晚高峰时段没有。由此,我们可以假设其他因素,如温度和风,在决定空气污染水平方面起着更重要的作用。

北方的人们受苦更多

随着季风季节的开始,曼谷的天气会变好,公众对这个问题的关注可能会消退。然而,如果不立即采取政策措施,这个问题将在明年冬天再次出现。事实上,曼谷地区并不是唯一遭受颗粒空气污染的地方。下面,我展示一张 2019 年 2 月的颗粒物污染图。

particle pollution map in February 2019

季节性污染不仅限于中部地区。虽然曼谷的空气污染在 1 月份达到顶峰,但污染转移到了北部省份。事实上,从下面显示的全国最高污染水平来看,他们的情况要糟糕得多。请注意,这是一个月平均值的最大值图,用于剔除异常值。

maximum particle pollution in each province

北部省份,如南邦、清迈和清莱,空气污染比曼谷更严重,但受到的媒体关注却少得多。南部省份,如普吉、宋卡和庄,全年空气质量良好。

总之,PM 2.5 污染在曼谷和北部省份有季节性趋势,只是最近才受到公众关注。在这次冬季雾霾期间,有害颗粒污染水平全天都很高,包括周末。在这篇博文的第二部分,我将尝试使用机器学习来识别曼谷的空气污染源。

感谢您的阅读,敬请期待第二部分!如果你有任何建议,请在下面留下你的评论。我将给你们留下一张泰国每月平均颗粒污染的 gif 图。

确定曼谷冬季空气污染的来源第二部分

原文:https://towardsdatascience.com/identifying-the-sources-of-winter-air-pollution-in-bangkok-part-ii-72539f9b767a?source=collection_archive---------1-----------------------

Mae Fah Luang University Campus on March 2019. (Photo by MFU Photoclub with permission)

在之前的博客里,我看了一下曼谷冬天的空气污染。主要污染源来自小于 2.5 微米的颗粒物(PM 2.5 颗粒物)。这些颗粒比人类头发的宽度还小,可以很容易地进入我们的身体,甚至进入我们的血液。上周(2019 年 3 月 17 日),泰国北部多个省份因颗粒污染出现全球最差的空气质量指数(AQI)。到目前为止,还没有提出长期的解决方案,因为 PM 2.5 颗粒污染的来源还没有明确指出。在这本笔记本中,我通过机器学习模型识别了曼谷高 PM 2.5 颗粒物的来源。代码可以在我的 GitHub 页面找到。

高 PM2.5,罪魁祸首是谁?

关于曼谷的空气污染源有三个主要的理论:(1)逆温效应,冷空气和污染物被困在接近地球表面的地方。这一理论是政府在 2019 年冬季开始时提出的。政府将污染归咎于旧柴油发动机的排放。(2)农业焚烧,无论是本地的还是周边省份的。在冬天,全国各地都有大量露天农业焚烧。一些官员试图通过减少露天农业燃烧来解决空气污染问题。(3)来自其他省份或国家的污染。一些非政府组织将污染归咎于发电厂附近。

我的分析过程如下:建立一个机器学习模型(ML)来预测曼谷的空气污染水平,使用环境因素,如天气,交通指数和火灾地图。在模型中包括日期-时间特征,如当地时间、工作日与周末,以捕捉人类活动的其他影响。使用 ML 模型提供的重要性特征识别主要污染源。

如果污染源是本地的,那么空气质量指数将取决于天气模式(风速、湿度、平均温度)、本地交通和一天中的时间等因素。如果污染来自农业燃烧,空气质量指数将取决于活跃的火灾,并有一定的时间滞后,以说明地理分离。根据与曼谷的距离,包括消防活动。另一方面,如果污染与火灾地图不相关,那么模型应该更加重视天气模式,例如风向和风速。

以下是我考虑的特性及其数据来源的列表:

  • 来自美国宇航局公司项目的主动火力信息
  • 天气模式:温度、风速、湿度和降雨,从天气地下网站上刮来
  • 交通指数来自龙道交通
  • 日期时间特性:一天中的小时、一天中的时间和假日模式(在第一部分博客文章中探讨)

让我首先介绍一下该模型中包含的所有功能。

农业烧荒是个大问题!

东南亚的农民选择一月至三月作为焚烧季节。对于泰国北部和东北部省份来说,这些燃烧活动的规模足以使这些省份成为这段时间世界上污染最严重的地方之一。对于曼谷,有人可能会说,因为该地区是重工业而不是农业,它可能不会受到农业燃烧的影响。但事实并非如此。

由于 PM 2.5 颗粒的尺寸很小,它们可以长时间悬浮在大气中,并且可以传播很远的距离。从天气数据来看,平均风速为 10 公里/小时。报告的 PM 2.5 水平是 24 小时的滚动平均值。粗略估计,目前的 PM 2.5 读数可能来自 240 公里以外的来源。下图显示了美国宇航局的卫星在 2018 年 1 月 8 日和 2018 年 2 月 8 日测量的火灾地图,指示了农业燃烧。黄圈表示曼谷 240 公里以内的区域。1 月 8 日的火灾数量(污染水平可接受)远低于 2 月 8 日的火灾数量(污染水平不健康)。

Fire spots from NASA’s satellites

事实上,火灾模式与 PM 2.5 模式密切相关。

The number of fires aligns with spikes in PM 2.5 levels

天气模式

逆温效应经常发生在冬季,因为近地面温度较低。顶部较热的空气阻碍了冷空气的流动。这种停滞的大气条件使 PM 2.5 颗粒在空气中悬浮的时间更长。另一方面,较高的湿度或雨水将有助于清除大气中的颗粒。这也是过去空气污染严重时,政府向空气中喷水的原因之一。不幸的是,这种缓解措施似乎并不有效,因为水量与实际降雨量相比微不足道。天气模式对空气污染的影响有多大?让我们比较一下冬天和其他季节的天气。

compare the weather pattern in winter and other seasons

冬天的温度、风速和湿度都较低,但幅度不大。现在,让我们来看看其中每一项与 PM 2.5 水平的关系。

Effect of temperature, wind speed, and humidity on PM 2.5 level in winter

较高的温度(这破坏了逆温效应)、风速和湿度与污染水平呈负相关。

Effect of wind on PM 2.5 level in winter

在有风的日子里,污染明显更好。与无风天气相比,有风天气 PM 2.5 水平分布的中值较低。

事实上,污染程度也取决于风向,正如这个图所示。为了简单起见,我只选择了四个主要的风向。

PM2.5 relationship with the wind direction in winter

在风从南方吹来的日子,污染水平可能较低,因为泰国湾在曼谷的南面。干净的海风改善了空气质量。来自其他三个方向的风通过陆路。然而,在风平浪静的日子里,有任何风都比停滞不前的大气条件要好。

在雨天和无雨天,PM 2.5 中值水平的变化较小。冬季的雨天较少,因此数据有些嘈杂,但在累积密度函数中可以观察到差异。

Effect of rain PM 2.5 level in winter

交通指数

PM 2.5 颗粒物的来源之一是汽车发动机尾气。虽然争取更多公共交通的使用总体上有利于环境,但减少 PM 2.5 污染的有效性尚不清楚。原因如下。

traffic index and air pollution

我们已经看到 PM 2.5 水平与一天中的时间有关。下午 3 点左右污染程度较低,但在夜间仍然很高。当相对于交通数据绘图时,与污染水平的关系非常嘈杂。似乎没有很强的相关性。

PM2.5 relationship with traffic index

将一天中的时间和工作日与周末的信息包含到模型中可能会使关系更加清晰。

自回归过程

当前的 PM 2.5 值也可以依赖于之前的值。下面的部分自相关图显示了 1 小时时滞的强相关性,这意味着 PM 2.5 水平是一个自回归过程。因此,我在模型中包括了 24 小时的平均值,并限制模型只允许查看以前的值来进行未来预测。这个特征的重要性应该与粒子在大气中停留的时间直接相关。

机器学习模型

下图显示了根据 Spearman 相关性计算的所有输入特征的 dedrogram。树状图有助于识别可以从模型中移除的冗余特征。各种距离内的火灾数量和 PM 2.5 的水平密切相关。其他功能就更远了。我最终在模型中使用了所有这些特性。

dendrogram of inputfeatures

为了确定污染的主要原因,我使用了随机森林回归来拟合模型,因为它简单且易于解释。在超参数调整期间,25%的数据分配给验证集。使用整个数据集再次重新训练该模型。该模型在训练集上达到 0.99 的 R 平方。由于这项研究的目的是了解过去空气污染的来源,所以我将重点放在训练集上。下图对每个影响因素的重要性进行了排序。重要性是根据置换列时 R 平方值的减少以及重新归一化所有列的总和来计算的。

feature of importance

不出所料,之前的污染水平是最重要的预测指标。其次是从最近到最远的火灾次数。远在 720 公里以外的火灾数量对空气质量的影响比当地的湿度、交通甚至降雨更大。一天中的时间是比交通指数更重要的预测因素。在天气特征中,湿度是最重要的特征。

下面使用 2019 年 1 月 13 日上午 8 点 96 分 2.5 级的数据的树解释器来说明每个特征的影响。

model interpretation on Jan 23, 2019

我们从平均值 26 开始。前一个小时的 PM 2.5 水平是 62,因此该模型增加了一个值 20。在 240 公里的半径范围内有 150 起火灾,因此该模型将污染水平增加了 10 级。现在的值是 56。240-480 km 之间有 1649 处起火,480-720 km 之间有 896 处起火,模型分别加值 9 和 8。低风速和早高峰时间(早上 8 点)给模型增加了 8。在预测 PM 2.5 水平的 96 个因素中,这六个因素占了 81 个。右侧的其余要素不太重要,因此增加的预测污染值较少。

model interpretation on Feb 2, 2019

在一个美好的日子,如 2019 年 2 月 2 日晚上 7 点,PM 2.5 水平为 10。前一小时的污染水平较低,因此模型减去了 10 的值。该地区仍然有许多火灾,该模型增加了值 2。风速很高,使数值降低了 2。天气和交通都很好。许多因素的综合导致 PM 2.5 的预测水平较低,为 10。

结论

PM 2.5 水平与各种因素有着复杂的关系:火灾数量、天气模式和交通。但这个分析证实了很多人的怀疑——农业焚烧是泰国 PM 2.5 污染的根本原因。燃烧活动远至 720 公里以外的曼谷,一个延伸到缅甸,老挝和柬埔寨的地区,会导致曼谷的空气问题。解决这个问题并不容易。这需要东南亚国家的国际合作。

我留给你一张 2019 年 3 月 17 日的火灾地图,这是有史以来最糟糕的一天!

用机器学习识别 Reddit 上的巨魔和机器人(第二部分)

原文:https://towardsdatascience.com/identifying-trolls-and-bots-on-reddit-with-machine-learning-709da5970af1?source=collection_archive---------12-----------------------

巨魔和机器人遍布社交媒体,它们以我们并不总是意识到的方式影响着我们。巨魔可能相对无害,只是试图以他人为代价来娱乐自己,但他们也可能是散播不信任或不和的政治行为者。虽然一些机器人提供了有用的信息,但其他机器人可以用来操纵投票数和推广支持其议程的内容。我们将向您展示机器学习如何帮助保护我们的社区免受虐待。

Source: pixabay.com

在本系列的第一部分,我们报道了流行网站 Reddit 上的巨魔和机器人问题。我们描述了如何构建一个仪表板来控制可疑的巨魔和机器人。在这一部分,我们将向您展示我们如何使用机器学习来检测政治讨论中的机器人和巨魔,然后在我们的版主仪表板上标记可疑的评论。

巨魔和僵尸检测的背景

巨魔和机器人检测是一个相对较新的领域。从历史上看,公司雇佣人工主持人来检测和删除不符合他们服务条款的内容。然而,这种手动过程是昂贵的,另外,对于人类来说,审查最差的内容可能是情绪上的疲劳。随着像开放 GPT-2 自然语言生成这样的新技术的释放,我们将很快触及人类版主效率的极限。随着机器人技术的进步,采用反制技术来保护在线社区的完整性变得非常重要。

已经有一些关于机器人检测的研究。例如,一名研究人员在 Twitter 上发现了竞争的支持特朗普和反对特朗普的机器人。印第安纳大学的研究人员提供了一个名为 botornot 的工具来检查 Twitter 用户。

也有关于网络巨魔的有趣研究。斯坦福大学的研究表明,仅仅 1%的账户就造成了 74%的冲突。佐治亚理工学院的研究人员使用自然语言处理模型来识别违反行为规范的用户,如进行人身攻击、歧视女性的诽谤,甚至是男性抱怨。

筛选评论进行审核

我们的目标是创建一个机器学习模型来筛选政治子编辑上的评论,供版主审阅。它不需要有完美的准确性,因为评论将由人类主持人审查。相反,我们衡量成功的标准是我们能让人类调解人更有效率。他们不需要审阅每个评论,而是能够审阅预先筛选的子集。我们并不试图取代 Reddit 提供的现有审核系统,该系统允许版主审查用户报告的评论。相反,这是一个补充现有系统的额外信息来源。

正如我们在第一部分的文章中所描述的,我们已经创建了一个仪表板,允许版主查看评论。机器学习模型会将每个评论分为普通用户、机器人或巨魔。

reddit-dashboard.herokuapp.com亲自体验一下。

为了满足您的期望,我们的系统被设计为概念验证。它不是一个生产系统,也不是 100%准确。我们将用它来说明构建一个系统所涉及的步骤,希望平台提供商将来能够提供像这样的官方工具。

收集培训数据

我们最初的训练数据集是从已知的机器人和巨魔列表中收集的。我们将使用两个列表,分别是这些已知的 393 个机器人和来自机器人观察子网站的 167 个机器人。我们还将使用 Reddit 2017 年透明度报告中的 944 个巨魔账户,这些账户被怀疑为俄罗斯互联网研究机构工作。

我们正在使用一个事件驱动的架构,该架构由一个从 Reddit 下载数据并将其放入 Kafka 队列的流程组成。然后,我们有一个 Kafka 消费者,它将数据批量写入红移数据仓库。我们编写了一个 Kafka producer 应用程序来下载机器人和巨魔列表中的评论。因此,我们的数据仓库不仅包含来自已知僵尸和巨魔的数据,还包含来自 politics 子编辑的实时评论。

虽然 Reddit 评论并不完全是隐私,但你可能有隐私数据。例如,您可能有受 HIPAA 或 PCI 管制的数据,或者对您的业务或客户敏感的数据。我们遵循了一个旨在保护私人数据的 Heroku 参考架构。它提供了一个 Terraform 脚本来自动配置一个红移数据仓库,并将其连接到一个 Heroku 私有空间。因此,只有在私有空间中运行的应用程序才能访问这些数据。

我们可以直接在 dyno 上训练我们的模型,也可以运行一次性的 dyno 将数据下载到 CSV 并在本地训练模型。为了简单起见,我们将选择后者,但是您可能希望将敏感数据保存在私有空间中。

heroku run bash -a kafka-stream-viz-jorge
export PGPASSWORD=<password>
echo “select * from reddit_comments” | psql -h tf-jorge-tf-redshift-cluster.coguuscncu3p.us-east-1.redshift.amazonaws.com -U jorge -d redshift_jorge -p 5439 -A -o reddit.csv
gzip reddit.csv
curl -F “file=@reddit.csv.gz” [https://file.io](https://file.io)

如果您更喜欢使用我们的培训数据亲自尝试,您可以下载我们的 CSV

现在我们有了两组用户的评论,总共有 93,668 条。不同职业之间的比例固定在 5%巨魔,10%机器人和 85%正常。这对于训练很有用,但是可能低估了正常用户的真实百分比。

选择功能

接下来,我们需要选择特征来构建我们的模型。Reddit 为每个用户和评论提供了几十个 JSON 字段。有些没有有意义的价值。例如,banned_by 在任何情况下都是 null,可能是因为我们缺少版主权限。我们选择了下面的字段,因为我们认为它们作为预测器或了解我们的模型表现如何很有价值。我们添加了列 recent_comments,其中包含该用户最近发表的 20 条评论。

no_follow
link_id
gilded
author
author_verified
author_comment_karma
author_link_karma
num_comments
created_utc
score
over_18
body
is_submitter
controversiality
ups
is_bot
is_troll
recent_comments

像“分数”这样的字段对于历史评论是有用的,但是对于实时仪表板来说就不那么有用了,因为用户还没有时间对评论进行投票。

我们添加了额外的计算字段,我们认为这些字段与机器人和巨魔有很好的关联。例如,我们怀疑用户最近的评论历史将提供关于他们是机器人还是巨魔的有价值的洞察。例如,如果一个用户反复发布带有负面情绪的有争议的评论,也许他们是一个巨魔。同样,如果一个用户用相同的文本重复发布评论,也许他们是一个机器人。我们使用了 TextBlob 包来计算这些的数值。我们将很快看到这些特性在实践中是否有用。

recent_num_comments
recent_num_last_30_days
recent_avg_no_follow
recent_avg_gilded
recent_avg_responses
recent_percent_neg_score
recent_avg_score
recent_min_score
recent_avg_controversiality
recent_avg_ups
recent_avg_diff_ratio
recent_max_diff_ratio
recent_avg_sentiment_polarity
recent_min_sentiment_polarity

有关这些字段是什么以及如何计算的更多信息,请参见我们在 https://github.com/devspotlight/botidentification的 Jupyter 笔记本中的代码。

构建机器学习模型

我们的下一步是基于这个列表创建一个新的机器学习模型。我们将使用 Python 出色的 scikit learn 框架来构建我们的模型。我们将训练数据存储到两个数据框中:一个用于训练要素集,另一个包含所需的类标签。然后,我们将数据集分成 70%的训练数据和 30%的测试数据。

X_train, X_test, y_train, y_test = train_test_split(
 input_x, input_y,
 test_size=0.3, random_state=16)

接下来,我们将创建一个决策树分类器来预测每个评论是机器人、巨魔还是普通用户。我们将使用决策树,因为创建的规则非常容易理解。使用更健壮的算法(如随机森林)可能会提高准确性,但为了保持示例简单,我们将坚持使用决策树。

clf = DecisionTreeClassifier(max_depth=3,
  class_weight={‘normal’:1, ‘bot’:2.5, ‘troll’:5},
  min_samples_leaf=100)

您会注意到上面代码示例中的几个参数。我们将树的最大深度设置为 3,不仅是为了避免过度拟合,也是为了更容易可视化生成的树。我们还设置了类别权重,这样机器人和巨魔就不太可能被遗漏,即使是以错误地标记一个普通用户为代价。最后,我们要求叶节点至少有 100 个样本,以保持我们的树更简单。

现在,我们将根据作为测试集的 30%的数据来测试模型。这将告诉我们,我们的模型在猜测每个评论是来自机器人、巨魔还是普通用户方面表现如何。

matrix = pd.crosstab(y_true, y_pred, rownames=[‘True’], colnames=[‘Predicted’], margins=True)

这将创建一个混淆矩阵,显示每个真实目标标签有多少评论被正确或错误预测。例如,我们可以在下面看到,在总共 1,956 条 troll 评论中,我们正确预测了其中的 1,451 条。

Predicted    bot        normal    troll        All
True                                 
bot          3677       585       33           4295
normal       197        20593     993          21783
troll        5          500       1451        1956
All          3879       21678     2477        28034

换句话说,巨魔的召回率是 74%。精度较低;在所有被预测为巨魔的评论中,只有 58%是真的。

Recall : [0.85611176 0.94537024 0.74182004]
Precision: [0.94792472 0.94994926 0.58578926]
Accuracy: 0.917493044160662

我们可以计算出 91.7%的整体准确率。该模型对普通用户表现最好,准确率和召回率约为 95%。对于机器人来说,它表现得相当好,但是很难区分巨魔和普通用户。总的来说,即使使用一个相当简单的模型,结果看起来也相当不错。

这个模型告诉了我们什么?

现在我们有了这个伟大的机器学习模型,可以预测机器人和巨魔,它是如何工作的,我们可以从中学到什么?一个很好的开始是看看哪些特性是最重要的。

feature_imp = pd.Series(
 clf.feature_importances_,
 index=my_data.columns.drop(‘target’)).sort_values(ascending=False)recent_avg_diff_ratio 0.465169
author_comment_karma 0.329354
author_link_karma 0.099974
recent_avg_responses 0.098622
author_verified 0.006882
recent_min_sentiment_polarity 0.000000
recent_avg_no_follow 0.000000
over_18 0.000000
is_submitter 0.000000
recent_num_comments 0.000000
recent_num_last_30_days 0.000000
recent_avg_gilded 0.000000
recent_avg_sentiment_polarity 0.000000
recent_percent_neg_score 0.000000
recent_avg_score 0.000000
recent_min_score 0.000000
recent_avg_controversiality 0.000000
recent_avg_ups 0.000000
recent_max_diff_ratio 0.000000
no_follow 0.000000

有意思!最重要的特征是最近评论文本中的平均差异率。这意味着如果最后 20 条评论的文本非常相似,它可能是一个机器人。下一个最重要的特性是评论因果关系、链接因果关系、最近评论的回复数量以及账户是否被验证。

为什么剩下的都是零?我们将二叉树的深度限制为 3 级,所以我们有意不包括所有的特性。值得注意的是,我们没有考虑之前评论的分数或情绪来对巨魔进行分类。要么这些巨魔相当有礼貌,赢得了相当多的选票,要么其他特征有更好的区分能力。

让我们看看实际的决策树,以获得更多信息。

export_graphviz(estimator, out_file=’tree.dot’,
 feature_names = data.drop([‘target’], axis=1).columns.values,
 class_names = np.array([‘normal’,’bot’,’troll’]),
 rounded = False, proportion = False, 
 precision = 5, filled = True)

现在我们可以了解这个模型是如何工作的了!您可能需要放大才能看到细节。

让我们从树的顶端开始。当最近的评论彼此相当相似(平均差异率高)时,那么它更有可能是一个 bot。当他们有不同的评论,低评论因果报应,高链接因果报应,他们更有可能是一个巨魔。这可能是有道理的,如果巨魔使用小猫的帖子来提升他们的链接业力,然后在论坛上发表令人讨厌的评论,要么被忽略,要么被否决。

托管 API

为了让我们的机器学习模型对全世界可用,我们需要让它对我们的版主仪表板可用。我们可以通过托管一个 API 供仪表板调用来做到这一点。

为了服务我们的 API,我们使用了 Flask ,这是 Python 的一个轻量级 web 框架。当我们加载我们的机器学习模型时,服务器启动。当它接收到包含带有注释数据的 JSON 对象的 POST 请求时,它用预测进行响应。

一个机器人用户的例子:

{
 “banned_by”:null,
 “no_follow”:true,
 “link_id”:”t3_aqtwe1",
 “gilded”:false,
 “author”:”AutoModerator”,
 “author_verified”:false,
 “author_comment_karma”:445850.0,
 “author_link_karma”:1778.0,
 “num_comments”:1.0,
 “created_utc”:1550213389.0,
 “score”:1.0,
 “over_18”:false,
 “body”:”Hey, thanks for posting at \\/r\\/SwitchHaxing! Unfortunately your comment has been removed due to rule 6; please post questions in the stickied Q&amp;A thread.If you believe this is an error, please contact us via modmail and well sort it out.*I am a bot”,
 “downs”:0.0,
 “is_submitter”:false,
 “num_reports”:null,
 “controversiality”:0.0,
 “quarantine”:”false”,
 “ups”:1.0,
 “is_bot”:true,
 “is_troll”:false,
 “recent_comments”:”[…array of 20 recent comments…]”
}

返回的响应是:

{
 “prediction”: “Is a bot user”
}

我们在 Heroku 上部署了我们的 API,因为它非常容易运行。我们仅仅创建了一个 Procfile ,其中有一行告诉 Heroku 哪个文件用于 web 服务器。

web: python app.py ${port}

然后我们可以把我们的代码推送给 heroku:

git push heroku master

Heroku 负责解决下载需求、构建 API、设置 web 服务器、路由等问题。我们现在可以在这个 URL 访问我们的 API,并使用 Postman 发送一个测试请求:

https://botidentification.herokuapp.com/

看到它工作了吗

感谢我们在本系列第一部分中写的伟大的版主仪表板,我们现在可以看到我们的模型在真实评论上的表现。如果你还没有,看看这里:reddit-dashboard.herokuapp.com

Dashboard at reddit-dashboard.herokuapp.com

这是来自 r/politics 子网站的实时评论。你可以看到每条评论,以及模型是以机器人、巨魔还是普通用户的身份给它打分。

你可能会看到一些被标记为机器人或巨魔的评论,但在检查他们的评论历史后,这并不明显。请记住,为了让我们的教程更容易理解,我们使用了一个简单的模型。标注巨魔的准确率只有 58%。这就是为什么我们把它设计成人类版主审核的过滤器。

如果你对自己玩这个模型感兴趣,可以在 GitHub 的https://github.com/devspotlight/botidentification查看代码。您可以尝试通过使用更复杂的算法(如随机森林)来提高模型的准确性。剧透警告:对于更复杂的模型,有可能在测试数据上获得 95%以上的准确性,但是我们将把它作为一个练习留给你。

用神经网络识别特朗普和希拉里的推文

原文:https://towardsdatascience.com/identifying-trumps-tweets-vs-hillary-s-with-neural-networks-4ed77dd230c6?source=collection_archive---------32-----------------------

我相信我们都听说过特朗普臭名昭著的推文…

https://twitter.com/realDonaldTrump/status/332308211321425920

等等,我是不是听到了再来一次的呼声?好吧,这里还有一些他的推文…

特朗普的推文很容易成为标志性的,(并因其引起混乱的能力而闻名)。如果你看到上面的任何一条推文,你可能会猜到作者是特朗普。换句话说,它们也很容易识别。

事实上,过去识别一条推文是特朗普的甚至更容易…

在 2018 年 3 月之前,特朗普使用 Andriod 手机发推文,在 Twitter API 中,你可以检查推文的来源。这就清楚了哪些话来自特朗普白宫工作人员。特朗普换成 iPhone 后,情况就不一样了,所以让我们想出一个新方法来区分这两者!

为了识别特朗普的推文,我们将使用神经网络。神经网络可以模拟变量之间的复杂关系并预测可能的结果,这意味着它是这项工作的完美工具!

收集数据📃

我从挖掘大量数据开始,收集了特朗普从 2015 年开始的推文。这恰好是来自三个来源的推文的集合,分别是 Andriod、他的新 iPhone 和 Twitter 网络客户端。有了这个庞大的数据集,我把数据分成一个训练集(训练神经网络),和一个测试集(检查神经网络的准确性)。

我能够通过使用访问令牌密钥从 twitter 中挖掘数据。

# Since I applied for a twitter developer here: [https://developer.twitter.com/](https://developer.twitter.com/)
# I created an app and generated the access token keysimport numpy as np
import pandas as pd
import twittertwitter_keys = {
    'consumer_key':        'veqNWYqeq46WB2tKM5FmDGilD',
    'consumer_secret':     '  2o1K5qMCU66gU5nzpm4C7xulj3ZR4K149U1DPLEw2itpnxAFIZ',
    'access_token_key':    '1190255551864885248-  5TOmS02DRKKd74ygZibYjh5bKdS3wX',
    'access_token_secret': 'cXImA3BCajKgxvXgBepDHw8j83VYbq9n8emts612veyD0'
}api = twitter.Api(
    consumer_key         =   twitter_keys['consumer_key'],
    consumer_secret      =   twitter_keys['consumer_secret'],
    access_token_key     =   twitter_keys['access_token_key'],
    access_token_secret  =   twitter_keys['access_token_secret'],
    tweet_mode = 'extended'
)

我将它们格式化为熊猫数据框架(有点像电子表格),并将 2016 年至 2018 年的挖掘数据连接在一起。

df = pd.concat([pdata2016, pdata2017, pdata2018])

这是数据集的最后几行…

Here are the last rows of the DataFrame with all of Trump’s tweeting data

准备数据📈

神经网络不能直接处理文本,所以我使用了来自 Scikit Learn modelTFIDF 矢量器来拟合文本数据。这实际上是将文本数据转换成一个数字模式,我们可以将它输入神经网络。想象一个巨大的电子表格,每个单词都有一列。为每个单词生成值。这些值可以是频率或者甚至是它对整个上下文的重要性/显著性

下面是将数据从文本格式更改为数字数组的部分代码。

# Transform text data into numerical pattern for neural networks to read 
# [https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html)tfidf_num = TfidfVectorizer(max_df=0.95,min_df=0.02)
# max_df -> ignore terms with frequency higher than threshold
# min_df -> ignore terms with frequency lower than thresholdtfidf_num.fit(df.text) #Learn vocabulary from training set.
column = len(tfidf_num.get_feature_names())

神经网络🧠

这就是它的工作原理!我们正在使用神经网络来模拟一个复杂的关系,在这个例子中是推文(输入)和谁发送它们(输出)之间的关系。神经网络由三个主要部分组成:

  1. 模型框架(节点和层的连接)
  2. 激活功能(决定节点是否被触发)
  3. 学习算法(逻辑回归和反向传播)

顺便说一句,如果你还没有读过,在这里读一读我的神经网络简介让你快速上手!

我们将带有标签的推文数据输入神经网络,表明它是来自 Trump 还是他的工作人员,这是算法的输入数据。该模型计算一个预测,将其与正确的标签进行比较,并对其权重偏差进行调整。

预言;预测;预告

它基于模型框架计算一个预测,这意味着首先我们为每个节点生成随机权重偏差,以达到一个预测

激活功能

在节点计算其输入的加权和之后,激活函数决定信息是被激发还是被传递。一个简单的激活功能是步进功能。阶跃函数计算加权和是否高于某个特定值,如果是,则认为激活,否则认为不是。

softmax 激活函数做类似的事情,除了它计算概率。 softmax 的输出将总是从 0 到 1,并累加到 1。例如,这作为一个置信度得分,我们可以有 60%的把握认为该推文来自特朗普。

学习算法

在生成一个概率后,该模型计算一个误差值(我们离正确的标签有多远)。使用这个误差值,我们回溯并编辑所有的权重偏差,从而更接近正确答案。这个过程被称为反向传播,它是减少错误和增加准确度得分的关键。

这是通用模型,我们将使用它来生成多个具有不同框架的模型,以找到哪个架构工作得最好。

def baseModel(inputSH, outputSH, layers=2, nodes=100):
    base_model = Sequential()
    base_model.add(Dense(100, activation='relu', inputSH = (inputSH,)))
    for x in range(layers):
        model.add(Dense(nodes, activation='relu'))
    model.add(Dense(outputSH, activation='softmax')) # Softmax activation - probabilities between 0-1
    model.compile(optimizer='adam',loss='binary_crossentropy', metrics=['accuracy','mean_squared_error'])
    return model

我们希望训练模型,直到预测接近实际标签。我们还想测试它从未遇到过的推文的准确性,这就是测试数据集派上用场的地方。

正确的模型📐

这个项目最困难的部分之一是找到正确的神经网络。改变节点层数可以改变模型的最终精度。所以我使用训练数据的不同部分测试了各种不同的模型架构

最后,我计算了哪些模型的得分最高(T36,T37),并利用了那个模型(T38,T39)(这次是 4 个隐藏层,每个隐藏层有 1000 个节点)。因为这个模型之前只使用了一部分训练数据进行训练。我用整个训练数据集重新训练了这个模型,并在训练数据上评估了它的性能(准确率为 93%)。

有趣的部分来了!测试时间!现在,我们将测试数据输入到不带标签的算法中,并要求模型给我们一个预测。总体而言,它能够以 80%的高准确率区分特朗普和白宫工作人员的。

但是还有更多…

如果我们把他的推特和他的对手希拉里的相比会怎么样?

事实证明,在挖掘清理希拉里的推文之后,我能够做到这一点。在测试该模型后,我发现我能够以 87%的准确率预测希拉里的推文,以 60%的准确率预测特朗普的推文。

这是我的算法认为最有可能成为希拉里的推文:

“我们敦促选民抛弃川普,在这场竞选中选择明显合格的候选人:希拉里。”——@ Denver posthttps://t.co/bpbgC5VhYV

这是我的算法认为有最高概率成为川普的推文:

…..与乌克兰新总统的通话很好,这不可能更好或更光荣了,假新闻媒体和民主党人作为一个团队,欺骗性地让它看起来很糟糕。还不错,非常合法,非常好。持续的政治迫害!

出于好奇,我调查了川普与希拉里相比最常见的 n 字母组合N-grams 是一段文本中一定数量单词(本例中为 2-5 个)的连续序列

以下是特朗普最常见的 n 字母组合:

[('fake news', 112),
 ('united states', 79),
 ('witch hunt', 74),
 ('president trump', 48),
 ('new york', 44),
 ('adam schiff', 44),
 ('north carolina', 40),
 ('republican party', 39),
 ('radical left', 32),
 ('news media', 31),
 ('federal reserve', 31),
 ('fake news media', 30),
 ('ukrainian president', 28),
 ('america great', 28),
 ('nancy pelosi', 27)]

以下是希拉里最常见的 n 字母组合:

[('donald trump', 117),
 ('make sure', 66),
 ('vote https', 63),
 ('health care', 48),
 ('debatenight https', 47),
 ('human rights', 37),
 ('hillary clinton', 36)
 ('human rights', 37),
 ('hillary clinton', 36),
 ('today https', 28),
 ('trump https', 27),
 ('president https', 27),
 ('climate change', 26),
 ('debate https', 25),
 ('election day', 24),
 ('young people', 24)]

其他应用⚙️

神经网络应用于数据分析有无限的可能性和方式。神经网络是非线性数据建模工具,这意味着它们可以对各种变量之间的复杂关系进行建模。

大多数申请可以分为三类:

  1. 分类——观察结果将被分成几类
  2. 时间序列——预测未来结果的预测模型
  3. 优化——找到解决问题的最有效方法

这里有几个神经网络可能应用的例子

  • 信用卡欺诈检测(分类)
  • 字符识别(分类)
  • 预测天气模式(时间序列)
  • 预测和识别心脏病发作(时间序列)
  • 车辆的有效路径问题(最优化)

关键要点📌

  • 神经网络能够对数据中的复杂非线性关系进行建模,找到模式,并且预测结果
  • 神经网络允许对数据进行更快更有效的分析
  • 它们可以应用于各种领域,并且在大数据时代的处理和理解海量数据中至关重要

如果仅仅从推特上就能获得这么多数据,想想我们周围到处都有多少数据!大数据时代已经开启,应用和可能性无穷。我们不仅可以将它用于推特,还可以将其应用于语音识别、天气预报,甚至为路由问题提供更有效的解决方案。

有了这么多数据,神经网络是理解这一切的关键!我们需要他们对数据进行适当的利用,并从数据中获得比以往更多的洞察力!

这绝对是一个非常有趣的项目,我希望我已经激发了你对神经网络和数据分析的探索!

在我的网站上查看我的项目页面这里

如果你想在未来阅读更多的文章,给我的帐户一个关注!

与此同时,你可以随时在 ariel.yc.liu@gmail.com 联系我,或者通过 LinkedIn 联系我。

你也可以在这里阅读我的每月简讯!

或者访问我的个人网站查看我的全部作品集这里

下次见!👋

身份、信任和价值:开放银行的未来

原文:https://towardsdatascience.com/identity-trust-and-value-s-the-future-of-open-banking-7926e22f085b?source=collection_archive---------28-----------------------

将有希望的想法转化为相关的数据实践需要超越 API

理论上,开放式银行可以利用创新的信息基础设施来重新定义金融数据的创建、应用和交流方式。在实践中,开放标准对金融服务的贡献取决于人类对价值、信任和身份的理解。对于传统银行机构和金融科技的新参与者来说,将有前途的想法转化为相关数据实践的能力需要超越编程接口,以了解人类智能如何影响新服务场景的机遇和挑战。

开放标准不会将数据转化为价值,人们会。开放银行业的承诺到底是什么?开放银行将如何规范个人数据的机构使用?技术标准本身是否足以建立信任,从而吸引传统银行和新市场的新服务提案?财务价值和人的价值之间有什么联系。管理层如何确保他们的数据实践将允许他们的组织在今天和不久的将来收获人工智能的好处?

开放银行业的承诺

开放的银行业建立在开放的标准之上,其中身份、信任和价值是设定所有标准的基础。开放式银行承诺从根本上改变消费者与银行和金融服务的互动方式。在 EC 修订版支付服务指令(PSD2)以及英国竞争和市场管理局(CMA)法规的推动下,开放银行框架有望增强金融机构之间的竞争,为消费者提供更个性化的产品,并增加服务创新。这一呼吁在整个欧洲引起了共鸣:仅 2018 年,欧洲前十大国家的金融科技初创公司就在 477 笔独立交易中积累了€28.9 亿美元的风险资本。开放银行业也在国际上引起了反响,刺激了新西兰、墨西哥、阿根廷、尼日利亚、香港、日本和台湾等不同市场的创新。【我】

机构银行传统上是围绕垂直整合模式建立的,涵盖价值链的所有方面,从发起到服务,再到风险和资产负债表管理。开放式银行框架规定了关于第三方访问、知情消费者同意、数据安全和个人金融数据争议解决的法律准则。从监管的角度来看,这些法规要求零售银行通过应用程序编程接口与授权的第三方共享其经常账户数据。从技术上讲,这些服务的实现将需要基于应用程序编程接口(API)的信息架构,以确保端到端的比较服务、自动储蓄和信用评分。这些架构反过来为金融数据的消费者和生产者创造了无数的潜在商机。

对政府和社会而言,开放的银行业可以推动市场做出更负责任、反应更灵敏的投资和债务决策。对于零售银行而言,开放银行业务将测试传统银行模式,并鼓励它们围绕“银行即服务”(BaaS)找到专业领域并开发自己的独特品牌。对于新的市场进入者,开放银行将有助于创造结合预测分析、人工智能和融资的创新服务主张,以触及不同的客户群。最后,消费者将受益于更容易地比较来自不同提供商的银行服务的能力,从而获得更好的产品和更广泛的选择。

身份的首要地位

准确识别每笔交易的合同方一直是金融机构的基础之一。确保严格身份标准的愿望要求企业和个人提供确认其身份的物理文件。新服务的客户入职需要更多面对面的互动,导致耗时、重复的账户注册、登录和支付授权申请流程。新的透明度监管要求,包括反洗钱(AML)和了解您的客户(KYC)程序,使这些流程变得更加复杂。因此,金融机构目前每年在身份管理解决方案上的花费超过 10 亿美元。【ii】

开放银行的愿景是让消费者能够控制自己的数据,并在此过程中促进他们获得贷款、测试其他金融产品和在线购买更广泛产品的能力。银行信息系统中持续存在的不兼容和记录不良的遗留应用程序阻碍了这一承诺:在入职流程中验证客户信息时,需要大量的人工劳动和运营成本。事实证明,如果没有一个无缝的产品组合管理平台,很难吸引客户转换或使用来自多个提供商的服务。最后,向第三方运营商开放遗留系统有其自身的风险,银行很可能会因为金融科技支持的第三方提供商的提议而失去其作为特许供应商的地位。

随着数据科学和分析的发展,机构对其客户的信念、动机和行为了解得越多,就越能更好地定制其服务和交易。数据科学已经广泛应用于银行的许多核心流程,包括成本和收入分配、客户拓展、欺诈检测、营销拓展、产品开发和风险管理。互联网银行、社交媒体和移动银行应用程序提供了大量数据,可以帮助金融机构更好地了解他们的客户和市场。机器学习算法和数据科学技术可以在促进客户细分、构建推荐引擎和简化客户支持方面显著改善银行的分析策略。

每天淹没市场的大量数据有助于金融部门做出更好的决策吗?算法还不能解释有效的客户经理与机器的区别:人类代理的概念,他或她的移情能力,人类智能的本质,以及一个人区分对错的能力。有限理性证明了组织如何使用数据来理解过去、分析现在和预测未来的伦理问题。隐性偏见限制了数据科学在描绘金融服务现实方面的相关性:人类的态度和先入之见污染了我们对数据、认知、逻辑和道德的看法。多次金融危机中凸显的数字化转型的管理问题值得思考:管理者和组织需要在多大程度上对其数据实践负责?

信任的悖论

如果开放银行是为了建立数据交换的标准,那么信任就是所有其他标准的基础。新监管框架的目的是提供在线信息基础设施,提供与机构银行遗留系统一样安全的服务。这项立法的主旨是顺应货币体系数字化转型的大趋势:20%的消费者交易已经在网上发生。从 2018 年到 2021 年,无现金交易的数量预计将每年增长 12.7%。【iv】这些数字提供了预期转变的证据,以及消费者倾向于金融服务提供商与其客户之间建立更开放关系的前提。

这一数据讲座为银行和金融科技公司打开了新的机遇,让它们将自己定位为客户的终身顾问。从总账的发明到区块链的概念,技术的基本目标之一一直是提供单一版本的真相,即作为可信中介的证据记录,以促进产品和服务的交换。最近的一项 nCipher 安全调查表明,与其他行业相比,消费者更信任金融行业,尤其是他们的银行能够保护他们的个人数据。然而,这种信任可能是相当不稳定的,只有 36%的英国消费者相信银行会为他们客户的最大利益服务,而在德国(35%)、意大利(30%)、法国(29%)和日本(27%),这种怀疑程度更高。【VI】

数据永远不会比消费者对组织的数据实践的信心更有价值。已经提出了几个假设来解释这种信任悖论。基于“人是产品”哲学的商业模式越来越受到那些讨厌被分类然后被产品化的人的质疑。公司对数据的感知需求超过了对个人隐私的任何关注,这种零和经验受到了公众的广泛谴责。基于“越大越好”的数据囤积实践被证明是毫无意义的,因为它们具有潜在的危险。最后,数字营销的社会机制进一步扭曲了真相和信任之间的关系,促使心理剖析成为反映现实矛盾版本的镜子。

数据架构需要超越满足数据机构的法律约束,在组织和他们的客户之间培养信任关系。我们在其他地方已经指出,数字化转型的最终目标不仅仅是优化销售流程,而是提供帮助消费者做出更好的经济和社会决策的洞察力。【VII】开放银行业的相关性与其说取决于其工具和技术的复杂程度,不如说取决于消费者利用金融应用来改善个人和集体福祉的程度。信任不是你拥有多少数据的数量的属性,而是消费者对这些数据如何被使用的看法的结果。

哪些物有所值?

“物有所值”在今天的行业中几乎就像一个累赘,即使什么是物有所值的问题仍然是一个公开的问题。开放式银行创造了多种途径来增强客户对金融服务价值的认识。消费者现在可以直接与他们的金融产品互动,而不是通过每个单独的银行。商家使用 API 代表客户发起支付的能力为新的支付方案打开了大门。金融科技可以利用交易和行为数据来建议和个性化产品。

对于金融机构本身而言,开放的银行监管可能会促使它们在再造合作伙伴生态系统时,重新考虑自己的商业模式和价值主张。一些机构很可能试图利用开放银行的可能性,直接控制产品和服务的生产和分销。有些人可能选择投资开发新产品和服务,由他们的商业伙伴分销。许多人可能会专注于金融科技创造的分销金融产品和服务。其他人仍将专注于该平台,充当市场中介,促进其生态系统中的活动。

开放银行业务的当前绩效指标(涉及账户、交易、余额、直接借记、长期订单、受益人、产品的处理时间)是否充分反映了金融价值和人文价值之间的关系?理查德·塞勒关于“一价定律”的经济学原理的研究表明,消费者的行为通常会违背理性思考。Gerald Zaltman 认为,多达 95%的购买决定都是基于潜意识的考虑。【IX】消费者对价值的感知取决于他们的感觉、直觉和洞察力。仅仅基于流程效率来阐述度量标准,充其量只能捕捉到消费者所看重的更大图景的一部分。指标捕捉到了它们被设计用来衡量的东西,算法按照它们被教授的方式执行,而金融决策则是由对价值的认知形成的。

Trust by Design 的首字母缩写下,我们认为开放银行的未来更多地依赖于开发以客户为中心的数据实践,而不是 API。金融机构需要提高其现有能力,特别是在数据和分析方面,以便利用新出现的机会。组织应该明智地集中投资,鼓励在整个企业和生态系统中使用开放数据。在利用非专有数据时,银行和金融科技需要解决使用个人数据的问题。最后,他们需要与客户就开放式银行如何应对数字经济的挑战和机遇展开有意义的对话。客户价值不是您拥有多少数据的数量属性,而是消费者对这些数据使用方式的看法。

开放银行业的未来需要超越数据,看到身份、信任和价值的基础。在为即将于 11 月 14 日和 15 日在伦敦举行的访问管理和开放银行业务峰会所做的贡献中,我们认为

  • 身份、信任和价值是建立开放银行业标准的基础。
  • 人口统计和行为特征还不能捕捉到有效的客户经理和机器之间的区别
  • 数据永远不会比消费者对组织的数据实践的信心更有价值。
  • 什么是物有所值的问题仍然是一个悬而未决的问题
  • 价值不是金融机构持有的数据量的属性,而是消费者对其数据使用方式的看法的结果。

Lee Schlenker 是商业分析和社区管理教授,也是 http://baieurope.com 商业分析研究所的负责人。他的 LinkedIn 个人资料可以在查看你可以在的 Twitter 上关注白


【I】Tobin,G. (2018),全球开放银行体系

【ii】埃森哲(2013),银行业身份的未来

【iii】Cochrane,m .(2019),投资者需要知道的关于现金之战的一切

【iv】Rolfe,a .,(2018)世界支付报告 2018:数字支付蓬勃发展

【v】助网安,(2019),消费者最信任银行的个人资料

【VI】Palenicek,J. (2018),大多数英国人信任银行…

【VII】sch lenker,Lee(2018)设计信任

【VIII】泰勒,理查德(2016),行为不端:行为经济学的形成,W. W .诺顿&公司

萨尔特曼,杰拉尔德(2003),顾客如何思考:对市场心理的基本洞察,哈佛商业评论出版社

如果玛丽·近藤做了 SQL…

原文:https://towardsdatascience.com/if-marie-kondo-did-sql-be86374b7cd8?source=collection_archive---------23-----------------------

…她会使用 dbplyr

在以前的一些帖子中,我提到过dbplyr包是一种在 r 中处理 SQL 数据库的非常酷的方式。dbplyr是一个非常聪明的 SQL 翻译器,随着每次更新,它变得越来越强大。它允许您将数据库表视为一个 R dataframe 对象,并使用简单、干净的 tidyverse 命令来操作它。在 R 控制台中处理所有这些乱七八糟的 SQL 字符串要好得多,也更直观。

我想我会用一个简单的例子来说明dbplyr是如何工作的,我希望你能拿起这个例子并进一步发挥它。不知不觉中,你就再也不想用 SQL 写东西了!

使用 chinook 数据库

chinook是一个 SQLite 数据库,可以在这里下载,练习用起来真的很方便。一旦你把它解压到一个文件夹,打开你的 R 会话,我们将使用下面的包:

library(tidyverse)
library(dbplyr)
library(DBI)
library(RSQLite)

首先,我们将建立与 SQLite 数据库的连接。虽然这个数据库只是一个本地保存的文件,但是您可以使用类似的连接到您的 Oracle 或 MSSQL 数据库或其他数据库[1]。

chinook <- DBI::dbConnect(
  drv = RSQLite::SQLite(),
  dbname = "chinook.db"
)

我们现在可以有效地连接到chinook数据库。我们可以使用RSQLite::dbListTables(chinook)来浏览其中的表格,这表明其中有以下表格:

"albums"          "artists"         "customers"       "employees"       "genres"         "invoice_items"   "invoices"        "media_types"     "playlist_track"  "playlists"      "sqlite_sequence" "sqlite_stat1"    "tracks"

我们将使用dbplyr对其中的一些表格进行试验,特别是以下表格:

  • employees —公司员工的详细信息
  • customers —客户详情表
  • invoices —附在客户 id 上的发票明细表
  • invoice_items —每个发票 ID 中订购单位和价格的详细信息表

我们可以很容易地使用dplyr将这些表设置为数据库对象,如下所示[2]:

employees <- dplyr::tbl(chinook, "employees")
customers <- dplyr::tbl(chinook, "customers")
invoices <- dplyr::tbl(chinook, "invoices")
invoice_items <- dplyr::tbl(chinook, "invoice_items")

这些表现在都是 R 会话中的 SQL 数据库对象,您可以像操作数据帧一样操作它们。注意,只需在 R 控制台中键入表名,就可以看到每个表中的数据摘录。重要的是,在定义这些表时,您并没有实际下载它们,只是创建了一个最少的摘录来使用。

使用 dbplyr 查询

现在让我们试着做一个非常简单的查询,比如我们按照雇佣他们的年份分组了多少员工。如果我们把它写成一个简单的 SQL 查询,它看起来会像这样:

qry <- "SELECT HireYear, COUNT(EmployeeId) FROM
(SELECT SUBSTR(HireDate, 1, 4) AS HireYear, EmployeeId
FROM employees)
GROUP BY HireYear"

现在,如果我们运行DBI::dbGetQuery(chinook, qry),就会得到这个返回:

 HireYear count(EmployeeId)
1     2002                 3
2     2003                 3
3     2004                 2

但是我们也可以使用如下的代码来实现:

employees_by_hire_year <- employees %>% 
  dplyr::mutate(HireYear = substr(HireDate, 1, 4)) %>% 
  dplyr::group_by(HireYear) %>% 
  summarize(Total = n())

由于这是一个非常小的表,您只需在控制台中键入它的名称就可以看到它,它确实会返回与上面的表相同的表。如果它比较大,您就必须从数据库中收集它——稍后会详细介绍。

这种魔力似乎是如何发生的?因为 R 将employees识别为 SQL 数据库对象,所以 R 在后台调用dbplyr将管道化的 tidyverse 代码翻译成 SQL。您可以使用dbplyr::sql_render()函数查看翻译后的 SQL。例如,dbplyr::sql_render(employees_by_hire_year)返回这个:

<SQL> SELECT `HireYear`, COUNT() AS `Total`
FROM (SELECT `EmployeeId`, `LastName`, `FirstName`, `Title`, `ReportsTo`, `BirthDate`, `HireDate`, `Address`, `City`, `State`, `Country`, `PostalCode`, `Phone`, `Fax`, `Email`, SUBSTR(`HireDate`, 1, 4) AS `HireYear`
FROM `employees`)
GROUP BY `HireYear`

让复杂的查询变得简单

上面的例子非常简单,直到你的查询变得非常复杂,你才能真正看到使用dbplyr的好处。

假设您想计算出客户每年在订单上花了多少钱。这意味着您必须从发票日期中提取年份,然后使用InvoiceIdinvoice连接到invoice_items,然后按年份分组,然后计算该年的总单价乘以订购数量。多亏了dbplyr,我们可以使用我们漂亮的 tidyverse 语法来做到这一点:

amount_per_year <- invoices %>% 
  dplyr::mutate(InvoiceYear = substr(InvoiceDate, 1, 4) %>%          
                  as.integer()) %>% 
  dplyr::inner_join(invoice_items, by = "InvoiceId") %>% 
  dplyr::mutate(ItemTotal = UnitPrice * Quantity) %>% 
  dplyr::group_by(InvoiceYear) %>% 
  dplyr::summarise(Total = sum(ItemTotal))

这比它的 SQL 等价物好得多,也更容易使用。注意,在其当前形式下,amount_per_year仍然只是一个数据库对象,数据还没有正式从数据库中提取出来。要正式提取数据,您可以使用dplyrcollect()函数,如下所示:

amount_per_year %>% dplyr::collect()

它将返回:

# A tibble: 5 x 2
  InvoiceYear Total
        <int> <dbl>
1        2009  449.
2        2010  481.
3        2011  470.
4        2012  478.
5        2013  451.

如果您在远程数据库上工作,而不是在本地 SQLite 数据库上工作,额外的优势是dbplyr确保所有的操作都在数据库上完成,您只需收集结果,而不必将所有数据提取到您的会话中。

练习练习

通过尝试以下练习,看看您能否让dbplyr为您的chinook数据集工作:

  1. 按国家分有多少客户?
  2. 2009 年第一季度开出了多少张发票,按客户所在国家分组?
  3. 卖给美国顾客的前十首歌曲的名字是什么?(对于这一个,您还需要tracks表)。

附录

[1]连接远程数据库的一般代码如下:

conn <- DBI::dbConnect(
  drv = [database driver, eg odbc::odbc()],
  dsn = "database_name",
  uid = "User_ID",
  pwd = "Password"
)

[2]要在远程数据库的模式中创建一个类似的表,可以使用dbplyr中的in_schema()函数:

my_db_tbl <- dplyr::tbl(
  conn, 
  dbplyr::in_schema("SCHEMA_NAME", "TABLE_NAME")
)

[3]下面是我写的最后一个dbplyr查询的 SQL 翻译:

最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn Twitter上找我。

如果“多维”伤脑…

原文:https://towardsdatascience.com/if-multi-dimensional-hurts-your-brain-c137c9c572d6?source=collection_archive---------24-----------------------

AI/ML 实用性

放松点。思考 N 维空间可能对机器学习至关重要,但这并不难。

Photo by Casey Horner on Unsplash

本文是 AI/ML 实用性 系列的一部分。

深度和广度数据集

隐藏在大量人工智能/人工智能炒作背后的是一个简单的事实:机器学习没有什么新意。这是一种建立统计模型的工具,自 1899 年吉尼斯啤酒厂开始使用这些方法测试新的啤酒配方以来,基本上使用了相同的方法。

Statistical pioneer and Guinness brewmaster
William Sealy Gosset, aka “Student” (Wikipedia)

《吉尼斯世界纪录》没有做到的是,机器学习使这一过程自动化,让计算机完成大部分统计工作。此外,由于计算机变得如此强大和廉价,机器学习可以处理巨大的数据集并开发复杂的模型,这在 19 世纪甚至 20 世纪是无法想象的。

这些“巨大的”数据集既深,因为它们包含许多例子,又广,因为它们包含关于每个例子的许多信息。

深度:脸书声称拥有超过 20 亿用户。

Wide:他们(至少)有每个帖子的记录,比如,点击,滚动,查看等。对于每个用户,加上大量的推断数据。他们知道大多数人的年龄、地点、家庭成员、朋友、兴趣、政治倾向、收入等。

Depth = number of examples / Width = number of features per example

换句话说,一个数据集有许多关于每个例子的信息,它有许多维度

但是,什么是维度呢?

如果你觉得我刚刚把这个带到了技术 10,深呼吸,让我们解开“维度”是什么。

Thinking about dimensions in space makes it very hard to imagine what other dimensions could be

作为一名学生,我对可能有超过 3 个维度的想法感到困惑。4 维物体是什么样子的,更何况是 10 维物体?我希望一些神奇的澄清洞察力。

我期待错了。至少以物理学家谈论更高维度的方式,人类根本无法想象超过 3 维的空间。但是,我们不需要。

维度只是描述事物的独立方式,与空间没有必然联系。在日常语言中,我们习惯于将“维度”理解为长度、宽度和高度。

是的,盒子的尺寸是长、宽和高。但我们无时无刻不在遇到非空间维度。我们来看一个具体的例子。

七度空间中的钻石

Photo by Edgar Soto on Unsplash

当美国宝石学院(GIA)对一颗钻石进行分级时,他们报告的 7 个维度是重量、颜色、净度、切割、抛光、对称和荧光。

如果你能想象出一个钻石列表,每颗钻石有 7 条信息,那么恭喜你。你在考虑更高维度,特别是 7 维空间。

在机器学习中,我们学习或预测的每个数据点都是一组输入。这些输入就是尺寸。如果我们想要建立一个模型,仅根据钻石的等级来预测其销售价格,那么该模型的输入将有 7 个维度(等级的详细信息),其输出将有 1 个维度,即预测销售价格。即它将从 7 个维度或 7 条信息映射到 1 个维度或 1 条信息,即价格。

A pricing model maps 7 dimensions (i.e. pieces of information) down to just 1 dimension: the price

机器学习伴随着高维度

有效地使用深度数据集带来了计算上的挑战,因为处理如此多的例子需要很长时间。但是,有效地利用深度要困难得多。

使用传统方法确定潜在指标之间的有用关系需要训练有素的统计人员的判断。在数以千计的潜在指标中寻找这样的信号,甚至超过了大型(且昂贵)团队的能力。

要评估的交互的数量随着输入的数量呈指数增长。在 2000 年代,我领导的团队负责预测借款人何时提前偿还抵押贷款。每次我们改变模型时,我们都会评估数以千计的图表,这些图表描绘了十几个输入之间的相互作用。五倍于此的投入会使努力变得棘手。想象 100 倍或者 1000 倍!

机器学习自动化了这种信号寻找过程,并且因为它可以在没有持续人类指导的情况下在巨大的计算农场上处理,所以我们通常可以让它寻找甚至微小而微妙的影响。

因此,机器学习对高维度有天然的亲和力。正如伟大的技术往往会做的那样,机器学习不仅取代了过程的一部分,而且通过其规模,使我们能够做我们以前不能做的事情。

如果虚拟现实是现实,虚拟虐待只是虐待。

原文:https://towardsdatascience.com/if-virtual-reality-is-reality-virtual-abuse-is-just-abuse-34f09f1007ef?source=collection_archive---------20-----------------------

随着越来越多的人拥抱虚拟空间,我们应该如何处理平行世界中发生的攻击性、辱骂性或猥亵行为?

“如果你有独立于你的思想之外的东西,它有因果力量,你能以所有这些方式感知,对我来说,你离真实还有很长的路要走,”哲学家大卫·查尔莫斯最近在接受 《纽约时报》 采访时告诉普拉尚·罗摩克里希纳。查默斯引用了澳大利亚哲学家塞缪尔·亚历山大的话,他说:“真实就是拥有因果力量”,科幻作家菲利普·K·蒂克说:“T10 真实的东西是当你不再相信它时不会消失的。

Chalmers 教授的评论是关于新的和日益复杂的虚拟现实世界的;他认为某些东西在我们已知的物理现实中具有“次现实”(或类似)的地位。一个独立于我们的想象仍然存在的地方,在那里行动有结果。

Chalmers 将我们信任的物理现实进行了类比,这在许多层面上已经是如此虚幻。毕竟,大脑与世界没有直接联系,它依赖于我们感官的调节。正如这位数学家兼哲学家指出的那样,科学告诉我们,像颜色这样的生动体验“只是物体的物理反射特性产生的一束波长,在我们身上产生某种体验”

在他的观察中,他肯定不是唯一的。有一个既定的传统,即询问我们的世俗经历是否只不过是一种欺骗——一种为了娱乐某种更高力量的虚拟欺骗(见这里这里)。在这种情况下,虚拟现实世界只是一个更大的虚拟世界中的另一种虚拟体验。

无论我们更熟悉的现实状况如何,我们可能很快就会在区分这些所谓的物理体验和虚拟体验方面遇到问题。即使在两者在视觉上截然不同的情况下,其中一个实施的行为的显著性可能会在另一个中产生反响——特别是当涉及到激发情绪反应的行为时。

在身临其境的互动环境中,我们应该如何应对令人苦恼的、操纵的或虐待的行为?尤其是当它从“内容”发展到更像是一种生活体验的时候?

事实上,这些问题已经开始显现。

以类似于 【第二人生】 的在线模拟环境为例,在这些环境中,虐待儿童的虚拟模拟是由同意的成年人在没有法律含义的情况下进行的。2018 年,一份关于“性年龄游戏”的研究报告研究了这一现象——随着更加流动和匿名的虚拟环境的出现,这一现象将变得更加普遍——指出在大多数司法管辖区,不存在违法行为,因为不存在对涉案儿童的直接伤害。尽管其他用户分享了一个“对性年龄游戏的共同理解是一种虚拟的恋童癖,而不是一种双方同意的成年人之间的性恋物癖。”**

尽管这一活动被描述为“无受害者”,但第二人生的创造者林登实验室试图用他们的社区规则来监管它。但是随着虚拟世界的不断增加,很有可能会涌现出以“年龄游戏”为特定目的的新的虚拟世界。他们在玩打地鼠游戏。

其他第二人生用户的反弹很有趣。尤其是考虑到同样的观众似乎对其他“边缘戏”有不同的看法。报告告诉我们:“……强奸游戏、谋杀游戏、乱伦游戏等行为在文化上被广泛接受,因为它们只是被构建为双方同意的幻想,因此不能反映或影响 RL[现实生活]居民及其未来的行为。**

尽管这些用户接受了双方同意的例子,但很明显,在虚拟环境中,性骚扰和性侵犯不涉及双方同意的例子数不胜数。

2016 年,一位名为 Jordan Belamire 的女子写下了她在一款名为 QuiVR 的虚拟现实游戏中被性侵的经历,在该游戏中,另一名(男性)玩家开始虚拟地摩擦她的胸部,当她大声喊他停下来时(该游戏允许口头交流),她开始用“抓捏动作进行追逐。可以理解的是,尽管没有实际发生身体接触,乔丹还是觉得这次遭遇被极大地侵犯了。

这场袭击既是真实的也是虚拟的。使用 Chalmers 的现实标准——它独立于 Belamire 的想象,它绝对有因果关系。

这种令人生畏的情况并不是孤立的事件。经常踏入 VR 环境的女性用户通常会有一串类似的例子来分享。随着头像和自我表达变得更加逼真,目前还不清楚平台和法律将如何适应这种行为。正如迈阿密大学的法学教授玛丽·安妮·弗兰克斯所警告的:

“我们正在接近这样一种情况,即将一个人的体型以惊人的准确度输入到他们可能被强奸、攻击甚至杀害的场景中。你永远也不会知道,在火车上,坐在你隔壁小隔间的人或者坐在你对面的人,是不是在用手机做同样的事情。”

令人沮丧的是,这种宽容的虚拟现实环境正在与另一种现象并行发展,这种现象允许坏演员控制另一个人的身体和身份: deepfakes 。我们已经看到这种媒介武器化的方式侵犯了个人——尤其是女性——同时通过玩弄微妙的现实模拟边界逃避真正的责任。

我们是否正在走向一个虚拟的疯人院,在那里掠食者可以在另一个现实的更深、更暗的角落里重建和操作我们近乎精确的人类肖像?或许还可以出售这种使用权?举证的责任落在否认这种可能性的人身上。

当然,有人会说这仍然是一项没有受害者的努力。毕竟,这不会是你,甚至不是你真正的身体。这是一个头像或相似物,没有身体接触。任何违反都只是一种感知。也许是冒犯,但不是冒犯。

然而,这削弱了我们与自己相似之处的非常真实的心理-生理联系——这种联系在不久的将来只会变得更强。在 2010 年,研究人员展示了一种身体所有权效应(可与橡胶手错觉相媲美)可以在虚拟现实中触发,方法是通过跟踪受试者的身体运动的细微细节,手和手指的运动水平,然后在虚拟身体中精确地复制这些运动。最近,另一组研究人员发现,这种所有权效应甚至可以在非人类动物的化身中重现,如蜘蛛和蝙蝠。《T4 麻省理工科技评论》很快指出这种效应“在色情世界中不可避免地会有应用”。

因此,如果我们对我们的虚拟身体有一种观点,认为它是某种形式的拥有,那么对这种形式的任何强加不就是对暂时居住在其中的人的强加吗?看起来的确如此,而且毫无疑问,它的攻击会造成真正的心理影响。

但是现在我们有一个问题。即使我们同意在虚拟环境中对用户的骚扰或攻击构成了现实生活中的伤害,这也不能谴责那些假扮成未成年人和施虐者参与道德上可疑的年龄游戏的用户。毕竟没有投诉人,所以有没有真正的伤害?我们不能像 Second Life 社区成员在 2018 年的研究中所做的那样,假设虚拟现实中的行为代表了现实生活中的行为。我们也不能对它可能促进的行为做出模糊的概括,这些行为最终会在一些感知的因果链上对儿童造成实际的伤害。如果我们认为这是一个虚拟的兽交问题——而不是虚拟的儿童虐待——由两个同意的成年人进行,我们不太可能使用“虐待动物”的论点来游说消除它。

然而,凭直觉,任何一个头脑正常的人都会反对虚拟虐童。那么,我们如何才能保护我们的新虚拟现实环境,而不被指责毫无必要地审查无受害者的幻想?

也许答案就在研究为什么某些虐待行为在现实世界中几乎普遍被定为犯罪。它总是建立在对受害者的伤害上吗?我觉得不是这样的。有些情况下,我们会谴责一种行为,即使我们不容易定义它的不良后果。事实上,一些行为——如通奸、习惯性说谎或侮辱死者——通常被认为是本质上错误的,不管是否有任何具体的后果。

这无疑是一个更复杂的场景,但也有一些先例。2008 年,英国宣布儿童性虐待漫画为非法。正如在虚拟世界中一样,在这些插图的创作和发行过程中,没有儿童受到直接伤害,因此它是一个有用的比较工具。值得注意的是,当时的司法部政务次官 Maria Eagle 评论说:

“这并不是将艺术或色情漫画定为犯罪,而是针对淫秽的、通常非常真实的儿童性虐待图像,这些图像在我们的社会中没有一席之地。”

这是对所描述的行为的广泛和明确的谴责。这是因为我不想生活在这样一个世界里,这样严重的虐待可以被成人轻视和公开庆祝。试图消除在它的描绘中有毒的东西。

因此,如果这种没有受害者的图像足以让我们至少感到非常不舒服——如果我们可以将它视为文明社会中的一种虐待——我们也应该认为现实虚拟世界中的表演性性虐待同样令人不安,如果不是更令人不安的话。当然,很多人会。但是,随着这个新的西部荒野展现在我们面前,重要的是我们要弄清楚什么是可接受的和有利可图的使用,以及什么样的行为会成为污染物。特别是如果像查尔莫斯教授所说的那样,虚拟现实实际上是另一个现实,而不是一些无法无天的游乐场,在那里我们可以想象的任何事情都可以成为现实。

当然,这是一个滑坡。如果现实世界的规则阻止游戏玩家在末日般的虚拟世界中热情地向对手射击,他们会感到震惊。同样,在现实生活中,出于安全原因,有大量的行为是非法的——比如高速驾驶——虚拟现实可能是完美的发泄途径。我们也知道,这是一个学习和练习特殊技能的好地方,比如外科手术,以主动减少真正的伤害。因此,似乎从物理现实到虚拟现实的法律的全面应用可能会破坏媒体的最佳使用,并很快恶化成闹剧。

然而,这并不意味着我们不应该适当考虑我们能够并且应该引入哪些规则。当一个行为对个人或更广泛的社会有真正的因果影响时,我们就应该采取措施保护那些珍贵的东西。不只是在现实生活中,而是在所有可能的世界里。

如果你是贝叶斯主义者,你必须是天真的!

原文:https://towardsdatascience.com/if-you-are-a-bayesian-you-have-to-be-naive-ac55492889bf?source=collection_archive---------17-----------------------

贝叶斯定理

source: Chris Albon

让我们从一个谜题开始吧

如果你第一次面试很成功,你获得第二次面试的可能性有多大?

  • 接受第一次面试的人中有 50%接受了第二次面试
  • 95%接受复试的人第一次面试都很顺利
  • 75%没有得到复试的人在第一次面试中表现良好

我们可以用常识来解决这个问题。这并不像听起来那么可怕。

假设有 200 人参加了面试,其中 100 人进入了第二轮,100 人没有。在第一批人中,有 95 人认为他们的第一次面试很棒。在第二批人中,有 75 人认为他们的第一次面试很成功。总共有 95 + 75 (170)人觉得他们的第一次面试很不错。

最后,在 170 人中,只有 95 人获得了第二轮面试。这就是了。

我们可以用贝叶斯定理把它复杂化。这就是我在这篇文章中要讨论的内容。

什么事?

贝叶斯定理允许我们从抽样(或似然)分布先验分布后验分布

简单来说,它可以利用一些相关观察的知识让你得到一些你还不知道的东西。

什么是抽样分布?

抽样分布是在给定我们的参数( θ )的情况下看到我们的数据(X)** 的概率。**这个写成 p(X|θ)。

例如,我们可能有 1000 次抛硬币的数据。其中 1 表示头部。这在 python 中可以表示为:

抽样分布允许我们指定我们认为这些数据是如何产生的。对于掷硬币,我们可以认为我们的数据是由伯努利分布产生的。这个分布有一个参数 p,它是得到 1 的概率(或者掷硬币的正面)。然后,它以概率 p 返回值 1,以概率(1-p)返回值 0。

你可以看到这是如何完美的抛硬币。对于一个公平的硬币,我们知道我们的 p = .5,因为我们同样有可能得到 1(正面)或 0(反面)。我们可以从这个分布中创建样本,如下所示:

现在,我们已经定义了我们认为我们的数据是如何生成的,我们可以计算给定我们的参数𝑝(𝑋|𝜃).看到我们的数据的概率既然我们选择了伯努利分布,我们只有一个参数:p。

我们可以使用伯努利分布的概率质量函数(PMF) 来获得单次抛硬币的期望概率。PMF 取一个观察到的数据点,然后给定参数(在我们的例子中为 p ),返回在给定这些参数的情况下看到该数据点的概率。对于伯努利分布,很简单:如果数据点是 1,PMF 返回 p,如果数据点是 0,它返回(1-p)。

这是一个非常简单的 PMF,但是其他发行版可能会复杂得多。所以很高兴知道 Scipy 内置了大部分这些功能。我们可以从 PMF 得出如下结论:

这很好,但我们真正想知道的是看到我们所有 1000 个数据点的概率。我们如何做到这一点?这里的技巧是假设我们的数据是独立且同分布的。这个假设允许我们说看到我们所有数据的概率只是每个个体概率的乘积:𝑝(𝑥1,…,𝑥𝑛|𝛽)=𝑝(𝑥1|𝛽)∗…∗𝑝(𝑥𝑛|𝛽)p(x1,…,xn|β)=p(x1|β)∗…∗p(xn|β).这很容易做到:

这个数字对我们有什么帮助?就其本身而言,它并没有太大的帮助。我们现在需要做的是为我们的采样模型得到更多的分布。目前,我们只测试了 p = .5 的模型,但是如果 p = .8 呢?还是. 2?那么我们的数据的概率会是什么样的呢?这可以通过为我们的 p 定义一个值网格来实现。下面我将制作一个由 0 和 1 之间的 100 个值组成的网格(因为 p 必须在 0 和 1 之间),然后我将计算在给定这些值的情况下看到我们的数据的概率:

现在我们有所进展。我们可以看到,看到我们的数据的概率在 p = .5 时达到峰值,几乎肯定在 p = .4 和 p = .6 之间。很好。现在我们有了一个很好的想法,假设 p 值是从伯努利分布中提取的,那么是什么 p 值产生了我们的数据。我们完了,对吧?不完全是…

先验分布

贝叶斯定理说,我们需要考虑我们的抽样分布和先验分布。我说的优先分配是什么意思?它是𝑝(𝜃)或看到我们参数的特定值的概率。在我们的抽样分布中,我们为参数 p 定义了从 0 到 1 的 100 个值。现在我们必须定义看到每个值的先验概率。这是我们在看到任何数据之前假设的概率。最有可能的是,我们会假设一个公平的硬币,它看起来像上面的分布。让我们看看如何做到这一点:

基本上,我们创建了 1,000 次公平抛硬币,然后像之前一样生成了抽样分布(除了我们除以抽样分布的总和以使值总和为 1)。现在,在我们的参数之前,我们有一个“公平硬币”。这基本上意味着,在我们看到任何数据之前,我们认为掷硬币是公平的。我们可以在我们的先验分布中看到这个假设,因为我们的先验分布峰值在 0.5,几乎都在 0.4 到 0.6 之间。

我知道你在想什么——这太无聊了。抽样分布和先验分布看起来完全一样。所以让我们把事情混在一起。让我们保持我们的公平先验,但改变我们的数据是一个不公平的硬币:

啊——这很有趣。我们有强有力的数据证据证明硬币是不公平的(因为我们生成了 p = .8 的数据,我们知道它是不公平的),但是我们先前的信念告诉我们硬币是公平的。我们该如何应对?

贝叶斯定理允许我们从抽样和先验分布到后验分布。后验分布是 𝑃(𝜃|𝑋).或者用英语来说,给定我们的数据,我们的参数的概率。如果你仔细想想,这就是我们真正想要的。我们通常从调查或网络流量中获得数据,我们希望找出哪些参数最有可能给定我们的数据。那么我们如何得到这个后验分布呢?下面是一些数学问题(不要担心,不算太糟):

根据定义,我们知道(如果你不相信我,查看这个页面复习一下):

  • 𝑃(𝐴|𝐵)=𝑃(𝐴,𝐵) / 𝑃(𝐵)或者在英语中,看到给定 b 的概率是看到两者的概率除以 b 的概率
  • 𝑃(𝐵|𝐴)=𝑃(𝐴,𝐵) / 𝑃(𝐴).或者用英语来说,给定 A 看到 B 的概率就是看到他们两个的概率除以 A 的概率。

您会注意到这两个值共享同一个分子,因此:

  • 𝑃(𝐴,𝐵)=𝑃(𝐴|𝐵)∗𝑃(𝐵)
  • 𝑃(𝐴,𝐵)=𝑃(𝐵|𝐴)∗𝑃(𝐴)

因此:

𝑃(𝐴|𝐵)∗𝑃(𝐵)=𝑃(𝐵|𝐴)∗𝑃(𝐴)

这意味着:

𝑃(𝐴|𝐵)=(𝑃(𝐵|𝐴)∗𝑃(𝐴)) / 𝑃(𝐵)

𝐴使用𝜃插件,𝐵:使用𝑋插件

𝑃(𝜃|𝑋)=(𝑃(𝑋|𝜃)∗𝑃(𝜃)) / 𝑃(𝑋)

不错!现在我们可以插入一些我们知道的术语:

𝑃𝑜𝑠𝑡𝑒𝑟𝑖𝑜𝑟=(𝑙𝑖𝑘𝑒𝑙𝑖ℎ𝑜𝑜𝑑∗𝑝𝑟𝑖𝑜𝑟) / 𝑃(𝑋)

但是什么是𝑃(𝑋)?或者用英语说,我们数据的概率?这听起来很奇怪…让我们回到数学上,再次使用𝐵和𝐴:

我们知道𝑃(𝐵)=∑𝑃(𝐴,𝐵)(查看第进行复习)

从上面的定义中,我们知道:

𝑃(𝐴,𝐵)=𝑃(𝐵|𝐴)∗𝑃(𝐴)

因此:

𝑃(𝐵)=∑ 𝑃(𝐵|𝐴)∗𝑃(𝐴)

插上我们的𝜃和𝑋:

𝑃(𝑋)=∑𝜃𝑃(𝑋|𝜃)∗𝑃(𝜃)

插入我们的术语:

𝑃(𝑋)=∑𝜃 𝑙𝑖𝑘𝑒𝑙𝑖ℎ𝑜𝑜𝑑 ∗ 𝑝𝑟𝑖𝑜𝑟

哇!是不是很牛逼!但是我们所说的∑𝜃是什么意思呢?这意味着对所有参数值求和。在掷硬币的例子中,我们为参数 p 定义了 100 个值,因此我们必须计算每个值的概率,并对所有答案求和。这是贝叶斯定理的分母。因此,我们对贝叶斯的最终回答是:

𝑃𝑜𝑠𝑡𝑒𝑟𝑖𝑜𝑟=(𝑙𝑖𝑘𝑒𝑙𝑖ℎ𝑜𝑜𝑑 ∗𝑝𝑟𝑖𝑜𝑟) / (∑𝜃 𝑙𝑖𝑘𝑒𝑙𝑖ℎ𝑜𝑜𝑑∗𝑝𝑟𝑖𝑜𝑟)

那是一大堆文字。让我们再做一些编码,把所有的东西放在一起。代码可以在这里找到。

您会注意到,我将先验和可能性的观察次数设置为 100。这增加了我们分布的方差。更多的数据通常会降低分布的扩散。此外,当你得到更多的数据来估计你的可能性时,先前的分布就不那么重要了。

我已经把它改成 10 了。你可以在上图中看到这种影响。因为我们有更多的数据来帮助我们估计我们的可能性,我们的后验分布更接近我们的可能性。相当酷。

结论

这就是了。贝叶斯定理导论。现在,如果你怀疑一枚硬币的公平性,你知道如何调查这个问题!或者是一个群体投票赞成一项法律的概率?或者任何其他是/否的结果。

一些旁注

  1. 你会注意到贝叶斯定理的分母只是一个常数。所以如果你只想得到最大后验值,你甚至不需要计算那个常数。由于这个原因,你经常会看到后验概率与可能性*先验概率成比例。
  2. 频率统计侧重于可能性。或者你可以说,常客是贝叶斯理论,具有非信息先验(像均匀分布)。但是不要太讨厌常客;应用环境中的大多数贝叶斯推理依赖于频率统计。
  3. 现在你知道了频率主义者的统计集中在可能性上,这就更清楚为什么人们经常误解频率主义者的置信区间了。可能性是𝑃(𝑋|𝜃)——或者给定我们的参数,我们的数据的概率。这有点奇怪,因为我们得到的是数据,而不是参数。大多数 frequentists 模型所做的是取似然分布的最大值(或最大似然估计(MLE))。基本上找到什么参数最大化看到我们数据的概率。这里重要的一点是,他们将数据视为随机的,所以 frequentist 置信区间的意思是,如果你不断获得新数据(可能更多的调查)并计算每个新样本的置信区间,这些样本中 95%的置信区间将包含你试图估计的真实参数。

朴素贝叶斯

在机器学习中,有一个利用贝叶斯定理的非常常见的模型,称为朴素贝叶斯。这是一个分类模型,如下所示:

𝑃(𝐶𝑙𝑎𝑠𝑠|𝐷𝑎𝑡𝑎)∝𝑃(𝐷𝑎𝑡𝑎|𝐶𝑙𝑎𝑠𝑠)∗𝑃(𝐶𝑙𝑎𝑠𝑠)

因此,我们使用贝叶斯定理的概念来计算给定数据的某个类的概率——这是有意义的。

在这个模型中,我们的先验很容易计算——它只是训练数据中出现在该类中的概率。例如,如果您的训练数据有 40%是 heads,那么您的 prior to P(Heads|Data)是. 40。

什么是 P(数据|类)?显然这是我们的可能性。在上面的例子中,我们用伯努利分布来表示我们的可能性。对于朴素贝叶斯,通常使用三种分布:

  • 伯努利
  • 多项式
  • 高斯的

你要做的是使用训练数据来估计每个特征的必要参数。例如,高斯的均值和标准差(给定感兴趣的类)。因此,如果你有一个特征,即被投掷硬币的重量,你将得到每一类(正面和反面)重量的平均值和标准差。然后对所有要素执行此操作,并假设所有要素都遵循相同的分布-在本例中为高斯分布。这也是它被称为幼稚的一个原因。

您还假设所有的特征都是独立的(天真的),因此这意味着您可以将所有特征的可能性的乘积作为 P(数据|类)。

因此,对于一行数据,计算 P(Class|Data)的方法是:获取该行的每个要素,根据训练数据中计算出的参数,将其代入所选分布的可能性,然后将所有这些值相乘,最后乘以训练数据中属于该类的概率。

您对每个类重复这个练习,然后您预测的类就是具有最大值的类。就是这样!

这个模型非常快,所以它的伸缩性很好。它在垃圾邮件分类领域也很有名,因为它是解决这个问题的原始模型之一。尽管如此,它最常用于具有多项式可能性的文本分类。

Sklearn 有一篇很好的文章,其中有一个如何使用该模型的示例:

http://scikit-learn.org/stable/modules/naive_bayes.html

如果你是从事人工智能的产品经理,你需要知道这一点

原文:https://towardsdatascience.com/if-you-are-a-product-manager-working-on-ai-you-need-to-know-this-be7f048ecaf9?source=collection_archive---------31-----------------------

我们可以从自然智能中学到什么来在人工智能领域取得成功…

作为人工智能产品经理,一个人的任务是创建、部署和发展人工智能产品或应用程序,并确保它在整个生命周期中交付。

在我(20 多年)的人工智能实践中,之前在学术界创造这些算法,然后在私营部门将它们应用到现实世界的应用中,我意识到在我们如何构思我们的人工智能应用中有一个缺失的成分:持续学习。这就是我的意思。

回到基础…

我写这篇文章的时候,正看着我的第四个孩子,新生的莱昂纳多·范思哲,在他生命的第五天小睡片刻。它强大的(天生的)智能在几个小时的紧张工作后正在休息。它在学习,为下一次玩耍重新连接自己,重组突触,这样他的大脑会在下一次玩耍时变得更好,哪怕只是一点点。

Taking inspiration from the most powerful learning machines we know of.

正如我听说或看到的所有婴儿一样,莱昂纳多出生时有一套非常基本的技能,而且有点“不熟”。有几个月的时间,他不会走路,不会说话,更不用说为他的爸爸做卡布奇诺了(到两岁时,他应该是一个熟练的咖啡师了)。

大自然母亲为人类选择了一种非常奇特的发展方式。我们的婴儿出生时,基本技能非常有限,但令人印象深刻,其中最重要的是:学习。

然后,日复一日地在球场上重复和不断地学习。

人类天生就有能力建立基本技能,学习和发展超越他们对世界的最初理解,并在现实世界中运用他们的技能。婴儿最终会感知和抓住机器人,并将它们撕碎(见上图,我的长子加布里埃尔在他面前正要撕掉不幸的 iRobot 的各种碎片)。

如果我们能够跟随自己的脚步构建和部署人工智能,我们就可以避免企业通常面临的许多问题。现实是,大多数人工智能开发遵循的过程与上面概述的过程非常不同。产品经理和工程团队倾向于在试图在相关环境中进行测试之前,尽可能多地构建人工智能系统。这个基本的、命运多舛的想法是:“让我尽可能多地将人工智能放入系统,我知道它需要做什么,然后当我在 67 个月后完成时,祈祷它能工作!”。

然后,88 个月后,人工智能失败了。

这是规则,而不是例外,一旦部署,你的人工智能将不会按预期工作。但是在把所有的责任都推给产品经理和 AI 专家之前要三思!今天,部署、培训和测试人工智能的过程很繁琐,为了不浪费宝贵的时间和金钱,尽可能好地进入系统是至关重要的。

只有在相关环境中的早期部署和学习,在一个连续的反馈循环中,它才能使我们真正建立一个(自然或人工)智能,能够应对现实与我们想象的概念。

人类日复一日地学习。AI 也应该这样做

Truly realiable AI should never stop being updated

我学到了艰难的方法…为机器人构建和部署人工智能。我认为花大量的时间设计一个防弹人工智能,然后看看它是否能在实地工作会是最好的。几次尝试失败后,我和我的同事不得不改变策略。现在,我们专注于在投入使用前的快速原型制作。我们越早了解潜在的缺陷,就越能更好地解决它们。

所以,日复一日,部署并坚持学习。和我们一样,AI 永远不应该停止学习!

如果你懂 SQL,你可能会理解 Transformer,BERT 和 GPT。

原文:https://towardsdatascience.com/if-you-know-sql-you-probably-understand-transformer-bert-and-gpt-7b197cb48d24?source=collection_archive---------21-----------------------

都是关于查询和检索的。

Paris, France

对于那些自 2017/2018 年以来一直关注自然语言处理如何发展的人来说, Transformer / BERT 对你来说并不陌生。由于 Alexander RushJay Alammar 和最近 Peter Bloem 写了许多非常详细的介绍,我不打算涵盖引擎盖下的内容;相反,我在寻找第一个原则,并试图用更容易理解的东西——数据库和内存——来做一个类比。

如果你能理解 SQL 查询,也许你能理解 Transformer 架构的本质。即使你不是,这也应该不难理解——我只是从我的“纸库”中提取所有 NLP 论文的作者和标题。

从纸质数据库中选择作者、标题,其中 Category = "NLP "

对数据库的查询必须灵活地适应各种键(Category = "NLP ")和值(作者和标题)。同时,键和值必须灵活地服务于用户进行的任何查询。在 SQL 背后,它由一个跨查询、键和值共享的数据模式管理。有效记录包含所有项目,以便它们可以互换使用。

本质上都是查询

当查询被传递到计算机时,它是一个两步过程:

  • 首先,计算机必须搜索并匹配你的查询和关键。
  • 第二,计算机返回键的相同记录的值。

这与注意力机制惊人地相似,它是变形金刚的支柱:

  • QKt 正在匹配查询和键。从数学上来说,它是测量 Q 和 k 之间的余弦相似性。相似性越高,记录越相关。
  • Softmax(。)V 是键的相关记录的返回值。数学上讲,softmax 函数会返回一个概率。这意味着,每条记录都是概率加权的。

Formula 1 in Transformer (Vaswani et al., 2017)

我想强调两点:

  • 查询关键字匹配和数据检索步骤从 IF/ELSE/AND/OR 逻辑跳到基于概率的逻辑。这呼应了经典/基于规则的人工智能是如何进化成概率人工智能的。毕竟,不可能根据任何条件写下所有的规则,最好的策略是用概率来编码。
  • 存储的值是一个向量(有理数数组),而不是整数。整数和有理数之间有很大的区别。毕竟从 0 到 1 (2 个整数),里面实际上有无限个数字(0.1,0.11,0.111,0.1111,…等等。).这意味着,如果我们将每个有理数与一个记录相关联,潜在地,我们可以存储 0 到 1 之间的大量记录。

我在 SQL 和注意力机制之间做了一个类比。

SQL vs Attention Mechanism

查询增强理解

注意力机制的另一个好处是,我们隐式地要求机器编写查询,使用返回的结果,并整合不同的返回结果以形成另一个有意义的查询和结果等。

Queries enhance understanding

一开始,如果我不明白 CV 是什么,我会查询“CV”,所有的计算机视觉论文都会被返回,所以我知道 CV 代表计算机视觉。反过来,如果我们不明白一篇论文讲的是什么,通过查询标题,返回类别,我知道这是一篇关于 NLP 的论文。通过迭代的,如果不是穷尽的,查询,我们通过在记录之间建立关联来更好地理解记录

同样,在 Transformer 中,我们查询每条记录,以便返回每条记录(单词)与所有其他记录(单词)的关联。例如,如果我以概率方式查询“paper ”,它可能会返回一个概率估计,其中“read”是最有可能的。通过对所有单词的详尽查询,机器可以跨所有单词开发理解和关系。

一个 Transformer 有多个关注点,并将关注点叠加在关注点上,所以你可以想象 Transformer 就像一群聪明的分析师,他们合作地使用高级语义 SQL 迭代地从一个超大型数据库中挖掘洞察力;当多个中层经理从他们的直接下属那里获得洞察力时,他们会将发现提交给他们的经理(比双重报告更难),他们最终会进行提炼,然后提交给首席执行官。

从变形金刚到伯特和 GPT

著名的伯特和 GPT 正在使用 Transformer 架构来从非常大的语料库中捕获和存储单词之间的语义关系。基本上,大多数其他最先进的语言模型都是基于 Transformer 的,因为这种类似数据库的结构允许更好的检索,因此可以存储像语言这样的大量数据中更复杂的关系。

而且这个数据库是可以转移的,你可以把任何一个预训练的模型想象成压缩的训练数据。事实上,探索这些预先训练好的模型几乎成了大多数从业者事实上的练习。

都是关于查询和检索的

良好的记忆力(又名数据库)对智力至关重要。你的每一个想法实际上都是在向你的大脑数据库查询,然后返回相关的语言、图像和知识。没有有效的查询和检索是不可能的。因此,找到一种有效的数据结构来更好地查询和检索一直是人工智能研究的重点,这也是为什么我们有越来越多新颖的深度学习架构可以玩的原因!

用夜灯照亮人类的活动

原文:https://towardsdatascience.com/illuminating-human-activities-using-the-night-light-9caceaab7867?source=collection_archive---------17-----------------------

Nightlights of the earth observed in 2016. Image processed and released by NASA

自从人类出现以来,人类从黎明到黄昏一直工作,日落之后才休息。但是自从托马斯·爱迪生发明了灯泡之后,情况就变了。

今天我们的夜晚变得比以往任何时候都更明亮,原因是我们到处都有灯。我们的市场、广告牌、道路和住宅都被点亮了。如今,人类居住的每个地方都有某种形式的夜灯。

现在多亏了卫星,我们可以从太空中看到并绘制这些夜光。这些数据有多种用途,包括帮助救灾、分析停电,甚至绘制全球和地区二氧化碳排放量的估计图等。

如果你想深入了解外部因素,Nightlights 是一个非常有用的数据集,可以纳入你的分析中。夜间值提供了关于人口和经济发展的非常丰富、独特的见解。

地球在夜间的图像经过处理后产生了这些数据,任何人都可以免费下载和处理/分析这些数据。在我的上一篇博客中,我谈到了谷歌地球引擎如何提供地理空间数据集,而无需下载和预处理。

使用地球引擎,我分析了从卫星图像中获取的免费夜灯数据集,发现了一些有趣的使用模式,并认为我应该分享一些。

古老的文明围绕河流发展

古老的文明围绕着河流。最有可能的原因是,在那些日子里,人类最依赖农业,这些河流使得大规模的农业成为可能。随着这些文明的消亡,新的文明在它们的足迹上诞生。

所以通过观察今天人类居住的模式,我们可以看到古代文明是如何发展的。所以让我们来看看这个星球上最古老的三个文明。

印度河流域文明

印度河流域文明,又称哈拉帕文明,始于 5300 年前。它盛行于目前从阿富汗延伸到巴基斯坦和印度的地区。印度河流域文明是旧世界三大早期文明之一,与埃及和美索不达米亚文明齐名。

这条河具有如此重要的历史意义,以至于“印度”这个名字也来源于“印度河”。它的大部分盆地在今天的巴基斯坦,如果你看看巴基斯坦的夜景,你会发现人类出现在印度河及其支流周围。

Nightlight in Pakistan along the river Indus

它非常相似,你可以在这张地图上画出河流。现在看看印度河系统,看看相似之处。

Indus River system

古埃及文明

古埃及文明发生在公元前 3100 年到公元前 2686 年之间。这是世界上最著名和最受推崇的文化。这种文化是沿着尼罗河两岸发展起来的。宏伟的金字塔是曾经繁荣的河岸文化的一些证据,并提醒人们在埃及沙漠中存在一个强大的帝国。

现代埃及也与古埃及文明位于同一地点,即尼罗河三角洲。夜灯数据集显示,埃及的人口集中在尼罗河及其三角洲周围。这又有一个相似之处。

Nightlights in Egypt along the River Nile

要看相似之处,请看一下埃及和尼罗河的地图。

Map of Egypt and the River Nile

美索不达米亚文明

美索不达米亚是人类历史上出现的第一个文明。该地区位于底格里斯河和幼发拉底河之间,位于小亚细亚和波斯湾之间。这个地区以其肥沃的农田而闻名。这一文明可以追溯到公元前 10,000 年,当时该地区的人们发现了农业的概念,并开始驯养动物。

这些河流发源于今天的土耳其,流经叙利亚,流入伊拉克,最终汇入波斯湾。如果你看看今天的伊拉克和叙利亚,你会发现他们的城市仍然有这种模式。

Development of Iraqi and Syrian cities around the Tigris and Euphrates rivers

现在看看这两条河的地图,看看有什么相似之处。

Map of rivers Tigris and Euphrates

新的文明正在沿海涌现

随着贸易的普及,人类改变了这一趋势,开始在海港周围定居。我们最近看到了迪拜、阿布扎比和沙迦等城市。沿阿联酋海岸弹出。我们在伊朗的恰巴哈尔和巴基斯坦的加瓦达尔沿海看到了类似的新发展。例如,看看澳大利亚

Nightlights in Australia

与我们之前谈到的文明相比,澳大利亚的城市要年轻得多,它们代表了人类居住的新模式。你可以看到澳大利亚是一片广阔的黑暗之地,除了沿海涌现的城市。

从太空中可以看到边境的紧张局势

从太空中可以看到的另一种人类活动是边界紧张。我们都知道印度和巴基斯坦相处不好。从上面可以看到。

Pakistan India Border from the space

India Pakistan border zoomed in

他们边界的南部是可见的,因为它位于人烟稀少的沙漠中,这使得两边都很暗,但边界被泛光灯照亮,因为双方全天候监控对方的活动。

出于同样的原因,从上方可以看到的另一条边界是朝鲜和韩国之间的边界。这就更清楚了。

Nightlights of North and South Korea as seen from the space

Korean Border zoomed

这里要看到的另一点是发展的巨大差异。与朝鲜相比,韩国要发达得多,你可以在韩国各地看到充满活力的城市,而在朝鲜,唯一有一些夜景的地方是平壤市。

经济发展

夜灯也可以被看作是经济发展的一个标尺。随着经济的发展,城市开始变得越来越大,越来越亮。我使用了 DMSP·OSP 的夜灯数据集进行分析,该数据集可以从 1992 年到 2013 年获得,所以我试图看看世界在这段时间里是如何变化的,我可以看到几乎整个世界都变得更亮了。

Left: South Korea in 1992. Right: South Korea in 2013

增长最快的两个国家之一是韩国。上图不言自明。在此期间,他们的国内生产总值从 3863 亿美元增加到 1.3 万亿美元,这一点从太空中可以看出。但是有一个国家甚至超过了韩国。

Left: China in 1992. Right: China in 2013

从 1992 年到 2013 年,中国的国内生产总值从 4269 亿美元增长到 9.6 万亿美元,从空间上可以很容易地看出这一点。但从太空中可以看到的另一件事是,所有的开发都在东半部,而西半部仍然相当不发达。或许这就是为什么中国通过一带一路将它的西半部与巴基斯坦的海港、中东和欧洲连接起来的原因。

战争使各国陷入黑暗

战争是地狱。它是冷漠的,向你展示了人类的生命是多么脆弱。战争使国家陷入黑暗。确实如此,我们可以从太空中看到。从 1992 年到 2013 年,两场战争开始了,我想我应该看看这些。

Left: Nightlights of Iraq in 2002. Right: Nightlights of Iraq in 2005

美国在 2003 年入侵伊拉克,声称伊拉克拥有大规模杀伤性武器。所以我们可以看到,与战争期间的 2005 年(右图)相比,2002 年伊拉克的夜晚更加明亮。

Left: Syria in 2010. Right: Syria in 2013

叙利亚内战始于 2011 年 3 月,持续至今。2010 年是叙利亚战争爆发的前一年,2013 年是该数据集可用的最后一年。在这三年里,你可以看到叙利亚陷入了黑暗。

现场对我的朋友大声喊出来

在这个瞬息万变的世界里,夜灯每天都在以非常精细的级别(100 米的分辨率)更新,以提供最新的信息。相比之下,像人口普查这样的数据集大约每 10 年更新一次!

这可以帮助你根据他们的增长情况决定你应该扩展到哪个城市,或者你应该在一个城市内的哪一组地点集中你的发布或营销工作,以这个值作为经济活动的代表。然而,处理这些数据本身就是一个巨大而独特的挑战。你需要大规模地处理它,校正云、森林火灾和太阳耀斑。

如果您想在您的模型中使用这些即插即用的见解,请点击这些人吧!!

光有黑暗的一面

到目前为止,我只谈到了光是和平与繁荣的象征,但故事还有另一面。夜灯也会引起一些问题,这就是为什么它被称为“光污染”的原因。

夜间迁徙的候鸟进化成了跟随远处昏暗的灯光,但现在它们被城市的灯光弄糊涂了,它们绕着亮着灯的建筑物转,由于疲惫而坠落。由于夜灯,每年有数百万只鸟死亡。

动物王国里有一些物种,比如蜣螂,进化到以乳道为参照来导航,但是夜晚的灯光让它看不见。这是一个可视化的展示,展示了它是如何让牛奶通道消失的。

Bortle Scale of Nightlight pollution

情况变得如此糟糕,以至于大多数住在城市的人已经忘记了牛奶路是什么样子。我最近在巴基斯坦的科希斯坦山徒步旅行,过了很久才看到这条奶道。我能看到它是因为这是一个偏远的地区,几乎没有夜灯,没有云,而且是新月。让我给你看看它是什么样子的。

Milkyway in Jahaz Banda meadows of Kohistan mountain range

我敢打赌,你们中的一些人(如果不是大多数人)从来没有见过这样的牛奶通道,城市灯光是罪魁祸首。顺便说一句,上面照片中穿黑色夹克的是我。

夜灯不仅对环境有害。甚至我们人类已经进化到天黑时睡觉,白天醒来。夜晚太多的光线会让我们误以为现在还是白天,这会导致失眠和其他健康问题。

我是拉米兹·萨米。我爬山、举重、构建 WebGIS 解决方案。在 Linkedin 上随时与我联系。

插图:10 个 CNN 架构

原文:https://towardsdatascience.com/illustrated-10-cnn-architectures-95d78ace614d?source=collection_archive---------0-----------------------

What architecture is this? 🤔

里面的艾

普通卷积神经网络的编译可视化

(TL;DR —此处跳转到插图)

变更日志:
2022 年 1 月 5 日—修复错别字并提高清晰度
2020 年 11 月 28 日—更新了每个 CNN 的“最新消息”
2020 年 11 月 17 日—编辑了从 4096 到 1000 的 Inceptionv1 的最后一个密集层的层数
2020 年 9 月 24 日—编辑了 ResNeXt-50 的“最新消息”部分

你是如何跟上不同的卷积神经网络(CNN)的?近年来,我们见证了无数 CNN 的诞生。这些网络已经变得如此之深,以至于很难想象整个模型。我们不再跟踪他们,把他们当作黑箱模型。

好吧,也许你不知道。但如果你也有罪,那么嘿,你来对地方了!这篇文章是 10 个常见的 CNN 架构的可视化,由你的忠实读者亲自挑选。这些插图提供了整个模型的更紧凑的视图,而不必为了查看 softmax 层而向下滚动几次。除了这些图像,我还写了一些笔记,说明它们是如何随着时间的推移而“演变”的——从 5 到 50 个卷积层,从普通卷积层到模块,从 2-3 个塔到 32 个塔,从 7⨉7 到 5⨉5—,但后面会有更多内容。

我说的‘常见’,是指那些预先训练好的权重通常被深度学习库(如 TensorFlow、Keras、PyTorch)共享给用户使用的模型,以及通常在课堂上教授的模型。这些模型中的一些已经在类似于 ImageNet 大规模视觉识别挑战赛 (ILSVRC)的比赛中取得了成功。

The 10 architectures that will be discussed and the year their papers were published.

Pre-trained weights are available in Keras for 6 of the architectures that we will talk about. Adapted from a table in the Keras documentation.

写这篇文章的动机是,没有很多博客和文章有这些紧凑的可视化(如果你知道任何,请与我分享)。所以我决定写一个给大家参考。为了这个目的,我阅读了论文和代码(大部分来自 TensorFlow 和 Keras ),提出了这些 vizzes。

这里我想补充一点,我们在野外看到的过多的 CNN 架构是许多事情的结果——改进的计算机硬件、ImageNet 竞争、解决特定任务、新想法等等。谷歌的研究员克里斯蒂安·塞格迪曾经提到

“这些进步不仅仅是更强大的硬件、更大的数据集和更大的模型的结果,更主要的是新思想、算法和改进的网络架构的结果。”(Szegedy 等人,2014 年)

现在,让我们继续研究这些野兽,观察网络架构如何随着时间的推移而改进!

关于可视化的说明 注意,我已经排除了插图中卷积滤波器、填充、步幅、漏失和展平操作的数量。

目录(按出版年份排序)

  1. LeNet-5
  2. AlexNet
  3. VGG-16
  4. 盗梦空间-v1
  5. 盗梦空间-v3
  6. ResNet-50
  7. 异常
  8. 盗梦空间-v4
  9. 盗梦空间
  10. ResNeXt-50

神话;传奇

1.LeNet-5 (1998 年)

Fig. 1: LeNet-5 architecture, based on their paper

LeNet-5 是最简单的架构之一。它有 2 个卷积层和 3 个全连接层(因此是“5”——神经网络的名称通常来自它们拥有的卷积层全连接层)。我们现在知道的平均池层被称为子采样层,它具有可训练的权重(这不是当今设计 CNN 的当前实践)。这个架构大约有60000 个参数

⭐️What's 小说?

这种架构已经成为标准的“模板”:堆叠具有激活功能的卷积,汇集层,并以一个或多个完全连接的层结束网络。

📝出版物

2.AlexNet (2012 年)

Fig. 2: AlexNet architecture, based on their paper.

有了 60M 参数,AlexNet 有 8 层——5 层卷积,3 层全连接。AlexNet 刚刚在 LeNet-5 上又堆了几层。在发表时,作者指出,他们的架构是“迄今为止 ImageNet 子集上最大的卷积神经网络之一。”

⭐️What's 小说?

  1. 他们首先实现了作为激活函数的整流线性单元(ReLUs)。
  2. 辍学。

📝出版物

3.VGG-16 (2014 年)

Fig. 3: VGG-16 architecture, based on their paper.

到现在为止,你可能已经注意到 CNN 开始越来越深入。这是因为提高深度神经网络性能的最直接的方法是增加它们的大小(Szegedy 等人。al)。视觉几何小组(VGG)的人发明了 VGG-16,它有 13 个卷积层和 3 个全连接层,带有来自 AlexNet 的 ReLU 传统。该网络在 AlexNet 上堆叠更多层,并使用较小尺寸的过滤器(2×2 和 3×3)。它由138m参数组成,占用大约 500MB 的存储空间😱。他们还设计了一种更深的变体,VGG-19。

⭐️What's 小说?

  1. 正如他们在摘要中提到的,这篇论文的贡献是设计了更深层次的网络(大约是 AlexNet 的两倍)。这是通过堆积均匀的回旋来实现的。

📝出版物

4.《盗梦空间》第一版(2014 年)

Fig. 4: Inception-v1 architecture. This CNN has two auxiliary networks (which are discarded at inference time). Architecture is based on Figure 3 in the paper.

这个拥有 5M 参数的 22 层架构被称为 Inception-v1。这里,网络中的网络(参见附录)方法被大量使用,如论文中所述。网络中的网络通过初始模块实现。一个初始模块的架构设计是对近似稀疏结构进行研究的产物(更多信息请阅读本文!).每个模块提出 3 个想法:

  1. 并行塔的卷积具有不同的滤波器,然后级联,在 1×1、3×3 和 5×5 捕获不同的特征,从而“聚集”它们。这一想法是由 Arora 等人在论文中提出的,论文提出了一种逐层结构,在这种结构中,应该分析最后一层的相关性统计数据,并将它们聚类到具有高相关性的单元组中。
  2. 1×1 卷积用于降维以消除计算瓶颈。
  3. 由于来自 1×1 卷积的激活函数,其加法也增加了非线性。这个想法是基于网络论文中的网络。此处见附录
  4. 作者还引入了和两个辅助分类器,以鼓励在分类器的较低阶段进行区分,增加传播回来的梯度信号,并提供额外的正则化。辅助网络(连接到辅助分类器的分支)在推理时被丢弃。

值得注意的是,“这种架构的主要特点是提高了网络内部计算资源的利用率。”

注: 模块的名称(Stem 和 Inception)在这个版本的 Inception 中没有使用,直到后来的版本,即 Inception-v4 和 Inception-ResNets。为了便于比较,我在这里添加了它们。

⭐️What's 小说?

  1. 使用模块/块构建网络。我们不是堆叠卷积层,而是堆叠模块或块,模块或块内是卷积层。因此得名《盗梦空间》(参照 2010 年由莱昂纳多·迪卡普里奥主演的科幻电影《盗梦空间》)。

📝出版物

  • 论文:用卷积深化
  • 作者:克里斯蒂安·塞格迪、、贾、Pierre Sermanet、Scott Reed、Dragomir Anguelov、Dumitru Erhan、Vincent Vanhoucke、Andrew Rabinovich。谷歌、密歇根大学、北卡罗来纳大学
  • 发表于:2015 年 IEEE 计算机视觉和模式识别会议(CVPR)

5.《盗梦空间》第三版(2015 年)

*Fig. 5: Inception-v3 architecture. This CNN has an auxiliary network (which is discarded at inference time). Note: All convolutional layers are followed by batch norm and ReLU activation. Architecture is based on their GitHub code.

Inception-v3 是 Inception-v1 的后继版本,有 24M 参数。等等,盗梦空间 v2 在哪里?不用担心——它是 v3 的早期原型,因此它与 v3 非常相似,但不常用。当作者推出 Inception-v2 时,他们在上面运行了许多实验,并记录了一些成功的调整。Inception-v3 是结合了这些调整的网络(对优化器、损失函数的调整以及对辅助网络中的辅助层添加批量归一化)。

Inception-v2 和 Inception-v3 的动机是避免表示瓶颈(这意味着极大地减少下一层的输入维度),并通过使用因式分解方法进行更有效的计算。

注: 模块名称(Stem,Inception-A,Inception-B 等。)直到它的更高版本,即 Inception-v4 和 Inception-ResNets,才被用于这个版本的 Inception。为了便于比较,我在这里添加了它们。

⭐️What's 小说?

  1. 首批使用批量标准化的设计者之一(为简单起见,上图中没有反映)。

✨What's 改进自上一版本, 盗梦空间-v1

  1. n × n 卷积分解为非对称卷积:1×n 和 n ×1 卷积
  2. 将 5×5 卷积分解为两个 3×3 卷积运算
  3. 用一系列 3×3 卷积替换 7×7

📝出版物

  • 论文:反思计算机视觉的初始架构
  • 作者:克里斯蒂安·塞格迪,文森特·范霍克,谢尔盖·约菲,黄邦贤·施伦斯,兹比格涅夫·沃伊纳。谷歌,伦敦大学学院
  • 发表于:2016 年 IEEE 计算机视觉与模式识别会议(CVPR)

6.ResNet-50 (2015 年)

Fig. 6: ResNet-50 architecture, based on the GitHub code from keras-team.

没错,就是你在文章上方看到的问题的答案这里(“这是什么架构?”).

从过去的几个 CNN 中,我们只看到设计中的层数越来越多,性能越来越好。但是“随着网络深度的增加,精确度会饱和(这并不奇怪),然后迅速下降。”微软研究院的人用 ResNet 解决了这个问题——在构建更深层次的模型时使用跳过连接(也称为快捷连接,残差)。

ResNet 是批量标准化的早期采用者之一(Ioffe 和 Szegedy 撰写的批量标准化论文已于 2015 年提交给 ICML)。上图是 ResNet-50,参数 26M

ResNets 的基本构造块是 conv 和标识块。因为它们看起来很像,你可能会把 ResNet-50 简化成这样(这个不要引用我的话!):

⭐️有什么小说?

  1. **普及跳过连接(他们不是第一个使用跳过连接的)。
  2. 设计更深层次的 CNN(多达 152 层),而不影响模型的泛化能力
  3. 首批使用批量标准化的公司之一。

📝出版物

7.例外(2016 年)

Fig. 7: Xception architecture, based on the GitHub code from keras-team. Depthwise separable convolutions are denoted by ‘conv sep.’

例外是对 Inception 的改编,其中 Inception 模块已经被深度方向可分离的卷积所取代。它还拥有与 Inception-v1 大致相同数量的参数( 23M )。

Xception 将盗梦假设发挥到了极致(因此得名)。什么是盗梦空间假说?谢天谢地,这篇论文明确而简洁地提到了这一点(谢谢弗朗索瓦!).**

  • 首先,通过 1×1 卷积获得跨通道(或跨特征图)相关性。
  • 因此,每个通道内的空间相关性通过常规的 3×3 或 5×5 卷积来捕获。

将这一想法发挥到极致意味着每个通道执行 1×1 到,然后每个通道执行 3×3 到的输出。这等同于用深度方向可分离的卷积替换初始模块。

⭐️What's 小说?

  1. 介绍了完全基于深度方向可分离卷积层的 CNN。

📝出版物

8.《盗梦空间》第 4 版(2016 年)

*Fig. 8: Inception-v4 architecture. This CNN has an auxiliary network (which is discarded at inference time). Note: All convolutional layers are followed by batch norm and ReLU activation. Architecture is based on their GitHub code.

谷歌的人又用 Inception-v4, 43M 参数罢工了。同样,这是对 Inception-v3 的改进。主要区别是 Stem 组和 Inception-C 模块中的一些小变化。作者还“为每个网格大小的初始块做了统一的选择。”他们还提到,拥有“剩余连接可以显著提高训练速度。”

总之,请注意,它提到了 Inception-v4 工作得更好,因为增加了模型大小。

✨What's 改进自上一版本, 盗梦空间-v3

  1. 阀杆模块的变化。
  2. 添加更多的初始模块。
  3. Inception-v3 模块的统一选择,意味着对每个模块使用相同数量的过滤器。

📝出版物

9.《盗梦空间》-ResNet-V2 (2016 年)

*Fig. 9: Inception-ResNet-V2 architecture. Note: All convolutional layers are followed by batch norm and ReLU activation. Architecture is based on their GitHub code.

在与 Inception-v4 相同的论文中,相同的作者还介绍了 Inception-ResNet——Inception-ResNet-v1 和 Inception-ResNet-v2 的家族。家族的后一个成员有 56M 参数。

✨What's 改进自上一版本, 《盗梦空间》-v3

  1. 将初始模块转换成剩余初始块。
  2. 添加更多的初始模块。
  3. 在 Stem 模块之后添加一个新类型的初始模块(Inception-A)。

📝出版物

10.ResNeXt-50 (2017 年)

Fig. 10: ResNeXt architecture, based on their paper.

如果你在想 ResNets,是的,它们是相关的。ResNeXt-50 有 25M 参数(ResNet-50 有 25.5M)。ResNeXts 的不同之处在于在每个模块中添加了并行的塔/分支/路径,如上面“总共 32 个塔”所示

⭐️有什么小说?

  1. 扩大一个模块中并行塔的数量(“基数”)(我的意思是这已经被 Inception network 探索过了,除了这些塔是在这里添加的)

📝出版物

  • 论文:深度神经网络的聚合残差变换
  • 作者:谢赛宁,罗斯·吉斯克,彼得·多拉尔,涂,何。加州大学圣地亚哥分校脸书研究所
  • 发表于:2017 年 IEEE 计算机视觉与模式识别会议(CVPR)

附录:网络中的网络(2014)

回想一下,在卷积中,像素值是过滤器和当前滑动窗口中权重的线性组合。作者建议用一个带有一个隐藏层的迷你神经网络来代替这种线性组合。这就是他们创造的 Mlpconv。因此,我们在这里处理的是(卷积神经)网络中的(简单的 1 个隐藏层)网络。

Mlpconv 的这种思想被比作 1×1 卷积,后来成为初始架构的主要特征。

⭐️What's 小说?

  1. MLP 卷积层,1×1 卷积
  2. 全局平均池(取每个特征地图的平均值,并将结果向量送入 softmax 层)

📝出版物

  • 论文:网络中的网络
  • 作者:,,水城颜。新加坡国立大学
  • arXiv 预印本,2013 年

为了便于参考,我们在这里再展示一次:

LeNet-5

AlexNet

VGG-16

盗梦空间-第一版

盗梦空间-第三版

盗梦空间-第 4 版

盗梦空间-ResNet-V2

例外

ResNet-50

ResNeXt-50

神经网络可视化资源

这里有一些资源供你想象你的神经网络:

类似文章

CNN 架构:LeNet、AlexNet、VGG、GoogLeNet、ResNet 等等。

盗梦空间网络版本的简单指南

参考

我参考了上面提到的产生这些架构的论文。除此之外,下面是我在本文中使用的一些其他方法:

https://github . com/tensor flow/models/tree/master/research/slim/nets(github.com/tensorflow)

Keras 团队深度学习模型的实现(github.com/keras-team)

卷积神经网络架构讲义:从 LeNet 到 ResNet(slazebni.cs.illinois.edu)

回顾:NIN —网络中的网络(图像分类)(towardsdatascience.com)

你在观想中注意到什么错误了吗?你觉得我还应该包括什么吗?在下面给我留言吧!

如果你喜欢我的内容并且还没有订阅 Medium,请通过我的推荐链接 这里 订阅!注意:你的会员费的一部分将作为介绍费分配给我。

特别感谢狄强、齐威、任杰、傅楠、希尔琳和德里克审阅本文。

关注我上 推特 @remykarem 或者LinkedIn。你也可以通过 raimi.bkarim@gmail.com 联系我。欢迎访问我的网站remykarem . github . io**

图解:有效的神经结构搜索

原文:https://towardsdatascience.com/illustrated-efficient-neural-architecture-search-5f7387f9fb6?source=collection_archive---------4-----------------------

内部 AI

ENAS 宏观和微观搜索策略指南

(TL;DR 你只需要知道的两个动画是 这里 )

更新:
2020 年 3 月 23 日:勘误表—之前提到过,micro search 中的所有卷积单元互不相同。这是错误的;卷积单元是
在最终的子模型中多次重复 。作者核实了这一信息。感谢 马丁·费利安 的指正!

为图像分类和自然语言理解等各种任务设计神经网络通常需要大量的架构工程和专业知识。进入神经架构搜索 (NAS),这是一个自动化人工设计神经网络过程的任务。NAS 将其日益增长的研究兴趣归功于最近深度学习模型的日益突出。

有许多方法可以搜索或发现神经结构。在过去的几年中,社区已经提出了不同的搜索方法,包括:

在本帖中,我们将关注高效神经架构搜索** (ENAS),它采用强化学习来构建卷积神经网络(CNN)和递归神经网络(RNNs)。作者 Hieu Pham、Melody Guan、Barret Zoph、Quoc V. Le 和 Jeff Dean 提出了一个预定义的神经网络,以使用宏搜索微搜索在增强学习框架的指导下生成新的神经网络(参见论文此处)。没错——一个神经网络构建另一个神经网络。**

这篇文章是一篇关于宏观和微观搜索策略如何产生神经网络的教程。虽然插图和动画用于指导读者,但动画的顺序并不一定反映操作流程(由于矢量化等原因)。).

我们将把本教程的范围缩小到在图像分类任务中搜索 CNN 的神经结构。本文假设读者熟悉 RNNs、CNN 和强化学习的基础知识。熟悉像迁移学习和跳过/剩余连接这样的深度学习概念将非常有帮助,因为它们在架构搜索中被大量使用。这并不要求你阅读这篇论文,但它会加快你的理解。

内容

0.概述1。搜索策略
1.1。宏搜索
1.2。微搜
2。注释注释
3。概要4。实现
5。参考文献

0.概观

在 ENAS,有两种类型的神经网络:

  • ****控制器–预定义的 RNN,是一种长短期记忆(LSTM)单元
  • ****子模型–用于图像分类的理想 CNN

像大多数其他 NAS 算法一样,ENAS 涉及 3 个概念:

  1. ****搜索空间——所有可能产生的不同架构或子模型
  2. 搜索策略 —生成这些架构或子模型的方法
  3. 性能评估 —衡量生成的子模型有效性的方法

让我们看看这五个想法是如何形成 ENAS 故事的。

控制器通过使用某种搜索策略**“生成一组指令”(或者更严格地说,做出决策采样 决策)来控制或指导子模型架构的构建。这些决定是像什么类型的操作(卷积,池等。)在子模型的特定层执行。使用这些决定,建立一个子模型。生成的子模型是可以在搜索空间中构建的许多可能的子模型之一。**

然后,使用随机梯度下降将该特定子模型训练至收敛(约 95%的训练精度),以最小化预测类和地面真实类之间的预期损失函数(对于图像分类任务)。这是在指定数量的时期内完成的,我称之为子时期,比如 100。然后,从该训练的模型获得验证准确度。

然后,我们使用基于策略的强化学习算法来更新控制器的参数,以最大化期望奖励函数,即验证准确性。这个参数更新希望改进控制器,以产生更好的决定,给出更高的验证精度。

这整个过程(从之前的 3 个段落开始)只是一个时期——姑且称之为控制器时期。然后,我们对指定数量的控制器时期重复这一过程,比如 2000 个。

在所有生成的 2000 个子模型中,具有最高验证准确性的模型将获得的荣誉,成为执行图像分类任务的神经网络。然而,这个子模型在用于部署之前,必须再经过一轮训练(同样由子时期的数量指定)。

整个训练的伪算法写在下面:

CONTROLLER_EPOCHS = 2000
CHILD_EPOCHS = 100Build controller networkfor i in CONTROLLER_EPOCHS: 1\. Generate a child model
     2\. Train this child model for CHILD_EPOCHS
     3\. Obtain val_acc
     4\. Update controller parametersGet child model with the highest val_acc
Train this child model for CHILD_EPOCHS

这整个问题本质上是一个具有原型元素的强化学习框架:

  • 代理—控制器
  • 行动——建立子网络的决策
  • 奖励—来自子网络的验证准确性

这个强化学习任务的目的是最大化代理(控制器)所采取的行动(建立子模型架构的决策)的回报(验证准确性)。

[ 返回页首

1.搜索策略

回想一下上一节,控制器使用某种搜索策略生成子模型的架构。在这个陈述中,你应该问两个问题——(1)管制员如何做决定,以及(2)什么样的搜索策略?

管制员如何决策?

这就把我们带到了控制器的模型,这是一个 LSTM。该 LSTM 通过 softmax 分类器以自动回归的方式对决策进行采样:前一步中的决策作为输入嵌入到下一步中。

有哪些搜索策略?

ENAS 的作者提出了搜索或生成架构的两个策略。

  1. 宏搜索
  2. 微搜索

宏搜索是一种控制器设计整个网络的方法。使用这种方法的出版物包括 Zoph 和 Le 的 NAS、FractalNet 和 SMASH。另一方面,微搜索是一种方法,其中控制器设计模块或构建块,它们被组合以构建最终网络。实现这种方法的一些论文是分层 NAS、渐进式 NAS 和 NASNet。

在以下两个小节中,我们将了解 ENAS 是如何实施这两项战略的。

[ 宏搜索 ][ 微搜索 ]

1.1 宏搜索

在宏搜索中,控制器为子模型中的每一层做出 2 个决定:

  • 对上一层执行的操作(操作列表见注释)
  • 跳过连接时要连接到的上一层

在这个宏搜索示例中,我们将看到控制器如何生成 4 层子模型。这个子模型中的每一层分别用红色、绿色、蓝色和紫色进行颜色编码。

卷积层 1(红色)

我们将从运行控制器的第一个时间步开始。这个时间步骤的输出被软最大化以获得一个向量,该向量被转换成一个conv3×3操作。

这对子模型意味着,我们在输入图像上用 3×3 滤波器执行卷积。

The output from the first time step (conv3×3) of the controller corresponds to building the first layer (red) in the child model. This means the child model will first perform 3×3 convolution on the input image.

我知道我提到过管制员需要做出两个决定,但这里只有一个。由于这是第一层,我们只能对要执行的操作中的一个决策进行采样,因为除了输入图像本身之外,没有其他要连接的内容。

卷积层 2(绿色)

为了构建随后的卷积层,控制器做出 2 个决定(没有更多谎言):(I)操作和(ii)要连接的层。在这里,我们看到它生成了1sep5×5

这对于子模型意味着我们首先对前一层的输出执行sep5×5 操作。然后,该输出沿着深度与层1的输出连接在一起,即红色层的输出。****

The outputs from the 2nd and 3rd time step (1** and sep5×5) in the controller correspond to building Convolutional Layer 2 (green) in the child model.**

卷积层 3(蓝色)

我们再次重复上一步以生成第三卷积层。同样,我们在这里看到控制器生成 2 个东西:(I)操作和(ii)要连接的层。下面,控制器产生12,以及操作max3×3

因此,子模型对前一层(第 2 层,绿色)的输出执行操作max3×3 。然后,该操作的结果沿着深度维度与层12连接。

The outputs from the 4th and 5th time step (1,2** and max3×3) in the controller correspond to building Convolutional Layer 3 (blue) in the child model.**

卷积层 4(紫色)

我们再次重复上一步以生成第四卷积层。这次控制器产生了13,以及操作conv5×5

子模型对前一层(第三层,蓝色)的输出执行操作conv5×5 。然后,该操作的结果沿着深度维度与层13连接。

The outputs from the 6th and 7th time step (1,3** and conv5×5) in the controller correspond to building Convolutional Layer 4 (purple) in the child model.**

结束

现在,您有了它——一个使用宏搜索生成的子模型!现在转到微搜索。

[ 返回顶部

1.2 微搜索

微搜索仅设计一个构建块,其架构在整个最终架构中重复。ENAS 称这个构建模块为卷积单元归约单元。两者是相似的——约简单元的唯一不同之处是运算的步长为 2,从而减少了空间维度。

微搜索的想法是为卷积单元构建一个单一的架构,并在整个最终模型中重复这个相同的架构。在下面的例子中,最终模型由一个卷积单元组成,其架构在 3 个模块中重复 N 次。如前所述,归约单元类似于卷积单元的架构。

Fig. 1.2.1: Overview of the final neural network generated. Image source.

让我们过一会儿再回到这个话题。

为微搜索导出的网络构建单元

从微搜索衍生的子网络的“构建单元”中有一种等级制度。从最大到最小:

  • 街区
  • 卷积单元/归约单元
  • 结节

子模型由几个模块组成。每个块由 N 个卷积单元和 1 个归约单元组成。每个卷积/归约单元包括B节点。并且每个节点都由标准卷积运算组成(我们稍后会看到这一点)。( NB 是超参数,可以由你这个架构师来调优。)

下面是一个有 3 个积木的子模型。每个块由 N =3 个卷积单元和 1 个归约单元组成。这里没有显示每个单元内的操作。

Fig. 1.2.2: Overview of the final neural network generated. It has 3 blocks and each block consists of 3 convolutional cells and 1 reduction cell. Image source.

那么你可能会问,如何从微搜索生成这个子模型呢?继续读!

通过微搜索生成子模型

对于这个微搜索教程,为了简单起见,让我们构建一个有 1 个块的子模型。该块包括 N =3 个卷积单元和 1 个归约单元,每个单元包括 B =4 个节点。

回想一下,这意味着只需为一个卷积单元设计一个架构,然后重复 3 次以上(2 个以上的卷积单元和 1 个归约单元)。这意味着我们生成的子模型应该如下所示:

Fig. 1.2.3: A neural network generated from micro search which has 1 block, consisting of 3 convolutional cells and 1 reduction cell. The individual operations are not shown here.

现在让我们构建一个卷积单元!

为了解释如何建立一个卷积单元,让我们假设我们已经有 2 个卷积单元。请注意,这两个单元的最后一个操作是add操作。

Fig. 1.2.5: ‘Preparing’ the third convolutional cell in micro search.

回想一下,一个卷积单元由 4 个节点组成。那么这些节点在哪里呢?

节点 1 和节点 2

前两个单元格 (红色和蓝色)将分别被视为节点 1 和节点 2。其他两个节点就在我们现在正在构建的这个卷积单元中。

Fig. 1.2.6: Identifying the 4 nodes while building Convolutional Cell #3.

从本节开始,您可以放心地忽略上图中的“卷积单元”标签,而专注于“节点”标签:

  • 节点 1 —红色
  • 节点 2 —蓝色
  • 节点 3 —绿色
  • 节点 4 —紫色

勘误 i̶f̶̶y̶o̶u̶'̶r̶e̶̶w̶o̶n̶d̶e̶r̶i̶n̶g̶̶i̶f̶̶t̶h̶e̶s̶e̶̶n̶o̶d̶e̶s̶̶w̶i̶l̶l̶̶c̶h̶a̶n̶g̶e̶̶f̶o̶r̶̶e̶v̶e̶r̶y̶̶c̶o̶n̶v̶o̶l̶u̶t̶i̶o̶n̶a̶l̶̶c̶e̶l̶l̶̶w̶e̶'̶r̶e̶̶b̶u̶i̶l̶d̶i̶n̶g̶,̶̶t̶h̶e̶̶a̶n̶s̶w̶e̶r̶̶i̶s̶̶y̶e̶s̶!̶̶e̶v̶e̶r̶y̶̶c̶e̶l̶l̶̶w̶i̶l̶l̶̶'̶a̶s̶s̶i̶g̶n̶'̶̶t̶h̶e̶̶n̶o̶d̶e̶s̶̶i̶n̶̶t̶h̶i̶s̶̶m̶a̶n̶n̶e̶r̶.̶

节点 3

节点 3 是建筑的起点。控制器采样 4 个决策(或者说 2 组决策):

  • 要连接的 2 个节点
  • 要在要连接的节点上执行的两个操作

有 4 个决策要做,控制器运行 4 个时间步。请看下面:

Fig. 1.2.7: The outputs of the first four controller time steps (2, 1, **avg5×5**, **sep5×5**), which will be used to build Node 3.

从上面我们看到,控制器从四个时间步长的每一个采样节点2、节点1avg5×5sep5×5。这如何转化为子模型的架构?让我们看看:

Fig. 1.2.8: How the outputs of the first four controller time steps (2, 1, **avg5×5**, **sep5×5**) are translated to build Node 3.

从上面,我们观察到三件事:

  1. 节点2(蓝色)的输出经过avg5×5操作。
  2. 节点1(红色)的输出经过sep5×5运算。
  3. 这两个操作的结果都经过一个add操作。

来自该节点的输出是经过add运算的张量。这解释了为什么节点 1 和 2 以add操作结束。

节点 4

现在是节点 4。我们重复相同的步骤,但是现在控制器有三个节点可供选择(节点 1、2 和 3)。下面,控制器生成31idavg3×3

Fig. 1.2.9: The outputs of the first four controller time steps (3, 1, **id**, **avg3×3**), which will be used to build Node 4.

这转化为构建以下内容:

Fig. 1.2.10: How the outputs of the first four controller time steps (3, 1, **id**, **avg3×3**) are translated to build Node 3.

刚刚发生了什么?

  1. 节点3的输出(绿色)经过id运算。
  2. 节点1的输出(红色)经过avg3×3运算。
  3. 这两个操作的结果都经过一个add操作。

就是这样!最终子模型中的所有卷积单元将共享相同的架构。类似地,最终子模型中的所有归约单元(其架构与卷积单元的架构不同,具有步长 2 运算)将共享相同的架构。

Fig. 1.2.11: An example of a convolution cell (with 7 nodes) discovered in the micro search space (credits).

Fig. 1.2.12: An example of a reduction cell (with 7 nodes) discovered in the micro search space (credits).

[ 返回顶部

2.笔记

因为这篇文章主要展示了宏观和微观的搜索策略,所以我忽略了许多小细节(尤其是关于迁移学习的概念)。让我简单介绍一下:

  • ENAS 有什么这么“高效”?答案:迁移学习。如果两个节点之间的计算之前已经完成(训练),则来自卷积滤波器和 1×1 卷积的权重(以保持信道输出的数量;在前面的章节中没有提到)将被重用。这就是 ENAS 比它的前辈更快的原因!
  • 控制器有可能对不需要跳过连接的决策进行采样。
  • 控制器有 6 种操作:滤波器大小为 3×3 和 5×5 的卷积,滤波器大小为 3×3 和 5×5 的深度可分卷积,内核大小为 3×3 的最大池和平均池。
  • 请仔细阅读每个单元格末尾的 concatenate 操作,它将任何节点的“松散端”连接起来。
  • 请简要阅读政策梯度算法(强化)强化学习。

[ 返回页首

3.摘要

宏搜索(针对整个网络)

最终的子模型如下所示。

Fig. 3.1: Generating a convolutional neural network with macro search.

微搜索(针对卷积小区)

注意,这里只显示了最终子模型的一部分。

Fig. 3.2: Generating a convolutional neural network with micro search. Only part of the full architecture is shown.

[ 返回页首

4.履行

[ 返回页首

5.参考

通过参数共享进行有效的神经结构搜索

具有强化学习的神经架构搜索

学习可扩展图像识别的可转移架构

就是这样!记得阅读 ENAS 的论文通过参数共享进行有效的神经架构搜索。如果您有任何问题,请突出显示并留下评论。

其他关于深度学习的文章

一般

统计深度学习模型中的参数数量

与 NLP 相关

动画版的 RNN、LSTM 和 GRU

经办人:图文并茂

画报:自我关注

逐行 Word2Vec 实现

与计算机视觉相关

分解平均平均精度(mAP)

优化

带随机梯度下降的线性回归分步指南

10 种梯度下降优化算法+备忘单

关注我上 推特 @remykarem 或者LinkedIn。你也可以通过 raimi.bkarim@gmail.com 联系我。欢迎访问我的网站remykarem . github . io**

插图:自我关注

原文:https://towardsdatascience.com/illustrated-self-attention-2d627e33b20a?source=collection_archive---------0-----------------------

内部人工智能

带插图和代码的自我关注循序渐进指南

插图最好在桌面上看。一个 Colab 版本可以在这里找到*(感谢* 罗梅洛 !).

变更日志:
2022 年 12 月 30 日—使用 Medium 的新代码块突出显示语法
2022 年 1 月 12 日—提高清晰度
2022 年 1 月 5 日—修复错别字并提高清晰度

伯特、罗伯塔、艾伯特、斯潘伯特、迪尔伯特、塞姆斯伯特、森伯特、西伯特、比奥伯特、莫比尔伯特、蒂尼伯特和卡门伯特有什么共同点?我不是在寻找答案“伯特”🤭。

回答:自我关注🤗。我们不仅在谈论名为“BERT”的架构,更准确地说,是基于变压器的架构。基于转换器的架构主要用于建模语言理解任务,避免了神经网络中的递归,而是完全依靠自我关注*机制来绘制输入和输出之间的全局依赖关系。但是这背后的数学原理是什么呢?*

这就是我们今天要发现的。这篇文章的主要内容是引导你完成自我关注模块中的数学运算。到本文结束时,您应该能够从头开始编写或编码自我关注模块。

这篇文章的目的不是提供自我关注模块中不同的数字表示和数学运算背后的直觉和解释。它也没有试图证明变形金刚中自我关注的原因和方式(我相信已经有很多了)。注意,本文中也没有详细说明注意力和自我注意力之间的区别。

内容

  1. 插图
  2. 代码
  3. 延伸至变压器

现在让我们开始吧!

0.什么是自我关注?

如果你觉得自我关注也差不多,那么答案是肯定的!它们从根本上共享相同的概念和许多共同的数学运算。

自关注模块接收 n 个输入,并返回 n 个输出。在这个模块中发生了什么?通俗地说,自我注意机制就是让输入相互作用(“自我”),找出自己应该更注意谁(“注意”)。输出是这些交互和注意力分数的集合。

1.插图

插图分为以下几个步骤:

  1. 准备输入
  2. 初始化重量
  3. 导出查询
  4. 计算输入 1 的注意力分数
  5. 计算 softmax
  6. 将分数乘以
  7. 加权求和,得到输出 1
  8. 对输入 2 和输入 3 重复步骤 4-7

实际上,数学运算是矢量化的,即所有的输入一起进行数学运算。我们将在后面的代码部分看到这一点。

步骤 1:准备输入

Fig. 1.1: Prepare inputs

对于本教程,我们从 3 个输入开始,每个输入的维度为 4。

*Input 1: [1, 0, 1, 0] 
Input 2: [0, 2, 0, 2]
Input 3: [1, 1, 1, 1]*

步骤 2:初始化砝码

每个输入必须有三个表示(见下图)。这些表示被称为(橙色)查询(红色),以及(紫色)。对于这个例子,让我们假设我们希望这些表示具有 3 维。因为每个输入的维数为 4,所以每组权重的形状必须为 4×3。

我们后面会看到 的维度也是输出维度。

Fig. 1.2: Deriving key, query and value representations from each input

为了获得这些表示,每个输入(绿色)都要乘以一组的权重、一组查询的权重(我知道这不是正确的拼写),以及一组的权重。在我们的例子中,我们如下初始化三组权重。

的重量:

*[[0, 0, 1],
 [1, 1, 0],
 [0, 1, 0],
 [1, 1, 0]]*

查询的权重:

*[[1, 0, 1],
 [1, 0, 0],
 [0, 0, 1],
 [0, 1, 1]]*

的权重:

*[[0, 2, 0],
 [0, 3, 0],
 [1, 0, 3],
 [1, 1, 0]]*

注释 在神经网络设置中,这些权重通常是小数字,使用适当的随机分布(如高斯、泽维尔和明凯分布)进行随机初始化。该初始化在训练前进行一次。

第三步:导出关键字、查询和值

现在我们有了三组权重,让我们获得每个输入的查询表示。

输入 1 的表示:

 *[0, 0, 1]
[1, 0, 1, 0] x [1, 1, 0] = [0, 1, 1]
               [0, 1, 0]
               [1, 1, 0]*

使用相同的一组权重来获得输入 2 的表示:

 *[0, 0, 1]
[0, 2, 0, 2] x [1, 1, 0] = [4, 4, 0]
               [0, 1, 0]
               [1, 1, 0]* 

使用相同的一组权重来获得输入 3 的表示:

 *[0, 0, 1]
[1, 1, 1, 1] x [1, 1, 0] = [2, 3, 1]
               [0, 1, 0]
               [1, 1, 0]*

更快的方法是将上述操作矢量化:

 *[0, 0, 1]
[1, 0, 1, 0]   [1, 1, 0]   [0, 1, 1]
[0, 2, 0, 2] x [0, 1, 0] = [4, 4, 0]
[1, 1, 1, 1]   [1, 1, 0]   [2, 3, 1]*

Fig. 1.3a: Derive key representations from each input

让我们做同样的事情来获得每个输入的表示:

 *[0, 2, 0]
[1, 0, 1, 0]   [0, 3, 0]   [1, 2, 3] 
[0, 2, 0, 2] x [1, 0, 3] = [2, 8, 0]
[1, 1, 1, 1]   [1, 1, 0]   [2, 6, 3]*

Fig. 1.3b: Derive value representations from each input

最后是查询交涉:

 *[1, 0, 1]
[1, 0, 1, 0]   [1, 0, 0]   [1, 0, 2]
[0, 2, 0, 2] x [0, 0, 1] = [2, 2, 2]
[1, 1, 1, 1]   [0, 1, 1]   [2, 1, 3]*

Fig. 1.3c: Derive query representations from each input

注意事项 实际上,一个偏置向量可能被加到矩阵乘法的乘积上。**

步骤 4:计算输入 1 的关注度分数

Fig. 1.4: Calculating attention scores (blue) from query 1

为了获得注意力分数,我们首先在输入 1 的查询(红色)和所有(橙色)之间取点积,包括它本身。由于有 3 个表示(因为我们有 3 个输入),我们获得 3 个注意力分数(蓝色)。

 *[0, 4, 2]
[1, 0, 2] x [1, 4, 3] = [2, 4, 4]
            [1, 0, 1]*

注意,我们只使用输入 1 中的查询。稍后,我们将对其他查询重复同样的步骤。

注意 以上操作就是众所周知的点积注意,其中的几个* 得分功能其他得分功能包括缩放点积加法/串联。*

第五步:计算 softmax

Fig. 1.5: Softmax the attention scores (blue)

softmax 穿过这些注意力得分(蓝色)。

*softmax([2, 4, 4]) = [0.0, 0.5, 0.5]*

注意,为了可读性,我们在这里四舍五入到小数点后 1 位。

第六步:将分数与数值相乘

Fig. 1.6: Derive weighted value representation (yellow) from multiply value (purple) and score (blue)

每个输入(蓝色)的最大关注分数乘以其相应的(紫色)。这产生了 3 个对准矢量(黄色)。在本教程中,我们将它们称为加权值

*1: 0.0 * [1, 2, 3] = [0.0, 0.0, 0.0]
2: 0.5 * [2, 8, 0] = [1.0, 4.0, 0.0]
3: 0.5 * [2, 6, 3] = [1.0, 3.0, 1.5]*

步骤 7:加权值求和得到输出 1

Fig. 1.7: Sum all weighted values (yellow) to get Output 1 (dark green)

取所有加权 (黄色)并按元素求和:

 *[0.0, 0.0, 0.0]
+ [1.0, 4.0, 0.0]
+ [1.0, 3.0, 1.5]
-----------------
= [2.0, 7.0, 1.5]*

结果向量2.0,7.0,1.5是输出 1,它基于来自输入 1 的查询表示与所有其他键交互,包括它自己。

第 8 步:重复输入 2 &输入 3

现在我们已经完成了输出 1,我们对输出 2 和输出 3 重复步骤 4 到 7。我相信我可以让你自己解决这个问题👍🏼。

Fig. 1.8: Repeat previous steps for Input 2 & Input 3

备注 维度 查询 因为点积得分函数的关系必须始终相同。但是 的维度可能与 查询 不同。结果输出将遵循 的尺寸。**

2.密码

下面是 PyTorch 中的代码🤗,Python 中流行的深度学习框架。要在下面的代码片段中享受用于@操作符、.T**None**索引的 API,请确保您使用的是 Python≥3.6 和 PyTorch 1.3.1。只需跟着做,将这些复制粘贴到 Python/IPython REPL 或 Jupyter 笔记本中。

步骤 1:准备输入

**>>> import torch

>>> x = [
...   [1, 0, 1, 0], # Input 1
...   [0, 2, 0, 2], # Input 2
...   [1, 1, 1, 1], # Input 3
... ]
>>> x = torch.tensor(x, dtype=torch.float32)**

步骤 2:初始化砝码

**>>> w_key = [
...   [0, 0, 1],
...   [1, 1, 0],
...   [0, 1, 0],
...   [1, 1, 0],
... ]
>>> w_query = [
...   [1, 0, 1],
...   [1, 0, 0],
...   [0, 0, 1],
...   [0, 1, 1],
... ]
>>> w_value = [
...   [0, 2, 0],
...   [0, 3, 0],
...   [1, 0, 3],
...   [1, 1, 0],
... ]

>>> w_key = torch.tensor(w_key, dtype=torch.float32)
>>> w_query = torch.tensor(w_query, dtype=torch.float32)
>>> w_value = torch.tensor(w_value, dtype=torch.float32)**

步骤 3:导出密钥、查询和值

**>>> keys = x @ w_key
>>> querys = x @ w_query
>>> values = x @ w_value

>>> keys
tensor([[0., 1., 1.],
        [4., 4., 0.],
        [2., 3., 1.]])

>>> querys
tensor([[1., 0., 2.],
        [2., 2., 2.],
        [2., 1., 3.]])

>>> values
tensor([[1., 2., 3.],
        [2., 8., 0.],
        [2., 6., 3.]])**

第四步:计算注意力得分

**>>> attn_scores = querys @ keys.T
>>> attn_scores
tensor([[ 2.,  4.,  4.],  # attention scores from Query 1
        [ 4., 16., 12.],  # attention scores from Query 2
        [ 4., 12., 10.]]) # attention scores from Query 3**

第五步:计算 softmax

**>>> from torch.nn.functional import softmax

>>> attn_scores_softmax = softmax(attn_scores, dim=-1)
tensor([[6.3379e-02, 4.6831e-01, 4.6831e-01],
        [6.0337e-06, 9.8201e-01, 1.7986e-02],
        [2.9539e-04, 8.8054e-01, 1.1917e-01]])

>>> # For readability, approximate the above as follows
>>> attn_scores_softmax = [
...   [0.0, 0.5, 0.5],
...   [0.0, 1.0, 0.0],
...   [0.0, 0.9, 0.1],
...  ]
>>> attn_scores_softmax = torch.tensor(attn_scores_softmax)**

第六步:将分数与数值相乘

**>>> weighted_values = values[:,None] * attn_scores_softmax.T[:,:,None]
>>> weighted_values
tensor([[[0.0000, 0.0000, 0.0000],
         [0.0000, 0.0000, 0.0000],
         [0.0000, 0.0000, 0.0000]],

        [[1.0000, 4.0000, 0.0000],
         [2.0000, 8.0000, 0.0000],
         [1.8000, 7.2000, 0.0000]],

        [[1.0000, 3.0000, 1.5000],
         [0.0000, 0.0000, 0.0000],
         [0.2000, 0.6000, 0.3000]]])**

步骤 7:加权值求和

**>>> outputs = weighted_values.sum(dim=0)
>>> outputs
tensor([[2.0000, 7.0000, 1.5000],  # Output 1
        [2.0000, 8.0000, 0.0000],  # Output 2
        [2.0000, 7.8000, 0.3000]]) # Output 3**

PyTorch 为此提供了一个 API 叫做 [*nn.MultiheadAttention*](https://pytorch.org/docs/master/nn.html#multiheadattention) 。但是,这个 API 要求您输入键、查询和值 PyTorch 张量。此外,该模块的输出经历线性变换。

3.延伸到变压器

那么,我们该何去何从?变形金刚!事实上,我们生活在深度学习研究和高计算资源的激动人心的时代。变形金刚是来自注意力就是一切的化身,原本是为了执行神经机器翻译而生。研究人员从这里开始,重新组装,切割,添加和扩展部件,并将其应用于更多的语言任务。

在这里,我将简要地提到我们如何将自我关注扩展到一个 Transformer 架构。

在自我关注模块中:

  • 尺寸
  • 偏见

自我关注模块的输入:

  • 嵌入模块
  • 位置编码
  • 缩短
  • 掩饰

添加更多自我关注模块:

  • 多传感头
  • 层堆叠

自我关注模块之间的模块:

  • 线性变换
  • 层状

那都是乡亲们!希望你觉得内容容易消化。你认为我应该在这篇文章中进一步补充或阐述什么吗?请留言!此外,一定要看看下面我创作的一幅插图

参考

你所需要的就是关注(arxiv.org)

图解变压器 (jalammar.github.io)

相关文章

【towardsdatascience.com】经办人:图文并茂

如果你喜欢我的内容并且还没有订阅 Medium,请通过我的推荐链接 这里 订阅!注意:你的会员费的一部分将作为介绍费分配给我。

特别感谢 Xin Jie、Serene、任杰、Kevin 和 Wei Yih 为本文提供想法、建议和更正。

在 Twitter 上关注我@ remykarem关于 AI、ML、深度学习和 Python 的消化文章和其他推文。**

通过时差说明在线学习

原文:https://towardsdatascience.com/illustrating-online-learning-through-temporal-differences-6a09daf61604?source=collection_archive---------36-----------------------

强化学习的基础

介绍

在我们关于 GradientCrescent 强化学习基础的文章中,我们研究了基于模型和基于样本的强化学习方法。简而言之,前一类的特点是需要了解所有可能的状态转移的完整概率分布,并以马尔可夫决策过程为例。相比之下,基于样本的学习方法允许简单地通过重复观察来确定状态值,消除了对转换动态的需要。在我们的上一篇文章中,我们讨论了蒙特卡罗方法在简单地通过环境采样来确定不同状态和行为的值中的应用。

更一般地,蒙特卡罗方法属于离线学习方法家族,就此而言,仅当达到终端状态时,或者在一集结束时,才允许更新状态的值。虽然这种方法对于许多受控或模拟环境来说似乎足够了,但对于需要快速变化的应用来说,比如在自动驾驶汽车的训练中,这种方法就远远不够了。在这种应用中使用离线学习可能会导致事故,因为更新状态值的延迟会导致不可接受的生命或财产损失。

Different agents playing Breakout via OpenAI’s gym utilizing DQN, an online-learning approach based on TD.

因此,今天使用的大多数强化学习算法都被归类为在线学习。换句话说,状态和动作的值是通过一系列的估计不断更新的。这也被称为时间差异学习,是更高级算法的基础,这些算法用于训练代理处理游戏环境,如在 OpenAI Atari 健身房观察到的环境。

时间差异学习

正如在蒙特卡罗中一样,时间差分学习(TD)是一种基于采样的方法,因此不需要模型知识来估计其价值函数。然而,与蒙特卡罗方法不同,TD 是一种在线方法,依赖于具有增量时间步长的剧集内更新。时间差异学习的核心是状态 St,的增量更新函数(“自举”),其特征在于 TD 误差(在底部以红色显示):

Monte Carlo (top) versus Temporal Difference (bottom) update functions.

注意在 TD 更新函数中引入了两个不同的时间步长( tt+1 )。TD 误差包含下一时间步的返回与状态 St+1 的当前估计值之和,并从该和中减去前一状态 St 的值。本质上,我们用在稍后的时间步骤中获得的另一个估计值来更新状态的估计值,在之前对于神经网络观察到的复制梯度下降中。

这在实践中是如何运作的?考虑状态(S)、动作(A)和(奖励)的顺序

由于这种循环行为,我们可以在到达下一个状态时更新前一个状态的值。更正式的定义,

时间差分学习与蒙特卡罗

为了更好地说明在线学习和离线学习的区别,考虑一下预测从办公室回家的路程的例子,这是在阿尔伯塔大学的强化学习课程中引入的。在下面指定的每个位置或州,预测的剩余时间以分钟为单位显示在圆圈内,实际经过的时间显示在每个州之间。

Locations, predictions, and time elapsed on a trip home from the office

让我们首先使用蒙特卡罗方法。我们将等待这一集结束,以获取旅行的实际总耗时,然后通过用返回更新值来更新我们的每个状态。因此,在出发点(离开)的情况下,我们可以累积我们的回报(在这种情况下没有折扣因子),并在剧集结束时更新其值,如下所示:

类似地,我们可以通过使用 38 的实际运行返回来更新下一个状态的估计值 35:

然后,我们依次对每个中间目的地重复这一过程,并实现最终更新,如下所示:

因此,我们的状态值现在更好地反映了我们旅行的实际花费时间。但是,请注意我们是如何不得不等到旅程结束时才执行更新的。如果我们的旅行目标是在特定时间在中间目的地取包裹,会怎么样?延迟更新可能会导致明显的延迟。

让我们使用时间差异分析来重复我们的估计。使用我们新的估计和实际经过的时间,我们可以使用时间差分析来更新我们先前的初始估计。从办公室 (t) 出发,估计要 30 分钟才能到家。然而,在五分钟 (t+1) 后到达“退出”状态,我们发现我们落后于计划,因此将时间步长 t 的剩余时间更新为 40 分钟。

继续前行,我们需要 15 分钟到达“出口高速公路”,从那里我们估计还需要 15 分钟才能到家。由于这比我们预期的要快,我们可以用这个增量回报来更新我们之前的估计:

我们可以在整个旅程中重复这个过程。

比较这两种方法,很明显,时间差异分析允许进入集内优化,增加我们的代理的反应能力,以更好地收敛,在最短的时间内找到最佳策略。在自动驾驶应用中,这将允许我们在更早的时间点监控和评估代理的性能,并允许我们更快地做出调整,防止探索中不必要的事故。

这就结束了对时间差异分析的介绍。在下一篇教程中,我们将在此基础上,通过 SARSA 和 Q-learning 介绍状态动作值的 TD,后者是一种众所周知的在线学习方法,用于在各种游戏环境中优化代理策略。

我们希望您喜欢这篇文章,并希望您查看关于gradient crescent covering applied AI的许多其他文章。要了解 GradientCrescent 的最新动态,请考虑关注该出版物。

参考文献

萨顿等人。强化学习

怀特等人。阿尔伯塔大学强化学习基础

席尔瓦等人。阿尔,强化学习,UCL

用 ROC 曲线说明预测模型

原文:https://towardsdatascience.com/illustrating-predictive-models-with-the-roc-curve-67e7b3aa8914?source=collection_archive---------11-----------------------

数据科学是一个在过去几年中真正成长起来的术语,似乎每个人都想加入进来。最有吸引力的目标之一是利用数据资产的力量来创建能够预测各种结果的机器学习模型。有了一个定义良好的模型,人们可以确定能够预测结果的最具影响力的因素,为战略假设开发有价值的洞察力,甚至可以通过友好的用户界面将模型的逻辑实现到软件应用程序中。

然而,在这种神奇的事情发生之前,我们需要知道这个模型所创造的预测是否是好的!例如,如果我们的电子邮件程序的垃圾邮件分类器只能检测到 50%的不受欢迎的电子邮件或请求,我们都会非常愤怒。在这篇文章中,我将介绍如何使用每个数据科学家都应该熟悉的经典工具来评估预测模型:接收器工作特性(ROC)曲线

说明性的例子:预测冠心病

我在这篇文章中使用的数据集来自 Bom 等人的“靶向蛋白质组学对疑似冠心病患者冠状动脉斑块形态的预测价值”,公众可以通过 https://data.mendeley.com/datasets/gdfvxvr7f2/1获得。

这项研究检查了两种不同的结果,我在这篇文章中重点关注的是没有冠状动脉疾病(CAD)。作者评估了蛋白质组生物标志物检测有症状患者是否存在 CAD 的预测能力。识别一组能够区分非冠心病患者和需要立即干预的患者的蛋白质将提供更准确和成本有效的非侵入性诊断测试。

这个数据集是测试几个数据科学主题的绝佳来源。对于少量的观察值,很容易处理,但是它也包含了大量的变量,增加了复杂性。一个可行的“金标准”的结果(使用冠状动脉计算机断层血管造影,或 CCTA)是用来测试预测。在这篇文章中,我将主要关注单个模型的 ROC 曲线的构建,但在后面的文章中,我可能会深入到更高级的主题。

预测精度测量概述

在开始创建曲线之前,了解一些评估预测准确性的常用指标很重要。

正类:我将把正类定义为我试图检测的结果类。在这种情况下,就是 CAD 的 缺席。虽然我意识到这可能会导致诊断测试领域中术语“阳性”和“阴性”的混淆,但是以这种方式定义阳性类更适用于其他情况。

在这种情况下,处理有症状患者的默认方法是让他们接受进一步的测试和程序。通过充分检测没有冠心病的患者,我们将不再需要不必要的、更具侵入性的手术。

一般准确性:简单来说,有多少受试者被正确分类?

灵敏度:正确识别的真阳性的比例。在这种情况下,由诊断工具正确识别的健康患者的比例。这有时被称为“召回”

  • SN =真阳性/(真阳性+假阴性)
  • 逆(1-灵敏度)= 假阴性率。该工具未检测到的健康患者被错误地识别为患有 CAD。假阴性也被称为第二类错误。

特异性:正确识别的真阴性的比例。在这种情况下,诊断工具正确识别的 CAD 患者的比例。

  • SP =真阴性/(真阴性+假阳性)
  • 逆(1-特异性)= 假阳性率。冠心病患者被错误地认定为无冠心病。假阳性也称为 I 型错误。

阳性预测值:工具报告的阳性结果的比例,实际上是阳性的。对于诊断工具报告没有 CAD 的患者组,PPV 是实际上没有该疾病的患者的比例。这有时被称为“精度”

  • PPV =真阳性/(真阳性+假阳性)

阴性预测值:工具报告的阴性比例,实际上是阴性的。对于诊断工具报告存在 CAD 的患者组,NPV 是实际上没有 CAD 的患者的比例。

  • NPV =真阴性/(真阴性+假阴性)

如果你在试图整理所有这些指标时头疼,不要担心。很容易混淆这些术语,尤其是在第一次学习它们的时候。我发现在一个 2x2 的表格中可视化事物是最容易的。

Confusion Matrix for a Binary Class ( positive = absence of CAD, negative = CAD)

曲线的剖析

ROC 曲线的好处在于,它是一个易于解释的图形工具,可以应用于您创建的任何预测模型。以下是曲线的基础:

坐标轴:灵敏度和假阳性率

首先,我们需要为情节创造空间。ROC 曲线是通过绘制灵敏度对 1-特异性(或假阳性率)的曲线建立的。

预测概率

现在我们需要一些东西来绘制。回想一下,预测模型会将每个观察值分配到最可能的类别(在这种情况下,没有 CAD 对有 CAD)。模型实际上做的是计算属于特定类别的概率。临界值在 0 和 1 之间选择,如果计算出的概率超过该阈值,则该观察值被分配给该类。

您可能会发现,在大多数包中,默认的截止值被设置为 0.5,其逻辑是,在二进制类中,人们会将一个观察值分配给一个最有可能的类。然而,正如我们将会看到的,最好在考虑到敏感性和特异性之间的权衡之后选择临界值。

ROC 曲线是通过绘制所有可能的临界值生成的,临界值是分配给每个观察值的概率。选择不同的临界值将改变预测工具的灵敏度和特异性,因此,可以使用相关的灵敏度和 1-特异性作为坐标,在图的空间中绘制每个截止概率。最靠近左上角的点(SN = 1,FPR = 0)在精度指标之间提供了最大的平衡。

曲线下面积

AUC 是一种类似于二元模型的一致性或 c 统计量的指标。这是正类中的观察比负类中的观察具有更大预测概率的概率。

如果 AUC = 1,这意味着模型有完美的预测。如果 AUC = 0.5,这将意味着模型不能区分类别。它在逻辑回归中的表现也类似于 r-square,因为增加更多的预测因子将增加 AUC。因此,在分析中包括交叉验证或对外部数据的验证非常重要。

AUC 可用于评估不同的预测模型。

参考线

通常画一条参考线是个好主意,在 ROC 图上 AUC = 0.5。这提供了与曲线进行比较的基线视觉。

生成 ROC 曲线

虽然可以使用几个不同的程序来开发预测模型和 ROC 曲线,但是我在 r。

分析这个数据集的完整代码可以在我的 Github 上找到:

[## dslans 预测-cad

靶向蛋白质组学数据集的数据分析预测有症状患者的冠状动脉疾病…

github.com](https://github.com/dslans/predicting-cad)

为了预测结果,我使用 xgboost 创建了一个分类模型,将蛋白质生物标志物作为预测器,并使用一种替代方法来预测数据集中的结果。使用预测的概率,我可以形成我上面展示的 ROC 曲线。

注意:该程序还被设置为使用 k-fold 交叉验证,或者可以被更新为利用外部验证,比如对训练集和测试集进行 70/30 的分割(尽管我会想要更多的数据)。

解读曲线

AUC 为 0.738,实际上刚好低于作者用他们的机器学习方法发现的值(堆叠可能提高了分类器的准确性)。然而,我更关心的是选择一个合适的截止值,并权衡该工具的成本和收益。

该模型的总体准确性还不错,但当假阳性结果出现时,就会发生这种情况,患有 CAD 的患者会被送回家,而不是通过必要的程序?我们一致认为这不是一件好事。

为了安全起见,让诊断工具的假阳性率尽可能小可能是个好主意。在生成混淆矩阵时,很容易选择一个概率截止值来保持较低的假阳性率。这将作为谁被贴上无 CAD 标签的决定标准。

通过选择保持 90%特异性(10%假阳性率)的概率截止值,分类工具能够检测 42%没有 CAD 的患者(灵敏度= 0.42)。在这种情况下,这实际上是一个非常好的结果,因为现状是让所有有症状的患者接受更具侵入性的诊断程序。尽管 42%的敏感度听起来很低,但在这个特定的场景中,这是一个有希望的结果。

在开发用于在有症状的患者中预测 CAD 状态的分类器时,最重要的是在保持低假阳性率的同时实现尽可能高的灵敏度。

ROC 曲线的美妙之处在于,您可以从一张图片中看到所有这些性能指标。将曲线与竞争模型进行比较是选择合适的分类或诊断工具的快速简便的方法。

我只探索了使用 ROC 曲线和二元分类工具,但是它可以很容易地扩展到多类场景。在同一个图形上,可以绘制出对应于每个特定类别的概率的多条曲线。

在撰写本文时,我详细介绍了如何构建 ROC 曲线,目的是增加对预测准确性度量的理解,以及如何评估您可能正在构建的这些数据科学分类工具。

参考

Bom MJ,Levin E,Driessen RS,等。靶向蛋白质组学对疑似冠心病患者冠状动脉斑块形态的预测价值。EBioMedicine。;39:109–117.doi:10.1016/j . ebiom . 2018 . 12 . 033

Python 插图:置信区间

原文:https://towardsdatascience.com/illustration-with-python-confidence-interval-ee4736cc3dc2?source=collection_archive---------6-----------------------

本文使用了中的知识,中心极限定理,还有的概念,弱大数定律的切比雪夫不等式,你可以通过访问链接来复习这些题目。如果你想继续下去,你可以从这个链接获得代码: Jupyter 笔记本

在我看来,这个话题是最令人困惑的定理,甚至维基百科的文章也提到了对它的误解,所以我会尽力解释它。

在深入研究之前,请记住,总体的均值(我们要估计的东西)是一个常数,这个数字没有随机性。

置信区间是我们用来估计总体参数值的估计量。间隔将创建一个可能包含这些值的范围。当我们创建区间时,我们使用样本均值。回想一下中心极限定理,如果我们多次采样,样本均值将呈正态分布。

我创建了样本均值分布来演示这个估计量。

# use gamma distribution
shape, scale = 2.0, 2.0  # mean=4, std=2*sqrt(2)
s = np.random.gamma(shape, scale, 1000000)
mu = shape*scale # mean and standard deviation
sigma = scale*np.sqrt(shape)# create sample mean distribution
meansample = []
# sample size
samplesize = 500
for j in range(0,50000):
    # sampling 500 sample from population
    rc = random.choices(s, k=samplesize)
    # collect mean of each sample
    meansample.append(sum(rc)/len(rc))plt.figure(figsize=(20,10))
plt.hist(meansample, 200, density=True, color='lightblue')
plt.show()

样本均值分布是正态分布,均值等于总体均值 4。我们可以把这个分布改成标准的正态分布,用 Z 表来计算概率。

我使用 Z 表创建一个覆盖样本平均值 95%的范围,如下图所示。

# set mean and 95% probability
plt.figure(figsize=(20,10))
plt.hist(meansample, 200, density=True, color='lightblue')
plt.plot([mu,mu],[0, 3.2], 'k-', lw=4, color='green')
plt.plot([mu-(1.96*sigma/np.sqrt(samplesize)),mu-(1.96*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=2, color='navy')
plt.plot([mu+(1.96*sigma/np.sqrt(samplesize)),mu+(1.96*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=2, color='navy')
plt.show()

The green line is the true mean or population mean. The two blue lines are a 95% border.

如果我们从总体中取样并计算平均值,在 95%的情况下,我们将得到两条蓝线内的平均值。

不幸的是,我们无法采样 50,000 次并创建这个分布。假设我们只能采样 1 次,我们得到的样本平均值为 3.85。我们得到的平均值是黑线。

# suppose that we sample 500 data that has a mean as 3.85
# Xbar mean = 3.85, sigma = sigma/np.sqrt(samplesize)
m, ss = 3.85, sigma/np.sqrt(samplesize) # mean and standard deviation
plt.figure(figsize=(20,10))
plt.hist(meansample, 200, density=True, color='lightblue')
plt.plot([mu,mu],[0, 3.2], 'k-', lw=4, color='green')
plt.plot([mu-(1.96*sigma/np.sqrt(samplesize)),mu-(1.96*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=2, color='navy')
plt.plot([mu+(1.96*sigma/np.sqrt(samplesize)),mu+(1.96*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=2, color='navy')
plt.plot([m,m],[0, 3.2], 'k-', lw=2, color='black')
plt.show()

The black line is the mean we got from sampling.

根据我们得到的平均值,我们希望创建一个估计量来估计真实平均值的值,因此我们使用 95%的范围(黄色区域)创建一个区间。稍后我会解释为什么我们使用 95%的范围。

# the interval we create cover the population mean because it is within 95% range from population mean
plt.figure(figsize=(20,10))plt.hist(meansample, 200, density=True, color='lightblue')
plt.plot([mu,mu],[0, 3.2], 'k-', lw=4, color='green')
plt.plot([mu-(1.96*sigma/np.sqrt(samplesize)),mu-(1.96*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=1, color='navy')
plt.plot([mu+(1.96*sigma/np.sqrt(samplesize)),mu+(1.96*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=1, color='navy')
plt.plot([m,m],[0, 3.2], 'k-', lw=4, color='black')
plt.plot([m-(1.96*ss),m-(1.96*ss)],[0, 3.2], 'k-', lw=2, color='red')
plt.plot([m+(1.96*ss),m+(1.96*ss)],[0, 3.2], 'k-', lw=2, color='red')
# Create a Rectangle patch
plt.gca().add_patch(plt.Rectangle((m-(1.96*ss), 0),2*(1.96*ss),3.21, fill=True, linewidth=3, fc=(1,1,0,0.3)))
plt.xlim(3.43, 4.67) 
plt.show()

The yellow area is an interval of the sample mean.

我们可以看到区间覆盖了真实均值(绿线)。区间(黄色区域)覆盖了真实平均值,因为样本平均值落在总体平均值(绿线)的 95%范围内。

由于样本均值是随机的,因此有 5%的概率均值会超出 95%的范围。当样本平均值超出 95%范围时,就会出现这种情况。

# if the interval is not within 95% range from population mean the interval will not cover the true population mean
plt.figure(figsize=(20,10))
m = 3.72
plt.hist(meansample, 200, density=True, color='lightblue')
plt.plot([mu,mu],[0, 3.2], 'k-', lw=4, color='green')
plt.plot([mu-(1.96*sigma/np.sqrt(samplesize)),mu-(1.96*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=1, color='navy')
plt.plot([mu+(1.96*sigma/np.sqrt(samplesize)),mu+(1.96*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=1, color='navy')
plt.plot([m,m],[0, 3.2], 'k-', lw=4, color='black')
plt.plot([m-(1.96*ss),m-(1.96*ss)],[0, 3.2], 'k-', lw=2, color='red')
plt.plot([m+(1.96*ss),m+(1.96*ss)],[0, 3.2], 'k-', lw=2, color='red')
# Create a Rectangle patch
plt.gca().add_patch(plt.Rectangle((m-(1.96*ss), 0),2*(1.96*ss),3.21, fill=True, linewidth=3, fc=(1,1,0,0.3)))
plt.xlim(3.43, 4.67) 
plt.show()

If we sample and get the mean that falls outside blue lines, the interval will not cover the true mean.

黄色区域不包含人口平均值。

我们使用 95%的范围,因为它与样本均值的概率相匹配。如果样本均值在概率的边界上,则该范围仍然覆盖真实均值,但如果再远一点,则不会覆盖真实均值。样本均值落在两条蓝线内的概率为 95%,因此两条线外 5%的区间不会覆盖真实均值。

95%这个数字是一个任意的数字,你可以把它设置成任意的数字。例如,我们可以将其设置为 90%的范围。

# use 90% instead of 95%
plt.figure(figsize=(20,10))
m = 3.72
plt.hist(meansample, 200, density=True, color='lightblue')
plt.plot([mu,mu],[0, 3.2], 'k-', lw=4, color='green')
plt.plot([mu-(1.645*sigma/np.sqrt(samplesize)),mu-(1.645*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=1, color='navy')
plt.plot([mu+(1.645*sigma/np.sqrt(samplesize)),mu+(1.645*sigma/np.sqrt(samplesize))],[0, 3.2], 'k-', lw=1, color='navy')
plt.plot([m,m],[0, 3.2], 'k-', lw=4, color='black')
plt.plot([m-(1.645*ss),m-(1.645*ss)],[0, 3.2], 'k-', lw=2, color='red')
plt.plot([m+(1.645*ss),m+(1.645*ss)],[0, 3.2], 'k-', lw=2, color='red')
# Create a Rectangle patch
plt.gca().add_patch(plt.Rectangle((m-(1.645*ss), 0),2*(1.645*ss),3.21, fill=True, linewidth=3, fc=(1,1,0,0.3)))
plt.xlim(3.43, 4.67) 
plt.show()

When we change the confidence from 95% to 90%, the interval becomes narrower.

因此,当我们说 95%的置信度时,意味着我们确信 95%的样本的平均值在真实平均值的 95%范围内(两条蓝线内)。问题是如果我们知道真正的意思,我们就不会这么做了。为了解决这个问题,我们将解释改为“我们确信 95%的抽样,样本将具有一个平均值,该平均值可以创建覆盖真实平均值的区间”。

就像我上面提到的,这里唯一随机的是样本均值,所以我们不能说真均值的概率在区间内,因为总体均值不是随机变量,真均值是一个数字。

理论上,如果我们采样 100 次,95 次,我们将得到一个样本均值,其区间覆盖真实均值,因此我使用 python 模拟 100 次采样,这就是所发生的情况。

# simulate 100 interval with 5,000 sample size
mu = shape*scale # mean
sigma = scale*np.sqrt(shape) # standard deviation
intervallist = []
k = 1.96
# sample size
samplesize = 5000
# start count
c = 0
for i in range(0,100):
    # sample 100 sample
    rs = random.choices(s, k=samplesize)
    # calculate mean
    mean = np.mean(rs)
    upbound = mean + k*sigma/np.sqrt(samplesize)
    lowbound = mean - k*sigma/np.sqrt(samplesize)
    # collect difference between sample mean and mu
    intervallist.append([lowbound,mean,upbound])
    if upbound >= mu and lowbound <= mu:
        c += 1

print("number of interval that cover the expected values:", c)
# set figure size.
plt.figure(figsize=(20,10))
# plot box plots of each sample mean.
plt.boxplot(intervallist)
plt.plot([1, 100],[mu,mu], 'k-', lw=2, color='red')
# show plot.
plt.show()

The red line is a true mean, the box plots are intervals.

这个数字可能不是精确的 95,因为它毕竟是一个概率。

最后一点,样本大小对这个话题有巨大的影响。如果样本量增加,样本均值的方差会减小。因此,间隔范围也减小。

# simulate 100 interval with 20,000 sample size
intervallist = []
# sample size
samplesize = 20000
# start count
c = 0
for i in range(0,100):
    # sample 100 sample
    rs = random.choices(s, k=samplesize)
    # calculate mean
    mean = np.mean(rs)
    upbound = mean + k*sigma/np.sqrt(samplesize)
    lowbound = mean - k*sigma/np.sqrt(samplesize)
    # collect difference between sample mean and mu
    intervallist.append([lowbound,mean,upbound])
    if upbound >= mu and lowbound <= mu:
        c += 1

print("number of interval that cover the expected values:", c)
# set figure size.
plt.figure(figsize=(20,10))
# plot box plots of each sample mean.
plt.boxplot(intervallist)
plt.plot([1, 100],[mu,mu], 'k-', lw=2, color='red')
# show plot.
plt.show()

Notice the y-axis scale is smaller.

如果我们的样本量很大,估计量会更精确。

代码可以在这个链接找到: Jupyter 笔记本

我是贝塞德,我知道

原文:https://towardsdatascience.com/im-bayesed-and-i-know-it-b8bfd71c2338?source=collection_archive---------24-----------------------

Source: deeredeemed.wordpress.com

如果你还太年轻,不知道标题出处,我会让你失去理智。它与聚会、摇滚和圣歌有关。实际上,不,我只是想让你玩得开心,所以我想让你看看标题图片。你注意到了什么?

显然,我让你注意标题和图片是有原因的。有了这个标题,你可能不会意识到它有一个“模式”,直到我指出来。对于这幅图,如果你只是匆匆一瞥,你可能只看到了羊。

如果你在我没有指出来的情况下,设法把两者都搞清楚了,你可以停止阅读了。

对于那些不知道的人来说,我(试着)比你们强一点的原因是因为我想谈谈偏见。不,不是机器学习中的偏见,这是指一个模型不能“学习”任何东西。我将要谈到的偏见更为严重,它与人类而非机器有关。你现在可能已经明白了…我们将要谈论认知偏见。为什么?因为它们通常与数据驱动的决策和数据科学有很大关系。

让我们开门见山吧。下面你会发现一些我们人类的认知偏见。本帖,我只说一个;它对我们的生活有着重大的影响,但也许还没有被人们谈论的那么多。这被称为基础率谬误。

Source & interactive version: Wikipedia

基础利率谬误

想想你最后一次参与项目的时候。它是否比您最初预期的花费了更多的时间?对我来说,在团队工作时,这种情况总是会发生。你还有一周就要截稿了;由于团队花了 4 天时间完成上一个项目,你们都认为这次最多花 4 天时间就能完成。突然到了晚上 11:50,离截止日期还有 5 分钟,在吃了四天街角小店的烤肉串后,你开始争先恐后地完成所有事情。

每当这种情况发生时,我也会责怪我的队友或老板,而不是我自己(顺便说一下,这实际上是一种偏见,自私的偏见),但事实上,我没有忽略基本率,因为作为一个人,我不太擅长将信息与概率分开。为了向你解释什么是基础利率谬误,我将遵从这方面的专家:

两位最著名的行为科学家阿莫斯·特拉弗斯基和丹尼尔·卡内曼进行了一项实验,他们向参与者描述了从 70 名律师和 30 名工程师中随机选出的 5 个人。参与者需要预测这 5 个人是律师还是工程师。Kahneman & Traversky 发现,参与者的预测完全忽略了这个群体的特征(这个群体由 30%的工程师或 70%的律师组成,这是 5 种描述中的每一种落入每一组的各自概率),最终的描述是从这个群体中得出的。相反,参与者似乎将他们对每个人职业的预测建立在描述与典型的律师或工程师相似的程度上。显然,参与者有偏见。如果不是,从 5 个样本中,他们最好说 3 个是律师,2 个是工程师(每个人的期望值)。

这种偏见对你和你未来的小组项目意味着什么?不要考虑以前同一个团队完成一个项目花了多长时间,开始收集在你之前其他团队完成相同或相似项目花了多长时间的数据!这样,你就不会忽略基础利率。

快速提示:显然,有相当大的一个专门的机器学习研究人员小组试图建立可以仅基于相似性进行预测的算法。佩德罗·多明戈斯(Pedro Domingos)在他的书《算法大师》(The Master Algorithm)中,将这些人描述为类比者。

对数据科学的影响

回到正题,基础率谬误不仅仅局限于团体项目。它对决策制定有深远的影响,并与数据科学相关联。通过忽略基础利率,我们可能会基于某人的长相(光环效应,或者为什么骗子会成功)而不是他们的实际支付能力,认为他们不支付信用卡账单的概率更高。另一个例子是医生误诊病人,因为他们没有考虑疾病发生的基本比率,本质上是给非常罕见的疾病附加了更高的概率。

现在戴上你的数据科学家帽子,想想机器学习是如何防止这种偏见干扰决策的?让我给你一个提示:

Thomas Bayes, Source: Wikipedia

事实证明,贝叶斯是没有偏见的。

由托马斯·贝叶斯在 18 世纪首次提出的贝叶斯定理,通过在计算后验概率时结合先验概率来考虑基础率。我不会在这篇文章中花时间解释它是如何工作的,因为佩德罗·多明戈斯做得更好,所以我强烈推荐他的书给那些更渴望了解居住在“ML 土地”上的部落的人。

我要说的是,贝叶斯定理是当今机器学习中最重要(也是最流行)的算法之一,它的应用见于一种叫做朴素贝叶斯的机器学习算法。

那又怎样?

你可能想知道我想证明什么。有些文章将数据科学和/或机器学习描述为会带来大量失业、过滤泡沫等等的东西。对这个行业的看法是,计算机科学家被付钱编写成千上万行代码,因为自动化比付钱给信贷员更便宜,或者更糟的是,公司想要发布假新闻来影响人们的决定。

我在这里的目的是给你一个不同的视角。事实上,许多数据科学都是基于被开发(或重新发现)以摆脱所有人类都有的认知偏见的想法。这包括信贷员和数据科学家。随着偏见的减少,我们以前做错的决定正在变得正确。例如,我们不再有仅仅因为信贷员不喜欢他们的穿着而不给他们贷款的问题(但没有意识到这影响了他/她的决定)。

我并不是说这都是阳光和彩虹,因为有许多关于数据科学的伦理困境正在进行辩论。无可争议的是,由于数据科学,我们在决策中的人类偏见更少了,这改善了全人类的生活。

你同意吗?

基于卷积神经网络的图像美学量化

原文:https://towardsdatascience.com/image-aesthetics-quantification-with-a-convolutional-neural-network-cnn-7b39b3cc8189?source=collection_archive---------21-----------------------

基于 MobileNetV1 的卷积神经网络(CNN)训练项目报告,仅使用 14,000 幅图像进行迁移学习

雅各布·欧文斯在 Unsplash 上的照片

一.定义

项目概述

“一幅画胜过千言万语”强调了图像在现代世界中的重要性。例如,图像的质量会影响我们在不同领域的决策。尤其是在电子商务领域,我们不能碰的东西是必不可少的。因此,他们对我们的产品购买决策有着重大影响。

订哪个房间?

和哪个家伙约会?

点什么菜?

这个项目的目标是创建一个可以量化图像美学的模型。

问题陈述

图像质量的量化是计算机视觉中的一个老问题。有客观和主观的方法来评估图像质量。使用客观方法,不同的算法量化图像中的失真和退化。主观方法基于人的感知。这些方法往往互不相关。客观方法涉及传统的基于规则的编程,主观方法不能以这种方式解决。

这个项目的目标是开发一种主观的图像质量评估方法。如前所述,这个问题不能用经典编程来解决。然而,有监督的机器学习似乎是解决该问题的完美候选,因为这种方法从示例中学习,并且是一种量化不可言喻的方式。具有图像质量注释的数据集是从样本学习的要求。

在机器学习生态系统中,卷积神经网络(CNN)是一类神经网络,已被证明在图像识别和分类等领域非常有效。它们受到生物过程的启发,因为神经元之间的连接模式类似于人类视觉皮层的组织。

主观质量模型是用卷积神经网络实现的,因为它似乎非常适合解决这个问题。

这些步骤是必要的:

  1. 查找带有高质量注释的图像数据集
  2. 对数据集进行探索性数据分析(EDA ),以评估问题空间的特征和适用性
  3. 数据集的清理和预处理
  4. CNN 架构设计
  5. CNN 的培训
  6. 对照基准测试模型
  7. 结果分析

步骤 4 有几次迭代。-7.

韵律学

项目中预测了用户评分的分布。从那里你可以预测一个定量的平均评级,也可以预测一个定性的评级桶。为了捕捉这两个指标,使用了。

推土机距离(EMD)

推土机距离(EMD) 是一种评价某个特征空间中两个多维分布之间不相似性的方法,其中给出了单个特征之间的距离度量,我们称之为地面距离。EMD 将这个距离从单个特征“提升”到完全分布。假设表现良好的 CNN 应该预测类别分布,使得更接近地面真实类别的类别应该比更远的类别具有更高的预测概率。对于图像质量评级,分数 4、5 和 6 比 1、5 和 10 更相关,即目标是如果实际分数是 10,那么当实际分数是 5 时,惩罚预测 4。EMD 定义为将一个分布(直方图)的质量转移到另一个分布的最小成本。(侯、于和萨马拉斯,2016 年)(鲁布纳、托马西和吉巴斯,2000 年)和米兰法尔,2018 年)

准确(性)

为了比较定性结果,使用了精度。准确度是正确预测的比率。在这种情况下,在“官方”测试集上使用阈值 5 的地面实况和预测平均值,因为这是 AVA 数据集的标准做法。

数据探索

由(Murray、Marchesotti 和 Perronnin 2012a),(Murray、Marchesotti 和 Perronnin 2012b)介绍的 AVA(美学视觉分析)图像数据集是各种图像美学的参考数据集。该数据集包含 255508 幅图像,以及各种美学、语义和摄影风格的注释。这些图片是从 www.dpchallenge.com 的收集的。

样本行

样本图像

最佳评价图片

评价最差的图片

评级数量的描述性统计

评分均值的描述性统计

探索性可视化

评级数量的分布

每张图片的评分数量:大多数由超过 100 名评分者进行评分

这些图片的评分从 78 到 549 不等,平均分为 210 分,从 1 到 10 分不等。

可以看出,所有的图像都被大量的评价者进行了评价。这是非常重要的,因为通过图像的美学来评价图像是非常主观的。要消除异常值评级,需要大量的评级人。

平均评级的分布

评分均值分布

从分布和描述性统计可以看出,50%的图像具有在 4.9 和 5.9 之间的评级均值,并且大约 85%的图像在 3.9 和 6.8 之间。从箱线图中可以看出,高于 7.2 和低于 3.5 的评级均值是异常值,因为这些值很少。

这是有问题的,因为模型性能不适用于质量优秀和糟糕的图像。

算法和技术

卷积神经网络(CNN)

卷积神经网络(CNN)将用于解决图像美学评估的问题。它们是受生物过程启发的深度神经网络,最常用于分析视觉图像。

CNN 由一个输入层、一个输出层和几个隐藏层组成。隐藏层通常是卷积层,后面是汇集层。

用于图像分类的典型 CNN 的结构。网络的每个卷积层都有多个过滤内核,用于提取特征。二次抽样或汇集层用于减少信息。(来源维基百科)

卷积层

卷积层的目的是从输入图像中提取特征。它们通过使用输入数据的小方块学习图像特征来保持像素之间的空间关系。

卷积运算提取特征

汇集层

卷积网络可以包括汇集层。这些层将一层的神经元簇的输出组合成下一层的单个神经元。这样做的原因如下:

  • 内存的减少和执行速度的提高
  • 过度拟合的减少

MaxPooling 层,提取一个区域中的最大值来减少信息。(来源维基百科)

全连接层

经过多层卷积层和汇集层,一个全连接层完成了网络。全连接层是负责分类任务的传统多层感知器。

迁移学习

迁移学习是计算机视觉中一种流行的方法,因为它允许我们以省时的方式建立精确的模型(Rawat 和 Wang 2017)。使用迁移学习,你不是从零开始学习过程,而是从解决一个不同的问题时已经学到的模式开始。这样你可以利用以前的经验,避免从头开始。

在计算机视觉中,迁移学习通常通过使用预先训练的模型来表达。预训练模型是在大型基准数据集上训练的模型,用于解决与我们想要解决的问题类似的问题。因此,由于训练这种模型的计算成本,通常的做法是从公开的文献(例如,VGG、Inception、MobileNet)中导入和使用模型。

迁移学习

一些最先进的图像分类应用程序基于迁移学习解决方案(何等人,2016 年),(Szegedy 等人,2016 年)谷歌在其(神经图像评估)论文中报告了基于迁移学习的模型的最高准确性(塔莱比和米兰法尔,2018 年)

该项目的目标是将 MobileNet 架构与 ImageNet 权重结合使用,并将 MobileNet 中的最后一个密集层替换为输出到 10 个类别(得分 1 至 10)的密集层,这些类别与(塔莱比和米兰法尔 2018 年)建议的评级分布一起形成

基准

在不同的论文中报道了不同模型在 AVA 数据集上的精度。这些精确度被用来作为在这个项目中创建的模型的基准。这些基准基于“官方的”AVA 测试集。目标是达到至少 68%的准确度,这高于图像美学相关论文的下限。

三。方法学

数据预处理

数据预处理可以分为两部分:第一部分是在探索性数据分析过程中完成的。在该步骤中,执行了以下检查和清洁:

  1. 移除图像:
  • 一些图像必须从元数据中删除,因为它们不存在。
  • 用脚本识别了几个损坏的图像。损坏的图像已从元数据中删除。

2.设计了技术图像属性来检查图像异常

几个技术图像属性(文件大小、分辨率、长宽比)被设计并检查异常。没有异常图像可以在这里确定这些属性。

第二个预处理步骤在训练期间执行:

  1. 将数据拆分为训练集和验证集

训练集的 10%的图像用于验证。

2.执行了基础模型特定预处理

Keras 提供的每个基础模型都提供了一个预处理函数,并为该模型提供了特定的预处理步骤。这个预处理步骤被应用于图像生成器,该图像生成器加载用于训练和模型评估的图像。

3.分布的标准化

评级分布是标准化的,因为每张图片由不同数量的人进行评级。

4.图像大小调整和随机裁剪

训练图像被重新缩放到 256×256 像素,然后,提取 224×224 像素的随机执行的裁剪。据报道,这可以减少过度拟合问题。(塔莱比和米兰法尔 2018)

5.数据的欠采样

对于更早的训练期,通过在 10 个分级箱中切割数据并取每个箱的前 n 个样本来减少图像的数量。这样做有两个原因:由于计算能力有限,使用的图像较少,这减少了训练模型的时间。另一个原因是数据不平衡。只有很少的几张图片有很低和很高的评分。预计欠采样会降低最常见等级周围的图像过拟合的影响。

履行

目标是创建一个清晰的训练脚本,可以从外部参数化,用于触发不同的训练课程。为了减少这个培训脚本的代码行,它用一个管道脚本来编排培训的构建块。

  1. 所有需要的库都被确定并放入 requirements.txt 中
  2. 实现了用于下载 AVA 图像和元数据的内部库。
  3. 使用用于训练的构建块创建了训练脚本(加载数据、准备数据、训练、评估)
  4. 培训脚本的构建块被移动到管道脚本中。这些脚本保存了不同的人工制品:模型架构、模型权重、训练历史、训练时间、训练可视化
  5. 创建了一个模型类,它封装了基础模型和顶层模型,并提供了帮助器函数来动态更改优化器和冻结层
  6. 创建了 EMD 损失函数
  7. 创建图像生成器是为了加载图像并执行图像的预处理
  8. 实现了几个用于模型评估的辅助函数

实际训练分两步进行:

  1. 基本模型的权重被冻结,只有顶部模型以较高的学习率被训练
  2. 基本模型权重被解冻,整个网络以较低的学习速率进行训练

CNN 的模型设计

如前所述,该模型由两部分组成。除了移除的第一层之外,基本模型保持不变。用 ImageNet 权重初始化模型。ImageNet 项目是一个广泛的视觉数据库,设计用于视觉对象识别软件研究。由于影像与 AVA 数据集中的影像相似,因此使用该数据集的权重。对于基本模型,使用 MobileNet 架构,因为该网络比其他网络小,适合计算能力不足的基于移动和嵌入式的视觉应用。(霍华德等人 2017 年)

顶层模型由两层组成。第一层是一个下降层,以减少过度拟合,随后是一个密集层,输出大小为 10,激活 softmax 以预测评级分布。具有不同学习速率和学习速率衰减的 Adam 优化器用于训练。

顶层模型的设计:避免过拟合的脱落层,10 个输出类的密集层

精炼

模型优化使用了几个参数:

  • 密集层和所有层的学习率
  • 密集层和所有层的学习率衰减
  • 密集层和所有层的历元数
  • 用于训练的每个分级箱的图像数量
  • 顶层模型中漏失层的漏失率

训练是迭代完成的:首先,用非常少的样本和上述参数的默认值训练模型。然后用更多的样本对模型进行训练,对参数进行微调。在模型被训练之后,为测试集计算损失值和准确度。然后将准确度与论文中的准确度分数进行比较(参见“基准”一节),直到达到足够的模型准确度。

训练过程由训练和验证集的损失图来监督,以检查一切是否正常,并优化学习过程。

训练历史图用于寻找两个学习阶段的最佳时期数。在第 1 阶段,验证损失在第 5 时段(图中为 4)变平,在第 2 阶段,val 损失在第 8 时段(图中为 12)变平

四。结果

模型评估和验证

在不同的模型中,选择了模型 8,因为它的 EMD 损失值最低,并且在测试集的所有模型中,它的精度最高。结果是可信的,因为测试集是 AVA 的“官方”测试集,模型在训练或验证期间从未“看到”这些图像。一个有趣的事实是,这个模型的表现略好于模型 9,模型 9 是用两倍数量的训练图像训练的。

最佳模型基于 MobileNet 架构,并使用以下参数。所有这些参数似乎都是合理的:

从下图中可以看出,最佳模型的实际平均评级和预测平均评级的分布非常相似。该模型适用于 3.5 到 7.5 之间的平均评分。低于或高于这些界限的评级没有被模型很好地覆盖。这是因为事实上,没有多少图像具有很高和很低的评级。因此,由于缺乏实例,该模型无法正确评估这些极端异常值。

大图:测试集上有蒂平均评分和真实评分的分布。小数字:分布在测试集的下端和上端。

正当理由;辩解

与基准测试相比,该模型在 AVA 的参考测试集上显示了中等的准确性,该测试集在论文的所有模型中使用。

结果相当令人印象深刻,因为该模型仅用 13,914 张图像进行了训练。论文中的模型使用完整的训练集(250,000 幅图像)进行训练。

动词 (verb 的缩写)结论

自由形式可视化

对于最后的快速和肮脏的测试,从“项目概述”部分的图像与模型评级。影像不是 AVA 数据集的一部分。

左图:4.23 右图:3.91

左图:3.27 右图:4.00

左图像:3.98 右图像:4.67

可以看出,虽然食物图像的质量几乎相同,但是我们作为人类会评价得更好的图像也被模型评价得更好。

反射

本项目所用的流程可概括为以下步骤

  1. 发现一个相关问题
  2. 对相关论文进行了研究
  3. 对该问题的数据集进行了研究和分析,并选择了最合适的数据集
  4. 数据集已被清理
  5. 模型基准是从论文中摘录的
  6. 项目的技术基础设施已经建立
  7. 模型被训练、微调,并对照基准进行检查,直到找到一个足够好的模型,解决问题

由于缺乏计算能力和数据集非常大,该项目非常具有挑战性。直到最后,我都无法在完整的训练集上训练模型,因为总是会出现内存不足、Keras 和 Tensorflow 特有的问题。我在某个时候卡住了,因为模型表现不佳。在做了一轮额外的研究后,我找到了谷歌的 Nima 论文,这是一篇全新的论文,以至于当我 7 月份开始这个项目时,它还没有发表。论文中的见解是一个突破,特别是对推土机 Loss 的使用和对基本模型的 MobileNet 架构的使用。我感到非常自豪的是,我可以在相关论文的范围内获得准确性,并掌握了一个目前非常热门的话题,主要是因为我在论文中使用的图像比研究人员少。

改进

令人兴奋的是,我确实用欠采样策略达到了一定的精度,这一半是出于需要。即使在对数据进行欠采样之后,评级的分布也是不平衡的。

更好地执行的策略是对未被充分表示的评级图像进行图像增强。这并不容易,因为不是每种图像增强都可以使用,例如,使图像变暗可能会影响图像的美观。另一个有趣的方法是用 GANs(生成-对抗-网络)生成具有非常高和非常低评级的图像。

该项目的另一个改进是用 Docker 和 Docker NVIDIA 将整个过程集装箱化。目标是有一个 docker 映像,它自动下载数据,对数据进行预处理,进行训练,并在训练后停止容器。在这个项目中,这是通过 anaconda 环境完成的,在我看来这并不理想。我不得不总是从我的本地环境切换到 AWS 云实例,这浪费了时间,因为环境不一样。Docker 环境也可以通过其他深度学习项目的可重用元素进行优化。

不及物动词参考

何、、、任、。2016."图像识别的深度剩余学习."Ieee 计算机视觉和模式识别会议论文集,770–78。

侯、乐、陈-、迪米特里斯-萨马拉斯。2016."平方推土机的距离为基础的损失训练深度神经网络." arXiv 预印本 arXiv:1611.05916

Howard,Andrew G,Menglong Zhu,,Dmitry Kalenichenko,,Tobias Weyand,Marco Andreetto 和 Hartwig Adam。2017." Mobilenets:用于移动视觉应用的高效卷积神经网络." arXiv 预印本 arXiv:1704.04861

孔、舒、沈晓辉、哲林、拉多米尔·梅克和查尔斯·福尔克斯。"照片美学排名网络与属性和内容适应."在欧洲计算机视觉会议上,662–79 页。斯普林格。

陆,辛,林哲,金海林,杨建超,王。2014." Rapid:使用深度学习评价绘画美学."在第 22 届 Acm 多媒体国际会议论文集,457–66。ACM。

陆、辛哲林、沈晓辉、拉多米尔·梅奇和詹姆斯·Z·王。2015."深层多补丁聚合网络,用于图像风格、美学和质量评估."在Ieee 计算机视觉国际会议论文集,990–98。

默里,奈拉,卢卡·马尔凯索蒂和弗洛伦特·佩罗宁。2012 年 a。" AVA:美学视觉分析的大规模数据库."https://github.com/mtobeiyf/ava_downloader

— — — .2012 年 b。" AVA:美学视觉分析的大规模数据库."在计算机视觉和模式识别(Cvpr),2012 Ieee 会议上,2408–15。IEEE。

拉瓦特、瓦西姆和王增辉。2017."用于图像分类的深度卷积神经网络:综述."神经计算 29 (9)。麻省理工学院出版社:2352–2449。

Rubner,Yossi,Carlo Tomasi 和 Leonidas J Guibas。2000."推土机的距离作为图像检索的度量."国际计算机视觉杂志 40 卷 2 期。斯普林格:99–121。

施瓦兹、卡塔琳娜、帕特里克·维肖莱克和亨德里克·帕·伦施。2018.“人们会喜欢你的形象吗?学审美空间。”在计算机视觉的应用(Wacv),2018 Ieee 冬季会议于,2048–57。IEEE。

塞格迪,克里斯蒂安,文森特·万霍克,谢尔盖·约菲,乔恩·施伦斯和兹比格涅夫·沃伊纳。2016."重新思考计算机视觉的初始架构."Ieee 计算机视觉和模式识别会议论文集,2818–26。

塔莱比、侯赛因和佩曼·米兰法尔。2018."尼玛:神经影像评估." IEEE 图像处理汇刊 27 (8)。IEEE:3998–4011。

2019 年 3 月 20 日由延斯·劳弗撰写

随意分享!

原载于 2019 年 3 月 20 日 jenslaufer.com**的

使用 Python、Numpy、Opencv 和 Skimage 的图像增强

原文:https://towardsdatascience.com/image-augmentation-using-python-numpy-opencv-and-skimage-ef027e9898da?source=collection_archive---------4-----------------------

图像增强是一种策略,使从业者能够显著增加可用于训练模型的图像的多样性,而无需实际收集新图像。对于训练任何机器学习模型,特别是深度学习模型,拥有大型数据集非常重要,可以显著提高模型的性能。当我们在图像上训练深度学习模型时,我们至少需要数万张图像来概括图像的模式。

生成图像数据是昂贵且乏味的工作。没有数据,机器是盲目的。在这种情况下,我们可以通过对现有图像应用不同的变换技术来生成更多的图像。有不同的技术,如旋转、翻转、移动等。这可以帮助我们使图像数据多样化。如果我们至少有 4-5 种变换技术,我们可以生成 10 倍或 100 倍以上的图像。我们也可以使用模糊图像和添加随机噪声的方法来生成更多的图像。

“即使是世界上最强大的模型也不过是没有适当数据的几行代码”。

在这篇文章中,我们将看到如何使用一些变换和方法从 289 幅图像生成 2000 幅图像。我已经使用 NumPy,Skimage 对图像执行了不同的操作,这些操作非常简单,任何人都很容易理解,即使是 python 和 opencv 的新手。我使用了随机图像的数据集,其中一些图像是彩色的,而一些是灰度图像。

彩色图像和灰度图像的区别在于,彩色图像有 R、G 和 B 三个通道,它们相互叠加,而灰度图像只有一个灰色通道。我说的通道是指矩阵。我们都知道图像只是一个像素阵列。例如:高度为 720,宽度为 1200 图像被表示为包含像素值的 720 行和 1200 列的二维阵列。

NumPy 是一个非常强大且易于使用的数字操作库。由于图像只是一组数字,numpy 让我们的工作变得如此简单。

让我们跳到操作。我们将使用翻转、旋转、移动、添加噪声和模糊图像等方法。不要担心编码部分,我已经在接下来的段落中解释了每一个操作。我在文章的最后还提供了源代码的 Github 链接,如果有帮助的话可以参考一下。

翻转:要水平翻转图像,我们需要颠倒矩阵列的顺序,这将导致图像水平改变。NumPy 有一个名为 fliplr()的方法,它通过反转列的顺序来返回数组。以同样的方式,有另一个方法 flipud()颠倒行的顺序,导致垂直翻转图像,如下所示。

旋转:我们将使用 sklearn 对图像进行旋转、移位添加噪点和模糊处理。Sklearn 提供了 rotate()方法,该方法以角度为参数,返回旋转后的图像。角度的正值逆时针旋转图像,而角度的负值顺时针旋转图像。请参考下图。

45 degree clockwise rotation and vice versa using rotate method

移动:我们可以向右、向左、向上、向下或对角移动图像。我们只需要将 dx 和 dy 值传递给函数。在移位操作之后,存在于输入图像中的位置(X,Y)处的对象被移位到新的位置(X,Y):
X = x + dx
Y = y + dy

Image after shifting operation

添加噪声:为了添加噪声,我们将使用 skimage 库中的 random_noise()方法。这种方法将随机噪声添加到图像中,噪声对于正则化的目的是非常有用的。它防止模型过度拟合。

模糊:对于模糊图像,我们使用了 opencv 中的 gaussian_blur()方法,该方法以图像和内核大小为参数。内核越大,图像越模糊。

Blurring image

现在,让我们使用所有的方法,并将它们应用于我们的数据集,以生成新的图像。我们将从目录中逐个读取图像,并将它们的名称存储到数组中。我们这样做是为了从目录中随机选择图像。我们将在随机图像上应用随机数的变换,直到生成 2000 个图像。

让我们看看代码部分,并阐明它的每一部分。

我们已经为将在图像上执行的每个操作定义了函数,并将它们的名称存储在字典中,以便我们可以在运行时随机调用它们。

Define functions and create dictionary to store them

让我们看看在对图像执行操作后读取图像并生成增强图像的主要代码。

Heart of the augmentation code.

我们定义了两条路径,一条用于读取图像,另一条用于写入图像。我们已经指定了希望生成的图像数量。

一旦外部 while 循环从图像数组中选择了一个随机图像,我们将读取该图像。使用 randint()方法从 random 库中随机选择应用于读取图像的变换数量。这个外部 while 循环将一直运行,直到 counts (i)达到 2000(要生成的图像数)。

内部 while 循环随机选择方法,并将原始图像传递给该方法,并将转换后的图像存储到 transformed_image 变量中。如果转换次数> 1,那么我们将再次随机选择方法名,并传递转换后的图像,使其再次转换。

在对图像执行随机选择数量的转换后,在将它写入磁盘之前,我们将它传递给 image_as_ubyte()方法。skimage 库中的 image_as_ubyte()函数用于将像素值保持在 0–255 范围内。最后,我们将把我们的图像转换成 RGB 并保存到 Augmented_Image 文件夹,这是我们的目的地。

万岁!!我们已经成功地从 289 张图片中创建了 2000 张图片。我们可以使用 7 种变换方法创建更多的图像。你可以在这里找到数据集,在这里找到源代码

如果你想阅读更多关于 Python 中数据扩充的内容,你可以点击查看其中一篇有趣的文章

感谢您的阅读:)

向我奶奶解释图像分类

原文:https://towardsdatascience.com/image-classification-explained-to-my-grandma-665d81a31e9?source=collection_archive---------31-----------------------

简明英语中的 CNN 是什么

2019 年,我参加了由 CodeProject 组织的国际活动,我的项目 KerasUI 取得了胜利,这是一个实现用于训练和消费神经网络的 web GUI 的工具。这是一个特别的机会,让我在神经网络和人工智能领域沉寂了几年之后,重新获得这方面的知识。现在两年过去了,我偶尔和朋友和同事聊天,但我仍然觉得社区对这个话题没有正确的认识。除了专家,大多数人根本忽略了什么是图像分类,或者简单地用 TensorFlow 库的一些方法来识别。嗯,这促使我再次写这个话题,只关注理论部分!

在文章的结尾,您会找到阅读获奖文章和下载代码的链接。我试图让事情变得尽可能简单,简单到可以向我奶奶解释😃

让我们开始解释吧!

Photo by Possessed Photography on Unsplash

学习什么是图像分类

图像分类问题是从一组固定的类别中给一幅图像分配一个标签的任务。这是计算机视觉中的核心问题之一,尽管它很简单,却有大量的实际应用。用穷人的话说,你想要的是,如果你给计算机一个狗的图像,它告诉你“这是一只狗”。

这是一个可以使用人工智能和计算机视觉解决的问题。计算机视觉有助于操纵和预处理图像,使它们成为计算机可以使用的形式(从位图到相关值的矩阵)。一旦你有了一个好的输入形式,你就可以应用一个算法来预测结果。

现在最常见的解决方案是使用 CNN(卷积神经网络)。这种神经网络对于图像处理非常方便,并且根据您将提供的数据集进行训练。

数据集只是一个样本列表,每个样本都有标签。主要话题是你告诉机器如何通过例子来决定。通常,数据集分为训练集、测试集和验证集。这是因为您想要训练网络,然后测试它如何在单独的数据上工作,直到它按预期工作。最后,如果你想得到客观的反馈,你必须使用其他数据:验证集。这是必需的,因为如果你让网络总是在相同的数据上训练,它将丢弃任何错误,但是将能够只处理你提供的样本。所以,如果你投入一点点不同的东西,你会想要得到一个好的结果。这被称为过度拟合,是应该避免的,因为这意味着网络没有抽象规则,而只是重复你告诉它的东西。想想一个数学表达式 2*5+10,就像记住结果是 25,而不是能够计算它。

理解卷积神经网络

在本节中,我们将了解什么是 CNN 及其工作原理。下一张图是网络的图形表示。这将在下面的章节中解释,但是现在,你可以把 CNN 想象成一个预处理管道,为最终的神经网络润色数据。我知道,这个定义可能看起来很胭脂,但是让我们跳到下一段,详细看看它是如何工作的!

A sample architecture for a CNN. made with ❤️ by the Daniele Fontani

输入

在图像分类中,我们从…图像开始!不难理解,图像是由像素组成的二维矩阵(宽*高)。每个像素由 RGB、红、绿、蓝三种不同的值组成。使用 CNN 可以方便的分离 3 个不同的图层,所以你最终的输入矩阵将会是 image_size x image_size x 3 。当然,如果你有一个黑色的&白色的图像,你不需要 3 层,只需要一层,所以你会有 image_size x image_size x 1。嗯,如果你也考虑到你的数据集将由 N 项组成,整个输入矩阵将是 N x 图像大小 x 图像大小 x 3 。图像的大小必须是相同的,不能是全高清图像,以避免太长的时间处理。这方面没有成文的规定,但通常是一种妥协:在某些情况下,256x256 可能是一个不错的值,换句话说,您将需要更高的分辨率。

卷积

在图像内部,许多细节、暗示和阴影与网络无关。所有这些细节可能会混淆训练,因此主要思想是简化图像,保留带来信息的所有数据。这很直观,在文字上很容易,但在实践中呢?CNN 使用卷积步骤,这是这种方法的核心,来减小图像的大小,保留图像中更相关的部分。卷积层之所以有这个名字,是因为它在矩阵的滑动部分和过滤器之间进行卷积。过滤器的大小和要分析的矩阵块是相同的。这一块叫内核。为了使矩阵大小适合内核大小,在所有维度上都用零填充。卷积为所有内核乘法生成一个标量值。这将产生尺寸下降,例如,在 32x32 矩阵(1024 个元素)上使用内核 4x4,您将在输出中得到 4x4 矩阵(16 个元素)。内核的大小会影响最终结果,通常最好保持小内核并链接多个卷积层,我可以在中间添加一些池层(我稍后会谈到池)。

The convoluton process. made with ❤️ by the Daniele Fontani

汇集

汇集层用于减少矩阵大小。有许多方法,但基本的是:我取一组相邻的值,我只用了一个。最常见的算法是最大池,所以,基本上,你把更大的元素放入集合。

The max pool layer. made with ❤️ by the author

完全连接的层

最后一步是神经网络。直到这最后一步,我们已经做了一些“确定性”的运算,只是代数计算。这一步,我们有了真正的人工智能。之前已经完成了所有工作,目的只是生成网络可以理解的数据。

结论

自从我第一次踏入这个领域,在 2008 年,就有了相关的变化。作为一个业余爱好者的第一感觉,就是现在所有的过程都是“确定性的”。通过使用标准技术和良好的文档,使网络工作变得更加容易。体验仍然很重要,我不想将人工智能与常规的数据库读/写操作进行比较,但找到大量的资料、教程、指南是让新手能够工作的事情。

这要归功于大玩家,像往常一样,他们让开发者可以访问 AI,共享他们的库,也许只是让我们知道把他们的所有东西作为服务来消费更容易。😃

给开发者,尤其是最年轻的开发者的大建议是,即使有很多实现神经网络的工具,也要首先专注于一个理论。当您将在库的基础上构建的系统将停止工作,并且您无法理解原因时,理解幕后的工作方式是非常重要的。

参考

利用 SSIM 进行图像分类

原文:https://towardsdatascience.com/image-classification-using-ssim-34e549ec6e12?source=collection_archive---------3-----------------------

用 OpenCV 实现简单的图像分类器

Find the Differences

作为人类,我们通常非常善于发现图片中的差异。比如我们看看上面这张图,看看它们有什么不同。首先,水果、冰淇淋和饮料明显发生了变化。很简单,对吧?

然而,对于计算机来说,这并不是一件容易的事情。计算机只能从我们训练它的模型的东西中学习。有一些很棒的模型可以很好地分类批量图像,比如谷歌的 TensorFlowKeras

多亏了像这样的图像分类器库,计算机视觉有了巨大的飞跃。现在我们可以创建复杂的模型,比如 kaggle 中的这个: Animals-10 ,它包含十种不同类型的动物以及已经训练和清洗过的非动物的数千张图片。你所要做的就是创建一个模型,看看你的模型能多好地预测每一种不同类型的动物。有关图像分类模型的教程,请查看 PrabhuAmitabha

然而,我想创建一个图像分类器,可以告诉如何相似的两个图像。为此,不需要任何复杂的库,如 TensorFlow 或上面链接的图像分类模型。有两种方法可以发现一个图像是否与另一个图像相似。首先是看均方差 ( MSE )其次是结构相似指数 ( SSIM )。

Left is MSE while right is SSIM

他们看起来都很可怕,但没必要担心。由于 NumPy 和 SSIM 是 Sci-Kit 图像库的内置方法部分,所以 MSE 可以很容易地计算出来,所以我们可以加载它。

在我们做所有这些之前,让我们定义一下每个人在计算什么。MSE 将计算我们正在比较的两幅图像的每个像素之间的均方误差。而 SSIM 会反其道而行之,在像素中寻找相似之处;即两个图像中的像素是否对齐和/或具有相似的像素密度值。唯一的问题是 MSE 往往有任意高的数字,所以很难标准化。虽然一般来说,mse 越高,它们越不相似,但如果图片集之间的 MSE 随机出现差异,我们就很难区分任何东西。另一方面,SSIM 把每件事都放在-1 到 1 的范围内(但是我不能给出小于 0 的分数)。1 分意味着它们非常相似,而-1 分意味着它们非常不同。在我看来,这是一个更好的衡量标准。

现在让我们关注代码,并开始导入所有必需的库:

Loading up necessary libraries

我使用 CV2(OpenCV 的一部分)来阅读和编辑我的图片。如果你愿意,也可以用 matplotlib 的 imread 来代替。我的朋友 Yish Lim 在她的博客中为口袋妖怪比赛的相似性做了这件事,这真是太棒了。

现在是写 MSE 公式的可怕部分:

Woah, that was tough

因为 SSIM 已经通过 skimage 导入,所以不需要手工编码。现在我们创建一个函数,它将接收两幅图像,计算它的 mse 和 ssim,并一次显示所有的值。

现在,接下来的三个步骤可以用 for 循环一次完成,但让我们在下面的代码中将其分解,这样更容易理解:

I chose a purposely large picture size for better SSIM, but beware it takes some time to calculate

首先,我们加载保存在目录中的图像。第二,我们必须确保它们都是相同的尺寸,否则我们会得到一个尺寸误差。这样做的问题是会导致图像失真,所以继续玩下去,直到你找到完美的数字。接下来我们再做一个函数,这样我们就可以看到我们的图片是什么样子。

It looks very small, and I haven’t figured out how to increase the size

现在来测试一下,看看我们的 MSE 和 SSIM 是否可以通过比较一张图片来工作。如果可行,那么我们应该得到 0 的 MSE 和 1 的 SSIM。

Yes, it works!

既然我们知道我们的电脑可以判断正在比较的图片是否相同,那么我们比较不同的图片怎么样?为了简单起见,我就把三张狗的图片比作自己,三张猫的图片比作自己。

Left: Comparing three different dogs to each other. Right: Comparing three different cats to each other

让我们看看我们的简单算法刚刚比较了什么。如你所见,MSE 变化很大,所以很难区分什么是什么。但是看看 SSIM,我们可以看到狗 2 和狗 3 相对于其他的狗是最相似的。视觉上,我同意,特别是耳朵。但是我认为狗 1 和狗 3 由于它们的姿势会有更高的 SSIM。事实上,在图片的灰度循环之前,狗 2 和狗 3 的鼻子周围有相似的白色皮毛,而狗 1 没有。这很可能是狗 2 和 3 比狗 1 具有更高 SSIM 值的原因。对于猫来说,这有点困难。猫 1 和猫 2 有相似的形状,照片是从相似的距离拍摄的,但是猫 2 和猫 3 有相似颜色的毛。这可能就是为什么第 1 类和第 3 类与第 2 类和第 3 类评级相似,而第 1 类和第 2 类评级不同的原因。

我只想再进行两项测试。一个是关于一只狗在一只猫面前的样子,第二个是每只动物如何与原始源代码附带的 gate 图片进行比较。

Dog vs. Gate vs. Cat

正如所料,狗和猫是相似的,特别是与一个无生命的物体相比,如侏罗纪公园 1 入口大门(侧注:如此伟大的电影!).狗和猫在门图片上有高 SSIM 的唯一原因是因为它的大小和灰度过滤器。

当谈到调整图像大小和重新配置图像时,OpenCV 不是最好的。为此,谷歌的 TensorFlow 是最好的。然而,我在 TensorFlow 上遇到的问题是,我无法将单张图片加载到它们的图库模块中。TensorFlow 最适合批量图片。

对于未来,我希望使用我提到的 kaggle Animal-10 数据集和 TensorFlow 来运行一个完整的图像分类实验室。

感谢阅读。

[## 图像相似性使用 SSIM

我的 github 链接包含代码。

github.com](https://github.com/imamun93/Image-Similarities-using-SSIM) [## 如何:Python 比较两个图像- PyImageSearch

你能猜到我是一个集邮者吗?开玩笑的。我没有。但是让我们玩一个假装的小游戏…

www.pyimagesearch.com](https://www.pyimagesearch.com/2014/09/15/python-compare-two-images/)

基于 Tensorflow 2.0 的影像分类

原文:https://towardsdatascience.com/image-classification-with-tensorflow-2-0-7696e4aa5ca7?source=collection_archive---------8-----------------------

对自定义图像进行分类的端到端流程

在这篇文章中,我们将解决一个最常见的人工智能问题。场景是这样的:你正在酒吧上网,喝着啤酒,吃着鸡翅,这时你开始想“我能使用 Tensorflow 2.0 和迁移学习编写一个图像分类器吗?”本文将展示实现这一点的端到端过程。注意,我不会深入研究这个模型是如何工作的,那将是另外一篇文章。本文将向您展示如何使用 Tensorflow 2.0。一旦我们有了它,我们就可以回过头来使用参数,这可能会使代码更有效。

唯一的先决条件是:

  1. 一台电脑(显然)。我在一台没有 GPU 的小型笔记本电脑上运行我的程序。
  2. 带摄像头的手机。我们将会生成我们自己的图像。
  3. (可选)云图像存储。我用了亚马逊照片。
  4. Docker,我们将用它来托管我们的 Tensorflow 2.0 环境。如果你没有,安装说明可以在这里找到

我们将遵循的步骤是:

  1. 安装 Tensorflow 2.0 Docker 镜像。
  2. 获取一组图像来训练/验证/测试我们的模型。
  3. 将我们的图像组织成适合我们模型的目录结构。
  4. 下载一个预先训练好的深度学习模型。
  5. 为我们的特定用例(啤酒或鸡翅)定制我们的模型。
  6. 训练我们的定制模型。
  7. 可视化模型预测。

安装 Tensorflow 2.0 Docker 映像

我按照 T2 页面上的指示做了。以下是我使用的具体命令。注意,对于本教程,图像必须包含 Jupyter。

docker pull tensorflow/tensorflow:2.0.0a0-py3-jupyter

首先,cd 到您将存储源代码的目录。从那里,我们将启动我们的映像。我创建了一个简单的 shell 脚本(注意,我是在 Linux 上运行的,如果你在 Mac 或 Windows 上,你可能不需要 sudo 命令:

sudo docker run-it-p 8888:8888-v $ PWD:/TF/data-w/TF/data tensor flow/tensor flow:2 . 0 . 0 A0-py3-jupyter

这里需要知道的最重要的事情是:

  • -p 是端口映射,我们的 Jupyter 笔记本在 Docker 中的端口 8888 上运行,因此我们将在我们的机器上映射端口 8888 以进行匹配。只有当端口 8888 已经在您的机器上使用时,您才应该更改它。
  • -v 是如何在 docker 中挂载一个卷。在本例中,我们将当前目录($ term)挂载为/tp/data。这个 Docker 映像中的 jupyter 笔记本运行在/tp 目录中,因此当您打开 Jupyter 时,应该会看到以下内容:

其中数据目录映射到机器上的当前目录。

运行上述命令后,您将在命令提示符下看到类似这样的内容。

这里重要的一行是“Jupyter 笔记本运行于”之后的一行。您需要复制以“:8888”开头的那一行。然后在你的浏览器中输入 http://localhost 并粘贴你复制的行。在这种情况下:

http://localhost:8888/?token=cd37ab44fab55bce5e44ac6f4bb187a4b34b713c5fbeac9e

至此,Tensorflow 2.0 已经在 Docker 容器中启动并运行,可以访问您的本地文件系统。

获取一组图像来训练/验证/测试我们的模型

这一步很容易。我用手机从不同角度拍了大约 30 张啤酒杯的照片,从不同角度拍了 30 张鸡翅的照片。我是亚马逊 Prime 的大用户,所以我把手机设置成把我的照片备份到亚马逊照片。你可以使用任何你喜欢的云环境(ICloud,Google photos 等),甚至可以用电子邮件给自己发照片。这里的重点是把照片复制到你的电脑上。

将我们的图像组织成适合我们模型的目录结构

第一步是给我们的图像贴标签。有几种方法可以做到这一点,但最终,你会想把所有的“啤酒”图片复制到一个名为“啤酒”的目录中,把你的“翅膀”图片复制到一个名为“翅膀”的目录中。从这里开始,您需要创建一个如下所示的目录结构:

以下是我在 Linux 中使用的命令:

mkdir train
mkdir test
mkdir val
mkdir train/beer
mkdir train/wings
mkdir test/beer
mkdir test/wings
mkdir val/beer
mkdir val/wings

此时,您需要将数据的子集移动到 val 和 test 目录中。经过一些谷歌搜索,我找到了这个命令:

shuf -n 6 -e * | xargs -i mv {} target-directory

我使用以下命令实现了这一点:

cd beer
shuf -n 6 -e * | xargs -i mv {} ../test/beer
shuf -n 6 -e * | xargs -i mv {} ../val/beer
mv * ../train/beer
cd ..
cd wings
shuf -n 6 -e * | xargs -i mv {} ../test/wings
shuf -n 6 -e * | xargs -i mv {} ../val/wings
mv * ../train/wings

这段代码将 6 幅图像分别移动到我们的 val 和 test 文件夹,其余的移动到我们的 train 文件夹。完成这些步骤后,您的目录结构应该如下所示:

下载预先训练好的深度学习模型

此时,在浏览器中返回到 Jupyter 笔记本,并创建一个新笔记本。首先,我们需要导入将要使用的 Python 库:

import numpy as np
import tensorflow.keras
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import  Dropout, Input
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.metrics import categorical_crossentropy
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import itertools
import matplotlib.pyplot as plt
%matplotlib inline

重要的故障排除步骤:您可能会得到缺少库的错误。根据 Docker 映像的版本,您可能需要运行以下步骤:

!pip install --upgrade pip
!pip install pillow
!pip install scipy
!pip install pandas

运行之后,您需要点击重启内核按钮并重新运行导入语句。

现在我们已经完成了 Python 导入,我们需要为每个图像文件夹生成 ImageGenerator 对象。图像生成器获取输入图像,并对其稍加修改,以提供一致性和形状来训练神经网络。请注意,我们的图片将是 224x224。

train_path = '/tf/data/beer_wings/train'
valid_path = '/tf/data/beer_wings/val'
test_path = '/tf/data/beer_wings/test'
train_batches = ImageDataGenerator().flow_from_directory(train_path, target_size=(224,224), classes=['beer', 'wings'], batch_size=32)
valid_batches = ImageDataGenerator().flow_from_directory(valid_path, target_size=(224,224), classes=['beer', 'wings'], batch_size=32)
test_batches = ImageDataGenerator().flow_from_directory(test_path, target_size=(224,224), classes=['beer', 'wings'], batch_size=32)

这是一个有用的函数,可以看看我们的图像生成器在做什么。我从一个非常有用的 Youtube 系列中找到了这个函数:

# plots images with labels within jupyter notebook
def plots(ims, figsize=(24,12), rows=4, interp=False, titles=None):
    if type(ims[0]) is np.ndarray:
        ims = np.array(ims).astype(np.uint8)
        if (ims.shape[-1] != 3):
            ims = ims.transpose((0,2,3,1))
    f = plt.figure(figsize=figsize)
    cols = len(ims)//rows if len(ims) % 2 == 0 else len(ims)//rows + 1
    for i in range(len(ims)):
        sp = f.add_subplot(rows, cols, i+1)
        sp.axis('Off')
        if titles is not None:
            sp.set_title(titles[i], fontsize=32)
        plt.imshow(ims[i], interpolation=None if interp else 'none')
imgs, labels = next(train_batches)
plots(imgs, titles=labels)

输出是:

注[0,1] =鸡翅,[1,0] =啤酒。

最后,我们准备下载我们的预训练模型。在这种情况下,我们将使用 VGG16 型号。Tensorflow 2.0 内置了众多模型。它们在这里被定义为。

这是导入预训练 VGG16 模型的代码:

vgg16_model = tensorflow.keras.applications.vgg16.VGG16(weights='imagenet', include_top=False, input_tensor=Input(shape=(224,224,3)))

就这么简单!嗯,差不多吧,重要的是我们设置 include_top = False,因为我们要创建自己的最终层,还要注意我们的输入形状是(224,224,3)。(224,224)与上面的图像生成器相匹配。多出来的 3 个是颜色通道(红、蓝、绿)。

为我们的特定用例(啤酒或鸡翅)定制我们的模型

现在我们已经下载了一个预训练的模型,它通常可以预测图像分类,让我们根据自己的需要定制它。从理论上讲,像这样的前几层模型简化了图像的部分,并识别出其中的形状。那些早期的标签非常普通(线条、圆环、正方形等等),所以我们不想重新训练它们。我们希望只训练网络的最后几层以及我们添加的新层。

首先,让我们禁用预训练模型中除最后 4 层以外的所有层的训练。

for layer in vgg16_model.layers[:-4]:
    layer.trainable = False

现在,让我们将自己的最后几层添加到网络中:

# Create the model
model = Sequential()

# Add the vgg convolutional base model
model.add(vgg16_model)

# Add new layers
model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(2, activation='softmax'))

# Show a summary of the model. Check the number of trainable parameters
model.summary()

这就是我们基于 VGG16 定制的模型!

训练我们的定制模型

现在我们已经定义了模型,让我们编译它并训练它。

model.compile(loss='categorical_crossentropy',
              optimizer=tensorflow.keras.optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])
history = model.fit_generator(
      train_batches,
      steps_per_epoch=train_batches.samples/train_batches.batch_size ,
      epochs=5,
      validation_data=valid_batches,
      validation_steps=valid_batches.samples/valid_batches.batch_size,
      verbose=1)

可视化模型预测

现在,让我们给训练好的模型输入一组它从未见过的图像。代码中最重要的部分是这两行:

test_imgs, test_labels = next(test_batches)predictions = model.predict(test_imgs)

第一个生成一批新的以前没有见过的图像。让我们看看我们的模型对这些图像的预测:

import pandas as pddef to_label(value):
    if value==0:
        return 'beer'
    else:
        return 'wings'test_imgs, test_labels = next(test_batches)
predictions = model.predict(test_imgs)

df = pd.DataFrame()
df['actual'] = test_labels[:,1]
df['predicted'] = np.round(predictions[:,1])df['predicted_labels']=df['predicted'].map(lambda x: to_label(x))
plots(test_imgs, titles=df['predicted_labels'])

结论

显然,这是一个实现图像分类的无意义的例子,但它确实提供了一些有价值的信息,可以应用于未来的项目。即数据获取、迁移学习和模型评估。请注意,代码可以很容易地修改,以允许多种分类(我们的例子只有 2 个)。

基于迁移学习的图像聚类

原文:https://towardsdatascience.com/image-clustering-using-transfer-learning-df5862779571?source=collection_archive---------2-----------------------

基于 Resnet50 + Kmeans 的猫狗图像聚类模型!!!!

聚类是无监督机器学习的一个有趣领域,我们将数据集分类到一组相似的组中。这是“无监督学习”含义的一部分,其中没有事先训练发生,数据集将是无标签的。可以使用不同的技术进行聚类,如 K-means 聚类、均值漂移聚类、DB 扫描聚类、层次聚类等。所有聚类算法背后的关键假设是特征空间中的邻近点具有相似的质量,并且它们可以被聚类在一起。

在本文中,我们将对图像进行聚类。图像也与常规 ML 中的数据点相同,可视为类似问题。但是最大的问题是,

定义图像的相似度!!!!!

相似性可以意味着看起来相似的图像,或者可以是相似的尺寸,或者可以是相似的像素分布,相似的背景等。对于不同的用例,我们必须导出特定的图像向量。即,包含图像实体(包含猫或狗)的图像向量将不同于具有像素分布的图像向量。

在这篇文章中,我们将有一组猫和狗的图片。我们会试着把它们聚类成猫照和狗照。为此,我们可以从预先训练的 CNN 模型(如 Resnet50)中导出图像向量。我们可以删除 resnet50 的最后一层,并提取 2048 大小的矢量。一旦我们有了向量,我们就在数据点上应用 KMeans 聚类。

这是我的数据集中的一些图片,大约有 60 张从网上随机抽取的猫狗图片。

代码遍历

第一步是加载所需的库并加载预训练的 Resnet50 模型。请记住从模型中移除最后一个 softmax 层。

resnet_weights_path = '../input/resnet50/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5'

my_new_model = Sequential()
my_new_model.add(ResNet50(include_top=False, pooling='avg', weights=resnet_weights_path))

*# Say not to train first layer (ResNet) model. It is already trained*
my_new_model.layers[0].trainable = False

一旦我们加载了模型,我们可以有一个函数来加载所有的图像,将图像调整到固定的像素大小(224,224),通过模型传递它并提取特征集。

def extract_vector(path):
    resnet_feature_list = []

    for im in glob.glob(path):

        im = cv2.imread(im)
        im = cv2.resize(im,(224,224))
        img = preprocess_input(np.expand_dims(im.copy(), axis=0))
        resnet_feature = my_new_model.predict(img)
        resnet_feature_np = np.array(resnet_feature)
        resnet_feature_list.append(resnet_feature_np.flatten())

    return np.array(resnet_feature_list)

一旦我们有了提取的特征集,我们就可以对数据集进行 KMeans 聚类。K 必须事先确定,或者我们可以画出损失函数与 K 的关系,并推导出它。由于我们知道 K 的值为 2,所以可以直接代入。

kmeans = KMeans(n_clusters=2, random_state=0).fit(array)
print(kmeans.labels_)

就这些!!!!我们已经完成了图像聚类模型。让我们看看,我们的模型能多好地聚集图像。

以下是与第一组相对应的一些图像:

这是另一个集群:

总体而言,集群性能似乎非常好。在我聚类的 60 个图像中,只有两个图像被错误地聚类。这些图片如下:

上面两只狗被错误的聚类成了猫。可能是 ML 模型觉得它们很像猫。😃

我们可以使用 t-SNE 算法进一步研究图像的分布。这是一种降维算法,其中 2048 图像向量将被降低到更小的维度,以便更好地绘图、存储和时间限制。下面是我得到的 60 个图像数据集的结果。

蓝点代表聚类-1(猫),绿点代表聚类-2(狗)。请注意,迷你照片不是 t-SNE 的一部分,它只是额外添加的。相交区域可以被认为是模型发现难以恰当地拟合聚类的地方。

结论

希望您对使用迁移学习构建一个基本的图像聚类方法有很好的理解。正如我已经说过的,在某些情况下,CNN 输出可能不是图像特征的最佳选择。我们也可以用 bagging 技术考虑 HSV(色调-饱和度-值)来创建向量,其中相似的像素分布是我们的聚类方法。

快乐学习:)

无监督学习:10 行 R 代码中的图像压缩

原文:https://towardsdatascience.com/image-compression-in-10-lines-of-r-code-7d7a8578d3bb?source=collection_archive---------27-----------------------

机器学习:无监督学习

使用主成分分析压缩图像的酷方法

Photo by Gaetano Cessati on Unsplash

主成分分析(PCA)是一种强大的机器学习工具。作为一种无监督的学习技术,它擅长于降维和特征提取。

但是,你知道我们可以用 PCA 来压缩图像吗?

在这篇文章中,我将介绍这个过程,并解释 PCA 如何用 10 行 R 代码压缩图像,最后描述了简单的数学运算。

Photo by Pietro Jeng on Unsplash

#安装包并加载库

#install.packages(“tidyverse”)
#install.packages(“gbm”)
#install.packages(“e1071”)
#install.packages(“imager”)
library(tidyverse)
library(tree) 
library(randomForest) 
library(gbm) 
library(ROCR) 
library(e1071) 
library(imager)# load the dataset. This is a 100*100*1000 array of data. An array is a generalization of a matrix to more than 2 dimensions. The first two dimensions index the pixels in a 100*100 black and white image of a face; the last dimension is the index for one of 1000 face images. The dataset can be accessed at: [https://cyberextruder.com/face-matching-data-set-download/](https://cyberextruder.com/face-matching-data-set-download/).load(“faces_array.RData”)#PAC requires a single matrix. so, we need to transform the 100*100 matrix into a single vector (10,000). face_mat <- sapply(1:1000, function(i) as.numeric(faces_array[, , i])) %>% t# To visualize the image, we need a matrix. so, let's convert 10000 dimensional vector to a matrix
plot_face <- function(image_vector) { 
 plot(as.cimg(t(matrix(image_vector, ncol=100))), axes=FALSE, asp=1)
 }plot_face(face_mat[, sample(1000, 1)])

这里,我们试图获得数据集的基本信息,并构造一个新的函数进行分析。

#查平均脸

face_average = colMeans(face_mat)plot_face(face_average)

很大程度上,我们可以把“平均脸”理解为其他图像的基线。通过在平均脸上加上或减去数值,我们可以得到其他的脸。

#以上代码不算 10 行的限制。#

#这是我们的 10 行代码#

# generate PCA results;
# scale=TRUE and center=TRUE --> mean 0 and variance 1
pr.out = prcomp(face_mat,center=TRUE, scale=FALSE)# pr.out$sdev: the standard deviations of the principal components; 
# (pr.out$sdev)²: variance of the principal components
pr.var=(pr.out$sdev# pve: variance explained by the principal component
pve = pr.var/sum(pr.var) # cumulative explained variance
cumulative_pve <-cumsum(pve)**#see the math explanation attached in the end** U = pr.out$rotation
Z = t(pr.out$x)# Let's compress the 232nd face of the dataset and add the average face back and create four other images adopting the first 10,50,100, and 300 columns.
par(mfrow=c(1,5))
plot_face(face_mat[232,])
for (i in c(10,50,100,300))
 {
 plot_face((U[,1:i]%*%Z[1:i,])[,232]+face_average) 
 }

我们做到了!成绩还不算太差。最左边是原始图像,后面是四幅压缩图像。

简单的数学解释。

PCA 与矩阵的奇异值分解(SVD)密切相关。所以,x= ud(vt)=**z***(vt),

其中 x 是的 1000*10000 矩阵,

  • v:特征向量的矩阵(由 prcomp 返回的旋转)
  • d:主成分的标准偏差(由 prcomp 返回的 sdev)
  • 所以, z = UD(旋转空间中主分量的坐标(prcomp$x))。

换句话说,我们可以使用 V 的前 k 列和 z 的前 k 列来压缩图像:

数学结束。

喜欢读这本书吗?

请在 LinkedInTwitter 找到我。

查看我关于人工智能和机器学习的其他帖子。

[## 使用 5 种机器学习算法对罕见事件进行分类

哪一种最适合不平衡数据?有什么权衡吗?

towardsdatascience.com](/classifying-rare-events-using-five-machine-learning-techniques-fab464573233)

使用 Python 进行影像数据分析:

原文:https://towardsdatascience.com/image-data-analysis-using-python-edddfdf128f4?source=collection_archive---------1-----------------------

本教程着眼于如何导入图像和观察它的属性,分裂层,还着眼于灰度。

内容:

  • 简介:关于像素的一点点
  • 观察图像的基本属性
  • 灰度
  • 使用逻辑运算符处理像素值
  • 掩饰
  • 图像处理

简介:关于像素的一点点

计算机将图像存储为微小方块的马赛克。这就像古代艺术形式的瓷砖马赛克,或者今天孩子们玩的熔珠工具。现在,如果这些方形瓷砖太大,就很难做出光滑的边缘和曲线。我们使用越多越小的瓷砖,图像就越平滑,或者说像素化程度越低。这些有时被称为图像的分辨率。

矢量图形是一种有点不同的存储图像的方法,旨在避免像素相关的问题。但即使是矢量图像,最终也显示为像素的马赛克。像素这个词的意思是一个图像元素。描述每个像素的简单方法是使用三种颜色的组合,即红、绿、蓝。这就是我们所说的 RGB 图像。

每张数码形式的照片都是由像素组成的。它们是组成图片的最小信息单位。通常为圆形或方形,它们通常排列成二维网格。

现在,如果这三个值都是最大强度,那就意味着它们是 255。然后它显示为白色,如果三种颜色都被静音,或者值为 0,则颜色显示为黑色。这三者的结合将依次给我们一个特定的像素颜色的阴影。因为每个数字都是 8 位数字,所以值的范围是从 0 到 255。

这三种颜色的组合趋于其中的最高值。因为每个值可以有 256 个不同强度或亮度值,所以总共有 1680 万种色调。

现在让我们加载一个图像,观察它的各种属性。

 import imageio
 import matplotlib.pyplot as plt
 %matplotlib inline
 pic = imageio.imread(‘images/me.jpg’)
 plt.figure(figsize = (5,5))
 plt.imshow(pic)

观察图像的基本属性

 print('Type of the image : ' , type(pic)) 
print('Shape of the image : {}'.format(pic.shape)) 
print('Image Hight {}'.format(pic.shape[0])) 
print('Image Width {}'.format(pic.shape[1])) 
print('Dimension of Image {}'.format(pic.ndim)) 

输出:

 Type of the image :  <class 'imageio.core.util.Array'> 
Shape of the image : (728, 720, 3) 
Image Hight 728 
Image Width 720 
Dimension of Image 3 

阵列的形状表明它是一个三层矩阵。这里的前两个数字是长度和宽度,第三个数字(即 3)用于三层:红色、绿色、蓝色。因此,如果我们计算一个 RGB 图像的大小,总的大小将被计算为高 x 宽 x 3

 print('Image size {}'.format(pic.size)) 
print('Maximum RGB value in this image {}'.format(pic.max())) print('Minimum RGB value in this image {}'.format(pic.min())) 

输出:

 Image size 1572480 
Maximum RGB value in this image 255 
Minimum RGB value in this image 0 # A specific pixel located at Row : 100 ; Column : 50  
# Each channel's value of it, gradually R , G , B  
print('Value of only R channel {}'.format(pic[ 100, 50, 0])) print('Value of only G channel {}'.format(pic[ 100, 50, 1])) print('Value of only B channel {}'.format(pic[ 100, 50, 2])) 

输出:

Value of only R channel 168
Value of only G channel 189
Value of only B channel 182

好了,现在让我们快速浏览一下整个图像中的每个通道。

plt.title('R channel') 
plt.ylabel('Height {}'.format(pic.shape[0])) 
plt.xlabel('Width {}'.format(pic.shape[1])) 
plt.imshow(pic[ : , : , 0])
plt.show()

plt.title('G channel')
plt.ylabel('Height {}'.format(pic.shape[0])) 
plt.xlabel('Width {}'.format(pic.shape[1])) 
plt.imshow(pic[ : , : , 1]) 
plt.show()

plt.title('B channel') 
plt.ylabel('Height {}'.format(pic.shape[0])) 
plt.xlabel('Width {}'.format(pic.shape[1])) 
plt.imshow(pic[ : , : , 2]) 
plt.show()

现在,我们还可以改变 RGB 值的数量。作为一个例子,让我们设置红色,绿色,蓝色层的后续行值为全强度。

  • r 通道:第 100 至 110 行
  • g 通道:第 200 至 210 行
  • b 通道:行— 300 至 310

我们将加载图像一次,这样我们可以同时看到每个变化。

pic[50:150 , : , 0] = 255 # full intensity to those pixel's R channel 
plt.figure( figsize = (5,5)) 
plt.imshow(pic) 
plt.show()

pic[200:300 , : , 1] = 255 # full intensity to those pixel's G channel 
plt.figure( figsize = (5,5)) 
plt.imshow(pic) 
plt.show()

pic[350:450 , : , 2] = 255 # full intensity to those pixel's B channel 
plt.figure( figsize = (5,5)) 
plt.imshow(pic) 
plt.show()

为了使它更清楚,让我们改变列部分,这一次我们将同时改变 RGB 通道。

# set value 200 of all channels to those pixels which turns them to white 
pic[ 50:450 , 400:600 , [0,1,2] ] = 200  
plt.figure( figsize = (5,5)) 
plt.imshow(pic) 
plt.show()

拆分层

现在,我们知道图像的每个像素由三个整数表示。将图像分割成单独的颜色分量仅仅是取出图像阵列的正确切片的问题。

import numpy as np 
pic = imageio.imread('images/me.jpg') 
fig, ax = plt.subplots(nrows = 1, ncols=3, figsize=(15,5))  
for c, ax in zip(range(3), ax):     
     # create zero matrix        
     split_img = np.zeros(pic.shape, dtype="uint8") 
     # 'dtype' by default: 'numpy.float64'  # assing each channel      
     split_img[ :, :, c] = pic[ :, :, c] # display each channel     
     ax.imshow(split_img)

灰度

黑白图像存储在二维数组中。有两种类型的黑白图像:

- Binary: Pixel is either black or white:0 or 255
- Greyscale: Ranges of shades of grey:0 ~ 255

现在,灰度化是一个将图像从全色转换为灰色阴影的过程。例如,在图像处理工具中:在 OpenCV 中,许多函数在处理之前使用灰度图像,这样做是因为它简化了图像,几乎起到了降噪的作用,并增加了处理时间,因为图像中的信息较少。

在 python 中有几种方法可以将图像转换为灰度,但使用 matplotlib 的一种直接方法是使用此公式对原始图像的 RGB 值进行加权平均。

Y' = 0.299 R + 0.587 G + 0.114 B

pic = imageio.imread('images/me.jpg') 
gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114])   gray = gray(pic) plt.figure( figsize = (5,5))  
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray')) 
plt.show()

使用逻辑运算符处理像素值

我们可以使用逻辑运算符创建一个相同大小的金块数组。然而,这不会创建任何新的数组,只是将 True 返回给它的主机变量。例如,假设我们想要过滤掉 RGB 图像中的一些低值像素或高值像素或(任何条件),是的,将 RGB 转换为灰度是很好的,但目前,我们不会这样做,而是处理彩色图像。

让我们首先加载一个图像并在屏幕上显示它。

pic = imageio.imread('images/logic_op_pic.JPG') 
plt.figure(figsize=(5,5)) 
plt.imshow(pic) 
plt.show()

让我们考虑这个转储图像。现在,在任何情况下,我们都要过滤掉所有的像素值,假设低于 20。为此,我们将使用一个逻辑操作符来完成这项任务,我们将为所有索引返回 True 值。

low_pixel = pic < 20  
# to ensure of it let's check if all values in low_pixel are True or not 
if low_pixel.any() == True:     
    print(low_pixel.shape)

输出:

(743, 911, 3)

正如我们所说的,主机变量传统上不被使用,但是我引用它是因为它的行为。它只包含真正的值,没有其他内容。所以,如果我们同时看到 low_pixel 和 pic 的形状,我们会发现两者的形状是一样的。

print(pic.shape)
print(low_pixel.shape)

输出:

(743, 911, 3)
(743, 911, 3)

我们使用全局比较运算符为所有小于 200 的值生成了低值过滤器。但是,我们可以使用这个 low_pixel 数组作为索引,将那些低值设置为一些特定的值,这些值可能高于或低于前面的像素值。

# randomly choose a value 
import random

# load the orginal image

pic = imageio.imread('images/logic_op_pic.JPG')

# set value randomly range from 25 to 225 - these value also randomly choosen
pic[low_pixel] = random.randint(25,225)
# display the image
plt.figure( figsize = (5,5))
plt.imshow(pic)
plt.show()

掩饰

图像遮罩是一种图像处理技术,用于从具有模糊边缘、透明或毛发部分的照片中移除背景。

现在,我们将创建一个圆盘形状的遮罩。首先,我们将测量从图像中心到每个边界像素值的距离。我们取一个方便的半径值,然后使用逻辑运算符,我们将创建一个圆盘。挺简单的,看看代码吧。

# Load the image 
pic = imageio.imread('images/logic_op_pic.JPG')  
# seperate the row and column values  
total_row , total_col , layers = pic.shape  
'''     Create vector.     Ogrid is a compact method of creating a multidimensional     ndarray operations in single lines.     
for ex:     
>>> ogrid[0:5,0:5]     
output: [array([[0],
                [1],
                [2],
                [3],
                [4]]),
         array([[0, 1, 2, 3, 4]])]  
''' 
x , y = np.ogrid[:total_row , :total_col]  
# get the center values of the image 
cen_x , cen_y = total_row/2 , total_col/2 '''    
 Measure distance value from center to each border pixel.     To make it easy, we can think it's like, we draw a line from center-     to each edge pixel value --> s**2 = (Y-y)**2 + (X-x)**2  
''' 
distance_from_the_center = np.sqrt((x-cen_x)**2 + (y-cen_y)**2)  
# Select convenient radius value 
radius = (total_row/2)  
# Using logical operator '>'  
''' 
logical operator to do this task which will return as a value  of True for all the index according to the given condition 
''' 
circular_pic = distance_from_the_center > radius ''' 
let assign value zero for all pixel value that outside the cirular disc. All the pixel value outside the circular disc, will be black now. 
''' pic[circular_pic] = 0 
plt.figure(figsize = (5,5)) 
plt.imshow(pic)  
plt.show()

图像处理

关于 edX 的 MOOC 课程之一,我们已经介绍了一些卫星图像及其处理系统。这当然是非常有益的。但是,让我们对它进行一些分析

这幅图像有一些有趣的地方。像许多其他可视化一样,每个 RGB 层中的颜色都有一定的含义。例如,红色的强度将指示像素中地理数据点的高度。蓝色的强度表示坡向的度量,绿色表示坡度。这些颜色将有助于以更快、更有效的方式传达这些信息,而不是显示数字。

Red pixel indicates: Altitude
Blue pixel indicates: Aspect
Green pixel indicates: Slope

仅仅通过看这张彩色的图像,一只训练有素的眼睛就能分辨出高度、坡度和方位。所以,这就是给这些颜色赋予更多意义的想法,以表明一些更科学的东西。

# Only Red Pixel value , higher than 180
pic = imageio.imread('images/sat_img.JPG')
red_mask = pic[:, :, 0] < 180
pic[red_mask] = 0
plt.figure(figsize=(5,5))
plt.imshow(pic)

# Only Green Pixel value , higher than 180
pic = imageio.imread('images/sat_img.JPG')
green_mask = pic[:, :, 1] < 180
pic[green_mask] = 0
plt.figure(figsize=(5,5))
plt.imshow(pic)
# Only Blue Pixel value , higher than 180
pic = imageio.imread('images/sat_img.JPG')
blue_mask = pic[:, :, 2] < 180
pic[blue_mask] = 0
plt.figure(figsize=(5,5))
plt.imshow(pic)
# Composite mask using logical_and
pic = imageio.imread('images/sat_img.JPG')
final_mask = np.logical_and(red_mask, green_mask, blue_mask)
pic[final_mask] = 40
plt.figure(figsize=(5,5))
plt.imshow(pic)

记住你可以在我的 github 库这里找到完整的工作代码。

感谢的阅读,我很高兴讨论你可能有的任何问题或纠正:)如果你想讨论机器学习或其他任何问题,请在 LinkedIn 上找到我。

Keras 中的图像数据生成器

原文:https://towardsdatascience.com/image-data-generators-in-keras-7c5fc6928400?source=collection_archive---------4-----------------------

如何有效和高效地使用 Keras 中的数据生成器进行深度学习的计算机视觉应用

我做过学术研究员,目前在业内做研究工程师。到目前为止,我在这两个角色中的经验告诉我,不能过分强调数据生成器对于培训的重要性。从只有 6 万张训练图像的 MNIST 数据集到拥有超过 1400 万张图像的 ImageNet 数据集[1],数据生成器将是深度学习训练和推理的无价工具。使用数据生成器的几个主要优势如下:

  • 允许使用多处理:在多个 CPU 内核上并行化加载过程,以加快进程。
  • 允许你生成批次:你可以使用更小的数据块通过批次梯度下降来训练你的模型。实际上,所有与深度学习相关的真实世界数据集通常都无法一次放入内存,所以大多数时候这是唯一可能的解决方案。
  • 允许您进行数据增强:不管您的数据是否有限,也不管您是否希望在噪声增强方面增加多样性,您通常都会这样做。通过使用现代 CPU 的多处理能力,数据生成器有助于静态和动态地完成这些工作。
  • 不需要编写样板代码:大多数深度学习框架都支持他们的数据加载器/数据生成器版本,这减少了您必须编写样板代码来处理批量数据的创建及其并行化增加的时间。这也在代码中引入了一致性和可读性。

在本文中,我将讨论如何使用 Keras中的数据生成器进行图像处理相关的应用,并分享我在研究期间使用的技术。

Keras 中的数据生成器[2]

Keras 有适用于不同数据类型的 DataGenerator 类。然而,正如我前面提到的,这篇文章是关于图像的,对于这个数据来说,ImageDataGenerator 是相应的类。

我将使用代码来解释这个过程,因为我相信这会导致更好的理解。我将涉及六个方面。

  1. 创建数据生成器
  2. 一些有用的数据生成器属性
  3. 用于快速正确性测试的可视化数据生成器张量
  4. 使用数据生成器进行培训
  5. 使用数据生成器进行预测
  6. 培训、验证和测试集创建

1.创建数据生成器

我们从本教程所需的导入开始。这涉及 ImageDataGenerator 类和其他一些可视化库。

创建生成器包括两个主要步骤。

  1. 用必需的参数实例化 ImageDataGenerator 以创建对象
  2. 根据数据在磁盘上的存储方式,使用适当的 flow 命令(稍后将详细介绍)。这个命令将允许您动态地生成和访问批量数据。

下面显示了实现上述两个步骤的示例代码。

我们从指定批量大小的第一行代码开始。我们将其设置为 32,这意味着一批图像将有 32 个图像以张量形式堆叠在一起。这个数组的形状应该是(batch_size,image_y,image_x,channels)。这是信道最后的方法,即信道的数量在最后的维度中。

字典中为 ImageDataGenerator 构造函数指定的参数很少。下面将对它们进行解释。[2]

  • 旋转 _ 范围:整数。随机旋转的度数范围。
  • height_shift_range :沿高度方向移动图像。它支持各种输入。对于浮动,如果<为 1,图像将移动总高度的
    部分,或者如果> = 1,图像将移动像素。
  • width_shift_range :沿宽度方向移动图像。
  • 重新调整:重新调整因子。默认为无。如果无或为 0,则不应用重缩放,否则我们将数据乘以所提供的值(在应用所有其他变换之后)。
  • fill_mode :为{"constant "、" nearest "、" reflect "或" wrap"}之一。默认值为“最近”。根据给定的模式填充输入边界外的点。

除了上述论点之外,还有其他几个论点。这些允许你在向你的网络提供数据的时候动态地扩充你的数据。有关更多详细信息,请参考文档[2]。

然后,使用 python 关键字参数将这些参数传递给 ImageDataGenerator,我们创建 datagen 对象。下一步是使用这个对象的 flow_from _directory 函数。当您将映像组织到操作系统上的文件夹中时,可以使用这种方法。

目录结构应该如下所示。

Source: From author

数据目录应该为每个类包含一个文件夹,该文件夹与该类以及该特定类的所有训练样本具有相同的名称。在上面的例子中,每个类有 k 个类和 n 个类。这使得样本总数 nk 。虽然每个类可以有不同数量的样本。

flow_from_directory 函数的参数解释如下。[2]

  • 目录:字符串,目标目录的路径。每个类应该包含一个子目录。
  • :可选的类子目录列表(如['dogs', 'cats'])。如果你只需要直接在中的几个类,只需要把它们指定为一个列表。顺序事项和类别索引按照列表顺序分配。
  • class_mode :“分类”、“二元”、“稀疏”、“输入”或无之一。默认:“分类”。这决定了生成器返回的标签类型。
    ‘分类’用于多个类。标签是一种热编码。
    ‘二进制’是两个类。
    “稀疏”返回 1D 整数标签
    “输入”这对于自动编码器非常有用,因为您需要输入图像是标签
    “无”将导致生成器不返回任何标签
  • target_size :整数元组(height, width),默认:(256, 256)。找到的所有图像将被调整到的尺寸。
  • 插值:如果目标尺寸与加载的图像尺寸不同时,用于对图像重新取样的插值方法。“lanczos”在你缩小图片时很有用。在这个例子中,这就是我使用“lanczos”的原因。

在本教程中,我使用的是可描述的纹理数据集[3],它可以在这里找到。它包含 47 节课,每节课 120 个例子。所有的图像都有不同的尺寸。flow_from_directory 的 target_size 参数允许您创建大小相等的批。如果数据集包含不同大小的图像,这将非常方便。

2.一些有用的数据生成器属性

接下来,我们看看我们刚刚创建的数据生成器的一些有用的属性和函数。“样本”给出了数据集中可用图像的总数。' class _ indices '给出了类名到整数映射的字典。这些是非常重要的,因为当你做预测的时候你会需要这个。因为当你做预测时,你将得到类别号,除非你知道映射,否则你将不能区分哪个是哪个。

Source: From author

Source: From author

“文件名”给出了目录中所有文件名的列表。如果您想要分析模型在几个选定样本上的性能,或者想要将输出概率直接分配给样本,这将非常有用。

Source: From author

datagenerator 对象是一个 python 生成器,在每一步都生成(x,y)对。在 python 中,应用于生成器的 next()从生成器生成一个样本。

Source: From author

正如所料,( x,y)都是 numpy 数组。图像批次是具有(128,128,3)维的 32 个样本的 4d 阵列。标签是一个具有(32,47)形状的热编码矢量。一种热编码意味着将类别号编码为长度等于类别数的向量。除了样本所属的类别之外,所有类别的向量都为零。因此,对于一个三类数据集,来自类 2 的样本的一个热向量将是[0,1,0]。

3.用于快速正确性测试的可视化数据生成器张量

因为我们现在有了一个批次和它的标签,我们将观察并检查是否一切都如预期的那样。

我已经编写了一个网格绘图实用函数,它可以绘制整洁的图像网格,并有助于可视化。它接受输入 image_list 作为图像列表或 numpy 数组。 nrowsncols 分别是结果网格的行和列。

下面显示了一个可视化示例。

Source: https://www.robots.ox.ac.uk/~vgg/data/dtd/

我们看到图像如预期的那样随机旋转,并且填充是最近的,它重复有效帧中最近的像素值。图像也在水平和垂直方向上随机移动。它们都被调整到(128,128)的大小,并且它们保留它们的颜色值,因为颜色模式是“rgb”。

在这个阶段,你应该观察几个批次,确保样品看起来像你想要的样子。转换工作正常,没有任何不希望的结果。例如,如果对包含手写数字的 MNIST 数据集应用垂直翻转,9 将变成 6,反之亦然。这将损害训练,因为即使对于正确的预测,模型也会受到惩罚。

接下来,让我们比较一下与原始图像相比,图像批次是如何出现的。为此,我们将 shuffle 设置为 False,并创建另一个生成器。这允许我们将文件名映射到由数据生成器生成的批处理。datagenerators 有一个 reset()方法,可以将它重置为第一批。因此,每当您想要将模型输出与文件名相关联时,您需要将 shuffle 设置为 False,并在执行任何预测之前重置数据生成器。这将确保我们的文件被正确读取,并且没有任何错误。

Source: From author

我们可以看到原始图像具有不同的大小和方向。我们批量获得增强图像。

4.使用数据生成器进行培训

接下来,让我们继续讨论如何使用数据生成器来训练模型。这就是 Keras 的亮点,它提供了这些训练抽象,可以让你快速训练你的模型。这对快速成型非常有利。并且训练样本将使用多处理(如果启用的话)动态生成,从而使训练更快。

我将解释所使用的论点。[2]

  • steps_per_epoch :整数。在宣布一个时期结束并开始下一个时期之前,从generator开始产生的总步骤数(样品批次)。它通常应该等于ceil(num_samples / batch_size). This ensures that the model sees all the examples once per epoch.
  • 历元:整数。训练模型的时期数。按照steps_per_epoch的定义,一个历元是对所提供的全部数据的迭代。
  • 工人:整数。使用基于进程的线程时要加速运行的最大进程数。如果未指定,workers将默认为 1。如果为 0,将在主线程上执行生成器。
  • 使用 _ 多重处理:布尔型。如果True,使用基于进程的线程。如果未指定,use_multiprocessing将默认为False。注意,因为这个实现依赖于多重处理,所以您不应该将不可选择的参数传递给生成器,因为它们不容易传递给子进程。
  • 验证 _ 数据:这可以是下面的:
    ‣验证数据的生成器或对象Sequence
    ‣元组(x_val, y_val) ‣元组(x_val, y_val, val_sample_weights)在每个时期结束时在其上评估损失和任何模型度量。该模型不会根据此数据进行训练。
  • 验证 _ 步骤:仅当validation_data为发电机时相关。在每个时期结束时停止之前,从validation_data发生器产生的总步骤数(样品批次)。它通常应等于认证数据集的样本数除以批次大小。Sequence可选:如果未指定,将使用len(validation_data)作为多个步骤。

workers 和 use_multiprocessing 函数允许您使用多重处理。一次只指定其中一个。请记住将该值设置为 CPU 上的核心数,否则如果您指定一个更高的值,将会导致性能下降。

5.使用数据生成器进行预测

Keras 使得使用数据生成器进行预测变得非常简单和直接。

它有相同的多重处理参数可用。

6.培训、验证和测试集创建

本文最后一部分将集中在训练、验证和测试集创建上。这可以通过两种不同的方式实现。

  1. 第一种方法是创建三个独立的目录,并创建三个不同的数据生成器。关于如何以可重复的方式进行分割,请参考【4】。这是一个简单的选择,因为你知道训练集、val 集和测试集中有哪些样本。
  2. 第二种方法是在 ImageDataGenerator 构造函数中使用“validation_split”参数。仅当每个类别有一个包含训练和验证样本的文件夹,而不是有两个不同的目录时,才使用此参数。但是在这种情况下,您仍然有一个单独的测试集目录。此外,您必须为 flow_from_directory 函数使用 subset 参数。这些论点解释如下。
    验证 _ 拆分:浮点。保留用于验证的图像比例(严格介于 0 和 1 之间)。因此,如果使用值 0.2,那么将为验证集保留 20%的样本,为训练集保留剩余的 80%。
    子集:如果ImageDataGenerator中设置了validation_split,则为数据的子集("training""validation"

第二种方法的代码如下所示,因为第一种方法很简单,已经在第 1 节中介绍过了。

Source: From author

由于我将 validation_split 值指定为 0.2,因此 20%的样本(即 1128 幅图像)被分配给验证生成器。训练和验证生成器是在 flow_from_directory 函数中用 subset 参数标识的。

关于 Keras 中数据生成器的教程到此结束。希望到现在为止,您已经对 Keras 中的数据生成器有了更深的理解,为什么这些很重要,以及如何有效地使用它们。

我已经在下面的库中提供了代码。

https://github.com/msminhas93/KerasImageDatagenTutorial

如果您发现任何错误或面临任何困难,请不要犹豫,通过 LinkedIn 或 GitHub 与我联系。

感谢您阅读帖子。快乐学习!

参考

[1]ImageNet(image-net.org)

[2]https://keras.io/preprocessing/image/

https://www.robots.ox.ac.uk/~vgg/data/dtd/

https://cs230.stanford.edu/blog/split/

基于 MCMC 的图像去噪

原文:https://towardsdatascience.com/image-denoising-by-mcmc-fc97adeaba9b?source=collection_archive---------27-----------------------

用马尔可夫链蒙特卡罗结合伊辛模型清除噪声二值图像

在这篇文章中,我将演示使用马尔可夫链蒙特卡罗去噪二值图像。

马尔可夫链蒙特卡罗(简称 MCMC)是指一类通过抽样来估计概率分布的技术。基于用于绘制样本的方法,构成 MCMC 的各种技术彼此不同。一些更著名的 MCMC 技术是 Metropolis-Hastings、Gibbs 抽样和 Hamiltonian 蒙特卡罗。我将使用的技术是吉布斯抽样。

Gibbs 抽样是在所有其他变量保持不变的情况下,从多元分布中进行抽样的一种方法。

例如,如果分布只有两个变量 x1 和 x2,则抽样如下:

Example distribution

它从点 1 开始,然后当要对第二个点进行采样时,它是这样的:

P(x2|x1),它在与 x1 相同的行上寻找下一个样本(保持不变)

随后第三个点采样如下:

P(x1|x2),它在与 x2 相同的线上寻找下一个样本(保持不变)

依此类推,采样过程针对设定数量的点继续进行,从而允许其遍历整个空间。

Ising Model

伊辛模型是对应于用于模拟相变的正方形晶格的数学模型。晶格中的每个元素可以以两种离散状态存在,可以用+1 和-1 来表示。每个元素对其所有相邻元素施加影响,并试图达到一种平衡状态,在这种状态下,所有元素都以相同的状态存在。

应用:

Conceptualized model of image

二进制图像可以被认为是格子的形式,每个像素代表一个元素。根据像素的颜色,像素的状态可以表示为 1 或-1。图像可以想象为由两层组成,下面的层代表真实的图像,上面的层代表噪声。高斯噪声被称为叠加在图像上,它在某些地方与实际图像匹配,而在某些地方取相反的值。

伊辛模型被应用于由噪声组成的上述层。噪声受每个相邻噪声的影响取决于它们之间的紧密程度,由边缘电位表示。他们越是紧密地联系在一起,就越是试图处于同一种状态。边缘电位的公式由下式给出:

exp(J,X,X)

这里 J 是耦合常数,它表示邻居之间的联系有多紧密。Xₐ代表考虑中的像素,Xₙ代表其邻居的观察值。

高斯观察模型用于模拟噪声和预先存在的像素之间的关系。噪声被认为是实际基础像素值的函数,也是与其标准偏差的函数。它可以表示为:

N(Yₐ | Xₐ,σ)

这里,Yₐ代表像素的观察值,Xₐ代表考虑中的像素,σ代表标准差。

正是这两种力量的相互作用决定了像素的最终值。耦合常数试图保持所有相邻像素(噪声)处于相同的状态或颜色。高斯模型试图将像素的实际颜色与观察到的颜色(噪声)相匹配。这两种力的影响可以通过改变 J 和σ的值来控制。

所应用的吉布斯采样将根据其所有邻居和基础真值对每个像素进行采样。然后,它会修正这个值,继续处理下一个元素,并重复相同的操作。当它遍历完整个网格时,一次迭代就完成了。根据迭代次数,最终图像质量可能会有所不同。

Xₐ所考虑的像素可以取值+1 或-1。上面的表达式给出了 Xₐ取值+1 或-1 的可能性。

分子给出 Xₐ为例如+1 的可能性,并检查其与像素 Yₐ的观察值以及与其邻居 Xₙ.的观察值的关系

它除以分别取值为+1 和-1 的可能性之和,得出 Xₐ实际值为+1 的概率。

代码:

代码的目的是从损坏的图像中恢复原始图像。

Corrupted image

import numpy as np
import cv2 
import random 
import scipy
from scipy.spatial import distance
from scipy.stats import multivariate_normal
import pandas as pd
from PIL import Imagedata = Image.open('noise_img.png')
image = np.asarray(data).astype(np.float32)

图像以二维数组的形式导入并保存,其中包含像素的灰度值。为了便于操作,这个图像被转换成一个数组。

然后通过将所有 0(对应黑色)替换为-1,将所有 255(对应白色)替换为+1,将其转换为伊辛模型。数组的所有边都用 0 填充,以使在网格上迭代的任务更容易。

#Convert image values to ising model
for i in range(len(image)):
    for j in range(len(image[0])):
        if image[i,j,:] == 255:
            image[i,j,:] = 1
        else:
            image[i,j,:] = -1#Create array to perform operations on
ising = np.zeros((len(image)+2,len(image[0])+2))for i in range(len(image)):
    for j in range(len(image[0])):
        ising[i+1,j+1] = image[i,j,:]

Image array

第一行和第一列是填充。其余的行和列分别对应于一个像素的颜色。行号和列号对应于像素的位置,单元值对应于颜色。

在开始吉布斯采样之前,为耦合强度设置一个值。

#Coupling strength
J=4#Gibbs sampling 
for n in range(3):
    for i in range(1,len(ising[0])-1):
        for j in range(1,len(ising)-1):
            pot = []
            for x in [-1, 1]:
                edge_pot = np.exp(J*ising[j-1,i]*x) * np.exp(J*ising[j,i-1]*x) * np.exp(J*ising[j+1,i]*x) * np.exp(J*ising[j,i+1]*x)
                pot.append(edge_pot)
            prob1 = multivariate_normal.pdf(image[j-1,i-1,:], mean = 1, cov = 1)*pot[1]/(multivariate_normal.pdf(image[j-1,i-1,:], mean = 1, cov = 1)*pot[1] + multivariate_normal.pdf(image[j-1,i-1,:], mean = -1, cov = 1)*pot[0]) 
            if np.random.uniform() <= prob1:
                ising[j,i] = 1
            else:
                ising[j,i] = -1

迭代原始数组中除零以外的所有值。通过检查原始颜色为+1 或-1 的可能性,对每个点进行采样。对于这两种情况,都计算了与其邻居的边缘电势。与边缘电位一起,观察值的可能性是相对于真实值+1 或-1 计算的。

基于以上两个值,像素为+1 的可能性通过将其除以像素为+1 和-1 的可能性来计算。

然后将该值与从标准正态分布中随机抽取的值进行比较。如果原始值为+1 的概率较高,则该值被设置为+1,否则被设置为-1。

当下一个元素被采样时,它在计算边沿电位时采用上述元素的新值。这段代码遍历整个点阵的每个元素三次。

#Retrieving the final array
final = np.zeros((len(image),len(image[0])))
final = ising[1:len(ising)-1,1:len(ising[0])-1]#Converting it back to image
for i in range(len(final[0])):
    for j in range(len(final)):
        if final[j,i] == 1:
            final[j,i] = 255
        else:
            final[j,i] = 0

然后移除填充,然后将值转换回灰度值,然后可视化。

Cleaned image

最后,我们有去噪的图像。

你也可以通过 LinkedIn 与我联系。

Python 中的图像过滤器

原文:https://towardsdatascience.com/image-filters-in-python-26ee938e57d2?source=collection_archive---------2-----------------------

我目前正在从事一个计算机视觉项目,我想研究图像预处理,以帮助改进我计划建立的机器学习模型。图像预处理包括对图像应用图像过滤器。本文将比较一些最著名的图像过滤器。

图像过滤器可用于减少图像中的噪声量并增强图像的边缘。图像中可能存在两种类型的噪声:斑点噪声和椒盐噪声。斑点噪声是在图像采集期间出现的噪声,而椒盐噪声(指稀疏出现的白色和黑色像素)是由图像信号中的突然干扰引起的。增强图像的边缘可以帮助模型检测图像的特征。

图像预处理步骤可以提高机器学习模型的准确性。当与在未经预处理的图像上训练的更复杂的模型相比时,预处理的图像可以帮助基本模型实现高精度。对于 Python,Open-CV 和 PIL 包允许你应用几个数字滤波器。应用数字滤波器需要将图像与内核(一个小矩阵)进行卷积。内核是一个n×n的方阵,其中 n 是奇数。内核依赖于数字滤波器。图 1 显示了用于 3 x 3 均值滤波器的内核。来自 http://kdef.se/ KDEF 数据集的一幅图像(可以在这里找到:)将用于数字滤波器示例。

Figure 1: A 3 x 3 mean filter kernel

1.均值滤波器

均值滤波器用于模糊图像,以消除噪声。它包括确定一个n×n内核中像素值的平均值。然后,中心元素的像素强度由平均值代替。这消除了图像中的一些噪声,并平滑了图像的边缘。Open-CV 库中的模糊函数可用于对图像应用均值滤镜。

当处理彩色图像时,首先需要从 RGB 转换到 HSV,因为 RGB 的维度相互依赖,而 HSV 中的三个维度相互独立(这允许我们分别对三个维度中的每一个应用过滤器。)

以下是均值过滤器的 python 实现:

import numpy as npimport cv2from matplotlib import pyplot as pltfrom PIL import Image, ImageFilter%matplotlib inlineimage = cv2.imread('AM04NES.JPG') # reads the imageimage = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # convert to HSVfigure_size = 9 # the dimension of the x and y axis of the kernal.new_image = cv2.blur(image,(figure_size, figure_size))plt.figure(figsize=(11,6))plt.subplot(121), plt.imshow(cv2.cvtColor(image, cv2.COLOR_HSV2RGB)),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(cv2.cvtColor(new_image, cv2.COLOR_HSV2RGB)),plt.title('Mean filter')plt.xticks([]), plt.yticks([])plt.show()

Figure 2: The result of applying a mean filter to a color image

图 2 显示,虽然一些散斑噪声已经减少,但是图像中现在存在许多以前不存在的伪像。我们可以检查在对灰度图像应用均值滤波时是否产生了任何伪像。

# The image will first be converted to grayscale
image2 = cv2.cvtColor(image, cv2.COLOR_HSV2BGR)image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)figure_size = 9new_image = cv2.blur(image2,(figure_size, figure_size))plt.figure(figsize=(11,6))plt.subplot(121), plt.imshow(image2, cmap='gray'),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(new_image, cmap='gray'),plt.title('Mean filter')plt.xticks([]), plt.yticks([])plt.show()

Figure 3: The result of applying a mean filter to a grayscale image

图 3 显示均值滤波去除了一些噪声,并且不会为灰度图像产生伪像。然而,一些细节已经丢失。

2.高斯滤波器

高斯滤波器类似于均值滤波器,但是它涉及周围像素的加权平均,并且具有参数σ。核表示高斯分布的离散近似。虽然高斯滤波器会模糊图像的边缘(像均值滤波器一样),但它在保留边缘方面比类似大小的均值滤波器做得更好。Open-CV 软件包中的“GaussianBlur”函数可用于实现高斯滤波器。该函数允许您指定内核的形状。您也可以分别指定 x 和 y 方向的标准偏差。如果只指定了一个西格玛值,那么它被认为是 x 和 y 方向的西格玛值。

new_image = cv2.GaussianBlur(image, (figure_size, figure_size),0)plt.figure(figsize=(11,6))plt.subplot(121), plt.imshow(cv2.cvtColor(image, cv2.COLOR_HSV2RGB)),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(cv2.cvtColor(new_image, cv2.COLOR_HSV2RGB)),plt.title('Gaussian Filter')plt.xticks([]), plt.yticks([])plt.show()

Figure 4: The result of applying a Gaussian filter to a color image

图 4 显示,与均值滤波器相比,高斯滤波器在保留图像边缘方面做得更好,但是它也会在彩色图像上产生伪像。我们现在可以检查高斯滤波器是否会在灰度图像上产生伪像。

new_image_gauss = cv2.GaussianBlur(image2, (figure_size, figure_size),0)plt.figure(figsize=(11,6))plt.subplot(121), plt.imshow(image2, cmap='gray'),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(new_image_gauss, cmap='gray'),plt.title('Gaussian Filter')plt.xticks([]), plt.yticks([])plt.show()

Figure 5: The result of applying a Gaussian filter to a grayscale image

图 5 显示 9 x 9 高斯滤波器应用于灰度图像时不会产生伪像。该滤波器可以保留比 9 x 9 均值滤波器更多的细节,并去除一些噪声。

3.中值滤波器

中值滤波器计算在 n x n 内核中围绕中心像素的像素亮度的中值。然后,中值替换中心像素的像素强度。与均值和高斯滤波器相比,中值滤波器在去除椒盐噪声方面做得更好。中值滤波器保留了图像的边缘,但它不处理斑点噪声。Open-CV 库中的“medianBlur”函数可用于实现中值滤波器。

new_image = cv2.medianBlur(image, figure_size)plt.figure(figsize=(11,6))plt.subplot(121), plt.imshow(cv2.cvtColor(image, cv2.COLOR_HSV2RGB)),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(cv2.cvtColor(new_image, cv2.COLOR_HSV2RGB)),plt.title('Median Filter')plt.xticks([]), plt.yticks([])plt.show()

Figure 6: The result of applying a median filter to a color image.

图 6 显示中值滤波器能够保留图像的边缘,同时消除椒盐噪声。与均值和高斯滤波器不同,中值滤波器不会在彩色图像上产生伪像。中值滤波器现在将应用于灰度图像。

new_image = cv2.medianBlur(image2, figure_size)plt.figure(figsize=(11,6))plt.subplot(121), plt.imshow(image2, cmap='gray'),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(new_image, cmap='gray'),plt.title('Median Filter')plt.xticks([]), plt.yticks([])plt.show()

Figure 7: The result of applying the median filter to a grayscale image

图 7 显示 9 x 9 中值滤波器可以去除一些椒盐噪声,同时保留图像的边缘。

其他过滤器:

以下是几个可用于图像预处理的过滤器:

保守滤波器

保守滤波器用于去除椒盐噪声。确定像素邻域内的最小强度和最大强度。如果中心像素的亮度大于最大值,它将被最大值取代。如果它小于最小值,则用最小值代替。保守滤波器保留边缘,但不去除斑点噪声。

以下代码可用于定义保守过滤器:

# first a conservative filter for grayscale images will be defined.def conservative_smoothing_gray(data, filter_size):temp = []

    indexer = filter_size // 2

    new_image = data.copy()

    nrow, ncol = data.shape

    for i in range(nrow):

        for j in range(ncol):

            for k in range(i-indexer, i+indexer+1):

                for m in range(j-indexer, j+indexer+1):

                    if (k > -1) and (k < nrow):

                        if (m > -1) and (m < ncol):

                            temp.append(data[k,m])

            temp.remove(data[i,j])

            max_value = max(temp)

            min_value = min(temp)

            if data[i,j] > max_value:

                new_image[i,j] = max_value

            elif data[i,j] < min_value:

                new_image[i,j] = min_value

            temp =[]

    return new_image.copy()

现在保守滤波器可以应用于灰度图像:

new_image = conservative_smoothing_gray(image2,5)plt.figure(figsize=(11,6))plt.subplot(121), plt.imshow(image2, cmap='gray'),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(new_image, cmap='gray'),plt.title('Conservative Smoothing')plt.xticks([]), plt.yticks([])plt.show()

Figure 9: The result of applying the conservative smoothing filter to a grayscale image

图 9 显示保守平滑滤波器能够消除一些椒盐噪声。它还表明,该滤波器不能像中值滤波器那样去除那么多的椒盐噪声(尽管它确实保留了更多的细节)。)

拉普拉斯滤波器

图像的拉普拉斯算子突出了强度快速变化的区域,因此可以用于边缘检测。如果我们让 I(x,y) 表示图像的强度,则图像的拉普拉斯由以下公式给出:

特定像素处的拉普拉斯算子的离散近似可以通过取该像素的小邻域中的像素强度的加权平均值来确定。图 10 示出了代表近似拉普拉斯算子的两种不同方式的两个核。

Figure 10: Two kernels used to approximate the Laplacian

因为拉普拉斯滤波器检测图像的边缘,所以它可以与高斯滤波器一起使用,以便首先去除斑点噪声,然后突出图像的边缘。这种方法被称为高斯滤波的拉普拉斯算子。Open-CV 库中的“拉普拉斯”函数可用于查找图像的拉普拉斯。

new_image = cv2.Laplacian(image2,cv2.CV_64F)plt.figure(figsize=(11,6))plt.subplot(131), plt.imshow(image2, cmap='gray'),plt.title('Original')plt.xticks([]), plt.yticks([])plt.subplot(132), plt.imshow(new_image, cmap='gray'),plt.title('Laplacian')plt.xticks([]), plt.yticks([])plt.subplot(133), plt.imshow(image2 + new_image, cmap='gray'),plt.title('Resulting image')plt.xticks([]), plt.yticks([])plt.show()

Figure 11: The result of adding the Laplacian of an image to the original image

图 11 示出了虽然将图像的拉普拉斯算子添加到原始图像可以增强边缘,但是一些噪声也被增强。

频率滤波器

当对图像应用频率滤波器时,重要的是首先将图像转换成图像的频域表示。傅立叶变换(将函数分解成正弦和余弦分量)可以应用于图像,以获得其频域表示。我们对图像的频域表示感兴趣的原因是,在频域中对图像应用频率滤波器比在空间域中应用滤波器成本更低。这是因为频域表示中的每个像素对应于图像的频率而不是位置。

低通滤波器和高通滤波器都是频率滤波器。低通滤波器保留最低频率(低于阈值),这意味着它模糊了边缘,并在空间域中从图像中去除了斑点噪声。高通滤波器保留高频,这意味着它保留边缘。“dft”函数确定图像的离散傅立叶变换。对于N×N图像,二维离散傅立叶变换由下式给出:

其中 F 是空间域中的图像值,F 是频域中的图像值。以下是离散傅里叶逆变换(将图像从频域转换到空间域)的公式:

一旦对图像应用了频率滤波器,就可以使用傅立叶逆变换将图像转换回空间域。现在将给出低通滤波器的 python 实现:

dft = cv2.dft(np.float32(image2),flags = cv2.DFT_COMPLEX_OUTPUT)# shift the zero-frequncy component to the center of the spectrum
dft_shift = np.fft.fftshift(dft)# save image of the image in the fourier domain.
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))# plot both imagesplt.figure(figsize=(11,6))plt.subplot(121),plt.imshow(image2, cmap = 'gray')plt.title('Input Image'), plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])plt.show()

Figure 12: An image’s spatial domain and frequency domain representations

rows, cols = image2.shapecrow,ccol = rows//2 , cols//2# create a mask first, center square is 1, remaining all zerosmask = np.zeros((rows,cols,2),np.uint8)mask[crow-30:crow+30, ccol-30:ccol+30] = 1# apply mask and inverse DFTfshift = dft_shift*maskf_ishift = np.fft.ifftshift(fshift)img_back = cv2.idft(f_ishift)img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])# plot both imagesplt.figure(figsize=(11,6))plt.subplot(121),plt.imshow(image2, cmap = 'gray')plt.title('Input Image'), plt.xticks([]), plt.yticks([])plt.subplot(122),plt.imshow(img_back, cmap = 'gray')plt.title('Low Pass Filter'), plt.xticks([]), plt.yticks([])plt.show()

Figure 13: The result of applying a low pass filter to an image.

图 13 显示丢失了相当多的细节,但是去除了一些斑点噪声。

Crimmins 斑点去除

Crimmins 互补剔除算法用于去除斑点噪声和平滑边缘。它还降低了椒盐噪声的强度。该算法将图像中一个像素的亮度与其 8 个相邻像素的亮度进行比较。该算法考虑了 4 组邻居(南北、东西、西北-东南、东北-西南。)设 a,bc 为三个连续像素(例如从 E-S)。那么算法就是:

  1. 对于每次迭代:
    a)暗像素调整:对于四个方向中的每一个方向
    1)处理整个图像:如果 ab + 2b=b+1
    2)处理整个图像:如果 a > bb ≤ c 则 处理整幅图像用:如果 c > bb ≤ ab=b+1
    4)处理整幅图像用:如果cb+2b = b + 处理整幅图像用:如果 ab — 2 那么b=b1*
    2)处理整幅图像用:如果 a < bb ≥ c 那么b=b 处理整幅图像用:如果 c < bb ≥ ab=b1
    4)处理整幅图像用:如果 c ≤ b — 2b=b1***

互补剔除算法的 Python 实现可以在这里找到:https://github . com/m4nv1r/medium _ articles/blob/master/Image _ Filters _ in _ Python . ipynb

图 14 显示了对图像应用 Crimmins 斑点去除滤波器的结果。一些斑点噪声被去除,但是一些边缘是模糊的。

Figure 14: The result of applying the Crimmins Speckle Removal filter

模糊滤镜

钝化滤镜可用于增强图像的边缘。图像过滤器。PIL 软件包的反锐化掩模功能将反锐化滤波器应用于图像(图像首先需要转换为 PIL 图像对象。)图像过滤器。Unsharpmask 函数有三个参数。“半径”参数指定边缘周围有多少相邻像素受到影响。“百分比”参数指定边缘变暗或变亮的程度。第三个参数“阈值”定义了在滤波器执行任何操作之前,相邻色调值之间的距离。

image = Image.fromarray(image.astype('uint8'))
new_image = image.filter(ImageFilter.UnsharpMask(radius=2, percent=150))plt.subplot(121),plt.imshow(image, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(new_image, cmap = 'gray')
plt.title('Unsharp Filter'), plt.xticks([]), plt.yticks([])
plt.show()

Figure 15: The result of applying the Unsharp filter

图 15 显示了反锐化滤波器的结果。当图像的边缘被增强时,一些噪声也被增强。

结论

在去除噪声和保留图像边缘之间总是有一个权衡。为了去除图像中的斑点噪声,需要应用模糊滤波器,这反过来模糊了图像的边缘。如果你想保留图像的边缘,唯一可以去除的噪声就是椒盐噪声。包含本文使用的所有代码的 Jupyter 笔记本可以在这里找到:https://github . com/m4nv1r/medium _ articles/blob/master/Image _ Filters _ in _ python . ipynb

图像伪造检测

原文:https://towardsdatascience.com/image-forgery-detection-2ee6f1a65442?source=collection_archive---------1-----------------------

利用 CNN 的力量来检测图像操纵

随着脸书和 Instagram 等社交网络服务的出现,过去十年中生成的图像数据量大幅增加。使用图像(和视频)处理软件,如 GNU GimpAdobe Photoshop 创建篡改过的图像和视频,是脸书等互联网公司的一大担忧。这些图像是假新闻的主要来源,并经常被恶意使用,如煽动暴民。在根据可疑图像采取行动之前,我们必须验证其真实性。IEEE 信息取证与安全技术委员会(IFS-TC)于 2013 年发起了一项检测和定位取证挑战,即首届图像取证挑战,以解决这一问题。他们提供了一个开放的数字图像数据集,包括在不同光照条件下拍摄的图像和使用以下算法创建的伪造图像:

  • 内容感知填充和修补匹配(用于复制/粘贴)
  • 内容感知修复(用于复制/粘贴和拼接)
  • 克隆图章(用于复制/粘贴)
  • 线缝雕刻(图像重定向)
  • 修复(受损部分的图像重建——复制/粘贴的特殊情况)
  • 阿尔法抠图(用于拼接)

挑战包括两个阶段。

  1. 第一阶段要求参与团队将图像分类为伪造的或原始的(从未被篡改)
  2. 第二阶段要求他们检测/定位伪造图像中的伪造区域

这篇文章将讲述一种解决第一阶段挑战的深度学习方法。从数据清洗,预处理,CNN 架构到训练和评估的一切都将被阐述。

为什么用 CNN?

在人工智能的深度学习时代之前,即在 2012 年的图像网络挑战赛之前,图像处理领域的研究人员过去常常设计手工制作的功能来解决一般图像处理问题,特别是图像分类问题。一个这样的例子是用于边缘检测的 Sobel 内核。之前使用的图像取证工具可分为 5 类,即

  1. 基于像素的技术,检测像素级引入的统计异常
  2. 基于格式的技术,利用特定有损压缩方案引入的统计相关性
  3. 基于相机的技术,利用相机镜头、传感器或片内后处理引入的伪像
  4. 基于物理的技术,明确地模拟和检测物理对象、光和相机之间的三维交互中的异常
  5. 基于几何的技术,对世界上的对象及其相对于相机的位置进行测量

礼貌:https://ieeexplore.ieee.org/abstract/document/4806202

几乎所有这些技术都利用了图像的基于内容的特征,即图像中存在的视觉信息。CNN 的灵感来自视觉皮层。从技术上讲,这些网络被设计成提取对分类有意义的特征,即最小化损失函数的特征。网络参数——通过梯度下降学习内核权重,以便从输入网络的图像中生成最具鉴别性的特征。这些特征然后被馈送到一个完全连接的层,该层执行分类的最终任务。

在看了一些伪造的图像后,很明显通过人类视觉皮层定位伪造区域是可能的。因此,CNN 是这项工作的完美深度学习模型。如果人类的视觉皮层能够探测到它,那么在一个专门为这项任务设计的网络中肯定会有更多的能量。

资料组

在对数据集进行概述之前,先要弄清楚所使用的术语

  • 假图像:使用两种最常见的操作,即复制/粘贴和图像拼接,对图像进行了处理/篡改。
  • 原始图像:除了根据比赛规则调整所有图像的尺寸以达到标准尺寸之外,没有被处理过的图像。
  • 图像拼接:拼接操作可以组合人的图像,给建筑物添加门,给停车场添加树和汽车等。拼接图像还可以包含复制/粘贴操作产生的部分。接收拼接部分的图像称为“主”图像。与宿主图像拼接在一起的部分被称为“外星人”。

第一阶段和第二阶段的整个数据集可以在这里找到。对于这个项目,我们将只使用列车组。它包含两个目录——一个包含假图像及其相应的遮罩,另一个包含原始图像。伪图像的遮罩是描述伪图像的拼接区域的黑白(非灰度)图像。蒙版中的黑色像素代表在源图像中执行操作以获得伪造图像的区域,具体来说,它代表拼接区域。

Example of a fake image and corresponding mask

该数据集由 1050 幅原始图像和 450 幅伪图像组成。彩色图像通常是 3 个通道的图像,每个通道用于红色、绿色和蓝色,然而有时可能存在用于黄色的第四通道。我们数据集中的图像是 1、3 和 4 通道图像的混合。在查看了几幅 1 通道图像(即灰度图像)后,很明显这些图像

  1. 数量非常少
  2. 是黑色或蓝色的溪流

挑战设置者故意添加这些图像,因为他们希望解决方案对这种噪声具有鲁棒性。尽管一些蓝色图像可以是晴朗天空的图像。因此,它们中的一些被包含在内,而另一些则作为噪声被丢弃。来到四通道图像——他们也没有任何有用的信息。它们只是用 0 值填充的像素网格。因此,清理后的原始数据集包含大约 1025 幅 RGB 图像。

伪图像是 3 和 4 通道图像的混合,然而,它们都没有噪声。相应的遮罩是 1、3 和 4 通道图像的混合。我们将使用的特征提取只需要来自掩模的一个通道的信息。因此,我们的假货图像语料库有 450 个假货。接下来,我们做了一个训练测试分割,保留 1475 个图像中的 20%用于最终测试。

训练集上的特征提取

当前状态的数据集不适合训练模型。它必须被转换成非常适合手头任务的状态,即检测由于伪造操作而引入的像素级异常。从这里的中汲取灵感,我们设计了以下方法来从给定的数据中创建相关的图像。

对于每一个假图像,我们都有一个相应的面具。我们使用该掩模沿着拼接区域边界对伪图像进行采样,以确保图像的伪造部分和非伪造部分至少有 25%的贡献。这些样本将具有只有在假图像中才会出现的有区别的边界。这些界限是我们设计的 CNN 要学习的。由于遮罩的所有 3 个通道包含相同的信息(不同像素的图像的虚假部分),我们只需要 1 个通道来提取样本。

为了使边界更加清晰,在使用高斯滤波器去噪后,使用 Otsu 的阈值(在 OpenCV 中实现)将灰度图像转换为二进制。在此操作之后,采样仅仅是移动 64×64 的窗口(步长为 8)通过假图像,并计数相应蒙版中的 0 值(黑色)像素,并在值位于某个区间的情况下进行采样。

Boundaries in a binary mask are much more distinct than in grayscale

经过采样,我们从假图像中得到了 175,119 个 64×64 的面片。为了生成 0 个标记的(原始的)补丁,我们从真实图像中采样了大致相同的数量。最后,我们有 350,728 个补丁,这些补丁被分成训练集和交叉验证集。

现在我们有了一个大的高质量输入图像数据集。是时候试验各种 CNN 架构了。

定制 CNN 架构

我们尝试的第一个架构受到了最初的研究论文中给出的架构的启发。他们的输入图像大小为 128×128×3,因此网络很大。由于我们只有一半的空间大小,我们的网络也更小。这是第一个尝试的建筑。

First architecture

这里绿色层是卷积层,蓝色层是最大池。该网络在 150,000 个训练样本(用于测试目的)和 25,000 个验证样本上被训练。该网络有 8,536 个参数,与训练样本相比相对较少,因此避免了对更激进的退出的需要。0.2 的退出率适用于 20 个单位的扁平化产出。我们使用 Adam 优化器,默认值为学习率(0.001)和 beta_1、beta_2。大约 ___ 个时期后,结果如下

训练准确率:77.13%,训练损失:0.4678

验证准确率:75.68%,验证损失:0.5121

这些数字并不令人印象深刻,因为 2012 年 CNN 以巨大优势击败了专家长达一年的研究。然而,考虑到我们完全没有使用图像取证知识(像素统计和相关概念)来获得看不见的数据的 ___ 准确性,这些数字也不是很糟糕。

迁移学习

既然 CNN 在 ImageNet 分类任务中击败了所有经典的机器学习算法,为什么不利用这些强大机器中的一个来解决手头的问题呢?这就是转移学习背后的理念。简而言之,我们使用预训练模型的权重来解决我们的问题,该模型可能是在更大的数据集上训练的,并且在解决问题时给出了更好的结果。换句话说,我们“转移”一个模型的知识来构建我们的模型。在我们的例子中,我们使用在 ImageNet 数据集上训练的 VGG16 网络来矢量化数据集中的图像。

这里获取想法,我们尝试了两种方法

  1. 使用 VGG16 输出的瓶颈特性,并在此基础上构建一个浅层网络
  2. 微调上面(1)中 vgg 16+浅层模型的最后一个卷积层

很明显,2 比 1 给出了更好的结果。在最终实现之前,我们尝试了多种浅层网络架构

Top layer architecture

展平层的输入是 VGG16 输出的瓶颈特征。这些是形状为(2×2×512)的张量,因为我们使用了 64×64 的输入图像。

以上架构给出了以下结果

训练准确率:83.18%,训练损失:0.3230

验证准确率:84.26%,验证损失:0.3833

它使用 Adam optimizer 进行训练,具有每 10 个时期后降低的自定义学习率(除了 Adam 在每批后的定期更新之外)。

Custom update rule

第二种方法需要最后一层的微调。这里需要注意的重要一点是,我们必须使用预训练的顶层模型进行微调。目标是稍微改变已经学习的权重,以便更好地适应数据。如果我们使用一些随机初始化的权重,微小的变化对它们没有任何好处,大的变化会破坏卷积层的学习权重。我们还需要一个非常小的学习率来微调我们的模型(原因和上面提到的一样)。在这个帖子里,建议使用 SGD 优化器进行微调。然而,我们观察到亚当在这项任务中表现优于 SGD。

微调模型给出了以下结果

训练准确率:99.16%,训练损失:0.018

验证准确率:94.77%,验证损失:0.30

稍微过度拟合的模型,可以通过使用更小的学习率来补救(我们使用 1e-6)。

除了 VGG16,我们还尝试了在 Image-Net 数据集上预训练的 ResNet50 和 VGG19 模型的瓶颈特征。ResNet50 的特性优于 VGG16。VGG19 没有给出一个很满意的表现。我们使用相同的学习率更新策略,以类似于 VGG16 的方式微调 ResNet50 架构(最后一个卷积层),它给出了更有希望的结果,过拟合问题更少。

训练准确率:98.65%,训练损失:0.048

验证准确率:95.22%,验证损失:0.18

测试数据的最终模型预测

为了从先前创建的测试集中采样图像,我们采用了与用于创建训练和交叉验证集类似的策略,即使用它们的遮罩在边界处采样伪图像,并采样相同数量的具有相同尺寸的原始图像。微调的 VGG16 模型用于预测这些补丁的标签,并给出以下结果

测试准确率:94.65%,测试损失:0.31

另一方面,ResNet50 对测试数据给出了以下结果

测试准确率:95.09%,测试损失:0.19

如我们所见,我们的模特表现不错。我们仍有很大的改进空间。如果通过数据扩充(剪切、调整大小、旋转和其他操作)可以生成更多的数据,也许我们可以微调更多层的 SOTA 网络。

在这篇文章中,我们谈到了检测假图像。然而,一旦检测到伪造图像,我们必须确定该图像中的伪造区域。假图像中拼接区域的定位将是下一篇文章的主题。这部分的全部代码可以在这里找到。

这个帖子到此为止。请在评论区告诉我其他检测假图片的好方法。下次见…再见。

来源

  1. http://ifc.recod.ic.unicamp.br/fc.website/index.py?sec=5
  2. https://ieeexplore.ieee.org/abstract/document/4806202
  3. https://www.youtube.com/watch?v=uihBwtPIBxM
  4. https://medium . com/@ gopalkalpande/biological-inspiration-of-convolutionary-neural-network-CNN-9419668898 AC
  5. https://ieeexplore.ieee.org/abstract/document/7823911
  6. https://blog . keras . io/building-powerful-image-class ification-models-using-very-little-data . html

Numpy 和 OpenCV 中的图像几何变换

原文:https://towardsdatascience.com/image-geometric-transformation-in-numpy-and-opencv-936f5cd1d315?source=collection_archive---------4-----------------------

图像变形背后的数学和代码

Source: Geometric Transformations

几何变换在计算机视觉中普遍存在

几何变换是一种重要的图像处理技术,有着广泛的应用。例如,在计算机图形学中,一个简单的用例是在桌面和移动设备上显示图形内容时简单地重新缩放图形内容。

它还可以应用于将图像投影扭曲到另一个图像平面。例如,我们希望从另一个角度看一个场景,而不是直直地看着它,在这个场景中应用了透视变换来实现这一点。

另一个令人兴奋的应用是训练深度神经网络。训练深度模型需要大量数据。几乎在所有情况下,随着训练数据的增加,模型都会受益于更高的泛化性能。人工生成更多数据的一种方法是对输入数据随机应用仿射变换。这种技术也被称为增强

在本文中,我将带您了解一些转换,以及我们如何在 Numpy 中执行它们,首先从基本原则上理解这个概念。然后如何使用 OpenCV 轻松实现。如果你像我一样喜欢从基础理论中理解概念,这篇文章会让你感兴趣!

我将特别关注 2D 仿射变换。你需要的是一些线性代数的基础知识,你应该能跟上。附带的代码可以在这里找到,如果你喜欢自己尝试的话!

仿射变换的类型

在不深入数学细节的情况下,变换的行为由仿射 A 中的一些参数控制。

x' = Ax

where A = [[a_11, a_12, a_13],
           [a_21, a_22, a_23],
           [  0 ,   0 ,   1 ]]

是齐次坐标中的 2x3 矩阵或 3x3,并且 x 是齐次坐标中形式为[x, y][x, y, 1]的向量。上面的公式说 A 取任意向量 x 并将其映射到另一个向量x’。

通常,仿射变换具有 6 个自由度,在逐像素矩阵相乘之后,将任何图像扭曲到另一个位置。变换后的图像保留了原图像中的平行线直线(想想剪切)。满足这两个条件的任何矩阵 A 都被认为是仿射变换矩阵。

缩小我们的讨论,有一些特殊形式的 A,这是我们感兴趣的。这包括如下图所示的旋转平移缩放矩阵。

Figure 1: 2D Coordinate Transformations. Note that rotation is about z-axis

上述仿射变换的一个非常有用的特性是它们是线性函数。它们保留了乘法和加法的运算,遵守叠加原理。

source: Wikipedia

换句话说,我们可以组合两个或更多的变换:向量加法来表示平移,矩阵乘法来表示线性映射,只要我们在齐次坐标中表示它们。例如,我们可以将旋转后的平移表示为

A = array([[cos(angle),  -sin(angle), tx],
            [sin(angle), cos(angle),  ty],
            [0,          0,           1]])

图像表示

Figure 2: Pixel Coordinates

在 Python 和 OpenCV 中,2D 矩阵的原点位于左上角,从 x,y= (0,0)开始。坐标系是左手坐标系,其中 x 轴指向正右侧,y 轴指向正下方。

但是你在教科书和文献中找到的大多数变换矩阵,包括上面显示的 3 个矩阵,都遵循右手坐标系。所以必须做一些小的调整来对齐轴的方向。

欧氏空间中的常见变换

在我们对图像进行变换实验之前,让我们看看如何在点坐标上进行变换。因为它们本质上与图像是网格中的 2D 坐标阵列是一样的。

利用我们在上面学到的知识,下面的代码可以用来转换点[0, 0], [0, 1], [1, 0], [1,1]。图 3 中的蓝点。

Python 提供了一个有用的速记运算符,@ 来表示矩阵乘法。

# Points generator
def get_grid(x, y, homogenous=False):
    coords = np.indices((x, y)).reshape(2, -1)
    return np.vstack((coords, np.ones(coords.shape[1]))) if homogenous else coords# Define Transformations
def get_rotation(angle):
    angle = np.radians(angle)
    return np.array([
        [np.cos(angle), -np.sin(angle), 0],
        [np.sin(angle),  np.cos(angle), 0],
        [0, 0, 1]
    ])
def get_translation(tx, ty):
    return np.array([
        [1, 0, tx],
        [0, 1, ty],
        [0, 0, 1]
    ])
def get_scale(s):
    return np.array([
        [s, 0, 0],
        [0, s, 0],
        [0, 0, 1]
    ])R1 = get_rotation(135)
T1 = get_translation(-2, 2)
S1 = get_scale(2)# Apply transformation x' = Ax
coords_rot = R1 @ coords
coords_trans = T1 @ coords
coords_scale = S1 @ coords
coords_composite1 = R1 @ T1 @ coords
coords_composite2 = T1 @ R1 @ coords

Figure 3: Transforming points: (0,0), (0,1), (1,0), (1,1)

重要的是要注意,除了少数例外,矩阵通常不交换。即

A1 @ A2 != A2 @ A1

因此,对于转换来说

# Translation and then rotation
coords_composite1 = R1 @ T1 @ coords# Rotation and then translation
coords_composite2 = T1 @ R1 @ coords

您将在图 3 中观察到,它们不会导致相同的映射,并且顺序很重要。函数如何应用可以从右到左理解。

数字转换

Source: Kitti Dataset

现在对于图像,有几件事需要注意。首先,如前所述,我们必须重新调整垂直轴。其次,变换后的点必须投影到图像平面上。

本质上,需要采取的步骤是:

  1. 创建一个新的图像 I'(x,y)来输出变换点
  2. 应用转换一个
  3. 将这些点投影到一个新的图像平面上,只考虑那些位于图像边界内的点。

示例:关于图像中心的旋转、缩放和平移

让我们来看一个变换,我们希望放大 2 倍并将图像围绕其中心位置旋转 45 度

这可以通过应用以下复合矩阵来实现。

height, width = image.shape[:2]
tx, ty = np.array((width // 2, height // 2))
angle = np.radians(45)
scale = 2.0R = np.array([
    [np.cos(angle), np.sin(angle), 0],
    [-np.sin(angle), np.cos(angle), 0],
    [0, 0, 1]
])T = np.array([
    [1, 0, tx],
    [0, 1, ty],
    [0, 0, 1]
])S = np.array([
    [scale, 0, 0],
    [0, scale, 0],
    [0, 0, 1]
])A = T @ R @ S @ np.linalg.inv(T)

应用于图像

# Grid to represent image coordinate
coords = get_grid(width, height, True)
x_ori, y_ori = coords[0], coords[1] # Apply transformation
warp_coords = np.round(A@coords).astype(np.int)
xcoord2, ycoord2 = warp_coords[0, :], warp_coords[1, :]# Get pixels within image boundary
indices = np.where((xcoord >= 0) & (xcoord < width) &
                   (ycoord >= 0) & (ycoord < height))xpix2, ypix2 = xcoord2[indices], ycoord2[indices]xpix, ypix = x_ori[indices], y_ori[indices]# Map the pixel RGB data to new location in another array
canvas = np.zeros_like(image)
canvas[ypix, xpix] = image[yy, xx]

在上面的两个代码片段中有几点需要注意。

  1. 左手坐标系旋转通过交换符号来解决。
  2. 因为点是围绕原点旋转的,所以在进行旋转和缩放之前,我们首先将中心平移到原点。
  3. 然后,点被转换回图像平面
  4. 变换点被四舍五入为整数以表示离散的像素值。
  5. 接下来,我们只考虑位于图像边界内的像素
  6. 映射对应 I(x,y)和 I'(x,y)

正如你所看到的,由于步骤 4,结果图像(图 4)将有几个锯齿和漏洞。为了消除这一点,开源库使用插值技术来填充转换后的缺口。

Figure 4: Image rotated by 45 degrees counter-clockwise and scale by 2x. Aliasing effect is significant

逆翘曲

另一种防止混叠的方法是在给定扭曲点 X’的情况下,将扭曲公式化为从源图像 I(x,y)重采样的扭曲。这可以通过将 X '乘以 a 的倒数来实现。注意,变换必须是可逆的。

  1. 对 X '进行逆变换。
X = np.linalg.inv(A) @ X'

注意:对于图像,X '的逆变形只是将 I'(x,y)重新投影到 I(x,y)上。所以我们简单地对 I'(x,y)像素坐标进行逆变换,如下图所示。

2.确定它在原始图像平面中的位置

3.从 I(x,y)重新采样 RGB 像素,并将其映射回 I'(x,y)

代码

# set up pixel coordinate I'(x, y)
coords = get_grid(width, height, True)
x2, y2 = coords[0], coords[1]# Apply inverse transform and round it (nearest neighbour interpolation)
warp_coords = (Ainv@coords).astype(np.int)
x1, y1 = warp_coords[0, :], warp_coords[1, :]# Get pixels within image boundaries
indices = np.where((x1 >= 0) & (x1 < width) &
                   (y1 >= 0) & (y1 < height))xpix1, ypix1 = x2[indices], y2[indices]
xpix2, ypix2 = x1[indices], y1[indices]# Map Correspondence
canvas = np.zeros_like(image)
canvas[ypix1, xpix1] = image[ypix2,xpix2]

运行上面的代码应该会给你一个密集的、没有孔洞的图像:)可以随意下载代码并使用参数来应用其他的转换。

OpenCV 中的转换

既然您对几何变换有了更好的理解,大多数开发人员和研究人员通常会省去编写所有这些变换的麻烦,只需依靠优化的库来执行任务。在 OpenCV 中做仿射变换非常简单。

有几种方法可以做到。

  1. 自己写仿射变换,调用cv2.**warpAffine**(image, A, output_shape)

下面的代码显示了整个仿射矩阵,它将给出与上面相同的结果。一个很好的练习就是自己推导公式!

def get_affine_cv(t, r, s):
    sin_theta = np.sin(r)
    cos_theta = np.cos(r)

    a_11 = s * cos_theta
    a_21 = -s * sin_theta

    a_12 = s * sin_theta
    a_22 = s * cos_theta

    a_13 = t[0] * (1 - s * cos_theta) - s * sin_theta * t[1]
    a_23 = t[1] * (1 - s * cos_theta) + s * sin_theta * t[0]return np.array([[a_11, a_12, a_13],
                 [a_21, a_22, a_23]])A2 = get_affine_cv((tx, ty), angle, scale)
warped = cv2.warpAffine(image, A2, (width, height))

2.依靠 OpenCV 使用cv2.**getRotationMatrix2D**(center, angle, scale)返回仿射变换矩阵。

该功能将图像绕点中心旋转角度,并用标尺对其进行缩放

A3 = cv2.getRotationMatrix2D((tx, ty), np.rad2deg(angle), scale)warped = cv2.warpAffine(image, b3, (width, height), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=0)

摘要

在本文中,我介绍了几何变换的基本概念,以及如何将它应用于图像。许多先进的计算机视觉,如使用视觉里程计的 slam 和多视图合成依赖于首先理解变换。

我相信,作为一名计算机视觉从业者,当我们使用 imgaug 和 albumentation 等强大的库时,理解这些转换是如何工作的肯定是有益的。

感谢阅读!我希望您已经更好地理解了这些公式是如何在库中编写和使用的。请关注查看更多关于计算机视觉和机器学习的帖子:)如果你发现任何错误或任何不清楚的地方,请在评论中指出来!

更多文章

[## 深度估计:基础和直觉

理解事物相对于相机有多远仍然是困难的,但对于激动人心的…

towardsdatascience.com](/depth-estimation-1-basics-and-intuition-86f2c9538cd1) [## 相机-激光雷达投影:在 2D 和 3D 之间导航

激光雷达和相机是感知和场景理解的两个必不可少的传感器。他们建立了一个环境…

medium.com](https://medium.com/swlh/camera-lidar-projection-navigating-between-2d-and-3d-911c78167a94)

10 个 Python 图像处理工具。

原文:https://towardsdatascience.com/image-manipulation-tools-for-python-6eb0908ed61f?source=collection_archive---------2-----------------------

概述了一些常用的 Python 库,它们提供了一种简单直观的方法来转换图像。

Photo by Luriko Yamaguchi from Pexels

本文内容改编自我之前在opensource.com发表的 自己的文章

介绍

当今世界充满了数据,而图像是这些数据的重要组成部分。然而,为了投入使用,这些图像需要被处理。因此,图像处理是分析和处理数字图像的过程,主要目的是提高图像质量或从中提取一些信息,然后加以利用。

图像处理中的典型任务包括显示图像、基本操作,如裁剪、翻转、旋转等。图像分割、分类和特征提取、图像恢复和图像识别。Python 成为这种图像处理任务的合适选择。这是因为它作为一门科学编程语言越来越受欢迎,并且在其生态系统中有许多先进的图像处理工具可以免费获得。

让我们看看一些常用于图像操作任务的 Python 库。

1.scikit 图像

scikit-image 是一个开源 Python 包,可以与[numpy](http://docs.scipy.org/doc/numpy/reference/index.html#module-numpy)数组一起工作。它在研究、教育和工业应用中实现算法和实用程序。这是一个相对简单的库,即使对于那些不熟悉 Python 生态系统的人来说也是如此。该代码由一群活跃的志愿者编写,质量很高,经过了同行评审。

资源

有很多例子和实际使用案例很好地证明了这一点。在这里阅读文档。

使用

这个包作为skimage导入,大多数功能都在子模块中。克扣的一些例子包括:

  • 滤像
import matplotlib.pyplot as plt 
%matplotlib inlinefrom skimage import data,filtersimage = data.coins()
# ... or any other NumPy array!
edges = filters.sobel(image)
plt.imshow(edges, cmap='gray')

Image filtering in skimage

Template Matching using match_template function

您可以在图库中找到更多示例。

2.Numpy

Numpy 是 Python 编程中的核心库之一,提供对数组的支持。图像本质上是包含数据点像素的标准 Numpy 数组。因此,通过使用基本的 NumPy 操作,如切片、遮罩和花式索引,我们可以修改图像的像素值。可以使用 skimage 加载图像,并使用 matplotlib 显示图像。

资源

Numpy 的官方文档页面上有完整的资源和文档列表。

使用

使用 Numpy 遮罩图像。

import numpy as np
from skimage import data
import matplotlib.pyplot as plt 
%matplotlib inlineimage = data.camera()
type(image)**numpy.ndarray #Image is a numpy array**mask = image < 87
image[mask]=255
plt.imshow(image, cmap='gray')

3.Scipy

scipy 是 Python 的另一个核心科学模块,类似于 Numpy,可用于基本的图像操作和处理任务。特别地,子模块[**scipy.ndimage**](https://docs.scipy.org/doc/scipy/reference/ndimage.html#module-scipy.ndimage)提供了在 n 维 NumPy 阵列上操作的功能。该软件包目前包括线性和非线性过滤功能,二元形态学,B 样条插值,和对象测量。

资源

关于scipy.ndimage包提供的功能的完整列表,请参考此处的文档

使用

使用 SciPy 使用高斯滤波器进行模糊处理:

from scipy import misc,ndimageface = misc.face()
blurred_face = ndimage.gaussian_filter(face, sigma=3)
very_blurred = ndimage.gaussian_filter(face, sigma=5)#Results
plt.imshow(<image to be displayed>)

4.PIL/枕头

PIL ( Python 图像库)是 Python 编程语言的免费库,增加了对打开、操作和保存许多不同图像文件格式的支持。然而,它的发展停滞不前,最后一次发布是在 2009 年。幸运的是,还有 Pillow ,这是 PIL 积极开发的一款更容易安装的 fork,可以运行在所有主流操作系统上,并且支持 Python 3。该库包含基本的图像处理功能,包括点操作、使用一组内置卷积核进行过滤以及色彩空间转换。

资源

文档包含安装说明和涵盖库每个模块的示例。

使用

使用图像过滤器增强 Pillow 中的图像:

**from** PIL **import** Image**,** ImageFilter
*#Read image*
im = Image.open**(** 'image.jpg' **)**
*#Display image*
im.show**()**from PIL import ImageEnhance
enh = ImageEnhance.Contrast(im)
enh.enhance(1.8).show("30% more contrast")

Source

5.OpenCV-Python

OpenCV ( 开源计算机视觉库)是计算机视觉应用最广泛使用的库之一。OpenCV-Python是针对 OpenCV 的 Python API。OpenCV-Python 不仅速度快,因为后台包含用 C/C++编写的代码,而且易于编码和部署(由于前台有 Python 包装器)。这使得它成为执行计算密集型计算机视觉程序的最佳选择。

资源

OpenCV2-Python-Guide 让 OpenCV-Python 的入门变得简单。

使用

下面这个例子展示了 OpenCV-Python 在使用金字塔创建一个名为“苹果”的新水果的图像混合中的能力****

Source

6.简单 CV

SimpleCV 也是一个构建计算机视觉应用的开源框架。有了它,您可以访问 OpenCV 等几个高性能的计算机视觉库,而不必先了解位深度、文件格式、色彩空间等。学习曲线比 OpenCV 小得多,正如他们的标语所说,“这是使计算机视觉变得容易的”支持 SimpleCV 的一些观点有:

  • 即使是初级程序员也能编写简单的机器视觉测试
  • 相机、视频文件、图像和视频流都可以互操作

资源

T21 的官方文档简单易懂,有大量的例子和用例可供参考。

使用

7.马霍塔斯

Mahotas 是另一个用于 Python 的计算机视觉和图像处理库。它包含传统的图像处理功能,如过滤和形态学操作,以及用于特征计算的更现代的计算机视觉功能,包括兴趣点检测和局部描述符。界面是 Python 语言的,适合快速开发,但算法是用 C++实现的,并针对速度进行了微调。Mahotas 库速度很快,代码很少,依赖性也很小。点击阅读他们的官方论文获得更多见解。

资源

文档 n 包含安装说明、示例,甚至一些教程来帮助开始使用 Mahotas。

使用

Mahotas 库依靠使用简单的代码来完成工作。对于' 寻找沃利 的问题,' Mahotas 做得非常出色,而且代码量也很少。下面是源代码

Source

8.SimpleITK

ITKInsight Segmentation and Registration Toolkit是一个开源的跨平台系统,为开发人员提供了一套广泛的图像分析软件工具。K 是建立在 ITK 之上的一个简化层,旨在促进它在快速原型、教育和解释语言中的使用。 SimpleITK 是一个图像分析工具包,包含许多支持一般过滤操作、图像分割和配准的组件。SimpleITK 是用 C++编写的,但可用于许多编程语言,包括 Python。

资源

已经提供了大量的 Jupyter 笔记本来说明 SimpleITK 在教育和研究活动中的应用。这些笔记本演示了使用 Python 和 R 编程语言使用 SimpleITK 进行交互式图像分析。

使用

下面的动画显示了用 SimpleITK 和 Python 创建的严格的 CT/MR 配准过程。这里看源代码

Source

9.pgmagick

p gmagick 是 GraphicsMagick 库的基于 Python 的包装器。GraphicsMagick图像处理系统有时被称为图像处理的瑞士军刀。它提供了一个强大而高效的工具和库集合,支持以超过 88 种主要格式读取、写入和操作图像,包括重要的格式,如 DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM 和 TIFF。

资源

PgMagick 的官方 Github 库有安装说明和要求。关于这个主题还有一个详细的用户 guid。

使用

使用 pgmagic k 可以执行的一些图像操作活动包括:

图像缩放 g :

边缘提取:

10.皮开罗

Pycairo 是图形库 Cairo 的一套 Python 绑定。Cairo 是一个用于绘制矢量图形的 2D 图形库。矢量图形很有趣,因为它们在调整大小或变换时不会失去清晰度。Pycairo 是用 Python 为 cairo 编写的一组绑定。

资源

Pycairo GitHub 资源库是一个很好的资源,里面有关于安装和使用的详细说明。还有一个 G etting 入门 指南,里面有 Pycairo 的简要教程。

使用

使用 Pycairo 绘制线条、基本形状和径向渐变

结论

这些是 Python 的一些有用的免费图像处理库。有些相对比较了解,有些可能对你来说比较陌生。尝试一下,了解更多。

基于 Tensorflow-js 的图像目标检测🤔

原文:https://towardsdatascience.com/image-object-detection-with-tensorflow-js-b8861119ed46?source=collection_archive---------7-----------------------

这是图像处理系列从零到一的第四篇帖子。

这是其他帖子的列表

  1. 图像处理— OpenCV 和 Node.js(第三部分)
  2. 图像处理—制作自定义滤镜— React.js —第二部分
  3. 使用 Cloundinary 的图像处理(第一部分)

在这篇文章中,我们将使用 Tensorflow-js 和预训练的模型构建一个图像对象检测系统。

首先,在网页中部署 TensorFlow 有很多方法,其中一种方法是包含 ml5js。参观 https://ml5js.org/。它是 tf.js 的包装器,一个张量流和 p5.js 库,用于在 Html 元素中进行操作。

但是,我们希望保持后端部分的电源,以便我可以尝试使用 API 的后端进程等在后端运行这些模型。

因此,在本文的前半部分,我们将使用 React.js 和 Material-UI 创建一个 UI,在后半部分,我们将在 Node.js 中创建一个 API 来支持这个 UI。

让我们从构建一个示例 React 项目开始。🚀

前端部分:-

如果您遵循了我的前一篇文章,那么 react 项目似乎很容易构建。

  1. 打开终端,做
create-react-app image_classification_react_ui

这将创建一个 react 项目来使用。

2.让我们安装所需的依赖项

npm install @material-ui/core
npm install — save isomorphic-fetch es6-promise

注意:从 React 代码调用对象检测 API 端点需要同构提取。

3.在你最喜欢的编辑器中打开项目,让我们创建两个文件夹

  1. 容器 —这将包含一个文件— ImageOps.jsx,其中包含所有的前端 UI 代码。
  2. utils —这将包含一个文件Api.js,用于调用对象检测端点。
└── src
    ├── containers
        ├── ImageOps.jsx
    ├── utils
        ├── Api.js

让我们研究一下ImageOps.jsx代码并理解它。

import React from 'react';

import Container from '[@material](http://twitter.com/material)-ui/core/Container';
import Grid from '[@material](http://twitter.com/material)-ui/core/Grid';

import Card from '[@material](http://twitter.com/material)-ui/core/Card';
import CardContent from '[@material](http://twitter.com/material)-ui/core/CardContent';
import Typography from '[@material](http://twitter.com/material)-ui/core/Typography';
import Button from '[@material](http://twitter.com/material)-ui/core/Button';
import { red } from '[@material](http://twitter.com/material)-ui/core/colors';

import {api} from '../utils/Api';

import Table from '[@material](http://twitter.com/material)-ui/core/Table';
import TableBody from '[@material](http://twitter.com/material)-ui/core/TableBody';
import TableCell from '[@material](http://twitter.com/material)-ui/core/TableCell';
import TableHead from '[@material](http://twitter.com/material)-ui/core/TableHead';
import TableRow from '[@material](http://twitter.com/material)-ui/core/TableRow';
import Paper from '[@material](http://twitter.com/material)-ui/core/Paper';
import CircularProgress from '[@material](http://twitter.com/material)-ui/core/CircularProgress';

export default class ImageOps extends React.Component {

   constructor(props) {
       super(props);

       this.state = {
           image_object: null,
           image_object_details: {},
           active_type: null
       }
   }

   updateImageObject(e) {
       const file  = e.target.files[0];
       const reader = new FileReader();

       reader.readAsDataURL(file);
       reader.onload = () => {
           this.setState({image_object: reader.result, image_object_details: {}, active_type: null});
       };

   }

   processImageObject(type) {

       this.setState({active_type: type}, () => {

           if(!this.state.image_object_details[this.state.active_type]) {
               api("detect_image_objects", {
                   type,
                   data: this.state.image_object
               }).then((response) => {

                   const filtered_data = response;
                   const image_details = this.state.image_object_details;

                   image_details[filtered_data.type] = filtered_data.data;

                   this.setState({image_object_details: image_details });
               });
           }
       });
   }

   render() {
       return (
           <Container maxWidth="md">
               <Grid container spacing={2}>
                   <Grid item xs={12}>
                       <CardContent>
                           <Typography variant="h4" color="textPrimary" component="h4">
                               Object Detection Tensorflow
                           </Typography>
                       </CardContent>
                   </Grid>
                   <Grid item xs={12}>
                       {this.state.image_object &&
                           <img src={this.state.image_object} alt="" height="500px"/>
                       }
                   </Grid>
                   <Grid item xs={12}>
                       <Card>
                           <CardContent>
                               <Button variant="contained"
                                   component='label' // <-- Just add me!
                                   >
                                   Upload Image
                                   <input accept="image/jpeg" onChange={(e) =>  this.updateImageObject(e)} type="file" style={{ display: 'none' }} />
                               </Button>
                           </CardContent>
                       </Card>
                   </Grid>
                   <Grid item xs={3}>
                       <Grid container justify="center" spacing={3}>
                           <Grid item >
                               {this.state.image_object && <Button onClick={() => this.processImageObject("imagenet")}variant="contained" color="primary">
                                   Get objects with ImageNet
                               </Button>}
                           </Grid>
                           <Grid item>
                               {this.state.image_object && <Button onClick={() => this.processImageObject("coco-ssd")}variant="contained" color="secondary">
                                   Get objects with Coco SSD
                               </Button>}
                           </Grid>
                       </Grid>
                   </Grid>
                   <Grid item xs={9}>
                       <Grid container justify="center">
                           {this.state.active_type && this.state.image_object_details[this.state.active_type] &&
                               <Grid item xs={12}>
                                   <Card>
                                       <CardContent>
                                           <Typography variant="h4" color="textPrimary" component="h4">
                                               {this.state.active_type.toUpperCase()}
                                           </Typography>
                                           <ImageDetails type={this.state.active_type} data = {this.state.image_object_details[this.state.active_type]}></ImageDetails>
                                       </CardContent>
                                   </Card>
                               </Grid>
                           }
                           {this.state.active_type && !this.state.image_object_details[this.state.active_type] &&
                               <Grid item xs={12}>
                                   <CircularProgress
                                       color="secondary"
                                   />
                               </Grid>
                           }
                       </Grid>
                   </Grid>
               </Grid>
           </Container>
       )
   }
}

class ImageDetails extends React.Component {

   render() {

       console.log(this.props.data);

       return (
           <Grid item xs={12}>
               <Paper>
                   <Table>
                   <TableHead>
                       <TableRow>
                       <TableCell>Objects</TableCell>
                       <TableCell align="right">Probability</TableCell>
                       </TableRow>
                   </TableHead>
                   <TableBody>
                       {this.props.data.map((row) => {
                           if (this.props.type === "imagenet") {
                               return (
                                   <TableRow key={row.className}>
                                       <TableCell component="th" scope="row">
                                       {row.className}
                                       </TableCell>
                                       <TableCell align="right">{row.probability.toFixed(2)}</TableCell>
                                   </TableRow>
                               )
                           } else if(this.props.type === "coco-ssd") {
                               return (
                                   <TableRow key={row.className}>
                                       <TableCell component="th" scope="row">
                                       {row.class}
                                       </TableCell>
                                       <TableCell align="right">{row.score.toFixed(2)}</TableCell>
                                   </TableRow>
                               )
                           }
                           })
                       }
                   </TableBody>
                   </Table>
               </Paper>

           </Grid>
       )
   }
}

}

注:这里是上面的 Github repo 链接—https://Github . com/overflow js-com/image _ object _ det ction _ react _ ui。如果你觉得理解很难,那么我强烈推荐你阅读我们的第 2 部分和第 1 部分。

在渲染中,我们创建了一个三行的网格,其中一行包含标题

第二,包含要显示的图像

<Grid item xs={12}>
  {this.state.image_object &&
    <img src={this.state.image_object} alt="" height="500px"/>}                
</Grid>

如果图像已经上传或图像对象处于可用状态,我们将在此显示图像

下一个网格包含一个按钮,用于上传文件并将上传的文件更新到当前状态。

<Grid item xs={12}>
    <Card>
        <CardContent>
            <Button variant="contained"
                component='label' // <-- Just add me!
                >
                Upload Image
                <input accept="image/jpeg" onChange={(e) =>  this.updateImageObject(e)} type="file" style={{ display: 'none' }} />
            </Button>
        </CardContent>
    </Card>
</Grid>

我们调用了一个函数updateImage来更新状态下当前选中的图像。

updateImageObject(e) {
       const file  = e.target.files[0];
       const reader = new FileReader();

       reader.readAsDataURL(file);
       reader.onload = () => {
           this.setState({image_object: reader.result, image_object_details: {}, active_type: null
           });
       };
}

在上面的代码中,我们从文件输入上传器中读取当前文件对象,并在当前状态下加载它的数据。随着新图像的上传,我们正在重置 image_object_details 和 active_type,以便可以对上传的图像应用新的操作

下面是下一个网格,包含每个模型的两个按钮的代码。

<Grid item xs={3}>
        <Grid container justify="center" spacing={3}>
            <Grid item >
                {this.state.image_object && <Button onClick={() => this.processImageObject("imagenet")}variant="contained" color="primary">
                    Get objects with ImageNet
                </Button>}
            </Grid>
            <Grid item> 
                {this.state.image_object && <Button onClick={() => this.processImageObject("coco-ssd")}variant="contained" color="secondary">
                    Get objects with Coco SSD
                </Button>}
            </Grid>
        </Grid>
    </Grid>
    <Grid item xs={9}>
        <Grid container justify="center">
            {this.state.active_type && this.state.image_object_details[this.state.active_type] &&
                <Grid item xs={12}>
                    <Card>
                        <CardContent>
                            <Typography variant="h4" color="textPrimary" component="h4">
                                {this.state.active_type.toUpperCase()}
                            </Typography>
                            <ImageDetails data = {this.state.image_object_details[this.state.active_type]}></ImageDetails>
                        </CardContent>
                    </Card>
                </Grid>
            }
            {this.state.active_type && !this.state.image_object_details[this.state.active_type] && 
                <Grid item xs={12}>
                    <CircularProgress
                        color="secondary"
                    />
                </Grid>
            }
     </Grid>
</Grid>

在这里,我们将网格从 12 列父网格分为 3 列和 9 列两部分。

第一个有 3 列的网格包含两个有两个按钮的网格

<Grid container justify="center" spacing={3}>
    <Grid item >
        {this.state.image_object && <Button onClick={() => this.processImageObject("imagenet")}variant="contained" color="primary">
            Get objects with ImageNet
        </Button>}
    </Grid>
    <Grid item> 
        {this.state.image_object && <Button onClick={() => this.processImageObject("coco-ssd")}variant="contained" color="secondary">
            Get objects with Coco SSD
        </Button>}
    </Grid>
</Grid>

我们正在使用 ImageNet 和 Coco SSD 型号分析图像检测,并比较输出。

每个按钮都有一个动作事件 onClick,它调用一个函数processImageObject(),该函数将模型的名称作为参数。

processImageObject(type) {this.setState({active_type: type}, () => {
        api("detect_image_objects", {
            type,
            data: this.state.image_object
        }).then((response) => {

            const filtered_data = response;
            const image_details = this.state.image_object_details;image_details[filtered_data.type] = filtered_data.data;this.setState({image_object_details: image_details });
        });
    });
}

我们正在用当前选择的模态设置状态对象action_type

Process image 对象函数将从 state 中获取当前图像,并将其发送给 API 函数,我接下来将向您展示该函数,API 将被调用detect_image_objects,作为响应,我们将在 UI 中进行处理和显示。

将从 API 获取响应,并在阶段image_object_details中设置。

我们根据型号类型 (imagenet/coco-ssd) 设置每个 API 响应

该按钮仅在image_object处于该状态时可见。

{
 this.state.image_object && 
 <Button onClick={() => this.processImageObject()} variant="contained" color="primary">Process Image 
 </Button>
}

下面是我们创建的另一个网格:

<Grid item xs={9}>
    <Grid container justify="center">
        {this.state.active_type && this.state.image_object_details[this.state.active_type] &&
            <Grid item xs={12}>
                <Card>
                    <CardContent>
                        <Typography variant="h4" color="textPrimary" component="h4">
                            {this.state.active_type.toUpperCase()}
                        </Typography>
                        <ImageDetails  type={this.state.active_type} data = {this.state.image_object_details[this.state.active_type]}></ImageDetails>
                    </CardContent>
                </Card>
            </Grid>
        }
        {this.state.active_type && !this.state.image_object_details[this.state.active_type] && 
            <Grid item xs={12}>
                <CircularProgress
                    color="secondary"
                />
            </Grid>
        }
    </Grid>
</Grid>

这里我们已经检查了当前的action_type模式是否被选中,如果 API 已经处理了细节,它将显示对象细节。为此,我们创建了一个组件ImageDetails

让我们看看ImageDetails组件代码,它很容易理解。

class ImageDetails extends React.Component {

   render() {

       console.log(this.props.data);

       return (
           <Grid item xs={12}>
               <Paper>
                   <Table>
                   <TableHead>
                       <TableRow>
                       <TableCell>Objects</TableCell>
                       <TableCell align="right">Probability</TableCell>
                       </TableRow>
                   </TableHead>
                   <TableBody>
                       {this.props.data.map((row) => {
                           if (this.props.type === "imagenet") {
                               return (
                                   <TableRow key={row.className}>
                                       <TableCell component="th" scope="row">
                                       {row.className}
                                       </TableCell>
                                       <TableCell align="right">{row.probability.toFixed(2)}</TableCell>
                                   </TableRow>
                               )
                           } else if(this.props.type === "coco-ssd") {
                               return (
                                   <TableRow key={row.className}>
                                       <TableCell component="th" scope="row">
                                       {row.class}
                                       </TableCell>
                                       <TableCell align="right">{row.score.toFixed(2)}</TableCell>
                                   </TableRow>
                               )
                           }
                           })
                       }
                   </TableBody>
                   </Table>
               </Paper>

           </Grid>
       )
   }
}

该组件将显示从对象的模态名称接收的详细信息及其概率。基于我们正在处理的模态的类型,我们可以显示在这个类中处理的两个不同的输出。

4.最后一步是编写 API.js 包装器进行服务器端调用。

import fetch from  'isomorphic-fetch';

const BASE_API_URL = "[http://localhost:4000/api/](http://localhost:4000/api/)"

export function api(api_end_point, data) {

   return fetch(BASE_API_URL+api_end_point,
       {
           method: 'POST',
           headers: {
               'Content-Type': 'application/json'
           },
           body:JSON.stringify(data)
       }).then((response) => {
           return response.json();
       });
}

在这个示例代码中,我们提供了一个通过获取 API 函数的包装器,它将获取 API 端点和数据,并将构造完整的 URL 和从 API 发送的返回响应。

最终的用户界面将如下所示

后端部分:-

现在,既然我们已经有了自己的 UI,让我们开始使用 tensorflow.js 创建一个 API 端点,看起来像这样

[http://localhost:4000/api/detect_image_objects](http://localhost:4000/api/detect_image_objects)
  1. 第一步是选择一个样板文件,它使用 express.js 并提供只编写路由和对象检测逻辑的能力。在本教程中,我们使用https://github.com/developit/express-es6-rest-api。让我们克隆它
git clone [https://github.com/developit/express-es6-rest-api](https://github.com/developit/express-es6-rest-api) image_detection_tensorflow_api

2.现在,通过运行以下命令安装所有依赖项

cd image_detection_tensorflow_api
npm install

3.转到项目根目录下的config.json,将port编辑为 4000,将bodylimit编辑为 10000kb。

注意:我们将使用预先训练的模型imagenet and coco-ssd.从图像中寻找多个对象是一项繁琐的工作,尽管 image net 以从图像中检测单个对象(动物/其他对象)而闻名,但这两种模型都基于非常广泛的不同数据集。所以,如果你没有得到你的目标,不要担心😅。

4.从 TensorFlow 开始,如果您使用的是旧版本,我们需要更新节点版本。在你熟悉了节点版本之后,让我们运行下面的命令来安装https://github.com/tensorflow/tfjs-models

npm install @tensorflow/tfjs-node

注意:您可以根据您的系统 Linux/Windows/Mac 使用—https://www.npmjs.com/package/@tensorflow/tfjs-node安装 tfjs-node

5.现在让我们安装我们将要使用的两个模型,所以运行

npm install @tensorflow-models/mobilenet — save
npm install @tensorflow-models/coco-ssd — save

6.我们需要安装下面的模块,因为需要依赖

npm install base64-to-uint8array — save

7.现在转到src > api文件夹下的index.js,创建一个新的端点

api.post('/detect_image_objects', async (req, res) => {
  const data = req.body.data;
  const type = req.body.type; const objectDetect = new ObjectDetectors(data, type);
  const results = await objectDetect.process(); res.json(results);
});

这里我们调用ObjectDetectors类并传递从 UI 接收的两个参数,一个是 base64 编码的图像,另一个是模型的类型。

8.现在让我们创建ObjectDetectors类。转到src > api文件夹并创建object_detector文件夹。在object_detector中,我们将创建一个新文件ObjectDetectors.js

const tf = require('[@tensorflow/tfjs-node](http://twitter.com/tensorflow/tfjs-node)');

const cocossd = require('[@tensorflow](http://twitter.com/tensorflow)-models/coco-ssd');
const mobilenet = require('[@tensorflow](http://twitter.com/tensorflow)-models/mobilenet');

import toUint8Array from 'base64-to-uint8array';

export default class ObjectDetectors {

   constructor(image, type) {

       this.inputImage = image;
       this.type = type;
   }

   async loadCocoSsdModal() {
       const modal = await cocossd.load({
           base: 'mobilenet_v2'
       })
       return modal;
   }

   async loadMobileNetModal() {
       const modal = await mobilenet.load({
           version: 1,
           alpha: 0.25 | .50 | .75 | 1.0,
       })
       return modal;
   }

   getTensor3dObject(numOfChannels) {

       const imageData = this.inputImage.replace('data:image/jpeg;base64','')
                           .replace('data:image/png;base64','');

       const imageArray = toUint8Array(imageData);

       const tensor3d = tf.node.decodeJpeg( imageArray, numOfChannels );

       return tensor3d;
   }

   async process() {

       let predictions = null;
       const tensor3D = this.getTensor3dObject(3);

       if(this.type === "imagenet") {

           const model =  await this.loadMobileNetModal();
           predictions = await model.classify(tensor3D);

       } else {

           const model =  await this.loadCocoSsdModal();
           predictions = await model.detect(tensor3D);
       }

       tensor3D.dispose();

      return {data: predictions, type: this.type};
   }
}

我们有一个构造函数,它有两个参数,一个是图像 base64 编码,另一个是图像类型。

调用一个调用getTensor3dObject(3).process函数

注意:这里 3 是通道的数量,因为在 UI 中,我们将图像类型限制为 jpeg,现在是 3 通道图像。我们不处理 png 的 4 通道图像,你可以很容易地建立这个,因为你可以在 API 中发送图像类型,并根据需要改变给定的函数。

getTensor3dObject(numOfChannels) {
 const imageData = this.inputImage.replace('data:image/jpeg;base64','')
           .replace('data:image/png;base64','');const imageArray = toUint8Array(imageData);const tensor3d = tf.node.decodeJpeg( imageArray, numOfChannels );return tensor3d;
}

在这个函数中,我们从 base64 图像中移除标签,将其转换为图像数组,并构建 tensor3d。

我们的预训练模型使用 tensor3d 对象或<img> HTML 标记或 HTML 视频标记,但当我们从 Node.js API 执行此操作时,我们有一个 base64 图像,它被转换为 tensor3d 对象。

欣然 tensorflow.js 为它提供了一个函数decodeJpeg

TensorFlow 还提供了其他功能,您可以查看更多详细信息—https://js.tensorflow.org/api_node/1.2.7/#node.decodeJpeg

现在decodeJpeg将把我们的 3 通道图像的ArrayBuffer转换成 tesnor3d 对象。

if(this.type === "imagenet") {
 const model =  await this.loadMobileNetModal();
 predictions = await model.classify(tensor3D);} else {
 const model =  await this.loadCocoSsdModal();
 predictions = await model.detect(tensor3D);
}

基于选择的模型类型,我们在 API 调用中加载模型。你可以在 API 开始加载的时候加载模型,但是对于这个博客,我只是在 API 得到一个调用的时候加载它们,所以 API 可能需要时间来响应。

下面是我目前为止得到的结果

IMAGENET 模型输出

imagenet的输出它提供了物体的名称及其概率有三个物体用imagenet.标识

COCO-SSD 模型输出-

如果您了解更多关于 coco-ssd 的信息,它可以识别多个对象,即使它们是相似的。以及它们的对象所依赖的矩形坐标。

在这里阅读更多—https://github . com/tensor flow/tfjs-models/tree/master/coco-SSD

在这里你可以看到它已经确定了 6 个人,他们的位置是一个矩形。现在,您可以将这些坐标用于任何目的,因为它们会告诉您对象名称和对象位置。

您可以使用任何图像库来绘制这些矩形,围绕这些细节构建一些很酷的图像效果应用程序。

你可以试试我在 React.js 上的关于 Cloudniary 和 OpenCV 的教程,以前文章中的 Nodejs 试图使用这些知识来构建很酷的东西。

快乐编码❤️

如果您想被添加到我的电子邮件列表中,请考虑在这里输入您的电子邮件地址 和关注我的 medium 阅读更多关于 javascript 的文章,并关注github查看我的疯狂代码。如果有什么不清楚或者你想指出什么,请在下面评论。

你可能也会喜欢我的其他文章

  1. 用 Tensorflow-js 进行图像目标检测🤔
  2. Nodejs 应用程序结构——构建高度可扩展的架构。
  3. 图像处理——在 React.js 中制作自定义图像滤镜

如果你喜欢这篇文章,请随意分享并帮助他人找到它!

谢谢你!

用 OpenCV 实现图像全景拼接

原文:https://towardsdatascience.com/image-panorama-stitching-with-opencv-2402bde6b46c?source=collection_archive---------0-----------------------

图像拼接是计算机视觉中最成功的应用之一。如今,很难找到不包含此功能的手机或图像处理 API。

在这篇文章中,我们将讨论如何使用 Python 和 OpenCV 执行图像拼接。给定一对共享一些公共区域的图像,我们的目标是“缝合”它们并创建一个全景图像场景。

在整篇文章中,我们回顾了一些最著名的计算机视觉技术。其中包括:

  • 关键点检测
  • 局部不变描述符(SIFT、SURF 等)
  • 特征匹配
  • 使用 RANSAC 的单应性估计
  • 透视扭曲

我们探索了许多特征提取器,如 SIFT、SURF、BRISK 和 ORB。你可以使用这款 Colab 笔记本进行跟踪,甚至用你的图片进行尝试。

特征检测和提取

给定一对像上面这样的图像,我们想把它们拼接起来,创建一个全景场景。需要注意的是,两个图像需要共享一些公共区域。

此外,我们的解决方案必须是健壮的,即使图片在以下一个或多个方面有差异:

  • 缩放比例
  • 空间位置
  • 捕捉设备

这个方向的第一步是提取一些关键点和感兴趣的特征。然而,这些特征需要具有一些特殊的属性。

让我们首先考虑一个简单的解决方案。

关键点检测

一个最初的可能是幼稚的方法是使用算法提取关键点,比如 Harris Corners。然后,我们可以尝试基于某种相似性度量(如欧几里德距离)来匹配相应的关键点。我们知道,角点有一个很好的性质:它们对于旋转是不变的。这意味着,一旦我们检测到一个角点,如果我们旋转图像,这个角点将仍然存在。

然而,如果我们旋转然后缩放一幅图像呢?在这种情况下,我们将有一段艰难的时间,因为角落不是不变的比例。也就是说,如果我们放大一幅图像,之前检测到的角点可能会变成一条线!

总之,我们需要对旋转和缩放不变的特征。这就是 SIFT、SURF 和 ORB 等更健壮的方法的用武之地。

要点和描述符。

像 SIFT 和 SURF 这样的方法试图解决角点检测算法的局限性。通常,角点检测算法使用固定大小的核来检测图像上的感兴趣区域(角点)。很容易看出,当我们缩放图像时,这个内核可能会变得太小或太大。

为了解决这个限制,像 SIFT 这样的方法使用高斯差分(DoD)。这个想法是将 DoD 应用于同一幅图像的不同比例版本。它还使用相邻像素信息来寻找和改进关键点和相应的描述符。

首先,我们需要加载两个图像,一个查询图像和一个训练图像。最初,我们从提取关键点和描述符开始。我们可以使用 OpenCVdetectAndCompute()函数一步完成。注意,为了使用 detectAndCompute() ,我们需要一个关键点检测器和描述符对象的实例。可以是 ORB,SIFT 或者 SURF 等。此外,在将图像输入 detectAndCompute() 之前,我们将它们转换成灰度。

我们在查询和火车图像上运行 detectAndCompute() 。此时,我们有了两幅图像的一组关键点和描述符。如果我们使用 SIFT 作为特征提取器,它为每个关键点返回一个 128 维的特征向量。如果选择 SURF,我们得到一个 64 维的特征向量。下图显示了使用 SIFT、SURF、BRISK 和 ORB 提取的一些特征。

Detection of key points and descriptors using SIFT

Detection of key points and descriptors using SURF

Detection of key points and descriptors using BRISK and Hamming distances.

Detection of key points and descriptors using ORB and Hamming distances.

特征匹配

如我们所见,我们从两幅图像中获得了大量特征。现在,我们想比较两组特征,并坚持使用显示更多相似性的特征对。

在 OpenCV 中,特征匹配需要一个 Matcher 对象。在这里,我们探索两种口味:

  • 强力匹配器
  • KNN(k-最近邻)

BruteForce (BF)匹配器正如其名所示。给定 2 组特征(来自图像 A 和图像 B),将 A 组中的每个特征与 B 组中的所有特征进行比较。默认情况下,BF Matcher 计算两点之间的欧几里德距离。因此,对于集合 A 中的每个特征,它返回集合 b 中最接近的特征。对于 SIFT 和 SURF,OpenCV 建议使用欧几里德距离。对于其他特征提取器,如 ORB 和 BRISK,建议使用汉明距离。****

要使用 OpenCV 创建一个 BruteForce 匹配器,我们只需要指定 2 个参数。第一个是距离度量。第二个是交叉检查布尔参数。

crossCheck bool 参数指示两个特征是否必须相互匹配才能被视为有效。换句话说,对于被认为有效的一对特征( f1,F2),f1需要匹配 f2 ,并且 f2 也必须匹配 f1 作为最接近的匹配。该过程确保了一组更稳健的匹配特征,并且在原始 SIFT 论文中有所描述。**

然而,对于我们想要考虑多个候选匹配的情况,我们可以使用基于 KNN 的匹配过程。

KNN 不会返回给定要素的单个最佳匹配,而是返回 k 个最佳匹配。

注意,k 值必须由用户预先定义。正如我们所料,KNN 提供了更多的候选特性。然而,我们需要确保所有这些匹配对在进一步之前都是健壮的。

比率测试

为了确保 KNN 返回的特征具有很好的可比性,SIFT 论文的作者建议使用一种叫做比率测试的技术。基本上,我们迭代 KNN 返回的每一对,并执行距离测试。对于每一对特征( f1,f2 ),如果 f1f2 之间的距离在一定比例之内,我们保留它,否则,我们丢弃它。此外,比率值必须手动选择。

本质上,比率测试的工作与来自 BruteForce Matcher 的交叉检查选项相同。两者都确保一对检测到的特征确实足够接近以被认为是相似的。下图显示了 BF 和 KNN 匹配器在 SIFT 特征上的结果。我们选择只显示 100 个匹配点,以便清晰可视化。

Feature matching using KNN and Ration Testing on SIFT features

Feature matching using Brute Force Matcher on SIFT features

请注意,即使在 KNN 对暴力和比率测试进行了交叉检查之后,一些特性仍然不能正确匹配。

然而,匹配器算法将从两幅图像中给我们最好的(更相似的)特征集。现在,我们需要获得这些点,并找到转换矩阵,该矩阵将基于它们的匹配点将两幅图像缝合在一起。

这种变换称为单应矩阵。简而言之,单应矩阵是一个 3×3 矩阵,可用于许多应用,如相机姿态估计、透视校正和图像拼接。单应是 2D 变换。它将点从一个平面(图像)映射到另一个平面。让我们看看我们如何得到它。

估计单应性

随机样本一致性或 RANSAC 是一种拟合线性模型的迭代算法。与其他线性回归不同,RANSAC 旨在对异常值保持稳健。

线性回归等模型使用最小二乘估计来拟合数据的最佳模型。然而,普通最小二乘法对异常值非常敏感。因此,如果离群值的数量很大,它可能会失败。

RANSAC 通过仅使用数据中的内嵌器的子集来估计参数,从而解决了这个问题。下图显示了线性回归和 RANSAC 之间的比较。首先,注意数据集包含相当多的异常值。

我们可以看到,线性回归模型很容易受到异常值的影响。这是因为它试图减少平均误差。因此,它倾向于支持最小化从所有数据点到模型本身的总距离的模型。这包括离群值。

相反,RANSAC 仅在被识别为内点的点的子集上拟合模型。

这个特征对我们的用例非常重要。这里,我们将使用 RANSAC 来估计单应矩阵。事实证明,单应性对我们传递给它的数据质量非常敏感。因此,重要的是要有一种算法(RANSAC ),能够将明显属于数据分布的点从不属于数据分布的点中过滤出来。

Comparison between Least Squares and RANSAC model fitting. Note the substantial number of outliers in the data.

一旦我们有了估计的单应性,我们需要将其中一个图像扭曲到一个公共平面上。

这里,我们将对其中一幅图像应用透视变换。基本上,透视变换可以组合一个或多个操作,如旋转、缩放、平移或剪切。想法是转换其中一个图像,使两个图像合并为一个。为此,我们可以使用 OpenCV warpPerspective() 函数。它接受一幅图像和单应性作为输入。然后,基于单应性将源图像扭曲到目的图像。

生成的全景图像如下所示。正如我们看到的,结果中有几个工件。更具体地说,我们可以看到一些与图像边界处的光照条件和边缘效应相关的问题。理想情况下,我们可以执行后处理技术来归一化亮度,如直方图匹配。这可能会使结果看起来更真实。

感谢阅读!

******

Input image pair**

Panoramic Image

****

Input image pair

Panoramic Image

****

Input image pair

Panoramic Image

****

Input image pair.

Panoramic Image

使用 scikit 图像进行图像处理

原文:https://towardsdatascience.com/image-processing-using-scikit-image-cb57ce4321ed?source=collection_archive---------13-----------------------

突破图像分析的恐惧和复杂性

数据科学求职过程的一个积极方面是暴露在现实世界中的挑战和问题。一个这样的挑战是检测图像中的对象位置。这个项目可以用两种方法来处理。

  • 不使用神经网络的计算机视觉
  • 卷积神经网络的计算机视觉

对于一个不知道如何在没有神经网络的情况下进行基本图像分析的人来说,我最终在 4 天内成功完成了这个项目。这样做最关键的部分是弄清楚图像实际上是什么,以及如何处理它们。

这篇文章的重点就是要做到这一点,用 scikit image 简单地理解图像。遵循这些要点将对对计算机视觉感兴趣的初露头角的数据科学家大有裨益。

1。什么是图像?

它们只是 numpy 数组。对于数据科学家来说,搞清楚这一点可以减少一半的复杂性。

不相信我,试试这个。你将画出一幅 80 年代没有任何信号接收的电视机的图像。

import numpy as np
import matplotlib.pyplot as pltrandom_image = np.random.random([500,500])
plt.imshow(random_image, cmap = 'gray')
plt.colorbar();

TV set from the past

2。大致来说,图像有三层:红色、蓝色和绿色

图像只是数字的集合。您可以在真实图像上通过调整值和编辑图像来改变这些。这是一个演示,将显示图像的规模,也是它的形状。

#Checking out a color image
from skimage import data
cat = data.chelsea()print(f'Shape: {cat.shape}')
print("Values min/max", cat.min(), cat.max())
plt.imshow(cat)

注意形状中的 3。这些表示红色、蓝色和绿色层。编辑这些数组中的值应该可以编辑图像。让我们来测试一下。让我们在图像上画一个正方形。

#Drawing a red square on the image
cat[10:110, 10:110, :] = [255, 0, 0] #{red, green, blue }
plt.imshow(cat)

就像一个上课无聊的学生,我只是用 python 代码丑化了一个图像。如果有人感兴趣的话,试着用一些颜色和一条金链让这只猫看起来更酷(这是一个完整的附带项目)。我们继续吧。

3。在您的系统上处理图像

学习将图像从您的系统上传到 python 环境是必不可少的,可以使用以下代码完成

from skimage import io
image = io.imread('image path')

4。将图像转换为灰度

大多数时候,灰度图像的图像处理不太复杂,用外行人的话来说就是黑白图像。浏览可以通过以下方式将彩色(红、蓝、绿)图像转换为灰度图像:

gray_image = color.rgb2gray(image)
plt.imshow(gray_image, cmap = 'gray');

5。寻找图像的边缘

图像中对象检测和定位的一个非常关键的因素是检测其边缘的能力。让我们拍下这张一个人操作照相机的照片。

skimage 过滤并模糊这张图片,不要太详细,但找到了这个人的轮廓。这被称为像素化。

####Code for smooth pixelation####from skimage import filters, img_as_float
import scipy.ndimage as ndi#Convolution step(Like in CNN's)smooth_mean = ndi.convolve(image, mean_kernel)
image = data.camera()
pixelated = image[::10, ::10]
pixelated_float = img_as_float(pixelated)
sigma  =1
smooth = filters.gaussian(pixelated_float, sigma)
plt.imshow(smooth);

使用来自滤波器的 sobel 滤波,可以容易地找到该图像的边缘。使用下面的代码:

#Using the Sobel filter
plt.imshow(filters.sobel(pixelated_float))

建立在这些基础知识点上,肯定会是进入计算机视觉的一个很好的开始。通过观看和学习 2019 年 SciPy 会议,这些方法可以进入更实际的细节。它在 youtube 上免费提供,正是它教会了我基础知识。

跟随这个链接到达那里

我对每一个阅读这篇文章的读者的最终意图是消除对任何图像分析任务的恐惧和恐吓。图像只是基本的数字,这是每个数据科学家都乐于接受的一件事。

图像推荐引擎—利用迁移学习

原文:https://towardsdatascience.com/image-recommendation-engine-leverage-transfert-learning-ec9af32f5239?source=collection_archive---------12-----------------------

应用于图像推荐的预训练模型世界之旅

在本文中,我们将开发一个基于图像这种非结构化数据的推荐系统。为了有一个快速、可操作的模型,而不需要费力地微调[Convolutional neural network](https://en.wikipedia.org/wiki/Convolutional_neural_network)算法,我们将使用[Transfer Learning](https://en.wikipedia.org/wiki/Transfer_learning)

迁移学习机器学习中的一个研究问题,它专注于存储在解决一个问题时获得的知识,并将其应用于另一个不同但相关的问题。【1】例如,在学习识别汽车时获得的知识可以应用于识别卡车

为了使它更容易,我们将使用高级 API [Keras](https://keras.io/)。Keras 提供了几个预训练模型,这些模型已经证明了它们在泛化方面的价值。让我们立即开始建模吧!

我有一些关于时尚产品的数据,我在这里得到了,由于计算时间的原因,我将语料库减少到 2000 张图片。因此,正如我之前所说,Keras 提供了几个只需导入的预训练模型。

我输入了他们已经在训练的算法,现在我该怎么办?有几个初步的步骤,我们将准备我们的图像语料库并重新设计算法,以便它将返回通过训练确定的高级特征。

1.准备图片语料库

我们有一份巴布亚新几内亚的清单:

  • 对于每个 png,我们将调整它的大小
  • 把它变成三维数组
  • 在 3D 数组列表上构建矩阵
  • 用 Keras 内置函数对其进行预处理。

2.准备算法

  • 为了预测最后一个要素而不是预测的 1000 个标注的最后一层,我们需要重新设计模型以移除预测层。

首先,我们需要知道模型的输入是什么形状,并根据这个形状调整图像的大小。让我们用 VGG16 来做我们的预处理,它有如下结构。

VGG16 structure model

由于我们看到输入层中的输入形状是(none,224,224,3),我们将直接从模型中提取输入中请求的大小和宽度,这样我们就不必查看每个模型的摘要。

#with vgg model (or any model above)
image_width = eval(str(vgg_model.layers[0].output.shape[1]))
image_height = eval(str(vgg_model.layers[0].output.shape[2]))

注意:由于 self . model . layers[0]. output . shape[1]的输出是tensor flow . python . framework . tensor _ shape。Dimension 对象,我将对其求值以获得整数。然后,我们加载和调整图像大小为一个 PIL。Image . Image

pil_img = load_img('image.png',  target_size=(image_width, image_height))

我们将它转换为 shape (224,224,3)数组,并使用额外的维度对其进行扩展,以适应算法所需的(none,224,224,3)输入形状。

from keras.preprocessing.image import load_img,img_to_arrayarray_img = img_to_array(pil_img)
images = np.expand_dims(array_img, axis=0)

我们可以对每个文件都这样做,然后把它变成一个矩阵。

预处理 _ 输入减去数据的平均 RGB 通道。这是因为您正在使用的模型已经在不同的数据集上进行了训练:image.shape仍然是带有堆栈和预处理 _ 输入的(1, 224, 224, 3),它变成了带有 n 个输入数(即图像数)的(n, 224, 224, 3)

现在我们的输入已经准备好了,可以放入算法中了。我们需要重新设计我们的模型,在新模型中加入预先训练的输入和输出的倒数第二层。

from keras.models import Modelfeat_extract = Model(inputs=vgg_model.input,outputs=vgg_model.layers[-2].output)

有了这个模型,我们就可以使用。预测方法得到的图像特征与第二层特征一样多(vgg_model 'fc2 层'为 4096)。

imgs_features = feat_extract.predict(dense_mat)

现在,我们可以计算每个图像之间的余弦相似性,以获得索引和列中有 png 的(n*n)密集矩阵,然后我们可以提出一个或多个推荐。

cosSimilarities = cosine_similarity(imgs_features)cos_similarities_df = pd.DataFrame(cosSimilarities, columns=files, index=files)

让我们将所有这些归纳起来,一次测试几个模型。

我们已经定义了一个通用类,它采用任何预训练模型,并相应地调整图像集,并针对给定的图像提出建议,让我们看看结果。

  • MobileNetV2

  • 移动网络

  • InceptionResNet

  • VGG16

很酷不是吗!尽管我们使用了只有 2000 张图片的语料库,但我们有非常相关的推荐。

最后

我们已经看到了使用迁移学习的优势。为了有一个更准确的推荐系统,创建我们自己的卷积网络会更有意义,这将是下一篇文章的主题,保持联系!谢了。

此处代码:https://github.com/AlexWarembourg/Medium/blob/master/product _ recommendation . ipynb

带有 Keras 的图像推荐引擎

原文:https://towardsdatascience.com/image-recommendation-engine-with-keras-d227b0996667?source=collection_archive---------25-----------------------

建立一个 CNN 分类器,把它变成一个推荐引擎。

https://www.cleanpng.com/png-convolutional-neural-network-natural-language-proc-3083964/

我有一些漫画数据,我甚至写了一篇文章,以便你可以收集这些数据集(有一些修改)见:https://towards data science . com/scrape-multiple-pages-with-scrapy-ea 8 EDFA 4318

对于每一部漫画,我都在海报栏里找到了他的照片的网址。我将在此基础上建立我的图像语料库

import requestsmanga["title"] = manga["title"].replace({"%" : ""}, regex=True)
manga= manga[(manga["title"] != "") & (manga["title"].notnull()) & (manga["poster"].notnull())]import requests
from tqdm import tqdmkeep_in_memory = []for url, title in tqdm(zip(manga["poster"], manga["title"])) : 
    str_name = "/home/jupyter/Untitled Folder/%s.jpg" %title
    str_name = str_name.strip()
    keep_in_memory.append(str_name)
    with open(str_name, 'wb') as f:
        f.write(requests.get(url).content)

manga["pics_ref"] = keep_in_memory

我将使用性别列作为我的图像分类器的标签。但是我之前需要做一点清理,因为我有大约 3000 个独特的标签,我会清理我的标签并减少它们。

manga["genre"] = manga["genre"].str.strip()
manga["genre"] = manga["genre"] +  " ,"import redef clean(genre, string_to_filter) :
    return re.sub('(?<={})(.*\n?)(?=,)'.format(string_to_filter), '', genre)manga["genre"] = manga["genre"].apply(lambda  x : clean(str(x), 'Comic'))
manga["genre"] = manga["genre"].apply(lambda  x : clean(str(x), 'Action'))
manga["genre"] = manga["genre"].apply(lambda  x : clean(str(x), 'Josei'))
manga["genre"] = manga["genre"].apply(lambda  x : clean(str(x), 'Shoujo'))
manga["genre"] = manga["genre"].apply(lambda  x : clean(str(x), 'Shounen'))
manga["genre"] = manga["genre"].apply(lambda  x : clean(str(x), 'Horror'))manga['genre'] = [list(map(str.strip, y)) for y in [x.split(',') for x in manga['genre']]]manga['genre'] =[','.join(x) for x in manga['genre']]my_cat = ['Action', 'Adventure', 'Comedy', 'Hentai',
          'Harem', 'Fantasy', 'Drama', 'Horror', 'Romance','Josei',
          'Fantasy', 'Seinen', 'Sci-Fi', 'Slice of Life', 'Mecha', 'Yaoi',
          'Yuri', 'Thriller', 'Comic']manga["genre"] = manga["genre"].apply(lambda z : [x for x in my_cat if x in z])
manga['genre'] =[','.join(x) for x in manga['genre']]genre = manga["genre"].str.get_dummies(',')
manga = pd.concat([manga, genre], axis = 1)

我现在有 18 个标签,我把它们编码成每个标签的二进制矩阵。

我还有另一个问题:我的标签是不平衡的,所以我们将定义一个类权重,稍后我将在我的模型中传递它。

label_cnt = [(columns, manga[columns].sum()) for columns in manga.columns[8:]]
tot = sum([x[1] for x in label_cnt])
class_weight = dict(zip([x[0] for x in label_cnt], [x[1]/tot for x in label_cnt]))

最后,我们将建立我们的输入矩阵。

train_image = []
index_to_drop = []
for i, png in tqdm(list(enumerate(manga["pics_ref"]))):
    try : 
        img = image.load_img(png,target_size=(256,256,3))
        img = image.img_to_array(img)
        img = img/255
        train_image.append(img)
    except OSError : 
        index_to_drop.append(i)manga = manga.drop(manga.index[index_to_drop])

X = np.array(train_image)
y = np.array(manga[manga.columns[8:].tolist()])from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 777)

然后,我们将定义我们的模型。不管结构如何,这里有一点很重要,即我们的预测必须通过 sigmoid 函数激活,而不是 softmax,因为否则我们将有属于这样一个标签的累积概率,或者我们想要属于一个标签的独立概率。

最后,使用 ImageDataGenerator 模块增加数据,该模块将通过更改 RGB 通道、缩放、翻转图像等方式生成新照片…..

我们的模型拟合得非常准确,但它不是这项任务的完美指标。我们试试吧,省省吧。

randint = np.random.randint(1, manga.shape[0], 1)[0]
poster = manga["pics_ref"].iloc[randint]
img = image.load_img(poster, target_size=(256,256,3))
img = image.img_to_array(img)
img = img/255classes = np.array(manga.columns[8:])
proba = model.predict(img.reshape(1,256,256,3))
top_3 = np.argsort(proba[0])[:-4:-1]
for i in range(3):
    print("{}".format(classes[top_3[i]])+" ({:.3})".format(proba[0][top_3[i]]))
plt.imshow(img)

from keras.models import model_from_json# serialize model to JSON
model_json = model.to_json()
with open("model.json", "w") as json_file:
    json_file.write(model_json)
# serialize weights to HDF5
model.save_weights("model.h5")
print("Saved model to disk")
# load json and create model
json_file = open('model.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
'''
loaded_model = model_from_json(loaded_model_json)
loaded_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
'''

无论如何,我们对分类器的准确性不感兴趣,而是对训练产生的特征感兴趣,这将允许我们建立我们的推荐!首先,我们将通过删除最后一个预测层,用我们的预训练模型重建一个模型。

image_features_extractor = Model(inputs=model.input,  outputs=model.layers[-2].output)img_features = image_features_extractor.predict(X)cosSimilarities = cosine_similarity(img_features)cos_similarities_df = pd.DataFrame(cosSimilarities,
                                   columns=manga["title"],
                                   index=manga["title"])

最后,我们得到与给定海报最相似的海报。

def most_similar_to(given_img, nb_closest_images = 5):print("-----------------------------------------------------------------------")
    print("original manga:")original = load_img(given_img, target_size=(256,256,3))
    plt.imshow(original)
    plt.show()print("-----------------------------------------------------------------------")
    print("most similar manga:")closest_imgs = cos_similarities_df[given_img].sort_values(ascending=False)[1:nb_closest_images+1].index
    closest_imgs_scores = cos_similarities_df[given_img].sort_values(ascending=False)[1:nb_closest_images+1]for i in range(0,len(closest_imgs)):
        img = image.load_img(closest_imgs[i], target_size=(256,256,3))
        plt.imshow(img)
        plt.show()
        print("similarity score : ",closest_imgs_scores[i])

  • 推荐

看起来不错!但是还可以更好!

最后

我们编写了一个卷积神经网络来对我们的漫画进行分类,然后我们检索了训练过程中产生的变量,使其成为一个推荐系统。同一个模型的几种用法相当不错不是吗!
谢谢,代码在这里:https://github.com/AlexWarembourg/Medium

使用 Python 进行图像抓取

原文:https://towardsdatascience.com/image-scraping-with-python-a96feda8af2d?source=collection_archive---------0-----------------------

使用 PYTHON 进行 WEB 抓取

学习如何用 Python 从 Google 下载图片的代码指南!

Photo by Mr Cup / Fabien Barral on Unsplash

为了训练一个模型,你需要图像。你当然可以手动下载,甚至可以批量下载,但我认为有一种更令人愉快的方式。让我们使用 Python 和一些 web 抓取技术来下载图像。

更新 2(2020 年 2 月 25 日):抓取网页的一个问题是目标元素依赖于某种类型的 a selector。我们使用css-selectors从页面中获取相关元素。谷歌似乎在过去的某个时候改变了它的网站布局,这使得它有必要更新相关的选择器。提供的脚本应该可以再次工作。

更新:自从写了这篇关于图像抓取的文章后,我已经发表了关于构建图像识别卷积神经网络的文章。如果你想好好利用这些图片,看看下面这篇文章吧!

[## 猫,狗,还是埃隆马斯克?

了解如何使用 Python 和 Keras 在不到 15 分钟的时间内构建您的图像识别卷积神经网络!

towardsdatascience.com](/cat-dog-or-elon-musk-145658489730)

在今天的文章中,我们将讨论以下主题:

  1. 抓取静态页面
  2. 抓取交互式页面
  3. 从谷歌抓取图片
  4. 合法性后记

先决条件

一个 Python 环境(我建议 Jupyter 笔记本)。如果你还没有设置这个,不要担心。这是毫不费力的,不到 10 分钟。

[## 所以你想成为一名数据科学家?

到底是什么阻止了你?下面是如何开始!

towardsdatascience.com](/get-started-with-python-e50dc8c96589)

①抓取静态页面

Photo by David Marcu on Unsplash

编写静态页面(即不使用 JavaScript 在页面上创建高度交互的页面)非常简单。静态网页就是一个用标记语言编写的大文件,它定义了内容应该如何呈现给用户。您可以非常快速地获得原始内容,而无需应用标记。假设我们想从这个维基百科页面中获取下表:

Screenshot from Wikipedia page shows country codes and corresponding names

我们可以通过利用一个名为 requests 的基本 Python 库来实现这一点,如下所示:

using requests library to download static page content

如你所见,这不是很有用。我们不想要所有的噪音,而是想只提取页面的特定元素(准确地说是表格)。这种情况下美汤就派上了用场。

Static Extraction

漂亮的 Soup 允许我们轻松地导航、搜索或修改解析树。在通过适当的解析器运行原始内容之后,我们得到了一个可爱的干净的解析树。在这个树中,我们可以使用类“wikitable sortable”搜索“table”类型的元素。您可以通过右键单击表并单击 inspect 查看源代码来获得关于类和类型的信息。然后,我们遍历该表,逐行提取数据,最终得到以下结果:

parsed table from Wikipedia Page

巧妙的技巧: Pandas 有一个内置的read_html方法,通过运行pip install lxml安装 lxml (一个强大的 xml 和 HTML 解析器)后就可以使用了。read_html允许您执行以下操作:

the second result from read_html

正如你所看到的,我们调用res[2]是因为pd.read_html()会把它找到的所有东西转储到一个单独的数据帧中,即使是松散地类似于一个表。您必须检查哪个结果数据帧包含所需的数据。对于结构良好的数据,尝试一下read_html是值得的。

②抓取互动页面

Photo by Ross Findon on Unsplash

然而,大多数现代网页都具有很强的互动性。“单页应用程序”的概念意味着网页本身会改变,而用户不必一直重新加载或从一个页面重定向到另一个页面。因为只有在特定的用户交互之后才会发生这种情况,所以在抓取数据时几乎没有什么选择(因为这些操作必须发生)。

有时,用户操作可能会触发对公开的后端 API 的调用。在这种情况下,可以直接访问 API 并获取结果数据,而不必经过中间不必要的步骤。然而,大多数时候,你将不得不经历点击按钮、滚动页面、等待加载和所有这些步骤……或者至少你必须让网页认为正在做所有这些。硒来拯救!

Selenium 可用于自动化 web 浏览器与 Python(以及其他语言)的交互。通俗地说,selenium 假装是一个真实的用户,它打开浏览器,“移动”光标,并点击按钮,如果你告诉它这样做的话。据我所知,Selenium 背后最初的想法是自动化测试。然而,在自动化基于 web 的重复性任务方面,Selenium 同样强大。

让我们看一个例子来说明硒的用法。不幸的是,需要事先做一点准备。我将用谷歌 Chrome 概述 Selenium 的安装和使用。如果您想使用另一个浏览器(如 Headless ),您必须下载相应的 web 驱动程序。你可以在这里找到更多信息。

步骤:

  1. 安装谷歌浏览器(如果已经安装,跳过)
  2. 识别你的 Chrome 版本。通常通过点击“关于谷歌浏览器”找到。我目前有版本 77.0.3865.90 (我的主版本因此是 77 ,第一个点之前的数字)。
  3. 这里为你的主版本下载相应的 from 驱动程序,并将可执行文件放到一个可访问的位置(我使用Desktop/Scraping
  4. 通过pip install selenium安装 Python Selenium 包

启动网络驱动

运行下面的代码片段(为了便于演示,请在 Jupyter 笔记本上运行)并查看幽灵浏览器是如何打开的。

import selenium# This is the path I use
# DRIVER_PATH = '.../Desktop/Scraping/chromedriver 2'# Put the path for your ChromeDriver here
DRIVER_PATH = <YOUR PATH>wd = webdriver.Chrome(executable_path=DRIVER_PATH)

如果一切按计划进行,您现在应该会看到这样的内容:

Google Chrome browser controlled by Selenium

现在运行(在新单元格中):

wd.get('[https://google.com'](https://google.com'))

你的浏览器应该导航到——不出所料——google.com。现在运行:

search_box = wd.find_element_by_css_selector('input.gLFyf')
search_box.send_keys('Dogs')

当你的浏览器在搜索框中输入Dogs时,你就会看到结果。

好吧,让我们关闭驱动程序:

wd.quit()

完美!你已经掌握了基本知识。Selenium 非常强大,几乎每个交互都可以模拟。有些动作甚至可以通过抽象方法来实现,比如点击按钮或者悬停在物体上。此外,如果出现最坏的情况,您可以通过将光标移动到您想要的位置,然后执行单击操作来模仿人类行为。

③从谷歌上抓取图片

Photo by Bharathi Kannan on Unsplash

既然你现在明白了基本知识,我们就可以把所有的东西拼凑起来。让浏览器按照我们的要求行事:

  • 搜索特定术语并获取图片链接
  • 下载图像

搜索特定短语&获取图片链接

get_image_links.py

函数fetch_image_urls需要三个输入参数:

  1. **query**:搜索词,如**Dog**
  2. **max_links_to_fetch**:刮刀应该收集的链环数
  3. **webdriver**:实例化的 Webdriver

下载图像 为了让下面的代码片段工作,我们首先必须通过运行pip install Pillow来安装PIL

persist_image.py

persist_image功能抓取一个图片 URL url并下载到folder_path中。该函数将为图像分配一个随机的 10 位 id。

综合起来 下面的函数search_and_download结合了前面的两个函数,为我们使用 ChromeDriver 增加了一些弹性。更准确地说,我们在一个with上下文中使用 ChromeDriver,这保证了浏览器正常关闭,即使在with上下文中出现错误。search_and_download允许您指定**number_images**,默认设置为 5,但可以设置为您想要下载的任意数量的图像。

search_and_donwload.py

现在,我们可以执行以下操作:

Download some doggie images

并将获得:

恭喜你!你已经建立了你自己的图像刮刀。考虑使用刮刀,享受你正在喝的咖啡,而不是手动下载 100 张图片。

如果您想了解如何自动执行抓取过程并持续运行,请查看以下文章:

[## 实用 Python:如何在几分钟内编写和部署一个监控+通知服务?

你曾经希望有一种服务,一旦它观察到一个特定的事件,就反复地检查和 pings 你吗?—了解如何…

towardsdatascience.com](/practical-python-how-to-write-and-deploy-a-monitoring-notification-service-within-minutes-for-free-b682cffa66ef)

哦,如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名灵媒成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的链接注册,我甚至会做一些🍩。

[## 通过我的推荐链接加入 Medium-Fabian Bosler

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@fabianbosler/membership)

④关于网络抓取合法性的后记

我不是律师,所以我所说的一切都不应被视为法律意见。话虽如此,围绕网络抓取合法性的问题很可能要逐案评估。只要你不违反任何服务条款或对你抓取的网页产生负面影响,你就是清白的,这似乎是一个共识。网络抓取行为本身不可能违法。你可以抓取你的页面而不会有任何影响,毕竟谷歌机器人每天都在抓取整个网页。我的建议是:

确保您没有违反任何法律、服务条款或对您的目标产生负面影响。

使用 Python 的 scikit-image 模块进行图像分割。

原文:https://towardsdatascience.com/image-segmentation-using-pythons-scikit-image-module-533a61ecc980?source=collection_archive---------2-----------------------

scikit-image 库的图像分割方法概述。

source

所有的东西迟早都是数字,包括图像。

看过 【终结者】 的人一定会同意这是那个时代最伟大的科幻电影。在电影中, 詹姆斯·卡梅隆 引入了一个有趣的视觉效果概念,使观众有可能获得被称为终结者的电子人的眼睛后面。这种效果后来被称为 终结者视觉中的一种方式,它把人类从背景中分割出来。这听起来可能完全不合时宜,但图像分割是当今许多图像处理技术的重要组成部分。**

图象分割法

我们都很清楚 Photoshop 或类似的图形编辑器提供的无限可能性,它们可以将一个人从一幅图像中取出,放入另一幅图像中。然而,这样做的第一步是 识别该人在源图像中的位置 和这是图像分割发挥作用的地方。有许多为图像分析目的而编写的库。在本文中,我们将详细讨论 scikit-image ,这是一个基于 Python 的图像处理库。

完整的代码也可以从与本文相关的 Github 资源库 中获得。

sci kit-图像

scikit-image.org

Scikit-image 是一个专门用于图像处理的 Python 包。

装置

scikit-image 可以按如下方式安装:

*pip install scikit-image# For Conda-based distributions
conda install -c conda-forge scikit-image*

Python 中的图像概述

在讨论图像分割的技术细节之前,有必要先熟悉一下 scikit 图像生态系统及其处理图像的方式。

  • 从浏览库导入灰度图像

skimage 数据模块包含一些内置的示例数据集,这些数据集通常以 jpeg 或 png 格式存储。

*from skimage import data
import numpy as np
import matplotlib.pyplot as pltimage = data.binary_blobs()
plt.imshow(image, cmap='gray')*

  • 从浏览库导入彩色图像
*from skimage import data
import numpy as np
import matplotlib.pyplot as pltimage = data.astronaut()plt.imshow(image)*

  • 从外部来源导入图像
*# The I/O module is used for importing the image
from skimage import data
import numpy as np
import matplotlib.pyplot as plt
from skimage import ioimage = io.imread('skimage_logo.png')plt.imshow(image);*

  • 加载多张图片
*images = io.ImageCollection('../images/*.png:../images/*.jpg')print('Type:', type(images))
images.files
Out[]: Type: <class ‘skimage.io.collection.ImageCollection’>*
  • 保存图像
*#Saving file as ‘logo.png’
io.imsave('logo.png', logo)*

图象分割法

现在我们对 scikit-image 有了一个概念,让我们进入图像分割的细节。 图像分割 n 本质上是将数字图像分割成多个片段的过程,以简化和/或改变图像的表示,使其更有意义且更易于分析。

在本文中,我们将结合监督和非监督算法来处理分割过程。

Some of the Segmentation Algorithms available in the scikit-image library

监督分割:可能来自人的输入的一些先验知识用于指导算法。

无监督分割:不需要先验知识。这些算法试图将图像自动细分成有意义的区域。用户可能仍然能够调整某些设置以获得期望的输出。

让我们从称为阈值处理的最简单算法开始。

阈值处理

通过选择高于或低于某个 阈值的像素,这是从背景中分割对象的最简单方法。当我们打算从背景中分割出物体时,这通常是有帮助的。你可以在这里阅读更多关于阈值的内容。

让我们在预先加载了 scikit-image 数据集的教科书图像上尝试一下。

基本进口

*import numpy as np
import matplotlib.pyplot as pltimport skimage.data as data
import skimage.segmentation as seg
import skimage.filters as filters
import skimage.draw as draw
import skimage.color as color*

一个简单的函数来绘制图像

***def** image_show(image, nrows=1, ncols=1, cmap='gray'):
    fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(14, 14))
    ax.imshow(image, cmap='gray')
    ax.axis('off')
    **return** fig, ax*

图像

*text = data.page()image_show(text)*

这张图像有点暗,但也许我们仍然可以选择一个值,在没有任何高级算法的情况下,给我们一个合理的分割。现在,为了帮助我们选择这个值,我们将使用一个直方图

直方图是显示在图像中发现的不同亮度值下图像中的像素的数量的图表。简而言之,直方图是一种图表,其中 x 轴显示图像中的所有值,而 y 轴显示这些值的频率。

*fig, ax = plt.subplots(1, 1)
ax.hist(text.ravel(), bins=32, range=[0, 256])
ax.set_xlim(0, 256);*

我们的例子恰好是一个 8 位图像,所以我们在 x 轴上总共有 256 个可能的值。我们观察到存在相当亮的像素浓度(0:黑色,255:白色)。这很可能是我们相当轻的文本背景,但其余的是一种涂抹了。一个理想的分割直方图应该是双峰的,并且是完全分开的,这样我们就可以在中间选择一个数字。现在,让我们试着基于简单的阈值分割制作一些分段图像。

监督阈值

由于我们将自己选择阈值,我们称之为监督阈值。

*text_segmented = *text > (value concluded from histogram i.e 50,70,120 )*image_show(text_segmented);*

Left: text>50 | Middle : text > 70 | Right : text >120

我们没有得到任何理想的结果,因为左边的阴影产生了问题。现在让我们尝试无监督阈值处理。

无监督阈值处理

Scikit-image 有许多自动阈值方法,在选择最佳阈值时不需要输入。一些方法有:otsu, li, local.

*text_threshold = filters.threshold_  *# Hit tab with the cursor after the underscore to get all the methods.*image_show(text < text_threshold);*

**

Left: otsu || Right: li

local的情况下,我们还需要指定block_sizeOffset 帮助调整图像以获得更好的效果。

*text_threshold = filters.threshold_local(text,block_size=51, offset=10) 
image_show(text > text_threshold);*

local thresholding

这是非常好的,并且在很大程度上摆脱了噪声区域。

监督分割

阈值分割是一个非常基本的分割过程,在高对比度图像中无法正常工作,为此我们需要更先进的工具。

在本节中,我们将使用一个免费提供的示例图像,并尝试使用监督分割技术分割头部。

**# import the image*
from skimage import io
image = io.imread('girl.jpg') 
plt.imshow(image);*

source

在对图像进行任何分割之前,使用一些滤波器对其进行降噪是一个好主意。

但是,在我们的例子中,图像并不是很嘈杂,所以我们会照原样处理。下一步是用rgb2gray将图像转换成灰度。

*image_gray = color.rgb2gray(image) 
image_show(image_gray);*

我们将使用两种基于完全不同原理的分割方法。

活动轮廓分割

活动轮廓分割也称为*和使用感兴趣区域周围的用户定义轮廓或线条进行初始化,然后该轮廓缓慢收缩,并被光线和边缘吸引或排斥。*

对于我们的示例图像,让我们在人的头部周围画一个圆来初始化蛇。

***def** circle_points(resolution, center, radius): *"""*
 *Generate points which define a circle on an image.Centre refers to the centre of the circle*
 *"""*   
    radians = np.linspace(0, 2*np.pi, resolution) c = center[1] + radius*np.cos(radians)#polar co-ordinates
    r = center[0] + radius*np.sin(radians)

    **return** np.array([c, r]).T*# Exclude last point because a closed path should not have duplicate points*
points = circle_points(200, [80, 250], 80)[:-1]*

上面的计算计算了圆周上的点的 x 和 y 坐标。由于我们给定的分辨率是 200,它将计算 200 个这样的点。

*fig, ax = image_show(image)
ax.plot(points[:, 0], points[:, 1], '--r', lw=3)*

然后,该算法通过将闭合曲线拟合到人脸的边缘,将人脸从图像的其余部分中分割出来。

*snake = seg.active_contour(image_gray, points)fig, ax = image_show(image)
ax.plot(points[:, 0], points[:, 1], '--r', lw=3)
ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3);*

我们可以调整名为alphabeta的参数。较高的 alpha 值会使蛇收缩得更快,而 beta 值会使蛇更平滑。

*snake = seg.active_contour(image_gray, points,alpha=0.06,beta=0.3)fig, ax = image_show(image)
ax.plot(points[:, 0], points[:, 1], '--r', lw=3)
ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3);*

随机行者分割

在这种方法中,用户交互式地标记少量像素,这些像素被称为标记。然后,设想每个未标记的像素释放一个随机行走体,然后可以确定随机行走体从每个未标记的像素开始并到达预先标记的像素之一的概率。通过将每个像素分配给计算出最大概率的标签,可以获得高质量的图像分割。点击阅读参考文件。

在这里,我们将重用上一个示例中的种子值。我们可以用
完成不同的初始化,但是为了简单起见,让我们坚持使用圆形。

*image_labels = np.zeros(image_gray.shape, dtype=np.uint8)*

随机漫步算法需要一个标签图像作为输入。因此,我们将有一个较大的圆圈包围着这个人的整个脸,另一个较小的圆圈靠近脸的中间。

*indices = draw.circle_perimeter(80, 250,20)#from [here](https://medium.com/p/533a61ecc980/oeed)image_labels[indices] = 1
image_labels[points[:, 1].astype(np.int), points[:, 0].astype(np.int)] = 2image_show(image_labels);*

现在,让我们使用随机漫步机,看看会发生什么。

*image_segmented = seg.random_walker(image_gray, image_labels)# Check our results
fig, ax = image_show(image_gray)
ax.imshow(image_segmented == 1, alpha=0.3);*

它看起来不像我们想要的那样抓住边缘。为了解决这种情况,我们可以调整β参数,直到我们得到想要的结果。经过几次尝试后,值 3000 工作得相当好。

*image_segmented = seg.random_walker(image_gray, image_labels, beta = 3000)# Check our results
fig, ax = image_show(image_gray)
ax.imshow(image_segmented == 1, alpha=0.3);*

这就是监督分割,我们必须提供某些输入,还必须调整某些参数。然而,让一个人看着一幅图像,然后决定给出什么输入或者从哪里开始,并不总是可能的。幸运的是,对于这些情况,我们有无监督分割技术。

无监督分割

无监督分割不需要先验知识。考虑一个如此大的图像,以至于不可能同时考虑所有像素。因此,在这种情况下,无监督分割可以将图像分解成几个子区域,所以不是数百万像素,而是数十到数百个区域。让我们来看两个这样的算法:

SLIC(简单线性迭代聚类)

SLIC 算法实际上使用了一种叫做 K-Means 的机器学习算法。它接受图像的所有像素值,并试图将它们分成给定数量的子区域。在此阅读参考文件

SLIC 是彩色的,所以我们将使用原始图像。

*image_slic = seg.slic(image,n_segments=155)*

我们所做的只是将我们找到的每个子图像或子区域设置为该区域的平均值,这使得它看起来不像是随机分配的颜色的拼凑物,而更像是被分解成类似区域的图像。

**# label2rgb replaces each discrete label with the average interior color*
image_show(color.label2rgb(image_slic, image, kind='avg'));*

我们将这张图片从 512512 = 262,000 像素缩减到 155 个区域。*

费尔曾兹瓦尔布

该算法还使用了一种叫做最小生成树聚类的机器学习算法。Felzenszwaib 没有告诉我们图像将被划分成多少个簇。它将运行并生成它认为适合图像上给定的
比例或缩放因子的尽可能多的集群。参考文件可在此处获取。

*image_felzenszwalb = seg.felzenszwalb(image) 
image_show(image_felzenszwalb);*

这是很多地区。让我们来计算独特区域的数量。

*np.unique(image_felzenszwalb).size
3368*

现在让我们使用区域平均值对它们重新着色,就像我们在 SLIC 算法中做的那样。

*image_felzenszwalb_colored = color.label2rgb(image_felzenszwalb, image, kind='avg')image_show(image_felzenszwalb_colored);*

现在我们得到了相当小的区域。如果我们想要更少的区域,我们可以改变scale参数或者从这里开始合并它们。这种方法有时被称为过度分割

这几乎看起来更像是一个色调分离的图像,本质上只是减少了颜色的数量。要再次组合它们,可以使用 区域邻接图(RAG ) ,但这超出了本文的范围。

基于深度学习的图像分割

到目前为止,我们只使用 scikit 图像模块研究了图像分割技术。然而,值得一提的是一些使用深度学习的图像分割技术。这里有一篇精彩的博客文章,重点介绍了图像分割架构、损失、数据集和框架,您可以将其用于您的图像分割项目。

* [## 2020 年的图像分割:架构、损失、数据集和框架

在这篇文章中,我们将使用深度学习深入研究图像分割的世界。我们将讨论:什么…

海王星. ai](https://neptune.ai/blog/image-segmentation-in-2020)*

结论

图像分割是一个非常重要的图像处理步骤。它是一个活跃的研究领域,应用范围从计算机视觉到医学成像,再到交通和视频监控。Python 以 scikit-image 的形式提供了一个健壮的库,其中包含大量用于图像处理的算法。它是免费的,没有任何限制,背后有一个活跃的社区。看看他们的文档,了解更多关于这个库及其用例的信息。

参考文献:

Scikit 图像文档

使用 fastai 的图像分割

原文:https://towardsdatascience.com/image-segmentation-with-fastai-9f8883cc5b53?source=collection_archive---------6-----------------------

了解如何使用 U-net 对图像的每个像素进行颜色编码

介绍

图像分割是计算机视觉的一种应用,其中我们对图像中的每个像素进行颜色编码。每个像素代表图像中的一个特定对象。如果你看上面的图片,每条街道都是紫色的,每栋建筑都是橙色的,每棵树都是绿色的,等等。我们为什么要这样做,它与对象检测有何不同?

当我们关心边缘和区域时,当我们想从背景中分离出重要的对象时,通常会使用图像分割。我们希望了解一个对象的具体情况,并从那里对其进行进一步的分析。想象一下无人驾驶汽车。自动驾驶汽车不仅要识别街道,还要知道它的边缘或曲线,以便正确转弯。

图像分割在医学领域有着重要的意义。需要研究的部分用颜色编码,并从不同角度扫描观察。然后,它们被用于器官的自动测量、细胞计数或基于提取的边界信息的模拟。

该过程

我们将图像分割视为一个分类问题,对于图像中的每个像素,我们试图预测它是什么。是自行车,道路线,人行道,还是建筑?这样,我们产生了一个彩色编码图像,其中每个物体都有相同的颜色。

代码

像往常一样,我们从导入 fastai 库开始。

让我们先来看看其中的一张图片。

接下来,我们来看看分割后的图像是什么样子。由于标记图像中的值是整数,我们不能使用相同的函数来打开它。相反,我们使用open_maskshow来显示图像。

注意open_mask内部的get_y_fn功能。在每一个分割问题中,我们都有两组图像,原始图像和标记图像。我们需要将标签图像与正常图像进行匹配。我们用文件名来做这件事。让我们来看看一些图像的文件名。

我们看到正常图像和标记图像的文件名是相同的,除了相应的标记图像在末尾有一个_P。因此,我们写了一个函数,对于每一个图像,识别其相应的标记副本。

我们还有一个名为codes.txt的文件,它告诉我们标记图像中的整数对应于什么对象。让我们打开标签图像的数据。

现在让我们检查代码文件中这些整数的含义。

标签数据里有很多 26。从代码文件中的索引 0 开始计数,我们看到整数 26 引用的对象是一棵树。

既然我们已经理解了我们的数据,我们可以继续创建一个数据束并训练我们的模型。

我们不会使用整个数据集,我们还会保持相对较小的批量,因为对每个图像中的每个像素进行分类是一项资源密集型任务。

像往常一样,我们创建我们的数据束。阅读上面的代码:

  • 从文件夹创建数据束
  • 根据valid.txt中提到的文件名将数据分为训练和测试
  • 使用功能get_y_fn找到带标签的图像,并将代码用作待预测的类别。
  • 在图像上应用变换(注意这里的tfm_y = True。这意味着我们对从属图像应用的任何变换也应该应用到目标图像上。(例如:如果我们水平翻转图像,我们也应该翻转相应的标签图像))

为了训练,我们将使用一个名为 U-Net 的 CNN 架构,因为他们擅长重建图像。

在解释什么是 U-Net 之前,请注意上面代码中使用的指标。什么是acc_camvid

图像分割问题中的精度与任何分类问题中的精度相同。

Accuracy = no. of correctly classified pixels / total no. of pixels

然而,在这种情况下,一些像素被标记为Void(该标签也存在于codes.txt),在计算精度时不应予以考虑。因此,我们创建了一个新的函数来计算精度,在这里我们避开了这些标签。

CNN 的工作方式是将一幅图像分解成越来越小的部分,直到只剩下一件事可以预测(下图 U-Net 架构的左边部分)。一个 U-Net 然后把它变得越来越大,它为 CNN 的每个阶段都这样做。然而,从一个小矢量构建一幅图像是一项困难的工作。因此,我们有从原始卷积层到反卷积网络的连接。

像往常一样,我们找到学习率并训练我们的模型。即使只有一半的数据集,我们也能达到 92%的准确率。

检查一些结果。

事实是真正的目标,而预测是我们的模型所标注的。

我们现在可以在完整的数据集上进行训练。

结论

这就是本文的全部内容。在本文中,我们看到了如何使用 U-net 对图像的每个像素进行颜色编码。U-nets 越来越受欢迎,因为它们在从模糊图像生成高分辨率图像等应用上的表现优于 GANs。因此,知道它们是什么以及如何使用它们是非常有用的。

完整的笔记本可以在这里找到。

如果你想了解更多关于深度学习的知识,可以看看我在这方面的系列文章:

[## 深度学习系列

我所有关于深度学习的文章的系统列表

medium.com](https://medium.com/@dipam44/deep-learning-series-30ad108fbe2b)

~快乐学习

Tensorflow 2.0 中的图像相似性检测

原文:https://towardsdatascience.com/image-similarity-detection-in-action-with-tensorflow-2-0-b8d9a78b2509?source=collection_archive---------2-----------------------

准备好为您的 web 应用程序使用管道了吗

Photo by Sharon McCutcheon on Unsplash

在这篇文章中,我将向您展示我是如何在我的'时尚价格比较' web 应用程序中实现'图像相似性检测任务的。我将使用图像相似性,根据用户搜索的内容向他们推荐视觉上相似的产品。

实现的完整源代码可以在我的 GitHub 库的中找到。

在整篇文章中,将有专门的部分来讨论以下每一个主题:

  • 如何使用 Tensorflow 2.0Tensorflow Hub 生成产品图像的【图像特征向量】
  • 如何使用Spotify/airy库和图像特征向量计算图像相似度得分。
  • 在一个 JSON 文件中存储相似性分数和相关的产品标识号,以便在我们的 web 应用程序中进行可视化搜索。

什么是“图像相似性检测”,为什么它很重要?

图像相似性检测用于量化图像的视觉和语义相似程度。

在现代应用中,重复产品检测、图像聚类、视觉搜索和推荐任务都是使用这种技术来执行的。

“搜索的未来将是图片而不是关键词。”——本·希伯尔曼,Pinterest CEO

视觉搜索的一个优点是它完全依赖于商品的外观。不需要条形码、二维码、产品名称或其他产品元数据等其他数据。”——布伦特·拉博斯基、 亚马逊网络服务

“顾客越来越多地使用社交媒体平台,如 Instagram 和 Pinterest,作为灵感的来源,因此视觉搜索有可能改变我们为家庭购物的方式。” —马克钢,数字导演,Argos

Photo by Vidar Nordli-Mathisen on Unsplash

如何使用 Tensorflow 2.0 和 Tensorflow Hub 生成“图像特征向量”

  • Tensorflow 2.0 和 Tensorflow Hub

Tensorflow 是 Google 开发的用于机器学习的端到端开源平台。它拥有工具、库和社区资源,让开发人员可以轻松构建和部署机器学习应用程序。

TensorFlow Hub 提供了许多可重用的机器学习模型。它使迁移学习变得非常容易,因为它为不同的问题领域和不同的任务(如图像分类、图像分割、姿态检测、文本嵌入、文本分类、视频生成等)提供了预训练的模型。

关于迁移学习的更多信息,你可以查看我以前的文章。

[## 浏览器中的机器学习:为自定义图像分类训练和服务 Mobilenet 模型

用 Tensorflow.js 和 Angular 在浏览器上训练基于 Mobilenet 的自定义图像分类模型

towardsdatascience.com](/training-custom-image-classification-model-on-the-browser-with-tensorflow-js-and-angular-f1796ed24934)

  • 什么是图像特征向量?

一个图像特征向量是代表整个图像的数字列表,通常用于图像相似性计算或图像分类任务。

一般来说,低级图像特征是图像的次要细节,例如线、边缘、角或点。高级特征建立在低级特征之上,以检测图像中的对象和较大的形状。

我们可以使用卷积神经网络提取这两种类型的特征:第一对卷积层将学习用于找到低级特征的过滤器,而后面的层将学习识别常见的形状和对象。

在我们的例子中,我们将使用存储在 Tensorflow Hub 中的mobilenet _ v2 _ 140 _ 224预训练的卷积神经网络来提取产品图像的高级特征。

MobilenetV2 是一个简单的神经网络架构,适用于移动和资源受限的应用程序。点击此链接可获得关于 MobilenetV2 的更多信息。

Photo by Quaid Lagan on Unsplash

在开始编码之前,需要在我们的本地计算机上安装 Tensorflow 2.0、Tensorflow Hub 和 Spotify/airy 库。

$ virtualenv --system-site-packages -p python3 ./TFvenv
$ source ./TFvenv/bin/activate$ pip install tensorflow
$ pip install tensorflow-hub
$ pip install annoy

我们来生成图像特征向量:get_image_feature_vectors.py

这个脚本的主要目的是通过读取位于本地文件夹中的图像文件来生成图像特征向量。

它有两个功能: load_img()get _ image _ feature _ vectors()

load_img(path) 获取文件名,作为函数的参数。然后加载并预处理图像,以便我们可以在我们的 MobilenetV2 CNN 模型中使用它们。

预处理步骤如下:

  • 将图像解码为 W x H x 3 形状张量,数据类型为整数。
  • 将图像大小调整为 224 x 224 x 3 形状张量,因为我们使用的 MobilenetV2 模型版本需要特定的图像大小。
  • 将张量的数据类型转换为 float 并添加一个新轴,使张量形状为 1 x 224 x 224 x 3。这正是模型所期望的输入形状。

get _ image _ feature _ vectors()函数是我提取图像特征向量的地方。你可以在下面看到,这个函数的一步一步的定义;

  • 使用 Tensorflow Hub 加载 MobilenetV2 模型
  • 遍历本地文件夹中的所有图像,并将它们传递给 load_img(path) 函数
  • 推断图像特征向量
  • 将每个特征向量保存到单独的文件中以备后用

get_image_feature_vectors.py in action

**# get_image_feature_vectors.py****#################################################
# Imports and function definitions
#################################################**
**# For running inference on the TF-Hub module with Tensorflow**
import tensorflow as tf
import tensorflow_hub as hub**# For saving 'feature vectors' into a txt file**
import numpy as np**# Glob for reading file names in a folder**
import glob
import os.path
**#################################################****#################################################
# This function:
# Loads the JPEG image at the given path
# Decodes the JPEG image to a uint8 W X H X 3 tensor
# Resizes the image to 224 x 224 x 3 tensor
# Returns the pre processed image as 224 x 224 x 3 tensor
#################################################**
def load_img(path):**# Reads the image file and returns data type of string**
 img = tf.io.read_file(path)**# Decodes the image to W x H x 3 shape tensor with type of uint8**
 img = tf.io.decode_jpeg(img, channels=3)**# Resizes the image to 224 x 224 x 3 shape tensor**
 img = tf.image.resize_with_pad(img, 224, 224)**# Converts the data type of uint8 to float32 by adding a new axis
 # img becomes 1 x 224 x 224 x 3 tensor with data type of float32
 # This is required for the mobilenet model we are using**
 img = tf.image.convert_image_dtype(img,tf.float32)[tf.newaxis, ...]

 return img**#################################################
# This function:
# Loads the mobilenet model in TF.HUB
# Makes an inference for all images stored in a local folder
# Saves each of the feature vectors in a file
#################################################**
def get_image_feature_vectors():

 **# Definition of module with using tfhub.dev**
 module_handle = "https://tfhub.dev/google/imagenet/
                  mobilenet_v2_140_224/feature_vector/4"
 **# Loads the module**
 module = hub.load(module_handle)**# Loops through all images in a local folder**
 for filename in glob.glob('/Users/erdemisbilen/Angular/
          fashionWebScraping/images_scraped/full/*.jpg'):

  print(filename)**# Loads and pre-process the image**
  img = load_img(filename)**# Calculate the image feature vector of the img**
  features = module(img)**# Remove single-dimensional entries from the 'features' array ** 
  feature_set = np.squeeze(features)

 **# Saves the image feature vectors into a file for later use**
  outfile_name = os.path.basename(filename) + ".npz"

  out_path = os.path.join('/Users/erdemisbilen/Angular/
            fashionWebScraping/images_scraped/feature-vectors/',
            outfile_name)**# Saves the 'feature_set' to a text file**
  np.savetxt(out_path, feature_set, delimiter=',')get_image_feature_vectors()

Photo by 浮萍 闪电 on Unsplash

如何使用 Spotify/airy 库计算相似度得分

  • 什么是 Spotify/骚扰库?

(AapproximateNearestNeighborOhYeah)是一个用于近似最近邻实现的开源库。

我将使用它来查找给定集合中与给定特征向量最接近(或最相似)的图像特征向量。

调优 aroy 只需要两个主要参数:树的数量*n_trees*和搜索过程中要检查的节点数量*search_k*

*n_trees*在构建期间提供,影响构建时间和索引大小。较大的值会给出更准确的结果,但索引也较大。

*search_k*在运行时提供,影响搜索性能。较大的值会给出更准确的结果,但需要更长的时间返回。

来自 Spotify/asury

让我们来计算相似度得分:cluster _ image _ feature _ vectors . py

这个脚本的主要目的是使用我们在前一章刚刚生成的图像特征向量来计算图像相似性得分。

它有两个功能: match_id(文件名)cluster()

cluster() 函数按照以下流程进行图像相似度计算:

  • 通过追加存储在本地文件夹中的所有图像特征向量来建立恼人的索引
  • 计算最近邻和相似性得分
  • 将信息保存和存储在 JSON 文件中,以备后用。

match_id(filename) 是一个帮助函数,因为我需要将图像与产品 id 进行匹配,以便在我的 web 应用程序中实现可视化产品搜索。有一个 JSON 文件,其中包含与产品图像名称匹配的所有产品 id 信息。该函数使用 JSON 文件检索给定图像文件名的产品 id 信息。

cluster_image_feature_vectors.py in action

****# cluster_image_feature_vectors.py****#################################################
# Imports and function definitions
#################################################
# Numpy for loading image feature vectors from file**
import numpy as np**# Time for measuring the process time**
import time**# Glob for reading file names in a folder**
import glob
import os.path**# json for storing data in json file**
import json**# Annoy and Scipy for similarity calculation**
from annoy import AnnoyIndex
from scipy import spatial
**#################################################****#################################################
# This function reads from 'image_data.json' file
# Looks for a specific 'filename' value
# Returns the product id when product image names are matched
# So it is used to find product id based on the product image name
#################################################**
def match_id(filename):
 with open('/Users/erdemisbilen/Angular/fashionWebScraping
 /jsonFiles/image_data.json') as json_file:for file in json_file:
   seen = json.loads(file)for line in seen:

     if filename==line['imageName']:
      print(line)
      return line['productId']
      break
**#################################################****#################################################
# This function:
# Reads all image feature vectores stored in /feature-vectors/*.npz
# Adds them all in Annoy Index
# Builds ANNOY index
# Calculates the nearest neighbors and image similarity metrics
# Stores image similarity scores with productID in a json file
#################################################** def cluster():
 start_time = time.time()

 print("---------------------------------")
 print ("Step.1 - ANNOY index generation - Started at %s" 
 %time.ctime())
 print("---------------------------------")**# Defining data structures as empty dict**
 file_index_to_file_name = {}
 file_index_to_file_vector = {}
 file_index_to_product_id = {}**# Configuring annoy parameters**
 dims = 1792
 n_nearest_neighbors = 20
 trees = 10000**# Reads all file names which stores feature vectors**
 allfiles = glob.glob('/Users/erdemisbilen/Angular
 /fashionWebScraping/images_scraped/feature-vectors/*.npz')

 t = AnnoyIndex(dims, metric='angular')for file_index, i in enumerate(allfiles):**# Reads feature vectors and assigns them into the file_vector**
  file_vector = np.loadtxt(i)**# Assigns file_name, feature_vectors and corresponding product_id**
  file_name = os.path.basename(i).split('.')[0]
  file_index_to_file_name[file_index] = file_name
  file_index_to_file_vector[file_index] = file_vector
  file_index_to_product_id[file_index] = match_id(file_name)**# Adds image feature vectors into annoy index**
  t.add_item(file_index, file_vector)print("---------------------------------")
  print("Annoy index     : %s" %file_index)
  print("Image file name : %s" %file_name)
  print("Product id      : %s" 
  %file_index_to_product_id[file_index])
  print("--- %.2f minutes passed ---------" % ((time.time() -
  start_time)/60))**# Builds annoy index**
 t.build(trees)print ("Step.1 - ANNOY index generation - Finished")
 print ("Step.2 - Similarity score calculation - Started ")named_nearest_neighbors = []**# Loops through all indexed items**
 for i in file_index_to_file_name.keys():

 **# Assigns master file_name, image feature vectors 
  # and product id values**
  master_file_name = file_index_to_file_name[i]
  master_vector = file_index_to_file_vector[i]
  master_product_id = file_index_to_product_id[i]**# Calculates the nearest neighbors of the master item**
  nearest_neighbors = t.get_nns_by_item(i, n_nearest_neighbors)**# Loops through the nearest neighbors of the master item**
  for j in nearest_neighbors:

   print(j)**# Assigns file_name, image feature vectors and 
   # product id values of the similar item** neighbor_file_name = file_index_to_file_name[j]
   neighbor_file_vector = file_index_to_file_vector[j]
   neighbor_product_id = file_index_to_product_id[j]**# Calculates the similarity score of the similar item**
   similarity = 1 - spatial.distance.cosine(master_vector,
   neighbor_file_vector)rounded_similarity = int((similarity * 10000)) / 10000.0**# Appends master product id with the similarity score
   # and the product id of the similar items** named_nearest_neighbors.append({
     'similarity': rounded_similarity,
     'master_pi': master_product_id,
     'similar_pi': neighbor_product_id})print("---------------------------------")
 print("Similarity index       : %s" %i)
 print("Master Image file name : %s" %file_index_to_file_name[i])
 print("Nearest Neighbors.     : %s" %nearest_neighbors)
 print("--- %.2f minutes passed ---------" % ((time.time() -
 start_time)/60))print ("Step.2 - Similarity score calculation - Finished ")**# Writes the 'named_nearest_neighbors' to a json file**
 with open('nearest_neighbors.json', 'w') as out:
 json.dump(named_nearest_neighbors, out)print ("Step.3 - Data stored in 'nearest_neighbors.json' file ")
 print("--- Prosess completed in %.2f minutes ---------" %
 ((time.time() - start_time)/60))cluster()**

如您所见,我将每个产品图片的最高 20 个相似性分数保存在一个 JSON 文件中,并带有匹配的产品 id 信息。这是因为我不知道如何在客户端进行相似性计算来消除所需的工作量。

有了存储在 JSON 文件中的相似性得分,我可以轻松地填充 Elasticsearch 集群,或者填充数据库,以便在我的价格比较 web 应用程序的浏览器上实现近乎实时的可视化搜索体验。

为了开发这样的应用程序,web 抓取在开发和维护日常产品数据集方面起着重要的作用。如果你对这个主题感兴趣,可以看看我下面的相关文章。

**** [## 使用 Python 和 Scrapy 在 30 分钟内抓取 10 家在线商店的网页

获取启动应用程序项目所需的源数据

towardsdatascience.com](/web-scraping-of-10-online-shops-in-30-minutes-with-python-and-scrapy-a7f66e42446d)****

结论

Fashion Search Web Application by Erdem Isbilen — Visual Search Results

正如你在上面所看到的,MobileNetV2 和 Annoy 在寻找视觉上相似的产品方面做得非常好。

这种实现方式的一个缺点是它只能在整个图像级别工作。如果图像的背景不同,即使物体相似,它也不会提供好的结果。

该应用程序可以进一步改进,以实现类似于 PinterestHouzz 上的对象级相似性搜索。

使用三重损失的图像相似性

原文:https://towardsdatascience.com/image-similarity-using-triplet-loss-3744c0f67973?source=collection_archive---------2-----------------------

你训练过机器学习模型解决分类问题吗?如果是,班级数量是多少?也许 10 到 200?还是 1000?班级数量在百万量级的情况下,同样的模式是否行得通?如果答案是否定的,这篇文章是给你的。

行业中的几个真实世界的应用,从人脸识别到对象检测,从 POS 标记到 NLP 中的文档排序,都被公式化为多类分类问题。由于网络的稀疏性,当输出层中的类别数量过多时,典型的基于 softmax 的深度网络将不会有所帮助。相反,这种问题可以用不同的方式来表述。想法是以这样的方式学习数据点的分布式嵌入表示,即在高维向量空间中,上下文相似的数据点被投影在附近的区域中,而不相似的数据点被投影在彼此远离的地方。

三重损失结构通过相似性和相异性的概念帮助我们学习分布式嵌入。这是一种神经网络架构,其中多个并行网络被训练,彼此共享权重。在预测期间,输入数据通过一个网络来计算输入数据的分布式嵌入表示。

在本文中,我们将讨论如何训练三重态损失以及如何在预测过程中使用训练好的模型。

培训数据准备:

对于三元组丢失,目标是构建三元组,由锚图像、正图像(与锚图像相似)和负图像(与锚图像不同)组成。有不同的方法来定义相似和不相似的图像。如果您的数据集具有多个作为目标类的标注,则同一类的图像可被视为相似,而不同类的图像可被视为不相似。

我有一个包含 6 个不同类别的地质图像数据集。为了生成三元组,首先,随机选择 2 个类。然后,从一个类中选择两个图像,从另一个类中选择一个图像。现在,相同类别的图像被认为是相似的,所以它们中的一个被用作锚,而另一个是正面的,而来自另一个类别的图像被认为是负面的图像。

同样,对于每一批,选择一组 n 个三联体。

损失函数:

三重态损失的成本函数如下:

L(a,p,n) = max(0,D(a,p) — D(a,n) + margin)

其中 D(x,y):x 和 y 的学习向量表示之间的距离。可以使用 L2 距离或(1 -余弦相似度)作为距离度量。该功能的目的是保持锚点和正极之间的距离小于锚点和负极之间的距离。

模型架构:

想法是有 3 个相同的网络具有相同的神经网络架构,它们应该共享权重。我重复一遍,所有的网络应该共享潜在的权重向量。【请参考 github 知识库,了解 tensorflow 实现中如何在网络间共享权重】。深度网络的最后一层具有 D 个神经元,用于学习 D 维向量表示。

锚、正和负图像通过它们各自的网络传递,并且在反向传播期间,使用共享架构更新权重向量。在预测期间,任何一个网络都用于计算输入数据的矢量表示。

Triplet Loss architecture

下面是实现的张量板可视化。

tensorboard visualization of the computation graph

模型学习:

该模型不仅学会了同时为不同的类制定聚类,而且还成功地将相似的图像投影到它们的邻域中。在分类架构的情况下,该模型试图学习一对类之间的决策边界,但是该模型不考虑类内相似和不相似图像之间的完整性。

为了了解训练模型的学习有多好,我随机选择了 20%的图像,并在对高维向量空间表示进行降维后,在 2D 空间中绘制这些图像。

Plot of data points in 2D space

成绩:

以下是模型执行情况的快照。我已经从测试图像的语料库中随机选择了 20 个查询图像。并且对于每个查询图像,绘制出在高维向量空间表示上在余弦相似性方面相似的前 10 个最可能图像。

结论:

三重损耗架构帮助我们解决了几个类数量非常多的问题。假设你想建立一个人脸识别系统,你有一个 100 万张人脸的数据库,预先计算每张人脸的三维向量。现在,给定一张人脸图像(作为测试图像),使用所有一百万个预先计算的向量计算余弦相似度,无论哪张图像具有最高的相似度,都将是被选中的候选图像。如果测试图像只是噪声,则最高相似度将非常低,并且将低于阈值参数。

计算语料库中每个图像的余弦相似度在计算上是非常低效的。同时,它可能需要大量的物理内存来存储语料库图像的矢量表示。

faiss 是 facebook-research 开发的一个开源框架,它帮助建立了一个基于可用内存的语料库索引,并提供了几种方法来相对更快地找到相似的图像。

Git 存储库:

克隆 git 库:https://github.com/sanku-lib/triplet_loss.git

延伸阅读:

用 PyTorch 中的暹罗网络实现基于内容的图像检索

参考文献:

[1]https://www.cs.cmu.edu/~rsalakhu/papers/oneshot1.pdf

https://arxiv.org/pdf/1503.03832.pdf

[3]https://arxiv.org/pdf/1702.08734.pdf

图像到图像的翻译

原文:https://towardsdatascience.com/image-to-image-translation-69c10c18f6ff?source=collection_archive---------17-----------------------

图像到图像的翻译是一类视觉和图形问题,其目标是学习输入图像和输出图像之间的映射。它的应用范围很广,如收藏风格转移、物体变形、季节转移、照片增强等。

CycleGAN

Unpaired Image-to-Image Translation Using Cycle-Consistent Adversarial Networks(ICCV 2017)

论文/ 项目/ 语义学者

作者提出了一种在缺少成对例子的情况下学习将图像从源域 X 翻译到目标域 Y 的方法。目标是学习映射 G : X → Y,使得来自 G(X)的图像分布与使用对抗损失的分布 Y 不可区分。因为这种映射是高度欠约束的,所以我们将其与逆映射 F : Y → X 耦合,并引入循环一致性损失来强制 F(G(X)) ≈ X(反之亦然)。

成对的训练数据(左)由一一对应的训练实例组成。不成对的训练集没有这样的对应关系(图取自论文)

图取自报纸。

该模型包含两个映射函数 G : X → Y 和 F : Y → X,以及相关的对抗性鉴别器 DY 和 DX。DY 鼓励 G 将 X 转换为与域 Y 不可区分的输出,反之亦然。为了进一步规范映射,他们引入了两个“循环一致性损失”,这两个损失捕捉了这样的直觉:如果我们从一个域转换到另一个域,然后再转换回来,我们应该到达我们开始的地方。

斯塔根

Unified Generative Adversarial Networks for Multi-Domain Image-to-Image Translation(CVPR 2018)

论文/ 代码/ 语义学者

现有的图像到图像的转换方法在处理多于两个域时具有有限的可扩展性和鲁棒性,因为对于每对图像域应该独立地建立不同的模型。StarGAN 是一种新颖且可扩展的方法,仅使用一个模型就可以为多个领域执行图像到图像的翻译。

跨域模型和我们提出的模型 StarGAN 之间的比较。(a)为了处理多个域,应该为每对图像域建立跨域模型。(b) StarGAN 能够使用单个生成器学习多个域之间的映射。图中显示了连接多个域的星型拓扑。(图取自论文)

StarGAN 概述,由两个模块组成,一个鉴别器 D 和一个生成器 G. (a) D 学习区分真假图像,并将真实图像分类到其对应的域。(b) G 接受图像和目标域标签作为输入,并生成假图像。目标域标签被空间复制并与输入图像连接。g 尝试从给定原始域标签的伪图像重建原始图像。(d) G 试图生成与真实图像无法区分的图像,并被 d 归类为目标域

原载于amberer . git lab . io

基于 CycleGAN 模型的图像到图像翻译

原文:https://towardsdatascience.com/image-to-image-translation-using-cyclegan-model-d58cfff04755?source=collection_archive---------14-----------------------

一种用于图像到图像翻译的无监督方法。

Photo by Tim Mossholder on Unsplash

如果你对 GANs 领域完全陌生,我建议你在开始写这篇文章之前先看看我以前的文章。

[## 基于 DCGAN 模型的人脸生成器

概观

towardsdatascience.com](/fake-face-generator-using-dcgan-model-ae9322ccfd65)

即使你不熟悉 GANs,我仍然建议你通读这篇文章,因为我们需要所有我们在上一篇文章中学到的基本概念来理解这篇文章。也就是说,让我们从这篇文章开始。

循环生成对抗网络 (CycleGAN) ,是一种训练深度卷积网络用于图像到图像翻译任务的方法。与其他用于图像转换任务的 GAN s 模型不同,C ycleGAN 使用无监督方法学习一个图像域和另一个图像域之间的映射。例如,如果我们对将马的图像转换成斑马的图像感兴趣,我们不需要将马物理转换成斑马的训练数据集。 CycleGAN 做到这一点的方法是通过训练生成器网络来学习从域 X 到看起来像是来自域 Y 的图像的映射(反之亦然)

当你阅读这篇文章时,你会对它是如何做到的有更深的理解。所以让我们开始吧…

CycleGAN

CycleGAN architecture. Image from https://modelzoo.co/model/mnist-svhn-transfer

出于直觉,我们会参考上面的图像。

对于成对的图像集,我们可以直接创建一个 GAN 来借助 Pix2Pix 学习从 x 到 y 的映射。你可以在这里阅读更多关于 Pix2Pix Networks 的内容。

但是准备成对的数据集既费时又困难。我的意思是,我们需要一幅斑马的图像,它的位置和马的位置一样,或者有着相同的背景,这样我们才能学会绘制地图。

为了解决这个问题,CycleGAN 架构应运而生。CycleGAN 能够学习从一个域 X 到另一个域 Y 的映射,而不必寻找完全匹配的训练对!我们来看看 CycleGAN 是怎么做到的。

假设我们有一组来自域 X 的图像和一组来自域 y 的不成对的图像,我们希望能够将一组图像转换成另一组图像。为此,我们定义了一个映射 G (G: X- > Y) ,它尽最大努力将 X 映射到 Y。但是对于不成对的数据,我们不再能够查看真实和虚假的数据对。但是我们知道我们可以改变我们的模型来产生一个属于目标领域的输出。

因此,当你推送一匹马的图像时,我们可以训练一个生成器生成逼真的斑马图像。但问题是,我们不能强迫生成器的输出对应于它的输入(在上面的图像中,第一个转换是正确的图像到图像的转换)。这导致了一个被称为模式崩溃的问题,其中一个模型可能将来自域 X 的多个输入映射到来自域 Y 的同一个输出。在这种情况下,给定一匹输入马(域 X) ,我们所知道的就是输出应该看起来像斑马(域 Y) 。但是为了在相应的目标域中获得输入的正确映射,我们引入了一个额外的映射作为逆映射 G' (G': Y- > X) ,它试图将 Y 映射到 X。这被称为循环一致性约束

可以这样想,如果我们将一幅马的图像(域 X) 翻译成一幅斑马的图像(域 Y) ,然后我们再从斑马(域 Y)翻译回一匹马(域 X),我们应该回到开始时的马的图像。

一个完整的翻译周期应该会让你回到开始时的图像。在从域 X 到 Y 的图像变换的情况下,如果满足以下条件,我们说图像从域 X 到域 Y 的变换是正确的。

condition -1

在循环一致性约束的帮助下,CycleGAN 确保模型学习到从域 X 到域 y 的正确映射。

图像到图像翻译任务

下面的任务被分解成一系列小任务,从加载和可视化数据到训练模型

可视化数据集

具体来说,我们将看一组在夏季或冬季拍摄的约塞米蒂国家公园的照片。季节是我们的两个领域!

Images from the summer season domain.

Images from the winter season domain.

一般来说,你可以看到夏天的图像比冬天的图像更亮更绿。冬天包含了像雪和多云图像这样的东西。在这个数据集中,我们的主要目标是训练一个生成器,学习将图像从夏天转换到冬天,反之亦然。这些图像不包含标签,被称为不成对的训练数据。但是通过使用 CycleGAN,我们可以使用无监督的方法学习从一个图像域到另一个图像域的映射。

你可以点击这里下载以下数据。

定义模型

CycleGAN 包括两个鉴别器( D_xD_y )和两个发生器( G_xtoyG_ytox )。

  • D_x —将来自域 X 的训练图像识别为真实图像,将从域 Y 到域 X 的翻译图像识别为伪造图像。
  • D_y —将来自域 X 的训练图像识别为真实图像,将从域 Y 到域 X 的翻译图像识别为伪造图像。
  • G_xtoy —将图像从域 X 转换到域 y。
  • G_ytox —将图像从域 Y 转换到域 x。

鉴别器

在这个 CycleGAN 中,鉴别器 D_xD_y 是卷积神经网络,它们看到一幅图像并试图将其分类为真实或伪造。在这种情况下,real 由接近 1 的输出表示,而 fake 由接近 0 的输出表示。鉴别器具有以下架构:

# helper conv function
def conv(in_channels, out_channels, kernel_size, stride=2, padding=1, batch_norm=True):
    """Creates a convolutional layer, with optional batch normalization.
    """
    layers = []
    conv_layer = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, 
                           kernel_size=kernel_size, stride=stride, padding=padding, bias=False)

    layers.append(conv_layer)

    if batch_norm:
        layers.append(nn.BatchNorm2d(out_channels))
    return nn.Sequential(*layers)

class Discriminator(nn.Module):

    def __init__(self, conv_dim=64):
        super(Discriminator, self).__init__()

        # Define all convolutional layers
        # Should accept an RGB image as input and output a single value
        self.layer_1 = conv(3,conv_dim,4,batch_norm = False)
        self.layer_2 = conv(conv_dim,conv_dim*2,4)
        self.layer_3 = conv(conv_dim*2,conv_dim*4,4)
        self.layer_4 = conv(conv_dim*4,conv_dim*8,4)
        self.layer_5 = conv(conv_dim*8,1,4,1,batch_norm = False)

    def forward(self, x):
        # define feedforward behavior
        x = F.relu(self.layer_1(x))
        x = F.relu(self.layer_2(x))
        x = F.relu(self.layer_3(x))
        x = F.relu(self.layer_4(x))

        x = self.layer_5(x)
        return x

解释

  • 以下架构由输出单个 logit 的五个卷积层组成。这个逻辑定义了图像是否真实。这种体系结构中没有完全连接的层。
  • 除了第一层和最后一层,所有卷积层之后都是批量归一化(在 conv 帮助函数中定义)
  • 对于隐藏单元,使用 ReLU 激活功能。
  • 每次卷积后特征图的数量基于参数conv _ 尺寸(在我的实现中 conv _ 尺寸= 64)

D_x 和 D_y 的架构都是一样的,所以我们只需要定义一个类,后面实例化两个鉴别器。

剩余块和剩余函数

在定义生成器架构时,我们将在我们的架构中使用称为 Resnet 块剩余函数的东西。使用 Resnet 块和剩余函数的思想如下:

残留块

残差块连接编码器和解码器。这种架构背后的动机如下:深度神经网络可能非常难以训练,因为它们更可能具有爆炸或消失的梯度,因此难以达到收敛;批处理规范化对此有所帮助。

这个问题的一个解决方案是使用 Resnet 块,允许我们学习所谓的剩余函数,因为它们被应用于层输入。

剩余功能

当我们创建深度学习模型时,该模型(应用了激活的若干层)负责学习从输入 x 到输出 y 的映射 M。

M(x) = y

我们可以定义一个剩余函数,而不是学习从 x 到 y 的直接映射。

F(x) = M(x)-x

这着眼于应用于 x 的映射与原始输入 x 之间的差异。F(x)通常是两个卷积层+归一化层以及其间的 ReLU。这些卷积层应该具有与输出相同数量的输入。这种映射可以写成如下形式:剩余函数和输入 x 的函数。

M(x) = F(x) + x

你可以在这里阅读更多关于深度剩余学习。下面是实现 Residual Block 的代码片段。

class ResidualBlock(nn.Module):
    """Defines a residual block.
       This adds an input x to a convolutional layer (applied to x) with the same size input and output.
       These blocks allow a model to learn an effective transformation from one domain to another.
    """
    def __init__(self, conv_dim):
        super(ResidualBlock, self).__init__()
        # conv_dim = number of inputs  

        # define two convolutional layers + batch normalization that will act as our residual function, F(x)
        # layers should have the same shape input as output; I suggest a kernel_size of 3
        self.layer_1 = conv(conv_dim,conv_dim,3,1,1,batch_norm = True)
        self.layer_2 = conv(conv_dim,conv_dim,3,1,1,batch_norm = True)

    def forward(self, x):
        # apply a ReLu activation the outputs of the first layer
        # return a summed output, x + resnet_block(x)
        out_1 = F.relu(self.layer_1(x))
        out_2 = x + self.layer_2(out_1)

        return out_2

发电机

生成器 G_xtoy 和 G_ytox 由编码器、将图像转换成小特征表示的 conv 网和解码器、负责将特征表示转换成变换图像的转置 conv 网组成。下面是实现生成器的代码片段。

def deconv(in_channels, out_channels, kernel_size, stride=2, padding=1, batch_norm=True):
    """Creates a transpose convolutional layer, with optional batch normalization.
    """
    layers = []
    # append transpose conv layer
    layers.append(nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride, padding, bias=False))
    # optional batch norm layer
    if batch_norm:
        layers.append(nn.BatchNorm2d(out_channels))
    return nn.Sequential(*layers)

class CycleGenerator(nn.Module):

    def __init__(self, conv_dim=64, n_res_blocks=6):
        super(CycleGenerator, self).__init__()

        # 1\. Define the encoder part of the generator
        self.layer_1 = conv(3,conv_dim,4)
        self.layer_2 = conv(conv_dim,conv_dim*2,4)
        self.layer_3 = conv(conv_dim*2,conv_dim*4,4)
        # 2\. Define the resnet part of the generator
        layers = []
        for n in range(n_res_blocks):
            layers.append(ResidualBlock(conv_dim*4))
        self.res_blocks = nn.Sequential(*layers)
        # 3\. Define the decoder part of the generator
        self.layer_4 = deconv(conv_dim*4,conv_dim*2,4)
        self.layer_5 = deconv(conv_dim*2,conv_dim,4)
        self.layer_6 = deconv(conv_dim,3,4,batch_norm = False)

    def forward(self, x):
        """Given an image x, returns a transformed image."""
        # define feedforward behavior, applying activations as necessary

        out = F.relu(self.layer_1(x))
        out = F.relu(self.layer_2(out))
        out = F.relu(self.layer_3(out))

        out = self.res_blocks(out)

        out = F.relu(self.layer_4(out))
        out = F.relu(self.layer_5(out))
        out = F.tanh(self.layer_6(out))

        return out

解说

  • 下面的架构由编码器的三个卷积层和解码器的三个转置卷积层组成,它们都使用一系列残差块(在我们的例子中为 6)连接。
  • 所有卷积层之后是批归一化
  • 除了最后一层,所有转置卷积层之后都是批量归一化
  • 对于隐藏单元,使用 ReLU 激活函数,除了最后一层,我们使用 tanh 激活函数,这是基于我们在之前的文章 (训练 DCGAN 的技巧)中的讨论。
  • 编码器和解码器中每次卷积后的特征图数量基于参数 conv_dim

G_xtoy 和 G_ytox 的架构都是一样的,所以我们只需要定义一个类,后面实例化两个生成器。

培训过程

训练过程包括定义损失函数、选择优化器以及最后训练模型。

鉴频器和发电机损耗

我们已经看到,常规 GANs 将鉴别器视为具有 sigmoid 交叉熵损失函数的分类器。然而,这种损失函数可能导致学习过程中的消失梯度问题。为了解决这个问题,我们将对鉴别器使用最小二乘损失函数。这种结构通常被称为最小二乘 GANs,你可以从 LSGANs 的原始论文中读到更多关于它们的内容。

鉴频器损耗

鉴别器损耗将是鉴别器的输出(给定图像)和目标值(0 或 1)之间的均方误差,这取决于它应该将该图像分类为假还是真。例如,对于一个真实的图像 x,我们可以通过观察它与使用均方误差将 x 识别为真实图像的接近程度来训练 D_x:

out = D_x(x)

real_error = torch.mean((out-1))(用于 Pytorch)

发电机损耗

在这种情况下,我们将生成看起来像是属于域 X 但却基于域 Y 的图像的假图像,反之亦然。我们将通过观察应用于这些伪图像的鉴频器的输出来计算这些生成图像的真实损失。

除了对抗性损失,发电机损失项将包括循环一致性损失。这种损失是重建图像与原始图像相比有多好的量度。例如,我们有一个假的生成图像 x^和一个真实的图像 y,在 g _ xtoy(g_xtoy(x^)= y^】的帮助下,我们可以从 x^生成 y^。这里,周期一致性损失将是原始图像和重建图像之间的绝对差异。

Cycle consistency loss. Image from https://ssnl.github.io/better_cycles/report.pdf

下面是定义损失的代码片段。

def real_mse_loss(D_out):
    # how close is the produced output from being "real"?
    return torch.mean((D_out - 1)**2)

def fake_mse_loss(D_out):
    # how close is the produced output from being "fake"?
    return torch.mean(D_out**2)

def cycle_consistency_loss(real_im, reconstructed_im, lambda_weight):
    # calculate reconstruction loss 
    # return weighted loss
    loss = torch.mean(torch.abs(real_im - reconstructed_im))
    return loss*lambda_weight

在周期一致性损失中,lambda 项是一个权重参数,它将对批次中的平均绝对误差进行加权。建议大家看一下 原文,CycleGAN 论文 得到一个 lambda_weight 的起始值。

【计算机】优化程序

对于 CycleGAN,我们为生成器 (G_xtoy 和 G_ytox) 和 D_x 和 D_y 定义了三个优化器。所有数值超参数均选自原始 CycleGAN 文件

# hyperparams for Adam optimizers
lr= 0.0002
beta1= 0.5
beta2= 0.999

g_params = list(G_XtoY.parameters()) + list(G_YtoX.parameters())  # Get generator parameters

# Create optimizers for the generators and discriminators
g_optimizer = optim.Adam(g_params, lr, [beta1, beta2])
d_x_optimizer = optim.Adam(D_X.parameters(), lr, [beta1, beta2])
d_y_optimizer = optim.Adam(D_Y.parameters(), lr, [beta1, beta2])

培训

当 CycleGAN 进行训练并看到来自集合 X 和 Y 的一批真实图像时,它通过执行以下步骤进行训练:

对于鉴别器:

  • 计算实际图像上的鉴别器 D_x 损失。
  • 在 G_ytox 的帮助下,使用集合 Y 中的图像生成伪图像,然后计算 D_x 的伪损失。
  • 计算总损失并进行反向传播和优化。对 D_y 做同样的事情,你的域就转换了。

对于发电机:

  • 根据域 Y 中的实像生成看起来像域 X 的假像,然后根据 D_x 如何响应假像 X 计算发电机损耗。
  • 基于步骤 1 中的伪 x 射线图像生成重建图像 Y^图像。
  • 计算重建和真实 Y 图像的周期一致性损失。
  • 重复步骤 1 至 4,仅交换域,添加所有发电机损耗,并执行反向传播和优化。

下面是这样做的代码片段。

def training_loop(dataloader_X, dataloader_Y, test_dataloader_X, test_dataloader_Y, 
                  n_epochs=1000):

    print_every=10

    # keep track of losses over time
    losses = []

    test_iter_X = iter(test_dataloader_X)
    test_iter_Y = iter(test_dataloader_Y)

    # Get some fixed data from domains X and Y for sampling. These are images that are held
    # constant throughout training, that allow us to inspect the model's performance.
    fixed_X = test_iter_X.next()[0]
    fixed_Y = test_iter_Y.next()[0]
    fixed_X = scale(fixed_X) # make sure to scale to a range -1 to 1
    fixed_Y = scale(fixed_Y)

    # batches per epoch
    iter_X = iter(dataloader_X)
    iter_Y = iter(dataloader_Y)
    batches_per_epoch = min(len(iter_X), len(iter_Y))

    for epoch in range(1, n_epochs+1):

        # Reset iterators for each epoch
        if epoch % batches_per_epoch == 0:
            iter_X = iter(dataloader_X)
            iter_Y = iter(dataloader_Y)

        images_X, _ = iter_X.next()
        images_X = scale(images_X) # make sure to scale to a range -1 to 1

        images_Y, _ = iter_Y.next()
        images_Y = scale(images_Y)

        # move images to GPU if available (otherwise stay on CPU)
        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        images_X = images_X.to(device)
        images_Y = images_Y.to(device)

        # ============================================
        #            TRAIN THE DISCRIMINATORS
        # ============================================

        ##   First: D_X, real and fake loss components   ##

        # 1\. Compute the discriminator losses on real images
        d_x_optimizer.zero_grad()
        real_D_loss = real_mse_loss(D_X(images_X))
        # 3\. Compute the fake loss for D_X
        fake_D_loss = fake_mse_loss(D_X(G_YtoX(images_Y)))
        # 4\. Compute the total loss and perform backprop
        d_x_loss = real_D_loss + fake_D_loss
        d_x_loss.backward()
        d_x_optimizer.step()

        ##   Second: D_Y, real and fake loss components   ##
        d_y_optimizer.zero_grad()
        real_D_y_loss = real_mse_loss(D_Y(images_Y))

        fake_D_y_loss = fake_mse_loss(D_Y(G_XtoY(images_X)))

        d_y_loss = real_D_y_loss + fake_D_y_loss
        d_y_loss.backward()
        d_y_optimizer.step()

        # =========================================
        #            TRAIN THE GENERATORS
        # =========================================

        ##    First: generate fake X images and reconstructed Y images    ##
        g_optimizer.zero_grad()
        # 1\. Generate fake images that look like domain X based on real images in domain Y
        out_1 = G_YtoX(images_Y)
        # 2\. Compute the generator loss based on domain X
        loss_1 = real_mse_loss(D_X(out_1))
        # 3\. Create a reconstructed y
        out_2 = G_XtoY(out_1)
        # 4\. Compute the cycle consistency loss (the reconstruction loss)
        loss_2 = cycle_consistency_loss(real_im = images_Y, reconstructed_im = out_2, lambda_weight=10)

        ##    Second: generate fake Y images and reconstructed X images    ##
        out_3 = G_XtoY(images_X)
        # 5\. Add up all generator and reconstructed losses and perform backprop
        loss_3 = real_mse_loss(D_Y(out_3))
        out_4 = G_YtoX(out_3)
        loss_4 =  cycle_consistency_loss(real_im = images_X, reconstructed_im = out_4, lambda_weight=10)

        g_total_loss = loss_1 + loss_2 + loss_3 + loss_4
        g_total_loss.backward()
        g_optimizer.step()

        # Print the log info
        if epoch % print_every == 0:
            # append real and fake discriminator losses and the generator loss
            losses.append((d_x_loss.item(), d_y_loss.item(), g_total_loss.item()))
            print('Epoch [{:5d}/{:5d}] | d_X_loss: {:6.4f} | d_Y_loss: {:6.4f} | g_total_loss: {:6.4f}'.format(
                    epoch, n_epochs, d_x_loss.item(), d_y_loss.item(), g_total_loss.item()))

        sample_every=100
        # Save the generated samples
        if epoch % sample_every == 0:
            G_YtoX.eval() # set generators to eval mode for sample generation
            G_XtoY.eval()
            save_samples(epoch, fixed_Y, fixed_X, G_YtoX, G_XtoY, batch_size=16)
            G_YtoX.train()
            G_XtoY.train()

        # uncomment these lines, if you want to save your model
#         checkpoint_every=1000
#         # Save the model parameters
#         if epoch % checkpoint_every == 0:
#             checkpoint(epoch, G_XtoY, G_YtoX, D_X, D_Y)

    return losses

使用 GPU 进行了超过 5000 个时期的训练,这就是为什么我必须将我的模型和输入从 CPU 移动到 GPU。

结果

  • 以下是在每个时期之后记录的发生器和鉴别器的训练损失的曲线图。

我们可以观察到,发生器开始时有很高的误差,但随着时间的推移,它开始产生像样的图像转换,从而有助于降低误差。

两种鉴频器误差都显示出非常小的误差波动。但是到 5000 个纪元结束时,我们可以看到两个鉴别器误差都减少了,从而迫使生成器进行更真实的图像转换。

  • 可视化样品。

经过 100 次迭代之后—

Translation from X to Y after 100 iterations

Translation from Y to X after 100 iterations

经过 5000 次迭代后—

Translation from X to Y after 5000 iterations

Translation from Y to X after 5000 iterations

我们可以观察到 CycleGAN 模型产生低分辨率图像,这是一个正在进行的研究领域,您可以通过点击此处了解更多关于使用多个生成器的高分辨率公式。

这种型号很难精确匹配颜色。这是因为,如果 G_xtoy 和 G_ytox 可能会改变图像的色调;周期一致性损失可能不受影响,并且仍然很小。你可以选择引入一个新的、基于颜色的损失项来比较 G_ytox(y)和 y,以及 G_xtoy(x)和 x,但这变成了一种监督学习方法。也就是说,CycleGAN 能够做出令人满意的翻译。

如果你想保持联系,你可以在 LinkedIn 上找到我。

参考

查看我关于这篇文章的 Github 报告。

使用 Tesseract.js 进行图像到文本的 OCR

原文:https://towardsdatascience.com/image-to-text-ocr-with-tesseract-js-3540b420e0e7?source=collection_archive---------3-----------------------

使用 javascript 从图像中提取文本

Photo by Franck V. on Unsplash

您是否希望从图像、照片中提取文本?是不是刚拍了一张讲义的照片,想转换成文字?然后你需要一个可以通过 OCR(光学字符识别)识别文本的应用程序。

今天,我将实现你期待已久的愿望,用强大的 JavaScript 库 Tesseract.js 构建一个图像到文本的转换器

点击下面的链接亲自尝试一下:

[## 使用 Tesseract.js - Benson 技术的图像到文本 OCR

您是否希望从图像、照片中提取文本?今天,我要满足你的愿望,建立一个图像文本…

bensonruan.com](https://bensonruan.com/image-to-text-ocr-with-tesseract-js/)

履行

你是不是觉得自己发现了宝藏?我们可以得到一本书的扫描图像,使用 OCR 技术读取图像,并以我们可以在机器上使用的格式输出文本。这可以极大地提高我们的生产率,并避免重复的手工输入。

在本教程中,我将向您展示如何使用 Tesseract.js 构建 OCR web 应用程序。让我们直接进入代码。

#步骤 1:包含 tesseract.js

首先,我们需要包含 JavaScript 库 tesseract.js,在你的 HTML5 页面中包含 Tesseract.js 最简单的方法就是使用 CDN。因此,将以下内容添加到您的网页的<head>中。

<html>
  <head>
    <script src='[https://unpkg.com/tesseract.js@v2.0.0-alpha.13/dist/tesseract.min.js](https://unpkg.com/tesseract.js@v2.0.0-alpha.13/dist/tesseract.min.js)'></script>
  </head>

如果您使用的是 npm,也可以通过运行下面的命令来安装它

npm install tesseract.js@next

在的末尾,包含主 javascript 文件 tesseract-ocr.js

 <script src="js/tesseract-ocr.js"></script>
  </body>
</html>

#步骤 2:设置 html 元素

接下来我们需要做的是添加下面的 html 元素

  • 语言选择器
  • 图像文件选择器
  • 所选图像的缩略图预览
  • 处理后结果的占位符

#步骤 3:初始化并运行 Tesseract

此外,我们将初始化一个TesseractWorker。然后利用recognize功能。这个函数异步运行并返回一个TesseractJob对象。

您可以在一个回调函数中获得文本结果,该函数可以使用then()方法添加。此外,使用progress()方法添加一个回调来监控 OCR 操作的状态和进度。

#第 4 步:显示进度和结果

最后,让我们探索返回的TesseractJob对象,并使用它来显示结果。

一旦结果返回,它包含一个置信度,从图像中提取的文本。在单词数组中,还包括单词在图像内部的位置。现在我们使用下面的函数progressUpdate将它显示给用户。

代码差不多就是这样了!选择你自己的图片和一些文字,看着结果滚滚而来!

GitHub 知识库

您可以通过下面的链接下载上述演示的完整代码:

[## 本森阮/宇宙魔方光学字符识别

使用 javascript 库 tesseract.js 在浏览器中从图像中提取文本…

github.com](https://github.com/bensonruan/Tesseract-OCR)

Photo by Temple Cerulean on Unsplash

结论

毕竟,我已经用不同的图像做了一些实验,并且发现了 Tesseract.js 的一些优点和缺点。

优点:

  • 它支持多种语言,点击这里查看支持语言的完整列表。
  • 在正常字体和清晰背景的情况下,精确度相当高

缺点:

  • 它在嘈杂的背景下不太好用
  • 它被一些自定义字体弄糊涂了

但是,我仍然认为它是一个伟大的 JavaScript 库。它为浏览器带来了 OCR 的强大功能,并为开发人员打开了一扇机会之门。

ImageAI:动态物体识别

原文:https://towardsdatascience.com/imageai-object-recognition-on-the-fly-815c7741928d?source=collection_archive---------15-----------------------

将物体识别快速连接到你的应用程序

如果计算机有眼睛,它能识别什么?

区分猫和狗会很好,但更好的是识别开放图像数据集中的所有 7870 个对象!这里有一个练习。向窗外看,数一数你能认出多少物体。物体识别是将人类的这部分能力引入计算机。它实现了计算机以前很难实现的广泛应用——从无人驾驶汽车到高级安全。你的脸书人脸识别到交通管理。

计算机视觉已经真正从对整个图像进行分类发展到识别图像中的单个物体。这就是“这是一张有车辆的道路照片”和“这张照片上有 12-15 辆汽车和 4-6 辆摩托车”的区别。这是一种算法,它给出了足够的上下文来声明“中等流量”。

听起来不错。我该如何报名?

许多大型云提供商都有现成的 API 来做这件事。有谷歌微软亚马逊的实现。如果你有预算,那么只需将它插入你的应用程序,你就有了而不是热狗应用程序。但是我想把重点放在一些你可能会弄脏手的东西上。这些 API 大多由深度学习模型驱动,在对象识别方面,YOLO 是你的人。我推荐看看他们为 YOLO v3 的实现所做的惊人的开场白:

我们向 YOLO 展示一些更新!我们做了一些设计上的小改动,让它变得更好。我们还训练了这个新的网络,它非常棒。比上次大一点,但是更准确。不过还是很快,别担心。

作者有幽默感,但不要让这愚弄了你。这是一个伟大的算法。它被命名为YOOonlyLookO因为该算法的主要贡献是速度非常快。其他模型执行两阶段区域提议和对象分类阶段。YOLO 使用单一模型来输出包围盒和类别概率。它在速度和准确性方面远远超过了其他算法。

这个 YOLO 不错。怎么才能拿到?

有一个开源库可以解决这个问题。ImageAI 是一个 Python 库,它可以轻松地使开发人员利用现成的训练好的模型进行对象识别。你也可以用自己的物品进行定制训练。

我在这个 Kaggle 笔记本上尝试了简单的识别用例。就像下面这个片段一样简单:

from imageai.Detection import ObjectDetection

# load YOLO here
detector = ObjectDetection()
detector.setModelTypeAsYOLOv3()
detector.setModelPath("yolo.h5")
detector.loadModel()

# load your image here "input_img"
# ...
detections = detector.detectObjectsFromImage(
          input_img, input_type='array', 
          minimum_percentage_probability=50, output_type='array')

我在开放的图像数据集上进行测试,挑选出至少有一个“人”对象的图片。YOLO 模型是 ImageAI 的现成产品,它接受了包括人员、车辆和家居用品在内的 80 个类别的培训。我将模型设置为输出成为对象的概率大于 50%的区域。

看看它在我的一些样本输入中的表现

从左到右。(1) 100%一个人,但注意领带。(2)重叠的包围盒被识别出来,太神奇了。(3)失焦的人还是可以识别的。(4 和 5)图纸被认为是人。(6–8)可以检测多个人。(9)模型以为有两只狗。

(1)这是一个算法被难住的例子。(2)感觉良好!(3)404 消息被误标为时钟。(4)多个人被误标为一个人。我真的不知道这里发生了什么——某种聚会?(6)到处都是错误的标签!(7–9)全部正确。

(1)我不认为这个图像包含一个人!(2)发现了一个碗,真酷。(3–9)人!

这个人在废墟中行走的图像提出了一种可能性,即同样的技术可以帮助灾难恢复工作。例如,巡逻森林火灾或洪水的无人机可以识别被困人员。

它以 Python 字典的形式输出对象,所以你应该能够在你的应用程序中轻松操作它。这是一个普通的应用程序。能够分辨照片中的单个物体可以自动分类你越来越多的相机图像。或者至少,点钟,碗和滑板。

原载于 2019 年 8 月 25 日http://itstherealdyl.wordpress.com

作为数据结构的图像:艺术到 256 整数

原文:https://towardsdatascience.com/images-as-data-structures-art-through-256-integers-8898bce17230?source=collection_archive---------16-----------------------

让我们以数据结构的形式介绍图像的基本知识,认识一些迷幻的猫,并使用 NumPy“绘制”一个粉红色的棋盘!

形象问题一直让我兴奋。

我非常习惯在日常工作中使用表格数据。我相信大多数数据人都能理解。这篇文章将让你了解如何将图像表示为数据结构的基本知识,这样当奇异的图像识别或对象检测问题出现时,你就从some knowledge的地方开始,而不是从no knowledge的地方开始!

说到图像,我们将遵循一个由来已久的互联网传统。我们的一些主题将是猫!认识一下艾尔莎斯穆希

现在你注意到我了…我们开始吧。

黑白图像

让我们从这张简陋棋盘的图片开始:

信不信由你,我刚刚用NumPy做了这个!

让我们假设我们有一个名为chessboard8x8 NumPy 数组。让我们看一下它最上面的一行。这是一行,其中最左边的像素是白色的:

chessboard[0]array([255,   0, 255,   0, 255,   0, 255,   0], dtype=uint8)

现在让我们看看第二排。这是一行,其中最左边的像素是黑色:

chessboard[1]array([  0, 255,   0, 255,   0, 255,   0, 255], dtype=uint8)

每个数字代表从0 to 255开始的像素强度。也就是说,在这个颜色系统中有256个可能的值。你可能已经猜到了,这里的0代表‘黑’,而255代表‘白’。介于两者之间的一切都是灰色的。

为了制作棋盘,我简单地堆叠了这些黑白行,直到得到一个维度数组8x8(即 8 行 8 列):

import matplotlib.pyplot as plt
import numpy as npwhite_row = np.zeros(8).astype(np.uint8)
black_row = np.zeros(8).astype(np.uint8)
black_row[[1, 3, 5, 7]] = 255
white_row[[0, 2, 4, 6]] = 255chessboard = np.array([
    white_row,
    black_row,
    white_row,
    black_row,
    white_row,
    black_row,
    white_row,
    black_row,
])print(chessboard)[[255   0 255   0 255   0 255   0]
 [  0 255   0 255   0 255   0 255]
 [255   0 255   0 255   0 255   0]
 [  0 255   0 255   0 255   0 255]
 [255   0 255   0 255   0 255   0]
 [  0 255   0 255   0 255   0 255]
 [255   0 255   0 255   0 255   0]
 [  0 255   0 255   0 255   0 255]]

随机边注: 如果说*0**255*之间的一切在我们的色彩体系中都是一种深浅灰,那么五十度灰是怎么回事?让我们忽略灰色恰好是一个人的名字。为什么不:**

总之,这 254 种灰色看起来像什么?让我们创建一个 *16x16* NumPy 数组,因为 *16x16 = 256* 而这恰好是我们要绘制的像素强度的个数。

*all_shades = np.reshape(np.arange(256), (16,16))*

让我们画出那些可怜的、被忽视的灰色阴影:

很美,不是吗?

够了!“随机附言”完毕。

彩色图像呢?让我们增加一些音量!

我相信你们大多数人都听说过 RGB 颜色系统,其中:

  • R == 'red'
  • G == 'green',以及
  • B == 'blue'

在 RGB 彩色图像中,我们现在有三个矩阵,而不是一个8x8:

  • 专用于red像素强度的矩阵,
  • 专用于green像素亮度的矩阵,以及
  • 专用于blue像素亮度的矩阵。

这些被称为我们的 RGB 图像的红色、绿色和蓝色通道。

每个矩阵包含一个介于0255之间的整数,其中0表示该通道中的颜色已经被有效地“关闭”,而255表示该通道中的颜色已经被“打开到最大”。

当我们将这些矩阵堆叠在一起时,我们得到了一幅彩色图像!RGB系统是additive颜色系统的一个例子,其中颜色是通过将三个矩阵中的每一个矩阵的像素强度相加形成的。

我们现在知道彩色图像是三维的。彩色图像具有:

  • 以像素为单位的height
  • 以像素为单位的width,以及
  • 3 个通道的一个depth

让我们制作红色、绿色和蓝色的图像!

首先,请注意通道-第一个通道-最后一个约定。我们的 NumPy 数组是一维的3x8x8。也就是说,当描述数组的维度时,我们的“RGB 通道优先”。另一个约定是 channels-last,其中通道在数组的维度中列在最后(即8x8x3)。

我们将使用Matplotlib's imshow功能来绘制图像。检查函数的 docstring,我们会看到:

(M,N,3):具有 RGB 值(0–1 float 或 0–255 int)的图像…前两个维度(M,N)定义图像的行和列。

换句话说,imshow需要一个“channels-last”NumPy 数组。放心吧!我们将通过使用np.moveaxis将频道轴移动到末端,将“频道优先”图像转换为“频道最后”图像:

*channels_first = np.zeros((3, 8, 8)).astype(np.uint8)channels_first.shape(3, 8, 8)channels_last = np.moveaxis(channels_first, 0, 2)channels_last.shape(8, 8, 3)*

很简单,对吧?我们继续。

让我们turn on所有的red像素。假设 RGB 排序,我们将把第一个矩阵中的所有像素亮度设置为255的最大值。

我们将首先创建一个3x8x8阵列,所有像素亮度“关闭”(即设置为零):

*all_pixels_off = np.zeros((3, 8, 8)).astype(np.uint8)print(all_pixels_off)[[[0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]]

 [[0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]]

 [[0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]
  [0 0 0 0 0 0 0 0]]]*

所有通道像素都已关闭。所以我们得到一个全黑的图像是有道理的:

*_ = plt.imshow(np.moveaxis(all_pixels_off, 0, 2))*

让我们把红色像素调到最大:

*from copy import deepcopy
red_image = deepcopy(all_pixels_off)
red_image[0, :] = 255*

检查矩阵,我们看到这个:

*print(red_image)[[[255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]][[  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]][[  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]]]*

绘制它,我们得到这个:

*_ = plt.imshow(np.moveaxis(red_image, 0, 2))*

绿色像素重复:

*green_image = deepcopy(all_pixels_off)
green_image[1, :] = 255
print(green_image)[[[  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]][[255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]][[  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]]]_ = plt.imshow(np.moveaxis(green_image, 0, 2))*

并且再次针对蓝色像素:

*blue_image =  deepcopy(all_pixels_off)
blue_image[2, :] = 255
print(blue_image)[[[  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]
  [  0   0   0   0   0   0   0   0]][[  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0]][[255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255]
 [255 255 255 255 255 255 255 255]]]_ = plt.imshow(np.moveaxis(blue_image, 0, 2))*

如果我们把所有的像素亮度都调到最大会怎么样?

让我们将红色、绿色和蓝色通道中的所有像素强度设置为它们的最大值255:

*all_channels_to_the_max = deepcopy(all_pixels_off)
all_channels_to_the_max[:, :] = 255
print(all_channels_to_the_max)[[[255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]][[255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]][[255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]
  [255 255 255 255 255 255 255 255]]]_ = plt.imshow(np.moveaxis(all_channels_to_the_max, 0, 2))*

我们得到一个完全白色的图像!

给定一个 RGB 图像数据结构,我们如何获得灰度?

你大概能猜到我们需要做什么。让我们将所有像素的亮度设置为0255之间的某个值。我们将在所有三个矩阵中应用相同的值:

*greyscale = deepcopy(all_pixels_off)
greyscale[:, :] = 150
print(greyscale)[[[150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]][[150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]][[150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]
  [150 150 150 150 150 150 150 150]]]*

绘制它,我们得到:

嘣!我们自己有一个灰色的形象。

NumPy art:我们来做一个火辣的粉色棋盘吧!

快速搜索一下,我就知道【粉红佳人】的 RBG 值是这样的:

*red = 255
green = 105
blue = 180*

这是我们将要做的:

  • 我们将复制三份我们原来的8x8棋盘阵列。一个代表红色通道。另一个代表绿色通道。最后一个代表蓝色通道。
  • 然后,我们将改变每个通道的像素强度,以匹配上面的粉红色 RBG 值。我们将改变原始黑色像素的值(即零)。
  • 一旦我们完成了这些,我们将创建一个3x8x8数组,它将代表我们在 RGB 颜色空间中的棋盘。

当我们绘制图像时,我们将有希望看到一个神话般的,粉红色的棋盘。我们开始吧!

首先,副本:

*red_channel = deepcopy(chessboard)
green_channel = deepcopy(chessboard)
blue_channel = deepcopy(chessboard)*

接下来,像素值:

*red_channel[np.where(red_channel == 0)] = 255
green_channel[np.where(green_channel == 0)] = 105
blue_channel[np.where(blue_channel == 0)] = 180*

让我们创建我们的3x8x8数组,其中3代表我们的通道:

*hot_pink_chessboard = np.array([red_channel, green_channel, blue_channel]).astype(np.uint8)*

现在开始策划!请击鼓…

万岁!那确实是一个漂亮的棋盘。

迷幻猫

让我们用我们对图像的了解来搞乱我的猫 Elsa 和 Smooshie 的图像。

我们将使用cv2包将我们的猫图像读入 Python。cv2可以通过发布pip install opencv-python来安装。

*import cv2
elsa = cv2.imread('./elsa_original.jpg')*

恼人的是,cv2以不同的通道顺序存储图像。代替 RGB,我们有一个 BGR 通道排序。所以我们现在有一个 BGR 的图像。我们可以看到颜色有点偏离:

*_ = plt.imshow(elsa)*

我们现在将重新排列我们的频道,看看我们的图像是否看起来更好:

*elsa = cv2.cvtColor(elsa, cv2.COLOR_BGR2RGB)
_ = plt.imshow(elsa)*

那就好多了!

让我们增加红色通道的像素强度。假设我们想要将50添加到红色通道的像素亮度中。当使用numpy.uint8数据类型时,如果current pixel intensity + 50 > 255,我们的像素强度环绕并从零开始计数。这是一个整数溢出的例子。

为了避免这种情况,我们将使用一个次优但快速的解决方案。我们将把 NumPy 数组转换为numpy.uint16数据类型,它的上限是65,535。我们会给每个像素强度加上100imshow自动裁剪数组,使其最大值为255,这样我们就可以直接绘制图像了。

*elsa_int16 = elsa.astype(np.int16)
elsa_int16 = np.moveaxis(elsa_int16, 2, 0)elsa_red = deepcopy(elsa_int16)
elsa_red[0, :] += 100_ = plt.imshow(np.moveaxis(elsa_red, 0, 2))*

艾尔莎绝对有红色调!

让我们用绿色通道重复:

*elsa_green = deepcopy(elsa_int16)
elsa_green[1, :] += 100
_ = plt.imshow(np.moveaxis(elsa_green, 0, 2))*

是的,绝对更环保!最后,蓝色通道:

*elsa_blue = deepcopy(elsa_int16)
elsa_blue[2, :] += 100
_ = plt.imshow(np.moveaxis(elsa_blue, 0, 2))*

是的,绝对是蓝色的。

让我们将任意数字添加到每个通道,看看我们会得到什么:

*elsa_psychedelic = deepcopy(elsa)
elsa_psychedelic = np.moveaxis(elsa_psychedelic, 2, 0)elsa_psychedelic[0, :] += 150
elsa_psychedelic[1, :] += 5
elsa_psychedelic[2, :] += 50_ = plt.imshow(np.moveaxis(elsa_psychedelic, 0, 2))*

看起来很酷,艾尔莎!斯穆希呢?

*smooshie = cv2.imread('./smooshie_original.jpg')
smooshie = cv2.cvtColor(smooshie, cv2.COLOR_BGR2RGB)
_ = plt.imshow(smooshie)*

让我们给 Smooshie 的照片添加一些不同的数字:

*smooshie_psychedelic = deepcopy(smooshie)
smooshie_psychedelic = np.moveaxis(smooshie_psychedelic, 2, 0)smooshie_psychedelic[0, :] += 85
smooshie_psychedelic[1, :] += 10
smooshie_psychedelic[2, :] += 175_ = plt.imshow(np.moveaxis(smooshie_psychedelic, 0, 2))*

我们有两只迷幻猫!

( 排队《你爱的阳光》)

结论

我们已经学会了如何将图像表达为可以在 Python 中操作的数据。我们一路上做了一个热粉色的棋盘和一些迷幻的猫照!

我希望这篇文章已经给了你处理图像核等主题所需的基础,这些主题对于理解卷积神经网络如何工作很重要。

下次见。

贾斯廷

原载于 2019 年 12 月 14 日https://embracingtherandom.com

幻想工程和复活

原文:https://towardsdatascience.com/imagineering-resurrections-883506f2bcf9?source=collection_archive---------19-----------------------

Protohouse (2012) by Gilles Retsin and Softkill Design. A house structurally optimized for minimal volume and uniform stress. Image: ArchDaily

生成式设计描绘了想象的新领域,同时重组了过去的元素。这与我们现有系统的运作方式不协调。

新一代设计技术赋予设计师超能力。他们指的是为设计者设计的一套基于算法的技术。他们不仅是制造的工具,更是思考 的工具。

创成式设计技术通过让设计者指定设计问题的参数来工作。使用聪明的算法和大量的处理能力,生成式设计软件遵循一个进化过程,快速循环通过数千个——如果不是数百万个——设计选择,测试配置并从每次迭代中学习什么可行什么不可行。然后,设计师从无数生成的选项中进行策划和选择。

这些工具非常有用。他们可以优化材料的使用,加快设计过程,创造艺术,想象全新的产品形式。他们是从大规模生产过渡到 大规模定制 的推动者之一。生成式设计的未来看起来非常光明。

Tensegrity nodes. Image: engineering.com courtesy of Arup

然而,生成式设计技术的一个关键问题是,它们所实现的输出并不完全符合我们现有系统的规则。虽然我们的法律是围绕静态、类别和稀缺建立的,但生成式设计系统会产生流动、梯度和大量的解决方案。

例如,专利法依赖于根据独创性和实用性对技术进行分类。生成式设计产生了无数模糊了这两种分类的设计。他们质疑谁制造了什么,谁拥有什么,以及谁应该拥有什么。

我们的社会系统和生成设计系统之间的不一致表明,如果生成设计的用途扩大,将不得不做出一些让步。这篇文章没有提供这样的解决方案。相反,它概述了生成式设计技术与我们的规则和法律之间的四个摩擦领域。如果这些摩擦被认为会愈演愈烈,那么我们就有责任以相应的紧迫感做出回应。

I .(去)个性化媒体

对于它们的许多用例,创成式设计技术不依赖于先前的数据来生成解决方案。例如,可以通过处理一组参数来设计桥梁,而不需要参考预先存在的结构。

但是数据可以作为有用的参数来指导解决方案的创建。这在 2016 年谷歌泄露的内部视频中得到了说明,该视频强调了一种推测性的用例,即用户的详细数据被用于设计“个性化”产品。在这种情况下,我们未来的自己不仅会收到定制的媒体信息,还会收到定制的物理媒体。

The Selfish Ledger (2016) by Google. Source: The Verge

收到认识到我们独特需求的定制产品的前景令人兴奋,但也提出了这样做的合适范例的问题。

哈佛大学社会学家 Shoshana Zuboff 提出了当前数字范式的一个特征。她称之为监督资本主义,这是一种市场逻辑,公司从人类经验中积累大量数据,将这些数据组织成未来行为的预测模型,并拍卖外部实体修改这种行为的能力。在这个体系中,“给予”给我们的东西是达到他人目的的手段。

由于我们生活中的个人物品可能会受到生活数据的影响,我们需要谨慎对待这些数据收集和使用背后的商业模式。如果一个数字系统的可用性取决于它改变我们行为以消费更多的能力,我们希望我们最亲密的物品也这样做吗?

决定数字服务的规则和边界的问题还没有解决。随着数字领域与物理领域的融合,它们将会复合。

二。重构的真实性

创成式设计技术可以用来模拟和重新配置已经存在的事物。已经有很多关于“deepfakes”的影响的讨论,deep fakes 是深度学习的一种应用,它基于真实的副本创建假的照片、视频和文字。但是很少有人讨论整部作品如何被拆开、合成和复活。

艺术界现在正在见证“已故艺术家”的“新作品”。一个著名的例子是下一个伦勃朗,这是一幅模仿伦勃朗风格的 3D 打印画,伦勃朗是一位去世已久的 17 世纪荷兰画家。该项目由荷兰国际集团发起,荷兰国际集团是一家荷兰跨国银行集团“,寻求一种创新的方式,并在竞争对手中脱颖而出——并利用了微软的技术诀窍。这幅名为“T4”的肖像画由 1.48 亿像素组成,取材于伦勃朗作品中的 168,263 个片段。

The Next Rembrandt (2016). It’s not a Rembrandt, but it looks like one. Source: The Next Rembrandt

“我们观察了许多伦勃朗的画作,扫描了它们的表面纹理、元素构成以及使用的颜料种类。如果你想虚拟生成一幅伦勃朗的画,这就是你需要的信息。”— Joris Dik,代尔夫特技术大学

最近,伦敦大学学院的研究人员使用了一种神经转移风格技术来“恢复”毕加索著名的“蓝色吉他手”下面的一幅被涂掉的画。他们的过程使用了隐藏画作的红外和 x 射线图像,以及毕加索其他作品的“风格”图像,来重现这幅画。基本的算法是通用的,可以将任何图像转换成另一个艺术家的风格。

伦勃朗和毕加索会因为复制他们作品的算法而在坟墓里打滚吗,或者他们会赞同这些(再)创造的叛逆行为吗?活着的艺术家呢?

像前面提到的专利法一样,我们的系统是围绕类别设计的。他们裁定事物是真是假,原件还是复印件,专利还是专利侵权,等等。

生成设计引入了真实、现实、信任和价值的粒度。新的规则可能需要被书写——或者甚至可能产生。

三。一个分布式网络

除了 deepfakes 的利用性质之外,生成式设计技术有可能被用于明显的恶意目的。例如,生成对抗网络(GANs),一种算法,已经被麻省理工学院技术评论认定为网络威胁,因为它们能够入侵系统。一个尚未看到的风险是,生殖设计可能有助于创造以前无法想象的武器。

The Shuty (2015) by Defence Distributed. A semi-automatic gun made of metal and plastic parts. The plastic parts are 3D printed, while the metal parts can be purchased from typical hardware stores. Source: YouTube

在线网络通过扩散和普及对抗性算法和设计,加剧了这种潜在的危害。

一个这样的例子是 3D 打印枪的蓝图和 CAD 模型是如何在发明后不久就在网上传播的。虽然一名美国联邦法官确实批准了一项针对 Defense Distributed(发布该设计的组织)的全国性禁令,但一旦设计被共享,它们很少会被取消共享。

限制生成设计技术的对抗性使用及其设计的传播没有简单的答案。开发人员很难将约束编码到他们的工具中。设计师可以被要求选择加入行为准则——但这些可以被忽略。政府或平台可以尝试监控内容,但过去的努力基本无效。

斯图尔特·布兰德曾打趣道,“信息想要自由。“互联网和生成式设计技术的融合表明在这个方向上又前进了一步——无论是字面上还是象征性的——这将是危险的。

四。像国家一样产生

生成式设计技术非常适合优化,但它们只能优化可测量的内容。这可能会引入许多设计问题,这些问题源于以下前提:

  • 测量只能得到现实的一部分。
  • 测量可能会被扭曲,尤其是当受试者知道他们正在被测量的时候。
  • 没有或不能衡量的东西可能会被忽略。

这种对可测量性的偏好在智能城市计划中是有先见之明的。亚当·格林菲尔德写道支撑这些倡议的是一种隐含的世界观,即“世界在原则上是完全可知的,其内容是可计数的,它们之间的关系能够在技术系统的状态下被有意义地编码,没有偏见或扭曲[……]那么,如果对制定合理的公民政策至关重要的信息在某种程度上从它们的探测中缺失,存在于它们之间的空间中,或者来自于我们着手测量的世界的任何质量和我们对它的物质经验之间的相互作用,那又会怎么样呢?”

在智能城市出现之前,詹姆斯·c·克拉克将这种心态称为高级现代主义。在他的书《看起来像一个国家》中,他认为善意的大规模项目之所以失败,是因为没有——也不可能——充分理解复杂的相互依存关系,有利于使事物清晰易读。它将我们引向巴西利亚这样的城市:设计合理,却缺乏内在生活。

创成式设计面临同样的问题。乔尔·史密斯的实验研究项目“进化平面图”强调了这一点。该项目探索了一所小学的推测性、优化的平面布局——考虑了交通流量、材料使用和消防通道等因素。这个项目很有创意,但是我们应该对这种想法如何应用于现实世界持谨慎态度。像儿童之间的社会互动这样的事情,是无法通过量化来完全理解的。

Evolving Floorplans (2018) by Joel Smith. An elementary school. Left: Optimized for minimizing traffic flow between classes and material usage. Right: Also optimized for minimizing fire escape paths. Source: Joelsmith.net

对于这个问题,似乎确实有一个明确的解决方案:一个深思熟虑的设计过程。生成式设计软件的创造者之一 Autodesk 就用它的软件设计了它的多伦多办公室。通过提出一个框架良好的问题,让员工参与进来,并仔细策划解决方案,他们找到了一个原始设计,这是任何人和计算机都无法独立构思的。

Toronto Office (2018) by Autodesk. Source: YouTube

然而,如果我们生活中的许多事情都是例证的话,深思熟虑的设计远非无处不在。生成式设计技术只会基于可以测量的东西进行设计,而忽略不可测量的东西太容易了。在生成性设计的所有产品和服务中培养对这些考虑的警觉可能是一个持续的挑战。

综上

生成式设计技术是超级工具,它引入了一种围绕框架问题、观察难以理解的操作和管理结果的新设计实践。他们通常像外星人一样的输出反映了他们外星人的内部运作,莫名其妙地将过去和假设的碎片编织在一起。它们非常有用。

对我们当前社会系统中的生成设计产品的简要审视表明,工具、规则或法律可能需要改变或再生,以激发未来的利益并减轻伤害。

喜欢你读的书吗?关注我LinkedIn ,或者 Twitter

不平衡的类:第 1 部分

原文:https://towardsdatascience.com/imbalanced-class-sizes-and-classification-models-a-cautionary-tale-3648b8586e03?source=collection_archive---------9-----------------------

避免分类中的不平衡分类陷阱

在最近的一个数据科学项目中,我开发了一个监督学习模型,对度假屋网站 Airbnb 的首次用户的预订位置进行分类。作为 2015 年 Kaggle 竞赛的一部分,该数据集可在 Kaggle 上获得。

在我的项目中,我决定将用户分为两组:一组是在美国和加拿大境内预订首次旅行的用户,另一组是在国际其他地方预订首次旅行的用户,这实质上是将问题转化为一个二元分类问题。听起来很简单,对吧?

问题是分类目标(预订位置)非常不平衡。近 75%的首次用户预订了美国和加拿大境内的旅行。在我的初始模型显示了有希望的结果之后,对模型性能度量的进一步检查突出了一个关键问题,即当试图用不平衡的类大小执行二进制分类时。这篇文章旨在强调在构建具有不平衡类的分类模型时要注意的一些陷阱,并强调一些处理这些问题的方法。

数据

这张图显示了我的目标群体中固有的严重不平衡:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import pickle
import seaborn as snsdf = pd.read_pickle('data_for_regression_20k.pkl')sns.set_style("white")
dests2 = df.groupby('country_USA_World_bi').agg({'country_USA_World_bi':['count']}).reset_index()
dests2.columns = ['dest', 'count']
dests2['pct'] = dests2['count']*100/(sum(dests2['count']))x = dests2['dest']
y = dests2['pct']
palette = ['olive','mediumvioletred']fig, ax = plt.subplots(figsize = (8,4))
fig = sns.barplot(y, x, estimator = sum, ci = None, orient='h', palette=palette)
y_lab = ['USA/Canada', 'International']
ax.set_yticklabels(labels=y_lab, ha='right')for i, v in enumerate(y):
    ax.text(v - 15, i + .05, str(int(v)+.5)+'%', color='white', fontweight='bold')plt.title('Country Destinations as Percent of Total Bookings',size = 16, weight = 'bold')
plt.ylabel('Country')
plt.xlabel('Percent of total');

Close to 75% of users booked vacation rental in the U.S.A. and Canada

在将逻辑回归分类器应用于我的数据之前,我将数据分为训练集(80%)和测试集(20%)。由于国际旅行者的代表性不足,我使用了分层参数来确保两个目标类都在测试集中得到了体现。然后,我使用一个标准标量对训练和测试特性集进行了标准化。

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import precision_score, recall_score, precision_recall_curve,f1_score, fbeta_score, make_scorery = df['country_USA_World_bi']  
X = df.drop(['country_dest_id','country_USA_World_bi','month_created', 'day_created', 'month_active', 'day_active'], axis = 1)Xtrain, Xtest, ytrain, ytest = train_test_split(X, y, test_size=0.2, stratify=y,random_state = 88)std_scale = StandardScaler()
X_train_scaled = std_scale.fit_transform(Xtrain)
X_test_scaled = std_scale.transform(Xtest)

我运行的第一个模型是逻辑回归,因为逻辑回归包括特征系数(这有助于可解释性)。我用默认的 hypterparameters 拟合了一个初始模型,并惊喜地发现,在任何 hypter parameter 调整之前,该模型有 75%的准确性。很自然地,我发现自己在想这是不是好得不像真的。回想 75%的用户在美国/加拿大境内旅行,难道我每次只需猜测目的地就能有 75%的准确率吗?

事实上,模型精度(预测的国际预订实际上是国际预订的比例)、模型召回率(模型正确识别的国际预订的比例)和 f1 分数(两者的平衡)都非常差。

出于这个项目的目的,我对回忆分数最感兴趣,因为我认为模型能够准确预测将进行国际旅行的用户是最有用的(因为那些进行国际旅行的用户更有可能是具有较大旅行预算的狂热旅行者)。然而,鉴于最初的回忆分数只有 0.01,我还有很长的路要走,以改善这个模型!

from sklearn.linear_model import LogisticRegressiondef fit_logistic_regression_classifier(X_training_set, y_training_set):
    logreg = LogisticRegression(random_state=88)
    model = logreg.fit(X_training_set, y_training_set)
    y_pred = model.predict(X_test_scaled)
    print('accuracy = ',model.score(X_test_scaled, ytest).round(2),
          'precision = ',precision_score(ytest, y_pred).round(2), 
          'recall = ',recall_score(ytest, y_pred).round(2), 
          'f1_score = ',f1_score(ytest, y_pred).round(2)
         )
    return(y_pred)
y_pred = fit_logistic_regression_classifier(X_train_scaled, ytrain)

混淆矩阵是一个很好的工具,可以形象化模型被混淆的程度。在 sklearn 中的混淆矩阵给出了根据实际类别预测的每个类别中观察值数量的原始值计数。plot_confusion_matrix()函数给出了每个实际类和预测类中值的百分比的可视化表示。

import itertools
from sklearn.metrics import confusion_matrix
def make_confusion_matrix(cm, classes,title='Confusion matrix',cmap=plt.cm.Blues):
    print(cm)
    # Normalize values
    cm = cm.astype('float')*100 / cm.sum(axis=1)[:, np.newaxis]
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)fmt = '.2f'
    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, format(cm[i, j], fmt),
                 horizontalalignment="center",
                 color="white" if cm[i, j] > 50 else "black")
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    plt.tight_layout()
def plot_confusion_matrix(y_test_set, y_pred):
    class_names = ['Domestic','International']
    cnf_matrix = confusion_matrix(y_test_set, y_pred)
    np.set_printoptions(precision=2)
    plt.figure()
    make_confusion_matrix(cnf_matrix, classes=class_names, title='Confusion matrix with normalization');

该图表明我的直觉是正确的——该模型将几乎 100%的观察结果分类为国内旅行者,因此有 75%的时间达到了目标!

plot_confusion_matrix(ytest, y_pred)

1。随机过采样

不平衡学习库包括多种方法来重新平衡类别,以获得更准确的预测能力。我尝试的方法叫做随机过采样。根据文档,“随机过采样可用于重复一些样本,并平衡数据集之间的样本数量。”基本上,这种重新平衡方法使用目标类的随机抽样和替换来获得训练集中每个类的平衡表示。事实上,在将随机抽样器应用于我的训练集之后,我在每个目标类中都有 12,743 个观察样本,而我的基线场景是 3,186 个国内预订和 1,088 个国际预订。

from imblearn.over_sampling import RandomOverSamplerros = RandomOverSampler(random_state=88)
X_resampled, y_resampled = ros.fit_sample(X_train_scaled, ytrain)yvals, counts = np.unique(ytest, return_counts=True)
yvals_ros, counts_ros = np.unique(y_resampled, return_counts=True)
print('Classes in test set:',dict(zip(yvals, counts)),'\n',
      'Classes in rebalanced test set:',dict(zip(yvals_ros, counts_ros)))

和以前一样,我用默认参数拟合了一个逻辑回归分类器,并观察了模型的性能指标和混淆矩阵。由于该模型不再能在 75%的时间内正确猜测国内位置,其性能显著下降:准确率降至 54%。

然而,回想一下,我的兴趣指标增加了——从 0.01 增加到 0.58。在测试集中提供平衡的班级规模显著提高了模型预测少数民族班级的能力(在我的例子中,Airbnb 在国际地点的预订)。

y_pred_ros = fit_logistic_regression_classifier(X_resampled, y_resampled)
plot_confusion_matrix(ytest, y_pred_ros)

2。SMOTE 和 ADASYN

合成少数过采样技术(SMOTE)和自适应合成(ADASYN)是对少数类进行过采样的另外两种方法。与对现有观测值进行过采样的随机过采样不同,SMOTE 和 ADASYN 使用插值在少数类的现有观测值附近创建新观测值。

对于 SMOTE 重新平衡,我使用了 SMOTENC 对象,因为我的大多数特征(除了六个之外)都是非连续的(即分类的)特征。就像以前一样,我最终得到了一套平衡的训练。

ADASYN 给了我一个新的培训集,其中约 49%的旅行者去了美国/加拿大,51%的旅行者去了国外。这种(微不足道的)不平衡是由于 ADASYN 根据难度的加权分布在困难点周围创建新数据点的方式造成的(见 he 等人,2008 )。

就像随机过采样一样,模型对所有目的地进行分类的能力(准确性)会随着过采样而下降。另一方面,SMOTE 和 ADASYN 都提高了模型对少数类的分类能力(回忆)。

from imblearn.over_sampling import SMOTENC, ADASYN
smote_nc = SMOTENC(categorical_features=list(np.arange(7,80)), random_state=88)
X_smoted, y_smoted = smote_nc.fit_resample(X_train_scaled, ytrain)adasyn = ADASYN(random_state=88)
X_adasyn, y_adasyn = adasyn.fit_resample(X_train_scaled, ytrain)yvals, counts = np.unique(ytest, return_counts=True)
yvals_smt, counts_smt = np.unique(y_smoted, return_counts=True)
yvals_ads, counts_ads = np.unique(y_adasyn, return_counts=True)print('Classes in test set:',dict(zip(yvals, counts)),'\n',
      'Classes in rebalanced test set with SMOTENC:',dict(zip(yvals_smt, counts_smt)),'\n',
      'Classes in rebalanced test set with ADASYN:',dict(zip(yvals_ads, counts_ads)))

y_pred_smt = fit_logistic_regression_classifier(X_smoted, y_smoted)
plot_confusion_matrix(ytest, y_pred_smt)

y_pred_ads = fit_logistic_regression_classifier(X_adasyn, y_adasyn)
plot_confusion_matrix(ytest, y_pred_ads)

3。平衡类网格搜索

由于采用 ADASYN 过采样的基线模型在召回率方面表现最佳,因此我对这个测试集进行了网格搜索,以找到进一步优化模型性能的参数。

from sklearn.model_selection import GridSearchCV
grid = {"C":np.logspace(-3,3,7), "penalty":["l1","l2"]}# l1 lasso l2 ridge
logreg = LogisticRegression(random_state=88)
logreg_cv = GridSearchCV(logreg,grid,cv=5,scoring='recall')
logreg_cv.fit(X_adasyn, y_adasyn)
print("tuned hpyerparameters :(best parameters) ", logreg_cv.best_params_)

具有 0.001 的 C 参数和 L2 正则化惩罚的逻辑回归模型具有 0.65 的改进的回忆分数。这意味着该模型能够有效地抓住 65%的将在国际上预订 Airbnbs 的新用户。

y_pred_cv = logreg_cv.predict(X_test_scaled)
print('accuracy = ',logreg_cv.score(X_test_scaled, ytest).round(2),
        'precision = ',precision_score(ytest, y_pred_cv).round(2), 
        'recall = ',recall_score(ytest, y_pred_cv).round(2), 
        'f1_score = ',f1_score(ytest, y_pred_cv).round(2)
        )
plot_confusion_matrix(ytest, y_pred_cv)

虽然平衡类和超参数调整显著提高了模型的召回分数,但模型精度仍然很低,只有 0.3。这意味着,只有 30%被归类为国际旅行者的用户实际上在国际上预订 Airbnbs。在商业环境中,像这样的模型可以用于根据预测的预订目的地通知度假屋的定向广告。这意味着 70%收到建议的用户,比如说,可以俯瞰埃菲尔铁塔的房子,实际上会考虑在国内旅行。这种错误定位不仅与该集团无关,而且未能向美国/加拿大集团传播相关广告可能意味着随着时间的推移会损失收入。

现在,我已经通过对少数类进行过采样解决了模型性能的高估问题,接下来的步骤可能包括额外的特征工程,以梳理出更多的信号并拟合替代分类算法(如 K-最近邻或随机森林分类器)。

结论

在这个例子中,一旦我重新平衡了目标类的大小,模型的准确性就会显著下降。即使在使用 gridsearch 交叉验证进行超参数调整后,逻辑回归模型的准确性也比具有不平衡类别的基线模型低 10 个百分点。

这个例子说明了考虑类别不平衡的重要性,以避免高估分类模型的准确性。我还用工作代码概述了通过过采样(随机过采样、SMOTE 和 ADASYN)重新平衡类的三种技术。关于每种技术的更多信息可以在不平衡学习文档中找到。

不平衡的班级:第 2 部分

原文:https://towardsdatascience.com/imbalanced-class-sizes-and-classification-models-a-cautionary-tale-part-2-cf371500d1b3?source=collection_archive---------12-----------------------

避免分类中的不平衡分类陷阱

R 最近,我写了这篇文章关于分类模型中不平衡的班级规模可能会导致分类模型的性能被高估。这篇文章讨论了我正在使用来自 Kaggle 的 Airbnb 首次用户预订数据开发的一个分类项目。该项目的目标是预测首次使用 Airbnb 的用户是否会在美国/加拿大或国际上的某个地方预订度假屋。然而,美国/加拿大境内的预订量约占数据的 75%,因此很难准确估计国际预订量。

考虑到几乎 100%的观察值被预测为主导类(在我的例子中,是去美国/加拿大的旅行者),我使用自适应合成(ADASYN)对测试集中的少数类进行过采样。由于对使用默认参数的开箱即用逻辑回归的结果不满意,我决定使用 scikit-learn 中的 GridSearchCV 进行一些模型选择和强力参数调整。我的特性是工程化的,我的类是平衡的,我闪亮的新 AWS 实例是计算优化的。什么会出错?

数据预处理

我急切地想拟合一些模型,看看我能根据已获得的特征对用户位置进行多好的分类。我已经将数据框架分成了目标变量(y)和特征矩阵(X)。我对数据集执行了训练-测试-分割(80%训练,20%测试),并进行分层,以确保少数类在测试集中得到代表。我在特征集(X_train 和 X_test)上使用了标准的标量转换。最后,我使用了自适应合成(ADASYN)方法对训练数据中的少数类进行过采样(详见不平衡类第一部分)。

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from imblearn.over_sampling import ADASYNX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, 
                                                stratify=y,random_state = 88)
std_scale = StandardScaler()
X_train_scaled = std_scale.fit_transform(X_train)
X_test_scaled = std_scale.transform(X_test)adasyn = ADASYN(random_state=88)
X_adasyn, y_adasyn = adasyn.fit_resample(X_train_scaled, y_train)

GridSearchCV

我循环了五个分类器:逻辑回归、K 近邻、决策树、随机森林和支持向量分类器。我将“模型”定义为带有分类器对象的每个分类器的字典列表(为了再现性,随机状态总是设置为 88,你能猜出我最喜欢的数字吗?),以及要调整的特定于模型的超参数网格。

from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVCmodels = [{'name': 'logreg','label': 'Logistic Regression',
           'classifier': LogisticRegression(random_state=88),
           'grid': {"C":np.logspace(-3,3,7), "penalty":["l1","l2"]}},

          {'name': 'knn','label':'K Nearest Neighbors',
           'classifier':KNeighborsClassifier(),
           'grid': {"n_neighbors":np.arange(8)+1}},

          {'name': 'dsc','label': 'Descision Tree', 
           'classifier': DecisionTreeClassifier(random_state=88),
           'grid': {"max_depth":np.arange(8)+1}},

          {'name': 'rf', 'label': 'Random Forest',
           'classifier': RandomForestClassifier(random_state=88),
           'grid': {'n_estimators': [200, 500],'max_features': ['auto', 'sqrt', 'log2'],
                    'max_depth' : [4,5,6,7,8],'criterion' :['gini', 'entropy']}},

          {'name': 'svm_rbf', 'label': 'SVC (RBF)',
           'classifier':SVC(random_state=88),
           'grid': {'C': [1, 10, 100, 1000], 'gamma': [0.001, 0.0001], 'kernel': ['rbf']}}]

我在下面定义了 model_selection 函数来执行网格搜索,以优化给定模型的五个交叉验证集中的 hypterparameters。我决定使用受试者操作特征曲线(ROC AUC)分数下的计算面积来确定模型性能,以便尝试最大化真阳性,同时最小化模型预测中的假阳性。该函数返回一个字典,其中包括分类器、GridSearch 中的最佳参数以及验证集中的最佳平均 ROC_AUC 分数。

from sklearn.metrics import roc_auc_score
def model_selection(classifier, name, grid, X_train, y_train, scoring):

    gridsearch_cv=GridSearchCV(classifier, 
                               grid,
                               cv=5, 
                               scoring = scoring)

    gridsearch_cv.fit(X_adasyn, y_adasyn)

    results_dict = {}

    results_dict['classifier_name'] = name    
    results_dict['classifier'] = gridsearch_cv.best_estimator_
    results_dict['best_params'] = gridsearch_cv.best_params_
    results_dict['ROC_AUC'] = gridsearch_cv.best_score_

    return(results_dict)results = []
for m in models:    
    print(m['name'])    
    results.append(fit_first_model(m['classifier'], 
                                   m['name'],
                                   m['grid'],
                                   X_adasyn, 
                                   y_adasyn, 
                                   'roc_auc'))      
    print('completed')

最后,我将每个分类器的结果进行了比较!这个过程花费的时间并不多,所以要准备好消磨一些时间(这个过程结束时,我的厨房一尘不染!).

我将结果放入数据框中,以便更好地查看:

results_df = pd.DataFrame(results).sort_values(by='ROC_AUC', ascending = False)

GridSearch ross-validation results across several classifiers with optimized parameters

嗯,我对第一行非常满意,随机森林分类器获得了 0.85 的 ROC_AUC 分数。这让我想到了 XGBoost 树分类器的一些宏伟计划。我将得到一个预测模型来与 Kaggle 竞赛的获胜者竞争…或者我是吗?

为了确认随机森林分类器的性能,我在测试集上对模型的预测性能进行了评分。当我看到测试集的 ROC_AUC 分数只有 0.525 时,我惊呆了。根据我的经验,测试分数通常低于交叉验证分数,我知道随机森林可能容易过度拟合,但这是 38%的性能下降!

为了更好地衡量,我对测试集上其余四个分类器的性能进行了评分。果然,ROC_AUC 测试分数明显低于交叉验证 ROC_AUC 平均值。逻辑回归是个例外,在验证集和测试集上的表现都比随机猜测略好。

Average cross-validation ROC_AUC scores are well above test scores

订单事项

这里发生了什么事?嗯,请记住,在分割我的训练数据进行交叉验证之前,我用 ADASYN 进行了过采样。所以,我的五重验证集并不代表现实世界中的分布。相反,它们包含代表少数类中难以分类的观察的“合成”数据点。因此,当我在测试集上对模型性能进行评分时(目标类比例代表真实世界),分数显著下降。

幸运的是,不平衡学习有一个管道类,它将只在分类器拟合期间应用 ADASYN 重采样,从而允许我避免一些笨拙的 for 循环和手动 GridSearchCV。

下面是在交叉验证拟合期间使用过采样在随机森林分类器上构建 GridSearchCV 超参数调整管道的代码。(注意网格字典里的 class__ 前缀!)

from imblearn.pipeline import make_pipeline, Pipelinerf = RandomForestClassifier(random_state=88)
adasyn = ADASYN(random_state=88)grid = {'class__n_estimators': [200, 500],
        'class__max_features': ['auto', 'sqrt', 'log2'],
        'class__max_depth' : [4,5,6,7,8],
        'class__criterion' :['gini', 'entropy']}pipeline = Pipeline([('sampling', adasyn), ('class', rf)])grid_cv = GridSearchCV(pipeline, grid, scoring = 'roc_auc', cv = 5)

grid_cv.fit(X_train_scaled, y_train)grid_cv.best_score_

你瞧,交叉验证的 ROC_AUC 只有 0.578,更能说明模型在应用于测试集时的实际表现。我又一次遍历了所有模型,保存了最佳参数、平均验证分数和测试分数,以确保完整性。

Average cross-validation roc_auc scores with pipeline oversampling are far more similar to test set scores

关键要点

在验证集中使用合成数据的分类算法的 ROC-AUC 曲线(左)表明,与在具有代表性不平衡类别的验证集中评分的 ROC-AUC 曲线(右)相比,明显高估了拟合度。(注意:这些算法是在单个验证集上评分的,而不是三次的平均值,因此得分与上表不同)。

ROC-AUC Curves

虽然我无法自信地预测 Airbnb 用户的度假目的地,但这个项目说明了关注高级机器学习算法“幕后”发生的事情的重要性。特别是,我在之前关于不平衡的类规模如何导致分类器性能被高估的文章的基础上,讨论了为什么在使用交叉验证和超参数调整对重新采样的训练数据拟合分类器时,顺序很重要。

我希望这个系列对您有用。请随时在下面的评论中提供任何意见或额外的见解!

公共/私人区块链中的不变性—第 2 部分

原文:https://towardsdatascience.com/immutability-in-public-private-blockchains-part-2-307afa416094?source=collection_archive---------13-----------------------

Photo by marcos mayer on Unsplash

在第 1 部分中,我们讨论了什么是不变性,在什么情况下它是重要的,以及所有这些与区块链的关系。

关于区块链不变性的进一步讨论涉及到具体的实现。在这一部分,我要谈一谈公共的和私人的区块链;具体来说,比特币和 Hyperledger Fabric。公共与私人的区别更丰富了讨论。

比特币不变性

根据我们设定的起点,分析比特币不变性时会涉及很多内容。试图从零开始涵盖这个主题将导致一篇文章的一个真正情有可原的解释。

关于比特币不变性,最常见的困惑之一是,既然区块被链接在一起,那么区块链就是不可变的。这不是真正正确的;真正让比特币不可改变的是工作证明。

工作证明

工作证明(PoW),你可能知道,不是为比特币发明的东西。顾名思义,工作证明是工作被执行的证明。一个非常抽象的定义将是:一个工具,证明足够的努力致力于某事。特别是,防止拒绝服务攻击很有意义。

所以有三个有趣的问题:

  • 为什么比特币需要能量?
  • 谁在工作?
  • 他们为什么这么做?

要理解这些问题,我们应该记住,比特币是一个公共区块链,因此任何人都可以在网络中扮演任何角色。正如在任何一种公共系统中一样,参与者之间的信任程度是有限的。在比特币中,执行 PoW 算法的节点被称为矿工,他们的角色是为链提出新的区块。

因为任何人都可以成为矿工、在任何时间点都有多个竞争区块被开采。由于每个挖掘器可以决定在块中包含哪些未确认的事务,因此我们将有许多可能的块,每个块都有不同的事务。那么,如果网络有多种可能的选择,它如何决定哪一个是下一个块呢?换句话说,网络如何达成共识?一个解决办法是让创造过程足够艰难。

如果生成一个有效的块足够困难,以至于所有的矿工作为一个整体只能生成一个,比如说,在几分钟的时间里,那么我们就不会有从许多中选择一个的问题。这就像一个硬彩票,检查 102 个中奖者比检查 3000 个中奖者更容易。此外,这不仅是一个难题,寻找解决方案也很昂贵。既然也贵,矿工在向网络广播无效块之前会三思。此外,矿工 T21 可以证明工作已经完成,这是无可争议的。

这并没有以确定性的方式解决一致性问题,但足以在网络中提供可靠的一致性保证。选择正确的硬度是分叉概率、网络负载和确认速度之间的权衡。

但是对于一个矿工来说,权力到底意味着什么呢?在比特币方面,矿工应该找到通常被称为密码难题的解决方案。这个难题包括找到一个,使得新的块散列值低于某个阈值。这个是的一个证明矿工按预期执行了 PoW。当验证一个新的块时,这个不满足这个条件的事实足以认为它是无效的。

为什么是这个谜题而不是另一个?因为我们很确定唯一的解决方法就是暴力。它没有捷径;是骗不了的。此外,网络将自动调整其难度,即前面提到的阈值,以响应网络散列能力的增加或减少,从而保持块创建的定义速度。

我们可以想象,也许矿工会为了在网络中达成共识而解决这个昂贵的问题,但这太天真了,不是因为矿工邪恶,而是因为他们理性。激励矿工的真正原因是激励

采矿者成功开采一个区块时,它将获得奖励以及该区块内包含的交易的交易费用的总和;都在比特币里。这些激励在供应链的生命周期内是动态的。

奖励是确定性的,每 210.000 个块减半,交易费用可以根据受未决交易池的大小或某种外源交易紧急程度影响的需求而变化。

关于激励和权力是如何交织在一起使系统变得安全和可持续的,有很多话要说。这部分制度设计更多的是心理学,经济学,博弈论。在一个不可信的网络中,你不能假设网络参与者总是按照预期行事,或者有不同于他们自己的其他兴趣。

PoW 作为一种共识机制,但是它和不可变性有什么关系呢?为了理解这一点,我们应该考虑比特币中的节点应该遵循的一个重要规则:最长的链是当前链当前链是什么概念?。

假设链中的最后一个块是 100 号。由于在矿工之间没有任何协调来生成块号 101,事实上,他们在比赛/抽奖成为奖励的所有者,所以有可能他们中的两个大约同时生成有效的 101 块(比如 101a 和 101b)。我所说的“同时”是指两个块都被广播到网络,并且对于附加到其当前链的其他节点来说是完全有效的选项。

在这种情况下,网络中的节点可以接收这两个有效块,在链中有一个分叉。挡块 101a 是指 a 叉中的挡块编号 101, 101b 是指 b 叉中的挡块编号 101。

起初,这个节点持有两条链并等待一段时间。如果几分钟后生成了一个 102a 块(带有父块 101a ,则发生以下情况:

  • 包含块 102a 的链被认为是当前链,因为它是已知的最长的链。(链条长度也称为高度
  • 具有 101b 的前叉被分开放置,不被视为当前链条。

这对矿工来说有着重要的意义,因为他们可以选择在现有的链条上采矿,也可以尝试在叉子上继续挖掘。因为最长的链是当前的链,所以在另一个分支上提交工作是有风险的,因为采矿的任何回报在现实中没有任何价值。

最明显的选择是在最长的链上挖掘,因为这个链更有可能继续是最长的。如果矿工坚持在滞后的叉/链上采矿,则该叉有可能永远赶不上当前的链长度。因此,为获得奖励和收取费用而参与发电区块发电的所有工作都完全浪费了。

此外,由于每个理性的矿工会选择这个选项,有更多的矿工开采最长的链,因此新块的当前链速度比任何其他链快几个数量级的可能性更高。你可以计算一下,发现追上最长链的概率随着链间长度的不同而呈指数下降。

决定在哪里挖掘未来的块与不变性无关,因为我们考虑的是追加,而不是修改历史。但事实证明,试图修改历史是在有意构建当前链条的分叉。

同样,如果当前区块是 100 号,并且我们试图生成另一个有效区块 90,我们应该与具有 11 个区块滞后的最长链竞争,并且让每个矿工联合起来反对我们在最长链上采矿。所以这是一个巨大的挑战。

我们应该对 11 个街区(从 90 号街区到 100 号街区)供电。这意味着我们自己解决电力问题,导致大量的电力成本,并在这个过程中,在一个仍然不被认为是当前的链上产生回报,因此在现实中仍然没有价值。

当我们再次生成第 100 个块时,我们意识到在这段时间内,其他矿工在开采原始链,现在链长度差异很可能比我们开始时更大。

我们应该有超过 50%的网络散列能力,以真正最终赶上一个分叉链,成为当前链。这取决于我们的散列能力超过网络的散列能力多少,以及你想要修改的块有多旧。这叫做 51%攻击

如果我们只有不到 50%的网络散列能力,那么我们很可能永远也赶不上,因此所有投入到分叉点的电力(因此,成本)都将被完全浪费。

当然,我这里是简化;在中本聪撰写的原创比特币论文第 11 章中有更详细的计算。个人推荐这篇优秀的论文,更详细的了解中本聪的计算和验证。

从整体上考虑网络的哈希能力,任何种类的实体都有能力攻击网络的不变性,这种可能性微乎其微。这就是为什么有时你可能会听,这是一个很好的做法,等待 6 块,大约 1 小时,在您的交易确认后,以确保它是不可变的。你想更安全吗?等 12 个,或者更多。如果你对确切的概率感兴趣,这个计算器很有用。

超分类帐结构不变性

在织物的情况下,不变性分析要简单得多,因为它是一个许可的区块链。由于在网络中有更多的信任,解决这个问题需要更少的工件。

In 结构块由订购服务生成。它的职责是建立网络中交易的总秩序。与比特币一样,块包含交易,每个块包含前一个块的哈希值。

一个通用的生产就绪订购服务由一个 Apache Kafka 集群和一个或多个订购者组成。每个想要发送交易提议的参与者通过 broadcast 接口将其发送给任何一个order,然后order将其作为 Kafka 中的一个消息推送到一个映射到交易的通道分区主题中。

Kafka 完成了为每个通道建立事务总排序的繁重工作,因为每个通道都有一个到主题的一对一映射,而主题只有一个分区。在 Kafka 中,每个分区每个主题的消息保证有一个定义良好的顺序。

在事务在主题上之后,排序器读取分区以生成下一个块。块生成在通道配置中定义了一些确定性规则,它基于块的总大小或基于时间的标准。在后者中,使用来自 Kafka 的元数据,因此不同的排序者将选择包含在块中的相同的有序交易集。

你可能认为这是一个事件源系统,其中任何规则都是基于确定性数据和函数的。事实上,如果所有节点从 Fabric 中消失,但 Kafka 集群仍然存在,我们可以从头开始重建所有块。你的 Kafka 集群是网络安全最重要的组成部分。

然后一个排序器创建一个包含一定数量事务的块,但是这里没有 PoW。为了使该块有效,它应该由一个订购者签名。如果块由来自订购服务的任何订购者签名,则块被视为有效。

**对等点是网络中通过交付接口与排序器接收块的节点。他们验证事务并将其标记为有效或无效(考虑到读写集,以及一系列其他标准),然后修改 CouchDBLevelDB 中的世界状态,并明显地将块附加到分类帐。

通过通道配置,维护通道分类帐副本的对等方知道哪个是订购服务CAs ,因此它可以检查新块是否来自可信来源。如您所见,块生成依赖于对来自订购服务CA 的信任。

很明显,如果任何一个订购者CA 的私钥被泄露,或者不知何故凭空产生了一个新的订购者,那么我们就有大麻烦了。

首先,我们可以想象恶意方可能会生成新的块,并开始混淆网络中的不同对等点,使它们的分类帐出现分歧。此外,如果恶意方作为对等节点参与,那么它可以修改自己的分类帐,因为制作新块就像制作签名一样容易。这包括修改以前存在的任何块。它有改写账本历史的力量。可以进行的修改是块内交易的审查或重组,因为每笔交易都是由客户签名的,不能被篡改。

这听起来很严重…但是如果我们有足够的时间和大量的现金来支付电费,我们也可以改写历史。那有什么区别呢?。在织物中,如果我能以某种方式破解任何订购者的私钥,那么与比特币中永恒而昂贵的程序相比,重写历史是非常便宜和快速的;但是如何让其他同事相信我修改过的账本是真正的账本呢?如果我不能说服别人,我在现实世界中也不能产生太大的影响。在织物如果你是唯一一个有一个有效的,但不同的分类帐相比,世界上其他地方,有些事情听起来很不对劲。

在比特币中,这涉及到以某种方式拥有比当前更长的链,如果我们没有接近网络散列能力的 50%,这将是非常困难的。在 Fabric 的情况下,这实际上是不可能的,原因很简单:分类帐中的分叉被认为是关键情况,节点不会接受它们。这种情况被认为是恶意攻击或系统中的错误。

您可能会想:既然这与块篡改的难度无关,那么在 Fabric 中链接块的目的是什么?在比特币中,区块链是必须的,因为它迫使恶意节点不仅挖掘修改过的区块,还挖掘所有后续的区块。

事实证明,在 Fabric 中,块链接对于保持分类帐的不变性并不重要。该实用程序使分类帐变得显窃启,这意味着很容易检查分类帐是否被修改。如果一个诚实的节点从另一个节点接收到一个块,而它的 hash 与另一个块不匹配(在同一高度),那么我们可以确定它对应的是一个不同的分类帐,出现了危急情况。我们可以进一步调查哪个块是真正的差异,但这个问题可以通过简单快速的检查来检测。

结论

比特币实现不变性的方式与 Hyperledger Fabric 完全不同。当我们谈到区块链时,我们看到一个重要的特性,那就是数据块是用哈希链接起来的。

在比特币中,它对账本不变性的重要性是显而易见的,因为它与不变性的硬度直接相关。我想要修改的块越老,就越难生成足够高的链来说服网络的其余部分。

在 Fabric 中,块链接与篡改分类帐的难度无关;考虑到一个订购者的私钥被泄露,这可以在几秒钟内完成。尽管如此,说服另一个节点改变它的分类帐是不被设计所接受的;叉子是不被接受的,应该需要人工干预,因为这是出了问题的征兆。

本系列涵盖了许多值得更详细讨论的主题,但我希望您会发现它很有用。

Python 中的不可变数据类型与可变数据类型

原文:https://towardsdatascience.com/immutable-vs-mutable-data-types-in-python-e8a9a6fcfbdc?source=collection_archive---------0-----------------------

了解可变数据类型和不可变数据类型之间的区别,以及如何找出哪个是哪个!

到现在为止,你可能听说过“Python 中的一切都是对象”这句话。对象是数据的抽象,Python 有多种多样的数据结构,你可以用它们来表示数据,或者组合它们来创建你自己的定制数据。

Python 对数据的第一个基本区别是对象的值是否会改变。如果值可以改变,对象称为可变,如果值不能改变,对象称为不可变

在这个速成课程中,我们将探索:

  • 可变类型和不可变类型的区别
  • 不同的数据类型以及如何确定它们是可变的还是不可变的

理解可变和不可变之间的区别非常重要,因为它会影响您编写的代码。

我们开始吧!

这个速成课程改编自 Next Tech 的学习 Python 编程课程,该课程使用理论和实践的混合来探索 Python 及其特性,并从 Python 初学者进步到熟练。它包括一个浏览器内沙盒环境,预装了所有必要的软件和库。这里可以免费上手

可变与不可变

首先,理解 Python 中的每个对象都有一个 ID(或标识)、一个类型和值是很重要的,如下面的代码片段所示:

age = 42
print(id(age))    # id
print(type(age))  # type
print(age)        # value [Out:]
10966208
<classint’>
42

一旦创建,对象的 ID 永远不会改变。这是它的唯一标识符,当我们想要使用它时,Python 在幕后使用它来检索对象。

类型也永远不会改变。类型告诉对象支持哪些操作,以及可以分配给它的可能值。

该值可以更改,也可以不更改。如果可以,则称该对象是可变的,如果不能,则称该对象是不可变的。

让我们来看一个例子:

age = 42
print(id(age))
print(type(age))
print(age)age = 43
print(age)
print(id(age)) [Out:]
10966208
<classint’>
42
43
10966240

age的值变了吗?嗯,【T1 号】是一个整数,类型为int,是不可变的。所以,实际上在第一行,age是一个名字,它指向一个int对象,它的值是42

当我们键入age = 43时,所发生的是另一个对象被创建,类型为int,值为43(同样,id也会不同),名字age被设置为指向它。所以,我们没有把那个42改成43。我们实际上只是将age指向了一个不同的位置。

从第二个名为age的对象创建前后的打印id(age)可以看出,它们是不同的。

现在,让我们看看使用可变对象的同一个例子。

x = [1, 2, 3]
print(x)
print(id(x))x.pop()
print(x)
print(id(x)) [Out:]
[1, 2, 3]
139912816421064
[1, 2]
139912816421064

对于这个例子,我们创建了一个名为m的列表,其中包含 3 个整数123。在我们通过“弹出”最后一个值3来改变m之后,m的 ID 保持不变!

因此,int类型的对象是不可变的,而list类型的对象是可变的。现在让我们讨论其他不可变和可变的数据类型!

可变数据类型

可变序列在创建后可以改变。Python 的一些可变数据类型有:列表字节数组集合字典

列表

如前所述,列表是可变的。这里是另一个使用append()方法的例子:

a = list(('apple', 'banana', 'clementine'))
print(id(a))a.append('dates')
print(id(a)) [Out:]
140372445629448
140372445629448

字节数组

字节数组代表了bytes对象的可变版本。它们公开了大多数可变序列的常用方法以及大多数bytes类型的方法。项目是范围[0,256]内的整数。

让我们看一个简单的例子,用bytearray类型来说明它是可变的:

b = bytearray(b'python')
print(id(b))b.replace(b'p', b'P')
print(id(b)) [Out:]
139963525979808
139963525979808

设置

Python 提供了两种集合类型,setfrozenset。它们是不可变对象的无序集合。

c = set((‘San Francisco’, ‘Sydney’, ‘Sapporo’))
print(id(c))
c.pop()
print(id(c)) [Out:]
140494031990344
140494031990344

如你所见,set s 确实是可变的。稍后,在不可变数据类型部分,我们将看到frozenset是不可变的。

字典

d = {
    'a': 'alpha',
    'b': 'bravo',
    'c': 'charlie',
    'd': 'delta',
    'e': 'echo'
}
print(id(d))d.update({
    'f': 'foxtrot'
})
print(id(d)) [Out:]
14007111431940
14007111431940

不可变数据类型

不可变数据类型与可变数据类型的不同之处在于,它们在创建后不能更改。一些不可变类型包括数字数据类型字符串字节冻结集元组

数字数据类型

你已经看到整数是不可变的;同样,Python 的其他内置数值数据类型如布尔、浮点、复数、分数和小数也是不可变的!

字符串和字节

Python 中的文本数据是用str对象处理的,通常称为字符串。它们是不可变的 Unicode 码位序列。Unicode 码位可以表示一个字符。

当涉及到存储文本数据或在网络上发送文本数据时,您可能希望对其进行编码,使用适合您所使用的介质的编码。编码的结果产生一个bytes对象,其语法和行为类似于字符串。

字符串和字节都是不可变的,如下面的代码片段所示:

# string
e = 'Hello, World!'
print(id(e))e = 'Hello, Mars!'
print(id(e)) [Out:]
140595675113648
140595675113776# bytes
unicode = 'This is üŋíc0de'  # unicode string: code points
print(type(unicode))
f = unicode.encode('utf-8')  # utf-8 encoded version
print(type(f))
print(id(f))f = b'A bytes object'        # a bytes object
print(id(f)) [Out:]
<class 'str'>
<class 'bytes'>
140595675068152
140595675461360

在字节部分,我们首先将f定义为我们的unicode字符串的编码版本。正如你从print(type(f))中看到的,这是一款bytes型。然后我们创建另一个名为fbytes对象,其值为b'A bytes object'。两个f对象有不同的 id,这表明字节是不可变的。

冻结集

正如上一节所讨论的,frozensetset相似。但是,frozenset对象在可变对应物方面非常有限,因为它们不能被改变。尽管如此,对于成员测试、并集、交集和差运算以及性能原因,它们仍然被证明是非常有效的。

元组

我们将要看到的最后一个不可变序列类型是元组。元组是任意 Python 对象的序列。在元组中,项目由逗号分隔。这些也是不可变的,如下例所示:

g = (1, 3, 5)
print(id(g))g = (42, )
print(id(g)) [Out:]
139952252343784
139952253457184

我希望你喜欢这个速成班,它讲述了不可变对象和可变对象之间的区别,以及如何找出哪一个是对象!既然您已经理解了 Python 编程的这个基本概念,那么现在您可以探索可以用于每种数据类型的方法。

如果你想学习这方面的知识并继续提高你的 Python 技能,Next Tech 有一个完整的 学习 Python 编程 课程,该课程涵盖:

  • 功能
  • 条件编程
  • 理解和生成器
  • 装饰器、面向对象编程和迭代器
  • 文件数据持久化
  • 测试,包括对测试驱动开发的简要介绍
  • 异常处理
  • 剖析和性能

这里 可以免费上手

自动化对经济的影响

原文:https://towardsdatascience.com/impact-of-automation-on-the-economy-33ef17352f5b?source=collection_archive---------14-----------------------

这篇文章是为 Darakhshan Mir 博士在巴克内尔大学的计算机和社会课程写的。我们讨论技术中的问题,并用伦理框架来分析它们。

Photo by Rock'n Roll Monkey on Unsplash

在一个自动驾驶汽车、智能语音助手和网飞推荐的世界里,有必要就人工智能如何影响社会进行对话。

最近一段时间,我们看到人工智能(AI)出现了巨大的增长。人工智能系统正变得越来越普遍。通常,关于人工智能的讨论围绕着自动化如何影响就业市场。在这篇文章中,我试图回答这个问题,主要是引用弗曼等人的观点。下面,我将讨论就业市场的趋势,以及自动化影响总体经济格局的几种方式。

—就业市场的趋势

1942 年,经济学家约瑟夫·熊彼特创造了短语创造性破坏,指的是一个过程,通过这个过程,一个现有的生产系统被一个更具创新性的系统所取代,从而提高劳动生产率【2】。这样的过程产生了“经济失败者”,他们注定会在变革中遭受损失。一些人可能会被减薪,而另一些人可能会完全失业。凯恩斯将后者描述为,

“由于我们发现节约使用劳动力的方法的速度超过了我们发现劳动力新用途的速度而导致的失业”

Figure 1: A look at which jobs are more likely to be automated based on the skills required for those jobs [6]. If you’re curious about the probability of computerization for a specific job, check out https://willrobotstakemyjob.com/. The estimates are based on US data.

历史证据表明,虽然某些工作可能面临迫在眉睫的风险,但从长远来看,新的工作通常会出现在互补行业[4]。虽然说起来容易做起来难,但重要的是人们要适应这个不断变化的市场。不幸的是,我们已经看到了劳动力参与率的“长期下降”,因为个人无法跟上工作场所所需的技能。这提出了一个关键问题。

谁该为缺乏劳动力参与负责?

使用一组(例如工程师)作为建立系统的手段,将另一组人(例如低技能劳动者)排除在工作之外,技术部门应该受到指责吗?这种排斥在资本主义经济中似乎很难避免,因为企业总是竞相(通过创新)实现利润最大化。那么,是我们的教育制度不能使个人为新的工作做好准备吗?还是政府对人工智能的发展监管过于宽松?

这些都是很难回答的问题,也没有放之四海而皆准的解决方案。即使一个有自动化的社会与没有自动化的社会产生相同或更大的经济产出,忽视(尽管是无意的)最脆弱的利益相关者(即低技能工人)的需求也是不公平的。在这种情况下,我们能希望做的最好的事情就是投资再培训工人,以促进公共利益。

—AI 成长的副作用

初创企业的进入壁垒

自本世纪初以来,人工智能相关的初创企业每天都在获得更多的资金[7]。然而,像谷歌和百度这样的科技巨头主导了大部分投资,而其他公司(科技或其他)则被留下来追赶。这给创造“成熟的人工智能经济”带来了一些挑战,在某种程度上,这为现有者和进入者提供了公平的竞争环境。

Figure 2: Top 35 high tech companies invest a whopping $18-27 bn in AI. Here, M&A refers to mergers and acquisitions and PE refers to Private Equity. To learn more, check the full MGI report.

随着互联网的成熟,我们观察到客户停止使用现有平台并转向新平台的“转换成本”越来越高。像谷歌搜索这样的平台享有先发优势,能够收集他们的用户数据以进一步巩固他们的市场优势。大多数人工智能应用依赖于机器学习[7],因此大数据集的不可用性对人工智能初创公司来说是一个重大障碍。

一些人认为,那些花费资源精心制作一个好数据集的公司应该有权根据需要分发它。另一方面,有理由相信数据本身属于用户。为了解决这些对立的利益相关者利益,[1]提出了数据可移植性的概念,它“允许客户将他们的数据从一个提供商带到另一个提供商。”虽然这是朝着正确方向迈出的一步,但作者也承认,需要进一步的工作来确定大型数据集如何影响市场。

关于数据的可移植性,有关于数据安全性的问题,以及客户是否应该能够“拥有”基于人工智能的应用程序对其行为做出的推断[8]。因此,任何未来的监管第三方机构的作用是确保公司遵守道德数据实践标准,并将用户的福祉(身体、社会或情感)放在首位。

收入不平等

自动化的怀疑者担心人工智能会导致收入水平的巨大差异。弗曼等人写道,

“替代非熟练工人和补充熟练工人的技术将导致非熟练工人的相对工资下降”

这种担忧导致人们重新审视诸如普遍基本收入(UBI)、工资补贴和就业保障等提议。可以理解的是,这些提议没有一个是万无一失的,否则早就付诸实施了。尤其是 UBI,它看起来雄心勃勃,因为除了每年 1 万亿美元的融资之外,它还需要增加近 50%的税收[1]。

正如我们一次又一次看到的那样,收入不平等会导致已经处于不利地位的社会阶层陷入恶性反馈循环。在人工智能取代低技能劳动力的背景下,缩小贫富差距的最佳政策是什么?

—最终想法

我们的社会离“人工智能接管”(一般的人工智能)还很远,我们还没有看到该领域的突破,尽管机器学习中特定任务的进步已经吸引了所有人。然而,这不应该成为我们不去思考如何监管人工智能的借口。

低技能工人尤其容易受到自动化的影响,其中一些人甚至无法从失业中恢复过来。此外,作为一家初创企业,由于缺乏竞争和无法获得“标准化数据集,进入该领域变得越来越困难所有这些都引发了一系列伦理讨论,比如谁应该为工作岗位的流失指责以及谁拥有用户数据的权利,这是每个人工智能应用程序所依赖的关键。

世界各地的政策制定者都试图设计出监管人工智能的框架。然而,正如[9]所指出的,他们都没有讨论他们对未来社会的愿景。这项研究的作者认为,只有了解我们未来的优先事项,我们才能全面解决这篇文章中提出的问题。

参考

[1]弗曼,杰森和罗伯特·西曼。“人工智能与经济。”创新政策与经济 (2019)。

[2]熊彼特,约瑟夫。“创造性破坏。”资本主义、社会主义和民主 825 (1942)。

[3]凯恩斯,约翰·梅纳德。1930.“我们子孙后代的经济可能性。”劝导随笔 (2010)。

[4]戴维·h·奥特尔,“为什么仍然有这么多工作?工作场所自动化的历史和未来。”《经济透视杂志》 (2015)。

5 经济顾问委员会。总裁经济报告 (2016)。

[6]弗雷、卡尔·贝内迪克特和迈克尔·奥斯本。"就业的未来:工作对计算机化有多敏感?"技术预测与社会变革 (2017)。

[7]布欣,雅克等人。艾尔。"人工智能:下一个数字前沿?" MGI 报告,麦肯锡全球研究院(2017 年 6 月)。链接

[8]塔克,凯瑟琳。“隐私和创新。”载于创新政策与经济,第 11 卷(2012)。芝加哥:芝加哥大学出版社。

[9] Cath,Corinne 等人,“人工智能和‘好社会’:美国、欧盟和英国的方法。”科学与工程伦理 (2018)。

[10]史蒂文·n·德劳夫,“持久收入不平等理论”经济增长杂志 1.1 (1996)。

如果你喜欢这个,请看看我的其他媒体文章和我的个人博客。请在下面评论我该如何改进。

自然语言处理中使用迁移学习的影响

原文:https://towardsdatascience.com/impact-of-using-transfer-learning-in-nlp-59ffc4ffb806?source=collection_archive---------30-----------------------

我们分析了基于从零开始训练的语言模型或使用语料库 wikitext-103 的预训练模型对电影评论情感进行分类的影响

Photo by Riccardo Annandale on Unsplash

背景

在 NLP 的不同分类工作中,我们使用了 ULMFiT 。我们可以在用于推文姿态分类的NLP 迁移学习和用于文本分类的通用语言模型微调-ULMFiT 中找到两篇关于这种方法的优秀文章。

ULMFiT 已经在 fastai 库的版本 1 中实现了,他们开发了一些技术,使得迁移学习变得非常方便。

原始文件中,ULMFiT 包括三个阶段:

  • 使用通用领域数据集在捕获高级自然语言特征的语料库上训练语言模型。
  • 调整和微调第一阶段创建的语言模型,并使用迁移学习在目标数据集上创建新的模型语言。
  • 使用在第二阶段调整的模型语言学习来创建和微调分类器。

本文的主要目的是衡量从第三阶段(分类器)、从预先训练的语言模型(第二阶段)或直接从零开始之间的差异和影响。

换句话说,第二阶段模型是在有和没有迁移学习的情况下创建的,比较初始结果。

在本文的第一部分,我们将导入数据集并执行必要的数据转换操作。

然后,我们将测量使用从另一个已经训练好的模型接收迁移学习的语言模型的影响,或者直接从数据集创建语言模型的影响,并比较两种结果。

最后,我们将使用上一节中创建的最好的语言模型来开发 NLP 上的情感分类器。

数据集

用于二元情感分类的数据集由 Andrew Maas 等人管理,包含 IMDB 上总共 100,000 条评论。其中 25,000 个标记为阳性和阴性用于训练;另外 25,000 个被标记用于测试。

还有另外 50,000 个未标记的数据,我们将用于创建我们的模型语言学习。

df = pd.read_csv(path/'texts.csv')
df.head()

第 1 部分-导入数据集和要素工程

“由于文本是由单词组成的,不能直接对它们应用数学函数,我们首先必须将它们转换成数字。在 fastai 中,这是通过两个不同的步骤完成的:标记化和数值化。在 fastai API 中,TextDataBunch 为我们做了这些*。”

%reload_ext autoreload
%autoreload 2
%matplotlib inline
from fastai.text import *
path = untar_data(URLs.IMDB_SAMPLE)
data_lm = TextDataBunch.from_csv(path, 'texts.csv')

标记化

data = TextClasDataBunch.from_csv(path, 'texts.csv')
data.show_batch()

数字化

一旦我们从文本中获得了标记,TextDataBunch 就会通过创建一个包含所有使用过的单词的列表来转换成整数。默认情况下,最大词汇量为 60,000,并替换那些没有被未知令牌 UNK 切断的词汇。

从 id 到令牌的对应关系存储在一个名为 itos 的字典中的 vocab 属性中。

data.vocab.itos[:10]

现在,如果我们查看数据集,我们会看到标记化的文本如下:

data.train_ds[0][0]

如果我们看所有的火车,都是数字:

data.train_ds[0][0].data[:10]

第 2 部分—创建语言模型学习

Photo by Conor Luddy on Unsplash

语言建模

“一个语言模型试图通过层次化的表征来学习自然语言的结构,因而既包含低级特征(词的表征),也包含高级特征(语义)。语言建模的一个关键特征是它是生成性的,这意味着它的目标是在给定一个单词序列的情况下预测下一个单词。它能够做到这一点,因为语言模型通常是以无监督的方式在非常大的数据集上训练的,因此该模型可以以比单词嵌入更深入的方式“学习”语言的句法特征。

在他的文章中,Sebastian Ruder 做了一个非常优雅的工作,强调了为什么语言建模对于广泛的自然语言处理任务如此强大。未标记的语言数据相对容易获得(它可以以大型文本语料库的形式免费获得),因此通过向语言模型提供足够大的数据集,现在可以对数十亿个单词进行无监督的预训练,同时融入更深入的语言语法知识。"⁴

我们将使用 fastai 的 API 中的 language_model_learner,这是一种学习者⁵,它采用一组配置,从数据集中假设一个语言模型。

Language_model_learner 承认属性“pre-trained (Bool)”,其默认选项为 True,并假设每种语言都有一个迁移学习模型。

从头开始创建我们的语言模型学习

这种技术已经被用来为不同的习语创建一个语言模型,这里是一篇文章在 Vietnamese⁶.有一个极好的例子

path = untar_data(URLs.IMDB)
data_lm = (TextList.from_folder(path)
.filter_by_folder(include=['train', 'test', 'unsup'])
.split_by_rand_pct(0.1)
.label_for_lm()
.databunch(bs=bs))data_lm.save('data_lm.pkl')

“我们必须为语言模型使用一种特殊的TextDataBunch,它会忽略标签(这就是为什么我们在任何地方都放 0 ),在将它们连接在一起之前,会在每个时期对文本进行洗牌(仅用于训练,我们不会对验证集进行洗牌),并且会发送按顺序读取该文本的批处理,目标是句子中的下一个单词。*"

data_lm = load_data(path, 'data_lm.pkl', bs=bs)
data_lm.show_batch()

在这里,我们向 API 表明,我们希望“学习”模型不采用预训练迁移学习的默认权重,而是在不假设预训练的情况下开始:

learn = language_model_learner(data_lm, AWD_LSTM, **pretrained=False**, drop_mult=0.3)

在调整学习率和训练之后,我们获得了 0.284114 的准确度

使用预训练模型进行迁移学习

在 fastai 中使用的更大数据集上预先训练的模型是维基百科的一个清理过的子集,名为 wikitext-103

“我们将使用英语语言的‘知识’来构建我们的分类器,但首先,像计算机视觉一样,我们需要根据我们的特定数据集微调预训练模型。因为人们在 IMDB 上留下的评论的英文和维基百科的英文不一样,我们需要稍微调整一下模型的参数。此外,可能有一些词在评论数据集中非常常见,但在维基百科中几乎不存在,因此可能不是模型训练的词汇表的一部分。*"

learn = language_model_learner(data_lm, AWD_LSTM, drop_mult=0.3)
learn.lr_find()
learn.recorder.plot(skip_end=15)

准备要在分类器中使用的模型

不仅要为下一个零件保存模型,还要保存它的编码器。这一部分非常重要,因为要重用这个模型,单词列表和它们的 id 必须相同。

**learn.save_encoder('fine_tuned_enc')**

第 3 部分—电影评论情感分类器:采用模型

Photo by Georgia Vagim on Unsplash

path = untar_data(URLs.IMDB)
data_clas = (TextList.from_folder(path, vocab=data_lm.vocab)
.split_by_folder(valid='test')
.label_from_folder(classes=['neg', 'pos'])
.databunch(bs=bs))data_clas.save('data_clas.pkl')
data_clas = load_data(path, 'data_clas.pkl', bs=bs)

我们创建分类器,并将其指定为前一阶段的编码器。

learn = text_classifier_learner(data_clas, AWD_LSTM, drop_mult=0.5)
**learn.load_encoder('fine_tuned_enc')**

结果……

左边,模型语言从零开始,右边,模型用迁移学习:

最后,在调整学习率和一些额外的训练之后,我们在电影评论数据集上获得了一个准确率为 0.943960 的情感分类器。

摘要

我们已经试验了来自先前数据体的预训练语言模型和从头开始的语言模型的应用,在使用迁移学习时获得了更好的结果。

使用 fastai 和 UMLFiT 的工具,我们可以通过维基百科的数据语料库来应用这一点,以任何语言进行预训练,这在 NLP 中是一个很大的优势,因为工具和数据集的偏见是英语。

最后,记住在语言模型和文本分类器之间保持编码器是非常重要的。这个练习的基础是来自 [fastai 课程](https://fast.ai course/)第 3 和第 4 课的 token,在那里你可以找到完整的代码和对数据集的访问。

我希望这篇文章有助于看到在 NLP 中使用迁移学习的积极影响,类似于在计算机视觉中使用的迁移学习。欢迎任何更正、评论或想法。

参考

[1]https://course.fast.ai/

[2]http://ai.stanford.edu/~amaas/

[3]https://www.imdb.com/

[4]https://towards data science . com/transfer-learning-in-NLP-for-tweet-stance-class ification-8ab 014 da 8d de

[5]https://docs.fast.ai/basic_train.html#Learner

[6]https://towards data science . com/pre-trained-language-model-in-any-language-7531 ea 7217d 4

[*]本文中的许多概念都直接来自于第 3 课和第 4 课 fast.ai 课程

不完美的信息,不完美的超人人工智能

原文:https://towardsdatascience.com/imperfect-information-imperfect-superhuman-ai-58eaba48fe3?source=collection_archive---------29-----------------------

[1]

应该允许 AI 参与我们的赌博吗?卡耐基梅隆大学的脸书人工智能研究人员刚刚创造了一种可以在扑克中击败人的人工智能。这是一项巨大的成就。在扑克游戏中,没有最佳答案,也没有要寻找的一系列赢棋。相反,最大化回报和最小化风险是最好的赌博。但是,我们能负责任地运用训练有素的代理人在不完全信息的情况下取得成功吗?这些类型的超人人工智能会在哪些方面下错赌注,我们如何围绕它们设计系统以造福社会?

[2]

我们来看一个思维实验。医疗诊断和治疗是机器学习研究中最发达和最多产的领域之一。诊断在很大程度上是一个分类问题。你有大量来自患者的输入数据,比如症状数据、环境数据等。机器学习算法用于在大量数据中寻找模式,以诊断患者。通常算法发现的模式是如此错综复杂,以至于专业人士并不总是能理解它们。诊断是一个经典的机器学习应用,伴随着它的伦理问题。为了实验起见,我们假设医生非常敏锐或者一个 ML 算法准确地给出了正确的诊断。

然而,推荐治疗并不是一个标准的分类问题。这是一个不完全信息的游戏。你必须根据个人情况和诊断结果来选择最佳的治疗方案。算法的工作是观察治疗、诊断和个人的各种成功机会,并推荐最佳的治疗方案来挽救他们的生命。他们可能没有时间接受更多的治疗,所以每一个建议都必须是高质量的。这个问题是脸书和 CMU 的研究可能被应用的地方。毕竟,如果每个人都得到正确的诊断,并给予尽可能最好的治疗,那难道不是一个值得建设的世界吗?

[3]

可悲的是,这可能是不可能的。如果我们让一个人工智能代理来推荐治疗,我们可能会发现和医生一样的盲点。推荐治疗方法的代理人可能不得不考虑各种疗法的成功率,作为要分析的许多数据特征的一部分。成功率可能会被 p-hacked,或者不诚实地操纵统计数据,使其高于实际水平。例如,立普妥,一种宣称有 36%成功率而实际只有 1%成功率的药物。人工智能代理推荐治疗方法并查看成功率等指标可能会下错赌注。

医生也可能成为错误成功率的牺牲品。这个弱点就是问题所在。医生和超人 AI 都有同样的缺陷:腐败或有偏见的数据。但是医生可以为他们的诊断提供理由。尽你所能去寻找,但是在 50,000 个矩阵中找出以不同的顺序方式相乘的确切模式并正确识别其原因是不现实的。也许你可以制造一个人工智能来理解并把人工智能的见解翻译成人类的理解,但是你会再次遇到同样的问题。

即使我们能够在信息不完善的领域超越人类,我们仍然依赖于手头问题的准确和无偏见的数据。赌一赌这是否可能是人工智能未来的一个关键问题。

[4]

图片来源:【1】【2】【3】【4】

使用 Python Pandas 数据帧与最小堆数据结构

原文:https://towardsdatascience.com/implement-a-min-heap-to-solve-performance-issue-with-data-processing-1f7f891a4ec0?source=collection_archive---------17-----------------------

Photo by Marian Kroell on Unsplash

介绍

最近我花了很多时间研究基本的数据结构,包括栈、队列、堆和树。它教会了我用以下不同的方式解决问题(代码):

  • 总是寻找最简单、最有效、最优雅的方式(可读性是金)
  • 审查,审查和审查,以提高代码的效率(是否有重复的部分?我能换一种方式做吗?有些步骤是多余的吗?)
  • 在选择你可以使用的工具(框架、数据结构、算法)时,要实际考虑

阅读理论只是一个开始,在我看来,巩固所学知识的最好方法是将其应用到现实世界的问题中。幸运的是,我参与的一个项目中有一部分可以利用Min Heap的实现,也就是通常所说的Priority Queue

An example of a Binary Min Heap, visualised in a tree structure.

我在下面几节中概述了实现:

  • 问题是
  • 在最小堆实现之前
  • 在最小堆实现之后
  • 参考

问题是

任务很简单:从所有满足包含依赖规则的输入表中找到所有列对。规则是,对于每个列对,一列的所有值都必须存在于它的列对中。下面是为了更容易理解的例子。

In Example 1, there were 2 checks performed: 1) column A in column B and 2) column B in column A. The valid column pair in this example is 2) column B in column A, because all values in column B exists in column A (inclusion dependency rule satisfied). In Example 2, both checks 1) column C in column D and 2) column D in column C are invalid, because the value LL300 only exists in column D.

现在,您可能会想,为什么要让事情变得复杂呢?您可以通过检查每一对,一列中的所有值是否都包含在另一列中,来应用强力方法。问题是大约有 900 个表,每个表都有不同数量的列。简而言之,当使用暴力方法时,要花很长时间来完成检查。

在最小堆实现之前

我最初的方法比暴力方法稍微好一点,但是,它仍然需要很长时间来运行。本质上,应用了Single Pass算法。这意味着在找出列对时,所有数据(或值)将只被读取一次,而不是多次(想想暴力方法,您将多次读取相同的列/值)。

为此,我使用pandas库构建了一个单独的data frame,存储所有表中的所有列,包括它们的值。最后的data frame看起来是这样的。

A       B     C
index
0        nan     0.0   0.0
1        1.0     nan   1.0
2        2.0     nan   2.0
3        nan     3.0   3.0

让我通过这些步骤来了解上面的data frame:

  • 对于每个表中的每一列,将其唯一值存储在一个list中,按升序排序
  • 从所有列中获取所有唯一值,将它们存储在一个list中,按升序排序,例如按照上述data frame[0, 1, 2, 3]
  • 构造一个data frame并将其index设置为包含来自步骤 2 的所有唯一值的list
  • 通过index上的left join合并从步骤 1步骤 3 的所有列表(当一列没有特定值时,会在最后的data frame中产生一个nan条目),例如,列A没有[0, 3]

注意,由于*nan*值的形成,*data frame*中的列类型不是*float64*。那些列的原始值实际上是*int64*

在迭代data frame中的每一行之前,我们需要初始化一个包含初始包含依赖列列表的dictionary。等等,什么?让我给你展示一下dictionary的样子,让你明白这一点。

inclusion_dict = {'A': ['B', 'C'],
                  'B': ['A', 'C'],
                  'C': ['A', 'B']}

现在更有意义了?因此,基本上,我们初始化所有可能的列对(例如,列 B 中的列 A,列 C 中的列 A,表示为字典条目'A': ['B', 'C'],等等。)作为我们迭代前的起点。当我们迭代data frame中的每一行时,inclusion_dict将会相应地更新(更多信息见下文)。

好了,让我们来谈谈迭代。下面是执行迭代的代码。

def sp_algorithm(dataframe, inclusion_dict): # for each value, get all columns that contains it
    for val in dataframe.index: cols_list = dataframe.columns[dataframe.isin([val]).any()] # for each column in inclusion_dict.keys(), intersect its values with cols_list to get the remaining column pairs candidates
        for key_col in inclusion_dict.keys(): column_val = dataframe.loc[val, key_col]# if the current column value is null, then do nothing
            if (column_val == column_val) & (column_val != ''):
                col_dict[key_col] = list(set(col_dict[key_col]).intersection(cols_list))

提醒一下,这是data frame

A       B     C
index
0        nan     0.0   0.0
1        1.0     nan   1.0
2        2.0     nan   2.0
3        nan     3.0   3.0

data frame行的每次迭代中,会发生以下情况:

  • cols_list:获取包含当前索引值的所有列(只是它们的名称)val
  • 对于inclusion_dict中的每一列(字典的key),根据位置.locdata frame中获取其值
  • 检查第二步的值是否为nan和/或'',如果不是,通过与cols_list相交更新inclusion_dict。例如,在上面的data frame的第一次迭代中,cols_list将是['B', 'C'],因为它们包含值0。当我们查找inclusion_dict时,key_col = 'A'将被跳过,因为它在if statement中返回False,因为它是nan(参见data frame中索引0处的A列)。对于key_col = 'B',我们将把它当前的inclusion_dict值与cols_list相交,这样我们就有了['C']。这是因为['A', 'C'] ['B', 'C']相交的就是['C']。对于key_col = 'C',其inclusion_dict剩余值将为['B']

嗯,上面的一系列代码实际上工作并产生了我想要的结果,但是,运行时间非常慢!所以,我开始问自己一个问题,如果数据库大得多,如果有更多的表和列要处理怎么办?

此外,每次在sp_algorithm运行时代码中出现错误,我都必须从头重新运行整个程序,这花费了我很长时间。代码看起来也不可读,难以理解,并且可能不可持续。

在最小堆实现之后

多亏了Min Heap数据结构,我能够将运行时间提高 10 到 60 倍,这取决于数据库(大小、表计数、列计数、唯一值计数等。)!

无论如何,这是一个巨大的进步!我不必整夜运行我的代码,希望没有任何东西会中断,并在早上第一件事就是检查它。现在,我可以随时运行代码,并在几分钟内得到结果,而不是几个小时。

事不宜迟,下面是实现代码。

# inclusion_dict from above
inclusion_dict = {'A': ['B', 'C'],
                  'B': ['A', 'C'],
                  'C': ['A', 'B']}# instead of a data frame, a dictionary is used to store columns from all tables
# column_dict stores sorted (ascending order) unique values from all columns from all tables
column_dict = {'A': [1, 2], 
               'B': [0, 3],
               'C': [0, 1, 2, 3]}def sp_algorithm(column_dict):
    # initialise min heap
    min_heap = [] for column in column_dict:
        vals = column_dict[column] for val in vals:
            tup = (val, column)
            heapq.heappush(min_heap, tup) while min_heap: # get the smallest value in the heap
        att = [] current_smallest, var = heapq.heappop(min_heap)
        att.append(var) # pop all elements where values are equal to current smallest and put them in att list
        while min_heap and min_heap[0][0] == current_smallest:
            next_var = heapq.heappop(min_heap)[-1]
            att.append(next_var) # update inclusion_dict
        for a in att:
            if a in inclusion_dict:
                inclusion_dict[a] = list(set(inclusion_dict[a]).intersection(att))# final inclusion_dict should look like
inclusion_dict = {'A': ['C'],
                  'B': ['C'],
                  'C': []}

inclusion_dict最后的结果基本上说:

  • 列 A 可能依赖于列 C,因为它的所有值都在列 C 中
  • 列 B 可能依赖于列 C,因为它的所有值都在列 C 中
  • 列 C 在此上下文中没有依赖关系,因为列 A 和列 B 都不包含列 C 中的所有值

我希望这能给你一个在项目中实现*Min Heap*的潜在好处的想法。正如我前面提到的,思考并重新思考你可以使用哪些工具,并明智地选择。

Min Heap背后的理论不在本文讨论范围之内。本文的主要目的是向您展示一个真实世界中的Min Heap实现。别担心,只要在谷歌上搜索一下,你就会在Min Heap上找到大量的资源。

参考

上面描述的技术来自一篇讨论单程包含依赖识别(SPIDER) 算法的论文。你可以在这里了解更多信息

前往章节 2.2.22.2.3 了解蜘蛛算法的更多细节。

Heap理论而言,你可以在谷歌上找到很多参考资料。这里有一本你可以读。

最后的话

这是我写的第一篇有点冗长的文章,所以,如果你觉得有用,请留下你的反馈、评论或给我鼓掌或加书签。

欢迎提出任何问题或在下面留下建议。

干杯!🙂

使用 Python 在不到 3 分钟的时间内实现人脸检测

原文:https://towardsdatascience.com/implement-face-detection-in-less-than-3-minutes-using-python-9f6b43bb3160?source=collection_archive---------5-----------------------

使用这个简单的代码将人脸检测功能添加到您的应用程序中

Face detection (Image by teguhjati pras from Pixabay)

人脸检测是人工智能最常见的应用之一。从智能手机中的相机应用到脸书的标签建议,人脸检测在应用程序中的使用每天都在增加。

人脸检测是计算机程序在数字图像中识别和定位人脸的能力。

随着应用程序中对人脸检测功能的需求不断增加,每个人都希望在自己的应用程序中使用人脸检测,这样他们就不会在竞争中落后。

在这篇文章中,我将教你如何在不到 3 分钟的时间内为自己建立一个人脸检测程序。

如果尚未安装以下 python 库,则需要进行安装:

opencv-python
cvlib

下面是导入所需 python 库、从存储中读取图像并显示它的代码。

# import libraries
import cv2
import matplotlib.pyplot as plt
import cvlib as cvimage_path = 'couple-4445670_640.jpg'
im = cv2.imread(image_path)
plt.imshow(im)
plt.show()

Couple Photo (Image by Sonam Prajapati from Pixabay)

在加载的图像中检测人脸,在检测到的人脸周围绘制一个边界框,并显示带有检测到的人脸的最终图像的代码如下。

faces, confidences = cv.detect_face(im)# loop through detected faces and add bounding box
for face in faces: (startX,startY) = face[0],face[1]
    (endX,endY) = face[2],face[3] # draw rectangle over face
    cv2.rectangle(im, (startX,startY), (endX,endY), (0,255,0), 2)# display output        
plt.imshow(im)
plt.show()

Result of Face Detection on couple image

你已经准备好了面部检测程序。就这么简单!

觉得这个帖子有帮助? 在下面留下你的想法作为评论。

点击这里 阅读我其他关于 AI/机器学习的帖子。

要了解更多关于 cvlib 库的信息,可以访问下面的链接。

[## cvlib

用于 Python 的高级易用开源计算机视觉库。它的开发重点是实现简单的…

www.cvlib.net](https://www.cvlib.net/)

为了理解人脸检测是如何工作的,这里有一些进一步的阅读:

[## FaceNet:人脸识别和聚类的统一嵌入

尽管最近在人脸识别领域取得了重大进展,但实现人脸验证和识别…

arxiv.org](https://arxiv.org/abs/1503.03832) [## 卷积神经网络| Coursera

从 deeplearning.ai 学习卷积神经网络。本课程将教你如何构建卷积神经网络…

www.coursera.org](https://www.coursera.org/learn/convolutional-neural-networks) [## 深度学习计算机视觉 CNN、OpenCV、YOLO、SSD 和 GANs

深度学习计算机视觉使用 Python & Keras 实现 CNN、YOLO、TFOD、R-CNN、SSD & GANs+A 免费…

www.udemy.com](https://www.udemy.com/master-deep-learning-computer-visiontm-cnn-ssd-yolo-gans/)

用 Q-Learning 实现网格世界

原文:https://towardsdatascience.com/implement-grid-world-with-q-learning-51151747b455?source=collection_archive---------3-----------------------

强化学习在网格游戏中的应用

之前的故事中,我们谈到了如何使用值迭代实现一个确定性的网格世界游戏。这一次,让我们进入一种更普遍的强化学习形式——Q 学习。

提高一个档次

鉴于 V(s) 是从状态到该状态的估计值的映射,Q 函数— Q(s,a) 只是与 V 函数不同的一个分量。当你处于特定的状态时,不要认为你得到了一个值,向前想一步,你处于一种状态,通过采取特定的行动,你得到了相应的值。本质上,这两种功能没有区别,只是通过将状态与行动绑定在一起方便了我们的生活。例如,回想一下使用值迭代的 grid world 的结果,我们得到了每个状态的估计值,但是为了拥有我们的策略 π(s,a) ,这是从状态到动作的映射,我们需要更进一步,选择可以达到下一个状态的最大值的动作。然而,在 Q 函数中,状态和动作首先是成对的,这意味着当一个人拥有最佳 Q 函数时,他就拥有该状态的最佳动作。

除了 Q-function,我们还将为我们的游戏增添更多乐趣:

  • 代理操作是不确定的
  • 报酬随比率γ衰减

非确定性意味着代理将不能去它想要去的地方。当它采取一个动作时,它将有可能在不同的动作中崩溃。

衰变率γ在 0 和 1 之间。它表示代理人对未来奖励的关心程度,1 表示奖励永不衰减,代理人同样关心未来的所有奖励,0 表示代理人只关心当前状态的奖励。这个因素有助于调整代理人的长期愿景——想象一下像围棋这样的战略游戏,有时在当前状态下看似愚蠢的行动在长期利益和胜利方面是值得的。

就是这样!让我们着手实施。[ 完整代码

电路板设置

Board

董事会设置与之前讨论的基本相同,唯一的区别是代理采取行动。当它采取行动时,它将有 0.8 的概率进入期望的状态,并有相等的概率处于垂直状态。也就是说,如果代理人选择向上,那么它有 0.8 的概率向上,0.1 的概率向左和向右。

在确定代理的下一个位置时,我们将采取返回chooseActionProb()的操作,并利用我们已经定义的nxtPosition()函数。

nxtPosition()函数接受一个动作,验证该动作的合法性并返回该动作的状态。

代理人

让我们跳到主课程——如何通过迭代计算和更新 Q 值。

Q-value update

首先,在每一步,代理采取行动a,收集相应的奖励r,并从状态s移动到s'。所以每一步都要考虑一整对(s, a, s',r)

其次,我们给出当前 Q 值的估计,它等于当前奖励加上下一状态的最大 Q 值乘以一个衰减率γ。值得注意的一点是,我们将所有中间奖励设置为 0,因此代理在结束状态之前无法收集任何非零奖励,无论是 1 还是-1。(这不是强制性的,你可以尝试其他奖励,看看代理如何行动)

最后,我们通过将α乘以一个时间差(新的估计值和当前值之间的差)来更新当前 Q 值的估计值。

q 值初始化

整个更新与值迭代非常相似,尽管 Q value 认为动作和状态是一对。当初始化 Q 值时,我们需要将每个状态和每个动作设置为 0,并将它们存储在字典中作为Q_value[state][action]=0

行动

就采取行动而言,仍将基于我们在勘探&开采中讨论的勘探率。当代理利用状态时,它将根据当前估计的 Q 值采取最大化 Q 值的行动。

更新 Q 值

类似于数值迭代, Q 数值更新也是以相反的方式进行,每次更新将在游戏结束时进行。

在游戏结束时,我们显式地将最后一个状态的所有行为设置为当前奖励,即 1 或-1,但这部分是可选的,它有助于更快地收敛。以下部分与值迭代相同,只是我们在这里加了一个decay_gamma(注:self.decay_gamma * reward应该是self.decay_gamma * reward + 0作为我们设置为 0 的当前状态的奖励)。

玩游戏

我们开球吧!玩了 50 轮之后,我们有了下面的状态-动作对的更新。

result after 50 rounds

我们从(2, 0)开始,最大行动应该是值为0.209up,然后到达(1, 0),从那里最佳行动仍然是值为0.339up,以此类推……最后我们得到我们的策略up -> up -> right -> right -> right。我们可以看到,通过传播和更新,我们的代理足够聪明,可以在每个状态下产生最佳行动。Q-learning 的一个好处是,与基本值迭代相比,我们可以直接获得每个状态下的最佳行动。

请在这里查看完整代码,如果您发现任何警告,欢迎评论或投稿!

在 R 中实现随机森林

原文:https://towardsdatascience.com/implement-random-forest-in-r-b00b69eb8501?source=collection_archive---------13-----------------------

随机森林在乳腺癌患者分类中的实际应用

Photo by Rural Explorer on Unsplash

什么是随机森林(RF)?

为了理解 RF,我们需要首先理解决策树。 Rajesh S. Brid写了一篇关于决策树的详细文章。我们不会过多地讨论决策树的定义,因为这不是本文的目的。我只想快速总结几点。决策树是一系列是/否问题。对于树的每一级,如果你的答案是肯定的,你就属于一个类别,否则,你就属于另一个类别。你将回答这一系列是/否的问题,直到你到达最后一类。你将被归入那一组。

Taken from here

对于我们用来训练的数据,树工作得很好,但是当涉及到新的数据样本时,它们的表现并不好。幸运的是,我们有随机森林,它是许多具有灵活性的决策树的组合,因此导致了准确性的提高。

在这里,我不会过多地讨论 RF 的细节,因为我们可以从外部的各种来源了解它背后的数学原理。这里的就是其中之一。

本文更多的是关于 RF 在癌症患者分类中的实际应用,所以我将直接进入编码部分。现在让我们打开 Rstudio,动手干一场:)

在 R 中实现 RF

首先,我们需要加载以下包。如果您不能加载它们,很可能您还没有安装它们。所以请在加载下面的包之前先这样做。

library(ggplot2)
library(corrplot)
library(reshape2)
library(ggthemes)
library(dplyr)
library(randomForest)
Wisconsin = read.table(url(paste0("[https://archive.ics.uci.edu/ml/machine-learning-databases/](https://archive.ics.uci.edu/ml/machine-learning-databases/)",
"breast-cancer-wisconsin/wdbc.data")),header=FALSE,sep=",",nrows=570)

我直接从 web 链接中读取数据,并将数据集命名为 Wisconsin。让我们稍微检查一下数据

head(Wisconsin)

V1 是 ID,所以它与我们这里的分析无关。V2 是分类结果,“M”代表“恶性”,“B”代表“良性”。剩下的只是关于癌症诊断信息的变量。

现在我想把 M 和 B 改成真和假,以便于解释。

Wisconsin$V2 <- Wisconsin$V2 == “M”

预处理数据

首先,我们将数据混洗并分成训练和测试。我们决定七三分成。

set.seed(2019)test_size = floor(0.3 * nrow(Wisconsin))
samp = sample(nrow(Wisconsin), test_size,replace = FALSE)y_train = Wisconsin[-samp,2]
x_train = Wisconsin[-samp,-c(1,2)] #since the first column is just ID
y_test= Wisconsin[samp,2]
x_test = Wisconsin[samp,-c(1,2)] #since the first column is just ID**#convert labels to categorical**
y_train = factor(y_train)
y_test = factor(y_test)

我们应该注意,RF 只在响应变量是一个 因子 时才起作用。刚才我们把‘M’和‘B’转换成 TRUE 和 FALSE 的时候,这个变量的类型是逻辑的。因此,我们需要使用 factor()函数将其转换为 factor。

现在让我们将 x 和 y 组合起来,形成训练集和测试集。

#Create training set and testing set
train = cbind(y_train,x_train)
test = cbind(y_test,x_test)

训练集将用于训练 RF 模型,测试集将用于测试模型的性能。现在让我们给我们的响应变量命名。在这里,我把它命名为“标签”

colnames(train)[1] = ‘label’
colnames(test)[1] = ‘label

它现在看起来像这样

拟合随机森林模型

现在一切准备就绪。我们可以开始拟合模型了。这一步很容易。

包中的“randomForest()”函数使随机森林模型适合数据。除了包括数据集和指定公式和标签之外,该函数的一些关键参数包括:

  1. ntree :要种植的树木数量。默认值为 500。

  2. mtry :每次分割随机选择的变量个数。在这个例子中,我们使用 p 的平方根(p 表示预测值的数量)。请注意,对于回归分析,一般规则是使用 mtry = p/3,这也是该参数在回归中的默认值。

3.重要性:如果为真,模型将计算特征的重要性,以供进一步分析。(默认值=假)

4.邻近度:如果为真,模型将包含一个 N*N 矩阵,代表邻近度。

  1. maxnodes :树可以拥有的最大终端节点数。

6.动作:指定如何处理缺失数据的功能。

由于有 30 个独立变量,我们将 mtry 设为 30 的平方根,然后拟合模型

mtry = sqrt(30)
model_1 = randomForest(label~., data = train, importance = TRUE)

就是这样。简单不是吗?现在我们已经有了一个射频模型

print(model_1)

出袋 OOB 误差估计率为 3%,这是非常好的,即 97%的准确度。如果我们看混淆矩阵,我们可以看到分类误差相当低。这表明我们的 RF 模型在分类训练集方面表现良好。

让我们用测试集来测试这个模型。

pred_1 = predict(model_1, x_test)
table(y_test, pred_1)accuracy_m1 = mean(y_test == pred_1)

看起来我们的模型在测试集上表现也很好,准确率达到 95%。

可变重要性

varImpPlot(model_1)

Importance of variables in the model. The higher the rank, the more important the variables

我们可视化绘图的另一种方法是使用 ggplot 包。请注意,下面的代码是为了可视化“平均降低准确度”。要得到“平均下降基尼系数”,只需将下面的粗体字改为“MeanDecreaseAccuracy”(无间距)。

importance = importance(model_1)
varImportance = data.frame(Variables = row.names(importance),
 Importance =round(importance[, “**MeanDecreaseAccuracy**”],2))rankImportance=varImportance%>%mutate(Rank=paste(‘#’,dense_rank(desc(Importance))))ggplot(rankImportance,aes(x=reorder(Variables,Importance),
 y=Importance,fill=Importance))+ 
 geom_bar(stat=’identity’) + 
 geom_text(aes(x = Variables, y = 0.5, label = Rank),
 hjust=0, vjust=0.55, size = 4, colour = ‘white’) +
 labs(x = ‘Variables’) +
 coord_flip() + 
 theme_classic()

Mean Decrease Accuracy

结果和我们之前得到的图类似。结果显示变量 V25、V30、V26 和 V23 是最重要的。

Mean Decrease Gini

使用平均下降基尼系数,我们得到 V25、V23 和 V26 作为最重要的变量。

结论

本文展示了如何实现一个简单的随机森林模型来解决分类问题。我没有深入研究如何调整参数以优化模型,因为分类的准确度如此之高,我认为简单的模型就足够了。然而,在现实生活中,还有其他更复杂的分类问题需要我们调整参数以获得最佳模型,我将在下一次单独撰写一篇文章。但重要的是要记住总是从简单的模型开始,然后从那里建立模型以获得更好的预测。

谢谢你的时间。我希望这篇文章能帮助你们,尤其是那些以前从未尝试过在 R 中实现 RF 的人,更好地了解如何实现。如果您有任何意见或问题,请告诉我。

祝您愉快,编程愉快:)

使用非最大抑制(NMS)实现平均精度(mAP)

原文:https://towardsdatascience.com/implementation-of-mean-average-precision-map-with-non-maximum-suppression-f9311eb92522?source=collection_archive---------10-----------------------

实现对象检测的度量

写完你的 CNN 物体检测模型后,你可能会认为最艰难的部分已经过去了。衡量你的物体探测器表现如何的标准呢?衡量异议检测的标准是映射。为了实现 mAP 计算,工作从来自 CNN 对象检测模型的预测开始。

非最大抑制

诸如 Yolov3 或更快的 RCNN 的 CNN 对象检测模型产生比实际需要更多的边界框(bbox)预测。第一步是通过非最大值抑制来清理预测。

ground truth bbox (Blue), predicted bbox (light pink), averaged predicted bbox (red)

上图显示了一个图像,其中蓝色矩形是基本事实边界框。浅粉色矩形是预测的边界框,其具有超过 0.5 的客观性,即边界框中存在对象的置信度得分。红色边界框是由浅粉色边界框平均得到的最终预测边界框。浅粉色包围盒到红色包围盒的平均称为非最大值抑制。

https://github.com/eriklindernoren/PyTorch-YOLOv3提供了 Yolov3 预测后的非最大值抑制和 mAP 计算的详细实现,如本文所述。每个 Yolov3 的预测由右上边界框坐标(x1,y1)、左下边界框坐标(x2,y2)、对象置信度(Objectness)和每个类的分类置信度(C1,..C60,如果边界框内容可以被分类为 60 个类别)。对于每个图像,假设预测了 10654 个初始边界框,仅保留 6 个具有高于 0.5 的客观置信度的预测。在 6 个边界框中,彼此具有高重叠(高 IOU)并且预测相同类别的边界框被一起平均。这些步骤的详细说明解释如下:

真阳性检测

一旦最终预测被确定,预测的边界框可以相对于地面真实接地框被测量,以产生 mAP 来查看对象检测器做得有多好。为此,需要确定真正阳性的数量。如果预测的边界以 IOU 阈值(0.5)与基本真实边界框重叠,则认为是成功的检测,并且预测的边界框是真的正的。如果预测的边界框与基本事实的重叠小于阈值,则认为是不成功的检测,并且预测的边界框是假阳性。精确度和召回率可以通过真阳性和假阳性来计算,如下所示:

详细的实现如下所示。对于一批中的每个图像,对于图像中的每个预测边界框,如果边界框的预测类别不是图像中的目标类别之一,则将边界框记录为假阳性,否则,检查预测边界框与图像中的所有目标框,并获得与目标框的最高重叠。如果最高重叠大于 IOU 阈值,则认为目标框被成功检测到,并且预测的边界框被记录为真阳性。否则边界框被记录为假阳性。隐藏成功检测到的目标框,并继续循环以检查其他预测的边界框。返回每个预测的对象、其预测的类别以及它是否为真阳性。这些步骤的详细说明如下所示:

地图计算

上述步骤的输出用于计算 mAP。按照反对程度的降序对预测进行排序。从具有最高客观性的预测开始,在每次增量预测之后,测量召回率(真阳性的计数/全局所有目标框的计数)和精确度(真阳性的计数/到目前为止的预测计数),并绘制召回率对精确度曲线。曲线下的区域就是地图。计算的面积为矩形,因此图形的三角化部分被忽略。可以为每一类预测计算 mAP,然后对所有类进行平均。感谢https://medium . com/@ Jonathan _ hui/mAP-mean-average-precision-for-object-detection-45c 121 a 31173对地图的详细讲解。召回率对精确度曲线的绘制如下所示:

dataframe for Recall-Precision graph (left), Recall-Precision graph (right)

详细的实现如下所示。按照客观性降序排列真阳性记录、客观性记录和类别记录。对于每个类,按照排序顺序,在每次增量预测后,从真阳性记录中找出累积的真阳性和假阳性。通过将累积的真阳性分别除以基础真值和预测的数量(真阳性+假阳性),找到相应的召回率和精确度值。计算每一类的曲线下面积。这些步骤的详细说明如下所示:

https://github.com/eriklindernoren/PyTorch-YOLOv3的 test.py 和 utils/utils.py 可以参考 NMS 和 mAP 的完整实现。

RNN、LSTM 和 GRU 的实施情况

原文:https://towardsdatascience.com/implementation-of-rnn-lstm-and-gru-a4250bf6c090?source=collection_archive---------4-----------------------

Recurrent Neural Network

递归神经网络是一类人工神经网络,其中节点之间的连接沿着时间序列形成有向图。与前馈神经网络不同,递归神经网络使用其内部状态存储器来处理序列。递归神经网络的这种动态行为使得它们非常有用,并且可应用于音频分析、手写识别和一些这样的应用。

Keras 中简单的 RNN 实现。

数学上,简单的 RNN 可以用公式表示如下:

其中 x(t)和 y(t)是输入和输出向量,Wᵢₕ、Wₕₕ和 Wₕₒ是权重矩阵,fₕ和 fₒ是隐藏和输出单元激活函数。

具有 2 个简单 RNN 层的 RNN 的实现可以如下所示,每个层具有 32 个 RNN 单元,随后是用于 10 个类别分类的时间分布密集层:

def get_model(_rnn_nb, _fc_nb):spec_start = Input((256,256))
 spec_x = spec_start
 for _r in _rnn_nb:
 spec_x = SimpleRNN(_r, activation=’tanh’, dropout=dropout_rate, recurrent_dropout=dropout_rate, return_sequences=True)(spec_x)for _f in _fc_nb:
 spec_x = TimeDistributed(Dense(_f))(spec_x)
 spec_x = Dropout(dropout_rate)(spec_x)spec_x = TimeDistributed(Dense(10))(spec_x)
 out = Activation(‘sigmoid’, name=’strong_out’)(spec_x)_model = Model(inputs=spec_start, outputs=out)
 _model.compile(optimizer=’Adam’, loss=’binary_crossentropy’,metrics = [‘accuracy’])
 _model.summary()
 return _model

参数:

rnn_nb = [32, 32] # Number of RNN nodes. Length of rnn_nb = number of RNN layers
fc_nb = [32] # Number of FC nodes. Length of fc_nb = number of FC layers
dropout_rate = 0.5 # Dropout after each layer

模型总结如下:

Summary.

LSTM 在喀拉斯的实施。

LSTM,也被称为长短期记忆,是一种具有反馈连接的 RNN 架构,这使得它能够执行或计算图灵机可以执行的任何事情。

单个 LSTM 单元由一个单元、一个输入门、一个输出门和一个遗忘门组成,这有助于单元记忆任意时间的值。这些门控制着进出 LSTM 细胞的信息流。

LSTM 单元的隐藏状态 hₜ可以计算如下:

这里, i,f,o分别称为输入、遗忘和输出门。注意,它们具有完全相同的方程,只是具有不同的参数矩阵( W 是在前一隐藏层和当前隐藏层的递归连接, U 是将输入连接到当前隐藏层的权重矩阵)。

LSTM 的 Keras 实现具有 2 层 32 个 LSTM 单元,每层用于上述 10 个类别分类的任务,可以说明如下:

def get_model(_rnn_nb, _fc_nb):spec_start = Input((256,256))
 spec_x = spec_start
 for _r in _rnn_nb:
 spec_x = LSTM(_r, activation=’tanh’, dropout=dropout_rate, recurrent_dropout=dropout_rate, return_sequences=True)(spec_x)for _f in _fc_nb:
 spec_x = TimeDistributed(Dense(_f))(spec_x)
 spec_x = Dropout(dropout_rate)(spec_x)spec_x = TimeDistributed(Dense(10))(spec_x)
 out = Activation(‘sigmoid’, name=’strong_out’)(spec_x)_model = Model(inputs=spec_start, outputs=out)
 _model.compile(optimizer=’Adam’, loss=’binary_crossentropy’,metrics = [‘accuracy’])
 _model.summary()
 return _model

参数:

rnn_nb = [32, 32] # Number of RNN nodes. Length of rnn_nb = number of RNN layers
fc_nb = [32] # Number of FC nodes. Length of fc_nb = number of FC layers
dropout_rate = 0.5 # Dropout after each layer

模型总结如下:

Summary.

GRU 在喀拉斯的实施。

GRU 被称为门控循环单元,是一种 RNN 建筑,类似于 LSTM 单元。GRU 由复位门和更新门组成,而不是 LSTM 的输入、输出和遗忘门。

复位门决定如何将新的输入与先前的存储器相结合,而更新门定义要保留多少先前的存储器。如果我们将 reset 设置为全 1,将 update gate 设置为全 0,我们又会得到简单的 RNN 模型。

对于 GRU,隐藏状态 hₜ可以计算如下:

这里 r 是复位门, z 是更新门。

GRU 的实施情况可以说明如下:

def get_model(_rnn_nb, _fc_nb):spec_start = Input((256,256))
 spec_x = spec_start
 for _r in _rnn_nb:
 spec_x = GRU(_r, activation=’tanh’, dropout=dropout_rate, recurrent_dropout=dropout_rate, return_sequences=True)(spec_x)for _f in _fc_nb:
 spec_x = TimeDistributed(Dense(_f))(spec_x)
 spec_x = Dropout(dropout_rate)(spec_x)spec_x = TimeDistributed(Dense(10))(spec_x)
 out = Activation(‘sigmoid’, name=’strong_out’)(spec_x)_model = Model(inputs=spec_start, outputs=out)
 _model.compile(optimizer=’Adam’, loss=’binary_crossentropy’,metrics = [‘accuracy’])
 _model.summary()
 return _model

参数:

rnn_nb = [32, 32] # Number of RNN nodes. Length of rnn_nb = number of RNN layers
fc_nb = [32] # Number of FC nodes. Length of fc_nb = number of FC layers
dropout_rate = 0.5 # Dropout after each layer

模型摘要:

Summary.

网络的比较。

  • 从我的经验来看,如果你在做语言建模(不确定其他任务),GRUs 在较少的训练数据上比 LSTMs 训练得更快和表现更好。
  • gru 更简单,因此更容易修改,例如在网络有额外输入的情况下增加新的门。一般来说代码更少。
  • 理论上,lstm 应该比 GRUs 记住更长的序列,并且在需要模拟远距离关系的任务中胜过它们。
  • 从上面的模型总结中可以看出,gru的参数复杂度也比 LSTM 低。
  • 简单的 rnn 只有简单的循环操作,没有任何门来控制信元之间的信息流。

如何使用合适的批量获得 4 倍的加速和更好的泛化能力

原文:https://towardsdatascience.com/implementing-a-batch-size-finder-in-fastai-how-to-get-a-4x-speedup-with-better-generalization-813d686f6bdf?source=collection_archive---------7-----------------------

有一次在推特上,我看到了杰瑞米·霍华德引用 Yann LeCun 关于批量的对话:

Batch size discussion on Twitter

自从我遇到 Fastai 的非常好的学习率查找器以来,这个主题一直在我脑海中的某个部分,我一直想知道是否有一个有用的批量大小查找器,人们可以使用它快速开始训练他们的模型具有良好的批量大小。

作为一个提醒,Fastai 中使用的学习率查找器通过测试不同的学习率来找到正确的学习率,以找到哪一个能最大程度地减少损失。更详细的解释可以在这里找到:https://sgu gger . github . io/how-do-you-find-a-good-learning-rate . html

拥有一个批量查找器的想法在我脑海中已经存在了很长时间,在从 Jeremy 那里获得了动力之后,我已经决定开始实现用于训练神经网络的批量查找器的旅程。

今天我想分享实现一篇论文的旅程和目的地,因为它们在我看来都很有趣,也许会激励你去尝试更多的东西!

一、大小故事

OC meme about batch size

一个普遍的看法是,您不应该使用大批量,因为这只会导致模型过拟合,并且您可能会耗尽内存。虽然后者显然是正确的,但前者比后者更复杂,为了回答这个问题,我们将稍微深入一点 OpenAI 论文“大批量训练的经验模型”

这篇我推荐阅读的文章解释了许多简单的想法,值得记忆。

首先,我们的目标是通过随机梯度下降法来最小化损失,并且有一个真正的基础景观,在此基础上我们将最小化损失。尽管如此,我们无法获得整个数据集的真实梯度(或者更准确地说,是整个分布的梯度),因此,我们必须用有限的批量来近似梯度。

因为我们对一批进行平均,如果我们的批量很小,就会有很多噪声,我们可能只训练噪声模型。尽管如此,应用几个连续的更新将朝着正确的方向推进,但我们还不如直接使用更大的批处理大小,这在计算上更有效,并直接平均掉噪声。尽管如此,在达到一定规模后,如果您的梯度已经很精确,那么再增加批量规模就没有意义了,因为这只是一种计算上的浪费,精度上的收益很小。

此外,通过使用更大的批量(达到 GPU 允许的合理数量),我们可以加快训练速度,因为这相当于迈出几大步,而不是迈出许多小步。因此,对于更大的批量,对于相同数量的历元,我们有时可以获得 2 倍的计算时间!

第二,有一个统计称为“简单噪声标度,它帮助我们确定什么是好的批量,它被定义为:

Simple Noise Scale equation

其中 G 是在 n 个参数上我们损失 L 的真实梯度。

在不深入研究这篇论文的详细内容的情况下,我们的想法是,如果我们使用小于简单噪声标度的批量大小,我们可以通过增加批量大小来加快训练速度,相反,如果我们使用大于简单噪声标度的过大批量大小,我们只会浪费计算能力。

为了更好地理解这一统计数据的含义,让我们来研究一下每个术语:

  • 分子是梯度中每个变量的方差之和。这是对梯度中存在的噪声的测量。
  • 分母是梯度的平方范数,我们称之为标度,给出了梯度接近于零的局部最小值的接近程度的度量。

因此,梯度越大,我们想要的批量就越大,这很自然,因为我们想要在正确的方向上采取梯度步骤。相反,如果梯度没有噪声,我们将从较小的步长中受益更多,因为我们不需要平均大量的观察值并分别使用它们。

另一方面,我们越接近最小值,批量越大,因为我们越接近局部最小值,我们希望采取更谨慎的步骤,因为我们不希望超过它而错过正确的方向。

最后,简单的噪声标度为我们提供了一个工具来回答“较大的批量会使我们过度适应,而较小的批量有助于调整”这个问题:

不一定!如果您的任务已经很复杂,并且近似梯度会有噪声,那么您可能会有兴趣使用更大的批量,以确保您的模型不会在太多的噪声上进行训练。不是说较大的批量会使你过度拟合,而是较小的批量会通过噪声注入增加更多的正则化,但是如果你连拟合都不合适,你还要增加正则化吗?

二。实施文件

OC meme of my journey

现在,我们已经了解了为什么选择正确的批量大小很重要,以及我们如何通过简单的噪声比例统计找到合适的批量大小,现在是时候实施了!好吃!

记住,简单的噪声比例公式是:

Simple Noise Scale equation

问题是,我们不仅需要知道真实的梯度,还需要知道这个梯度的方差,这就更加困难了。为了解决这个问题,作者提出了两种不同的统计方法来逼近简单噪声标度的分子和分母。

Estimator for the scale

Estimator for the noise

这里,我们使用两个不同的批量大小, B 大和 B 小 ,使用以下公式计算实际梯度的两个不同估计值:

Approximate gradient for a given batch size

一旦有了这两个近似值,我们就可以用下面的公式来计算简单的噪声比例:

Approximation of the Simple Noise Scale

为了确保该估计量具有低方差,作者在整个训练过程中计算了几个简单的噪声尺度估计量,并对其进行了平均。

正如论文中所解释的,一种自然的方法是利用几个 GPU 来计算每个 GPU 的局部梯度,这将是小梯度,然后将其与不同 GPU 之间的平均梯度进行比较,这将是大梯度。尽管如此,这种方法假设我们有一个多 GPU,但对我们大多数人来说并不是这样。

因此,必须找到一种有效的方法来为单个 GPU 实现这一点,而这在原始论文中没有描述。这就是我开始的地方,现在我将与你分享我如何解决这个问题的理由!

文章其余部分使用的代码可以在这里找到:https://colab . research . Google . com/drive/15 ltg _ r 03 yqswshz 0 jo 4xaowixlmxmemv

在第一行代码中,我设置了一个 Fastai 环境来在 MNIST 上运行一个模型,因为这个数据集已经在论文中进行了测试,他们得到了平均 900 的简单噪声标度。

我不会详细解释代码,因为我要花一整篇文章来解释 Fastai 如何将所有东西与他们的 API 放在一起,但是代码应该是一个好的开始。如果你想进一步了解代码,请在评论中告诉我,我可以解释它,甚至可以写一篇关于编码部分的文章。

A .使用指数移动平均线的第一种方法

由于我没有多 GPU 设置,所以我发现论文中提出的统计数据并没有真正的帮助,我想我可以跳过它,通过进行近似,直接计算方差的总和:

首先,我用给定批次的估计梯度来近似真实梯度。

然后,由于协方差矩阵的计算可以被视为两个平均值,我试图用指数移动平均值来近似它,因为我不想在训练中存储许多梯度。

Running average of noise, scale, and Simple Noise Scale over batches computed

正如您在这里看到的,结果很奇怪,简单噪声标度太不稳定,噪声比噪声大得多,这给出了一个非常负的简单噪声标度,没有意义。

B .存储梯度

我们看到,使用指数移动平均并不是逼近协方差矩阵的好主意。

解决这个问题的另一种方法是简单地预先设置若干个【N】梯度来保持,然后我们将简单地计算 N 不同的梯度,并使用那些 N 梯度来近似协方差矩阵。

它开始显示结果,但是它的计算方式很复杂:x 轴是我存储的批次数量,以这种方式计算简单的噪声范围。虽然它似乎提供了某种结果,但实际上并不可用,因为我已经存储了数百个渐变!

C .进行两次培训

又一次失败后,我决定按照论文的思路,计算他们的两个统计量。尽管如此,当我只有一个 GPU 时,我需要有一种方法在训练期间获得两个不同大小的批次。

然后我想,当我可以用两种不同的批量大小运行两个训练时期,然后再计算它时,为什么要运行一个训练时期呢?

于是我带着这个想法去做了,用 B 大 = 2 * B 小 ,这将允许我计算它们各自的梯度,并使用它们来计算 GS 如文中所述以指数移动平均的方式。

哎哟!与第一种方法一样,它产生了奇怪的结果!此外,当我想到这一点时,我得到的批次可能在两次运行之间并不相同,因为没有什么会强制将小批次包含在大批次中。此外,我需要运行两个训练时期来计算这一点,所以它不是很好。

D .连续批次

最后,我意识到最好的方法似乎是第二种,但有些东西必须修改,因为我不想保留大量的梯度来计算统计数据。

然后,一个非常简单但有效的想法出现在脑海中:如果我不是像论文中那样以平行的方式对几个批次进行平均,而是以连续的方式对连续的批次进行平均,会怎么样?

这仅仅意味着我只需要设置一个参数,我调用【n _ batch】这是在计算大梯度和小梯度之前我必须存储的批次号,然后我将能够以连续的方式计算论文的统计数据!

以这种方式实现后,我得到了以下结果:

她真是个美人!在论文中,他们描述了增长趋势是可以预期的,因为噪声更可能保持不变,而梯度的规模将随着我们越来越接近最小值而减小,这将导致简单噪声规模的增长。

因为我们很可能没有相同的设置,我也没有访问他们的代码,所以我们的结果略有不同,但在论文中,作者提到了一个简单的噪声标度,从大约 50 开始,到 900,这才是重要的。考虑到理论和实践中的许多近似值,结果可能会有所不同,但正如论文中所解释的那样,差异不应超过一个数量级。

因此,在这个漫长的旅程之后,似乎有一个实现正在工作,尽管本文对此没有提供什么帮助,最好的部分是,要在实践中使用它,您只需要一行代码!

这里的参数对应于:

  • 学习:快速学习者。
  • lr:完成一个训练循环的学习率,可以使用 lr_find()找到
  • num_it:您想要处理的批次数量,可以设置为 【无】 ,它会在一个时期内自动训练。
  • n_batch:在计算简单噪声标度之前要存储的批次数量。20 似乎可以很好地完成不同的任务。
  • beta:指数移动平均的 beta 参数,用于计算方差和以及渐变的比例。如果绘图太不规则,如果需要,尝试增加到 0.999 或更大,或者增加 n_batch 参数。

三世。在不同任务上测试批量查找器

Time to take big steps !

现在我们有了一个工作的实现,看看它在实践中如何帮助找到一个好的批量大小会很有意思。

首先,我们将研究罗斯曼数据集。这个数据集已经在 Fastai courses v3 中进行了探索,您可以在这里找到:https://github . com/Fastai/course-v3/blob/master/nbs/dl1/lesson 6-rossmann . ipynb

在这里,我将简单地运行我的批量大小查找器,并进行与原来完全相同的训练,但是批量大小考虑了简单的噪声标度。

现在如何解读这一点?这意味着,对于给定的学习速率,训练似乎收敛到大约 500 的简单噪声标度,即噪声和标度在训练的后期稳定。因此,计算时间和效率之间的最佳权衡似乎是批处理大小为 512。

在使用批量大小 512 和 64 运行相同的训练后,我们可以观察到一些情况。

First one-cycle training with batch size 512

First one-cycle training with batch size 64

批量大小为 512 时,培训速度比批量大小为 64 时快近 4 倍!此外,即使批量大小 512 采取更少的步骤,最终它具有更好的训练损失和稍差的验证损失。

然后,如果我们查看每个批量的第二个训练周期损失:

Second one-cycle training losses with batch size 512

Second one-cycle training losses with batch size 64

我们可以看到,与批量大小为 512 的情况相比,批量大小为 64 的情况下,训练更加不稳定,因为验证损失继续减少。

最后,我们可以观察到最后一个培训周期的以下结果:

Last one-cycle training losses with batch size 512

Last one-cycle training losses with batch size 64

所以最后,如果我们总结 Rossmann 的结果,使用 512 而不是 64 的批量

  • 减少 4 的训练时间
  • 提供了更好的训练和验证损失,以及感兴趣的度量,这里是 exp_rmse

我研究过文本和图像数据,但考虑到它们要重得多,尤其是具有巨大身体的预训练模型,当我尝试以批量大小运行训练时,我遇到了 CUDA 内存不足,所以我不会在这里显示结果,但你可以在 Colab 笔记本上看看。

结论

贯穿这篇文章我们看到了很多东西!我希望你喜欢这次旅行,如果有什么事情你必须记住的话,那就是:

  • 没有神奇的批量大小数字,例如 32,它取决于您的数据的复杂性,以及您的 GPU 约束。我们看到,小批量可以通过噪声注入帮助调整,但如果你想学习的任务很难,这可能是有害的。而且,跑很多小步会花更多的时间。相反,大批量确实可以加快你的训练,甚至有更好的泛化性能。
  • 一个很好的方法是使用“大批量培训的经验模型”中介绍的简单噪音等级度量。我在这里提供了第一个快速的实现:【https://github.com/DanyWind/fastai_bs_finder】。您可以在自己的数据集上尝试它,特别是在推荐系统或表格模型上,在那里您不太可能遇到 CUDA 内存不足的问题。
  • 不要犹豫去尝试一些事情,一个小小的推动有时可以推动你做好事!我大概在 6 个月前看到了这篇论文,但我并没有真正注意到它,直到我真正尝试(并且失败了很多次)去实现它。但是现在,我不仅可以与大型社区分享这些结果,它还帮助我更好地理解批量大小是如何工作的,以及它的常见概念可能是错误的。所以不要犹豫,现在就实施酷的东西,即使它不直接工作也没关系,旅程比目的地更有价值!

所以,我希望你喜欢读这篇文章,如果能得到你的反馈,那就太好了,我会在未来试着发布更多的文章。

如果您有任何问题,请不要犹豫,通过 Linkedin 联系我,您也可以通过 Twitter 找到我!

实施企业人工智能战略

原文:https://towardsdatascience.com/implementing-a-corporate-ai-strategy-a64e641384c8?source=collection_archive---------6-----------------------

行动太慢会有代价——几乎和行动太快一样

随着这一代人的数字化转型,机器学习和人工智能的更大承诺在人们的脑海中创造了奇迹,并在组织内部产生了活力。这个领域的吸引力是有道理的:每天都有大量的流程改进被公布,每个新的科技创业公司都有一部人工智能剧,甚至政府也在宣布他们独特的战略来跟上。

未来财富的承诺足以让最脚踏实地的领导人眩晕。人工智能创新的惊人速度意味着新的软件创意可以在几天内提交、检查、测试、检验和部署。新特性随着持续的开发周期一步一步来;突发商机的新想法。

(对于那些仍然怀疑这个行业发展速度的人,这里有一个故事:我们曾经在 一个半小时 设计、创建、验证和部署了一个用于海上监控的概念验证预测模型——我们所要做的就是花两周时间告诉客户回去再清理一些他们的数据。)

网飞时代的大片

业务活动和流程来来去去;它们旨在反映一天的心情,或者及时捕捉机会。然而,战略往往进展缓慢且无处不在。他们不再受欢迎后还会留下来,因为“这是我们一贯的做事方式。”

企业战略和企业文化之间有明显的重叠:创新可以被视为信口开河,就像精心策划可以被描述为陈旧和繁琐。有一个深思熟虑的方法来定义你的组织的问题,允许人们独立地做决定,避免灾难。

企业战略包含什么?

在最基本的层面上,战略是在不确定的条件下实现一个或多个目标的高层次计划。“它是一系列启发和信念,旨在提供针对对手(如竞争对手)或情况(如市场)的优势(进攻性或防御性)。

在你的组织内有一个战略的意义就像在隧道里有一个手电筒:你不能看到全貌,但你可以对你的下两步,也许是三步相当有信心。这就是你继续前进所需要的。

通常,公司战略可以用一两句话来概括,对外界来说有些显而易见——正是这种战略的实施经验是专有的,并使公司取得成功。与毕马威保守的程序和可靠的立场相比,德勤具有探索性和灵活性。IBM 正在失去其经典的政府和财富 500 强优势,因为 AWS 和 Azure 等新的云玩家在定价策略和谈判策略上不采取行动。

公司战略基础

早在 1996 年,迈克·E·波特写了一篇内容广泛的文章来帮助定义公司战略的“是什么”和“为什么”。他的要点如下:

  • 仅仅优化您的流程不会带来更多利润;你的竞争对手也在这么做。所以你所在行业的所有公司都会收敛到同一个最优点。
  • 为了避免这种趋同和随后的后果,你可以通过做不同的事情、做不同的事情来获得优势。
  • 然而,选择接下来做什么事情的行为在逻辑上意味着你选择不做其他事情。因此,从选项列表中选择正确的事情突然变得非常重要。

当情况不明朗,或者必须在两个不理想的结果之间做出选择时,一个好的策略将有助于支持和证明你的决定。一个糟糕的策略会让你喘不过气来,并强迫你根据呈现给你的信息做出逻辑上的错误选择。

企业环境中的人工智能策略

对于大多数企业来说,人工智能的实现是面向内部的。这意味着一个好的商业策略将是独一无二的,并与你的竞争对手区分开来,但你的 AI 策略可以和其他所有人的一样。你的数据与他们的不同,因此你的结果也会不同。启动这一内部驱动战略的一个简单问题如下:

我们可以或应该用机器学习来加速、增强或取代哪些业务活动或流程,从而影响感兴趣的结果?

要回答这个问题,需要一些输入:

  • 流程映射。对于所执行的每项活动,是否有一系列明确的步骤来产生结果?如果没有写下来,你的团队成员有能力写下这些过程吗?
  • 功力。你的团队拥有实现机器学习项目的全部技能吗?如果不是,外部团队的重点角色应该是什么?
  • 衡量成功的标准。流程或活动增加或替换后,预期会发生什么变化?
  • 持续支持。未来几年将如何支持这一新安装?组织内部会有所有者吗?
  • 范围。需要实施的仅仅是一项产品功能,还是需要对整个部门进行彻底改革?

你的 AI 战略的执行和实施,需要和开辟一个新部门一样的关注和专注。在我们的参与下,成功的公司实施并雇佣了数据科学团队,并为其提供了与其 it、HR 或销售部门相同的条件:有预算和授权。

人工智能策略建议

围绕在您的组织内采用人工智能,还有其他一些考虑因素。

首先,来自首席执行官的法令是好的,但各级领导的认同更好。我们看到的典型阻力是团队成员对替换或淘汰的恐惧,掩饰为犬儒主义。必须让整个组织的领导人意识到重点是增加工作人员,而不是替换。甚至有人因为机器学习的声势而根本不相信它——然而一个影响组织底线的清醒的过程改进通常会很快说服他们。

此外,比拥有人工智能能力更重要的是拥有数据和分析文化。如果没有结果和结果的集合,那么就不能得到预测或解释模型。机器学习需要从数据中学习,数据来自记录,记录来自流程。

在员工层面,有许多考虑要支持参与的每个人。一个人工智能项目框架将有助于帮助经理提供一个去/不去的决定。内部创业文化将允许人们探索解决棘手问题的不同方法。持续的学习环境让每个人都跟上时代。如果只有一个冠军离开,会对士气造成不利影响,所以要通过展示和讲解来确保团队内部的知识转移。

第一次做对

在我们咨询过的大型组织中,他们让我们加入是有明确原因的。他们知道自己有资源雇佣数据科学家团队,让他们横行无忌,就像鬣狗嗅出受伤的瞪羚一样;他们没有的是第二次机会来建立正确的团队而不是建立正确的团队

我们给他们的建议和随后的项目实施遵循以下几点:

  • AI 应该没意思。如果它是外来的,很有可能会被误解,甚至误用。你要的是厨师刀,不是搅拌机。当有一个明确的问题,有一个已知的解决方案,使用它。谈到流程优化,好已经足够好了。完美永远不会实现,因为不管怎样,明天会有更好的研究论文。
  • 它直接影响 KPI。每一项努力都应该为你的公司赚更多的钱,为你的公司省钱,或者为你的员工节省工作和时间。聪明的计划失败了。回到你的组织的基本原则。
  • 实施起来需要时间。需要像马拉松一样实施,而不是短跑。记住,人们花了大约 15 年的时间才意识到电动机可以被移到它改进制造的地方,而不是被插入它的蒸汽对应物的位置。保持耐心,专注于获得动力而不是一夜成名。
  • 从小处着手。大多数大的努力都会失败。(在加拿大,我们仍然受到联邦政府支付系统改革失败的影响。)如果你不确定自己是否会游泳,尝试一下比从深水区跳下去更安全。选择一个项目,把它分解成关键活动,自动化其中一个,然后是另一个,等等。

最终注释

在他 2011 年的书《适应:为什么成功总是始于失败》中,蒂姆·哈福德讨论了人们容易犯的三种错误:失误、违规和错误。滑倒是按错了按钮,违规是有人故意骗你。至于第三类,作者解释得最好。“错误是你故意做的事情,但会产生意想不到的后果,因为你对世界的心理模型是错误的。”

在这个数字能力的新时代,正确的心理模型将机器学习技术与商业问题结合起来,并准备在明天被重新发明。利用这种速度成为你的优势,而不是让它成为你的劣势。

如果您对本文或我们的 AI 咨询框架有其他问题,请随时通过*LinkedIn或通过* 电子邮件 联系。**

你可能喜欢的其他文章

我的首席技术官丹尼尔·夏皮罗(Daniel Shapiro)的其他文章您可能会喜欢:

用 Django 实现数据仓库

原文:https://towardsdatascience.com/implementing-a-data-warehouse-with-django-e4856c92f146?source=collection_archive---------2-----------------------

在本文中,我们将介绍如何利用 Django 及其 rest 框架来实现数据仓库。我们将特别关注来自外部 API 的数据源,但是同样的原则也适用于任何其他类型的数据源:平面文件或直接 ODBC 连接。

使用 Django 实现数据仓库的一个主要好处是,您将能够使用 Python 处理任何组件或任务:ETL、查询、数据操作、报告、web 应用程序应用程序…

请注意,Django 可能不适合您的用例,但是同样的原则也适用。

本文使用的所有代码都可以在 GitHub 上找到。

什么是数据仓库?

数据仓库的实现通常是为了整合整个公司的不同数据源。在我们的案例中,我们使用不同的外部和内部 API 来整合所有这些信息,以便进行分析、报告和预测建模。

主要挑战是将不同来源的数据提取、转换和加载为一种通用格式,并能够跟踪数据随时间的变化。

我们将在下面的章节中详细介绍这些挑战。

Django 和 rest 框架

Django 是开源的 web 框架模板;并遵循模型、视图、模板(MVT)设计模式。

在本文中,我们将主要关注 Django 架构的模型组件。为了能够与数据库交互,Django 使用了对象关系映射器;这意味着它们将被表示为 Python 类,而不是使用 SQL 表。这意味着我们可以使用 Python 执行任何 CRUD 操作,而无需直接与 SQL 或数据库本身进行交互。
这将是我们数据仓库实现的关键,因为我们将利用这个 ORM 来执行插入和更新。

Rest-Framework 是 Django 生态系统的一部分,是创建 web APIs 的有用工具包。
我们将使用的框架组件称为序列化器;它允许将复杂的数据结构序列化为一个呈现的 JSON(典型的 GET 请求),还允许在首先验证传入的数据(也称为反序列化)之后解析要转换回复杂类型的数据。
这在我们的情况下将非常有用,因为我们可以利用反序列化来确保信息以正确的格式出现,并且我们可以将每个元素映射到数据仓库中的正确字段。
-https://www.djangoproject.com/
-https://www.django-rest-framework.org/

基本模型

一旦我们创建了 Django 项目和应用程序(https://docs.djangoproject.com/en/2.1/intro/tutorial01/);我们现在可以创建我们的模型了。

Models.py 将包含所有允许 Django ORM 与数据库交互的逻辑; models.py 中的每个类都是数据库中的一个物理表。

在这个例子中,我们将创建 3 个表:
-Person;通过名字和姓氏

  • 车辆唯一识别的自然人的实例;通过其注册号
  • 人员车辆唯一识别的车辆;一个人拥有车辆的例子
from **django.db** import **models**class **Person**(models.Model):
 *“”” Person class identifies a unique physical person by its first name, last name and email “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 first_name = models.CharField(max_length=100)
 last_name = models.CharField(max_length=100)
 email = models.CharField(max_length=100)def __str__(self):
 return “{} {}”.format(self.first_name, self.last_name)class **Vehicle**(models.Model):
 *“”” Vehicle class uniquely with the registration plate number “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 registration_plate = models.CharField(max_length=100)def __str__(self):
 return self.registration_plateclass **PersonVehicle**(models.Model):
 *“”” PersonVehicle register the relationship between a vehicle in a person,
 in other words, the owner of the vehicle at a given point in time “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 vehicle = models.ForeignKey(Vehicle, on_delete=models.PROTECT)
 person = models.ForeignKey(Person, on_delete=models.PROTECT)def __str__(self):
 return “{} {}”.format(self.vehicle, self.person)

created_atupdated_at 是两个自动生成的字段,将记录创建或更新记录的日期时间。

保护将禁止删除任何与其他表有关系的记录。如果您希望删除与该记录相关的所有记录,也可以使用级联

现在我们已经创建了我们的模型,我们可以通过 Django shell ( )插入信息。/manage.py shell ):

跟踪更改

为了能够跟踪随时间的变化,我们将使用简单历史;它允许在每次创建/更新/删除时存储 Django 模型状态:https://django-simple-history.readthedocs.io/en/2.7.0/

from django.db import models
from **simple_history.models** import **HistoricalRecords**class Person(models.Model):
 *“”” Person class identifies a unique physical person by its first name, last name and email “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 first_name = models.CharField(max_length=100)
 last_name = models.CharField(max_length=100)
 email = models.CharField(max_length=100)
 **history = HistoricalRecords()**class Meta:
 **unique_together = ((“first_name”, “last_name”),)**def __str__(self):
 return “{} {}”.format(self.first_name, self.last_name)class Vehicle(models.Model):
 *“”” Vehicle class uniquely with the registration plate number “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 registration_plate = models.CharField(max_length=100)def __str__(self):
 return self.registration_plateclass PersonVehicle(models.Model):
 *“”” PersonVehicle register the relationship between a vehicle in a person,
 in other words, the owner of the vehicle at a given point in time “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 vehicle = models.ForeignKey(Vehicle, on_delete=models.PROTECT)
 person = models.ForeignKey(Person, on_delete=models.PROTECT)
 **history = HistoricalRecords()**class Meta:
 **unique_together = ((“vehicle”),)**def __str__(self):
 return “{} {}”.format(self.vehicle, self.person)

请注意,我们在每个模型中添加了字段 *history* ,以便跟踪随时间的变化。这些更改将存储在前缀为*历史*的镜像表中。

为了能够跟踪变更,我们还需要定义*代理键,*这些键是记录唯一性的业务定义。例如,在 *Person* 表中,我们将 *first_name**last_name* 定义为 *unique_together* ,这意味着这些字段将不可更新,但是 *email* 是可更新的。

现在让我们尝试修改我们之前记录的记录:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6420586a70a064efc40fbc444421d155.png)

现在让我们看一下历史表,看看这些变化是如何记录的:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/239413297e8cc6c571a7bd09325c87d5.png)

## 序列化程序

如前所述,在将输入数据插入相关的 SQL 表之前,将使用序列化程序来解析和验证输入数据。

现在让我们假设一个外部源通过 REST API 以下面的 JSON 格式向我们提供信息:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b3ab2ba89f8c86e04fc1340481ccc5ea.png)

JSON 提供了此人的身份和当前属于此人的车辆列表,以下是将用于解析此 JSON 的序列化程序:

from rest_framework import serializersfrom dwh_app_simple_history.models import Person, PersonVehicle, Vehicleclass VehicleSerializer(serializers.Serializer):
“””
Nested serializer within the JSON source; in this example all vehicles that belong to the
person nested in the JON as a list of all active vehicles.
“””
registration_plate = serializers.CharField(max_length=100)class PersonVehicleSerializer(serializers.Serializer):
“””
Serializer that will be used to deserialize the json to be then imported in the datawarehouse
“””
first_name = serializers.CharField(max_length=100)
last_name = serializers.CharField(max_length=100)
email = serializers.CharField(max_length=100)
vehicles = VehicleSerializer(many=True)def save(self):
“””
Overwrite the save function on the serializer to be able to control how we want to
insert/update the data provided by the source in our datawarehouse.
“””
# First update or create the person
person_obj, created = Person.objects.update_or_create(
first_name=self.validated_data[“first_name”],
last_name=self.validated_data[“last_name”],
defaults={“email”: self.validated_data[“email”]},
)# Then create each Vehicle and link it to the person created before
for vehicle in self.validated_data[“vehicles”]:
vehicle_obj, created = Vehicle.objects.get_or_create(registration_plate=vehicle[“registration_plate”])

personvehicle_obj, created = PersonVehicle.objects.update_or_create(
vehicle=vehicle_obj, defaults={“person”: person_obj}
)


首先,我们创建了一个嵌套的序列化器 *VehicleSerializer* 来解析一辆车的实例,然后在父序列化器 *PersonVehicleSerializer* 中,我们可以使用参数 *many=True* 来告诉 Django 它们可以是多辆车。

为了正确保存所有信息,我们重写了 *save()* 方法,首先我们创建或更新 *Person* ,然后为嵌套字典中的每辆车创建一个 *Vehicle* ,然后将它链接到 *PersonVehicle* 中的 *Person* 。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/063bb3146129677fb2d03f18eb6c0fc7.png)

请注意,如果需要,可以通过添加验证或转换规则来丰富序列化程序,就像在传统的 ETL 实现中一样。

## 视图

在前面的例子中,我们使用 JSON 文件和 Django shell 将数据插入到我们的数据仓库中。

现在让我们假设信息不是由外部提供者提供的,而是公司架构的源系统向数据仓库发送信息。这可以通过添加一个允许通过一个 *POST* API 请求插入数据的*视图*来实现。

from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Responsefrom dwh_app_simple_history.serializers import PersonVehicleSerializer@api_view([“POST”])
def PersonVehicle(request):
“””
This view will be called through a POST request to add or update the information provided in
the request
“””
# Deserialize the information provided in the request
ser = PersonVehicleSerializer(data=request.data)# Validate the information provided
ser.is_valid(raise_exception=True)# Save the information in the datawarehouse
ser.save()return Response({“All good, everything has been saved”})


正如你所看到的,我们使用了与 Django shell 中相同的序列,但是使用了 *api_view* decorator 将这个端点暴露给另一个系统或用户。这意味着我们现在可以从任何系统与我们的数据仓库通信(您需要确保您的 Django 服务器正在运行)。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1f26deafa49d2b639a639842329c5bd0.png)

## 结论

在本文中,我们已经介绍了使用 Django 构建数据仓库的所有步骤和组件:
——使用 Django ORM 创建第三范式数据模型;
-使用简单的历史记录来跟踪随时间的变化;
-使用 serializer rest 框架对来自外部提供者或内部系统的信息进行反序列化,并将结果保存在数据仓库中;和
——使用来自 rest 框架的视图,允许源系统通过 POST 请求发送信息。

以上所有内容应该为构建您的数据仓库提供了足够的信息,当然,您必须浏览所有不同的来源,了解数据将如何在下游以最有效的方式建模数据,并在您的 ETL 中添加所有转换/验证规则。

# 在 PyTorch 中实现线性链条件随机场

> 原文:<https://towardsdatascience.com/implementing-a-linear-chain-conditional-random-field-crf-in-pytorch-16b0b9c4b4ea?source=collection_archive---------4----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/68f4266c815001ecb9b8798bb60aaede.png)

Random fields 😝. Photo by [Matthew Miles](https://unsplash.com/@matthewmiles?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

嗨伙计们!这是我在 Medium 上的第一篇帖子。我希望你喜欢它!

在过去的日子里,我使用 PyTorch 从头开始实现了一个 CRF 模型。我这样做的想法是为了更好地理解 CRF 模型是如何工作的。我在网上找到了很多关于 CRFs 的内容,包括博客帖子、教程和书籍。我还看了 Hugo Larochelle 的关于 CRF 模型的系列视频讲座,发现它们非常直观。

看完之后,我决定用 PyTorch 从头开始实现这些数学方程(不用担心梯度!).所以,这就是这篇帖子的目的!与您分享一个关于如何实施(*线性链* ) CRF 模型的简单易懂的指南!

*免责声明:CRF 是任何无向图结构的概括,例如序列、树或图。在这篇文章中,我将重点关注顺序结构,这意味着我们的模型将只以先前的转换为条件。这种参数化被称为线性链 CRF。在这篇文章的其余部分,我将使用缩写 CRF 来命名一般的 CRF 和它的线性链对应物*互换*。*

在这篇文章中,我不会描述使用 CRFs 的原因和它的应用。我想如果你正在读这篇文章,是因为你已经知道了所有这些,而且你只对技术部分感兴趣。也就是说,我将介绍它背后的一些基本理论,并介绍用于编写代码的符号。

总之,在这篇文章中,你会看到:

1.  通用报告格式背后的基本理论;
2.  给定一系列观察值,如何找到最可能的标签序列;
3.  如何在给定标签的情况下计算一系列观察值的分数;
4.  如何计算配分函数来归一化这个分数;
5.  如何在对数空间中实现它们(数值稳定)。

**在下一篇文章中:**如何向量化 *for 循环*以使并行计算机单元的计算更容易(比如说 GPU🙌).在这里先睹为快矢量化代码。

# 幕后的基本理论

最初的条件随机场论文发表于本世纪初[【1】](https://repository.upenn.edu/cgi/viewcontent.cgi?referer=https://en.wikipedia.org/&httpsredir=1&article=1162&context=cis_papers)。从那以后,机器学习社区一直在到处应用 CRF,从计算生物学和计算机视觉到自然语言处理。在 google scholar 上用“使用 CRF”和“使用条件随机场”这样的关键词快速搜索,会得到大约 20000 个答案。

在过去的几年中,CRFs 模型与 LSTMs 相结合以获得最先进的结果。在 NLP 社区中,在 BiLSTM 上堆叠 CRF 层被认为是在序列标记问题上实现更高准确性的经验法则。你可以看到一些例子[在这里](https://github.com/sebastianruder/NLP-progress/blob/master/english/part-of-speech_tagging.md)和[在这里](https://github.com/sebastianruder/NLP-progress/blob/master/english/semantic_role_labeling.md)。

在序列分类问题中,我们的主要目标是在给定一个序列向量( **X** )作为输入的情况下,找到一个标签序列( ***y*** )的概率。这表示为条件概率*P*(**y***|**X**)。*

*首先,让我们定义一些改编自 Larochelle 的类的符号:*

*   *训练集:输入和目标序列对 *{(* **X** *i,* **y** *i)}**
*   *向量的第 *i-* 个输入序列:**x***I =[***x***1、…、***x**ℓ*
*   **标签的第 *i-* 个目标序列:**y**t46】I =【y1,…,y ℓ】**
*   **ℓ是序列长度。**

**假设时间独立,对于一个样本( ***X*** *,* ***y*** ),在一个常规的分类问题中,我们通过乘以每个项目在 *k-t* 处的概率来计算*P*(**y***|***X******

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/43add53fb7fdfd09794e594bf297d59a.png)**

**请注意,我们正在使用标准化的指数对*P(yk |***x***k)*进行建模。这类似于神经网络中广泛使用的 *softmax* 变换。这是使用 *exp* 函数 *:* 的一些直觉**

1.  ****下溢:**当我们将非常小的数相乘时,我们得到的是一个更小的数,它可能会发生*下溢*。**
2.  ****非负输出:**所有值都映射在 0 和+inf 之间。**
3.  ****单调递增:**将高值向上推,低值向下推。这与 *argmax* 操作有相似的效果。更多[此处](https://datascience.stackexchange.com/questions/23159/in-softmax-classifier-why-use-exp-function-to-do-normalization)。**

**我们从帽子里拿出两个符号: *U 和 z。*让我们看看它们是什么。**

***U* ( *x,y* ) 被称为我们的**排放量**或**一元分数** *。*这只是给定我们在第 *k* 时间步的 **x** 向量的标签 *y* 的分数。你可以把它看作是 BiLSTM 的第 k 个输出。其实理论上我们的 **x** 向量可以是你想要的任何东西。实际上,我们的 **x** 向量通常是周围元素的串联,就像滑动窗口中的单词嵌入。在我们的模型中,每个*一元*因子由一个可学习的权重加权。如果我们把它们看作 LSTM 输出,这就很容易理解了。**

***Z*(*x*)*俗称**分区函数**。我们可以把它看作一个归一化因子,因为我们想得到最终的概率。这类似于 *softmax* 函数的分母。***

**到目前为止,我们描述了一个带有“最终 softmax 激活”的常规分类模型,以便获得概率。现在我们将添加新的可学习权重来模拟标签 *yk**yk+1 跟随的几率。*通过建模,我们在连续的标签之间创建了一个依赖关系。因此,名为*直链 CRF!*为了做到这一点,我们将之前的概率乘以 *P(yk+1 | yk),*我们可以使用指数属性将其重写为一元分数*U*(***x****,y* )加上可学习的**转换分数** *T* ( *y,y* )**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6b4fc75883532aa73b78027935ce15ba.png)**

**在代码中, *T* ( *y,y* ) 可以看作一个具有形状 *(nb_labels* ,*nb _ labels)*的矩阵,其中每个条目都是一个可学习的参数,表示从第**标签到第**标签的过渡。让我们回顾一下我们所有的新变量:**

*   ****排放或一元分数** *(U):* 分数代表在给定输入的情况下*yk*x*k .***
*   ****过渡分数** *(T):* 代表可能性的分数 *yk* 后跟 *yk+1***
*   *****分区函数****【Z】:*归一化因子为了得到序列上的概率分布。**

**唯一需要正确定义的是配分函数 *Z:***

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/02c8008b94d23cdd7f134827835b0783.png)**

**结果是计算 *Z* (X)并不简单,因为我们有太多的嵌套循环😖。它是在每个时间步*标签集上所有可能组合的总和。*更准确地说,我们在标签集上进行ℓ计算。这给了我们一个时间复杂度 *O(|y|^* ℓ *)。***

**幸运的是,我们可以利用循环依赖,并使用动态编程来有效地计算它!完成这项工作的算法被称为**正向算法**或**反向算法—** ,这取决于你在序列上迭代的顺序。不要与神经网络中使用的前向和反向传播混淆。**

**这就是我们开始实施之旅所需了解的全部内容!如果你在我的解释中迷失了,有很好的资源可以更详细地解释 CRF。比如埃德温·陈的这篇精彩的教程,或者萨顿和麦卡勒姆的这篇内容丰富的教程,或者迈克尔·柯林斯的这篇直截了当的笔记。**

# **密码**

**让我们通过创建一个从 PyTorch 的 *nn 继承而来的名为 CRF 的类来开始我们的代码。模块*以便自动跟踪我们的坡度。此外,我为句子的开头/结尾添加了特殊的标记,并添加了一个特殊的标志来通知我们是否正在传递批量优先维度的张量。**

**我们还可以为 pad id 添加一个特殊的令牌。如果我们这样做,我们必须确保强制约束以防止从填充的过渡*和从*填充到*填充的过渡——除非我们已经处于填充位置。我们可以看到,我们的转换分数 *T* 被表示为矩阵 *self.transitions* ,并使用 *torch.parameter.* 进行编码。这样,PyTorch 将通过 autodiff 学习这些权重!太好了!***

# *定义损失函数*

*在监督分类问题中,我们的目标是在训练期间最小化期望误差。我们可以通过定义一个损失函数 *L* 来做到这一点,该函数将我们的预测和我们的真实标签作为输入,如果它们相等,则返回零分,如果它们不同,则返回正分——指示错误。*

*注意,我们正在计算*P*(**y***|**|*X***),这是我们想要最大化的东西。为了将这作为一个最小化问题,我们取这个概率的负对数。这也被称为*负对数似然损失(NLL-Loss)。*在我们的例子中,我们得到:*L =*-*log*(*P*(**y***|***X***)。应用 log-properties,如*log(a*/*b)= log(a)-log(b)*,我们得到:***

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7eddb20ff93c6955b893e5832c951d83.png)**

**其中 *Z_log* 表示我们在计算配分函数时取 *log* 。当我们应用向前算法时,这将使事情变得更容易。因此,让我们检查一下这部分的代码:**

**我们的*正向*传递仅仅是 *NLL 损失*(不要与计算 Z(X)的正向算法混淆),其中我们在常规的 *log_likelihood* 方法前面插入了减号。 *log_likelihood* 通过首先计算分数和对数分割方法,然后彼此相减来计算。此外,我们向这些方法传递一个掩码矩阵,以便它们可以忽略与填充符号相关的计算。为了完整起见,掩码矩阵如下所示:**

input = [['lorem', 'ipsum 'dolor', 'sit', 'amet'],
['another', 'sentence', 'here', '', '']]mask = [[1, 1, 1, 1, 1],
[1, 1, 1, 0, 0]]


# **计算分子:分数**

**由于我们将 *log* 应用于 *exp* 函数,分子就是我们在每个时间步长的发射和跃迁分数的总和。在代码中:**

**为了理解这段代码,您必须认为批处理中的每个句子的所有操作都是相同的。因此,我们首先通过调用`tags[:, 0]`来获取每批中第一个单词的标签。类似地,我们对时间步长维度上的掩码求和,以获得一个长度列表,对于上一个示例来说是`[5, 3]`。在实践中,它返回了一个*火炬。长型*带外形`(batch_size,)`。例如,让我们看看第 28 行:**

emissions[:, 0].gather(1, first_tags.unsqueeze(1)).squeeze(1)


1.  **首先,我们从第一个时间步长`emissions[:, 0]`中选择所有批次,它返回一个形状为`(batch_size, nb_labels)`的张量。**
2.  **然后,我们希望只从形状为`(batch_size,)`的*long tenser*`first_tags`中的列( *dim=1* )中选择值。由于`emissions`是一个 2D 矩阵,我们*取消`first_tags`的最后一个维度*得到形状`(batch_size, 1)` : `first_tags.unsqueeze(1)`**
3.  **现在它们有了相同的形状,我们可以使用*聚集*函数在`emissions` : `emissions[:, 0].gather(1, first_tags.unsqueeze(1))`的指定维度中选择`first_tags`内的值**
4.  **最后,这将产生一个形状为`(batch_size, 1)`的矩阵,所以我们*将*压缩回去,得到一个 1D *长传感器。***

**整个代码都使用这个简单的过程来选择指定维度内的一组标签。**

**关于这段代码,我想说的最后一件事是我们如何忽略与填充符号相关的分数。解决这一问题的思路非常简单:我们在两个向量(分数和掩码向量)之间执行逐元素乘法,以在与填充位置相关联的时间步长中将分数清零。**

# **计算配分函数:正向算法**

**既然我们已经计算了分数,让我们把注意力集中在分母上。为了有效地计算配分函数,我们使用了向前算法。我将简要描述它,并展示我们如何在对数空间中计算它。**

**正向算法的伪代码如下:**

**1)初始化*y’2:*的所有值**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b8ca21ef03dad2fcec13bf07647227d3.png)**

**2)对于 *k=2 到* ℓ-1,对于*y’k+1*(对数空间) *:* 的所有值**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/aa11aee12b4d0ced9b0a7abdead7d29a.png)**

**3)最后:**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d22fe40241e7c31826a3940fb994ef3e.png)**

**请注意,在第二步中,我们记录了 exp 的总和。这可能会有问题:如果一个给定标签的分数太大,那么指数将很快增长到一个非常大的数字。因此,在我们最终获取日志之前,我们可能会发现一个*溢出*。幸运的是,有一个技巧可以使这个操作稳定:**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/fcee87c5aa9e598eb7bc3983dbb29138.png)**

**左边等于右边的证明看起来是这样的:**

_ = log sum(exp(zk))
= log sum(exp(zk-c) * exp(c))
= log exp(c) + log sum(exp(zk-c))
= c + log sum(exp(zk-c))


**设置 *c**max* ( *z* )我们就完成了。此外,PyTorch 已经在`torch.logsumexp`中为我们提供了这个稳定的实现。现在让我们使用 PyTorch 对上面的算法进行编码:**

**上面的代码与我们在分子中计算分数的方式非常相似。其实我们是在计算分数!但是现在我们通过查看以前的迭代来积累它们。我添加了关于形状的注释,这样你就能明白发生了什么。**

**这里只有一件事我们以前没有看到(*种*):**

*   **在这一行中,如果我们没有到达填充位置,我们就用新的值来改变 alpha 的当前值,否则就保持相同的值。要了解这是如何工作的,请看这个例子,当我们在时间步长 *i=1* 时:**

**>>> mask
tensor([[1., 0., 0.],
[1., 1., 0.],
[1., 1., 1.]])

alphas
tensor([[-0.7389, -0.6433, -0.0571, -0.3587, -2.1117],
[ 1.0372, 1.8366, -0.9350, -1.2656, -0.5815],
[ 0.1011, 0.7373, 0.0929, -0.8695, 0.7016]])>>> new_alphas
tensor([[11.1889, 10.6471, 11.0028, 11.0248, 11.0909],
[10.3975, 11.0104, 8.5674, 10.2359, 13.9150],
[10.1440, 9.9298, 11.3141, 10.1534, 10.3397]])>>> is_valid = mask[:, 1].unsqueeze(-1)
is_valid
tensor([[0.],
[1.],
[1.]])>>> is_valid * new_alphas + (1 — is_valid) * alphas
tensor([[-0.7389, -0.6433, -0.0571, -0.3587, -2.1117],
[10.3975, 11.0104, 8.5674, 10.2359, 13.9150],
[10.1440, 9.9298, 11.3141, 10.1534, 10.3397]])**


**我们已经更新了第二和第三序列,但没有更新第一序列,因为在时间步 *i=1* 我们到达了填充位置。**

**作为一个很好的观察,你可以看到一旦我们取了 *logsumexp* 我们就已经在日志空间中了!所以,我们可以把α的值加到我们的分数上。最后,我们在最后的时间步再进行一次 *logsumexp* 操作,返回到达句子末尾的最终值——所以我们仍然在 log-space 中。**

**这个算法的时间复杂度是 O(𝓁| *y* |),这比我们用朴素方法得到的指数界限低得多。**

# **寻找标签的*最佳*序列**

**现在我们已经计算了配分函数,我们几乎完成了所有的工作。如果我们也计算向后算法——它只是向后遍历序列——我们可以找到在每个时间步长最大化*P*(**y***k*|**X**)的标签 *k.* 有趣的是,如果我们假设 CRF 是真实分布,这个将是最优解。它可以这样表述:**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/df09c2f6f1146f54ea21341cb1090664.png)**

**其中 *α* 分数来自正向算法,而 *β* 分数来自反向算法。为了找到标签 **y** *的最佳序列,我们可以在每个时间步长取 *argmax* :**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/0b3018c6a86653d9fb7d8dceb9bad740.png)**

## **维特比算法**

**但是,事实证明我们不需要计算反向算法来找到最可能的标签序列。取而代之的是,我们可以在向前算法期间简单地跟踪每个时间步长的最大分数。一旦我们完成了,我们就可以沿着 max 运算( *argmax* )的反向轨迹,以便**解码**使分数最大化的序列。这正是下面的代码所做的:**

**这种算法被称为维特比算法。这与我们在 log_partition 函数中使用的前向算法几乎相同,但我们没有对整个序列使用常规分数,而是使用最大分数和使这些分数最大化的标签**换句话说,我们用 *torch.max* 代替了 *torch.logsumexp* 操作,它一起返回 *max* 和 *argmax* 。**

**所以,我们现在需要做的一切就是挑选这些最终的标签,并沿着向后的轨迹找到" *argmax"* 标签的整个序列。上面代码的延续如下:**

**请注意,对于每个样本,我们都在对该样本的回溯进行迭代,并且在每个时间步长中,我们都在`best_path`的开头插入了使分数最大化的标签。因此,在最后,我们有一个列表,其中第一个元素对应于序列的第一个标签,最后一个元素对应于最后一个标签有效标签(*见第 15 行*)。还要注意。python 中的 insert(0,)是 O(n),所以更快的方法是使用。append()并在以后反转列表。**

**就是这样!当我们为批次中的所有样本计算 *find_best_path* 操作时,我们就完成了!**

# **把所有的放在一起**

**完整的代码可以在这里找到:[https://github.com/mtreviso/linear-chain-crf](https://github.com/mtreviso/linear-chain-crf)。看看`main.py`和`bilstm_crf.py`看看实践中的 CRF!**

# **结论**

**这个帖子比我预想的要长😛。请随意让这段代码更有效率,并留下评论告诉我们你是如何做到的🙂。**

**最后,我认为值得一提的是,如果你想在生产中使用 CRF 模型,我强烈建议你使用一个经过充分测试的高效实现,比如[这个伟大的 pytorch 包](https://github.com/kmkurn/pytorch-crf),或者由 [allennlp 库](https://github.com/allenai/allennlp)提供的那个。**

**在下一篇文章中,我们将看到如何对循环*进行矢量化,以计算配分函数和维特比算法。***

# **更多信息**

**通用报告格式只是众多连续模型中的一种。我强烈推荐你看一看[诺亚·史密斯关于序列模型的演讲](http://lxmls.it.pt/2016/sequencemodels.smith.7-23-16.pdf)或者[安德烈·马丁斯的演讲](https://andre-martins.github.io/docs/dsl2018/lecture_05.pdf)来看看这篇文章中提出的算法的一些可视化例子。或者更好的是,你可以参加下一届 [Lisbon 机器学习暑期学校](http://lxmls.it.pt/2019/),它将涵盖序列模型和许多关于机器学习和自然语言处理的有趣主题!**

# **参考**

*   **Hugo Larochelle 关于 CRFs 的讲座:[http://www . DMI . usherb . ca/~ la rochelle/neural _ networks/content . html](http://www.dmi.usherb.ca/~larocheh/neural_networks/content.html)**
*   **Pytorch 教程—高级:制定动态决策和 Bi-LSTM 通用报告格式:[https://py torch . org/tutorials/初学者/nlp/advanced_tutorial.html](https://pytorch.org/tutorials/beginner/nlp/advanced_tutorial.html)**
*   **Michael Collins 关于对数线性模型、MEMMs 和 CRF 的注释:[http://www.cs.columbia.edu/%7Emcollins/crf.pdf](http://www.cs.columbia.edu/%7Emcollins/crf.pdf)**
*   **迈克尔·科林斯关于向前向后算法的笔记:[http://www.cs.columbia.edu/~mcollins/fb.pdf](http://www.cs.columbia.edu/~mcollins/fb.pdf)**
*   **Sutton 和 McCallum 的教程—条件随机字段介绍:[https://home pages . INF . ed . AC . uk/csutton/publications/crftutv 2 . pdf](https://homepages.inf.ed.ac.uk/csutton/publications/crftutv2.pdf)**
*   **Edwin Chen 博文:[http://blog . echen . me/2012/01/03/introduction-to-conditional-random-fields/](http://blog.echen.me/2012/01/03/introduction-to-conditional-random-fields/)**
*   **Ravish Chawla 的条件随机字段概述:[https://medium . com/ml 2 vec/Overview-of-Conditional-Random-Fields-68 a2a 20 fa 541](https://medium.com/ml2vec/overview-of-conditional-random-fields-68a2a20fa541)**

**🔍*特别感谢@flassantos31、@erickrfonseca 和@thales.bertaglia 对本帖的审核。***

**🔮回顾后感谢: [André Luís Macêdo Farias](https://medium.com/u/a800706492c5?source=post_page-----16b0b9c4b4ea--------------------------------) 指出了使用朴素方法计算 *Z* 的正确时间复杂度。**

# 用五个步骤实现用于文本分类的朴素贝叶斯分类器

> 原文:<https://towardsdatascience.com/implementing-a-naive-bayes-classifier-for-text-categorization-in-five-steps-f9192cdd54c3?source=collection_archive---------2----------------------->

## 我希望我以前有朴素贝叶斯分类器指南

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b286e95adf75c6dea9c5a1368d367d6f.png)

Thomas Bayes (1701–1761) author of the Bayes’ theorem

> 朴素贝叶斯是一种常用于文本分类的学习算法。

朴素贝叶斯分类器的一些应用是:

*   **(自动)对文件夹**中的电子邮件进行分类,因此收到的电子邮件信息会进入**:**“家人”、“朋友”、“更新”、“促销”等文件夹。
*   **(自动)工作列表的标记。给定一个原始文本格式的工作列表,我们可以给它分配标签,如:“软件开发”、“设计”、“营销”等。**
*   **(自动)产品分类。给定一个产品描述,我们可以将其分类,如:“书籍”、“电子产品”、“服装”等。**

本文的其余部分将提供必要的背景知识和直觉,通过五个步骤从头构建一个朴素贝叶斯分类器。

# 第一步。确定训练朴素贝叶斯分类器的先决条件

如前所述,贝叶斯分类器在文本分类中的应用是无止境的。唯一的先决条件是,对于我们希望将文本片段进行分类的每个类别( *class)* ,都有一组现有的*示例*。

例如,对于工作列表分类示例,我们需要一组已知针对“软件开发人员”的工作列表,一组已知针对“设计人员”的工作列表,以及一组针对“营销人员”的工作列表。

在这种情况下,有三个类(“软件开发”、“设计”和“营销”)。利用每个类别中的工作列表样本,我们可以训练一个朴素贝叶斯分类器,以便自动对*新的*工作列表进行分类。

我们将在本文剩余部分探讨的示例是**垃圾邮件/垃圾邮件分类,**因此,有两个类别:“垃圾邮件”和“垃圾邮件”(即非垃圾邮件)。如前所述,唯一的先决条件是拥有已知为垃圾邮件的现有*训练集*和已知为垃圾邮件的训练集*。*

为了说明清楚,我们的训练集将由三封垃圾邮件和三封垃圾邮件组成(下面的图片是可点击的,因此您可以放大并阅读每封邮件):

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d6bea97abb6f54cb2ca1fd7e2d7740f7.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4a9f493486c24bc3660d8c462616c5c5.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/2b6bd46992a03ad03362d7859539e3d6.png)

Examples of HAM emails.

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/2b86f712d37afd14f04f2ec07ca2f34a.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/010ee4a290d36304b60b1e2b02814c37.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f07446d42cc48c483efe53b94448d8f1.png)

Examples of SPAM emails.

请注意,在生产级垃圾邮件过滤器中,训练集的大小(即,已知垃圾邮件和 Ham 电子邮件的数量)通常要大得多,然而,我们将在此开发的概念和直觉确实适用。

# **步骤二。计算每个类别的术语文档矩阵(TDM)**

术语-文档矩阵(TDM)由出现在一组文档中的词频列表组成。

TDM 矩阵是由 *n* 个字和 *m* 个文档组成的稀疏矩形矩阵。之所以说它稀疏,是因为它包含的大部分都是零。TDM 矩阵的条目( *i,j* )表示单词“*I”*在文档“*j”*中的出现频率。

对于考虑英语中所有单词的英语垃圾邮件分类器,单词的数量( *n* )大约为 170k。至于每节课的例题数量,一般规律是越多越好:-)。然而,实际上,几千条信息给出了合理的预测。对于垃圾邮件检测任务,垃圾邮件标记数据的实际来源是 [SpamAssassin](https://spamassassin.apache.org/) 。

以下图片摘自垃圾邮件和垃圾邮件类别的 TDM 矩阵:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/aa76766b660c6b03012f7ec4f7af83b4.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e9a0817c07c5e8fcc7e4b83493c94bdf.png)

Term document matrix excerpts for the HAM and SPAM emails.

# 九月三日。计算频率

一旦为每个类别计算了 TDM 矩阵,下一步就是计算每个术语的频率和出现次数:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e833114811c71d74b0b08b056920869e.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/caaa13cd3339892be9ae788ffdf6569c.png)

Top 10 terms sorted by frequency for the HAM and SPAM classes.

根据原始频率计数,您可以推断垃圾邮件包含高频术语,如“免费”,而垃圾邮件包含高频术语,如“考试”。这就是分类器将能够区分一个类和另一个类的方式。

“频率”列是每个术语在所有文档中出现的次数,即 TDM 矩阵各列的总和。“出现”列是每个术语在所有文档中出现的时间百分比。

“频率”和“出现”列都可以用于计算概率估计,但是,“出现”列是优选的,因为它被限制在 0 和 1 之间。

# **第四步。回想一下朴素贝叶斯法则**

根据基本概率,假设另一个事件 **B** 也发生了,那么一个事件 **A** 发生的概率是多少?按顺序的话,**A**给 B 的概率是多少?

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c2ac916bb20192a95310e4394e8ab40c.png)

Probability of A given B.

从下面的文氏图中

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3d9329f29079ce89f2f1f858cd05d6d4.png)

我们可以看到,给定 B 的概率是 A 和 B (交集)发生的**概率除以 B** 发生的**概率**,**即:**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/900fe7404c0a0b8811907d4d91c22d39.png)

Eq. 1

现在,假设 A 也发生了,那么 B 发生的概率呢?根据前面的公式,我们得到:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1cbf5f4f09ce52ff0b386f6285aa8000.png)

Eq. 2

从文氏图中可以看出

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7d3e92b1e8f98064609c9aef8c983af0.png)

因此,通过等式。1 和 Eq。2 我们得到贝叶斯定理:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/cf33ed06385068bc5c1a9e00a32d1580.png)

**Bayes theorem**

鉴于贝叶斯定理在概率论中的重要性,每个术语都有一个名称:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/625045fae7ca9f542a0b68f390f72acc.png)

Naming terms in Bayes theorem

简单来说,“**先验**”*P(A)*、“**证据**”*P(B)*是指相互独立地观察到 A 和 B 的概率,而“**后验**”和“**似然**是观察到给定 B 的**条件** **概率**,反之亦然。

回到我们在垃圾邮件或 Ham 中的电子邮件分类示例,我们要计算的概率是:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/99fc6599097094139c81e5b96889d5bc.png)

其中 **x** 是包含来自垃圾邮件的单词的特征向量:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b22e2702a79fb290e5ff8adb2bb00912.png)

Feature vector **x** composed of **n** words coming from spam emails.

*朴素贝叶斯*结果是“**可能性**”是在一组垃圾邮件或业余电子邮件中看到每个单词的个体概率的乘积。我们在步骤 3 中计算了这些概率,并将它们存储在“发生”列中。形式上:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/40971eab4758062380b5b9b846cd0926.png)

注意“**证据**”是一个仅取决于特征的常数因子,因此在前面的等式中为“**可能性**”计算引入了比例符号。

此外,由于我们的数据集有 3 封垃圾邮件和 3 封垃圾邮件,我们知道“**优先于**”*P(垃圾邮件)*是 50%。

总之,由于我们在贝叶斯定理中有所有必要的术语(“**可能性**”、“**先验**”和“**证据**”),我们可以继续计算“**后验**”概率。回答这个等式的概率是,给定的(看不见的)电子邮件是垃圾邮件的概率是多少?

> 回想一下,朴素贝叶斯分类器的主要假设是每个特征(单词)彼此独立。

# **第五步。计算收到垃圾邮件的概率**

假设我们计算了垃圾邮件或业余爱好者电子邮件中出现的术语的概率数据库,我们可以继续进行*朴素贝叶斯分类器*的最后一步,即分类。

正式的决策规则是:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/73f4c073f3cf4ed1915d95179ca04673.png)

Decision rule: pick the most probable hypothesis.

这意味着,对于每个传入的电子邮件,我们必须计算此类电子邮件是垃圾邮件和垃圾邮件的概率(即,对于每个类),并且我们的最终验证将由最大概率给出。

以下面的电子邮件为例:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/58d8b477af52ed92f973d066a10035c9.png)

Test HAM email.

假设不在我们的训练集中的单词的任意小概率为 1e-2,则每个类别的概率为:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6eb01dde7dc38970b057512d6b04a27d.png)

表明该电子邮件是垃圾邮件。

关于小数字的链乘的注释(感谢 [jgrahamc](https://news.ycombinator.com/user?id=jgrahamc) ):

【http://getpopfile.org/docs/faq:bayesandlogs】
参考:“实际上,取概率的 log()是有用的,这样你就可以处理对数的和,而不是乘以小的浮点数”

## 参考资料和源代码:

[![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5cd71e827eea520f79696a3f5ab61aca.png)](https://amzn.to/2Xjkuqa)

文件处理、TDM 矩阵计算、频率、最终分类和示例电子邮件的源代码可以在这个存储库中找到:[**https://github . com/gchave z2/code _ machine _ learning _ algorithms**](https://github.com/gchavez2/code_machine_learning_algorithms)。

该代码大量借鉴了 O'Reilly Media 出版的[Conway&Myles Machine Learning for Hackers 一书第 3 章](https://amzn.to/2Xjkuqa),该书还提供了一个更大的垃圾邮件和业余邮件数据库,以及估计不在训练集词汇中的单词概率的策略。

*我是劳伦斯伯克利国家实验室的博士后,在那里从事机器学习和高性能计算的交叉工作。*

*如果你觉得这篇文章很有趣,请随意打个招呼,联系 LinkedIn* *,我总是很乐意与该领域的其他专业人士交流。*

*一如既往:非常感谢评论、问题和分享!❤️*

[![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/fc9812283b6ecba784677161ec8ba4ef.png)](http://eepurl.com/giSKB9)

No Spam, ever.

# 用机器学习实现星巴克的盈利促销策略(上)

> 原文:<https://towardsdatascience.com/implementing-a-profitable-promotional-strategy-for-starbucks-with-machine-learning-part-1-2f25ec9ae00c?source=collection_archive---------11----------------------->

在这个系列中,我们将为星巴克设计一个促销策略,并介绍从数据预处理到建模的整个过程。这是我为 Udacity 数据科学家 Nanodegree Capstone 项目设计的解决方案。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b7f216b2994797da58853fc3d5a78e71.png)

*在本系列的第一部分,我们将介绍项目介绍、数据集描述、可用促销类型、缺失值输入、数据预处理和探索性数据分析。*

[*链接*](https://medium.com/@joshxinjielee/implementing-a-profitable-promotional-strategy-for-starbucks-with-machine-learning-part-2-8dd82b21577c) *到本文第二部分。*

*本文附带的代码可以在* [*这里*](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) *找到。*

# 一.导言

在这一系列文章中,我们将探索星巴克奖励移动应用程序的数据,并利用机器学习来设计促销策略。我们还将浏览整个数据预处理工作流程,并设计一个指标来测试我们的促销策略。

我们希望在本文结尾回答的问题是:

我们能通过采取更具选择性的促销策略来增加星巴克的利润吗?

作为 Udacity 数据科学家 Nanodegree Capstone 项目的一部分,星巴克友好地提供了一个模拟数据集,模拟客户在他们的奖励移动应用程序上的行为。数据集也可以在我的 [GitHub](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) 仓库中找到。

情况是这样的:每隔几天,星巴克就会在手机 app 上向顾客发出促销信息。这些可以是折扣优惠、买一送一优惠(BOGO)或信息优惠。

促销通常需要一定的成本。在我们的例子中,买一送一或打折促销会导致公司的“利润损失”,因为公司牺牲了一些利润来给予顾客金钱激励(免费产品或折扣)。

如果顾客已经愿意在没有任何促销的情况下购买星巴克的产品,那么我们应该放弃给这部分顾客任何促销。

此外,还有一群人被称为“睡狗”。“睡狗”是购买你的产品的人,但如果他们被包括在你的营销活动中,他们会停止这样做。

因此,向每个人发送促销信息并不是一个合理的商业策略。理想情况下,我们希望将促销信息发送给那些只有在收到优惠信息时才会购买的人,同时我们也希望避免将促销信息发送给“睡觉的狗”。

我们的目标是制定一个促销策略,该策略可以确定我们应该向哪些人进行促销,以实现公司利润的最大化。

为了帮助我们解决这个问题,我们将利用抬升模型。提升模型允许我们对治疗(在我们的案例中是促销)对客户购买行为的增量影响进行建模。

如果您有兴趣了解关于提升模型的更多信息,请查看这篇[文章](https://medium.com/datadriveninvestor/simple-machine-learning-techniques-to-improve-your-marketing-strategy-demystifying-uplift-models-dc4fb3f927a2)。

虽然提升模型确实非常有益,但它们有时很难实现。值得注意的是,最大的挑战是找到最佳方法来模拟促销对个人反应的增量影响。

尽管如此,这些模型为我们提供了提高促销效果的最佳机会。所以,我们应该试一试!

# 二。资料组

Starbucks 为此项目提供了 3 个数据文件。下面列出了数据文件及其模式:

## 作品集. json

1.  id(字符串)—优惠 id
2.  offer_type (string) —优惠的类型,如 BOGO、折扣、信息
3.  难度(int)——完成报价所需的最低花费
4.  奖励(int) —为完成一项提议而给予的奖励
5.  duration (int) —报价的有效期
6.  渠道(字符串列表)—发送要约的媒介

投资组合数据集包含有关 10 种可通过应用程序获得的促销活动的信息。

有三种主要的促销方式:信息促销、折扣促销和买一送一(BOGO)促销。

在数据集中,术语“优惠类型”用于指代类似促销的集合。例如,它可以指一系列的折扣促销。

我发现这个术语令人困惑,所以我将把类似的促销统称为简单的家庭型优惠。我将使用术语“优惠类型”或“促销类型”来指代 10 种促销类型中的每一种。

信息提供没有附加的金钱奖励。这些促销活动主要是饮料广告。

折扣优惠通常提供少量的金钱奖励,前提是顾客在优惠期限内消费了一定数量的钱。

解锁奖励所需花费的金额将被称为提供的难度。

BOGO 类似于折扣优惠,除了他们提供相当于优惠难度的金钱奖励。

优惠详情可在下面查看:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/45b2628f3fb3ff4d83aca8611ed2c0da.png)

Portfolio dataset with offer id re-encoded

请注意,为了简化工作过程,我将原始报价 id 从它们的原始哈希值重新编码为整数(0–9)。

## profile.json

1.  年龄(整数)—客户的年龄
2.  变成 _ 成员 _ 开(整数)—客户创建应用帐户时的数据
3.  性别(str) —客户的性别
4.  id (str) —客户 id
5.  收入(浮动)—客户的收入

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6e5453ea1a919685d2528307aba64e91.png)

Snapshot of original profile dataset

简档数据集包含关于客户的人口统计信息。

只有 4 个人口统计属性,我们可以工作:年龄,收入,性别和会员开始日期。一部分配置文件数据集有缺失值,这些问题将在本文后面讨论。

## 抄本. json

1.  事件(str) —记录描述(即交易、收到的报价、查看的报价等)
2.  人员(字符串)—客户 id
3.  time (int) —以小时为单位的时间。数据开始于时间 t=0
4.  value(字符串字典)—根据记录,可以是报价 id,也可以是交易金额。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9322ecff174e8ef229c6a9e63fc5592c.png)

Snapshot of original transcript dataset

副本数据集记录了在应用程序上进行购买的时间戳,以及收到、查看或完成报价的时间戳。

在我们继续之前,有几个关于数据集的细节需要强调。

1.  客户不需要在一次交易中花光所有的钱来激活优惠。只要他们在要约的持续时间内达到要求的金额,无论他们进行了多少次交易,他们都将获得要约的奖励。
2.  即使用户实际上没有查看报价而是花费了所需的金额,报价也可以被记录为已完成。
3.  即使优惠已过期,也可以将优惠记录为已完成。例如,让我们考虑在时间 7 到期的报价。如果客户在稍后的时间(可能是时间 20)花费了所需的金额,该报价仍将被记录为已完成。实际上,这一优惠并未“完成”,客户也不会享受到促销的回报。因此,在处理数据时,我们需要考虑这种情况。
4.  每个报价、人员和时间组合都没有唯一的序列号。这可能会导致关于转录数据集的解释的混乱。例如,客户可能在时间 7 收到 10 美元的 BOGO 折扣,在时间 31 收到另一个相同的报价。该应用然后可以在时间 52 记录要约完成。但是,我们不知道哪个是在时间 52 完成的相关报价,因为问题编号为 3。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/aa450f2a06229b29d8abcc0a322be1b1.png)

An example illustrating problems 3 and 4\. Note the events at time 0, 6, 132\. This offer has a validity of 7 days and should have been expired at time 7\. Nonetheless, it was “completed” 132 days after it was sent.

这些特性意味着,尽管我们应该能够恢复其中的大部分,但重新获得每个报价的确切结果可能是不可能的。

# 三。可用优惠

以下是通过该应用程序提供的优惠:

***优惠 id 号:优惠家庭类型、有效期、难度、奖励***

1.  优惠 id 0:折扣 10/20/5
2.  优惠 id 1:折扣 7/7/3
3.  优惠 id 2:折扣 7/10/2
4.  报价 id 3:信息 4/0/0
5.  优惠 id 4:BOGO 2010 年 10 月 5 日
6.  报价 id 5:信息 3/0/0
7.  报价 id 6: BOGO 7 月 5 日
8.  优惠 id 7:BOGO 2010 年 7 月 10 日
9.  报价 id 8: BOGO 5 月 5 日
10.  优惠 id 9:折扣 10/10/2

我将在整篇文章中使用相同的报价参考系统。

注意:我将使用 Offer id 10 来表示非 Offer 情况。这一点过一会儿就清楚了。

# 四。预测缺失值

大约 12.8%的个人资料数据集包含性别和收入的缺失值。巧合的是,个人要么缺少年龄和收入数据,要么一个都没有。此外,性别和收入信息缺失的个人都有相同的 118 岁。

很可能这些人实际上并没有 118 岁。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d733df020cd2ba79fdbe7f3f1e59eb95.png)

Distribution of Age. Note the outlier group at age 118.

合理的解释是,在处理缺失的人口统计数据时,118 是应用程序的默认输入年龄。

由于年龄、收入和性别是唯一可用的人口统计数据(除了会员开始日期),因此解决这些缺失数据非常重要。

一种解决方案是删除丢失数据的个人。然而,这也将意味着丢失很大一部分数据。

由于该群体的规模,这些人可能具有不同的人口统计属性。因此,我决定使用基于机器学习的方法来预测缺失值,而不是用单个值(如平均值)来输入缺失值。

## 特征工程

由于会员开始日期是唯一可以用于我们的机器学习模型的人口统计信息,我希望不同性别、收入水平和年龄组的个人之间存在交易行为的差异。

交易行为的统计数据将在单个基础上进行汇总。对于每个人,我都记录了:

1.  收到的报价数量
2.  成功完成的出价数
3.  已尝试但未完成的聘用数量
4.  成功完成的出价百分比
5.  尝试出价的百分比
6.  报价总支出
7.  为报价进行的交易总数
8.  报价的平均每笔交易支出

这些数字是在累积的基础上(所有报价加无报价)、每种报价类型(id0–9 加 id 10 代表无报价)和每种报价系列类型(BOGO、折扣、信息)汇总的。

*注:成功/尝试报价的定义可在第五节定义成功/尝试/失败报价小节中找到。数据预处理:生成月度数据*

还计算了其他比率,例如:

1.  优惠类型和优惠系列类型的支出占总支出的比率
2.  优惠类型和优惠系列类型的交易数量占交易总数的比率
3.  收到的优惠类型和优惠系列类型的数量与收到的优惠总数的比率

由于创建了大量的特性,所以我不会在本文中一一列出。要了解更多细节,请参考我的 [GitHub](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) 存储库中的文件 *input_missing_data.ipynb* 中的代码。

任何空值都将被替换为 0,因为空值通常表示没有收到/查看/完成报价或没有支出。

为了区分 1)收到一份工作邀请但没有回应的情况和 2)根本没有收到工作邀请的情况,跟踪了每个人收到的工作邀请的数量。

模型的输入特征将是新设计的特征和成员资格开始日期。

由于特征的高度稀疏性,很大程度上由于低完成率和报价的低支出,对这些输入特征进行了降维。

为了防止具有较大值的特征支配其他特征,对特征进行了归一化。标准缩放用于将这些特征减少到平均值 0 和标准偏差 1。

## 模型

创建了 3 个独立的模型,每个模型对应一个缺失的属性:年龄、收入和性别。没有缺失值的概况数据集部分将用于训练模型(约占概况数据的 87.2%)。

年龄和收入模型都是回归问题,而性别模型是多类分类问题。在网格搜索过程中使用具有 5 个折叠的 k 折叠交叉验证来优化模型。

XGBRegressor 和 XGBClassifier 分别是为回归和分类任务选择的模型。这些是相对快速和准确的基于树的非线性模型。

这些模型唯一的主要缺点是它们不能天生地提取特征交互。

例如,如果我们的数据集只跟踪每种优惠类型的总支出(例如,BOGO 5/5/5 为 10 美元,BOGO 7/10/10 为 30 美元,等等。),但并非针对每种家庭类型(例如,所有 BOGO 优惠均为 40 美元),XGBoost 模型将仅基于每种优惠类型的支出做出建模决策。它无法提取任何关于 BOGO 优惠等级总支出的信息,也无法在建模过程中使用这些信息。

因此,如果我们想要我们的模型利用它们,我们将需要手工设计这些特性交互。

## 韵律学

均方根误差(RMSE)被选为年龄和收入模型的优化指标,因为我想优先考虑预测的准确性。

请注意,最小化 RMSE 等同于最小化均方误差(MSE),因为 RMSE 是 MSE 的平方根(线性变换)。

RMSE 是这样计算的:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d08780a38f1e0250b815318415b668c3.png)

In our case, Pi is the predicted age/gender and Oi is the actual age/gender for each sample i.

另一方面,微观平均 F1 分数被用作性别模型的优化指标。微观平均 F1 分数将按以下方式计算:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/84b6974143d687ad7f8d4c791391d5c9.png)

在哪里

*   TP —真阳性。预测属于性别 *g* ,实际属于性别 *g* 的样本数。
*   FP —误报。预测属于性别 *g* 但实际不属于性别 *g* 的样本数。
*   TN——真正的否定。预测不属于性别 *g* ,实际不属于性别 *g* 的样本数。
*   FN —假阴性。预测不属于性别 *g* 但实际属于性别 *g* 的样本数。

f、M、O 分别代表“女性”、“男性”和“其他”性别。

## 结果

预测个人年龄的模型实现了大约 16.5 的 RMSE,而预测个人收入的模型实现了大约 13,500 的 RMSE。这些数字意味着,平均而言,年龄预测误差 16.5 岁,而收入预测误差 13500 美元。

另一方面,在性别预测模型的测试集上记录了 0.6 的 F1 分数(1 是最佳可能模型的分数)。一个有趣的观察是,性别的预测值似乎由男性主导。如果时间允许,可以进行更多的调查,以查明为什么会出现这种情况。

这些模型指标远非理想。然而,考虑到可用的信息量有限,这些结果是可以接受的。尽管如此,这些估算的数字应该比用常数填充缺失值的替代方法更好地为我们服务。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f8565051ac17b1ffbc511671b45b4a77.png)

Left: Original Distribution of Age, Middle: Distribution of Predicted Age for Missing Data, Right: Final Combined Distribution of Age

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/93595545da01c26ff9bbfc0075796dc0.png)

Left: Original Distribution of Income, Middle: Distribution of Predicted Income for Missing Data, Right: Final Combined Distribution of Income

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/478bbb59d060df501092649332e866d7.png)

Left: Original Distribution of Gender, Middle: Distribution of Predicted Gender for Missing Data, Right: Final Combined Distribution of Gender

# 动词 (verb 的缩写)数据预处理:生成每月数据

为了将数据集转换成有用的东西,我们必须执行大量的数据清理和预处理。

在本节的最后,我们将生成一个数据集,如下所示:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/25f8ea49cd163693d694cbbadf96ae44.png)

Snapshot of Monthly Data After Data Preprocessing

主要任务是确定与没有收到报价相比,收到报价时可能会花更多钱的人。因此,我们需要一个数据集来反映用户在促销和非促销情况下的反应。

我们还对顾客的行为是否会随着时间的推移而改变感兴趣。

因此,我选择每月汇总客户的反馈。由于没有给出实际的日期,我将估计一个月为 30 天,并将第 0 天视为第 0 个月的开始。

从上面的快照中,我们知道“人员 id 2”在第 0 个月收到了促销“优惠 id 2”。这个人在这个月里没有在这个提议上花任何钱。同样,“人物标识 2”也没有在非促销场合花任何钱。

请注意,为简单起见,我将使用“优惠 id 10”来表示非促销支出。

每个月,数据集应该跟踪:

1.  如果客户收到优惠,他们在优惠有效期内消费了多少。如果他们不花钱,这个数字可能是 0。
2.  顾客在没有优惠的时候花了多少钱。如果他们不花钱,这个数字也可能是 0。

对随机选择的个人交易的检查表明,客户通常一个月不会收到超过 1 个报价。因此,与每月的促销日相比,消费者暴露于更多的非促销日。

每月汇总数据比每天/每周汇总数据更受欢迎,因为大多数客户每隔几个月就会收到一次报价。如果每天/每周汇总数据,将会有太多天/周没有任何促销活动。

我现在将讨论生成每月数据集的过程。这是一个冗长的讨论,最好遵循代码。因此,如果您想跳过这一部分,请继续阅读第六部分。本页末尾附近的“探索性数据分析”。

## 定义成功/尝试/失败的报价

在我们跟踪顾客在促销有效期内花了多少钱之前,我们需要根据可能的结果对优惠进行分类。有三种可能性:成功、尝试和失败。

要将要约归类为成功,必须在要约到期前收到、查看并完成要约。这意味着客户知道促销活动,并因此进行交易。

如果客户在查看报价之前完成了报价,则报价不会被分类为成功,因为客户在进行交易时不受报价的影响。

如果顾客在查看报价之前进行了一些交易,但是没有花足够的钱来完成报价。如果他/她在要约仍然有效时查看了要约,并在要约到期前花了更多的钱来完成要约,那么要约也将被归类为成功。

因此,成功报价的事件流程是:

*   已收到报价-> *可选:已成交* - >已查看报价- >已成交- >已完成报价- >已到期报价

“尝试过的优惠”是指顾客在优惠到期前查看了优惠,花了一些钱,但没有完成它。因此,客户没有花足够的钱来完成要约的要求。

由于信息性要约没有要约完成事件,如果客户在要约有效期内查看了要约并花费了一些钱,则它们将被视为尝试性要约。

尝试报价的事件流程如下:

*   报价已收到-> *可选:成交- >* 报价已查看- >成交- >报价已到期- > *可选:报价已完成*

失败的报价将不属于前面提到的两个类别。

例如,如果收到并查看了要约,但在要约到期之前没有进行交易,则该要约将是失败的要约。

如果要约在到期前收到但未被查看,也将被归类为失败的要约,即使在要约的有效期内花了钱。这是因为顾客在消费时不受优惠的影响。

跟踪促销期间花费的金额相当于找到成功和尝试过的优惠花费的金额。

## 分割抄本数据集

预处理的第一步包括将原始转录物分成 4 个更小的子集:

1.  *抄本 _ 报价 _ 已收*:跟踪客户何时收到报价以及他们收到了何种报价
2.  *文字记录 _ 报价 _* 已查看:跟踪客户查看报价的时间以及他们查看的报价类型
3.  *抄本 _ 报价 _ 已完成*:跟踪客户何时完成报价以及他们完成了何种报价
4.  *transcript_trans* :跟踪客户进行的所有交易

## 生成带标签的月度交易数据

首先,我们将确定成功或尝试过的产品。我们首先将*抄本 _ 报价 _ 接收、抄本 _ 报价 _ 查看*和*抄本 _ 报价 _ 完成*合并在一起*。*生成的数据帧将如下所示。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7e897a8774b95eeda9124a0581c1f459.png)

在这个阶段,合并过程中产生的许多报价将是无意义的。

我们可以通过保留符合以下条件的产品来消除大量虚假产品:

1.  完成的报价时间>查看的报价时间>收到的报价时间
2.  (查看的报价时间>收到的报价时间)和(完成的报价时间为空)
3.  查看的时间报价和完成的时间报价均为空

现阶段虚假要约依然存在,需要进一步处理。

我们可以通过将要约的持续时间与要约的接收时间相加来计算所有要约的到期时间。

接下来,我们可以将这些提议分为可能的结果:成功、尝试或失败/错误。请注意,在这个阶段的分类并不一定意味着要约是真正成功的或尝试。我们稍后将需要交易信息来找出答案。

满足以下条件的报价将被归类为可能成功的报价:

1.  (收到的优惠时间≤查看的优惠时间)和(查看的优惠时间≤完成的优惠时间)以及(完成的优惠时间≤优惠到期时间)

满足以下条件的要约被归类为可能尝试的要约:

1.  (收到报价时间≤查看报价时间)和(查看报价时间≤报价到期时间)以及(报价到期时间
2.  (收到的时间报价≤查看的时间报价)和(查看的时间报价≤时间报价到期)以及完成的时间报价为空

不满足这些条件的其余提议或者是失败的或者是错误的提议,并且将被丢弃。

除了第一次出现的情况之外,任何具有重复的“接收时间”、“人员标识”和“报价标识”值的报价都将被删除。一个人不太可能一次收到同一种聘用不止一次,这些重复的条目是在合并过程中生成的错误条目。

我们将调用结果数据帧*succ _ tryed _ offers*。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/718964ede2d6ed93646ccd153e3691e2.png)

A snapshot of succ_tried_offers at this stage of processing

接下来,我们可以将*的抄本 _ 交易*与*的成功 _ 尝试 _ 报价*合并,以获得成功/尝试报价和交易之间所有可能的交叉积。

我们可以标记每笔交易,看看它们是否发生在报价有效期内。换句话说,我们将检查消费是否发生在收到报价之后和报价过期之前。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/de48e97c142378aee999429331a4b239.png)

在有效期内发生交易的*succ _ tryed _ offers*中的任何报价都可能是实际成功或已尝试的报价。

然后,我们可以将带标签的事务执行左合并,返回到原始的事务副本,以避免任何潜在的事务重复计算。这也将使我们能够确定哪些交易发生在非促销期间。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/70ecb28b48e1c01d8499504a7b6b3f07.png)

The labelled transactions

接下来,我们可以分配交易发生的月份,并根据月份号、人员 id 和优惠 id 聚合数据。这将每月生成一份客户在促销和非促销期间消费金额的汇总。我们将该数据帧称为*月度交易*。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/941053c3b12248d8c9b4113c12cce416.png)

A snapshot of monthly_transactions

## 寻找没有每月交易的优惠

从*succ _ tryed _ offers*中,我们知道哪些报价是成功的或尝试过的。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/96340907a5a4482f7e529b0f188582b0.png)

Offers that were successful or tried

我们可以从*抄本 _received 中获得星巴克发出的所有报价的列表。*

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/152df4effb3d54ed0944db2d9e357d11.png)

Snapshot of all offers sent

两者之间的差异可以告诉我们哪些提议失败了。这些要约在有效期内没有引发任何货币交易。

接下来,我们可以指定收到这些失败报价的月份号,并将结果数据帧命名为 *monthly_failed_offers。*

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e8ecec191bdc7941337ba9aa78258291.png)

Snapshot of *monthly_failed_offers*

## 找出个人没有进行非要约交易的月份

请注意 *monthly_transactions* 已经跟踪了客户在非促销期间的花费。我们的目标是找出哪些月份的顾客在非促销期间没有花钱。

首先,我们生成月份号、人员 id 和报价 id 10(非促销曝光)的所有可能组合。我们把这个数据帧称为 *non_offer_trans* 。

然后,我们可以将 *monthly_transactions* 数据框架合并到 *non_offer_trans* 中,以找出哪些月份-个人组合在非促销期间没有货币交易。

因此,我们将获得客户在非促销情况下不花钱的月度账户。我们姑且称这个数据帧 *no_offer_no_trans* 。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6883b0fc3a150bed6c14a0fb3bb916c0.png)

Snapshot of no_offer_no_trans

## 将它们聚集在一起

最后,我们可以将 *monthly_transactions* 、 *monthly_failed_offers* 和 *no_offer_no_trans* 串联在一起*,生成 *monthly_data**产生的数据集每月追踪每个人在发送给他们的不同促销活动上花了多少钱,以及他们花了多少非促销费用。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d170fac52ca9554bf6d7c0de1b1e7a76.png)

Snapshot of monthly data at this stage

## 计算利润并生成标签

接下来,我们必须计算数据集的每个实例产生的利润。我们首先需要计算每个人每月收到的报价数量。这使我们能够计算与报价相关的成本。

一个简单的方法是检查个人是否在一个月内接触到每种类型的一个以上的报价。通过检查*抄本 _ 已接收*,我们注意到以下内容:

1.  没有人在同一个月内多次收到相同的报价类型。
2.  如果个人收到下个月到期的要约,他/她在下个月将不会收到类似的要约。例如,如果个人在第 16 个月收到“要约 id 2 ”,而要约在第 17 个月到期。他/她不会在第 17 个月收到另一个“要约 id 2”。

因此,我们可以得出结论,客户每月最多只能接触到一次优惠类型。

这意味着 *monthly_data* 中的成本只是完成促销的奖励。

我们可以通过以下 3 条规则来计算每个人每个月为每种优惠类型创造的利润:

1.  如果要约成功,利润将是每月收入减去要约的成本。请注意,提供信息是没有成本的。
2.  如果要约不成功,利润将是在该实例中产生的收入。
3.  如果交易不是要约的一部分,利润就是收入,因为不涉及成本。

我们将使用的提升模型涉及在两种情况下对给定人员和月份的利润概率进行建模:

1.  如果这个人收到一份工作邀请。
2.  如果这个人没有收到聘书。

因为我们想要预测利润的概率,我们的标签( *has_profit)* 将只是一个指示变量,指示该实例是否有利润。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/25f8ea49cd163693d694cbbadf96ae44.png)

Resulting monthly_data obtained at the end of the process

# 不及物动词探索性数据分析

## 大多数优惠都没有被顾客尝试过

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6fe7a66f033279fb913e3d2dbb74a009.png)

从上面的图表中,我们注意到绝大多数的优惠都没有被顾客尝试过。

一个普遍的观察是,具有更长有效期、更高回报和更低难度的报价往往具有更高的成功/尝试率。

请注意,信息性报价无法完成,因为它们缺乏难度。因此,他们要么尝试或失败。

## 只有少数客户成功完成或尝试了一次以上的优惠

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b6a2c8a6299e60adb392b9faf2d9b368.png)

在研究期间,大多数客户收到了 3 到 6 份报价。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e942d3ac2effd6c8754f7e46e039265d.png)

然而,绝大多数客户没有成功完成任何优惠。他们中只有一小部分人完成了 1 次报价,更少的人完成了 2 次或更多次报价。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/bb0c58190a49c9c6258371c77bf1ae16.png)

对于尝试过(但未成功完成)的要约也是如此。面对优惠,很少有顾客做出反应(花钱)。对两个或两个以上的提议做出回应的情况极为罕见。

总的来说,优惠似乎效力有限。

## 月度利润趋势

左边的图表显示了每月获得晋升的人数。此外,图表将显示这些人中有多少人每月产生促销利润和非促销利润。盈利实例也可以定义为来自 *monthly_data* 数据集的数据点,其 *has_profit* 标签为 1。

右边的图表显示了接受促销的个人每月产生的总利润,以及他们的促销和非促销支出的总利润。

从这些图表中,我们可以衡量促销的有效性,并评估这些促销的有效性是否随时间而变化。

**折扣 10/20/5(优惠 ID 0)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/395c7ebe9a9506ee274bb4829e4a5737.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9bcc150fa55f40d5f5c750e5c90c1cf1.png)

Plotted from individuals who received Discount 10/20/5 offers each month

**折扣 7/7/3(优惠 ID 1)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/bfd8219b698cfc2c26f0fc69f7ac3058.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/482fe431d626de1b9cfedfd3200a5d4e.png)

Plotted from individuals who received Discount 7/7/3 offers each month

**折扣 7/10/2(优惠 ID 2)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4ad9ef84471c874b2204e4bbb281cba2.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d03ef833ebb67794d0742ed1b3b754ca.png)

Plotted from individuals who received Discount 7/10/2 offers each month

**信息 4/0/0(报价 ID 3)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3d95bd7eafd44060994907818ad68845.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/632ce69af4bed4459aaee9b44361e0cc.png)

Plotted from individuals who received Informational 4/0/0 offers each month

**BOGO 2010 年 5 月 10 日(报价 ID 4)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9bf27e6ee6144156e7e47eddf32b52e2.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c60d2d62aa3a1176bc26a3a3d52c4199.png)

Plotted from individuals who received BOGO 5/10/10 offers each month

**信息 3/0/0(报价 ID 5)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a2715416b178a33a34b1d0fb585b7b5e.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/173ffc509db5d9461f5f5c56ad082f86.png)

Plotted from individuals who received Informational 3/0/0 offers each month

**BOGO 5 月 7 日(报价 ID 6)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a2348560d3bb6daa856b1f8aeb27ae53.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/85f2f9d05fd7329037b5749b198ebba6.png)

Plotted from individuals who received BOGO 7/5/5 offers each month

**BOGO 2010 年 7 月 10 日(报价 ID 7)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f67a2def9267f342299b38628d928198.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3bbfb1158b682c24e7457ba2e17af05b.png)

Plotted from individuals who received BOGO 7/10/10 offers each month

**BOGO 5/5/5(报价 ID 8)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/20931b89629403dcf2c195e2333ccc18.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/af9e8bcefaa50baca664c23579816b42.png)

Plotted from individuals who received BOGO 5/5/5 offers each month

**折扣 10/10/2(优惠 ID 9)**

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/bf448290fbd653aead0cdb7efd7061ae.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/bc2473944acc40b85455a1bf7a3700f6.png)

Plotted from individuals who received Discount 10/10/2 offers each month

一个反复出现的观察结果是,在每月接受促销的人中,他们更有可能在没有任何促销活动的日子里购物,而不是在有促销活动的日子里。因此,非促销利润实例的数量通常超过促销利润实例的数量。

在促销和非促销期间产生的利润总额中也观察到类似的情况,非促销利润经常超过促销利润。

当然,一个人接受要约的天数通常低于一个人没有接受任何要约的天数。

每个月,个人受要约影响的天数受到要约有效期的限制,该有效期可以是 3 至 10 天。请注意,没有人在一个月内收到相同的报价超过一次。

然而,即使我们考虑了暴露期之间的差异,在大多数情况下,非促销利润仍然会超过促销利润。

因此,这表明促销在诱导顾客比平时多花钱方面的效果有限。

如果顾客普遍愿意购买星巴克的产品,而没有得到任何促销,那么发送更多的促销信息将不符合星巴克的最佳利益,因为这样做可能会由于促销成本而侵蚀公司的盈利能力。

我们的希望是,我们将能够识别出那些只有在获得促销时才消费的人。限制向这些人发送促销信息将有助于最小化成本和最大化利润。

在本系列的第 2 部分中,我们将介绍特征工程、提升模型的实现、对模型和数据的额外调整、结果以及项目的结论。[](https://medium.com/@joshxinjielee/implementing-a-profitable-promotional-strategy-for-starbucks-with-machine-learning-part-2-8dd82b21577c)链接到文章的第 2 部分。

*本文附带的代码可以在这里*[](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone)**找到。**

# 用机器学习实现星巴克的盈利促销策略(下)

> 原文:<https://towardsdatascience.com/implementing-a-profitable-promotional-strategy-for-starbucks-with-machine-learning-part-2-8dd82b21577c?source=collection_archive---------18----------------------->

在这个系列中,我们将为星巴克设计一个促销策略,并介绍从数据预处理到建模的整个过程。这是我为 Udacity 数据科学家纳米学位顶点项目提供的解决方案。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/58e3b9121bd55117fd388c3d175fd955.png)

*在本系列的最后部分,我们将介绍特征工程、隆起模型的实施、附加模型和数据调整以及项目结果。*

[*链接*](https://medium.com/@joshxinjielee/implementing-a-profitable-promotional-strategy-for-starbucks-with-machine-learning-part-1-2f25ec9ae00c) *到本文第 1 部分。*

*本文附带的代码可以在* [*这里*](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) *找到。*

# 七。特征工程

只有 4 个人口统计属性的工作,特征工程可以证明是有益的。

顾客经常在很长一段时间内没有得到促销。因此,累积值和移动平均值将用于捕捉客户过去的交易行为。

将计算以下统计数据的累积和:

1.  总支出
2.  交易数量
3.  收益

例如,时间 N 的累计利润将为

*N 时累计利润= 0 时累计利润+…+N-1 时累计利润*

请注意,第 N 个月的累积和的计算将基于第 0 个月到第 N-1 个月的值,以避免数据泄漏。

同样,计算相同统计数据的移动平均数(滚动平均数)。例如:

*N 时利润移动平均值=**N 时累计利润/月数*

将为每个“报价 id”计算累积统计数据和移动平均值,包括非促销情况(由“报价 id 10”表示),以及累积基础(所有报价和无报价)。

例如,我们将计算:

*   *报价 id 0 在时间 N 的累计利润*
*   *报价 id 1 在时间 N 的累计利润*
**   *报价 id 10 在时间 N 的累计利润*
*   *id 为 0–10 的所有报价在时间 N 的总累计利润*

此外,每笔交易的累计支出(总支出/总交易次数)和每笔交易的累计利润(总利润/总交易次数)也将被添加。

任何缺失的值都将用 0 填充,因为空值表示客户尚未进行任何交易。

最后,将计算这些工程特性的 1 个月滞后,以使我们的模型能够捕捉交易行为的最新变化。

由于第 0 个月之前没有上一个月,因此第 0 个月的工程特性和第 1 个月的 1 个月延迟特性将完全由空值组成。因此,我们将从训练数据中丢弃月份 0 和 1。

同样,由于创建了大量的特性,我不会在本文中一一列出。要了解更多细节,请参考我的 [GitHub](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) 存储库上的代码,位于文件*generate _ monthly _ data . ipynb*下。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/74f24fc9f4cac0543152f626348d7575.png)

Examples of engineered features

# 八。指标提升模型和推广策略

我们将使用单一模型来预测促销和非促销风险的利润概率。在训练阶段,创建一个指示变量来跟踪来自 *monthly_data* 的数据点是否属于促销。

每种类型的报价都有自己的模型,因此每个模型有一个指标变量就足够了。稍后将讨论使用单独模型的基本原理。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6380df733949443a00ea37a6a2205f3d.png)

Training Features for promotion ‘offer id 0’. The column ‘offer_id_0’ serves an indicator variable that tracks if a data point belongs to ‘offer_id_0’ (indicator=1), or if it belongs to a non-offer instance (indicator=0). Note that the other training features have been reduced with PCA, a process which we will discuss shortly.

一旦模型被训练,它可以被用来制定我们的促销策略。

在测试我们的策略时,为了预测个人是否应该获得晋升,我们可以通过将指标变量设置为 1 来预测个人在获得晋升时的利润概率。接下来,我们可以通过将指标变量设置为 0 来预测个人在没有获得晋升时的盈利概率。

请注意,相同的模型用于预测促销期和非促销期的利润概率。只有输入,特别是指示变量,在程序中被改变。

如果概率差(也称为抬升效应)大于 0,我们将发送促销。这是因为与没有晋升相比,得到晋升的个人更有可能创造利润。

*提升效应=获得促销时的盈利概率—未获得促销时的盈利概率*

或者,可以使用回归模型来模拟促销活动相对于非促销活动的预期利润额。这可能会告诉我们,通过向个人发送报价,我们可以期望获得多少利润。

对于这个项目,我决定将重点放在利润的概率建模上,而不是利润的预期金额。

此外,还有其他类型的提升模型可用于此任务。

一个这样的例子是使用两个独立的模型来测量提升效应。在这种情况下,一个模型将根据促销数据进行训练,而另一个模型将根据非促销数据进行训练。两个模型预测概率之间的差异将表明抬升效应。

有关其他提升模型的更多信息,请查看这篇文章。

# 九。附加数据和模型调整

在我们讨论建模结果之前,我们将做一些最后的调整。

## 对每种优惠类型使用单独的模型

对所有报价类型使用单一模型的初始试验导致了不令人满意的结果。这可能是因为在不同的报价类型之间,有利可图的实例的数量差别很大。因此,某些优惠类型的正面实例可能比其他优惠类型的权重更大。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/62c19258e86849db4da63e07800078d1.png)

Distribution of labels between the different offer types.

也有可能不同的报价类型共享很少的共同信号,可用于识别有利可图的报价。

因此,决定为每种报价类型创建单独的模型。

每个模型将集中于对单一报价类型的促销和非促销支出的差异建模。

## 使用月度数据的子集

此外,每月数据的缩减子集用于训练每个模型。

主要目标将是模拟个人在收到报价的几个月中的交易行为,并确定他们中的哪些人可能在促销期间比非促销期间花费更多的钱。

只有发送相关要约的月份才会包含在数据集中。此外,我们将只包括那些在这几个月中有促销和非促销交易记录的个人。

例如,假设我们正在处理一个报价 id 为 0 的模型。如果个人 id 1 在第 1 个月收到“优惠 id 0”,则个人 id 1 在第 1 个月的促销和非促销支出将包括在数据集中。如果个人 id 2 在第 1 个月没有收到优惠 id 0,则个人 id 2 在第 1 个月的信息(非促销交易记录)将不包括在内。同样,如果 id 为 1 的人在第 9 个月没有收到 id 为 0 的报价,那么他/她的该月交易信息将不会被使用。

因此,每个报价都有自己独特的月度数据子集。

获取月度数据的子集将允许我们准确地比较同一个人在促销和非促销情况下的月度支出差异。

此外,这种方法将有助于确保模型每个月看到相同数量的促销和非促销风险。这将有助于减少过度适应特定暴露的可能性。

## 标签不平衡

如前所述,标签的价值计数不平衡。数据点更可能是非盈利的 *(has_profit* 标签为 0)而不是盈利的 *(has_profit* 标签为 1)。

如果我们观察促销活动中 *has_profit* 标签的分布,与非促销活动相比,这种不平衡甚至更加明显。对于“优惠 id 0”和“优惠 id 3”的促销来说尤其如此,它们的盈利实例数量极低,而无优惠数据点的盈利实例数量要高得多。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/62c19258e86849db4da63e07800078d1.png)

Distribution of labels between the different offer types.

因此,我们需要解决标签之间的不平衡,以便它们在促销和非促销风险之间保持一致。

如果不解决这种不平衡,模型将更倾向于预测促销的标签为 0,尤其是在“报价 id 为 0”和“报价为 3”的情况下。

合成少数过采样技术 SMOTE 将用于对盈利类进行过采样。换句话说,我们将添加带有 *has_profit* 标签 1 的人工创建的人月实例。

SMOTE 允许我们创建新的观测值,其特征值与原始观测值略有不同。

为了创建一个新的样本,它将从数据集中提取一个数据点,并选择它的一个 k-最近邻。然后,它将获取所选邻居和当前数据点之间的向量,并将该向量乘以介于 0 和 1 之间的随机数。最后,它会将结果添加到当前数据点,以创建新的样本。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f8b17ae75baf03b344a58b398f2cf9dc.png)

An overview of SMOTE. Taken from [Rich Data](http://rikunert.com/SMOTE_explained).

这通常是比仅重新采样原始数据更好的方法,这将创建太多重复的数据点,并导致机器学习模型中的过拟合。

由于过采样通常以精度为代价来提高召回率,所以我选择只对促销数据点进行过采样。这是因为非促销数据点已经比促销数据点具有更高的盈利与非盈利标签的比率。

因此,通过仅过采样促销数据点,促销情况下的盈利与非盈利标签的比率将更接近非促销情况。

最后,将仅对训练数据执行过采样。我们希望我们的验证和测试数据能够模拟真实世界中的实际客户行为,在真实世界中,很可能只有少数客户会每月为公司创造利润。

## 缩放和降维

SMOTE 最适用于连续数据。由于我们的数据是分类变量和连续变量的混合物,我们需要将它们转换成连续变量。一种方法是缩放数据集并执行维度缩减。这将生成一个仅包含连续变量的数据集。

进行降维的另一个好处是,在研究期间,大多数客户通常只对单一类型的报价做出反应。客户可能会收到几种类型的优惠,但大多数人通常只会对一种类型的优惠采取行动。因此,对于许多个人来说,大多数优惠类型的历史消费金额将为 0。

由于我们已经根据每种优惠类型的历史消费行为设计了新功能,这些设计的功能中有很大一部分将是稀疏的(许多功能为 0)。因此,降维将有助于减少数据集的稀疏性。

对每种报价类型分别进行标准化和降维。标准标度用于将所有变量标准化为平均值 0 和标准偏差 1,而主成分分析用于降低数据集的维度。

对于大多数报价类型,40 到 50 个维度足以捕获数据集中的大部分差异。由于要素的原始数量约为 200,这表明数据集中的稀疏程度很高。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/0a9fe36d8018358aad2ef8ac5c2e72c5.png)

Scree plot for Discount 10/20/5 (Offer ID 0) promotion

## 公制的

我们促销策略的绩效将通过净增量收入(NIR)来确定,其中:

*NIR =促销收入—促销成本—非促销收入*

这也可以表示为

*NIR =促销利润—非促销利润*

根据我们的战略,NIR 将根据应该收到报价的个人进行计算。换句话说,这些人有积极的提升价值。

因此,NIR 通过向这些个人发送促销来衡量赚了(或赔了)多少。

例如,让我们假设我们正在计算第 19 个月的 NIR。假设我们的促销策略预测 id 为 15 和 5550 的客户将有正的提升值,他们应该得到促销,这些人在第 19 个月的实际交易记录如下:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1435c649dce6d7b832330627af8e4dd8.png)

Offer id 0 is a Discount 10/20/5 promotion. Offer id 10 tracks non-promotional spending

国家清单报告的计算如下:

*近红外光谱=($ 0+$ 23.20)—($ 8.69+$ 16.76)=-$ 2.25*

## 网格搜索

XGBoost 分类器将用于对利润的概率建模,早期停止用于减少模型的过度拟合。精确回忆曲线下的面积,而不是 ROC 曲线下的面积,被用来决定训练何时应该停止。这一选择是由于数据集中类的不平衡,这意味着使用 ROC 曲线下的面积可能会导致过于乐观的情况。

为了确定最佳促销策略,对以下参数进行了网格搜索:上采样率、树的最大深度和最小子权重。网格搜索将评估每组参数的有效性并测试 NIRs。

上采样比率控制我们应该对促销数据点的利润实例( *has_profit* label 为 1)进行多少次过采样。在促销和非促销的情况下,保持盈利与非盈利的平衡并不总是能取得最佳结果。因此,需要改变上采样比率。

最大树深度越大,最小子权重越低,建模能力越高。这意味着该树更能够学习特定样本的特定关系。另一方面,较小的最大树深度和较高的最小子权重将使模型更加保守,并更好地控制过度拟合。

因为报价是在不规则的月份发送的,所以每个报价的测试月份是不同的。一般来说,发送要约的最后一个月将用作测试月,而倒数第二个月将用作验证月。最后,剩下的几个月将分配给训练数据。在大多数情况下,每个报价大约有 3 或 4 个月的培训时间。

对于这个项目,所选择的促销策略不一定是产生最佳验证 NIR 的策略。据观察,在验证月期间表现最好的策略在测试月期间可能不会产生正的 NIRs。

因此,所选择的策略将是产生最高确认 NIR 同时仍产生阳性测试 NIR 的策略。

如果在验证和测试月都没有发现产生阳性 NIR 的策略,将报告产生最高验证 NIR 的策略。

通常情况下,使用测试结果来调整模型并不理想。然而,我们没有足够的月度数据来增加用于验证和测试期的月数。如果有更多的数据可用,我们可以留出额外的几个月来进行验证和测试。这可能会导致结果更加一致,并允许我们避免使用测试结果来调整我们的策略。

因此,这个项目只是为了证明一个有利可图的促销策略的可行性。如果我们想获得可靠且有利可图的促销策略,还需要进一步的改进。

正如我们一会儿将会看到的,不管我们选择什么策略,提升模型产生的结果通常比实验中最初获得的结果好得多。

# X.结果

我们现在将比较从基线策略和我们的提升模型获得的结果。

基线策略将是研究中采用的原始策略。换句话说,在实际实验中收到提议的每个人都会收到基线策略中的提议。

我们的模型的目标是确定这些人的一个较小的子集,这些人在得到促销时可能会比没有得到促销时花费更多。换句话说,提升模型将只向具有正提升值的个人发送促销。

理想情况下,星巴克可以通过将促销活动仅限于最有希望的顾客来实现利润最大化。

## 折扣 10/20/5(优惠 ID 0)

Offer ID 0 是折扣促销,难度 20 美元,奖励 5 美元,有效期 10 天。

基线策略~验证 NIR:108.70 美元,测试 NIR:4,889.48 美元

提升模型~验证 NIR:72.83 美元,测试 NIR:$ 2,163.47 美元

## 折扣 7/7/3(优惠 ID 1)

Offer ID 1 是一个折扣促销,难度为 7 美元,奖励为 3 美元,有效期为 7 天。

基线策略~验证 NIR:185.14 美元,测试 NIR:4,732.18 美元

提升模型~验证 NIR:60.41 美元,测试 NIR:4.61 美元

## 折扣 7/10/2(优惠 ID 2)

Offer id 2 是折扣促销,难度 10 美元,奖励 2 美元。报价有效期为 7 天。

基线策略~验证 NIR:65.88 美元,测试 NIR:5,519.62 美元

提升模型~验证 NIR:12.40 美元,测试 NIR:3.17 美元

## 信息 4/0/0(报价 ID 3)

Offer id 3 是信息化推广,没有难度,没有奖励。它的有效期是 4 天。根据星巴克的说法,这意味着顾客将在 4 天内“感受到”它的影响。可能的解释是,客户将能够在 4 天内查看应用程序中的报价。

基准战略~验证国家清单报告:$4,193.67,测试国家清单报告:$8,754.95

升级模型~验证 NIR: $29.39,测试 NIR:$ 34.26

## BOGO 2010 年 10 月 5 日(报价 ID 4)

Offer id 4 是买一送一的促销活动,难度 10 美元,奖励 10 美元。它的有效期是 5 天。

基线策略~验证 NIR:$ 4,634.69,测试 NIR:$ 7,027.36

升级模型~验证 NIR:12.39 美元,测试 NIR:10.20 美元

## 信息 3/0/0(报价 ID 5)

优惠 id 5 是信息促销,有效期为 3 天。

这些是模型的结果:

基准战略~验证国家清单报告:$5,188.06,测试国家清单报告:$6,707.87

升级模型~验证 NIR:2.19 美元,测试 NIR:130.91 美元

## BOGO 2005 年 7 月 5 日(报价 ID 6)

Offer id 6 是买一送一的促销活动,难度 5 美元,奖励 5 美元。它的有效期是 7 天。

这些是模型的结果:

基线策略~验证 NIR:121.58 美元,测试 NIR:6,542.62 美元

提升模型~验证 NIR:21.81 美元,测试 NIR:10.15 美元

## BOGO 2010 年 10 月 7 日(报价 ID 7)

Offer 7 是买一送一的促销活动,难度 10 美元,奖励 10 美元。优惠 id 7 类似于优惠 id 4,只是它的有效期为 7 天。

基线策略~验证 NIR:65.13 美元,测试 NIR:6,207.28 美元

提升模型~验证 NIR:24.29 美元,测试 NIR:0.73 美元

## BOGO 5 月 5 日(出价 ID 8)

Offer id 8 是买一送一的促销活动,难度 5 美元,奖励 5 美元。它与报价 id 6 相同,只是有效期较短,只有 5 天。

基准战略~验证国家清单报告:$5,779.91,测试国家清单报告:$7,508.97

升级模型~验证 NIR: $481.78,测试 NIR:$ 786.3

## 折扣 10/10/2(优惠 ID 9)

报价 id 9 是我们将讨论的最后一次促销。是难度 10 美元,奖励 2 美元,有效期 10 天的打折促销。它类似于优惠 id 2,只是它的有效期为 10 天,而优惠 id 2 的有效期为 7 天。

基线策略~验证 NIR:104.30 美元,测试 NIR:5,006.65 美元

提升模型~验证 NIR:51.87 美元,测试 NIR:3.02 美元

在所有情况下,我们都能够对基线策略的测试月 NIRs 进行显著改进。

对于 10 种促销类型中的 6 种,我们能够找到在验证和测试月份中有利可图的策略。

我们未能做到的 4 种促销类型是折扣 10/20/5、信息 4/0/0、信息 3/0/0 和 BOGO 5/5/5。

对于我们的策略在信息提供上表现不佳,有两种可能的解释。

首先,由于信息提供缺乏回报,它们的有效性有限。因此,它们对消费者支出的影响可以忽略不计。

或者,它们相对较短的有效期,加上客户没有动力快速“完成”它们,意味着这些促销的真正影响要到以后才能感受到。客户可能会对这些促销活动做出回应,但只能在促销活动结束后。

此外,我们的策略在 10/20/5 折扣促销中的糟糕表现表明,促销的难度($20)可能太高,无法激励有意义的客户做出回应。

尽管上述 4 项促销活动的促销策略并不盈利,但它们仍然代表了对基准策略的重大改进。因此,他们的采用将提高星巴克的底线。

在许多促销活动中,我们的提升模型策略在验证月份获得的 NIRs 比最初在实验中获得的略低。然而,这些策略确实显著改善了测试月份的 NIRs。因此,这种权衡是可以接受的。

# XI。结论

## 回答我们的问题

现在让我们回到开始时的问题:

我们能通过采取更具选择性的促销策略来增加星巴克的利润吗?

我们已经证明,提高原始促销策略的有效性并获得更好的回报是完全可能的。在 10 次促销中,有 6 次发现了盈利策略,我们还设法在另外 4 次促销中大幅减少了损失。

然而,我们目前的方法并不能为所有的报价生成正的 NIRs。此外,还有关于结果一致性的问题。为了获得可靠且有利可图的策略,必须进行进一步的改进。如前所述,提升模型可能很难实现。

从这个实验中得出的关键结论是,促销似乎不会在短期内产生明显更高的利润。大多数顾客通常是忠诚的,并且经常愿意购买产品,不管是否有促销活动。

因此,我们在确定要进行促销的个人时需要更有选择性。否则,我们可能会对公司的利润产生不利影响。

## 潜在的改进

我们注意到产生最高验证 NIRs 的策略不能产生阳性测试 NIRs。验证和测试结果之间的不一致可能表明信号不是很强,就是在不同的月份中信号不一致。

考虑到只有一小部分客户对优惠做出了回应,我们没有太多的交易数据可以处理。此外,只有 4 个人口统计属性可用。因此,获取更多的交易和人口统计数据可能有助于改善信号。

或者,我们可以通过多种方式改进我们的提升模型:

1.  仅向提升值高于某个百分点的个人发送促销信息,而不仅仅是提升值为正的个人。
2.  使用回归模型模拟促销和非促销情况下的利润额。
3.  尝试其他提升模型,如双模型法、四象限法等。

尝试所有这些替代方法将相对耗时,因此我没有在这个项目中探索它们。

此外,由于产生的成本,发送这些促销可能会导致短期利润下降,但它们可能会建立客户的忠诚度,并鼓励他们在未来的交易中花费更多的钱。

我们目前的方法没有模拟这些促销的长期影响。因此,解决这个问题的另一种方法是设计一种策略,使未来利润最大化,而不是获得短期利润。在这种情况下,我们的目标将是确定在获得晋升后的未来几个月中可能会花更多钱的人。

*本文附带的代码可以在* [*这里*](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) *找到。*

*感谢您阅读本文!如果你有任何想法或反馈,请在下面留下评论或给我发电子邮件到 leexinjie@gmail.com。我很乐意收到你的来信。*

# 从头开始实现 ResNet 模型。

> 原文:<https://towardsdatascience.com/implementing-a-resnet-model-from-scratch-971be7193718?source=collection_archive---------3----------------------->

## ResNet 如何工作的基本描述和理解最先进网络的实践方法。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/05f21c3e7b88bcfcb80ff865217b8bdb.png)

Source: [https://www.quantamagazine.org/brain-computer-interfaces-show-that-neural-networks-learn-by-recycling-20180327/](https://www.quantamagazine.org/brain-computer-interfaces-show-that-neural-networks-learn-by-recycling-20180327/)

当我在一个深度学习项目中实现 **ResNet** 架构时,这是我习惯的基本、简单的卷积神经网络的一个巨大飞跃。

ResNet 的一个突出特点是在其较大的*宏架构* ***:*** **残余块**内利用了一个*微架构*!

我决定亲自研究这个模型,以便更好地理解它,并研究为什么它在 ILSVRC 如此成功。我在 Adrian Rosebrock 博士的 【用于计算机视觉的深度学习】 [*中实现了完全相同的 ResNet 模型类[1],*,它遵循了 2015 年 ResNet 学术出版物中的 ResNet 模型,](https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/) [*何等人的*](https://arxiv.org/abs/1512.03385) 【用于图像识别的深度残差学习】[2]。

# 雷斯内特

当 ResNet 首次推出时,它为当时深度神经网络的一个巨大问题提供了一个新的解决方案:消失梯度问题。虽然神经网络是通用函数逼近器,但是在某个阈值,增加更多的层会使训练变得更慢,并且使精度饱和。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d1c9562d0ab704f2eedcedb86ed3f506.png)

Source: [https://towardsdatascience.com/an-overview-of-resnet-and-its-variants-5281e2f56035](/an-overview-of-resnet-and-its-variants-5281e2f56035)

这是由于梯度从最终层到最早层的反向传播——将 0 和 1 之间的数相乘多次会使其变得越来越小:因此,当到达更早的层时,梯度开始“消失”。这意味着早期的层不仅训练速度慢,而且更容易出错。这是一个巨大的问题,因为最早的层是整个网络的构建模块,它们负责识别基本的核心功能!

为了缓解这一问题,ResNet 结合了**身份快捷连接**,本质上跳过了一层或多层的训练——创建了**残差块**。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/256d4136051cc5fb8d385fc86fdc1458.png)

A single residual block; the original one proposed by He et al. Source: [1]

然后作者提出了一个“优化的”剩余块,增加了一个叫做**瓶颈的扩展。**它将减少前两个 CONV 层中的维度(在最终的 CONV 层中学习的过滤器的 1/4 ),然后在最终的 CONV 层中再次增加。这里有两个剩余模块堆叠在一起。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7b2b0eb2bc2dc4c4ffe7b1d14d8ae321.png)

Source: Deep Learning for Computer Vision using Python: Practitioner Bundle [1]

最后,他等人发表了第二篇关于剩余模块的论文,称为深度剩余网络中的*身份映射*,它提供了剩余模块的更好版本:**预激活剩余模型**。这允许梯度通过快捷连接无障碍地传播到任何较早的层。

我们不是从卷积(*权重*)开始,而是从一系列(*BN*=>*RELU*=>*conv*)* N 层开始(假设正在使用瓶颈)。然后,剩余模块输出*加法*运算,该运算被馈入网络中的下一个剩余模块(因为剩余模块堆叠在彼此之上)。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a64ded3eb2e3d7cbf477e4f539b79c40.png)

(a) original bottleneck residual module. (e) full pre-activation residual module. Called pre-activation because BN and ReLU layers occur before the convolutions. Source: [2]

整个网络架构看起来是这样的,我们的模型也类似于此。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/044a03eaff9c70d5b77bdcb8acad2a40.png)

Source: [2]

让我们开始用 Python 编码实际的网络。这个具体的实现受到了 He 等人的 Caffe 发行版和的 mxnet 实现的启发。

我们将把它写成一个类( *ResNet* ),这样我们就可以在训练深度学习模型时调用它。

我们从标准的 CNN 导入开始,然后开始构建我们的 *residual_module* 函数。看一下参数:

*   *数据*:输入到剩余模块
*   *K* :最终 CONV 层将学习的滤波器数量(前两个 CONV 层将学习 K/4 个滤波器)
*   *步幅*:控制卷积的步幅(将帮助我们在不使用最大池的情况下减少空间维度)
*   *chanDim* :定义批量归一化的轴
*   *红色*(即减少)将控制我们是减少空间维度(真)还是不减少空间维度(假),因为并非所有剩余模块都会减少我们的空间体积的维度
*   *reg:* 对残差模块中的所有 CONV 层应用正则化强度
*   *bnEps:* 控制ɛ,负责在标准化输入时避免“被零除”错误
*   *bnMom:* 控制[移动平均线](https://www.coursera.org/lecture/deep-neural-network/exponentially-weighted-averages-duStO)的动量

现在让我们看看函数的其余部分。

首先,我们初始化(标识)快捷方式(连接),它实际上只是对输入数据的引用。在剩余模块的末尾,我们简单地将快捷方式添加到预激活/瓶颈分支的输出中(第 3 行)。

在第 6–9 行,ResNet 模块的第一个块遵循 BN ==> RELU ==> CONV == >模式。CONV 层通过 *K/4* 滤波器利用 1x1 卷积。请注意,CONV 层的偏置项是关闭的,因为偏置已经在后面的 BN 层中,所以不需要第二个偏置项。

根据瓶颈,第二 CONV 层学习 3×3 的 *K/4* 过滤器。

最后一个块将再次增加维度,应用维度为 1 x 1 的 *K* 过滤器。

为了避免应用最大池,我们需要检查是否有必要减少空间维度。

如果我们被命令减少空间维度,跨度大于 1 的卷积层将被应用于快捷方式(第 2-4 行)。

最后,我们将快捷方式和最终的 CONV 层添加到一起,创建 ResNet 模块的输出(第 7 行)。我们终于有了开始构建深层剩余网络的“基石”。

让我们开始构建*构建*方法。

看看参数*阶段**滤波器*(都是列表)。在我们的架构中(如上所示),我们将 N 个剩余模块堆叠在一起(N =阶段值)。同一*级*中的每个剩余模块学习相同数量的*滤波器*。每个阶段学习完各自的过滤器后,接下来就是降维。我们重复这个过程,直到我们准备好应用平均池层和 softmax 分类器。

## 阶段和过滤器

例如,让我们设置 stages=(3,4,6)和 filters=(64,128,256,512)。第一滤波器(64)被应用于不属于剩余模块的唯一 CONV 层,即网络中的第一 CONV 层。然后,*三个*(阶段= 3)剩余模块堆叠在彼此之上——每个模块将学习 *128* 过滤器。空间维度将被减少,然后我们将*四个*(阶段= 4)剩余模块堆叠在彼此之上——每个学习 256 个过滤器。最后,我们再次减少空间维度,并继续堆叠*六个*(阶段= 6)剩余模块,每个模块学习 512 个过滤器。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/67a252297adbec2eb15da9583af21b51.png)

ResNet architecture. Circled numbers are the filter values, while the brackets show the stacks. Notice how there is a dimensionality reduction after every stage. Unrelated to written example earlier.

让我们回到构建*构建*方法。

根据我们使用的是“通道最后”还是“通道优先”排序,初始化 *inputShape**chanDim* (第 3-4 行)。

如上所述,ResNet 使用一个 BN 作为第一层,作为对您的输入(第 2-4 行)的附加标准化级别。然后,我们应用一个 CONV = >,BN => ACT = >池来减少空间大小(第 7–13 行)。现在,让我们开始堆叠剩余层。

要在不使用池层的情况下减小体积,我们可以更改卷积的步幅。该阶段中的第一个条目的步幅将为(1,1),表示缺少缩减采样。然后,在这之后的每个阶段,我们将应用步长为(2,2)的残差模块,这将减小卷的大小。这显示在第 5 行的**上。**

然后,我们在第 10–13 行的**上循环当前阶段的层数(将堆叠在彼此顶部的剩余模块数)。我们使用[i + 1]作为过滤器的索引,因为已经使用了第一个过滤器。一旦我们将 stage[I]剩余模块堆叠在彼此之上,我们就返回到**线 6–7**处,在那里我们减小体积的空间维度并重复该过程。**

为了避免密集的全连接层,我们将应用平均池化来将卷大小减少到 1 x 1 x 类:

最后,我们将为我们将要学习的所有类别创建一个密集层,然后应用 softmax 激活来生成我们的最终输出概率!

这就结束了我们的构建函数,现在我们有了完全构建的 ResNet 模型!你可以调用这个类在你的深度学习项目中实现 ResNet 架构。

如果你有任何问题,欢迎在下面评论或者联系我们!

*   我的领英:[https://www.linkedin.com/in/gracelyn-shi-963028aa/](https://www.linkedin.com/in/gracelyn-shi-963028aa/)
*   给我发邮件到 gracelyn.shi@gmail.com

## 参考

[1] A. Rosebrock, [*用 Python 进行计算机视觉的深度学习*](https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/) (2017)

[2]何国光,张,任,孙,[](https://arxiv.org/abs/1512.03385)**【2015】*[【https://arxiv.org/abs/1512.03385】](https://arxiv.org/abs/1512.03385)*

# 在 Tensorflow 中实现一个简单的自动编码器

> 原文:<https://towardsdatascience.com/implementing-a-simple-auto-encoder-in-tensorflow-1181751f202?source=collection_archive---------10----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/776a2c12a0dfce4b471b0226c42376f8.png)

Peele using DeepFake to forge a video of Obama — Source: [BuzzFeed](https://www.youtube.com/watch?v=cQ54GDm1eL0), YouTube

生成对抗网络(GAN)最近通过展示它们的一些能力而变得越来越受欢迎,最初是通过模仿著名画家的艺术风格,但最近是通过无缝替换视频中的面部表情,同时保持高输出质量。

Source: [BuzzFeed](https://www.youtube.com/watch?v=cQ54GDm1eL0), YouTube

GANs 的支柱之一是使用自动编码器。自动编码器是一种具有两种特性的神经网络:输入和输出数据是相同的,并且网络包括比输入更低维度的层。起初,这可能听起来令人困惑和无用,但通过训练网络复制输入数据,虽然有一个“瓶颈”,但我们真正做的是让网络学习数据的“压缩”版本,然后
解压缩它。用行话来说,这意味着找到我们数据的“潜在空间”表示。

在这篇文章中,我将解释如何用 python 实现自动编码器,以及如何在实践中使用它来编码和解码数据。假设您已经安装了`Python 3` 和`Tensorflow`并正在运行,尽管代码只需要很小的改动就可以在`Python 2.`上运行

所以,一个好的自动编码器必须:
1。“压缩”数据,即潜在尺寸<输入尺寸
2。很好地复制数据(咄!)
2。允许我们得到编码的潜在表示法
3。允许我们解码一个编码的表示

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/cfd65763d4f15b46c430d26c94188204.png)

[Source](/applied-deep-learning-part-3-autoencoders-1c083af4d798): another very interesting article, explaining and using auto-encoder to remove noise from images.

我将向您展示两种方法,一种是严格的/学究式的(取决于您的观点),它使用低级的`tensorflow` API,另一种是更快更随意的,它利用了`keras` API,尽管如果您想正确理解第二种 API 的内部工作方式,第一种方法是必要的。

# Tensorflow 低级实现

> 只有最酷的孩子才会用这个——比尔·盖茨

他的实现将直接使用`tensorflow core` API,这需要一些先决知识;我将简要解释三个基本概念:`tf.placeholder`、`tf.Variable`和`tf.Tensor`。

一个`tf.placeholder`仅仅是一个“变量”,它将是模型的输入,但不是模型本身的一部分。它基本上允许我们告诉模型,它应该期望一个特定类型和特定维度的变量。这与强类型语言中的变量声明非常相似。

`tf.Variable`与其他编程语言中的变量非常相似,其声明类似于大多数强类型语言的声明。例如,网络的权重是`tf.Variables`。

一个`tf.Tensor`稍微复杂一点。在我们的例子中,我们可以认为它是一个包含操作的符号表示的对象。例如,给定一个占位符 ***X*** 和一个权重变量 ***W*** ,矩阵乘法***W******X***是一个张量,但是它的结果,给定一个特定的值 ***X*** 和 ***W,*** 不是张量。

既然介绍已经做好了,建立关系网的过程就相当简单,但是有点迂腐。我们将使用 MNIST 数据集,这是一个存储为 28x28 图片的手写数字数据集。我们将 *D* 定义为输入数据,在这种情况下,展平的图像尺寸为 784,将 *d* 定义为编码尺寸,我将其设置为 128。该网络然后具有以下维度的 3 层: *D,D,D* 。

我们现在将实现一个简单的自动编码器类,将逐行解释。如果你感兴趣的话,这里还有完整版本的代码。

我们走吧!首先,我们需要一个输入数据的占位符:

self.X = tf.placeholder(tf.float32, shape=(None, D))


然后,我们开始编码阶段,将第一层权重(带有额外偏差)定义为变量:

self.W1 = tf.Variable(tf.random_normal(shape=(D,d)))
self.b1 = tf.Variable(np.zeros(d).astype(np.float32))


注意重量的形状是`Dxd`,从较高维度到较低维度。接下来,我们为瓶颈层创建张量,作为输入和权重之间的乘积,加上偏差,所有这些都由 relu 激活。

self.Z = tf.nn.relu( tf.matmul(self.X, self.W1) + self.b1 )


然后,我们进入解码阶段,这与编码相同,但从低维到高维。

self.W2 = tf.Variable(tf.random_normal(shape=(d,D)))
self.b2 = tf.Variable(np.zeros(D).astype(np.float32))


最后,我们定义输出张量,以及预测变量。为了简单起见,选择了 Sigmoid 激活,因为它总是在区间[0,1]内,该区间与来自输入的归一化像素的范围相同。

logits = tf.matmul(self.Z, self.W2) + self.b2
self.X_hat = tf.nn.sigmoid(logits)


网络到此为止!我们只需要一个损失函数和一个优化器,我们可以开始训练了。选择的损失是 sigmoid 交叉熵,这意味着我们将该问题视为像素级别的二元分类,这对黑白图像数据集有意义。

关于乐观主义者,这是非常古老的魔法。给定一个问题,也许我们应该创建一个模型来输出使用哪个优化器?

self.cost = tf.reduce_sum(
tf.nn.sigmoid_cross_entropy_with_logits(
# Expected result (a.k.a. itself for autoencoder)
labels=self.X,
logits=logits
)
)

self.optimizer = tf.train.RMSPropOptimizer(learning_rate=0.005).minimize(self.cost)


最后一个稍微有点技术性的术语与会话有关,它是一个充当上下文管理器和后端连接器的对象,并且需要初始化:

self.init_op = tf.global_variables_initializer()
if(self.sess == None):
self.sess = tf.Session()
self.sess = tf.get_default_session()
self.sess.run(self.init_op)


就是这样!..或者差不多,现在我们需要拟合模型;但不用担心,这在 tensorflow 中非常简单:

Prepare the batches

epochs = 10
batch_size = 64
n_batches = len(X) // bs

for i in range(epochs):
# Permute the input data
X_perm = np.random.permutation(X)
for j in range(n_batches): # Load data for current batch
batch = X_perm[jbatch_size:(j+1)batch_size] # Run the batch training!
_, costs = self.sess.run((self.optimizer, self.cost),
feed_dict={self.X: batch})


最后一行确实是唯一有趣的一行。它告诉 tensorflow 运行一个训练步骤,使用`batch`作为占位符输入 *X,*,并使用给定的优化器和损失函数进行权重更新。

让我们看看这个网络给出的一些重建的例子:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/683d1d538482b33f62e5b85621b07136.png)

现在这一切都很好,但目前我们只训练了一个可以自我重建的网络..我们实际上如何使用自动编码器?我们需要定义另外两个操作,编码和解码..这其实很简单:

def encode(self, X):
return self.sess.run(self.Z, feed_dict={self.X: X})


这里我们告诉 tensorflow 计算`Z` 如果你回头看,你会发现是代表编码的张量。解码也很简单:

def decode(self, Z):
return self.sess.run(self.X_hat, feed_dict={self.Z: Z})


这一次,我们通过`Z`显式地给 tensorflow 编码,这是我们之前使用`encode` 函数计算的,我们告诉它计算预测输出`X_hat`。

如你所见,即使对于一个简单的网络来说,这也是相当长的。当然,我们可以对每个权重进行参数化并使用列表而不是单个变量,但是当我们需要快速或自动测试多个结构时会发生什么呢?除了致密层,其他类型的层呢?不要担心,第二种(不那么迂腐的)方法可以让我们轻松地做到所有这些!

# Keras API 实现

> 越简单越好——奥卡姆的威廉

他的第一条路又长又迂腐,而且,说实话,有点讨厌。此外,缺乏简单的概括也无济于事。因此,更简单的解决方案是关键,这可以通过使用`tensorflow`中包含的`keras`接口来实现。

所有的网络定义、损耗、优化和拟合都在几行中:

t_model = Sequential()
t_model.add(Dense(256, input_shape=(784,)))
t_model.add(Dense(128, name='bottleneck'))
t_model.add(Dense(784, activation=tf.nn.sigmoid))t_model.compile(optimizer=tf.train.AdamOptimizer(0.001),
loss=tf.losses.sigmoid_cross_entropy)
t_model.fit(x, x, batch_size=32, epochs=10)


就这样,我们有了一个训练有素的网络。生活有时不是很美好吗?

…但是整个编码/解码过程呢?是的,这时候事情会变得有点棘手,但是不要担心,你的向导在这里。
因此,要做到这一点,我们需要几样东西:

*   会话变量
*   输入张量,在`feed_dict`参数中指定输入
*   编码张量,用于检索编码,并用作解码`feed_dict`参数的输入
*   解码/输出张量,用于检索解码值

## 胡言乱语。

我们通过简单地从感兴趣的层中获得所需的张量来实现这一点!注意,通过命名瓶颈层,我使得检索它变得非常容易。

session = tf.get_default_session()
if(self.sess == None):
self.sess = tf.Session()# Get input tensor
def get_input_tensor(model):
return model.layers[0].input# get bottleneck tensor
def get_encode_tensor(model):
return model.get_layer(name='encode').output# Get output tensor
def get_output_tensor(model):
return model.layers[-1].output


就是这样!现在,给定一个训练好的模型,您可以通过以下几行获得您需要的所有变量:

t_input = get_input_tensor(t_model)
t_enc = get_bottleneck_tensor(t_model)
t_dec = get_output_tensor(t_model)session = tf.get_default_session()# enc will store the actual encoded values of x
enc = session.run(t_enc, feed_dict={t_input:x})# dec will store the actual decoded values of enc
dec = session.run(t_dec, feed_dict={t_enc:enc})


我希望你喜欢这篇文章,它是有用的或者至少是有趣的。最初我是专门为会议部分制作的,这部分没有很好的文档记录。我花了几个小时试图理解什么是张量,什么是会话,以及如何实际计算网络的一部分,评估和检索特定的张量,但总而言之,它实际上有助于巩固各种`tensorflow`概念,这些概念远非直观,但一旦理解就非常强大。

感谢您的阅读,不要犹豫,评论,并有一个美好的一天!

# 在 TensorFlow 2.0 中实现自动编码器

> 原文:<https://towardsdatascience.com/implementing-an-autoencoder-in-tensorflow-2-0-5e86126e9f7?source=collection_archive---------6----------------------->

*by*[*Abien Fred Agarap*](https://twitter.com/afagarap)

> 同时发布于[https://afagarap . works/2019/03/20/implementing-auto encoder-in-tensor flow-2.0 . html](https://afagarap.works/2019/03/20/implementing-autoencoder-in-tensorflow-2.0.html)

G oogle 宣布对世界上最受欢迎的开源机器学习库 TensorFlow 进行重大升级,承诺专注于简单易用、热切执行、直观的高级 API 以及在任何平台上灵活的模型构建。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/277bf02a04f9b064fcab51bcb9e2a485.png)

A new TensorFlow logo unveiled in this year’s TensorFlow Dev Summit at Sunnyvale, CA. Animated logo from [Test Drive TensorFlow 2.0 Alpha by Wolff Dobson and Josh Gordon (2019, March 7)](https://medium.com/tensorflow/test-drive-tensorflow-2-0-alpha-b6dd1e522b01) .

这篇文章是对 TensorFlow 2.0 例子的一个小小的尝试。具体来说,我们将讨论**自动编码器**的[子类化 API](https://www.tensorflow.org/guide/keras#model_subclassing) 实现。

要安装 TensorFlow 2.0,使用下面的`pip install`命令,

`pip install tensorflow==2.0.0`

或者如果你的系统中有一个图形处理器,

`pip install tensorflow-gpu==2.0.0`

通过[tensorflow.org](https://tensorflow.org)的[本指南](https://www.tensorflow.org/install)了解更多安装细节。

在深入研究代码之前,让我们先讨论一下什么是**自动编码器**# 自动编码器

我们在机器学习中处理大量的数据,这自然会导致更多的计算。然而,我们也可以选择对模型学习贡献最大的数据部分,从而减少计算量。选择数据的*重要部分*的过程称为*特征选择,*是一个 ***自动编码器*** 的用例数之一。

但是**自动编码器**到底是什么?好吧,让我们首先回忆一下,神经网络是一种计算模型,用于*寻找*描述* *的* *函数数据*特征* ***x*** 及其**(一个*回归*任务)或*标签*(一个**

*现在,**自动编码器**也是一个神经网络。但不是找到函数*映射**特征* ***x****它们对应的值**标签* ***y*** ,而是找到将*特征* ***x*** *映射到自身* ***x*** 的函数。等等,什么?我们为什么要这么做?*

*嗯,有趣的是在**自动编码器**内部发生了什么。为了更好的理解,我们来看一个**自动编码器**的图解。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/29ff595b267c0eb17e1686efd75eec5b.png)*

*Illustrated using [NN-SVG](http://alexlenail.me/NN-SVG/index.html). An autoencoder is an artificial neural network that aims to learn how to reconstruct a data.*

*从上图来看,一个**自动编码器**由两部分组成:(1)一个**编码器**,它学习数据的表示,即*重要的* *特征数据的****z***;以及(2)一个**解码器**,它根据它如何构造的想法 ***z*** 来重构数据。*

*回过头来,我们建立了一个**自动编码器**想要找到将 ***x*** 映射到 ***x*** 的函数。它通过其组件来实现这一点。数学上,*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1bffdac81b6788ced7729030a1b31f82.png)*

****z*** *is the learned data representation by the* ***encoder*** *from input data* ***x****.**

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/577754a80d46d05c4a0e4eb569be7cf0.png)*

***x-hat** is the reconstructed data by the **decoder** based on the learned representation **z**.*

***编码器** *h-sub-e* 从输入特征*中学习数据表示 ***z*** ,然后该表示作为**解码器** *h-sub-d* 的输入,以重构原始数据***x*****

**我们将在下面进一步剖析这个模型。**

# **编码器**

**第一个组件**编码器**,类似于传统的前馈网络。但是,它的任务不是预测值或标签。相反,它的任务是学习数据的结构,即数据表示 ***z*** 。**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/606dfb5cee0735219fab2daee3a47f6a.png)**

**Illustrated using [NN-SVG](http://alexlenail.me/NN-SVG/index.html). The **encoder** learns the representation of a given data.**

***编码*是通过将数据输入 ***x*** 传递给**编码器**的隐藏层 ***h*** 来完成的,以便学习数据表示***z = f(h(x))***。我们可以如下实现`Encoder`层,**

**The **encoder** layer of the **autoencoder** written in TensorFlow 2.0 subclassing API.**

**我们首先定义一个继承了`[tf.keras.layers.Layer](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Layer)`的`Encoder` 类,将其定义为一个层而不是一个模型。为什么是图层而不是模型?回想一下,编码器是**自动编码器**型号的*组件*。**

**浏览代码,`Encoder`层被定义为具有一个单独的神经元隐藏层(`self.hidden_layer`),用于学习输入特性的激活。然后,我们将隐藏层连接到一个层(`self.output_layer`),该层将数据表示编码到一个较低的维度,该维度由它认为重要的特征组成。因此,`Encoder`层的“输出”就是输入数据 ***x*** 的*学习数据表示* ***z*** 。**

# **解码器**

**第二个组件**解码器**,也类似于一个前馈网络。然而,它不是将数据减少到较低的维度,而是将数据从其较低维度表示 ***z*** 重建到其原始维度 ***x*** 。**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7e103adeeb300c4d88302e395551acca.png)**

**Illustrated using [NN-SVG](http://alexlenail.me/NN-SVG/index.html). The **decoder** learns to reconstruct the data from its lower dimension representation.**

***解码*是通过将较低的维度表示 ***z*** 传递给**解码器**的隐藏层 ***h*** 来完成的,以便将数据重建到其原始维度 ***x = f(h(z))*** 。我们可以如下实现**解码器**层,**

**The **decoder** layer of the **autoencoder** written in TensorFlow 2.0 subclassing API.**

**我们定义了一个`Decoder` 类,它也继承了`[tf.keras.layers.Layer](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Layer)`。**

**`Decoder`层也被定义为具有单个隐藏的神经元层,以通过编码器从学习到的表示中重建输入特征。然后,我们将它的隐藏层连接到一个层,该层将数据表示从较低的维度解码到其原始维度。因此,解码器层的“输出”是来自数据表示 ***z*** 的重构数据 ***x*** 。最终,解码器的输出是自动编码器的输出。**

**现在我们已经定义了我们的**自动编码器**的组件,我们终于可以构建模型了。**

# **构建自动编码器模型**

**我们现在可以通过实例化`Encoder`和`Decoder`层来构建**自动编码器**模型。**

**The **autoencoder** model written in TensorFlow 2.0 subclassing API.**

**如上所述,我们使用**编码器**层的输出作为**解码器**层的输入。就这样吗?不,不完全是。**

**到目前为止,我们只讨论了一个**自动编码器**的组件以及如何构建它,但是我们还没有讨论它实际上是如何学习的。至此,我们只知道*数据流*;从输入层到学习数据表示的**编码器**层,并使用该表示作为重构原始数据的**解码器**层的输入。**

**像其他神经网络一样,**自动编码器**通过[反向传播](https://www.youtube.com/watch?v=LOc_y67AzCA)进行学习。但是我们不是比较模型的值或者标签,而是比较*重构数据* ***x-hat*** 和*原始数据* ***x*** 。让我们称这个比较为*重建误差*函数,它由下面的等式给出:**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/11e172bfbef90b8898c6b6035c3b4318.png)**

**The reconstruction error in this case is the [mean-squared error](https://www.youtube.com/watch?v=6OvhLPS7rj4) function that you’re likely to be familiar with.**

**在张量流中,上述等式可以表示如下:**

**Reconstruction error written using TensorFlow core operations.**

**我们到了吗?够近了。只是再补充一些东西。现在我们已经定义了误差函数,我们终于可以为模型编写训练函数了。**

**Training function written in TensorFlow 2.0 following the paradigm of writing the forward pass imperatively through the use of [GradientTape](https://stackoverflow.com/questions/53953099/what-is-the-purpose-of-the-tensorflow-gradient-tape).**

**这种实现反向传播的方式通过使我们能够跟踪梯度以及对其应用[优化算法](http://ruder.io/optimizing-gradient-descent/)而为我们提供了更多的自由。**

**我们说完了吗?让我们看看。**

*   **定义一个**编码器**层。*已检查*。**
*   **定义一个**解码器**层。*已检查*。**
*   **使用**编码器**和**解码器**层构建**自动编码器**。*已检查*。**
*   **定义重建误差函数。*已检查*。**
*   **定义培训功能。*已检查*。**

**是啊!我们完事了。我们终于可以训练我们的模型了!**

**但在此之前,让我们实例化一个我们之前定义的`Autoencoder`类,以及一个要使用的优化算法。然后,让我们加载我们想要重建的数据。对于这篇文章,让我们使用*难忘的* [MNIST 手写数字数据集](http://yann.lecun.com/exdb/mnist/)。**

**我们可以使用 [TensorBoard](https://www.tensorflow.org/guide/summaries_and_tensorboard) 可视化我们的训练结果,为此,我们需要使用`[tf.summary.create_file_writer](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/summary/create_file_writer)`为结果定义一个摘要文件编写器。**

**Instantiating the **autoencoder** model, and the optimization function. Loading the MNIST dataset. Finally, the training loop for our **autoencoder** model.**

**接下来,我们使用定义的摘要文件编写器,并使用`[tf.summary.record_if](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/summary/record_if)`记录培训摘要。**

**我们最终(现在真正地)可以通过向它提供小批量数据来训练我们的模型,并通过我们之前定义的`train`函数计算它的每次迭代的损失和梯度,该函数接受定义的*误差函数*、 ***自动编码器*** *模型**优化算法**小批量*数据。**

**在训练模型的每一次迭代之后,计算的重构误差应该减少,以查看模型是否真的在学习(就像在其他神经网络中一样)。最后,为了在 TensorBoard 中记录训练摘要,我们使用`[tf.summary.scalar](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/summary/scalar)`记录重建误差值,使用`[tf.summary.image](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/summary/image)`记录原始数据和重建数据的小批量。**

**经过一些时代,我们可以开始看到一个相对良好的 MNIST 图像重建。**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/122a7c6c843ecab1e835c9f11120976a.png)**

**Plotted using [matplotlib](https://matplotlib.org/). Results on MNIST handwritten digit dataset. Images at the top row are the original ones while images at the bottom row are the reconstructed ones.**

**重建的图像可能足够好,但它们非常模糊。可以做许多事情来改善这个结果,例如添加更多的层和/或神经元,或者使用卷积神经网络架构作为**自动编码器**模型的基础,或者使用[不同种类的**自动编码器**](https://www.deeplearningbook.org/contents/autoencoders.html) 。**

# **结束语**

****自动编码器**对于降维非常有用。但是它也可以用于[数据去噪](https://www.deeplearningbook.org/contents/autoencoders.html),以及用于[学习数据集的分布](https://blog.keras.io/building-autoencoders-in-keras.html)。我希望我们在这篇文章中已经涵盖了足够多的内容,让你兴奋地学习更多关于**自动编码器**!**

**完整的代码可在[这里](https://gist.github.com/AFAgarap/326af55e36be0529c507f1599f88c06e)获得。如果您有任何反馈,您可以通过 [Twitter](https://twitter.com/afagarap) 联系我。我们也可以通过[脸书](https://facebook.com/afagarap)、 [Instagram](https://instagram.com/afagarap) 和/或 [LinkedIn](https://www.linkedin.com/in/abienfredagarap/) 联系!**

# **参考**

1.  **马丁·阿巴迪、阿希什·阿加瓦尔、保罗·巴勒姆、尤金·布莱夫多、陈质枫、克雷格·西特罗、格雷格·科拉多、安迪·戴维斯、杰弗里·迪恩、马蒂厄·德文、桑杰·格玛瓦特、伊恩·古德菲勒、安德鲁·哈普、杰弗里·欧文、迈克尔·伊萨德、拉斐尔·约泽福维茨、杨青·贾、卢卡斯·凯泽、曼朱纳斯·库德鲁尔、乔希·莱文伯格、丹·曼内、迈克·舒斯特、拉杰特·蒙加、雪莉·穆尔、德里克·默里、克里斯·奥拉、黄邦贤·施伦斯、伯努瓦·施泰纳 [*TensorFlow:异构系统上的大规模机器学习*](https://arxiv.org/abs/1603.04467) (2015)。tensorflow.org[公司](https://tensorflow.org)提供的软件。**
2.  **Francois Chollet,[在 Keras 建立自动编码器](https://blog.keras.io/building-autoencoders-in-keras.html) (2016 年 5 月 14 日),[Keras 博客](https://blog.keras.io/)。**
3.  **I. Goodfellow,Y. Bengio,& A .库维尔,[深度学习](https://deeplearningbook.org) (2016)。麻省理工出版社。**

# 实施数据库开发运维流程的组件

> 原文:<https://towardsdatascience.com/implementing-components-of-database-devops-process-9f2347146d79?source=collection_archive---------30----------------------->

## 让我们以潜在雇员数据库为例,看看如何实现数据库开发运维流程的一些组件。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/63e6634748bd5d50382e869e97cc71cd.png)

近年来,数据库 DevOps 已经成为需求最大的流程之一。没有它,即使是小公司也无法真正有效地工作,大多数 it 公司已经实施了 DevOps 数据库自动化,并将其作为工作流程的重要部分。

# **那么,数据库 DevOps 到底是什么?**

数据库开发运维流程的主要作用是不断地将开发和测试环境中的变更交付到生产环境中,监控生产环境的状态,并在需要时提供回滚变更的能力。在此之后,更改被传输到生产环境管理服务。基本上,DevOps 过程将开发和测试与各种类型的管理(系统、数据库等)联系起来。)等生产环境和系统管理流程。DevOps 数据库自动化特别包括所有环境中的自动化,并使数据库的开发和管理任务更简单、更安全。

通常,数据库 DevOps 过程分为*两部分*:

**1。生产前** —在将变更实际提交到生产环境之前发生的所有事情。这包括以下阶段:

1.1 编译和记录代码

1.2 用测试数据填充数据库并运行自动测试

1.3 将变更从开发环境应用到测试环境

1.4 用测试数据填充数据库

1.5 决定变更是否可以部署到生产环境中

流程的第一部分主要由开发人员和测试人员完成,第 1.3 阶段由 DevOps 工程师实施。阶段 1.2 到 1.4 可以根据任务规格以及 DevOps 流程本身的建立方式以任何顺序执行。这个想法是成功地通过从编译代码到决定是否准备好部署到生产的所有步骤。

在阶段 1.3 之后,对解决方案执行各种测试(压力、功能、集成测试等)。如果检测到与工作标准的任何重大偏差(例如,如果发现错误或性能问题),通常在阶段 1.5 确定代码还没有准备好部署到生产中,因此应该送回开发。此后,该过程从阶段 1.1 再次开始。事情与阶段 1.2 相似。

第 1.5 阶段也可能由于与第 1.2 或 1.3 阶段无关的原因而失败。只有在阶段 1.5 通过后,DevOps 流程才会进入第二个(也是最重要的)部分:

**2。实施** —将解决方案投入生产。这包括以下阶段:

2.1 部署

2.2 初级监控

2.3 回滚部署或将更改转移到生产环境管理服务。

阶段 2.1 通常由开发运维专家和生产环境管理服务专家共同手动启动,以避免生产中出现问题。最好提到阶段 2.1 包括阶段 1.3——唯一的区别是变更被部署到生产中。如果部署失败(阶段 2.1),则问题被定位,然后重复阶段 2.1 或者开发运维流程返回到第 1 部分的开头。

另一方面,如果部署成功但主要监控失败,通常决定部署应该回滚(阶段 2.3),开发运维流程返回到其第一部分。

只有当根据所有必要的标准进行评估时,阶段 2.1 和 2.2 完全成功,并且没有检测到任何问题,才会将更改提交给生产环境管理服务(阶段 2.3),以便由管理部门进行持续维护。这是 DevOps 流程迭代的终点。

重要的是要注意,这个过程是连续发生的,一次又一次,因此最大限度地减少了将代码从开发环境交付到测试环境的时间,反之亦然,或者在开发或测试环境之间交付。DevOps 流程还缩短了交付到生产环境的时间,并且能够监控和回滚更改。

# **创建 PowerShell 脚本来组织数据库开发操作流程**

让我们看看如何实现数据库开发运维流程的一些组件。在这个例子中,我们将使用潜在雇员的数据库。

我们将研究以下几个方面,以及如何为它们生成 PowerShell 脚本来组织数据库开发运维流程。[dbForge devo PS Automation for SQL Server](https://www.devart.com/dbforge/sql/database-devops/)和各种 db forge 工具将在这方面帮助我们:

## 1.生产前:

1.1 代码编译和文档( [SQL 完成](https://www.devart.com/dbforge/sql/database-devops/sqlcomplete.html)、[源代码控制](https://www.devart.com/dbforge/sql/database-devops/source-control.html)、[文档](https://www.devart.com/dbforge/sql/documenter/))

1.2 用测试数据填充数据库并运行自动测试([数据生成器](https://www.devart.com/dbforge/sql/database-devops/test-data-management.html)、[单元测试](https://www.devart.com/dbforge/sql/database-devops/unit-testing.html))

1.3 将解决方案从开发环境部署到测试环境([模式比较](https://www.devart.com/dbforge/sql/database-devops/database-schema-changes.html)、[数据比较](https://www.devart.com/en/dbforge/sql/datacompare/))

1.4 用测试数据填充数据库

1.5 决定代码是否准备好部署到生产中(这是一项管理职责,所以我们在这里不讨论它)

## 2.实施:

2.1 部署(数据库模式比较、数据比较、 [dbForge 数据泵](https://www.devart.com/dbforge/sql/database-devops/continuous-intergation-export-import-data.html))

2.2 主监控( [dbForge 事件探查器](https://www.devart.com/dbforge/sql/event-profiler/)、 [dbForge 监控器](https://www.devart.com/dbforge/sql/studio/monitor.html)、dbForge 数据泵)

2.3 回滚部署或将更改提交给生产环境管理服务(这可以通过多种方式完成,因此我们也将省略其讨论,但事务回滚可以使用 dbForge 事务日志来执行)

在本文中,我们不会深入研究 1.1 阶段和第二部分。然而,应该提到 [SQL Complete](https://www.devart.com/dbforge/sql/sqlcomplete/) 的一个重要特性。具体来说,要使用脚本格式化文件夹,我们可以使用以下 PowerShell 脚本:

$result = Invoke-DevartFormatScript -Source $scriptFolder


这里,$scriptFolder 是包含需要格式化的脚本的必要文件夹的完整路径。此外,Invoke-DevartFormatScript cmdlet 用于调用 SQL Complete 工具的格式化功能。正如我们从脚本中看到的,cmdlet 只有一个参数—包含数据库模式创建或更新脚本的文件夹的路径。

现在,我们将详细了解阶段 1.2–1.4。由于在数据库开发运维过程中,这些阶段可以按任何顺序执行,我们将按如下方式安排它们:

1.  用测试数据填充数据库(dbForge 数据生成器)
2.  运行自动测试(dbForge 单元测试)
3.  将解决方案从开发环境部署到测试环境(数据库模式比较、数据比较)

我们需要保存一个数据生成项目,或者创建一个包含必要参数的新项目,并将其保存为 JobEmplDB.dgen。

现在,我们可以使用 Invoke-DevartDatabaseTests cmdlet 根据 JobEmplDB.dgen 项目调用数据生成过程:

Invoke-DevartDatabaseTests -InputObject $ConnectionString -DataGeneratorProject $JobEmplDBFolder -InstalltSQLtFramework -RewriteReport -UnInstalltSQLtFramework -IncludeTestData


在这里,将$ConnectionString 替换为连接字符串,将$JobEmplDBFolder 替换为 JobEmplDB.dgen 文件的全名,即该文件的完整路径,包括实际的文件名和扩展名。

现在,让我们看看如何使用 PowerShell 脚本来运行自动测试。

为此,我们将使用 Invoke-DevartExecuteScriptInvoke-DevartDatabaseTests cmdlet:

Invoke-DevartExecuteScript -Input $UnitTestsFolder -Connection $ConnectionStringInvoke-DevartDatabaseTests -InputObject $ConnectionString -InstalltSQLtFramework -OutReportFileName $TestReportOutputFileName -ReportFormat JUnit


**第一个 cmdlet 从文件夹中为数据库创建测试,其中:**

1.  $UnitTestsFolder —包含单元测试的文件夹的路径;
2.  $ConnectionString —将为其创建测试的数据库的连接对象(在我们的示例中,它是 JobEmplDB 数据库)

**第二个 cmdlet 对数据库运行单元测试:**

1.  InputObject $ConnectionString 是我们需要对其运行测试的数据库的连接字符串。
2.  InstalltSQLtFramework 参数指定应该在运行测试之前安装 tSQLt 框架。

OutReportFileName $ TestReportOutputFileName 参数是输出测试报告文件的路径,ReportFormat JUnit 指定该文件的格式

将来,Invoke-DevartDatabaseTests cmdlet 将分为两个独立的部分,一部分用于运行自动测试,另一部分用于生成测试数据。

要传输架构更改,我们可以使用 Invoke-DevartSyncDatabaseSchema cmdlet 来使用以下 PowerShell 脚本:

$syncResult = Invoke-DevartSyncDatabaseSchema -Source $sourceConnection -Target $targetConnection


这里,$sourceConnection 是源数据库的连接字符串,$targetConnection 是目标数据库的连接字符串。$syncResult 变量将包含数据库模式同步的结果。

目前,没有用于在数据库之间同步数据的 cmdlet,但将来会有。

现在,我们可以使用启动 dbForge 数据泵的 Invoke-DevartDataImport cmdlet 来传输数据:

Invoke-DevartDataImport -Connection $connection -TemplateFile


这里,$connection 是 JobEmplDB 数据库的连接字符串,$importDataFileName 是用于创建导入数据的文件的全名。Devart 还有一系列其他有用的 cmdlets,它们将帮助使用 PowerShell 脚本实现各种 DevOps 流程组件。你可以在这里了解他们[](https://docs.devart.com/devops-automation-for-sql-server/powershell-cmdlets/export-devartdbproject.html)

正如我们所看到的,在 dbForge 模式比较和 dbForge 数据比较(dbForge 数据比较目前只能在手动模式下工作)的帮助下,数据库更改(模式和数据中的更改)可以在环境之间自动转移。我们还可以使用 dbForge 数据泵组件 cmdlets 来传输数据。

在 PowerShell 脚本的帮助下,我们可以自动化整个开发运维流程,从代码编译到将代码部署到生产和主要监控。

# 使用 C#中的 Azure 函数实现 Cosmos DB 变更提要

> 原文:<https://towardsdatascience.com/implementing-cosmos-db-change-feed-using-azure-functions-in-c-d76a7f3c4ac?source=collection_archive---------5----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/876875c03dffba3fe6bb7d012059d707.png)

Azure Cosmos DB 有一个很酷的特性叫做 [Change Feed](https://docs.microsoft.com/en-us/azure/cosmos-db/change-feed) ,它允许我们通过监听容器中发生的任何变化来对我们的容器进行实时分析。

然后,这些更改被生成为文档的排序列表,这些列表按照它们被修改的顺序进行了更改。这些是持久的,可以增量处理。然后,输出可以由多个使用者进行并行处理。

这个特性在一个项目的变化可能触发另一个事件或附加动作的情况下非常有用。一个例子可能是一个项目被插入到我们的容器中,我们用它来触发一个网站警报,告诉它在我们的容器中有一个新的项目。

**默认情况下,所有 Cosmos DB 帐户都启用变更订阅功能**。您不需要做任何特殊的事情来设置它,并且您可以使用您在您的 Cosmos 帐户上提供的吞吐量来读取更改提要,就像任何常规的 Cosmos DB 操作一样。

目前,变更提要包括对容器中的项目进行插入和更新操作(这是我们在本教程中要关注的)。如果您想要捕获容器中项目的删除,您可以使用一个标记来捕获软删除,或者在项目上设置一个 [**生存时间(TTL)**](https://docs.microsoft.com/en-us/azure/cosmos-db/time-to-live) 周期,并使用该属性来捕获更改提要。请记住,更改馈送需要在比 TTL 间隔更短的时间内处理。

更改在更改提要中只出现一次。管理您可能需要的任何检查点逻辑需要由您的应用程序来完成。[更改进给处理器库](https://docs.microsoft.com/en-us/azure/cosmos-db/change-feed-processor)很适合这种情况,因为它提供了自动检查点。对于这个简单的例子,现在不用担心这个。

更改可以从任何时间点同步,并且在每个逻辑分区键值内,它按修改的顺序排序。如果您有一个大型容器,那么变更提要可以由多个使用者处理,我们可以在同一容器上同时运行多个变更提要。

[**在这篇博文发表的时候,只有 SQL API 和 Gremlin API 支持变更提要。NET、Java、Python 和 Node.js 应用**](https://docs.microsoft.com/en-us/azure/cosmos-db/change-feed#supported-apis-and-client-sdks) 。

我们可以通过三种方式使用变更馈送:

1.  [使用 Azure Cosmos DB SQL API SDK](https://docs.microsoft.com/en-us/azure/cosmos-db/read-change-feed#using-the-azure-cosmos-db-sql-api-sdk)
2.  [使用更换进给处理器库](https://docs.microsoft.com/en-us/azure/cosmos-db/read-change-feed#using-the-change-feed-processor-library)
3.  [使用 Azure 功能](https://docs.microsoft.com/en-us/azure/cosmos-db/read-change-feed#using-azure-functions)

使用 Azure 函数是迄今为止开始使用 Cosmos DB change feed 最简单的方法。我们实际上创建了在容器的变更提要中的每个新事件上触发的函数。 [CosmosDB 触发器](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-cosmos-db-triggered-function#prerequisites)允许我们使用来改变提要功能,而不用担心任何基础设施。

出于我们的目的,我将创建两个函数:

1.  一个 [HTTP 触发器](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook)函数,允许我们插入和更新新的条目。
2.  一个 [CosmosDB Trigger](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-cosmosdb-v2) 函数,它使用变更提要来跟踪我们的容器上的变更和插入,然后将这些持久化到一个租用容器中。

我使用 2.x 运行时来运行我们的函数。

现在,即使更改提要支持 Gremlin API 和 SQL API Cosmos DB 帐户,[Azure 函数的 Cosmos DB 触发器只支持 SQL API](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-cosmosdb-v2#supported-apis) ,所以这就是我们将在本演示中使用的。

你可以在这里查看[完整的代码库](https://github.com/willvelida/ChangeFeedDemo/)。这包括我在这个项目中使用的相关模型和助手类。我只是使用 Azure Cosmos DB 本地模拟器作为我的 Cosmos 帐户。本地仿真器对于在 Azure 中进行本地开发而言非常酷,无需在实际的数据库上花钱。

让我们首先创建 HTTP 触发器函数来创建和更新我们的项目:

这里我们有两个函数, **CreateTaskItem****UpdateTaskItem。**在我们的 create 函数中,我们使用 HTTP 触发器输入向我们的 Cosmos DB 数据库发出 POST 请求。我们只是创建一个简单的 TaskItem 并将其持久化到我们的 TaskCollection 集合中。我在这里使用 CosmosDB 绑定只是为了这个例子,但是如果你在生产用例中使用 Azure 函数和 Cosmos DB,你应该考虑使用 Cosmos DB 的单一实例。对于我们的更新函数,我们只是向 task/{id}的路由发出一个 PUT 请求,其中 id 是我们的任务 id。

现在让我们创建另一个函数,它监听我们的 HTTP 函数并将这些更改记录到更改提要中:

在这里,我创建了一个名为**changeed listener**的函数,它连接到我们的 *TaskItemCollection* 并监听容器上的任何变化。然后,它将这些更改保存到一个 *LeaseCollection* 容器中。在我们的函数中,每次我们在 *TaskItemCollection* 中创建或更新一个 *TaskItem* 时,它都会打印出有多少文档被更改(在我们的简单用例中只有 1 个)以及被更改的文档的 id 是什么。

**在生产场景**中,我们可以将此作为消息发送到事件中心,使用 [Twilio 绑定](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-twilio)通过文本发送,甚至作为通知发送到网站。但是现在,这个简单的函数就可以了。

我们已经完成了两个函数,所以让我们用它们做点什么吧!

因为我在本地运行,所以我将使用 [Postman](https://www.getpostman.com/) 来触发我的 HTTP 函数。让我们从 Create 函数开始,创建一个任务。为此,我们将向我们的函数 app 发出一个 **POST** 请求,并传入一个 **JSON** 主体,其中包括 *TaskName**TaskDescription**IsCompleted* 属性。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ef072bf3d4f438b5c3694d85ece91ce7.png)

点击 send 按钮发送我们的 **POST** 请求,如果我们的函数正常工作,我们应该会看到下面的 **JSON** 响应:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6947d537410f7623ecf5bc9f6974aff0.png)

现在我们的 HTTP 函数已经被触发了,不久之后我们的**changeedplistener**函数就会被触发,告诉我们有一个修改。记下下面的文档 ID。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6dbee1cb3fbb08d1b8b0e5dd47cf08a4.png)

它与我们刚刚创建的 *TaskItem* 文档的 Id 相同!在 postman 中复制该 id,并将其作为参数传递给我们的 **UpdateTaskItem** 函数。让我们更改*任务描述**已完成*值,并更新我们的项目:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/23e00e6fb9f324abaf24f9a31a4ae018.png)

看看我们的函数返回的响应体。我们可以看到,我们的项目现在已经用更新后的值进行了更改。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/889d0824ac69e99dbec4bc5e09fce6a4.png)

当我们查看函数应用程序的日志时,我们看到变更提要已经跟踪了我们对 *TaskItem* 的更新。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ebc08eebde03923034106241965a389a.png)

所以你有它!Azure Cosmos DB 变更提要的一个非常基本的例子!

花点时间让[看看代码](https://github.com/willvelida/ChangeFeedDemo/),并随意克隆它,玩玩它!如你所见,使用 Azure 函数实现变更提要功能非常简单直接。

我们还可以使用[新 Azure Cosmos SDK v3 库](https://docs.microsoft.com/en-us/azure/cosmos-db/change-feed-processor)中的变更提要处理器来利用变更提要特性,所以将来我会尝试一下并写点东西。

如果您有任何问题,欢迎在此评论或联系我。

# 从零开始实现深度学习网络。Scala 例子。

> 原文:<https://towardsdatascience.com/implementing-deep-learning-from-scratch-scala-example-340817ce7760?source=collection_archive---------14----------------------->

在过去的几年里,深度学习受到了很多关注。它最初是一种巫术崇拜,现在正在成为一项非常标准的工程任务。它变得不那么神奇,但更像是一个成熟的工具集,可以解决各种各样与数据相关的问题。

尽管如此,仍然有一个神秘的地方,因为它并不清楚这个东西实际上如何能够自己学习,甚至在没有程序员直接干预的情况下“深入”学习。让我们试着理解这一点。

# 简而言之就是神经网络。

“深度学习”的概念指的是一个[人工神经网络](https://en.wikipedia.org/wiki/Artificial_neural_network),它在某种程度上模仿了我们大脑的工作模式。基本上,它是关于通过连接层的链发送输入,其中每一层对最终结果产生自己的影响。

实际的学习是通过迭代搜索每层必须提供的最佳可能影响/权重来实现的,以便获得我们需要的输出。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/2f8627d10670ff49b6ff182e2a09e2c5.png)

Figure 1\. Neural Network with 2 hidden layers

但是在我们看一看实际的实现之前,理解所有这些层(也称为隐藏层)的用途是很重要的。 [XOR](https://en.wikipedia.org/wiki/XOR_gate) 的问题说明了一切。正如你在图 2 的*中所看到的,*你找不到任何一个线性函数能把 A 的面积和 B 的面积分开,因为你可以用[](https://en.wikipedia.org/wiki/AND_gate)和[](https://en.wikipedia.org/wiki/OR_gate)来做。中间有一个交叉点,不允许我们决定我们是在 A 段还是在 B 段。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c2a4620c1ccdd0843ec31e4a769af22d.png)

Figure 2\. AND, OR, XOR gates

为了找到答案,我们用额外的维度(或者更多的维度)来扩展我们的 2D 空间,所以你最终可以把一个特征从另一个特征中分离出来。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b276a0b5bf79c4c39bf02f19f77c2991.png)

Figure 3\. 3D space of a XOR gate

就神经网络而言,额外维度只是另一个隐藏层。所以我们所需要的——是弄清楚这另一个维度是否能让我们解决 XOR 问题。为此,我们将应用一种[反向传播](https://en.wikipedia.org/wiki/Backpropagation)算法——1975 年发表的关键概念,使互连层能够学习它们自己的权重,或者换句话说,学习它们对帮助我们在 XOR 中分离 A 和 B 有多大意义。

有了反向传播算法,我们将基本上应用 3 个步骤来实现我们的“深度”学习:

1.  前进传球
2.  偶数道次
3.  更新权重

*前向传递*是利用当前可用的权重进行预测。*倒向* *传递*给我们关于贡献的信息,每一次预测都做不到目标。有了这些信息,我们将*修正*我们的维度权重,并希望在下一次迭代中,我们的预测将使我们更接近目标。

有不同的方法来确定重量。其中之一是[梯度下降](https://en.wikipedia.org/wiki/Gradient_descent),我们也将在这里使用。

# Scala 中的实现。

在 Scala 代码中,这 3 个步骤的过程可能是这样的:

Listing 1\. Basic Neural Network Pattern

让我们仔细看看我们的第一步— *forward* 函数。我们将把它实现为递归的:

Listing 2\. Making prediction with forward pass

*向前传球*负责:

1.将权重应用于网络层

2.将该加权层通过[s 形激活](https://en.wikipedia.org/wiki/Sigmoid_function)功能

作为一个结果,我们在一个网络中得到一个新的分层预测列表。有了这个*列表*之后,我们可以去寻找每个层的预测导致错过目标的错误(规则输出)。

我们将从目标值之间的差异开始,我们希望达到我们在最后一步中所做的预测。由于我们预测的*列表*是以后进先出的方式生成的,所以*列表*中的第一个元素也是我们做出的最后一个预测,所以我们可以取一个给定的目标,看看我们离目标有多远。有了第一个误差值,我们就可以使用*反向传播*模式*来寻找其余的误差值。*

Listing 3\. Finding the first predictions error and passing it to backpropagation

由于我们在训练网络的最终端发现了一个误差幅度(或增量),我们可以用它来发现前一层的误差增量,因为我们知道这一层得到的预测。在我们进入另一个递归函数之前,每隔一个隐藏层都是如此。

Listing 4\. Backpropagation pattern

你可能会注意到,我们提供的权重是倒序的,这是因为计算反向路径的唯一方法是从网络的末端开始计算。

总的来说,我们到此为止。我们知道如何计算预测及其误差增量,以及如何使用它来更新权重。我们唯一需要做的是开始迭代我们的数据集,并将更新的权重应用于我们试图满足的预测。这样做很长时间,直到我们得到一个尽可能接近目标的权重。

为了验证你在每一次迭代中有多接近,你需要确定一个网络损耗。随着我们的网络学习,损失必须减少。

Listing 5\. Calculation of a prediction’s loss

如果您运行为本博客提供的[示例实现](https://github.com/zavalit/neural-network-example),您将会看到:

Neural Network learning log

因此,减少损失意味着我们的预测更接近他们应该有的目标值。如果我们看一看在训练过程结束时所做的预测,它们与预期值非常接近。

Training results. XOR Gate is fulfilled

# 有点小技巧。

可能是最后一件还没有涉及到的事情,就是网络的初始权重。我们非常了解如何更新它们,但是我们首先从哪里得到它们呢?为了澄清这一点,我们需要后退一步,回顾一下 layer 预测的定义。我们已经看到,要制作一个,我们需要两个步骤:

1.  *输入**权重*的标量积: ***net = np.dot(输入,权重)***
2.  激活具有 *sigmoid* 功能的产品:***1/(1+NP . exp(-net))***

但是理论上第一步实际上看起来是这样的:

> ***net = np.dot(输入,权重)+ b***

其中 *b* 代表*偏差*或阈值,必须是另一个张量,负责在得到的**被 sigmoid 激活之前对其进行调节。我们实际上还需要有一个*偏差*,而不仅仅是*权重*就像我们之前做的那样,听起来我们需要实现更多的东西。但是这里有一个技巧。

为了避免额外的复杂性,我们只需执行以下操作:

1.  向我们的训练集张量添加额外的一列(清单 6。第 3 行)
2.  用相同的一列扩展层权重(清单 6。第 11 行)

因此在我们的优化问题中加入了一个*偏差*。

Listing 6\. Prepare network weights and bias

回到我们从哪里得到*权重*的问题。看看第 1 行上的 *generateRandomWeight* 函数。这就是我们的权重最初的来源,它们或多或少是随机的。第一次意识到这一点是很奇怪的,预测的主干— *权重*,可能只是随机生成的,并且在我们更新它们几次后仍然可以进行正确的预测。

# **结论。**

所以希望你能够看到“深度学习”非常接近于常规的编程任务。围绕这种软件和平的秘密,基本上基于两种主要模式:

1.  通过应用反向传播模式,确定我们的神经网络预测离实际目标有多远。
2.  通过借助于随机梯度下降模式更新层权重来逐渐减小该误差空间。

可能是一些有用的链接:

*   这篇博文中使用的代码库:[https://github.com/zavalit/neural-network-example](https://github.com/zavalit/neural-network-example)
*   神经网络游乐场:[http://playground.tensorflow.org](http://playground.tensorflow.org)
*   深入学习(基于 MXNet):[http://d2l . ai](http://d2l.ai)
*   从数学角度看密集连通层的工作:【https://www.youtube.com/watch?v=fXOsFF95ifk 
*   Scala 中的 Numpy 实现[https://github.com/botkop/numsca](https://medium.com/@koen_95886/nice-article-b83b6b7afbda?source=post_info_responses---------0---------------------)

*PS。我想值得一提的是,这不是一篇关于用 Scala 编写的神经网络的生产就绪实现的博文。也许下次吧;)这里的主要焦点是尽可能透明和明显地展示基本模式。我希望你喜欢它。*

# 使用 Python 实现和分析不同的激活函数和权重初始化方法

> 原文:<https://towardsdatascience.com/implementing-different-activation-functions-and-weight-initialization-methods-using-python-c78643b9f20f?source=collection_archive---------7----------------------->

## [深入分析](https://medium.com/towards-data-science/in-depth-analysis/home)

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b8c9b9c87bb44cb71cd0eebb53a5d256.png)

Non-Linearly Separable Data

在本帖中,我们将讨论如何在 python 中实现非线性激活函数和权重初始化方法的不同组合。此外,我们将分析激活函数和权重初始化方法的选择将如何影响准确性以及我们使用非线性可分离玩具数据集在深度神经网络中减少损失的速率。这是我上一篇关于[激活函数和权重初始化方法](https://medium.com/datadriveninvestor/deep-learning-best-practices-activation-functions-weight-initialization-methods-part-1-c235ff976ed)的后续文章。

注意:本文假设读者对神经网络、权重、偏差和反向传播有基本的了解。如果你想学习前馈神经网络的基础知识,可以看看我以前的文章(本文末尾的链接)。

> ***引用注:本文内容和结构基于四分之一实验室深度学习讲座—***[***pad hai***](https://padhai.onefourthlabs.in)***。***

# 激活功能概述

激活函数是非线性函数,我们将该函数应用于到达特定神经元的输入数据,并且该函数的输出将作为输入被发送到下一层中存在的神经元。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/89ecba901fc0cbcb6db41313f4dfa349.png)

即使我们使用没有非线性激活函数的非常非常深的神经网络,我们也只是将' **y** '学习为' **x** '的线性变换。它只能表示' **x** '和' **y** '之间的线性关系。换句话说,我们将被限制于学习线性决策边界,并且我们不能学习任何任意的非线性决策边界。这就是为什么我们需要激活函数——非线性激活函数来学习输入和输出之间复杂的非线性关系。

一些常用的激活功能,

*   **后勤**
*   Tanh
*   **ReLU**
*   **泄漏的 ReLU**

# 重量初始化概述

当我们训练深度神经网络时,权重和偏差通常用随机值初始化。在将权重初始化为随机值的过程中,我们可能会遇到消失梯度或爆炸梯度等问题。因此,网络将需要很长时间才能收敛(如果它真的收敛的话)。最常用的权重初始化方法:

*   Xavier 初始化
*   He 初始化

要理解最常用的激活函数和权重初始化方法背后的直觉,请参考我以前关于激活函数和权重初始化方法的帖子。

[](https://medium.com/datadriveninvestor/deep-learning-best-practices-activation-functions-weight-initialization-methods-part-1-c235ff976ed) [## 深度学习最佳实践:激活函数和权重初始化方法—第 1 部分

### 最佳激活函数和权重初始化方法可提高精确度

medium.com](https://medium.com/datadriveninvestor/deep-learning-best-practices-activation-functions-weight-initialization-methods-part-1-c235ff976ed) 

# 让我们编码

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8a2b0b3f36bfee9c430ecac221d60187.png)

Photo by [Goran Ivos](https://unsplash.com/@goran_ivos?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

在编码部分,我们将涉及以下主题。

1.  **生成不可线性分离的数据**
2.  **写一个前馈网络类**
3.  **绘图设置代码**
4.  **分析乙状结肠激活**
5.  **分析 tanh 激活**
6.  **分析 ReLU 激活**
7.  **分析泄漏 ReLU 激活**

## 概观

在本节中,我们将通过尝试激活函数和权重初始化方法的各种组合来比较简单前馈神经网络的准确性。

我们这样做的方式是,首先我们将生成具有两个类的非线性可分离数据,并编写我们简单的前馈神经网络,它支持所有的激活函数和权重初始化方法。然后使用损失图比较不同的场景。

如果你想跳过理论部分,直接进入代码,

[](https://github.com/Niranjankumar-c/DeepLearning-PadhAI) [## niranjankumar-c/deep learning-PadhAI

### 来自 pad hai-Niranjankumar-c/deep learning-pad hai 的深度学习课程相关的所有代码文件

github.com](https://github.com/Niranjankumar-c/DeepLearning-PadhAI) 

## 将库作为 L 导入

在我们开始分析前馈网络之前,首先我们需要导入所需的库。我们正在导入`numpy`来评估神经网络中两个向量之间的矩阵乘法和点积,导入`matplotlib`来可视化数据,并从`sklearn`包中导入函数来生成数据和评估网络性能。在 Jupiter notebook import 中内联显示/呈现 HTML 内容`HTML`。

在第 19 行,我们通过使用`LinearSegmentedColormap`的`[from_list()](https://matplotlib.org/api/_as_gen/matplotlib.colors.LinearSegmentedColormap.html#matplotlib.colors.LinearSegmentedColormap.from_list)`方法从颜色列表中创建一个定制的颜色映射。

# 生成虚拟数据

请记住,我们使用前馈神经网络是因为我们想要处理非线性可分数据。在本节中,我们将了解如何随机生成非线性可分数据。

为了随机生成数据,我们将使用`make_blobs`来生成高斯分布的点。我在具有四个斑点`centers=4`的 2D 空间中生成了 1000 个数据点,作为多类分类预测问题。每个数据点有两个输入和 0、1、2 或 3 个类别标签。注意`make_blobs()`函数会生成线性可分的数据,但是我们需要有非线性可分的数据进行二分类。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/66fbfc1bd702d4dc213a40a5ece28a30.png)

Multi-Class Linearly Separable Data

labels_orig = labels
labels = np.mod(labels_orig, 2)


将这 4 个类转换为二进制分类的一种方法是将这 4 个类的余数除以 2,这样我就可以得到新的标签 01。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/17eadf14011f32dde0f9e49d80e553f0.png)

从该图中,我们可以看到斑点的中心被合并,使得我们现在有一个二元分类问题,其中决策边界不是线性的。一旦我们准备好数据,我已经使用`train_test_split` 函数以 90:10 的比例分割`training``validation`的数据

# 前馈网络

在本节中,我们将编写一个通用类,它可以通过将隐藏层的数量和每个隐藏层中的神经元数量作为输入参数来生成神经网络。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ae2556334e70b65e22ee1b6f1f30b020.png)

Simple Neural Network

该网络总共有六个神经元——两个在第一个隐藏层,四个在输出层。对于这些神经元中的每一个,预激活用‘a’表示,后激活用‘h’表示。在网络中,我们总共有 18 个参数——12 个权重参数和 6 个偏差项。

我们将在一个名为 **FFNetwork** *的类中编写我们的神经网络。*

在`FirstFFNetwork`类中,我们有 8 个函数,我们将一个接一个地检查这些函数。

def init(self, init_method = 'random', activation_function = 'sigmoid', leaky_slope = 0.1):
......


`__init__`函数初始化网络的所有参数,包括权重和偏差。该函数接受几个参数,

*   `init_method`:用于初始化网络所有参数的初始化方法。支持—“随机”、“零点”、“何”和“泽维尔”。
*   `activation_function`:用于学习非线性决策边界的激活函数。支持—“sigmoid”、“tanh”、“relu”和“leaky_relu”。
*   `leaky_slope`:漏 ReLU 的负斜率。默认值设置为 0.1。

在第 5–10 行中,我们设置了网络配置和要在网络中使用的激活功能。

self.layer_sizes = [2, 2, 4]


`layer_sizes`表示网络有两个输入,第一个隐藏层有两个神经元,第二个隐藏层有 4 个神经元,在这种情况下,第二个隐藏层也是最后一层。之后,我们有一堆“if-else”权重初始化语句,在这些语句中,我们只根据选择的方法初始化权重,偏差总是初始化为值 1。权重和偏差的初始值存储在字典`self.params`中。

def forward_activation(self, X):
if self.activation_function == "sigmoid":
return 1.0/(1.0 + np.exp(-X))
elif self.activation_function == "tanh":
return np.tanh(X)
elif self.activation_function == "relu":
return np.maximum(0,X)
elif self.activation_function == "leaky_relu":
return np.maximum(self.leaky_slope*X,X)


接下来,我们有`forward_activation`函数,它将输入‘X’作为参数,并根据激活函数的选择计算输入的激活后值。

def grad_activation(self, X):
......


函数`grad_activation`也将输入‘X’作为参数,计算激活函数在给定输入处的导数并返回它。

def forward_pass(self, X, params = None):.......
def grad(self, X, Y, params = None):
.......


之后,我们有两个函数`forward_pass`来描述向前传球。向前传球包括两步

1.  激活后—计算输入**x**权重 **w** 和相加偏差 **b** 之间的点积
2.  预激活—获取后激活的输出,并在其上应用激活功能。

`grad`函数表征网络中每个参数的梯度计算,并将其存储在一个名为`gradients`的列表中。不要太担心我们是如何得到梯度的,因为我们将使用 Pytorch 来完成繁重的工作,但是如果你有兴趣学习它们,可以看看我以前的文章。

[](https://hackernoon.com/building-a-feedforward-neural-network-from-scratch-in-python-d3526457156b) [## 用 Python 从头开始构建前馈神经网络

### 在没有任何框架的情况下,构建您的第一个通用前馈神经网络

hackernoon.com](https://hackernoon.com/building-a-feedforward-neural-network-from-scratch-in-python-d3526457156b) 

def fit(self, X, Y, epochs=1, algo= "GD", display_loss=False,
eta=1, mini_batch_size=100, eps=1e-8,
beta=0.9, beta1=0.9, beta2=0.9, gamma=0.9 ):


接下来,我们定义`fit`方法,该方法将输入‘X’和‘Y’作为强制参数,以及实现梯度下降算法的不同变体所需的一些可选参数。请参考我以前的帖子,了解如何实现算法的详细解释。

[](https://hackernoon.com/implementing-different-variants-of-gradient-descent-optimization-algorithm-in-python-using-numpy-809e7ab3bab4) [## 使用 Numpy 在 Python 中实现梯度下降优化算法的不同变体

### 了解 tensorflow 或 pytorch 如何使用 numpy 实现优化算法,并使用…

hackernoon.com](https://hackernoon.com/implementing-different-variants-of-gradient-descent-optimization-algorithm-in-python-using-numpy-809e7ab3bab4) 

def predict(self, X):


现在我们定义我们的预测函数将输入`X`作为一个参数,它期望是一个`numpy`数组。在预测函数中,我们将使用训练好的模型计算每个输入的前向传递,并发回一个包含每个输入数据的预测值的 numpy `array`# 用于绘图和训练神经网络的设置

在本节中,我们将定义一个函数来评估神经网络的性能,并创建图形来可视化更新规则的工作。这种设置有助于我们使用不同的激活函数、不同的权重初始化方法和梯度下降的不同变量的绘图更新规则来运行不同的实验

首先,我们实例化前馈网络类,然后在具有 10 个时期和设置为 1 的学习率的训练数据上调用`fit`方法(这些值是任意的,不是该数据的最佳值,您可以围绕这些值进行操作,并找到最佳时期数和学习率)。

然后我们将调用`post_process`函数来计算神经网络的训练和验证精度(第 211 行)。我们还根据神经网络的预测值绘制了不同大小的输入点的散点图。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7647df73d189db1d13394d43c67ee39f.png)

Scatter Plot

图中每个点的大小由一个公式给出,

s=15*(np.abs(Y_pred_binarised_train-Y_train)+.2)


该公式采用预测值和实际值之间的绝对差值。

*   如果实际值等于预测值,则大小= 3
*   如果实际值不等于预测值,则大小= 18

图中的所有小点表示模型正确预测了这些观察值,大点表示这些观察值分类不正确。

第 20–29 行,我们绘制了使用反向传播从网络获得的每个参数的更新。在我们的网络中,总共有 18 个参数,所以我们迭代了 18 次,每次我们将找到每个参数得到的更新,并使用 subplot 绘制它们。例如,在 iᵗʰ纪元=Wᵢ₊₁-wᵢ更新 wᵢ权重

# 分析乙状结肠激活

为了分析 sigmoid 激活函数对神经网络的影响,我们将激活函数设置为“sigmoid ”,并执行神经网络类。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8a1011a38f3884432c58b01271f2949e.png)

即使我们已经运行了很少的迭代,网络的损耗也在下降。通过使用`post_process`函数,我们能够绘制 18 个支线剧情,我们没有提供任何轴标签,因为这不是必需的。18 个参数的 18 个图按行主顺序绘制,表示参数接收更新的频率。前 12 个图表示权重接收的更新,后 6 个图表示网络中偏置项接收的更新。

在任一子图中,如果曲线更靠近中间,则表明特定参数没有得到任何更新。我们将编写一个`for — loop`来执行所有可能的权重初始化组合,而不是手动执行每个权重初始化。

for init_method in ['zeros', 'random', 'xavier', 'he']:
for activation_function in ['sigmoid']:
print(init_method, activation_function)
model = FFNetwork(init_method=init_method,activation_function = activation_function)
model.fit(X_train, y_OH_train, epochs=50, eta=1, algo="GD", display_loss=True)
post_process(plot_scale=0.05)
print('\n--\n')


在上面的代码中,我只是添加了两个“for”循环。一个“for”循环用于重量初始化,另一个“for”循环用于激活功能。一旦执行了上面的代码,就会看到神经网络通过保持激活函数— sigmoid 常数,尝试了所有可能的权重初始化方法。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/2788355cb8c060f7509d8e8a1ec6ba54.png)

Sigmoid Function Execution

如果用 sigmoid 观察零权重初始化方法的输出,可以看到对称性破缺问题发生在 sigmoid 神经元中。一旦我们将权重初始化为零,在所有后续迭代中,权重将保持不变(它们将远离零,但它们将相等),这种对称性在训练期间将永远不会打破。这种现象被称为**对称性破缺问题**。因为这个问题,我们的准确率只有 54%。

在随机初始化中,我们可以看到对称性破缺的问题没有发生。这意味着所有的权重和偏差在训练期间取不同的值。通过使用 Xavier 初始化,我们得到了不同权重初始化方法的最高精度。 **Xavier 是 sigmoid 和 tanh 激活函数的推荐权重初始化方法。**

# 分析 Tanh 激活

我们将使用相同的代码,通过在第二个“for”循环中包含关键字“tanh ”,以不同的权重初始化方法组合来执行 tanh 激活函数。

for activation_function in ['tanh']:


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/fdc2dbe35b96256de527e02e17a2e06c.png)

Tanh Activation

在 tanh 激活的零初始化中,从权重更新支线剧情中,我们可以看到 tanh 激活几乎学不到什么东西。在所有图中,曲线更接近于零,表明参数没有从优化算法获得更新。这种现象背后的原因是,tanh 在 x = 0 时的值为零,tanh 的导数也为零。

当我们用 tanh 进行 Xavier 初始化时,我们能够从神经网络获得更高的性能。仅通过改变权重初始化的方法,我们就能够获得更高的准确度(86.6%)# 分析 ReLU 激活

通过在第二个“for”循环中包含关键字“relu ”,我们将使用相同的代码来执行具有不同权重初始化方法组合的 ReLU 激活函数。

for activation_function in ['relu']:


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1e82f4c862571e4d4d321d21607eddf0.png)

ReLU Activation

类似于零权重初始化的 tanh,我们观察到将权重设置为零对 ReLU 不起作用,因为 ReLU 在零处的值等于零本身。因此,权重不会传播回网络,网络也不会学习任何东西。**因此,在 tanh 或 ReLU 的情况下,将权重设置为零都不是一个好主意。**

ReLU 的推荐初始化方法是 he 初始化,通过使用 He 初始化,我们能够获得最高的精度。

# 分析泄漏 ReLU 激活

通过在第二个“for”循环中包含关键字“relu ”,我们将使用相同的代码来执行具有不同权重初始化方法组合的 ReLU 激活函数。

for activation_function in ['leaky_relu']:


类似于零权重初始化的 ReLU,我们观察到将权重设置为零对泄漏 ReLU 不起作用,因为泄漏 ReLU 在零处的值等于零本身。因此,权重不会传播回网络,网络也不会学习任何东西。

对于随机初始化,我们可以看到网络达到了非常好的精度,但是在更新子曲线中有很多振荡。大的振荡可能是由于大的学习速率而发生的。通过使用 He 初始化,我们在测试数据上获得了 92%的最高准确率。为了避免大的振荡,我们应该在任何权重初始化方法中设置较小的学习速率。**推荐的 Leaky ReLU 初始化方法是 he 初始化。**

现在,我们已经成功地分析了权重初始化方法和激活函数的不同组合。

# 下一步是什么?

> 代码代码代码

在本文中,我们使用了`make_blobs`函数来生成玩具数据,我们已经看到`make_blobs`生成线性可分数据。如果你想生成一些复杂的非线性可分数据来训练你的前馈神经网络,可以使用`sklearn`包中的`make_moons`函数。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/937d240a4dbef19067b63942970b2cc7.png)

您也可以尝试将学习算法(我们一直使用普通梯度下降)改为不同的梯度下降变体,如 Adam、NAG 等,并研究学习算法对网络性能的影响。使用我们的前馈神经网络类,您可以创建一个更深的网络,每层有更多数量的神经元([2,2,2,4] —前 3 个隐藏层各有两个神经元,输出层有 4 个神经元),并调整学习速率&多个时期,以检查在哪些参数下神经网络能够达到可能的最佳决策边界。

本文中讨论的全部代码都在这个 GitHub 存储库中。随意叉或者下载。**最棒的是,你可以直接在 google colab 中运行代码,不需要担心安装包**。

[](https://github.com/Niranjankumar-c/DeepLearning-PadhAI) [## niranjankumar-c/deep learning-PadhAI

### 来自 pad hai-Niranjankumar-c/deep learning-pad hai 的深度学习课程相关的所有代码文件

github.com](https://github.com/Niranjankumar-c/DeepLearning-PadhAI) 

# 结论

在这篇文章中,我们简要地看了权重初始化方法和激活函数的概述。然后,我们看到了如何构建一个通用的简单神经元网络类,它支持梯度下降、权重初始化和激活函数的不同变体。之后,我们分析了每个激活函数的不同权重初始化方法。

# 了解更多信息

如果你想学习更多的数据科学,机器学习。查看来自 [Starttechacademy](https://courses.starttechacademy.com/full-site-access/?coupon=NKSTACAD) 的 Abhishek 和 Pukhraj 的[机器学习基础知识](https://courses.starttechacademy.com/full-site-access/?coupon=NKSTACAD)和[高级机器学习](https://courses.starttechacademy.com/full-site-access/?coupon=NKSTACAD)。这些课程的一个优点是它们同时用 Python 和 R 语言授课,所以这是你的选择。

*推荐阅读*

[](https://hackernoon.com/deep-learning-feedforward-neural-networks-explained-c34ae3f084f1) [## 深度学习:解释前馈神经网络

### 你的第一个深度神经网络

hackernoon.com](https://hackernoon.com/deep-learning-feedforward-neural-networks-explained-c34ae3f084f1) 

**作者简介**

[Niranjan Kumar](https://medium.com/u/3e4fb2985698?source=post_page-----c78643b9f20f--------------------------------) 是汇丰银行分析部门的零售风险分析师。他对深度学习和人工智能充满热情。他是[人工智能](https://medium.com/tag/artificial-intelligence/top-writers)中[媒体](https://medium.com/u/504c7870fdb6?source=post_page-----c78643b9f20f--------------------------------)的顶尖作家之一。你可以在这里找到 Niranjan 的所有博客。你可以在 LinkedIn[LinkedIn](https://www.linkedin.com/in/niranjankumar-c/)、 [Twitter](https://twitter.com/Nkumar_283) 和 [GitHub](https://github.com/Niranjankumar-c) 上与 Niranjan 联系,了解他的最新博客文章。

**免责声明** —这篇文章中可能有一些相关资源的附属链接。你可以以尽可能低的价格购买捆绑包。如果你购买这门课程,我会收到一小笔佣金。

# 实现混合成员随机块模型

> 原文:<https://towardsdatascience.com/implementing-mixed-membership-stochastic-blockmodel-c8129b3bd985?source=collection_archive---------11----------------------->

MMSB:一种用于学习图形结构的概率模型。用 Julia 写的代码可以在这里找到(Jupyter 笔记本上的图表和输出)或者在这里找到(。jl 文件)。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5ddc2acc22f7b1d08378da91202cb5ee.png)

From social networks to protein interactions, graphs have become ubiquitous.

你好!

我叫索米亚·沙阿。这是一篇描述混合成员随机块模型实现的文章,这是一个学习图结构的贝叶斯模型。为此,我将使用用 Julia 编写的概率编程语言(PPL)turing . JL。在图灵中定义模型轻而易举。编写代码就像在纸上写模型一样。那么,事不宜迟,我们开始吧!

# 介绍

MMSB 用于对由成对测量值组成的数据进行建模,以图表的形式进行建模。考虑具有 N 个节点的图 *G* ,具有二进制边权重(即 0 或 1)。因此,1 表示两个节点之间有连接,0 表示没有连接。邻接矩阵表示节点之间的这些连接。MMSB 有助于学习该图的底层结构,这可以重建该图,识别节点之间的模式和关系,并预测未看到的数据的链接。在下面的例子中,我们假设这是一个**无向图**(即邻接矩阵是对称的)。

# 当然,它有一个奇特的名字,但是我在哪里使用它呢?

*   **社交网络:**从用户和他们所属的社区之间的关系数据中,我们可以聚集具有共同兴趣的群体,并提出建议。
*   **蛋白质相互作用:**不同的蛋白质以不同的方式相互作用。利用 MMSB,我们可以预测两种特定蛋白质之间的相互作用及其功能。
*   **学术引文:**引文网络可以帮助我们根据科学家的领域和他的出版物来确定一篇研究论文的重要性。

# 它是如何工作的?

我们来钻研一下数学:)。首先,我们假设我们的图有 *N* 个节点。总共有 *K 个*星团。每个节点具有由 *π_n* 表示的成员概率向量,其指定了节点 *n* 属于每个 *K* 集群的概率。对于每对节点 *n**m* ,我们从两个概率向量 *π_n**π_ m*中的每一个中得出一个集群。这意味着当考虑到节点 *n**m、*之间的链接时,节点 *n* 可以属于一个特定的集群,而当考虑到节点*n*之间的关系时,它可以属于另一个集群这就是模型的*混合成员*部分出现的地方。简而言之,每个节点 n 可能有多个集群成员,这取决于它与哪个节点 m 交互。

所以我们有每对节点的集群。我们该拿它怎么办?这就是*随机区块模型*部分的用武之地。一对对象之间的链接取决于它们所属的簇。为此,我们维护了一个 *K×K* 矩阵η,它指定了任意两个集群之间的连接概率。我们使用伯努利分布来确定从一对节点中抽取的一对集群之间是否存在链接。

综上所述,我们考虑所有节点对来确定它们是否链接。对于一个给定的对,我们从其各自的概率向量中为每个节点绘制一个簇分配。基于这些聚类分配,我们通过在矩阵η中查找其值来找到这一对聚类之间的链接的概率。然后,我们将这个概率传递给伯努利分布,得到 1(连接)或 0(不连接)值。

数学上,生成性故事被指定为(这里,α和η是超参数, **π** _1,…,π_N,z11,…,z_NN 是我们要推断的参数):

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7b2a7f5f57c35000447723078c955fec.png)

# 密码在哪里?

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ceb544b5e4f5b31d4e1e30d01bfab526.png)

“Talk is cheap. Show me the code.”- Linus Torvalds

好了,既然我们已经为 MMSB 是什么以及它是如何工作的打下了基础,那么让我们来看看代码。我们从导入库开始:

继续,我们选择集群的数量 *K = 2* 并设置超参数:

现在,我们生成用于模型的数据。为此,我们对每个节点进行随机集群分配。我们还使用 matplotlib 作为后端,以热图的形式可视化了这个图。

获得了以下可视化:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e6aac82e83767797eef4ec81ca56f535.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/86e1c51366016a2b91d52146c43e679e.png)

请注意,可视化效果可能因您而异,因为聚类是随机生成的。

我们来定义一下模型。我稍微调整了模型,使其具有“软”集群分配。因此,我们使用整个概率向量来确定每对节点之间存在链接的概率,而不是从分类分布中提取。因此,参数 z_11,…,z_NN 已被消除,我们只需要推断 pi_1,…,pi_N。这一调整减少了要估计的参数数量,并导致更快的收敛。

还记得我说过的在图灵中定义模型的简易性吗?这里有一个活生生的例子!注意模型是如何定义的,类似于它是如何编写的。

既然我们已经定义了模型,我们可以为后验样本绘制样本。下面的代码块演示了这一点:

您应该会看到描述该链的输出和采样参数的摘要。为了查看我得到的输出,你可以看看这里的代码(在 Jupyter 笔记本中)。我们还可以绘制这些样本,以可视化它们的分布,并检查它们是否已经收敛。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/03f1f0eb541042095892319781959f78.png)

从上面的图中可以看出,在大约 30,000 次迭代之后,所有的参数都收敛了。所以,我们可以期待我们的模型给出好的预测。让我们使用采样参数重建图形,看看它们的估计有多好。

预测图的热图为:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/86e1c51366016a2b91d52146c43e679e.png)

这与我们生成的数据完全相同!该模型成功地重建了原始图形。

我们还可以从数字上计算重建图和原始图之间的不匹配数。这方面的代码如下:

正如所料,这将打印:

The number of mismatches is 0


这就结束了我在 Julia 中混合成员随机块模型的实现。如果您对此有任何问题或疑问,请随时通过 [s](https://saumyagshah.github.io/) shah@iitk.ac.in 联系我,或者您可以在 Julia slack 上用@Saumya Shah 标记我。希望你能像我写这篇文章一样喜欢读这篇文章:)。

上面解释的代码可以在[这里](https://github.com/saumyagshah/JupyterNBTuringExamples/blob/master/mmsb.ipynb) (Jupyter 笔记本上的图和输出)或者[这里](https://github.com/TuringLang/TuringExamples/blob/master/mmsb.jl)(。jl 文件)。

# 下一步是什么?

我现在将继续实现一些非常有趣的主题:时间序列模型。一旦准备好了,我会写一个帖子。与此同时,图灵大学的一些学生正在开发一个变分推理界面,预计将在一两个月内完成。一旦完成,我将把它与上面的 MMSB 实现集成,以允许对更大的图形进行推断。

# 参考:

[1] Airoldi,Edoardo M .,David M. Blei,Stephen E. Fienberg,和 Eric P. Xing,[混合成员随机块模型](https://arxiv.org/abs/0705.4485) (2008),《机器学习研究杂志》第 9 期,9 月号(2008):1981–2014。

# 用 Doc2Vec 实现多类文本分类

> 原文:<https://towardsdatascience.com/implementing-multi-class-text-classification-with-doc2vec-df7c3812824d?source=collection_archive---------9----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8ec03ba38a32452bae40bf7c63f88d3e.png)

Image by [Gerd Altmann](https://pixabay.com/users/geralt-9301/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1668918) from [Pixabay](https://pixabay.com/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1668918) ([Image Link](https://pixabay.com/illustrations/film-negative-photographs-slides-1668918/))

# 介绍

在本文中,您将学习如何在使用 Doc2Vec 表示文档时将文本文档分类到不同的类别。我们将通过一个简单易懂的例子来了解这一点,这个例子使用 Doc2vec 作为特征表示,使用逻辑回归作为分类算法,通过流派对电影情节进行分类。 [**电影数据集**](https://github.com/RaRe-Technologies/movie-plots-by-genre) 包含简短的电影情节描述,它们的标签代表类型。数据集中有六个**流派**:

1.  科幻小说
2.  行动
3.  喜剧
4.  幻想
5.  动画
6.  浪漫性

# 什么是 Doc2Vec,我们为什么需要它?

那么,为什么要选择 **doc2vec** 表示法而不是使用广为人知的 bag-of-words( **BOW** )方法呢?对于复杂的文本分类算法, **BOW** 不适合,因为它缺乏捕捉文本中单词的语义和句法顺序的能力。因此,将它们用作机器学习算法的特征输入不会产生显著的性能。另一方面,Doc2Vec 能够检测单词之间的关系,并理解文本的语义。Doc2Vec 是一种无监督算法,它为段落/文档/文本学习固定长度的特征向量。为了理解 **doc2vec** 的基本工作,需要理解 **word2vec** 如何工作,因为它使用相同的逻辑,除了文档特定向量是添加的特征向量。关于这个的更多细节,你可以阅读这个[博客](https://medium.com/scaleabout/a-gentle-introduction-to-doc2vec-db3e8c0cce5e)。现在我们知道了为什么使用它,以及 doc2vec 将如何在这个程序中使用,我们可以进入下一个阶段,实际实现分类器。

让我们开始构建一个电影情节分类器吧!!

# **实施**

这涉及到以下三个主要部分:

1.  加载和准备文本数据
2.  使用 **doc2vec** 模型获取特征向量
3.  训练分类器

以下是输入 csv 文件的前三行:

,movieId,plot,tag0,1,"A little boy named Andy loves to be in his room, playing with his toys, especially his doll named ""Woody"". But, what do the toys do when Andy is not with them, they come to life. Woody believes that he has life (as a toy) good. However, he must worry about Andy's family moving, and what Woody does not know is about Andy's birthday party. Woody does not realize that Andy's mother gave him an action figure known as Buzz Lightyear, who does not believe that he is a toy, and quickly becomes Andy's new favorite toy. Woody, who is now consumed with jealousy, tries to get rid of Buzz. Then, both Woody and Buzz are now lost. They must find a way to get back to Andy before he moves without them, but they will have to pass through a ruthless toy killer, Sid Phillips.",animation1,2,"When two kids find and play a magical board game, they release a man trapped for decades in it and a host of dangers that can only be stopped by finishing the game.",fantasy


导入所需的库:

我们使用多处理技术来利用所有内核,以便通过 Doc2Vec 进行更快的训练。tqdm 包用于在训练时显示进度条。我们对 Doc2Vec 使用 gensim 包。出于分类目的,使用来自 scikit-learn 的逻辑回归。NLTK 包用于标记化任务。

from gensim.test.utils import common_texts
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from sklearn.metrics import accuracy_score, f1_score
from sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LogisticRegression
from sklearn import utils
import csv
from tqdm import tqdm
import multiprocessingimport nltk
from nltk.corpus import stopwords


## 1.阅读和准备文本数据

以下代码用于从 csv 读取数据,并用于标记化功能,在创建培训和测试文档作为 **doc2vec** 模型的输入时,将使用这些代码。数据有 2448 行,我们选择前 2000 行用于训练,其余的用于测试。

tqdm.pandas(desc="progress-bar")# Function for tokenizingdef tokenize_text(text):
tokens = []
for sent in nltk.sent_tokenize(text):
for word in nltk.word_tokenize(sent):
if len(word) < 2:
continue
tokens.append(word.lower())
return tokens# Initializing the variablestrain_documents = []
test_documents = []
i = 0# Associating the tags(labels) with numberstags_index = {'sci-fi': 1 , 'action': 2, 'comedy': 3, 'fantasy': 4, 'animation': 5, 'romance': 6}#Reading the fileFILEPATH = 'data/tagged_plots_movielens.csv'
with open(FILEPATH, 'r') as csvfile:
with open('data/tagged_plots_movielens.csv', 'r') as csvfile:
moviereader = csv.reader(csvfile, delimiter=',', quotechar='"')
for row in moviereader:
if i == 0:
i += 1
continue
i += 1
if i <= 2000: train_documents.append( TaggedDocument(words=tokenize_text(row[2]), tags=[tags_index.get(row[3], 8)] )) else:
test_documents.append( TaggedDocument(words=tokenize_text(row[2]),
tags=[tags_index.get(row[3], 8)]))print(train_documents[0])


第一行的 training_document 输出是 TaggedDocument 对象。这将标记显示为 TaggedDocument 的第一个参数,labelID 显示为第二个参数(5: Animation)。

TaggedDocument(['little', 'boy', 'named', 'andy', 'loves', 'to', 'be', 'in', 'his', 'room', 'playing', 'with', 'his', 'toys', 'especially', 'his', 'doll', 'named', '``', 'woody', "''", 'but', 'what', 'do', 'the', 'toys', 'do', 'when', 'andy', 'is', 'not', 'with', 'them', 'they', 'come', 'to', 'life', 'woody', 'believes', 'that', 'he', 'has', 'life', 'as', 'toy', 'good', 'however', 'he', 'must', 'worry', 'about', 'andy', "'s", 'family', 'moving', 'and', 'what', 'woody', 'does', 'not', 'know', 'is', 'about', 'andy', "'s", 'birthday', 'party', 'woody', 'does', 'not', 'realize', 'that', 'andy', "'s", 'mother', 'gave', 'him', 'an', 'action', 'figure', 'known', 'as', 'buzz', 'lightyear', 'who', 'does', 'not', 'believe', 'that', 'he', 'is', 'toy', 'and', 'quickly', 'becomes', 'andy', "'s", 'new', 'favorite', 'toy', 'woody', 'who', 'is', 'now', 'consumed', 'with', 'jealousy', 'tries', 'to', 'get', 'rid', 'of', 'buzz', 'then', 'both', 'woody', 'and', 'buzz', 'are', 'now', 'lost', 'they', 'must', 'find', 'way', 'to', 'get', 'back', 'to', 'andy', 'before', 'he', 'moves', 'without', 'them', 'but', 'they', 'will', 'have', 'to', 'pass', 'through', 'ruthless', 'toy', 'killer', 'sid', 'phillips'], [5])


## 2.从 doc2vec 模型中获取特征向量

接下来,我们初始化 [gensim doc2vec 模型](https://radimrehurek.com/gensim/models/doc2vec.html)并训练 30 个时期。这个过程非常简单。Doc2Vec 体系结构也有两个类似 word2vec 的算法,它们是这两个算法的对应算法,即“连续单词包”(CBOW)和“Skip-Gram”(SG)。doc2vec 中的一种算法称为段落向量分布单词袋(PV-DBOW ),它类似于 word2vec 中的 SG 模型,只是增加了额外的段落 id 向量。这里训练神经网络来预测给定段落中周围单词的向量和基于段落中给定单词的段落 id 向量。第二种算法是段落向量(PV-DM),类似于词向量中的 CBOW。

**doc2vec** 模型的几个重要参数包括:

`dm` ({0,1},可选)1: PV-DM,0: PV-DBOW

`vector_size`特征向量的维数(我们选择 300)

`workers`这是我们分配了核心数的线程数

其余参数详情可在[这里](https://radimrehurek.com/gensim/models/doc2vec.html)找到。初始化之后,我们使用`train_documents`构建词汇表

cores = multiprocessing.cpu_count()

model_dbow = Doc2Vec(dm=1, vector_size=300, negative=5, hs=0, min_count=2, sample = 0, workers=cores, alpha=0.025, min_alpha=0.001)
model_dbow.build_vocab([x for x in tqdm(train_documents)])train_documents = utils.shuffle(train_documents)
model_dbow.train(train_documents,total_examples=len(train_documents), epochs=30)def vector_for_learning(model, input_docs):
sents = input_docs
targets, feature_vectors = zip(*[(doc.tags[0], model.infer_vector(doc.words, steps=20)) for doc in sents])
return targets, feature_vectorsmodel_dbow.save('./movieModel.d2v')


## 3.训练分类器

最后,使用上述特征向量构建函数训练逻辑回归分类器。这里,我们在训练时使用为`train_documents`生成的特征向量,并在预测阶段使用`test_documents`的特征向量。

y_train, X_train = vector_for_learning(model_dbow, train_documents)
y_test, X_test = vector_for_learning(model_dbow, test_documents)

logreg = LogisticRegression(n_jobs=1, C=1e5)
logreg.fit(X_train, y_train)
y_pred = logreg.predict(X_test)print('Testing accuracy for movie plots%s' % accuracy_score(y_test, y_pred))
print('Testing F1 score for movie plots: {}'.format(f1_score(y_test, y_pred, average='weighted')))


`dm=1`时的输出如下:

Testing accuracy 0.42316258351893093
Testing F1 score: 0.41259684559985876


这种准确性只能通过很短的文本的少量记录来获得,因此,这可以通过添加更好的功能来提高,如 n-grams,使用停用词来消除噪声。

# **进一步发展**

在此基础上,您可以更容易地使用其他数据集进行实验,并且更改 doc2vec 的算法就像更改`dm`参数一样简单。希望这有助于您使用 Doc2Vec 开始您的第一个文本分类项目!

作者:[迪皮卡·巴德](https://www.linkedin.com/in/dipika-baad-154a2858/)

# 实施 Prophet 时间序列预测模型

> 原文:<https://towardsdatascience.com/implementing-prophet-time-series-forecasting-model-f16d2a191acc?source=collection_archive---------13----------------------->

## 一步一步地预测虚拟比特币价格的方法

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/0ab0bd36cdd760de4ac4942ea6e903bf.png)

Photo by [Aleksi Räisä](https://unsplash.com/@denarium_bitcoin?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

# **简介**

理解时间序列数据对任何类型的业务都非常重要。如果你与数字和分析打交道,通常情况下,你需要解决一些问题,比如未来几个季度有多少客户会继续购买,我们应该在股票上投资多少以防止缺货问题,明年的销售额是多少等等。或者你只是一个普通人,试图投资一些股票来赚取额外收入,了解并能够预测股票价格是非常必要的。这些都是预测问题,需要对时间序列数据有一定的技术理解和知识。

理解数据已经很难了,知道使用什么工具来生成高质量的预测图就更难了。许多预测模型需要强大的数据科学技术知识和技能。这些模型基于许多复杂的假设,即使是数据科学家也很难找到最好的模型来使用。

这就是为什么脸书发布了一个名为 Prophet 的惊人的预测模型,这是一个有 Python 和 r 两种版本的预测包。这是一个非常容易使用的包,不需要有很多技术背景。

***来自《走向数据科学》编辑的提示:*** *虽然我们允许独立作者根据我们的* [*规则和指导方针*](/questions-96667b06af5) *发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的* [*读者术语*](/readers-terms-b5d780a700a4) **

# **我写这篇文章的原因**

Prophet 并不是一个新工具,我很确定有很多人已经熟悉它了。网上还有许多资源,您可以从中找到如何使用该预测模型的分步说明。但是,我个人认为,那些资源还不够简单,不足以让很多人理解模型。所以我写这篇文章是因为我想让一个 ***非统计专业的学生也能轻松地做预测,而不必纠结于任何技术知识。***

在本文中,我将提供一个使用 Prophet in R 预测比特币价格的分步方法。我还将尽力将其作为一个模板,这意味着你也可以使用它来预测其他事情,如要购买的产品数量、航班数量、注册的学生数量等。我会尽量用非专业术语*来解释一切,让它尽可能简单。*

*我们开始吧!*

# ***导入并清除数据***

*我从[这里](https://www.investing.com/crypto/bitcoin/historical-data)取了历史数据。然后,您可以更改时间段和时间范围来获得您喜欢的数据集。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d1f8f1334c9c1b35142bfc675f1d7720.png)*

*在进行预测时,我们需要选择训练数据(来训练预测模型)和测试数据(在此基础上,预测模型将用于查看准确性)。为了方便大家,我没有实现代码将数据集分为训练集和测试集,而是简单地选择了 2017 年 7 月 25 日至 2019 年 7 月 25 日的时间段,然后下载。(耶!!!太简单了,每个人都能做到:))*

*下载的文件是一个 csv 文件。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a3a4d082b9a8ff52c1e7c52fac208e29.png)*

*Original data*

*下载后,让我们快速清理它,只保留那些我们感兴趣的组件,即日期和价格(前 2 列)。我们需要将日期列更改为日期数据类型。只需选择整个列(在 Excel 上)并将类型从 General 更改为 Date。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/85a5c10ce84d0f889ba041afe6cc2508.png)*

*太好了!现在数据已经准备好导入 r。*

# ***在 R 中实现先知***

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b65bb45ed280c5497e7a1b423548f6a0.png)*

*为了使这两列易于操作,我将这两列分别重命名为“ds”和“y”。然后我取 y 列的对数。在 R 中,在日期列中,数据将作为字符读取,所以我们需要使用库 Lubridate 将它们改为日期类型。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/53f4ec3f182a66634f0677daf1603cde.png)*

*然后我绘制了图表,看看数据是什么样的*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/953ec8b3af8665773df868ec0f1fcf84.png)*

*厉害!让我们开始使用 Prophet 进行预测。以下是代码:*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b0182c33c342254d3926159941eade00.png)*

*我不想使用 Prophet 函数的默认季节性效果,因为我意识到比特币数据略有不同。所以我把所有的年、周、日的季节性效应都设为‘假’,然后创造自己对数据季节性效应的理解。通过这样做,我可以更好地控制季节性。这很重要!我给你的建议是 ***不要盲目使用该函数,你需要回去查看你的数据并检查*。如果我们能够定制最适合模型工作的季节效应,我们就可以更准确地进行预测。***

*让我解释一下代码。*

*如果你将周期设置为,比如说,30 天,那么你实际上是在告诉模型,在某一点发生的事情很可能在 30 天内再次发生。在我的代码中,对于“每月”季节性,我选择周期为“30 * 1.8”。这基本上意味着模式/趋势可能在 30 * 1.8 = 54 天后重复。*

*你可能会问我是怎么知道这些数字的。如我之前所说,这一切都是为了理解您的数据。在这里,我定义一个月有 30 天,模式/趋势可能在 1.8 个月后重复。为了得到这个数字,我回到我之前绘制的图表来看总体趋势。我也回到了[网站](https://www.investing.com/charts/cryptocurrency-charts)上提供的现场图。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/0727c56448ba24d7c4c2f79efa299ebb.png)*

*让我们来看看这个特定的时间段。如你所见,当我们放大时,似乎有一种模式每两个月出现一次。我在这段时间的其他部分做了同样的事情。我意识到,平均而言,1.8 个月对于月度季节性来说是个不错的数字。同样的技巧也适用于年季节性和日季节性。对于每年,我定义一年有 365.25 天(实际上 364 ~ 366 天是一个很好的范围,但我测试了一下,发现 365.25 天最符合历史数据);这种模式似乎会在 1.5 年后重复。你可以通过查看历史数据的图表来做同样的事情,找出关键的转折点,看看整体模式是如何随时间变化的。这将允许您输入最合适的季节性,以给出最准确的预测模型。*

*接下来是傅立叶分量。在数学上,任何信号都可以用正弦和余弦曲线的和来表示。这就是 Prophet 产生季节性信号的方式。数字越大,显示的曲线越多。有时候,使用一个大的数字是好的,因为我们想要捕捉趋势中的每一个转折点。然而,较大的傅立叶阶可能导致称为 ***过拟合*** 的问题。因此,最好在训练集上尝试一个傅立叶级数范围,看看哪个数最符合数据。*

*现在我们已经重新定义了先知函数。是时候实施了,做个预测。只需遵循以下代码:*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ad5ce683507bf5c3f510586f657ab10d.png)*

*future = make_future_dataframe(m,periods = 40)*

*这里,“周期”代表您希望预测的未来天数。由于我们的训练数据截止到 2019 年 7 月 25 日,我们希望了解该模型是否能很好地预测 2019 年 7 月 25 日至 8 月底的数据。所以,我把期限定为 40 天。下面是获得的图:*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ea8c04445e541181efeb8f33ef700be1.png)*

*从图表中,模型预测从 7 月 25 日到 7 月底,比特币价格将下降,然后在 8 月份再次上升。这与真实数据非常相似*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/134bdca0e8f4f6a8cf195b2a269757d8.png)*

*也可以把周期改为 90 天,预测未来 3 个月的比特币价格。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6c0f5e2b698b2c5b30ddf3d3618164fa.png)*

*9 月份比特币价格预测在 exp(9.2)= 9897**(记得 y 轴是对数刻度)**左右。10 月份预测为 exp(9.15)= 9400,11 月份上升到 10900。*

*就是这样!希望它能给你们,特别是那些没有统计和编程背景的人一个如何做预测的想法。Prophet 是一个强大的时间序列预测模型,易于每个人使用。如果您很好地了解您的数据并相应地调整模型的参数,您可以极大地提高模型的性能并获得相当准确的预测结果。但是,同样重要的是要知道,模型只是模型,尤其是在预测未来的事情时,模型是基于历史数据和历史模式执行的。所以预测结果永远不会 100%准确。然而,正如我所说的,如果你训练好模型,你可以得到一个相当准确和可靠的结果,如果没有一个可靠的模式和趋势供你做分析。*

*谢谢你的时间。我期待着关于您如何实施和优化您的模型的讨论/反馈。如果有任何问题,请告诉我*

*查看我关于随机森林[的最新帖子](https://medium.com/@hoangkhangtran99/implement-random-forest-in-r-b00b69eb8501)*

# 使用 fastai 实现 SPADE

> 原文:<https://towardsdatascience.com/implementing-spade-using-fastai-6ad86b94030a?source=collection_archive---------4----------------------->

## 使用 GANs 生成照片级逼真图像

Nvidia 最新研究论文出来的时候我就被它的结果迷住了。如果你没有看过[论文](https://arxiv.org/abs/1903.07291)结果,那么你就错过了。此外,看看在 GIF 中基于 GAN 的铲动作。我等不及正式实现发布,决定使用我们最喜欢的 fastai 库自己实现这篇论文。fastai 提供了一个非常简洁的 API,可以用来开发高度可定制的模型。具体来说,它的数据块和回调 API 是令人兴奋的。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4ee66048b415ab9085a263a84a509ddc.png)

Source: [https://nvlabs.github.io/SPADE/](https://nvlabs.github.io/SPADE/)

这篇论文是一个非常简单的想法,据报道,它使用语义地图作为 GAN 模型的输入,在照片级真实感图像合成任务上提供了巨大的性能提升。今天我要一点一点地实现它。

如果您一直关注这篇博客,您将会了解 fastai 和 PyTorch,以及如何实现新的架构和使用新的数据集。

# SPADE 是什么?

SPADE 代表空间自适应归一化,它只是一种归一化技术,如批量范数、实例范数等。它在 GANs 中用于从**分割蒙版**生成合成的**照片级逼真图像**。本文在生成器的所有层中使用这种规范化技术。SPADE 的想法是,他们使用语义图来计算那些仿射参数,而不是学习批范数层中的仿射参数。困惑什么是仿射参数?

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/243e03f2c0856f89f16422db7fd94ede.png)

Source: [https://arxiv.org/abs/1502.03167](https://arxiv.org/abs/1502.03167)

这是来自批量标准纸的图像。那些小伽玛和贝塔是仿射参数。这些参数是可以学习的,让模型可以自由选择他们想要的任何分布。因此,SPADE 说为什么不使用语义图来分别计算那些被称为缩放和移位参数的γ和β。

SPADE 将利用语义图来计算这些参数,而不是使用随机初始化的缩放和移动参数,就是这样!他们这样做是因为传统的规范化层洗掉了输入语义掩码中的信息。SPADE 有助于在整个网络中有效地传播语义信息。下面是一个建筑的铲块。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/edaa3c8619cbf3acefdf4cec652852c9.png)

Source: [https://arxiv.org/abs/1903.07291](https://arxiv.org/abs/1903.07291)

现在,我所说的一切都开始有意义了。仍然执行传统的归一化,只是仿射参数不同。基本上,它们只是应用在输入语义图上的几个卷积。我真的很感谢 NVIDIA AI 的研究人员让这篇论文变得如此可视化。所以现在让我们开始编写代码。

# 纸面实现

我将在这里展示的所有代码都来自我的 [Github 仓库](https://github.com/divyanshj16/spade)。我将向您展示在[这个笔记本](https://github.com/divyanshj16/SPADE/blob/master/SPADE-without-feature-matching-loss.ipynb)中实现的具有更少功能的 SPADE paper 版本,但我已经在其他笔记本中实现了其他添加功能。由于它是一个 GAN,它将有一个发生器模块和一个鉴别器模块。生成器模块包含铲层。因此,我们将首先从实现基本的 SPADE 块开始。

## 铲形块

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a5753ca0462d6603d7a8ffec07791ef8.png)

Source: [https://arxiv.org/abs/1903.07291](https://arxiv.org/abs/1903.07291)

这张图片只是早期图片的更详细的版本。它准确地告诉我们在语义图上要执行哪些卷积。

它接受分段掩码和特征。分段掩码只是简单的长整数 2D 掩码,本文建议对类使用嵌入层,但我决定简化,因此输入滤波器的第一卷积层数是 1。然后,它会根据特征的大小调整遮罩的大小。这样做是因为 SPADE 图层将在每个图层上使用,所以它需要知道要素的大小,以便可以针对仿射参数的操作调整掩膜的大小。看看当我初始化 BatchNorm2d 图层时,我将仿射设置为 false,以不使用默认的仿射参数。在本文的所有卷积块中使用频谱归一化来稳定 GAN 训练。在 PyTorch 中,通过继承 *nn 实现了一个新的层。模块"*,并通过实现" *__init__"* 、"*" forward "*函数。变量名 *ni* 和 *nf* 分别用于卷积层中输入滤波器的数量和输出滤波器的数量。

## 铲状残余块

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/11784e1c1555cd5f17e9023ef359925d.png)

Source: [https://arxiv.org/abs/1903.07291](https://arxiv.org/abs/1903.07291)

在实现了 SPADE 块之后,我们现在可以在 SPADE ResBlk 中使用它了,而且非常简单。

## 发电机

现在,我们已经有了基本的模块设置,现在是将它们堆叠起来的时候了,如下面的架构所示。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9737f247a3ecab03129e6064c91d1170.png)

Source: [https://arxiv.org/abs/1903.07291](https://arxiv.org/abs/1903.07291)

我列出了各个图层将丢弃的特征地图的数量,并使用 for 循环创建了生成器。

为了使代码简单,我使用了一些技巧,比如用全局变量初始化模块的参数。你可以看到 *nfs* 变量包含所有 SPADE 残差块的输出,这些块用于初始化生成器中的层。最后,我将 *tanh* 层的输出设置在 0-1 的范围内,这样更容易可视化。

## 鉴别器

该鉴别器是一种基于多尺度、贴片 Gan 的鉴别器。多尺度意味着它在不同的尺度上对给定的图像进行分类。基于贴片 Gan 的鉴别器最后的输出层是卷积的,并且取空间平均值。多重标度的输出相加得到最终输出。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a2a2b1795fb5e02c0ebeb89079273b03.png)

Source: [https://arxiv.org/abs/1903.07291](https://arxiv.org/abs/1903.07291)

鉴别器同时获取掩模和生成的/真实的图像,并输出激活。从代码中可以看出,鉴别器中的 forward 方法将 mask 和 image 作为输入。

现在我们已经实现了模型的完整架构。完整的架构是这样的。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9d22e4f5b9b67790689c60c2a541451a.png)

Source: [https://arxiv.org/abs/1903.07291](https://arxiv.org/abs/1903.07291)

现在是实现损失函数的时候了。

## 损失函数

因为是 gan,所以有两个损耗函数,一个用于发生器,另一个用于鉴频器。损失函数是我在之前的博客中提到的萨根论文中的铰链损失。损失函数非常简单,实际上只有一行代码。但是,这是我花了最多时间并意识到损失函数在深度学习问题中有多重要的部分。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5ab9e3102a7375b95014b77430cdacca.png)

Source: Self-Attention GAN paper

以上两个等式可以在下面的代码块中用代码编写。有时这些看起来可怕的方程只是一行代码。

这里我们用代码实现了这篇论文,但是我们还需要做更多的事情。首先,我们需要将数据传递给模型,并对数据进行预处理,还需要一个训练循环来训练我们的模型。数据准备这一步以前经常困扰着我,但在 fastai 版本 1 发布之后就没有了。它让很多事情变得非常简单快捷。

## 数据准备

我使用了由[切萨皮克保护区土地覆盖数据项目](https://chesapeakeconservancy.org/conservation-innovation-center/high-resolution-data/land-cover-data-project/)提供的土地覆盖分类数据。我使用 ArcGIS Pro 的“导出深度学习的训练数据”工具从分类栅格中提取了的所有图像。一旦我在磁盘上获得了图像,我就使用 fastai 数据块 API 来加载它们,以创建一个 fastai 学习器并调用它的 fit 方法。在创建了适当的类之后,我使用下面的代码创建了一个 fastai databunch 对象。

我创建的类是 SpadeItemList,它只是 fastai 的 SegmentaionItemList 颠倒了。fastai 所做的是,你可以创建一个从 fastai 项目或标签类继承的类,并根据你的需要覆盖几个方法,它将使用该类创建 databunch 对象。Databunch 对象包含包含 PyTorch 数据集和数据加载器的属性。它包含一个显示你的数据的方法,叫做 *show_batch。*这里是我的 *show_batch* 的输出。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7acacb75dfcb0dd4feb67ae7c1374e03.png)

现在,数据准备步骤已经完成,所以现在必须训练模型。

## 让我们训练它。

在 fastai 中,我们必须创建一个学习器,其中包含实际训练模型的方法 fit。但这不是像图像分类那样简单的模型,在 GAN 中,我们需要将模型从生成器切换到鉴别器,反之亦然。要使用 fastai 库,我们需要创建回调机制来完成这项工作。我复制了 fastai library 的 GANLearner,并做了一点修改。

*self.gen_mode* 告诉 GANModule 何时使用发生器,何时使用鉴别器。fastai 中实现了一个回调函数,它以固定的时间间隔切换 GAN。对于每个发生器步骤,我将鉴别器步骤设置为五次。这是使用 FixedGANSwitcher 完成的。

还使用了其他回调函数。请看[我的 Github 库](https://github.com/divyanshj16/SPADE)里的代码。

现在我们可以运行*拟合*方法来训练模型。

## 结果

结果并不真实,但如果有足够的时间和计算,并消除任何存在的错误,将使模型生成良好的图像。下面是模型生成的初始图像。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/db4b6ec45363f5a912186751d414203f.png)

经过 100 次的训练。它开始产生一些详细的图像,但带有一些伪像。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6d9ea4ea369b83a75d3d1b55835c5f7d.png)

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

Spade 只是一个标准化层,有助于生成逼真的图像。我在这里实现了:[https://github.com/divyanshj16/SPADE](https://github.com/divyanshj16/SPADE)

> 如果你坚持到这里,我希望你会喜欢。如有任何疑问,您可以通过推特[联系我。在 GitHub 上跟随我,因为我将实现更多的文件。我是这篇论文实现业务的新手,所以请指出你可能在我的代码和博客中发现的任何错误。干杯!](https://twitter.com/divyanshjha)

# 通过使用气流在数据加载过程中实现功能数据工程范例

> 原文:<https://towardsdatascience.com/implementing-the-functional-data-engineering-paradigm-in-data-load-processes-by-using-airflow-61d3bae486b0?source=collection_archive---------13----------------------->

## [用气流概括数据加载过程](/generalizing-data-load-processes-with-airflow-a4931788a61f)

## 基于纯任务的方法

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b8706a92412855a5f596b6879375fca9.png)

Photo by [Max Duzij](https://unsplash.com/@max_duz?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

我们在一个包含四十多个应用程序的项目中集成了几个数据源。通过执行批处理来集成这些源,从而允许将数据从内部数据库增量加载到 AWS S3。我们使用 Airflow 作为我们的数据管道编排器,以便轻松地编排和监控此类流程。

在我们体验气流的早期,我们开始构建 Dag,允许我们集成数据源。然而,当重新处理数据源和执行回填过程时,开始出现一些问题。特别是,其中一些是:

*   **流程逻辑过于复杂**。它的设计方式产生了不必要的依赖。流程逻辑没有被恰当地分解成更小的任务。因此,测试和调试被认为是复杂的任务。
*   **大量重复的代码。**我们在 Dag 之间复制了大量代码。这可以用数据提取的内在本质来解释,*例如*,从两个不同的 MySQL 数据库中提取数据的代码通常不会有太大的不同——事实上,数据库连接是代码中大多数时间唯一变化的东西。因此,更改代码被认为是耗时的,因为相同的更改必须在几个 Dag 中传播。
*   **流程不易重现**。根据执行的时间点,流程会返回不同的结果。即使给定了相同的一组参数。因此,从过去执行的过程中复制结果并不容易。尤其是在重新处理数据源和执行回填操作时。

在这一点上,我们意识到我们做错了……经过一段时间的研究,我们发现了由 Maxime Beauchemin 在这篇文章中提出的功能数据工程范例。这种范式允许我们重新定义设计过程的方式。这对我们来说不容易。这就是为什么我们想与你分享我们实现功能数据工程范例的第一个方法。特别是它在数据加载过程中的实现。

# 功能数据工程

功能数据工程范式是基于定义基于 ***纯任务*** 的数据流程。根据 [Maxime Beauchemin](https://medium.com/u/9f4d525c99e2?source=post_page-----61d3bae486b0--------------------------------) :

> “一个纯任务应该是 [**确定性的**](https://en.wikipedia.org/wiki/Deterministic_algorithm) 和 [**幂等的**](https://en.wikipedia.org/wiki/Idempotence) ,意味着它每次运行或重新运行都会产生相同的结果”

特别是,Maxime Beauchemin[提出的三件事,我们认为对实现这种范例至关重要:](https://medium.com/u/9f4d525c99e2?source=post_page-----61d3bae486b0--------------------------------)

*   **上下文无关**。纯函数应该只依赖于它们的上下文,*即*它们的参数。特别是,我们认为上下文无关性可以通过遵循[关注点分离](https://en.wikipedia.org/wiki/Separation_of_concerns)原则来实现。这样的原则可以定义为"*将一个【过程】分解成功能上尽可能少重叠的不同特征的行为。*“所以,”*它们可以单独编写、测试、推理和调试,而不需要理解外部环境或围绕其执行的事件历史*。”
*   **覆盖方法。**在一的纯功能中,任何类型的副作用都应该避免。"*我们需要确定性***重新运行任务是安全的,不会导致重复计算或任何其他形式的不良状态…使用相同的输入参数重新执行一个纯任务应该会覆盖先前运行同一任务时可能会遗漏的任何先前输出。**
*   ***不可变的暂存区。一个有趣的模式是将分区视为不可变的对象,它们是纯任务的输出。它们可以被认为是不可变的临时区域的构建块。通过实施这种方法,即使在暴露的对象实际上是可变的情况下,也有可能使用功能实践。“因此,*给定一个持久不变的暂存区和纯任务,理论上可以从头开始重新计算整个仓库的状态(这不是你应该做的),并通过重新执行过去运行的数据加载流程来获得完全相同的状态*。***

# *功能数据加载*

*我们通过使用一组模式实现了上述原则,这些模式允许我们创建一个[框架](/generalizing-data-load-processes-with-airflow-a4931788a61f),用于提取数据并将其加载到我们的数据仓库中。为了简单起见,这样一个[框架](/generalizing-data-load-processes-with-airflow-a4931788a61f)不在本文讨论范围之内。相反,我们深入研究我们用来构建它的模式。这种模式被称为*装载模式。*这种模式是我们概括数据加载过程的方式。*

**加载器模式*基于这样一个概念,即将数据加载到数据湖或数据仓库——在我们的例子中是 AWS S3——只需提供一些与数据源和数据存储位置相关的信息。相应地,该模式的每个实例根据其目标数据库引擎实现一些功能,例如,加载程序连接到数据库的方式或提取数据的方式,以便实现这样的愿景。*

*下面是一个使用 *MySQL 加载器*的 DAG 示例。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/eab1879f3f3e06a3ef9d59ed1ac48e71.png)*

*Example DAG*

*DAG 的设计方式是,在每个任务中,通过运行 [*MySQL 加载器*](https://github.com/ajhenaor/pyspark-mysql-to-s3-loader) 加载一个数据库表。*装载器*在一个由气流编排的码头集装箱上运行——我们使用一个 [*码头操作员*](https://airflow.apache.org/docs/stable/_api/airflow/operators/docker_operator/index.html) 来完成*。**

*在下一段代码中, *MySQL 加载器*出现在*中。基本上,我们提取数据并加载到 S3 自动气象站。在此过程中,我们通过使*加载器*起作用、**起作用、通过实现上下文无关性、确保覆盖方法以及产生不可变对象作为加载器的输出来确保满足上述功能原则。**

*这是上周 S3 自动气象站的结果。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/19cba825412ba42650ce8d6ee61dc667.png)*

# *结论*

*最后,关于*装载机需要记住的一些事情:**

*   *通过确保给定相同的参数,*加载器*每次运行时都会产生相同的结果,从而满足确定性和幂等性。*
*   *覆盖方法的实现方式是,我们可以确保每次*加载程序*运行时,它都会覆盖先前运行时可能遗漏的任何先前输出——要查看它在 *MySQL 加载程序中的实现,请参见第 66 行。**
*   *不可变分区由*加载器*的输出表示。由于我们的需要,我们使用每日分区。*
*   *加载器模式可以扩展到任何类型的数据库源——例如、Oracle、PostgreSQL 等等——在这篇文章中,我们展示了 *MySQL 加载器*来举例说明它的实现。*

*我希望这些信息对你有用。*

*感谢阅读到最后。*

*下期帖子再见!*

**如果你想随时更新我的作品,* ***请加入我的*** [***简讯***](https://metadatacommunity.substack.com/) ***!*** *我会努力为你提供信息和资源,让你成为更好的数据从业者!**

# 用 Pytorch 中的 2 行代码实现最新的 Mish 激活

> 原文:<https://towardsdatascience.com/implementing-the-new-state-of-the-art-mish-activation-with-2-lines-of-code-in-pytorch-e7ef438a5ee7?source=collection_archive---------19----------------------->

## 最先进的深度学习从未如此简单

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6d015f042df7d3a9acd8451ed89f440c.png)

From [Pexels](https://www.pexels.com/photo/action-blur-bulb-dark-355904/)

[本文](https://arxiv.org/pdf/1908.08681.pdf)作者[迪甘塔·米斯拉](https://medium.com/u/b7a37456ed33?source=post_page-----e7ef438a5ee7--------------------------------)最近发表了一个关于深度学习的新激活函数,叫做 mish activation。当在 CIFAR-100 上使用 Squeeze Excite Net-18 进行测试时,这种新的激活功能击败了 ReLU 和 swish 激活功能。如果你想知道关于研究和激活功能的细节,我强烈推荐你去阅读我上面链接的论文。我不打算深入研究论文的数学和研究,但函数看起来是这样的。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/86404ca7a35ea2c800476b5603d17f01.png)

[Mish Activation Function from Paper](https://arxiv.org/ftp/arxiv/papers/1908/1908.08681.pdf)

如果你熟悉激活功能,你可能会认为它看起来很像 swish 激活。这是因为 mish 受到了 swish 的启发。从论文的初步阅读来看,似乎 mish 可能比 swish 和非常受欢迎的 ReLU 激活都要好。这个全新的激活功能最棒的地方是你可以用 2 行代码实现它。

# 履行

## 定制网络

首先,我将向您展示如何在您自己构建的神经网络中实现 mish。在构建我们的网络之前,我们需要使用 PyTorch 编写 mish 函数。正如承诺的那样,它只需要 2 行代码。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1eb03032d384080e3e9e0816fb089183.png)

用这两行代码,我们写了一个最先进的激活函数。所以现在让我们编写一个基本的 CNN,并在其中实现我们的激活功能。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/dd71b31f1650ea7ce311f74783f4f938.png)

在前面的部分,我将所有线性层的激活函数设置为我们上面写的 mish 激活。现在模型可以训练了。这是非常直接和容易实现的!我在 Kaggle 的空中仙人掌识别数据上运行了这个模型,并在 10 个训练时期后看到了比 ReLU 激活 1.5%的准确性增加。我不会抱怨那件事。

## 迁移学习

建立自己的神经网络很酷,但几乎不实用。当涉及到在深度学习中获得顶级结果时,迁移学习往往更有效。因此,让我们看看如何用 VGG-16 实现 mish 激活。我们需要为我们的 mish 激活写一个从 torch.nn.Module 类继承的类,而不是一个函数。它应该是这样的:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/35baa51ed293b429105d40b5933fd4f2.png)

我很抱歉,我答应 2 行代码,现在我把它改为 5。我希望在你用了这个并看到它有多酷之后,你会原谅我。把我们的激活函数写成一个类,我们现在可以准备把它添加到我们的 VGG-16 模型中。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6f82dabede21664c3fcf0246bdfa298e.png)

我们将 VGG-16 的分类部分中的 ReLU 激活改为 mish 激活,并用一个用于我们的分类问题的层替换最后一层。除去最后一层的渐变后,我们就可以开始训练了!有了这些小代码,你就实现了一个最先进的激活功能。

# 一些提示

如果你想实现它,我认为在 mish 的文章中提到的一些事情是值得注意的:

*   与其他激活函数相比,mish 函数在较低的学习速率下表现更好。所以一定不要去 high。
*   Mish 激活似乎对超参数的变化相当稳健。查看报纸,了解更多这方面的信息。
*   没有最佳激活函数。这不会总是比其他任何事情都好。不过这绝对值得一试。

如果你有兴趣看我的完整代码,我把它放在 Kaggle [这里](https://www.kaggle.com/nelsongriffiths/mish-activation-and-transfer-learning-pytorch)。随意克隆它,尝试不同的架构,或者将 mish 激活应用到卷积层。

# 用神经网络反向传播实现异或门

> 原文:<https://towardsdatascience.com/implementing-the-xor-gate-using-backpropagation-in-neural-networks-c1f255b4f20d?source=collection_archive---------1----------------------->

使用神经网络实现逻辑门有助于理解神经网络处理其输入以达到特定输出的数学计算。这个神经网络将处理 XOR 逻辑问题。XOR(异或门)是一种数字逻辑门,只有当它的两个输入彼此不同时,它才给出真输出。XOR 门的真值表如下所示:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5cc282e7515c2fd4f8124fcbbb2e9adc.png)

Truth Table for XOR

神经网络的目标是根据上述真值表对输入模式进行分类。如果输入模式是根据它们的输出绘制的,可以看出这些点不是线性可分的。因此,必须对神经网络进行建模,以使用*决策平面来分离这些输入模式。*

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/425638b0f47d02488419ae23808f423f.png)

XOR, Graphically

# 神经网络模型

如前所述,神经网络需要产生两个不同的决策平面,以根据输出模式线性分离输入数据。这是通过使用*隐藏层*的概念实现的。神经网络将由一个具有两个节点(X1,X2)的输入层组成;一个具有两个节点的隐藏层(因为需要两个决策平面);和一个具有一个节点(Y)的输出层。因此,神经网络看起来像这样:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/16af1c7f074731c87717cf4ce72b70f8.png)

The Neural Network Model to solve the XOR Logic (from: [https://stopsmokingaids.me/](https://stopsmokingaids.me/))

# 乙状结肠神经元

为了实现 XOR 门,我将使用一个 Sigmoid 神经元作为神经网络中的节点。乙状结肠神经元的特征是:

1.可以接受实值作为输入。

2.激活值等于其输入的加权和
,即∑wi xi

3.乙状结肠神经元的输出是乙状结肠函数的函数,也称为逻辑回归函数。sigmoid 函数是一个连续函数,它输出 0 到 1 之间的值:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/baaa859595038034a48477d434f39456.png)

The Sigmoidal Curve

# 学习算法

神经网络的信息存储在神经元之间的互连中,即权重中。神经网络通过根据帮助其收敛到预期输出的学习算法更新其权重来进行学习。学习算法是基于损失函数改变权重和偏差的原理方法。

1.  随机初始化权重和偏差。
2.  迭代数据
    i。使用 sigmoid 函数
    ii 计算预测输出。使用平方误差损失函数
    iii 计算损失。W(新)= W(旧)—α∏W
    iv。B(新)= B(旧)—αB
3.  重复直到误差最小

这是一个相当简单的学习算法,仅包含算术运算来更新权重和偏差。该算法可分为两部分:前向传递*和后向传递*也称为*“反向传播”***

让我们实现算法的第一部分。我们将根据 XOR 的真值表初始化我们的权重和预期输出。

inputs = np.array([[0,0],[0,1],[1,0],[1,1]])
expected_output = np.array([[0],[1],[1],[0]])


步骤 1:用随机值初始化权重和偏差

import numpy as npinputLayerNeurons, hiddenLayerNeurons, outputLayerNeurons = 2,2,1hidden_weights = np.random.uniform(size=(inputLayerNeurons,hiddenLayerNeurons))
hidden_bias =np.random.uniform(size=(1,hiddenLayerNeurons))output_weights = np.random.uniform(size=(hiddenLayerNeurons,outputLayerNeurons))
output_bias = np.random.uniform(size=(1,outputLayerNeurons))


正向传递包括计算预测输出,该输出是给予神经元的输入的加权和的函数:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/00a54104b165597502d5feb2e6f2d065.png)

The Sigmoid Function

其中σwx+b 称为激活。

def sigmoid (x):
return 1/(1 + np.exp(-x))hidden_layer_activation = np.dot(inputs,hidden_weights)
hidden_layer_activation += hidden_bias
hidden_layer_output = sigmoid(hidden_layer_activation)output_layer_activation = np.dot(hidden_layer_output,output_weights)
output_layer_activation += output_bias
predicted_output = sigmoid(output_layer_activation)


这就完成了一次正向传递,其中需要将我们的预测输出与预期输出进行比较。基于这种比较,使用反向传播来改变隐藏层和输出层的权重。反向传播是使用梯度下降算法完成的。

# 梯度下降

乙状结肠神经元的损失函数是平方误差损失。如果我们绘制损失/误差与重量的关系图,我们会得到如下结果:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/641410d1d2244f3a01c9a68d5bf8c25d.png)

Error/Loss vs Weights Graph

我们的目标是找到对应于误差最小的点的权重向量,即误差梯度的最小值。这就是微积分发挥作用的地方。

# 梯度下降背后的数学

误差可以简单地写成预测结果和实际结果之间的差异。数学上:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/87037ed9c0353bc4ae3d3449c176d933.png)

其中 *t* 是目标/预期输出& *y* 是预测输出

然而,为相同的误差量分配不同的误差值公平吗?例如,1 和 0 以及 1 和 0 之间的绝对差值是相同的,但是上面的公式会对预测-1 的结果产生负面影响。为了解决这个问题,我们使用平方误差损失。(注意没有使用模数,因为它使区分变得更加困难)。此外,这个误差被除以 2,以便更容易区分,我们将在下面的步骤中看到。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1ac51c60aea18e7ce831d58d0d1bfde3.png)

Squared Error Loss

由于可能有许多重量会导致这一误差,我们每次对每个重量进行偏导数,以找出最小误差。对于输出层权重(W31 和 W32)和隐藏层权重(W11,W12,W21,W22),权重的变化是不同的。
设外层权重为 wo,隐含层权重为 wh。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a8a6a49f4ab46310d964c62c8fa884d3.png)

我们将首先找到外层权重的 W。由于结果是激活的函数,并且进一步的激活是权重的函数,因此根据链式法则:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/38ec0f85324e8812ed1316cb387f4264.png)

在解决问题时,

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9f90cea1ce3028cf01186dafe4766744.png)

Change in the outer layer weights

注意,对于 Xo 来说,它只不过是隐藏层节点的输出。
隐藏层节点的输出也是激活的函数,并且相应地是权重的函数。因此,链式法则针对隐藏层权重进行扩展:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/afad0eafa470816a3bac59f4a6cdf6f2.png)

也就是说,

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/935284dca54c07202eaf4422f4be2c4a.png)

Change in the hidden layer weights

> 注意:Xo 也可以被认为是 Yh,即隐藏层的输出是输出层的输入。Xh 是隐藏层的输入,它是真值表中的实际输入模式。

然后让我们实现向后传递。

def sigmoid_derivative(x):
return x * (1 - x)#Backpropagation
error = expected_output - predicted_output
d_predicted_output = error * sigmoid_derivative(predicted_output)

error_hidden_layer = d_predicted_output.dot(output_weights.T)
d_hidden_layer = error_hidden_layer * sigmoid_derivative(hidden_layer_output)#Updating Weights and Biases
output_weights += hidden_layer_output.T.dot(d_predicted_output) * lr
output_bias += np.sum(d_predicted_output,axis=0,keepdims=True) * lr
hidden_weights += inputs.T.dot(d_hidden_layer) * lr
hidden_bias += np.sum(d_hidden_layer,axis=0,keepdims=True) * lr


重复这个过程,直到预测输出收敛到预期输出。将该过程重复一定次数(迭代次数/时期)比设置预期收敛程度的阈值更容易。

# PYTHON 实现

选择历元的数量和学习率的值决定了两件事:模型的精确度,以及模型计算最终输出的速度。*超参数调优*的概念本身就是一个完整的课题。
历元= 10000,学习率= 0.1 的输出为:

Output from neural network after 10,000 epochs:
[0.05770383] [0.9470198] [0.9469948] [0.05712647]


因此,神经网络已经收敛到预期输出:
【0】【1】【1】【0】。历元与误差图显示了误差是如何最小化的。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ce37c1ce3648dd57a71a8b8ad2432648.png)

# 资源

1.  凯文·格尼的神经网络导论
2.  [https://www . analyticsvidhya . com/blog/2017/05/neural-network-from-scratch-in-python-and-r/](https://www.analyticsvidhya.com/blog/2017/05/neural-network-from-scratch-in-python-and-r/)
3.  感谢[https://www.codecogs.com/latex/eqneditor.php](https://www.codecogs.com/latex/eqneditor.php)将 LaTeX 方程转换成本文使用的 png。

我希望听到任何反馈/建议!这里和我[连线。](https://www.linkedin.com/in/siddharthapratimdutta/)

# 实施时间序列 ARIMA

> 原文:<https://towardsdatascience.com/implementing-time-series-arima-38fd77fc1d79?source=collection_archive---------16----------------------->

我们听说过很多时间序列分析中基于 ARIMA 的模型,这是一种用于预测各种时间序列数据的流行工具。也就是说,不建议在不了解数据及其潜在趋势的情况下盲目使用 ARIMA 模型。

本文讨论 ARIMA 及其一般应用。ARIMA 是非季节性的,萨里玛具有季节性。SARIMA 扩展了 ARIMA 模型的适用性:它在建模和预测中包括了数据的季节性。但是等等,什么是 ARIMA 呢?

**ARIMA 阿玛简介:**

当数据已经稳定时,使用 ARMA(即自回归移动平均模型)。

当数据不稳定且具有趋势成分时,使用 ARIMA(即,与移动平均模型集成的自回归)。因为有一个差分组件(d)将数据转换为静态数据,然后应用其他顺序。(p,q)

p:自动回归项的阶数(时间步长滞后的数量)

问:移动平均项的顺序

d:获得平稳性的差分阶

本文不包括应用每种方法的统计描述;它只是涵盖了我们如何在 python 中应用 ARIMA 和萨里玛模型,并对其有一个大致的了解。因此,让我们一步一步地将这些模型与我们的数据相匹配。

**分步骤实施 ARIMA 的一般方法:**

**第一步**:加载数据集,绘制源数据。(检查数据是否有任何季节性模式、周期性模式、一般趋势)

*   处理缺失值:ARIMA 模型不适用于有 NAs 的数据。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/431d8adf6dd097b25329ba93360eb672.png)

Plotting the data*

**步骤 2** :应用扩展的 Dickey Fuller 检验(以确认数据的平稳性)

实现:adfuller()

*   如果数据是平稳的,则进行 ARMA 或 ARIMA。(这是你的选择!)
*   如果数据不是稳定的,继续 ARIMA。(因为,需要对数据进行差分以使其稳定:ARIMA 的“I”组件就是这样做的)

**步骤 3** :对数据进行 ETS 分解(检查数据的季节性)

实现:季节性分解()

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d6b557d2902209594d0a2b58ee8a1e36.png)

Seasonal Decomposition components

*   如果季节性与趋势成分相比很小,我们就不需要考虑它。在这种情况下,我们可以采用非季节性 ARIMA 模型。例如,在上面的示例图中,与趋势成分范围相比,季节性范围非常小。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ca0d04a232ecd39900d8b2920de1f872.png)

ACF Plot

ACF -可用于确定毫安顺序(q)。

PACF -可用于确定 AR 顺序(p)。

*   同样,如果数据中的季节性很明显,则使用季节性 ARIMA 或萨里玛。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c5f9c72c561610943c1ff22a9aa81405.png)

PACF plot

上述 ACF 和 PACF 图解释如下:ACF-MA 的顺序取为“1”,因为只有第 1 点(实际上是第 0 点和第 1 点)位于 95%置信区间(阴影区域)之外。PACF-AR 的顺序取为“1 ”,因为在第一个点之后值会急剧下降。

通常情况下,这些情节并不像我们在上面的例子中那样容易理解。这就是为什么我们使用 auto_arima()来确定订单。

**步骤 4** :使用自动金字塔 ARIMA 方法确定 ARIMA 的订单(P,D,Q)和萨里玛的订单(P,D,Q,P,D,Q)。(自动型号选择)

实现:auto_arima()

这些系数也可以通过查看 ACF/PACF 图(自相关/部分自相关图)来确定。使用这种技术通常很难确定顺序,而使用 auto_arima()则更好。

auto_arima()使用 p、d、q 值的不同组合运行不同的 arima(或 SARIMA)模型,并使用 AIC 和 BIC 指标比较它们的性能。

AIC 和 BIC 是如何工作的:这个度量标准的优点是,它提供了为防止过度拟合而使用的参数数量的惩罚。假设您有一个性能相对较好的简单模型和一个性能略好于前一个模型的复杂模型。如果这两个模型之间有微小的性能改进,那么 AIC 会考虑这一点,并告诉你选择简单的模型,而不是复杂的模型。在这种情况下,复杂模型将比简单模型具有更低的信息标准值。在某种程度上,AIC 惩罚了使用太多参数的模型。

此外,我们可以通过对我们的数据再次应用 Dickey Fuller 测试来验证 auto_arima()获得的“d”顺序。

**步骤 5** : *将数据集分割成训练集和测试集。*一旦我们应用了 auto_arima(),我们就获得了一组(p,d,q)订单,我们可以将这些订单直接分配给我们的 arima 模型。但是在拟合模型之前,我们首先要拆分数据。

*   在时间序列建模中,我们通常认为分割数据的百分比为 70:30(训练:测试)。但我们必须注意,测试数据的大小必须等于预测期。例如,如果我们想预测未来 6 个月的情况,那么我们必须至少采用*6 个月的测试数据量。*
*   另一个需要注意的要点是,我们*不需要*对数据进行采样来进行时间序列预测。这是因为在时间序列中,新值比旧值具有更大的权重。

**第六步** : *拟合 ARIMA 模型*。将步骤 4 中获得的 p、d、q 系数值分配给该模型。

执行:ARIMA()

**步骤 7** : *根据测试数据测试模型拟合。*

*   预测测试值。

实现:预测()

*   将预测值与实际测试值进行比较。(绘制两个图表,并使用误差指标(如 MSE、RMSE)来衡量模型性能。)

**第 8 步**:根据完整数据重新训练模型

我们需要用整个数据来拟合模型。这样做是为了将最近的值和旧的值纳入我们的建模过程。此外,较新的值具有较高的权重。因此,我们必须在整个数据集上重新训练模型。

**第九步**:预测未来!

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3f82fb636ff1dede8283ea29a7b2b9f4.png)

如前所述,预测周期必须等于或小于测试数据的大小。

实现:预测()

(很少有时间序列模型使用 forecast()来预测未来,也很少有像 ARIMA 这样的模型使用 predict()来预测未来)

此外,绘制数据及其预测。

**萨里玛:**季节性 ARIMA 模型有一组额外的参数(P,D,Q)

p:季节性 AR 条款的顺序

d:达到平稳性的差分阶

问:季节 MA 术语的顺序

萨里玛的实施与 ARIMA 相似。除了在步骤 4 中,我们获得 3 个值:ARIMA 的 P,D,Q,这里,我们获得 6 个值:萨里玛的 P,D,Q,P,D,Q。我们应用 SARIMA()进行模型拟合,并继续进行与 ARIMA 相同的过程。

感谢您阅读本文!

# 在自定义数据集上实现 YOLO

> 原文:<https://towardsdatascience.com/implementing-yolo-on-a-custom-dataset-20101473ce53?source=collection_archive---------4----------------------->

***在本文中,我们将逐步了解在自定义数据集上使用 keras 实施 YOLO v2,以及一些常见问题及其解决方案***

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/348c2ada46cb080db56e71d792c847ec.png)

# 了解 YOLO——你只需看一眼

[从 CNN 到面具 R-CNN 和 Yolo](https://medium.com/@arshren/computer-vision-a-journey-from-cnn-to-mask-r-cnn-and-yolo-1d141eba6e04) 第 1 部分

[从 CNN 到 Mask R-CNN 和 Yolo Part 2](https://medium.com/@arshren/computer-vision-a-journey-from-cnn-to-mask-r-cnn-and-yolo-part-2-b0b9e67762b1)

[使用 Yo](https://medium.com/@arshren/object-detection-using-yolov3-using-keras-80bf35e61ce1) lov3 进行物体检测

[Yolo 上的原始文件](https://pjreddie.com/darknet/yolov2/)

我将使用[袋鼠数据集](https://github.com/experiencor/kangaroo)作为我的自定义数据集

# 必需的库

*   Python 3.5 或更高版本
*   Tensorflow:我用过 CPU 版本
*   OpenCV
*   VC++ build 14

# 下载使用 keras 实现的 Yolo 代码

我们将使用暗流回购,可以从这里下载:[**https://github.com/thtrieu/darkflow**](https://github.com/thtrieu/darkflow)

# **降低预训练的重量**

重量可以从[https://pjreddie.com/darknet/yolov2/](https://pjreddie.com/darknet/yolov2/)下载

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/97f635c2df46558a6d71b6a5edc72970.png)

[https://pjreddie.com/darknet/yolov2/](https://pjreddie.com/darknet/yolov2/)

我创建了一个名为 bin 的新文件夹,并将下载的权重放在那里,如下所示

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f89a8cb1fa8716dbf9a93112c7beb709.png)

## **提示:配置(cfg)文件和权重应匹配**

如果配置(cfg)文件和权重不匹配,我们会得到以下错误

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b944371496856ba3f1eae102e0cdd084.png)

Darkflow 通过读取。当权重和配置文件之间的层不匹配时,从. weights 中读取相应的字节块。当权重解析器已经到达. weights 的结尾时,配置文件可能仍有要读取的层。这将生成 over read 断言错误。

# 构建代码

构建代码有三种选择。

**选项 1:**

python setup.py build_ext --inplace


**选项 2:** pip 在开发模式下全局安装暗流

pip install -e .


选项 3:全球安装 pip

pip install .


对我来说,选项 2 和 3 效果不错。

我们现在准备处理图像或视频文件。

# 使用 Yolo 处理图像文件

导入所需的库

import cv2
from darkflow.net.build import TFNet
import matplotlib.pyplot as plt%config InlineBackend.figure_format = 'svg'


要定义模型,我们可以使用以下选项

**1。型号**:配置**文件**(*。cfg)包含模型的细节

**2。加载** : **预训练重量**文件

**3。批次**:每批次要训练的数据数量

**4。纪元**:训练的迭代次数

**5。gpu** :如果想充分利用 gpu 硬件,设置 **1.0** 。如果您需要使用 cpu,则排除此选项

**6。训练**:训练数据集时使用此选项

**7。注释**:存储注释文件的目录

**8。数据集**:存储图像文件的目录

options = {
'model': 'cfg/yolo.cfg',
'load': 'bin/yolov2.weights',
'threshold': 0.3
}
tfnet = TFNet(options)


## 使用 Yolo 加载图像并识别图像中的对象

read the color image and covert to RGBimg = cv2.imread(‘sample_img\sample_dog.jpg’, cv2.IMREAD_COLOR)

img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# use YOLO to predict the image
result = tfnet.return_predict(img)
result


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e468540e6b8a97367f1cbffa66fa1d65.png)

predicting the class, confidence and bounding box in the image

## 在图像上显示类和边界框

pull out some info from the results

for i in range(0, len(result)):
tl = (result[i]['topleft']['x'], result[i]['topleft']['y'])
br = (result[i]['bottomright']['x'], result[i]['bottomright']['y'])
label = result[i]['label']
# add the box and label and display it
img = cv2.rectangle(img, tl, br, (0, 255, 0), 7)
img = cv2.putText(img, label, tl, cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 0), 2)
plt.imshow(img)

plt.show()


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9516f07b04b4eff70636fa5aa028b7e8.png)

# 使用 Yolov2 对新数据集进行训练

我正在使用[袋鼠数据集](https://github.com/experiencor/kangaroo)作为我的自定义数据集。

注释应该是 Pascal VOC(可视对象分类)兼容的。这种格式为对象类别识别提供了标准化的图像数据集。

在暗流文件夹下创建一个文件夹,存储图像和注释。我创建了一个新文件夹 new_data,并在它下面创建了 images 和 annots 文件夹,如下所示

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/dfea5f3f80b3846cdbd045e66b44e5d0.png)

## 用自定义类名更新 labels.txt

暗流使用标签选项从自定义标签文件加载对象类。当 lables 标志未设置时,默认情况下,darkflow 将从`labels.txt`加载。

## 在中更新模型。cfg 文件

我们在。cfg 文件。我们需要更新 cfg 文件中最后一个卷积层的类和过滤器的数量。

过滤器数量= (5 +类别数量)*5

在我们的例子中,因为我们只有一个袋鼠类,我们将有 5*(5+1)=30 个过滤器,如下所示

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/48a28fc28155dd6ea87b305f266488c1.png)

cgf file for the custom dataset

## 技巧 2:将 labels.txt 中的类与。cfg 文件

默认情况下,Darkflow 会尝试从 labels.txt 加载标签。与中的类相比,当模型在 labels.txt 中发现错误的标签数量时,会出现以下错误。cfg 文件

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4f82b6586ab45972cc3a7b072f2b3082.png)

## 定义模型选项

options = {"model": "cfg/yolo.cfg",
"load": "bin/yolov2.weights",
"batch": 2,
"epoch": 5,
"train": True,
"annotation": "new_data/annots/",
"dataset": "new_data/images/"}


## 构建暗流的实例

from darkflow.net.build import TFNet
tfnet = TFNet(options)


## 训练模型

tfnet.train()


## **使用命令提示符训练模型**

我们还可以使用命令行通过以下命令来训练自定义数据集

python flow --model cfg/yolo.cfg --load bin/yolov2.weights --train --annotation new_data\annots --dataset new_data\images --epoch 1


## 使用在新数据集上训练的权重来预测图像

options = {
'model': 'cfg/yolo-1c.cfg',
'load': 50,
'threshold': 0.3,
'backup':'ckpt/'

}
tfnet2 = TFNet(options)


## 加载检查点

这将从我们刚刚在 options 中指定的检查点加载预先训练的参数。

tfnet2.load_from_ckpt()


## 根据自定义数据集对影像进行预测

我们将采用一幅未用于训练的图像来预测类别、包围盒和置信度

original_img = cv2.imread(“new_data/images/00001.jpg”)
original_img = cv2.cvtColor(original_img, cv2.COLOR_BGR2RGB)
results = tfnet2.return_predict(original_img)
print(results)


我在实验中遇到的一个错误是

***转换时有四个字节大小差异的断言错误。***

解决方案是更改 utils 文件夹 weights_walker 中的 loader.py 文件。__init__()方法

change self.offset = 16 to self.offset = 20


根据字节误差,您可能需要对偏移量进行调整。一个通用公式将是

## self.offset = old_offset_value +(发现值-预期值)

文件中的 old_offset_value 是 16。错误将为您提供发现值和预期值的值

# 参考资料:

[https://pjreddie.com/darknet/yolov2/](https://pjreddie.com/darknet/yolov2/)

[](https://github.com/thtrieu/darkflow) [## thtrieu/darkflow

### 实时目标检测和分类。纸张:第一版,第二版。阅读更多关于 YOLO 的信息(在暗网上)和…

github.com](https://github.com/thtrieu/darkflow) [](https://github.com/markjay4k/YOLO-series) [## markjay4k/YOLO 系列

### 此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/markjay4k/YOLO-series) 

[Github](https://github.com/deep-diver/Soccer-Ball-Detection-YOLOv2/blob/master/YOLOv2-Train.ipynb)

# 网络卡车对执法和人工智能的影响

> 原文:<https://towardsdatascience.com/implications-of-the-cybertruck-for-law-enforcement-and-ai-31cd0eb692c6?source=collection_archive---------36----------------------->

你不能错过特斯拉的 Cybertruck 的公告,它带有与碎玻璃相关的“可爱”片段。价格点和两极分化的设计是关键的讨论点。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/754820294a25c20b89fee2daf38c307e.png)

The image of the Cybertruck (from tesla.com)

“bladerunner”的设计伴随着通常的粉丝热情和对福特、通用、康明斯、艾利森变速器影响的强制性金融分析师报告。

令人不安的是合金钢和防弹玻璃中“坚不可摧”材料的使用。

执法部门可能想再看看一辆类似坦克的汽车在街道上行驶的可能性,它也有内置电源。

模仿恐怖主义是全世界人民的祸害。传统和社交媒体引发的病毒式传播刺激了模仿者:从校园枪击案到人们驾驶卡车冲进人群和建筑物。

像这样的卡车需要背景调查吗?如果它被用于帮派暴力呢?问题比比皆是,社会需要对不断变化的技术做出反应。

例如,NHTSA 校车的安全标准可能需要重新审视。行人安全也是要检查的。

艾在这里也有一出戏。这种卡车的行驶里程超过 500 英里,可以邀请司机前往偏远地区,如国家公园和越野。计算机视觉系统对周围环境并不熟悉。就我而言,我很想看看视觉系统对鹿、野牛和熊的反应。

优步事故突出了行人检测(或缺乏检测),行人直到很晚才被识别为人。请记住,特斯拉花了很长时间和一些事件才开始认识到道路施工、分流和汽车从公路路肩并入。

对于像沙漠、丘陵和雪地这样的偏远地区和地形,人工智能需要为此进行训练。

识别雪人或稻草人,并将其与人区分开来也是一项任务。毫无疑问,这将是一个小学生想玩的游戏——试图欺骗人工智能计算机视觉。

伦理人工智能和可解释人工智能再次成为焦点。举例来说,偏僻狭窄的道路可能会让你在一辆停下来的、抛锚的汽车和一辆救护车之间做出选择。

我们生活在有趣的时代。

# 隐式解码器部分 1 - 3D 重建

> 原文:<https://towardsdatascience.com/implicit-decoder-3d-reconstruction-838193f9b760?source=collection_archive---------31----------------------->

## 内部人工智能

## **使用深度学习从单幅图像进行 3D 重建**

一种编码-解码类型的神经网络,用于对 2D 图像中形状的 3D 结构进行编码,然后对该结构进行解码并重建 3D 形状。这是我见过的最高质量的 3D 图像重建。

## 一些细节

*   输入图像:128X128 像素
*   透明图像背景
*   训练和生成是基于相似对象的类别来完成的
*   输出体素:基本分辨率为 64X64X64 体素。但是,可以产生任何所需分辨率的输出(!)而无需重新训练神经网络

## 神经网络结构:

*   2D 编码器—基于 ResNet18。从输入图像生成大小为 128 的编码向量(z 向量)
*   解码器——简单的 6 个全连接层,带 1 个分类输出神经元。接收空间中的 z 向量和- **1** - 3D 坐标作为输入,并分类该坐标是否属于物体的质量。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/38be0a4f0a2c80f725d26a7bbc71d843.png)

Neural Network Structure

## 重建是如何从这个网络发生的?

为了重建物体的整个结构,空间中的所有 3D 坐标被发送到解码器(在该论文的情况下,每个物体有 64X64X64 坐标),以及来自图像的单个 z 向量。解码器对每个坐标进行分类,并创建 3D 结构的表示。这创建了 3D 对象的体素表示。然后,使用[行进立方体](https://en.wikipedia.org/wiki/Marching_cubes)算法来创建网格表示。

# 汽车类别重建示例

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4d71b43c4bc5d0760f9c88fba6fb2f0b.png)

第一列是输入图像,第二列是 AI 3D 重建,最后一列是汽车的原始 3D 对象(或者,用技术语言来说,是地面真相)。这个图像案例中的神经网络是在汽车模型上训练的。在论文中有在椅子、飞机等上面训练的结果。请注意,本文中的输入输出图像和体素分辨率是特定的,但可以根据任何所需的实现进行相应的更改。

## 等等!最后一辆车是怎么改造的?

软件甚至没有看到图像中的车头。这就是 DL 培训的力量所在。由于我们通过许多以前的汽车例子来训练网络,它知道如何推断它从未见过的新车的形状。外推是可能的,因为网络是在来自相似类别的对象上训练的,所以网络有效地重建它之前被训练的相似结构,该结构匹配它在图像中看到的结构。

# 现有的三维重建软件

现在有很多工具可以从图像中进行三维重建。这些工具使用经典的[摄影测量](https://en.wikipedia.org/wiki/Photogrammetry)技术,从同一物体的多个图像中重建 3D 模型。两个例子:

*   [Agisoft](https://agisoft.com)
*   [欧特克公司——重述](https://www.autodesk.com/products/recap/overview)

这种类型的软件可以从当前的 AI 研究中受益。简单平面的重建,即使它们在图像中不完全可见,处理图像中的光反射或像差,更好的比例估计等等。所有这些都可以使用类似的神经网络解决方案来改进。

# 类似的研究

由于编码-解码架构和 GANs,单图像 3D 重建目前正在发展。这种研究的一个很好的例子是:[单幅图像的 3D 场景重建](https://2d3d.ai/index.php/2019/10/09/3d-scene-reconstruction-from-single-image/) —用于场景重建。单个物体重建的质量看起来不是很好,但令人印象深刻的是,他们是从自然场景图像中实现的。

# ShapeNet

与 ImageNet 的图像类似,ShapeNet 是一个大型的带注释的 3D 模型数据集,以及围绕 3D 主题进行 ML 研究的竞赛和人群。大多数(如果不是全部的话)3D ML 研究使用该数据集进行训练和基准测试,包括隐式解码器研究。有两个主要的 Shapenet 数据集,最新的是 ShapeNetCore.v2:

*   55 个常见对象类别
*   大约 51,300 个独特的 3D 模型
*   验证每个 3D 模型的类别和对齐(位置和方向)。

# 参考

*   博文原文:<https://2d3d.ai/index.php/2019/10/11/implicit-decoder-part-1-3d-reconstruction/>
*   研究:[1]陈、、。"学习生成式形状建模的隐式场."*IEEE 计算机视觉和模式识别会议论文集*。2019.
*   shape net:[https://www.shapenet.org/](https://www.shapenet.org/)

[隐式解码器第 2 部分— 3D 生成](/implicit-decoder-part-2-3d-generation-80dbcad8a563)

# 隐式解码器第 2 部分–3D 生成

> 原文:<https://towardsdatascience.com/implicit-decoder-part-2-3d-generation-80dbcad8a563?source=collection_archive---------40----------------------->

## 内部人工智能

## 深度学习和 3D 的 3D 生成和限制

前一篇文章— [隐式解码器第 1 部分—3D 重建](/implicit-decoder-3d-reconstruction-838193f9b760)

# 3D 生成

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d976387923120dbd10fd00b4f819975c.png)

3D Airplane Generation

还记得[甘斯](https://2d3d.ai/index.php/2019/11/11/the-deep-learning-dictionary/#What-are-generative-networks?)吗?嗯,同样的技术可以用来生成你在左边看到的飞机。

它是如何发生的?诀窍是使用相同的解码器网络如下所示。特别是与编码器一起训练的同一个解码器。我们训练一个 GAN 网络来生成一个假的 z 向量。

鉴别器从编码器-解码器网络获得真实的 z 向量作为输入,同时从生成器网络获得虚假的 z 向量作为输入。生成器网络被训练为仅基于随机输入产生新的 z 向量。由于解码器知道获得 z 向量作为输入,并从中重建 3D 模型,并且生成器被训练以产生类似真实的 z 向量,因此可以使用两个网络组合来重建新的 3D 模型。

此外,我们可以看到 gif 显示一个飞机模型变形为一个新的。这是通过获取第一个和最后一个 3D 模型的 z 向量来完成的,让我们将这些向量称为 z_start 和 z_end,然后新的 z 向量被计算为 z_start 和 z_end 的线性组合。具体来说,选取一个介于 0 和 1 之间的数字(假设为 alpha),然后计算一个新的 z-z _ new:z _ new =(z _ start * alpha+z _ end *(1-alpha))。然后,z_new 被馈送到解码器网络中,并且可以计算中间 3D 模型。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/93505e148ac569de1f6087ce7e5efec4.png)

Encoder-Decoder

在不同的 3D 模型之间存在这样的平滑过渡的原因是隐式解码器网络被训练来基于 z 向量识别模型的底层 3D 构造,并且更具体地,识别特定模型类别中的模型。因此,z_vector 的微小变化将导致 3D 模型的微小变化,但仍然保持模型类别的 3D 结构,这样就可以从 z_start 到 z_end 连续地改变模型。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/cf86d3485e0971e5d4803e41c8642f3d.png)

Generating z-vectors

# 深度学习和 3D 重建\生成的局限性

这些结果被带到这里和其他地方,使神经网络似乎是全能的,易于使用和推广到其他场景,用例和产品。有时候是这样,但很多时候不是。在 3D 生成和重建中,神经网络存在局限性。仅举几个例子:

## 数据集限制

正如我们已经证明的,神经网络每次都需要针对特定的模型类别进行训练。每个类别中需要有足够多的模型(通常至少数百个),并且足够多的类别允许这种类型的神经网络的任何类型的现实生活应用,ShapeNet 正在为学术界做这项工作,即使在学术界,类别和每个类别中的模型的数量也是有限的。为了使它在商业上可行,我们需要更多的型号和种类。此外,每个模型需要贴上标签,以其确切的类别,需要调整翻译和规模准确,需要以正确的格式保存。此外,对于每个模型,我们需要不同角度、不同照明位置和相机参数、不同比例对齐和平移的图像。同样,ShapeNet 和其他研究计划有助于建立这一系统,以帮助科学进步。但是,这也意味着,为了将这项研究转化为产品,在数据集创建和处理方面会有大量开销。

## 准确度测量

一个反复出现的问题是 3D 重建或生成有多精确。对此的一个回答是——如何测量 3D 重建的精确度?假设一个人类 3D 设计师从一幅图像重建一个 3D 模型,我们怎么能说他的工作准确与否呢?即使我们有了原始的 3D 模型,又怎么能说两个 3D 模型是相似的,或者说重建的 3D 模型与原点相似,又怎么能量化这种相似性呢?老派的方法,如 MSE、IoU、F1 分数、切角和法向距离[[添加参考—[https://2d 3d . ai/index . PHP/2019/10/09/3D-scene-re construction-from-single-image/](https://2d3d.ai/index.php/2019/10/09/3d-scene-reconstruction-from-single-image/)]]是不考虑对象的 3D 结构的直接度量。例如,IoU 检查与两个形状的联合体积相比,重建的 3D 形状的体积有多少与原始 3D 形状重叠。如果重建的形状被移动到空间中的不同体积中,即使形状是相同的,IoU 也可能为零(因为没有重叠)。

在隐式解码器论文中,作者使用了一种不同的 3D 形状相似性度量方法—[【LFD】](https://onlinelibrary.wiley.com/doi/abs/10.1111/1467-8659.00669)。该度量对于模型的比例、对齐和位置(平移)是不变的。基本想法是从十二面体上的角度拍摄模型的 10 个轮廓图像,并且每个模型拍摄 10 个不同的十二面体。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8c56886e5a5442bd59a74f94fb71fbf0.png)

然后,当在两个模型之间进行比较时,使用[傅立叶](https://en.wikipedia.org/wiki/Fourier_series)和[泽尼克](https://en.wikipedia.org/wiki/Zernike_polynomials)系数来比较来自这 10 个十二面体的图像的视觉相似性。

# 参考

*   陈,,和。"学习生成式形状建模的隐式场."*IEEE 计算机视觉和模式识别会议论文集*。2019.
*   shape net:[https://www.shapenet.org/](https://www.shapenet.org/)
*   ,陈,丁云,等,“基于视觉相似性的三维模型检索研究”*计算机图形学论坛*。第 22 卷。№3.英国牛津:布莱克威尔出版公司,2003 年。

*原载于 2019 年 11 月 16 日*[*https://2d3d . ai*](https://2d3d.ai/index.php/2019/11/16/implicit-decoder-part-2-3d-generation/?utm_source=2d3d.ai&utm_campaign=cf7b1bfd74-EMAIL_CAMPAIGN_2019_11_16_07_23&utm_medium=email&utm_term=0_9ef5ea9bbc-cf7b1bfd74-)*。*

# 数据可视化对获得可行见解的重要性

> 原文:<https://towardsdatascience.com/importance-of-data-visualization-to-derive-actionable-insights-46e4d6dfa33c?source=collection_archive---------23----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3153169d8b03ec655abc65fda756b1f1.png)

Photo by [NASA](https://unsplash.com/@nasa?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/data-visualization?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

数据可视化本身不是关于洞察力,而是关于交流洞察力。

从搅动大量数据中获得的定量洞察通常是微妙的、令人惊讶的、技术上复杂的。鉴于此,向任何受众,尤其是可能有兴趣/时间了解技术细节的业务受众传达这些见解变得更加困难。尽管如此,还是有一些人更喜欢用平淡无奇的黑白数字表格和方程式来展示结果,而不是更具视觉刺激的演示,但是这种人的比例非常小。

作为一名咨询出身的人,我们必须准备好面对各种类型的客户&喜欢表格和方程式的客户,以及想要好看的视觉效果的客户。

根据我的经验,以下是我得到的一些经验法则:

## 1.清楚

*   每张图讲述一个非常重要的观点,并找出讲述故事的元素
*   你陈述的每一件事都应该与整个故事相联系或引导整个故事
*   保持形象简单直接
*   简化但不要过度简化,以免丢失调查结果或关键数据特征

让我们来看一个我最喜欢的例子,数据可视化对于获得洞察力是多么重要。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a71aed92373aa268722a69d6b0b9756f.png)

上面的图表出现在《彭博》上,结论是在过去的 40 年里,所有年龄段的美国男性工人的收入中值都在急剧下降。但这真的是真的吗?让我们看看下面的视觉代表相同的数据集。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c71a7da5be9fb390280fc8aded3af169.png)

现在,从上面的图像中,你可以清楚地看到,在仅仅代表了 2 个数据点(1972 年和 2012 年)后,许多局部扰动被消除了

同样,如果你观察 y 轴,它不应该从零开始。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c5d9c119e50244de1003fec9f724702b.png)

完全相同的数据和图表视觉效果,只是 y 轴变为零。

完整阅读请参考 Eric 的原文[此处](https://medium.com/i-data/misleading-with-statistics-c63780efa928)。

## 2.透明度

*   解释获得适当深度洞察力的方法
*   陈述分析所依据的假设

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c8c889420c97f8f19ac96f749e00b6f6.png)

Source: [http://www.delphianalytics.net](http://www.delphianalytics.net/wp-content/uploads/2013/04/GrowthOfDataVsDataAnalysts.png)

没有 y 轴,上面的图表毫无意义。显然,数据增长和数据分析师增长的规模/单位完全不同。如果不考虑单个度量的比例/单位,你就无法将两个视觉效果叠加在一起。讲述故事最重要的元素应该取 X 轴和 Y 轴;在得出任何结论之前,一定要检查这一点(很多方法会误导观众)。

## 3.完整

*   准确、诚实地描述不确定性和局限性,因为夸大数据的含义是非常普遍和诱人的。
*   卓越的图形化始于讲述数据的真相。—爱德华·塔夫特,定量信息的可视化展示,2001

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c8775420d60664bd4967f6cd8adc6bee.png)

Source: [http://www.verticalmeasures.com](http://www.verticalmeasures.com/wordpress/wp-content/uploads/2013/11/Skyrocketing-Tax-Rate-Increase.jpg)

这篇博客的灵感来源于 Dakshinamurthy V Kolluru 博士主持的数据可视化会议,并引用了其中的内容。

请在评论区告诉我们你的想法。

这些内容最初发表在我的个人博客网站:[http://datascienceninja.com/](http://datascienceninja.com/?source=post_page---------------------------)。点击[此处](http://datascienceninja.com/2019/07/29/importance-of-data-visualization-to-derive-actionable-insights/)查看并订阅即时接收最新博客更新。

# 距离度量在机器学习建模中的重要性

> 原文:<https://towardsdatascience.com/importance-of-distance-metrics-in-machine-learning-modelling-e51395ffe60d?source=collection_archive---------3----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/580d218bdd3badfc3e9f422dedd2dd2b.png)

[Unsplash](https://unsplash.com/photos/smXusOhyHwg)

许多机器学习算法——有监督的或无监督的——使用距离度量来了解输入数据模式,以便做出任何基于数据的决策。良好的距离度量有助于显著提高分类、聚类和信息检索过程的性能。在本文中,我们将讨论不同的距离度量,以及它们如何帮助机器学习建模。

# 介绍

在许多现实世界的应用中,我们使用机器学习算法来分类或识别图像,并通过图像的内容检索信息。例如,人脸识别、在线审查图像、零售目录、推荐系统等。在这里,选择一个好的距离度量变得非常重要。距离度量有助于算法识别内容之间的相似性。

基础数学定义(来源维基百科),

> 距离度量使用距离函数来提供数据集中每个元素之间的关系度量。

你们有些人可能会想,这个距离函数是什么?它是如何工作的?它如何决定数据中的特定内容或元素与另一个内容或元素有某种关系?让我们在接下来的几节里试着找出答案。

# 距离函数

你记得学过勾股定理吗?如果你这样做了,那么你可能还记得用这个定理计算两个数据点之间的距离。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8c45f048f0a58b6d962a790aa7161758.png)

Source: [Khan Academy’s Distance Formula Tutorial](https://www.khanacademy.org/math/geometry/hs-geo-analytic-geometry/hs-geo-distance-and-midpoints/a/distance-formula)

为了计算数据点 A 和 B 之间的距离,勾股定理考虑了 x 轴和 y 轴的长度。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1808c5d6525e9f78a1dc678cc66ed7b7.png)

Source: [Khan Academy’s Distance Formula Tutorial](https://www.khanacademy.org/math/geometry/hs-geo-analytic-geometry/hs-geo-distance-and-midpoints/a/distance-formula)

你们中的许多人一定想知道,我们在机器学习算法中使用这个定理来寻找距离吗?回答你的问题,是的,我们确实使用它。在许多机器学习算法中,我们使用上述公式作为距离函数。我们将讨论使用它的算法。

现在你可能已经知道什么是距离函数了。下面是一个简化的定义。

来自 Math.net 的基本定义,

> 距离函数提供集合中元素之间的距离。如果距离为零,那么元素是等价的,否则它们彼此不同。

距离函数只不过是距离度量使用的数学公式。不同的距离度量的距离函数可以不同。让我们讨论不同的距离度量,并了解它们在机器学习建模中的作用。

# 距离度量

有许多距离度量,但是为了使本文简洁,我们将只讨论几个广泛使用的距离度量。我们将首先尝试理解这些度量背后的数学,然后我们将确定使用这些距离度量的机器学习算法。

以下是常用的距离度量-

# **闵可夫斯基距离:**

闵可夫斯基距离是赋范向量空间中的度量。什么是赋范向量空间?赋范向量空间是在其上定义了范数的向量空间。假设 X 是一个向量空间,那么 X 上的范数是一个实值函数| |*X*| |它满足以下条件

1.  **零矢量-** 零矢量的长度为零。
2.  **标量因子-** 当你把向量乘以一个正数时,它的方向不变,尽管它的长度会改变。
3.  **三角形不等式-** 如果距离是一个范数,那么两点之间的计算距离将始终是一条直线。

你可能想知道为什么我们需要赋范向量,我们能不能不要简单的度量?由于赋范向量具有上述性质,这有助于保持范数诱导的度量齐次和平移不变。更多细节可以在[这里](https://math.stackexchange.com/questions/152340/whats-the-need-of-defining-notion-of-distance-using-norm-function-in-a-metric-s)找到。

可以使用下面的公式计算距离

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a438924f5f38affbf8b2a11dc2a31cb6.png)

闵可夫斯基距离是广义距离度量。这里的广义是指我们可以操纵上述公式,以不同的方式计算两个数据点之间的距离。

如上所述,我们可以操作 *p* 的值,并以三种不同的方式计算距离-

> p = 1,曼哈顿距离
> 
> p = 2,欧几里德距离
> 
> p = ∞,切比雪夫距离

我们将在下面详细讨论这些距离度量。

**曼哈顿距离:**

如果我们需要计算网格状路径中两个数据点之间的距离,我们使用曼哈顿距离。如上所述,我们使用 ***闵可夫斯基距离*** 公式,通过设置 ***p 的*** 值为 ***1*** 来求曼哈顿距离。

比方说,我们要计算两个数据点- ***x*** 和 ***y*** 之间的距离, ***d*** 。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a829ae0ed91de116a0cc89280c96cc2c.png)

距离 ***d*** 将使用其笛卡尔坐标之间的 ***差*** 的绝对和来计算,如下所示:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7516f704d070c42289a31cec232777b8.png)

其中,******* 分别为二维向量空间中向量 x 和 y 的变量。即 ***x = (x1,x2,x3,...)*** 和 ***y = (y1,y2,y3,…)*** 。*

*现在距离 ***d*** 将被计算为-*

****【x1-y1】***+**+*(x2-y2)***+**+*(x3-y3)***+…+***(xn-yn)****

*如果您尝试将距离计算可视化,它将如下所示:*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3c6483de016e545b4e8a7ca32f5a21a2.png)*

*Source — [Taxicab geometry Wikipedia](https://en.wikipedia.org/wiki/Taxicab_geometry)*

*曼哈顿距离也被称为出租车几何,城市街区距离等。*

***欧几里德距离:***

*欧几里德距离是最常用的距离度量之一。通过将 ***p 的*** 值设置为 ***2*** ,使用闵可夫斯基距离公式进行计算。这将更新距离***【d】***公式如下:*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/47daa92a051526955ad5e6850186ae57.png)*

*我们停一会儿吧!这个公式看着眼熟吗?嗯是的,我们刚刚在这篇文章上面讨论 ***“勾股定理”的时候看到了这个公式。****

*欧几里德距离公式可以用来计算平面上两个数据点之间的距离。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/136156f0a0dcf829c766257d10a03443.png)*

# ***余弦距离:***

*余弦距离度量主要用于发现不同文档之间的相似性。在余弦度量中,我们测量两个文档/向量之间的角度(作为度量收集的不同文档中的术语频率)。当向量之间的大小无关紧要但方向重要时,使用这种特定的度量。*

*余弦相似性公式可以从点积公式中导出*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/0f2976b8b2806b219d01f54f5fb12be0.png)*

*现在,你一定在想余弦角的哪个值会有助于找出相似点。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/baea7d49c6f14bba674530190e22c53a.png)*

*现在我们有了用来衡量相似性的值,我们需要知道 1,0 和-1 代表什么。*

*这里余弦值 1 用于指向相同方向的向量,即在文档/数据点之间存在相似性。正交向量为零,即不相关(发现一些相似性)。指向相反方向的向量的值为-1(无相似性)。*

# ***马氏距离:***

*Mahalanobis 距离用于计算多元空间中两个数据点之间的距离。*

*根据维基百科的定义,*

> ***Mahalanobis 距离**是一个点 P 和分布 d 之间距离的度量。测量的想法是,P 离 d 的平均值有多少标准差。*

*使用 mahalanobis 距离的好处是,它考虑了协方差,这有助于测量两个不同数据对象之间的强度/相似性。观察值和平均值之间的距离可以计算如下-*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/979ae11f95223d03ef85a15cf28120ea.png)*

*这里,S 是协方差矩阵。我们使用协方差度量的倒数来获得方差归一化的距离方程。*

*现在,我们对不同的距离度量有了基本的了解,我们可以进入下一步,即使用这些距离度量的机器学习技术/建模。*

# *机器学习建模和距离度量*

*在这一部分,我们将研究一些基本的分类和聚类用例。这将有助于我们理解距离度量在机器学习建模中的用途。我们将从监督和非监督算法的快速介绍开始,然后慢慢转向例子。*

## *1.分类*

***K-最近邻(KNN)-***

*KNN 是一种非概率监督学习算法,即它不产生任何数据点的隶属概率,而是 KNN 根据硬分配对数据进行分类,例如数据点将属于 0 或 1。现在,你一定在想,如果没有概率方程,KNN 是怎么工作的。KNN 使用距离度量来找出相似点或不同点。*

*让我们看看 iris 数据集,它有三个类,看看 KNN 将如何识别测试数据的类。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1ab7f0a2e921d15c0651f3fc18a00ce2.png)*

*在黑色方块上方的#2 图像中是一个测试数据点。现在,我们需要借助 KNN 算法找到这个测试数据点属于哪一类。我们现在将准备数据集来创建机器学习模型,以预测我们的测试数据的类别。*

#Import required libraries#Import required librariesimport numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score#Load the dataset
url = "https://raw.githubusercontent.com/SharmaNatasha/Machine-Learning-using-Python/master/Datasets/IRIS.csv"
df = pd.read_csv(url)#quick look into the data
df.head(5)#Separate data and label
x = df.iloc[:,1:4]
y = df.iloc[:,4]#Prepare data for classification process
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=0)


*在 KNN 分类算法中,我们定义了常数*“K”。* K 是一个测试数据点的最近邻数。然后,这 K 个数据点将用于决定测试数据点的类别。(注意这是在训练数据集中)*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ebb781a15363087c9d06c6b7c16c1a98.png)*

**你是否想知道我们如何找到最近的邻居。这就是距离度量进入图片的地方。首先,我们计算每列火车和测试数据点之间的距离,然后根据 k 的值选择最接近的顶部**

*我们不会从头开始创建 KNN,但会使用 scikit KNN 分类器。*

#Create a modelKNN_Classifier = KNeighborsClassifier(n_neighbors = 6, p = 2, metric='minkowski')


*你可以在上面的代码中看到,我们使用的是闵可夫斯基距离度量,p 值为 2,即 KNN 分类器将使用欧几里德距离度量公式。*

*随着机器学习建模的发展,我们现在可以训练我们的模型,并开始预测测试数据的类别。*

#Train the model
KNN_Classifier.fit(x_train, y_train)#Let's predict the classes for test data
pred_test = KNN_Classifier.predict(x_test)


*一旦选择了顶部最近的邻居,我们检查邻居中投票最多的类-*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4ec05ab6c892dd69c7b75883dde28d77.png)*

*从上图中,你能猜出考点的类别吗?它是 1 类,因为它是投票最多的类。*

*通过这个小例子,我们看到了*距离度量*对于 KNN 分类器的重要性。*这有助于我们获得已知类别的最接近的列车数据点。*使用不同的距离指标,我们可能会得到更好的结果。所以,在像 KNN 这样的非概率算法中,距离度量起着重要的作用。*

## *2.使聚集*

***K-means-***

*在概率或非概率的分类算法中,我们将获得带标签的数据,因此预测类别变得更容易。尽管在聚类算法中我们不知道哪个数据点属于哪个类。距离度量是这类算法的重要组成部分。*

*在 K-means 中,我们选择定义聚类数的质心数。*然后使用距离度量(欧几里德)*将每个数据点分配到其最近的质心。我们将使用 iris 数据来理解 K-means 的基本过程。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/39f6bc43da653c95fc3383885ce7ee2f.png)*

*在上面的图像#1 中,你可以看到我们随机放置了质心,在图像#2 中,使用距离度量试图找到它们最近的聚类类。*

import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt#Load the dataset
url = "https://raw.githubusercontent.com/SharmaNatasha/Machine-Learning-using-Python/master/Datasets/IRIS.csv"
df = pd.read_csv(url)#quick look into the data
df.head(5)#Separate data and label
x = df.iloc[:,1:4].values#Creating the kmeans classifier
KMeans_Cluster = KMeans(n_clusters = 3)
y_class = KMeans_Cluster.fit_predict(x)


*我们将需要不断重复分配质心,直到我们有一个清晰的集群结构。*

*![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/aa2d1742066f9895de97b1c77d7c0a41.png)*

*正如我们在上面的例子中看到的,在 K-Means 中的距离度量的帮助下,在没有关于标签的任何知识的情况下,我们将数据聚类成 3 类。*

## *3.自然语言处理*

***信息检索***

*在信息检索中,我们处理非结构化数据。数据可以是文章、网站、电子邮件、短信、社交媒体帖子等。借助 NLP 中使用的技术,我们可以创建矢量数据,以便在查询时可以用来检索信息。一旦将非结构化数据转换成向量形式,我们就可以使用余弦相似性度量从语料库中过滤掉不相关的文档。*

*我们举个例子,了解一下余弦相似度的用法。*

1.  *为语料库和查询创建向量形式-*

import math
import numpy as np
import pandas as pd
import matplotlib.pyplot as pyplot
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import TfidfVectorizervectorizer = TfidfVectorizer()corpus = [
'the brown fox jumped over the brown dog',
'the quick brown fox',
'the brown brown dog',
'the fox ate the dog'
]query = ["brown"]X = vectorizer.fit_transform(corpus)
Y = vectorizer.transform(query)


*2.检查相似性,即找到语料库中与我们的查询相关的文档-*

cosine_similarity(Y, X.toarray())Results:
array([[0.54267123, 0.44181486, 0.84003859, 0. ]])


*从上面的例子可以看出,我们查询单词*“布朗”*,在语料库中只有三个文档包含单词*“布朗”。*当使用余弦相似性度量检查时,除第四个文档外,其他三个文档的>值均为 0,从而给出了相同的结果。*

# *结论*

*通过这篇文章,我们了解了一些流行的距离/相似性度量,以及如何使用这些度量来解决复杂的机器学习问题。希望这能对初入机器学习/数据科学的人有所帮助。*

# *参考*

1.  *余弦相似度- [Sklearn](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.cosine_similarity.html) , [TDS 文章](/overview-of-text-similarity-metrics-3397c4601f50),[维基百科](https://en.wikipedia.org/wiki/Cosine_similarity),[例题](http://www.sfs.uni-tuebingen.de/~ddekok/ir/lectures/tf-idf-dump.html)*
2.  *[Github 代码](https://github.com/SharmaNatasha/Machine-Learning-using-Python/blob/master/Distance_Metrics_MM.ipynb)*
3.  *距离度量-【Math.net ,[维基](https://en.wikipedia.org/wiki/Distance)*
4.  *闵可夫斯基距离度量- [维基](https://en.wikipedia.org/wiki/Minkowski_distance),[博客](https://people.revoledu.com/kardi/tutorial/Similarity/MinkowskiDistance.html),[著名度量](https://machinelearning1.wordpress.com/2013/03/25/three-famous-metrics-manhattan-euclidean-minkowski/)*

# 排气数据在数据科学中的重要性

> 原文:<https://towardsdatascience.com/importance-of-exhaust-data-in-data-science-2f5c1ab5df03?source=collection_archive---------28----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/114a30e793d8254f31f0c38d619c4965.png)

Image Credit: NASA/JPL-Caltech

当我第一次听到排气数据这个术语时,我被迷住了。关于同一个主题有很多不同的定义,我想深入探讨一下。简而言之,耗尽型数据是在没有特定目的的情况下生成的数据,可能不会立即显示出对组织在管理、存储和使用这些数据上花费金钱的重要性。嗯,让我们再举几个例子,同时我们会尝试将这些例子与数据科学联系起来。

几个例子(我们这里只是触及冰山一角!):

**网购活动:**假设你去一家网店买鞋。你看了几十个,最后选了一个放在购物车里。一个小时后你回来了,最后买下了它。对于在线商店,主要信息是您点击了哪双鞋,您将哪双鞋放在购物车上,您的鞋码,以及最终的交易信息。现在,让我们考虑一下尾气数据。这可能是你的位置信息,你在其他产品上花费的时间,你搜索的短语,鞋子在购物车中的时间,你使用的设备,安全日志,cookies 等。利用这些废气数据,您可以使用数据科学获得一些可行的见解,如产品推荐、欺诈检测、高效营销、改善客户体验、价格优化等。

**有人发微博吗?:**假设有人发微博说“第一场雪就像初恋——劳拉·比尤斯。”仅仅这条推文和用户名可能不会给我们太多的见解。以元数据的形式用尽数据,比如位置、设备 id、发布时间、用户的关注者数量、用户关注的用户数量、帐户的创建日期等等。现在,零售商店可以使用这些数据来储备药品、供应品、冬靴,媒体流媒体公司可以使用这些数据来播放假日电影,紧急服务可以使用这些数据,导航服务可以提醒司机等等。

**视频:**这是一个非常有趣的空间。视频自然带有一些元数据,如时长、文件大小、格式、创作者/导演、演员等。然而,数据科学在这方面的范围相当有限。进入机器学习,我们可以根据声音、场景的情感(想想静止图像上的情感,因为视频只是一系列超快的静止图像)、场景的位置、历史重要性、成人内容识别来自动生成文本。自然,这些元数据大量用于个性化视频分段、内容审核、视频推荐、基于内容的搜索和索引视频、个性化广告制作、成人内容过滤等。

**物联网空间:**同样,这是一个非常广泛的话题,与其他例子类似,工业物联网中的尾气数据可能是最大的。例如,世界上最大的金属和矿业公司之一 Rio Tinto 每分钟产生 2.4 万亿字节的数据,而地震数据的总量可达数十亿字节[1]。我觉得这里有两件事改变了游戏规则。得益于云计算,存储和计算的成本在过去十年中以指数速度下降。2.边缘计算尺寸减小,功耗增加(例如 FPGAs)。由于这种技术进步,这些公司可以在本地边缘运行机器学习模型,并保持存储大量数据以进行历史分析。

当然,这些只是收集尾气数据的热情日益高涨的几个例子。在这个蓬勃发展的信息社会中,每个工业部门都在利用尾气数据的力量来获得竞争优势,并在客户满意度方面出类拔萃。

总之,虽然收集尾气数据提供了一个很好的机会,但它也带来了保护个人和敏感信息的责任。一个例子是国家安全局大规模收集电话记录[2]。两名斯坦福大学的研究生在他们的研究中发现,监控元数据可以用来查找呼叫者的信息、医疗状况、财务和法律关系[3]。本着开放、积极和道德的心态,我认为利用尾气数据的领域将在未来成为游戏规则的改变者。

# 参考

[1]

G.Goidel,“https://rctom.hbs.org”,2018 年 11 月 12 日。【在线】。可用:[https://rctom . HBS . org/submission/data-is-the-new-oil-Rio-Tinto-builds-new-intelligent-mine/。](https://rctom.hbs.org/submission/data-is-the-new-oil-rio-tinto-builds-new-intelligent-mine/.)

[2]

E.中岛,“www.washingtonpost.com”,2015 年 11 月 27 日。【在线】。可用:[https://www . Washington post . com/world/national-security/NSAs-bulk-collection-of-Americans-phone-records-ends-Sunday/2015/11/27/75d c62e 2-9546-11e 5-a2d 6-f 57908580 b1f _ story . html?no redirect = on&UTM _ term = . 2f 344 e 00 EB 33 .](https://www.washingtonpost.com/world/national-security/nsas-bulk-collection-of-americans-phone-records-ends-sunday/2015/11/27/75dc62e2-9546-11e5-a2d6-f57908580b1f_story.html?noredirect=on&utm_term=.2f344e00eb33.)

[3]

C.b .帕克," news.stanford.edu ",2014 年 3 月 12 日。【在线】。可用:[https://news . Stanford . edu/news/2014/March/NSA-phone-surveillance-031214 . html?UTM _ content = buffer 07d 49&UTM _ medium = social&UTM _ source = Twitter . com&UTM _ campaign = buffer。](https://news.stanford.edu/news/2014/march/nsa-phone-surveillance-031214.html?utm_content=buffer07d49&utm_medium=social&utm_source=twitter.com&utm_campaign=buffer.)

# 特征工程方法的重要性

> 原文:<https://towardsdatascience.com/importance-of-feature-engineering-methods-73e4c41ae5a3?source=collection_archive---------11----------------------->

## 特征工程方法及其对不同机器学习算法的影响分析

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5ba48cfe72176b1e30b1bfc0ef357174.png)

Photo by [Fabrizio Verrecchia](https://unsplash.com/@fabrizioverrecchia?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

机器学习算法接受一些输入,然后生成一个输出。例如,这可能是一只股票第二天的价格,使用的是前几天的价格。从给定的输入数据,它建立一个数学模型。该模型以自动化的方式发现数据中的模式。这些模式提供了洞察力,这些洞察力被用于做出决策或预测。为了提高这种算法的性能,特征工程是有益的。特征工程是一个数据准备过程。一种是修改数据,使机器学习算法识别更多的模式。这是通过将现有特征组合并转换成新特征来实现的。

应用机器学习从根本上来说是特征工程。但是这也是困难和费时的。它需要大量的经验和领域知识。评估哪些类型的工程特征性能最佳可以节省大量时间。如果一个算法可以自己学习一个特性,就没有太大的必要提供。

# 特征工程方法的前期分析

杰夫·希顿在[1]中研究了公共特征工程方法。他评估了机器学习算法综合这些特征的能力。起初,他采样均匀随机值作为输入特征 *x* 。接下来,他用特定的方法设计了一个功能。他用这个工程特征作为标签 *y* 。然后使用预测性能来测量该能力。研究的特征工程方法有:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6ffceae381bd8f00a4c24e283cc97d71.png)

Counts

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c495c2ca2fa8b9d3bc5711ac70e43567.png)

Differences

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9b9e5895e61c7a171be39fb158ab5dd2.png)

Logarithms

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4cec1174e1f1e2f4aac402c2f28fc598.png)

Polynomials

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f13de66ad7f0a70171681b3c014d731b.png)

Powers (square)

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c3c7a6adb23e54037d0367763c0271c4.png)

Ratios

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6da19f8fad6c1bff5172838747aaf42d.png)

Ratio differences

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/68edda1e0b9cc627f864252091d82fd9.png)

Ratio polynomials

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/63f3eacdfc2778adf8935f49e3f0d4a3.png)

Root distance (quadratic)

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8d4b1a8f77ca4977eb08bc13ab7cc7ea.png)

Square root

他一次只测试一种特征工程方法。他对输入要素进行采样的范围各不相同。在每种情况下,他评估了四种不同模型的均方根误差(RMSE)。其中包括:

*   神经网络
*   高斯核支持向量机(SVM)
*   随机森林
*   梯度推进决策树(BDT)

他在自己的 GitHub 页面上发布了 [RMSE 结果](https://github.com/jeffheaton/papers/blob/master/2016/ieee-feature-eng/results.csv)。希顿得出以下结论:

*   所有的算法都不能综合比值差特征。
*   基于决策树的算法不能综合计数特征。
*   神经网络和 SVM 不能合成比率特征。
*   SVM 未能综合二次特征。

因此,结果表明,算法可以综合一些特征,但不是全部。尽管根据算法的类型有一些不同。

然而,均方根误差对标签的绝对值很敏感。并且实验的标签值在不同的数量级上变化。此外,分布也不相同。在某些情况下,当从稍微不同的范围对输入要素进行采样时,可能会得出不同的结论。因此,不同实验中的 RMSE 值不具有可比性。只是同一实验中不同模型的 RMSE 值。为了说明这一点,我用改进的评估方法重复了这个实验。这揭示了一些有趣的差异。

# 改进的分析设置和结果

我改变了评估方法,使标签值均匀随机抽样。我选择的范围在 1 到 10 之间。所有实验都使用相同的取样标签。之后,我在标注上使用逆变换创建了输入要素。例如,我没有使用输入要素的平方来创建标注,而是使用标注的平方根来创建输入要素。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c36e413cb993e7259ef7707d315c61fc.png)

Inversion

在反演有多个解的情况下,只使用一个解。在多输入的实验中,我随机采样了除一个输入特征之外的所有输入特征。我选择了采样范围,以便所有输入要素都在同一范围内。此外,我使用所有模型的标准化来缩放数据。最后,我在每个实验中尝试了神经网络和 BDT 的不同学习速率。取学习率,即各个模型表现最好的学习率。我用了希顿分析中剩下的装置。结果如图 1 所示。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/00e7ed30ed7abcc6aa8c69b1699bb9eb.png)

Figure 1: Capacity of Machine Learning algorithms to synthesize common Feature Engineering methods. Label values ranged uniformly between 1 and 10\. Simply predicting the mean of the labels, would result in an RMSE value of 2.6.

与希顿的分析一致,所有算法都无法合成比率差异特征。此外,计数和比率功能也有相似之处。基于决策树的算法比其他具有计数特征的算法性能更差。决策树没有总结不同特征的固有方式。他们需要为每种可能的组合创建一片叶子,以便很好地合成计数特征。此外,神经网络和 SVM 在比率特征方面表现较差。最后,实验结果证实了决策树可以综合单调变换特征。正如所料。

与希顿的分析相反,我的分析显示了二次特征的巨大差异。所有模型在综合这些特征时都有问题。在希顿的二次特征实验中,许多标签的值为零。其余的价值很小。这就解释了区别。此外,线性模型在综合对数特征方面存在更多问题。这个实验中的标记比其他实验中的标记小一个数量级。这导致了差异。

# 结论

该分析评估了特征工程方法在建模过程中的重要性。这是通过测量机器学习算法合成特征的能力来完成的。所有被测试的模型都可以学习简单的转换,比如只包含一个特征的转换。因此,专注于基于多个特征的工程特征可以更有效地利用时间。尤其是二次特征和包含除法的特征非常有用。

此外,这解释了为什么集合不同的模型通常会导致显著的性能提高。基于相似算法的集成模型则不会。例如,在具有类似计数和对数模式的数据集中,组合随机森林和增强决策树仅受益于对数特征。而组合神经网络和随机森林从两种特征类型中获益。

[1] J .希顿,[预测建模的特征工程实证分析](https://arxiv.org/pdf/1701.07852.pdf) (2016),arXiv

# 利用机器学习的创新指标的重要性

> 原文:<https://towardsdatascience.com/importance-of-innovation-indicators-utilizing-machine-learning-141fb5515866?source=collection_archive---------38----------------------->

## 希腊的例子

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/10b0dbd4f372aeb58d39ff0e314c4eb5.png)

Photo by [Anastasia Zhenina](https://unsplash.com/@disguise_truth?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

这篇文章对希腊进行了创新分析。利用多种机器学习算法的基于模型的特征重要性来确定影响希腊创新产出得分波动的最重要指标。使用的分类器有**逻辑回归****随机森林****额外树****支持向量机**。这项研究的数据由 [*欧洲创新记分牌*](https://ec.europa.eu/growth/industry/innovation/facts-figures/scoreboards_en) 免费提供。

# 介绍

创新可以定义为一个过程,它为组织、供应商和客户提供附加值和一定程度的新颖性,开发新的程序、解决方案、产品和服务以及新的营销方式[1]。这是每个组织最关心的问题之一。它在市场发展和协调中的作用是固有的。创新应用的重要性在从产品开发、管理方法到工作方式的所有人类领域都至关重要[2]。

# 背景资料

## 相关资料

欧盟委员会提供了各种工具来绘制、监测和评估欧盟在不同创新领域的表现。所提供的信息有助于欧盟、国家和区域层面的政策制定者和实践者衡量其绩效和政策,并了解新趋势和新出现的商业机会,从而为循证决策提供信息[3]。*欧洲创新记分牌* ( *EIS* )就是这样一个工具,它提供了对欧洲研究和创新绩效的比较评估。它评估国家研究和创新系统的相对优势和弱点,并帮助各国和各区域确定它们需要解决的领域。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/aba4ca491fd8391b21e7e56ece1e990b.png)

Photo by [Sara Kurfeß](https://unsplash.com/@stereophototyp?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

2018 年的 *EIS* 版本区分了四种主要类型的指标和十个创新维度,总共捕获了 27 个不同的指标[4]。包括综合指标在内的四个主要类别是:

*   *框架条件*:企业外部创新绩效的主要驱动因素,区分三个综合指标(人力资源、研究系统、创新友好型环境)。
*   *投资*:对公共和商业部门的投资,区分两个综合指标(金融和支持、企业投资)。
*   *创新活动*:商业部门创新的不同方面,并区分三个综合指标(创新者、联系、知识资产)。
*   *影响*:企业创新活动的影响以及两个综合指标之间的差异(就业影响、销售影响)。

*EIS* 2018 的时序数据是指 2010-2017 年的时间框架。

## 机器学习

特征选择是机器学习中的基本技术[5]。人们不能随意保留或删除特征。有几种特征选择方法,包括降维[6]。一般来说,有两种主要的特征重要性方法,模型无关的和基于模型的。与模型无关的特征选择技术,例如前向特征选择,提取所选关键性能指标的最佳值所需的最重要的特征。然而,这种方法通常有一个缺点,即时间复杂度大。为了避免这个问题,可以从被训练模型中直接获得特征重要性。上面的方法是基于模型的方法。因此,上述方法被用于估计特征的重要性。

**Logistic 回归**是一种二元分类算法。它的目标是在 *k* 维空间中找到分隔这两个类别的最佳超平面,最小化逻辑损失[7]。为了估计每个特征对模型输出的重要性,使用了 *k* 维权重向量。第 j *个*权重的大绝对值表示第 j *个*特征在类别预测中的较高重要性。

**随机森林**是决策树模型的变种。这是一个使用多个决策树作为基础学习器的集成模型。基础学习者是高方差、低偏差的模型。通过汇总所有基础学习者做出的决策来预测响应变量,减少了整个模型的方差。这个想法是为了确保每个基础学习者学习数据的不同方面。这是通过行和列采样实现的[8]。在分类设置中,聚合是通过采取多数表决来完成的。在决策树的每个节点,基于信息增益标准或计算成本更低的基尼系数杂质减少来决定用于分割数据集的特征。选择最大化信息增益(或减少基尼系数杂质)的特征作为分裂特征。通过使用基尼重要度,特征重要度被计算为通过到达该节点的概率加权的节点杂质的减少。节点概率可以通过到达节点的样本数除以样本总数来计算。因此,很容易理解,值越高,特征越重要。

**Extra-Trees** 代表极度随机化的树。该分类器是一种基本上基于决策树的集成学习方法。 **Extra-Trees** 分类器将某些决策和数据子集随机化,以最大限度地减少数据的过度学习和过度拟合。**多余的树**就像**随机森林**。这种算法建立和适应多棵树,并使用随机特征子集分割节点[9]。然而,**随机森林****额外树**分类器之间的两个关键区别如下:

*   **额外树**不引导观察。该算法使用无替换的采样。
*   **额外树**节点根据在每个节点选择的特征的随机子集的随机分裂来分裂,而不是最佳分裂。

从统计学的角度来看,放弃 bootstrapping 的想法会导致偏倚方面的优势,而分裂点随机化通常具有极好的方差减少效果。如上所述,在**随机森林**中使用基尼系数计算特征重要性。

**支持向量机** ( **SVM** )是一个强大的监督学习模型,用于预测和分类。 **SVM** 的基本思想是使用非线性映射函数将训练数据映射到高维空间,然后在高维空间执行“线性”回归以分离数据。预定的核函数用于数据映射。通过寻找最佳超平面来完成数据分离。这个最优超平面被称为**支持向量**,其具有来自分离类的最大余量【10】。

与人工神经网络、决策树等经典分类方法相比,SVM 有许多优点。在高维空间中的良好性能可以被认为是一种优势。此外,**支持向量**依赖于训练数据的一个小子集,这给了 **SVM** 惊人的计算优势。

在这项研究中,使用了线性核的 **SVM** 算法。因此,为了估计每个特征对模型输出的重要性,使用了 *k* 维权重向量。第 j *个*权重的大绝对值表示第 j *个*特征在类别预测中的较高重要性。权重系数彼此之间的绝对大小可以用于从数据中确定特征重要性。

# 数据收集和预处理

使用来自 2018 年*欧洲创新记分牌* ( *EIS* )数据库版本的数据,包括 2010-2017 年期间的希腊数据。数据是从 [*欧洲创新记分牌*](https://ec.europa.eu/growth/industry/innovation/facts-figures/scoreboards_en) 网站免费收集的。希腊的数据质量很高,只有少量遗漏的观测数据。

数据库被过滤以仅选择关于希腊的指标。数据中丢失的值将被清除。此外,这两个指标的值在希腊层面缺失,因此在分析中不予考虑。这些指标是“外国博士研究生占所有博士研究生的百分比”和“在快速增长的企业中就业的百分比”。对于每个指标,使用数据库提供的标准化分数构建了 2010 年至 2017 年的时间序列数据。总体而言,时间序列数据由 25 个指标和汇总创新指数组成。

为了便于阅读,指示器的名称被截断。指示器的全名如下所示:

*   **宽带 _ 渗透**:宽带渗透。
*   **Venture_capital** :风险资本占 GDP 的百分比。
*   **设计 _ 应用**:每十亿 GDP 的设计应用(PPS)。
*   **Trademark_apps** :每十亿 GDP 的商标申请量(pps)。
*   **就业 _ 活动**:知识密集型活动的就业(占总就业的%)。
*   **企业 _ 培训**:提供培训以发展或提升其员工信息和通信技术技能的企业。
*   **创新型中小企业**:与他人合作的创新型中小企业(中小企业的%)。
*   **国际 _ 出版物**:每百万人口的国际科学合作出版物。
*   **知识 _ 出口**:知识密集型服务出口占总服务出口的百分比。
*   新博士毕业生:每 1000 名 25-34 岁人口中的新博士毕业生。
*   **非研发**:非研发&创新支出(占营业额的百分比)。
*   **Opportunity_enterpre** :机会驱动型创业(动机指数)。
*   **Pct_patent** :每十亿 GDP 的 Pct 专利申请量(PPS)。
*   **百分比 _ 高等教育 _ edu**:25-34 岁人口完成高等教育的百分比。
*   **百分比 _ 终身学习**:参与终身学习的 25-64 岁人口的百分比。
*   **私人共同出资**:公共研发支出的私人共同出资(占国内生产总值的百分比)。
*   **Public_private_pubs** :每百万人口公私合作出版物。
*   **Rd_business** : R & D 商业部门的支出(占国内生产总值的%)。
*   **Rd_public** : R & D 公共部门的支出(占国内生产总值的%)。
*   **销售额**:新上市和新公司创新的销售额占营业额的百分比。
*   **Scientific_pubs** :世界范围内被引用次数最多的前 10%的科学出版物占该国全部科学出版物的百分比。
*   **内部中小企业**:内部创新的中小企业占中小企业的百分比。
*   **中小企业 _ 营销**:引入营销或组织创新的中小企业占中小企业的百分比。

# 建模和实施

首先,使用相关性分析来避免在分析中包括高度相关的特征。然后,简要描述了时间序列分类过程的建模技术。

下图显示了希腊指标的关联热图。出于可视化和解释的目的,热图用于呈现成对相关分析。为避免多重共线性问题,丢弃高度相关要素的阈值设置为 **0.90** 。但是,这个阈值仍然被认为是一个高值。使用阈值 **0.70** 当然更好,但是数据特征的数量有限。因此,具有 **0.90** 相关性的特征将从分析中删除。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/cde4c139e8742f47962d1dec2ccb8ffd.png)

因此,应删除以下指标:

*   每十亿国内生产总值的商标申请量(PPS)
*   知识密集型活动中的就业(占总就业的%)
*   每百万人口的国际科学合作出版物,
*   知识密集型服务出口占总服务出口的百分比,
*   25-64 岁参与终身学习人口百分比,
*   商业部门的研发支出(占国内生产总值的%)
*   公共部门的研发支出(占国内生产总值的%)
*   新上市和新公司创新的销售额占营业额的百分比,
*   世界上被引用次数最多的前 10%的科学出版物占该国全部科学出版物的百分比,
*   内部创新的中小企业占中小企业的百分比,
*   采用营销或组织创新的中小企业占中小企业的百分比,
*   引入产品或工艺创新的中小企业占中小企业的百分比。

接下来,描述了用于分类目的的时间序列建模技术。构建了一个向量 ***v*** ,该向量使用以下技术对时间范围(2010-2017)内的综合创新指数波动进行建模:

*   步长等于一年的滑动窗口从时间帧的开始开始,并且如果本年度的汇总创新指数的值高于上一年度的值,则 ***v*** =1,否则 ***v*** =0。因此,这是一个二元分类问题,特征矩阵为 ***X*** 指标,标号为 ***y*** 向量为 ***v*** 。

然后,使用三重交叉验证方法训练四个机器学习模型,即**逻辑回归****SVM** (线性核)、**随机森林**分类器和**额外树**分类器。数据实例有限的事实导致我们对模型进行交叉验证训练,特别是三重交叉验证。保持模型对 3 个折叠中每个折叠的特征重要性的估计。然后,重要性的最终值是每个模型的这 3 个折叠的平均值。每个基于模型的重要性值被转换为每个模型的百分比。最后,特征重要性的总结是来自每个模型的指标重要性的所有百分比值的平均值。

# 结果

下面是一个图表,以百分比形式总结了希腊指标的特征重要性。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5d78bd3ec08197dd1fdb8faceb5f1301.png)

毫无疑问,风险资本在希腊的创新产出中发挥着重要作用。具体来说,这是初创企业和企业家最关心的问题之一。它为创新铺平了道路,并允许它们被设计成适销对路的产品。它有助于为商业想法提供资金,否则这些想法将没有机会获得必要的资本。因此,创新技术和服务的发展在国家创新产出中发挥着关键作用。

此外,希腊还倾向于严重依赖受过良好教育的人和有创造力的中小企业来增加创新生产。新的博士毕业生和 25-34 岁的大学毕业生无疑在创新生产中发挥着重要作用。大多数创新的想法来自受过教育的人。在希腊,中小企业占该国私营部门总数的 99.9%。具体来说,微型企业约占私营部门的 96.6%,约占希腊经济总就业人数的 56%。换言之,中小企业是希腊经济中最重要的部分,直接影响着经济生活的金融和社会层面。与其他公司或组织合作的创新型中小企业是希腊企业家精神的一个重要标志。公共研究机构和公司之间以及公司和其他企业之间的专业知识转移似乎对创新的产生很重要。

# 结论

在这篇文章中,使用机器学习对创新指标的重要性进行了分析。通过对希腊综合创新指数采用建模技术,评估了希腊指标对其波动的影响。基于模型的希腊特征重要性分析是使用四个众所周知的分类器模型实现的。结果显示,排名前五位的重要特征是*设计申请*、*风险投资*、*25-34 岁完成高等教育的人口比例*、*每 1000 名 25-34 岁人口中新增博士毕业生*和*与他人合作的创新型中小企业*。

# 参考

[1] R .卡内基和澳大利亚商业理事会。管理创新企业:澳大利亚公司与世界最佳竞争。商业图书馆,1993 年,第 427 页,ISBN: 1863501517。【在线】。可用:[https://catalogue . nla . gov.au/Record/1573090](https://catalogue.nla.gov.au/Record/1573090)。

[2] H. Tohidi 和 M. M. Jabbari,“创新的重要性及其在组织成长、生存和成功中的关键作用”,《Procedia 技术》,第 1 卷,第 535-538 页,2012 年 1 月,ISSN:2212-0173。DOI:10.1016/j . protcy . 2012 . 02 . 116 .[在线]。可用:[https://www . science direct . com/science/article/pii/s 221201731200117 x](https://www.sciencedirect.com/science/article/pii/S221201731200117X)

[3]监测创新|内部市场、工业、企业家精神和中小企业。【在线】。可用:[https://ec.europa.eu/growth/industry/innovation/事实-数字 _en](https://ec.europa.eu/growth/industry/innovation/facts-figures_en) 。

[4]欧盟委员会,DocsRoom —欧盟委员会 EIS 2018 方法论报告,2018。【在线】。可用:[https://ec.europa.eu/docsroom/documents/30081](https://ec.europa.eu/docsroom/documents/30081)。

[5] I. Guyon 和 A. Elisseeff,“变量和特征选择导论”,机器学习研究杂志,第 3 卷,第 3 号,第 1157-1182 页,2003 年,ISSN:ISSN 1533-7928。【在线】。可用:【http://jmlr.csail.mit.edu/papers/v3/guyon03a.html】T2。

[6] M. L. Bermingham,R. Pong-Wong,A. Spiliopoulou,C. Hayward,I. Rudan,H. Campbell,A. F. Wright,J. F. Wilson,F. Agakov,P. Navarro 和 C. S. Haley,“高维特征选择的应用:对人类基因组预测的评估”,《科学报告》,第 5 卷,第 1 期,第 10-312 页,2015 年 9 月,ISSN:2045-2322。DOI: 10.1038/srep10312。【在线】。可用:【https://www.nature.com/articles/srep10312】T4。

[7] D. W. Hosmer 和 S. Lemeshow,应用逻辑回归。美国新泽西州霍博肯:约翰威利父子公司,2000 年 9 月,ISBN: 9780471722144。DOI: 10.1002/ 0471722146。【在线】。可用:[http://doi.wiley.com/10.1002/0471722146.](http://doi.wiley.com/10.1002/0471722146.)

[8] T. K. Ho,“随机决策森林”,载于第三届国际文件分析和识别会议录(第 1 卷)——第 1 卷,ser 美国 DC 华盛顿州 IC Dar ' 95:IEEE 计算机学会,1995 年,第 278 页,ISBN:0–8186–7128–9。【在线】。可用:[https://dl.acm.org/citation.cfm?id=%20844379.844681](https://dl.acm.org/citation.cfm?id=%20844379.844681)。

[9] P. Geurts、D. Ernst 和 L. Wehenkel,“极度随机化的树”,Mach Learn (2006 年。DOI:10.1007/s 10994–006–6226–1。【在线】。可用:[http://citeseerx.ist.psu.edu/viewdoc/download?doi = 10 . 1 . 1 . 65 . 7485&rep = re P1&type = pdf](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.65.7485&rep=rep1&type=pdf)。

[10] V. Vapnik,“统计学习理论概述”,IEEE 神经网络汇刊,第 10 卷,第 5 期,第 988-999 页,1999 年,ISSN: 10459227。DOI: 10.1109/72.788640。【在线】。可用:[https://ieeexplore.ieee.org/document/788640](https://ieeexplore.ieee.org/document/788640)。

# 损失函数在机器学习中的重要性

> 原文:<https://towardsdatascience.com/importance-of-loss-function-in-machine-learning-eddaaec69519?source=collection_archive---------9----------------------->

最初发表于 [OpenGenus IQ](https://iq.opengenus.org/importance-of-loss-function/) 。

答假设给你一个任务,用 10 公斤沙子装满一个袋子。你把它装满,直到测量机器给你一个 10 公斤的精确读数,或者如果读数超过 10 公斤,你就把沙子拿出来。

就像那个称重机,如果你的预测是错的,你的损失函数会输出一个更高的数字。如果他们很好,它会输出一个较低的数字。当你试验你的算法来尝试和改进你的模型时,你的损失函数会告诉你是否有所进展。

> *“我们要最小化或最大化的函数叫做目标函数或准则。当我们将其最小化时,我们也可以称之为成本函数、损失函数或误差函数”——*[*来源*](https://www.deeplearningbook.org/)

> 本质上,损失函数是对预测模型在预测预期结果(或价值)方面表现的度量。我们将学习问题转化为优化问题,定义一个损失函数,然后优化算法以最小化损失函数。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/33e565061fc63d4721d3a7c1cbd910ec.png)

# 损失函数有哪些类型?

最常用的损失函数有:

*   均方误差
*   绝对平均误差
*   对数似然损失
*   铰链损耗
*   胡伯损失

1.  **均方误差**

均方差(MSE)是基本损失函数的工作空间,因为它易于理解和实现,并且通常工作得很好。要计算 MSE,您需要获取模型预测值和地面真实值之间的差异,将其平方,然后在整个数据集内取平均值。
无论预测值和实际值的符号如何,结果总是正的,理想值为 0.0。

function to calculate MSE

def MSE(y_predicted, y_actual): squared_error = (y_predicted - y_actual) ** 2
sum_squared_error = np.sum(squared_error)
mse = sum_squared_error / y_actual.size return mse


**2。平均绝对误差**

平均绝对误差(MAE)在定义上与 MSE 略有不同,但有趣的是,它提供了几乎完全相反的性质。要计算 MAE,您需要获取模型预测和地面实况之间的差异,将绝对值应用于该差异,然后在整个数据集内进行平均。

function to calculate MAE

def MAE(y_predicted, y_actual):

abs_error = np.abs(y_predicted - y_actual)
sum_abs_error = np.sum(abs_error)
mae = sum_abs_error / y_actual.size

return mae

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/589cfce04abf5c114df0aa6b13866532.png)

MSE (blue) and MAE (red) loss functions

**3。对数似然损失**

这个损失函数也比较简单,常用于分类问题。在此,
使用交叉熵来测量两个概率分布之间的误差。

-(y_actual * log(y_predicted) + (1 - y_actual) * log(1 - y_predicted))


这里可以看到,当实际类为 1 时,函数的后半部分消失,当实际类为 0 时,前半部分下降。那样的话,我们最终会乘以实际预测概率的对数。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d72d5a2e0479d883ac3cca83f1d1e484.png)

Source: [fast.ai](https://www.fast.ai/)

二元或两类预测问题的交叉熵实际上是作为所有示例的平均交叉熵来计算的。

from math import log

function to calculate binary cross entropy

def binary_cross_entropy(actual, predicted):
sum_score = 0.0
for i in range(len(actual)):
sum_score += actual[i] * log(1e-15 + predicted[i])
mean_sum_score = 1.0 / len(actual) * sum_score
return -mean_sum_score


这个函数是 Kaggle 竞赛中最受欢迎的度量之一。这只是对数似然函数的简单修改。

**4。铰链损耗**

铰链损失函数在支持向量机中很流行。这些用于训练分类器。假设“t”是目标输出,使得 t = -1 或 1,并且分类器得分是“y”,则预测的铰链损失被给出为:`L(y) = max(0, 1-t.y)`

**5。胡贝尔损失**

我们知道 MSE 非常适合学习异常值,而 MAE 非常适合忽略它们。但是中间的东西呢?
考虑一个例子,我们有一个 100 个值的数据集,我们希望我们的模型被训练来预测。在所有这些数据中,25%的预期值是 5,而另外 75%是 10。

由于我们没有“异常值”,一个 MSE 损失不会完全解决问题;25%绝不是一个小分数。另一方面,我们不一定要用 MAE 来衡量太低的 25%。这些值 5 并不接近中值(10——因为 75%的点的值为 10 ),但它们也不是异常值。

# 我们的解决方案?

胡伯损失函数。

Huber Loss 通过同时平衡 MSE 和 MAE 提供了两个世界的最佳选择。我们可以使用以下分段函数来定义它:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9c9fe48e6ee9fac3e3403788ac89cb99.png)

这个等式的实际意思是,对于小于δ的损耗值,使用 MSE 对于大于 delta 的损失值,使用 MAE。这有效地结合了两个损失函数的优点。

function to calculate Huber loss

def huber_loss(y_predicted, y_actual, delta=1.0): huber_mse = 0.5*(y_actual-y_predicted)**2
huber_mae = delta * (np.abs(y_actual - y_predicted) - 0.5 * delta)

return np.where(np.abs(y_actual - y_predicted) <= delta, 
                         huber_mse,  huber_mae)

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/126836db3704474950bc7709fd7129f8.png)

MSE (blue), MAE (red) and Huber (green) loss functions

# 结论

损失函数提供的不仅仅是模型执行情况的静态表示,而是算法如何首先拟合数据。大多数机器学习算法在优化或为您的数据寻找最佳参数(权重)的过程中使用某种损失函数。

重要的是,损失函数的选择与神经网络输出层中使用的激活函数直接相关。这两个设计元素是联系在一起的。

将输出图层的配置视为对预测问题框架的选择,将损失函数的选择视为对问题给定框架的误差计算方式。

**进一步阅读**
[深度学习](https://www.deeplearningbook.org/)书作者*伊恩·古德菲勒、约舒阿·本吉奥和亚伦·库维尔*。

# 大数据时代采样的重要性

> 原文:<https://towardsdatascience.com/importance-of-sampling-in-the-era-of-big-data-d2cf83e06c6a?source=collection_archive---------20----------------------->

## 1936 年的教训

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/05e19c31443588d8982b2955b2367f8c.png)

数字时代的进步帮助我们克服了调查、研究和质量保证领域的统计抽样传统上面临的一些挑战。传统上,数据收集和处理的边际成本很高。现在,只需动动手指,收集、存储和处理大量数据就变得更加容易和快捷。在某些情况下,这导致了所谓的 [*大数据傲慢*](https://blogs.scientificamerican.com/observations/why-big-data-isnt-necessarily-better-data/) —假设大数据分析可以作为传统分析手段的替代而非补充。

本文的目的不是淡化大数据和大数据分析带来的优势,而是仅仅强调抽样的重要性。此外,应该警惕拥有大量数据将弥补分析中其他挑战的观念。

## **1936 年美国总统竞选的文学文摘民意调查**

在某种程度上,这可以被认为是 20 世纪 30 年代的“大数据”实验。1936 年,阿尔弗雷德·m·兰登(时任堪萨斯州州长)和在任的富兰克林·d·罗斯福分别代表共和党和民主党进行总统竞选。

《文学文摘》是当时备受尊重的新闻周刊。在那之前,他们一直顺风顺水——正确预测了自 1916 年以来总统选举的获胜者。他们大胆宣称将在 10 月举行 11 月的选举,发起了一场规模宏大的民意测验,邮件列表超过 1000 万。每个成员都收到了一张模拟选票,并被要求交回一张有标记的选票。约有 240 万人回复。根据这些回答,人们预测兰登将获得 57%的选票,而罗斯福将获得 43%的选票。但现实远非如此。罗斯福赢得了 46 个州和 60.8%的选票。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/932342979426f048f8892f444d7619cf.png)

Predicted vs. Actual share of popular vote Source: Qualtrics

与此同时,乔治·盖洛普通过仔细获取约 5 万人的样本,预测出了获胜者。

## 我们能从中学到什么?

> 即使您拥有的数据非常“大”,它也可能只代表一部分人口,而不代表全部人口!

在《文学文摘》的案例中,他们的邮件列表来源于电话簿、杂志订户列表、俱乐部会员名册等等。嗯……在 20 世纪 30 年代,电话是一种奢侈品,这个国家一直受到大萧条的困扰,经济问题成为竞选的主题是有原因的!有明显的迹象表明,对低收入群体存在选择偏见。

*在* ***机器学习*** *中,采样偏差会影响你的模型的性能。在训练和测试阶段,确保数据样本反映了您试图建模的相同基础分布是很重要的。*

> **在一个问题上投入计算资源(或金钱)并不总能解决问题**

花时间和精力选择合适的取样技术比对整个可及人群进行强力数据收集更有效。**的重点**不应该是增加样本量,而是**减少采样偏差**或其他误差。

> **有时候,少即是多!**

当数据量有限时,更容易控制数据的质量。花时间**去了解你的数据和收集数据的背景**是非常重要的。在通过模型运行数据之前,可视化和检查数据中的异常值或缺失值非常重要。此外,在错误分类中更容易发现错误。

当我们每天坐在越来越多的数据上时,你认为哪个统计概念更重要?欢迎在下面评论..

参考资料:

[](https://www.qualtrics.com/blog/the-1936-election-a-polling-catastrophe/) [## 1936 年的选举——一场投票灾难

### 在之前的帖子中,我们简要提到了 1936 年选举中一个经常被引用的投票错误。为了选举的荣誉…

www.qualtrics.com](https://www.qualtrics.com/blog/the-1936-election-a-polling-catastrophe/)

# 设定现实期望的重要性

> 原文:<https://towardsdatascience.com/importance-of-setting-realistic-expectations-4f23af01c956?source=collection_archive---------37----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f59e85406e7b8e199e606cabe0308800.png)

## 如果产品所有者有现实的期望,你的模型会更快地产生更大的影响

似乎每个公司现在都在建立数据科学团队,并投资机器学习平台,无论是第三方还是内部构建的。

然而,研究表明,很少有公司将机器学习模型部署到生产中[1]。虽然技术复杂性是原因之一,但不切实际的期望也是原因之一。

# 设定合理的期望值

开发机器学习模型需要大量投资。你需要雇佣数据科学家,投资大数据工具,建立/购买模型服务平台。因此,期望往往很高,有时过高。

为了确保人工智能项目的成功,数据科学家需要确保他们在开始建立模型之前就设定了现实的预期。如果预期无法实现,您将获得开发模型的批准,但它们永远不会投入生产。

设定期望可能会很复杂,但你可以做一些事情来帮助引导对话:

*   使用现有流程作为基线
*   谈谈误报和漏报——你在优化什么?
*   用一个简单的模型来设定期望值

# 使用现有流程作为基线

机器学习模型通常会取代或自动化现有流程。查看这些流程,并尝试量化其整体性能(准确性、假阳性/假阴性率、预测时间等)。这将给你一个你的模型需要达到的基线。

> *除非您的模型与现有流程的性能相匹配,否则无论节省多少成本,都不会部署该模型*

不要花太多时间考虑解决方案的总体成本,更多地关注整体模型的性能。这里的目标不是定义企业通过实施机器学习解决方案可以节省多少成本,而是了解您的模型预计将达到什么样的性能水平。

# 定义可接受的误报率和漏报率

在设定期望值时,我们首先考虑的是准确性。它很容易理解,通常是与产品负责人交谈时的神起点。

然而,仅仅同意一个目标精度是不够的。几乎在所有应用中,误报的业务成本都不同于漏报的成本。在很多情况下,成本可以相差一个数量级!

以欺诈预测为例。让我们假设你以 100 英镑的价格出售一件产品,利润率为 20%。这意味着一次销售将产生 20 英镑的利润但如果有人用偷来的卡购买产品你将损失 80 英镑(生产成本)外加支付处理商收取的费用(可能在 20 英镑左右)。在这种情况下,误报的成本是 20,而误报的成本是 100!因此,你的模型理论上可以有一个比假阳性率高 5 倍的假阴性率,并且仍然是有利可图的。

# 用一个简单的模型来设定期望值

部署一个机器学习模型涉及许多活动部件,从服务到监控。您部署的第一个模型必须相对简单,因为重点是围绕该模型的基础设施和流程。

> *模型的第一次迭代是关于建立流程,而不是关于性能*

在花太多时间在其他事情上之前,开始开发一个非常简单的模型,很少或没有特征工程。假设这将是部署的第一个模型。

如果简单模型没有达到在阶段 1 和阶段 2 中与产品所有者达成一致的指标,您可以采取两种方法:

*   构建特征处理和复杂的模型,但是由于部署成本的原因,存在无法部署模型的风险
*   让产品负责人重新参与进来,为模型的第一个版本设定更现实的期望

在这些选项之间进行选择将取决于您的组织以及您正在开发的模型的战略性。在任何情况下,不要在没有与产品负责人讨论之前就开始。这可能看起来不多,但这可以将开发周期加快 10 倍。

# 结论

为了让机器学习模型在组织中得到广泛采用,数据科学团队需要在构建第一个模型之前让业务参与进来。

在项目开始时就性能度量标准达成一致,并定期与产品所有者进行核对,将有助于确保模型被快速部署。

参考资料:

*   [1]: [BCG-MIT 报告:2018 年人工智能在商业中的进展](https://www.linkedin.com/pulse/bcg-mit-report-progress-ai-business-2018-philipp-a-gerbert)

# 理解机器学习算法复杂性的重要性

> 原文:<https://towardsdatascience.com/importance-of-understanding-the-complexity-of-a-machine-learning-algorithm-9d0532685982?source=collection_archive---------14----------------------->

## 运行时分析

## 解释理解机器学习算法的内部工作的重要性,它在实现和评估中的不同。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/75905f8ea2da6a525d48cebac894bca7.png)

Photo by [Vincent Botta](https://unsplash.com/@0asa?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/inner-workings?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

机器学习工程师经常会发现自己需要为手头的问题选择正确的算法。通常情况下,他们首先理解他们提供解决方案的问题的结构。然后他们研究手边的数据集。经过最初的观察和关键的总结,他们最终为任务选择了正确的算法。

决定应用于手头数据集的最佳算法似乎是一项微不足道的工作。工程师经常在这些情况下创建捷径。如果任务有 0–1 标签,就应用逻辑回归,对吗?不对!我们应该意识到这些捷径,并时刻提醒自己,尽管某些算法对特定问题很有效,但在为问题选择最佳算法时,并没有“处方”。然而,算法的复杂性和运行时分析应该经常被讨论和考虑。

算法的运行时分析不仅对理解算法的内部工作至关重要,而且还能产生更成功的实现。

在本文的其余部分,我将描述一种情况,忽略对算法的运行时分析,在这种情况下 k 意味着集群,会导致工程师损失大量的时间和精力。

# 什么是 K 均值聚类

K-means 聚类是最流行且易于实现的无监督机器学习算法之一。也是容易理解的机器学习算法之一。

通常,无监督的机器学习算法仅使用特征向量从输入数据集进行推断。因此,这些算法适用于没有标签数据的数据集。当想要从大量结构化和非结构化数据中提取价值或洞察力时,它们也非常有用。K-means 聚类是这些探索性数据分析技术中的一种,其目标是提取数据点子组,使得同一聚类中的数据点在定义的特征方面非常相似。

# K-均值聚类是如何工作的

K-means 聚类从第一组随机选择的数据点开始,这些数据点被用作质心的初始种子。然后,该算法执行迭代计算,将剩余的数据点分配给最近的聚类。当根据定义的距离函数执行这些计算时,质心的位置被更新。当出现以下任一情况时,它会停止优化聚类中心:

*   质心的位置是稳定的,即它们的值的变化不超过预定的阈值。
*   该算法超过了最大迭代次数。

因此,算法的复杂度是

O(n * K * I * d)n : number of points
K : number of clusters
I : number of iterations
d : number of attributes


# K-means 算法例题

我将分享一个 k 均值聚类任务的代码片段。我的唯一目的是演示一个例子,其中未能理解运行时的复杂性会导致对算法的糟糕评估。我所采取的步骤并没有针对算法进行优化,也就是说,你可以更好地预处理数据并得到更好的聚类。涉及的步骤概述如下:

1.  *导入库,并读取数据集。在这里,我导入相关的库并读取数据集,我已经将数据集下载到了本地文件夹中。*
2.  *预处理。在这一步中,我放弃了字符串类型的列,只关注数字特性。由于 k-means 聚类分析计算数据点之间的距离,因此它适用于数值列。*
3.  *应用主成分分析进行降维。在应用 k-means 聚类之前降低数据集的维度通常是一种好的做法,因为在高维空间中,距离度量并不十分有效。*
4.  *计算剪影分数。K-means 聚类不直接应用。它涉及到寻找最佳聚类数的问题。轮廓分数是可用于确定最佳聚类数的技术之一。不理解剪影分数分析中所涉及的计算的复杂性将导致较差的实现。*
5.  *替代方案。在这里,我列出了一些找到最佳集群数量的备选解决方案。就运行时间复杂性而言,与剪影分数相比,它们是有利的。*

您可以重现问题来试一试。数据集的链接:[https://www.kaggle.com/sobhanmoosavi/us-accidents](https://www.kaggle.com/sobhanmoosavi/us-accidents)。

## 步骤 1:导入库并读取数据集

## 第二步:预处理

出于说明目的,我们仅根据道路相关特征对数据点进行聚类。

## 第三步:应用主成分分析降低维数

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/340a57ae698735e3058b88795c41efd3.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/026e2010abd976d3ae5b7258dfad164f.png)

似乎 3 是最佳的。

## 步骤 4:计算剪影分数

有许多指标和方法可用于确定最佳聚类数。但我将集中讨论其中的几个。轮廓分数是这些度量之一。它是使用每个实例的平均类内距离和平均最近类距离来计算的。它计算每个样本与各个聚类中其余样本之间的距离。因此它的运行时间复杂度是 O(n)。如果不执行运行时分析,您可能需要等待数小时(如果不是数天)才能完成对大型数据集的分析。由于当前数据集有数百万行,一种解决方法是使用更简单的度量标准,如惯性或对数据集应用随机抽样。我将展示这两种选择。

## 第五步:替代解决方案

*   **肘法**

这种方法使用惯性或类内平方和作为输入。它描述了随着聚类数量的增加惯性值的减少。“肘”(曲线上的拐点)是惯性值的减少没有显著变化的点的良好指示。使用这种技术的优点是组内平方和不像轮廓分数那样计算昂贵,并且已经作为度量包括在算法中。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/09fa7075ce05288bed0e9c4a527bb20e.png)

上面代码片段的挂钟时间是:

27.9 s ± 247 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


*   **随机下采样**

缩减采样允许您处理更小的数据集。这样做的好处是算法完成的时间大大减少了。这使得分析师能够更快地工作。缺点是,如果随机进行下采样,可能无法表示原始数据集。因此,任何涉及缩减采样数据集的分析都可能导致不准确的结果。但是,您可以始终采取预防措施,确保缩减采样数据集代表原始数据集。

上面代码片段的挂钟时间是:

3min 25s ± 640 ms per loop (mean ± std. dev. of 2 runs, 1 loop each)


**结束语**

在这篇文章中,我试图强调理解机器学习算法的复杂性的重要性。算法的运行时分析不仅对特定任务中的算法选择至关重要,而且对成功实现也很重要。这也是大多数雇主在数据科学领域寻求的关键技能之一。因此,做运行时分析和理解算法的复杂性总是一个好的实践。

*如果你对这个帖子有任何疑问,或者对数据科学有任何疑问,你可以在*[***Linkedin***](http://www.linkedin.com/in/baran-köseoğlu-391b99b1)***上找到我。***

# 重要性抽样介绍

> 原文:<https://towardsdatascience.com/importance-sampling-introduction-e76b2c32e744?source=collection_archive---------1----------------------->

## 估计不同分布的期望值

重要抽样是一种近似方法,而不是抽样方法。它来源于一个小小的数学变换,能够以另一种方式表述问题。在这篇文章中,我们将:

1.  学习重要性抽样的概念
2.  通过实施流程获得更深入的理解
3.  比较不同抽样分布的结果

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/154cff4de630170d1d8ce2fe731c5981.png)

# 什么是重要性抽样?

考虑一个场景,你试图计算函数`f(x)`的期望值,其中`x ~ p(x)`服从某种分布。我们对`E(f(x))`有如下估计:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9142634edef3e6f942b5877cdd556573.png)

蒙特卡罗抽样方法是简单地从分布`p(x)`中抽取`x`样本,并取所有样本的平均值,从而得到期望值的估计值。那么问题来了,如果`p(x)`很难采样呢?我们能够根据一些已知的和容易抽样的分布来估计期望值吗?

答案是肯定的。它来自一个简单的公式转换:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d6ba247a9975a45bf256e0dd1f5b8cf0.png)

其中`x`是从分布`q(x)`中取样的,且`q(x)`不应为 0。通过这种方式,估计期望能够从另一个分布中抽样`q(x)`,`p(x)/q(x)`被称为抽样比率或抽样权重,它作为一个校正权重来抵消从不同分布中抽样的概率。

我们需要讨论的另一件事是估计的方差:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1ccca24f5c6a78c8966faae98ba7ff24.png)

其中在这种情况下,`X`是`f(x)p(x)/q(x)`,所以如果`p(x)/q(x)`很大,这将导致很大的方差,这是我们肯定希望避免的。另一方面,也可以选择适当的`q(x)`来产生更小的变化。我们来举个例子。

# 示范

首先,让我们定义函数`f(x)`和样本分布:

`f(x)`的曲线看起来像:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9b21decb3f2a7659e3cb62541ffe5f34.png)

现在我们来定义`p(x)`和`q(x)`的分布:

为了简单起见,这里`p(x)`和`q(x)`都是正态分布,你可以试着定义一些很难采样的`p(x)`。在我们的第一个演示中,让我们设置两个分布,它们具有相似的平均值(3 和 3.5)和相同的 sigma 1:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/fe2dbe99b0d3ba2f56973486dd314a6c.png)

现在我们能够计算从分布`p(x)`中采样的真实值

我们得到的估计值是 0.954。现在让我们从`q(x)`中取样,看看它的表现如何:

请注意,这里的`x_i`是从近似分布`q(x)`中抽取的,我们得到的估计值为 0.949,方差为 0.304。请注意,我们能够通过从不同的分布中取样来获得估计值!

## 比较

分布`q(x)`可能与`p(x)`过于相似,以至于你可能会怀疑重要性抽样的能力,现在让我们试试另一个分布:

带直方图:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/731c4158c2ef4ecbfab15e54ef14497e.png)

这里我们将`n`设置为 5000,当分布不同时,通常我们需要更多的样本来逼近该值。这次我们得到的估计值是 0.995,但是方差是 83.36。

原因来自`p(x)/q(x)`,因为两个分布相差太大可能会导致该值的巨大差异,从而增加方差。经验法则是定义`q(x)`,其中`p(x)|f(x)|`较大。([全面实施](https://github.com/MJeremy2017/Machine-Learning-Algorithm-Implemention))

**参考:**

[1][https://www.youtube.com/watch?v=3Mw6ivkDVZc](https://www.youtube.com/watch?v=3Mw6ivkDVZc)

[2][https://astro statistics . PSU . edu/su14/lectures/cisewski _ is . pdf](https://astrostatistics.psu.edu/su14/lectures/cisewski_is.pdf)

# 你需要知道的机器学习的重要话题

> 原文:<https://towardsdatascience.com/important-topics-in-machine-learning-you-need-to-know-21ad02cc6be5?source=collection_archive---------3----------------------->

## 机器学习基础

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/aefd3466d35ba7f3dbe9319e9800a253.png)

Robots (Photo by [Daniel Cheung](https://unsplash.com/@danielkcheung?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText))

机器学习现在是一个热门话题,每个人都试图获得任何关于这个话题的信息。关于机器学习的信息量如此之大,人们可能会不知所措。在这篇文章中,我列出了一些你需要知道的机器学习中最重要的主题,以及一些可以帮助你进一步阅读你有兴趣深入了解的主题的资源。

# **人工智能**

人工智能是计算机科学的一个分支,旨在创造模仿人类行为的智能机器,如知识、推理、解决问题、感知、学习、规划、操纵和移动物体的能力

人工智能是计算机科学的一个领域,它强调创造像人类一样工作和反应的智能机器。

[](https://en.wikipedia.org/wiki/Artificial_intelligence) [## 人工智能

### 在计算机科学中,人工智能(AI),有时称为机器智能,是智能证明…

en.wikipedia.org](https://en.wikipedia.org/wiki/Artificial_intelligence) [](https://searchenterpriseai.techtarget.com/definition/AI-Artificial-Intelligence) [## 什么是 AI(人工智能)?-WhatIs.com 的定义

### 人工智能是机器,尤其是计算机对人类智能过程的模拟

searchenterpriseai.techtarget.com](https://searchenterpriseai.techtarget.com/definition/AI-Artificial-Intelligence) 

# **机器学习(ML)**

机器学习属于人工智能的范畴,它为系统提供了自动学习和根据经验改进的能力,而无需显式编程。

学习的过程始于观察或数据,如例子、直接经验或指导,以便在数据中寻找模式,并根据我们提供的例子在未来做出更好的决策。

主要目的是让计算机在没有人类干预或帮助的情况下自动学习,并相应地调整行动。

[](https://en.wikipedia.org/wiki/Machine_learning) [## 机器学习

### 机器学习(ML)是对算法和统计模型的科学研究,计算机系统使用这些算法和统计模型来…

en.wikipedia.org](https://en.wikipedia.org/wiki/Machine_learning) [](https://www.expertsystem.com/machine-learning-definition/) [## 什么是机器学习?定义专家系统

### 机器学习是人工智能(AI)的一种应用,它为系统提供了自动…

www.expertsystem.com](https://www.expertsystem.com/machine-learning-definition/) [](https://medium.com/machine-learning-for-humans/why-machine-learning-matters-6164faf1df12) [## 人工智能/人工智能初学者指南🤖👶

### 机器学习终极指南。简单明了的英语解释伴随着数学,代码和现实世界…

medium.com](https://medium.com/machine-learning-for-humans/why-machine-learning-matters-6164faf1df12) 

# **监督学习**

监督学习是基于示例输入-输出对学习将输入映射到输出的函数的机器学习任务。监督学习算法分析训练数据并产生推断的函数,该函数可用于映射新的示例。

在监督学习中,我们已经标记了训练数据。

[](https://en.wikipedia.org/wiki/Supervised_learning) [## 监督学习

### 监督学习是一种机器学习任务,它学习一个函数,该函数基于…

en.wikipedia.org](https://en.wikipedia.org/wiki/Supervised_learning) [](https://www.coursera.org/lecture/machine-learning/supervised-learning-1VkCb) [## 监督学习-简介| Coursera

### 本课程视频抄本机器学习是让计算机在没有明确…

www.coursera.org](https://www.coursera.org/lecture/machine-learning/supervised-learning-1VkCb) 

# **无监督学习**

无监督学习是一种机器学习任务,它从由没有标记响应的输入数据组成的数据集进行推断。无监督学习的目标是对数据中的底层结构或分布进行建模,以便了解更多关于数据的信息。

聚类和关联是一些非监督学习子类别。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f54ba485f5c9cbb0cf4ec0793fefd6fb.png)

Photo by [Hans-Peter Gauster](https://unsplash.com/@sloppyperfectionist?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

[](https://en.wikipedia.org/wiki/Unsupervised_learning) [## 无监督学习

### 无监督学习是一种自组织的 Hebbian 学习,有助于在数据中发现以前未知的模式…

en.wikipedia.org](https://en.wikipedia.org/wiki/Unsupervised_learning)  [## 什么是无监督机器学习?数据机器人

### 无监督的机器学习算法从数据集推断模式,而不参考已知的或标记的…

www.datarobot.com](https://www.datarobot.com/wiki/unsupervised-machine-learning/) [](https://dataconomy.com/2015/01/whats-the-difference-between-supervised-and-unsupervised-learning/) [## 有监督学习和无监督学习有什么区别?

### 维基监督学习的定义监督学习是数据挖掘的任务,从标签中推断出一个函数

dataconomy.com](https://dataconomy.com/2015/01/whats-the-difference-between-supervised-and-unsupervised-learning/) 

# **神经网络或人工神经网络**

神经网络是一种生物启发的编程范式,它使计算机能够从观察数据中学习。人工神经网络的设计受到了人脑生物神经网络的启发,导致了一个远比标准机器学习模型更有能力的学习过程。

神经网络也称为人工神经网络,由输入层和输出层以及隐藏层组成,隐藏层由将输入转换为输出层可以使用的东西的单元组成。他们在需要寻找模式的任务中表现得非常好。

[](/understanding-neural-networks-19020b758230) [## 理解神经网络

### 我们探索神经网络如何运作,以建立对深度学习的直观理解

towardsdatascience.com](/understanding-neural-networks-19020b758230) [](http://neuralnetworksanddeeplearning.com/chap1.html) [## 神经网络和深度学习

### 人类视觉系统是世界奇迹之一。考虑下面的手写数字序列:大多数…

neuralnetworksanddeeplearning.com](http://neuralnetworksanddeeplearning.com/chap1.html) [](https://www.techradar.com/au/news/what-is-a-neural-network) [## 什么是神经网络?

### 神经网络是一种机器学习类型,它模仿人脑来模拟自身。这就造成了一种人为的…

www.techradar.com](https://www.techradar.com/au/news/what-is-a-neural-network) 

# **反向传播**

这是神经网络中的一个概念,它允许网络在结果与创造者希望的不匹配的情况下调整其隐藏的神经元层。

[](https://en.wikipedia.org/wiki/Backpropagation) [## 反向传播

### 反向传播算法是一系列用于有效训练人工神经网络的方法

en.wikipedia.org](https://en.wikipedia.org/wiki/Backpropagation) [](/how-does-back-propagation-in-artificial-neural-networks-work-c7cad873ea7) [## 人工神经网络中的反向传播是如何工作的?

### 自从机器学习的世界被引入到递归工作的非线性函数(即人工…

towardsdatascience.com](/how-does-back-propagation-in-artificial-neural-networks-work-c7cad873ea7) 

# **深度神经网络(DNN)或深度学习**

深度学习是机器学习的一个子集,其中多层神经网络堆叠在一起,创建了一个巨大的网络,将输入映射到输出。它允许网络提取不同的特征,直到它能够识别它正在寻找什么。

[](https://www.techopedia.com/definition/32902/deep-neural-network) [## 什么是深度神经网络?-来自 Techopedia 的定义

### 深度神经网络定义-深度神经网络是一种具有一定复杂程度的神经网络,一种神经…

www.techopedia.com](https://www.techopedia.com/definition/32902/deep-neural-network) [](/the-basics-of-deep-neural-networks-4dc39bff2c96) [## 深度神经网络的基础

### 随着 Tensorflow 2.0 和 Fastai 等库的兴起,实现深度学习已经变得触手可及

towardsdatascience.com](/the-basics-of-deep-neural-networks-4dc39bff2c96) [](https://www.coursera.org/learn/neural-networks-deep-learning) [## 神经网络和深度学习| Coursera

### 从 deeplearning.ai 学习神经网络和深度学习,如果你想打入前沿 ai,这门课…

www.coursera.org](https://www.coursera.org/learn/neural-networks-deep-learning) 

# **线性回归**

线性回归是一种基于监督学习的机器学习算法。它执行回归任务。回归基于独立变量对目标预测值进行建模。它主要用于找出变量和预测之间的关系。可以使用线性回归的任务的一个例子是根据过去的价值预测房价。

线性回归的成本函数是预测 y 值(pred)和真实 y 值(y)之间的均方根误差(RMSE)。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5c31ebdc31cfdce1642fda2f54ee438a.png)

Linear Regression (By Sewaqu — Own work, Public Domain, [https://commons.wikimedia.org/w/index.php?curid=11967659](https://commons.wikimedia.org/w/index.php?curid=11967659))

[](https://en.wikipedia.org/wiki/Linear_regression) [## 线性回归

### 在统计学中,线性回归是一种建模标量响应(或变量)之间关系的线性方法

en.wikipedia.org](https://en.wikipedia.org/wiki/Linear_regression) [](/linear-regression-detailed-view-ea73175f6e86) [## 线性回归-详细视图

### 线性回归用于寻找目标和一个或多个预测值之间的线性关系。有两个…

towardsdatascience.com](/linear-regression-detailed-view-ea73175f6e86) [](https://machinelearningmastery.com/linear-regression-for-machine-learning/) [## 机器学习的线性回归

### 线性回归也许是统计学和机器中最著名和最容易理解的算法之一

machinelearningmastery.com](https://machinelearningmastery.com/linear-regression-for-machine-learning/) 

# **逻辑回归**

逻辑回归是用于分类问题的监督机器学习算法。这是一种分类算法,用于将观察值分配给一组离散的类。分类问题的一些例子是垃圾邮件或非垃圾邮件、在线交易欺诈或非欺诈。

逻辑回归使用逻辑 sigmoid 函数转换其输出,以返回概率值。

有两种类型的逻辑回归:

1.  二进制的
2.  多类

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ca1ebb3eddc7f98fabcae5426e40913f.png)

Logistic Regression (By Michaelg2015 — Own work, CC BY-SA 4.0, [https://commons.wikimedia.org/w/index.php?curid=42442194](https://commons.wikimedia.org/w/index.php?curid=42442194))

[](/logistic-regression-detailed-overview-46c4da4303bc) [## 逻辑回归—详细概述

### 逻辑回归在二十世纪早期被用于生物科学。它后来被用于许多社会…

towardsdatascience.com](/logistic-regression-detailed-overview-46c4da4303bc) [](https://en.wikipedia.org/wiki/Logistic_regression) [## 逻辑回归

### 在统计学中,逻辑模型(或 logit 模型)用于模拟某一类或某一事件的概率…

en.wikipedia.org](https://en.wikipedia.org/wiki/Logistic_regression) [](https://www.statisticssolutions.com/what-is-logistic-regression/) [## 什么是逻辑回归?-统计解决方案

### 一个人体重每增加一磅,患肺癌的概率(是与否)会有怎样的变化…

www.statisticssolutions.com](https://www.statisticssolutions.com/what-is-logistic-regression/) 

# **K-最近邻(K-NN)**

k-最近邻(KNN)算法是一种简单、易于实现的监督机器学习算法,可用于解决分类和回归问题。

KNN 算法假设相似的事物存在于附近。换句话说,相似的事物彼此靠近。

可以用在推荐系统上。

KNN 的工作方式是找出查询和数据中所有示例之间的距离,选择最接近查询的指定数量的示例(K),然后投票选择最频繁的标签(在分类的情况下)或平均标签(在回归的情况下)。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4a2712930872980242ae2adcde3854fb.png)

K-NN (Photo by Antti Ajanki AnAj [CC BY-SA 3.0 ([http://creativecommons.org/licenses/by-sa/3.0/](http://creativecommons.org/licenses/by-sa/3.0/))])

[](https://medium.com/capital-one-tech/k-nearest-neighbors-knn-algorithm-for-machine-learning-e883219c8f26) [## 机器学习的 k-最近邻(KNN)算法

### 机器学习算法介绍系列的第 1 部分

medium.com](https://medium.com/capital-one-tech/k-nearest-neighbors-knn-algorithm-for-machine-learning-e883219c8f26) [](https://blog.usejournal.com/a-quick-introduction-to-k-nearest-neighbors-algorithm-62214cea29c7) [## K-最近邻算法快速介绍

### 大家好!今天我想谈谈 K-最近邻算法(或 KNN)。KNN 算法是一种…

blog.usejournal.com](https://blog.usejournal.com/a-quick-introduction-to-k-nearest-neighbors-algorithm-62214cea29c7)  [## KNN 分类

### 编辑描述

www.saedsayad.com](https://www.saedsayad.com/k_nearest_neighbors.htm) 

# **随机森林**

随机森林就像一种通用的机器学习技术,可用于回归和分类目的。它由大量单独的决策树组成,这些决策树作为一个整体运行。随机森林中的每个单独的决策树都给出一个类别预测,拥有最多票数的类别成为我们模型的预测。

一般来说,随机森林模型不会过度拟合,即使过度拟合,也很容易阻止它过度拟合。

随机森林模型不需要单独的验证集。

它只做了一些统计假设。不假设您的数据是正态分布的,也不假设关系是线性的。

它只需要很少的特征工程。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/2a4c96a6664a9dabd0fd7608511a8f65.png)

Random Forest ([Source](https://www.researchgate.net/figure/Random-forest-model-Example-of-training-and-classification-processes-using-random_fig5_280533599))

[](/things-i-learned-about-random-forest-machine-learning-algorithm-40fde28fa89e) [## 我学到的关于随机森林机器学习算法的东西

### 第一课概述:Fast.ai 机器学习课程随机森林介绍

towardsdatascience.com](/things-i-learned-about-random-forest-machine-learning-algorithm-40fde28fa89e) [](/understanding-random-forest-58381e0602d2) [## 了解随机森林

### 该算法如何工作以及为什么如此有效

towardsdatascience.com](/understanding-random-forest-58381e0602d2) 

# **合奏学习**

集成学习通过组合几个模型来帮助改善机器学习结果。与单一模型相比,这种方法可以产生更好的性能。

集成方法是一种元算法,它将几种机器学习技术结合到一个预测模型中,以减少方差(bagging)、偏差(boosting)或改善预测(stacking)。

例子是随机森林,梯度提升决策树,ADA 提升。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6b90bd13764af8bfc5b71ff9681ddcad.png)

Ensembling ([Source](https://medium.com/mlreview/gradient-boosting-from-scratch-1e317ae4587d))

[](/simple-guide-for-ensemble-learning-methods-d87cc68705a2) [## 集成学习方法简单指南

### 什么,为什么,如何和装袋——推进去神秘化,而非传统的解释,读下去:)

towardsdatascience.com](/simple-guide-for-ensemble-learning-methods-d87cc68705a2) [](/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205) [## 整体方法:装袋、助推和堆叠

### 理解集成学习的关键概念。

towardsdatascience.com](/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205) 

# **梯度提升决策树**

Boosting 是一种集成技术,其中预测器不是独立产生的,而是顺序产生的。

这是一种将弱学习者转化为强学习者的方法。梯度增强是增强的一个例子。它是一种用于回归和分类问题的机器学习技术,它以集成或弱预测模型的形式产生预测模型,通常是决策树。

[](https://medium.com/mlreview/gradient-boosting-from-scratch-1e317ae4587d) [## 从零开始的渐变提升

### 简化复杂的算法

medium.com](https://medium.com/mlreview/gradient-boosting-from-scratch-1e317ae4587d) [](http://blog.kaggle.com/2017/01/23/a-kaggle-master-explains-gradient-boosting/) [## 一位 Kaggle 大师解释梯度推进

### 如果线性回归是丰田凯美瑞,那么梯度推进将是 UH-60 黑鹰直升机。一个特别的…

blog.kaggle.com](http://blog.kaggle.com/2017/01/23/a-kaggle-master-explains-gradient-boosting/) 

# **过拟合**

当模型对训练数据建模得太好时,就会发生过度拟合。

当模型学习训练数据中的细节和噪声达到对新数据的模型性能产生负面影响的程度时,就会发生过度拟合。它会对模型的概括能力产生负面影响。

可以通过以下方式预防:

1.  交叉验证
2.  正规化

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3abf034d3788250bf4e288189298fa08.png)

Overfitting ([Source](https://commons.wikimedia.org/wiki/File:Overfitting.svg))

[](https://elitedatascience.com/overfitting-in-machine-learning) [## 机器学习中的过度拟合:什么是过度拟合以及如何防止过度拟合

### 你知道有一个错误吗......成千上万的数据科学初学者在不知不觉中犯的错误?还有这个…

elitedatascience.com](https://elitedatascience.com/overfitting-in-machine-learning) [](https://machinelearningmastery.com/overfitting-and-underfitting-with-machine-learning-algorithms/) [## 机器学习算法的过拟合和欠拟合

### 机器学习性能不佳的原因是数据过拟合或欠拟合。在这篇文章中,你…

machinelearningmastery.com](https://machinelearningmastery.com/overfitting-and-underfitting-with-machine-learning-algorithms/) 

# **欠适**

欠拟合指的是既不能对训练数据建模也不能推广到新数据的模型。它将在训练数据上表现不佳。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e3d62a79486032d0c13dda15f074b820.png)

Underfitting ([Source](http://christianherta.de/lehre/dataScience/machineLearning/basics/pics/zeichnungen-twoClass-not-linear-separable-underfitting.png))

[](https://chemicalstatistician.wordpress.com/2014/03/19/machine-learning-lesson-of-the-day-overfitting-and-underfitting/) [## 今天的机器学习课——过度拟合和欠拟合

### 当统计模型或机器学习算法捕捉到数据的噪声时,就会发生过拟合。直觉上…

chemicalstatistician.wordpress.com](https://chemicalstatistician.wordpress.com/2014/03/19/machine-learning-lesson-of-the-day-overfitting-and-underfitting/) [](https://medium.com/greyatom/what-is-underfitting-and-overfitting-in-machine-learning-and-how-to-deal-with-it-6803a989c76) [## 机器学习中什么是欠拟合和过拟合,如何处理。

### 每当处理一个数据集来预测或分类一个问题时,我们倾向于通过实现一个设计…

medium.com](https://medium.com/greyatom/what-is-underfitting-and-overfitting-in-machine-learning-and-how-to-deal-with-it-6803a989c76) [](https://www.datarobot.com/wiki/underfitting/) [## 什么是欠拟合|数据机器人人工智能维基

### 当机器学习模型不够复杂,无法准确地…

www.datarobot.com](https://www.datarobot.com/wiki/underfitting/) 

# **正规化**

正则化是一种修改机器学习模型以避免过拟合问题的技术。你可以将正则化应用于任何机器学习模型。正则化通过向目标函数添加惩罚项来简化容易过度拟合的过于复杂的模型。如果一个模型过度拟合,它将有泛化的问题,因此当它暴露于新的数据集时,将给出不准确的预测。

[](/regularization-in-machine-learning-76441ddcf99a) [## 机器学习中的正则化

### 训练机器学习模型的一个主要方面是避免过度拟合。该模型将有一个低…

towardsdatascience.com](/regularization-in-machine-learning-76441ddcf99a) [](/all-you-need-to-know-about-regularization-b04fc4300369) [## 关于正规化,你需要知道的是

### 艾丽斯:嘿,鲍勃!!!我已经训练了我的模型 10 个小时了,但是我的模型精度很差,虽然它…

towardsdatascience.com](/all-you-need-to-know-about-regularization-b04fc4300369) 

# **L1 vs L2 正规化**

使用 L1 正则化技术的回归模型称为 Lasso 回归。使用 L2 正则化技术的模型被称为刚性回归。

两者之间的关键区别是添加到损失函数中的惩罚项。

刚性回归将系数的“平方值”作为惩罚项添加到损失函数中。Lasso 回归(最小绝对收缩和选择算子)将系数的“绝对值”作为惩罚项添加到损失函数中。

[](https://medium.com/datadriveninvestor/l1-l2-regularization-7f1b4fe948f2) [## L1 L2 正则化

### 在这篇文章中,我们将了解为什么我们需要正规化,什么是正规化,什么是不同类型的…

medium.com](https://medium.com/datadriveninvestor/l1-l2-regularization-7f1b4fe948f2) [](https://developers.google.com/machine-learning/crash-course/regularization-for-simplicity/l2-regularization) [## 为了简单而正规化:L₂正规化|机器学习速成班|谷歌…

### 估计时间:7 分钟考虑以下一般化曲线,该曲线显示了训练集…

developers.google.com](https://developers.google.com/machine-learning/crash-course/regularization-for-simplicity/l2-regularization) [](http://www.chioka.in/differences-between-l1-and-l2-as-loss-function-and-regularization/) [## L1 和 L2 作为损失函数和正则化的差异

### 2014/11/30:通过经过验证的方案图更新了 L1-诺姆与 L2-诺姆损失函数。感谢读者的…

www.chioka.in](http://www.chioka.in/differences-between-l1-and-l2-as-loss-function-and-regularization/) 

# **交叉验证**

交叉验证是一种评估机器学习模型的技术,通过在可用输入数据的子集上训练几个 ML 模型,并在数据的互补子集上评估它们。它用于防止模型过度拟合。

不同类型的交叉验证技术有:

1.  保持方法
2.  k 倍(最受欢迎)
3.  漏接

[](/cross-validation-70289113a072) [## 交叉验证

### 验证可能是数据科学家使用的最重要的技术之一,因为总是需要…

towardsdatascience.com](/cross-validation-70289113a072) [](/why-and-how-to-cross-validate-a-model-d6424b45261f) [## 为什么以及如何交叉验证模型?

### 一旦我们完成了对模型的训练,我们就不能假设它会在数据上很好地工作,如果它没有…

towardsdatascience.com](/why-and-how-to-cross-validate-a-model-d6424b45261f) 

# **回归性能指标**

**平均绝对误差(MAE):** 测量实际值和预测值之间的平均绝对差值。

**均方根误差(RMSE):** 测量实际值和预测值之间的平方差的平均值的平方根。

[](https://becominghuman.ai/understand-regression-performance-metrics-bdb0e7fcc1b3) [## 了解回归性能指标

### 请不要让你的表现退步。

becominghuman.ai](https://becominghuman.ai/understand-regression-performance-metrics-bdb0e7fcc1b3) [](https://medium.com/usf-msds/choosing-the-right-metric-for-machine-learning-models-part-1-a99d7d7414e4) [## 为评估机器学习模型选择正确的度量标准—第 1 部分

### 本系列的第一部分关注回归度量

medium.com](https://medium.com/usf-msds/choosing-the-right-metric-for-machine-learning-models-part-1-a99d7d7414e4) [](https://medium.com/human-in-a-machine-world/mae-and-rmse-which-metric-is-better-e60ac3bde13d) [## 梅和 RMSE——哪个指标更好?

### 平均绝对误差与均方根误差

medium.com](https://medium.com/human-in-a-machine-world/mae-and-rmse-which-metric-is-better-e60ac3bde13d) 

# **分类问题的性能指标**

**混淆矩阵:**它是用于发现模型正确性和准确性的最直观和最容易的度量之一。它用于分类问题,其中输出可以是两种或多种类型的类。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a59edc34db913a612481f6a60e6340d1.png)

Confusion Matrix ([Source](/understanding-confusion-matrix-a9ad42dcfd62))

**真阳性(TP):** 是数据点的实际类别为 1(真)且预测类别也为 1(真)的情况。

**真阴性(TN):** 是数据点的实际类别为 0(假)且预测类别也为 0(假)的情况。

**假阳性(FP):** 是数据点的实际类别为 0(假)而预测类别为 1(真)的情况。False 是因为模型预测不正确,而正数是因为预测的类是正数。

**假阴性(FN):** 是数据点的实际类别为 1(真)而预测类别为 0(假)的情况。False 是因为模型预测不正确,负值是因为预测的类为负(0)。

**准确性:**分类问题中的准确性是模型在所有预测中做出的正确预测的数量。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b4576d27491b6cc75bf6a9df4f0ae645.png)

Accuracy in the confusion matrix ([Source](http://cdn-images-1.medium.com/max/800/1*5XuZ_86Rfce3qyLt7XMlhw.png))

**何时使用精度:**当数据中的目标变量类接近平衡时,精度是一个很好的度量。

何时不使用精确度:当数据中的目标变量类是一个类的大多数时,精确度决不应该被用作度量。

**Precision(hits):**Precision 是一种度量,它告诉我们预测值为真的比例实际上是真的。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5133db49f1b0db213f11b79ecfbb76a3.png)

**回忆或敏感度(缺失):**回忆是一种度量,它告诉我们有多少比例的患者实际上是真实的,而被模型预测为真实的。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8844da629fc9b7d3710732ddf6cca2ab.png)

**F1 评分:**同时代表了查准率和查全率。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4dd6b0faa8eff8f31441f1744a032e4e.png)

F1 Score ([Source](https://www.oreilly.com/library/view/hands-on-recommendation-systems/9781788993753/assets/dcd94ad1-96f6-4e27-84c9-d6f42e1efee2.png))

**受试者工作特性(ROC)曲线:**ROC 曲线是显示分类模型在所有分类阈值下的性能的图表。

该曲线绘制了两个参数:

1.  真实阳性率(回忆)
2.  假阳性率(特异性)

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e94ccf6d24eaaa5e4dabea4d5c91bb15.png)

ROC Curve ([Source](https://www.statisticshowto.datasciencecentral.com/wp-content/uploads/2016/08/ROC-curve.png))

**AUC(ROC 曲线下面积):** AUC 测量整个 ROC 曲线下的整个二维面积。

它提供了跨所有可能的分类阈值的综合性能度量。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d38417916cf6ef7ba5a3ff973d832f94.png)

Area under ROC curve ([Source](https://miro.medium.com/max/722/1*pk05QGzoWhCgRiiFbz-oKQ.png))

[](https://medium.com/thalus-ai/performance-metrics-for-classification-problems-in-machine-learning-part-i-b085d432082b) [## 机器学习中分类问题的性能度量

### “数字有一个重要的故事要讲。他们依靠你给他们一个声音。”—斯蒂芬·诺

medium.com](https://medium.com/thalus-ai/performance-metrics-for-classification-problems-in-machine-learning-part-i-b085d432082b) [](/understanding-confusion-matrix-a9ad42dcfd62) [## 理解混淆矩阵

### 当我们得到数据,经过数据清洗,预处理和争论,我们做的第一步是把它提供给一个…

towardsdatascience.com](/understanding-confusion-matrix-a9ad42dcfd62) 

上面讨论的主题是机器学习的基础。我们讨论了人工智能、机器学习和深度学习等基本术语,不同类型的机器学习:监督和非监督学习,一些机器学习算法,如线性回归、逻辑回归、k-nn 和随机森林,以及不同算法的性能评估矩阵。

你认为哪个话题最重要?请在下面留下你的想法。

# 帮助您成为更好的数据科学经理的重要特征

> 原文:<https://towardsdatascience.com/important-traits-to-help-you-become-a-better-data-science-manager-dc0de3a37961?source=collection_archive---------25----------------------->

## 管理点,基于我管理两个数据科学家团队的经验。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ec208814da88ab48afd225c0bafbe062.png)

*Pão de Açúcar,* Rio de Janeiro, Brazil. Ori Cohen.

以下几点是基于我领导一个小型数据科学家团队的经验,但是,我相信它们可以让任何未来或现有的经理受益,不仅仅是研究和数据科学。这些是我一直努力坚持的价值观,去年,我和两个非常有才华的数据科学家团队一起,改进、推进并成功管理了 56 个项目,从小概念验证到大型项目。

## 一般管理:

1.  向你过去最好和最差的经理学习。我学会了将团队成员视为同事,而不是“我的员工”,授权、信任并允许他们领导自己的项目。另一方面,我认识到微观管理是一个可怕的想法,因为它不会带来最好的人。
2.  保持一个可以犯错的良好环境,研究不是防弹的,结果是未知的,我们需要犯错来提供一个可行的解决方案。这样的环境可以减少压力和恐惧。因此,你的团队成员永远不会害怕向你提出错误。总的来说,错误帮助我们前进,更不用说我们总能改正错误。
3.  信任你的团队成员,听从他们的想法和建议,让他们尽可能地发挥创造力。你是经理并不意味着你什么都知道。试着向你周围的每个人学习,包括你的团队,因为这将帮助你成为一个更好的管理者。
4.  当批评来临时,做他们的墙,防止他们偏离和偏离焦点。
5.  永远相信参与其中的每个人。感谢他人,尤其是如果你做了大部分工作,不会减少你的成就或投资。

## 数据科学管理

1.  灵活管理 DS 项目([数据科学?敏捷?周期?我管理高科技行业数据科学项目的方法](/data-science-agile-cycles-my-method-for-managing-data-science-projects-in-the-hi-tech-industry-b289e8a72818)
2.  通过每天坐下来和你的团队成员保持高水平的交流和冗余。当每个人都同步时,每个人都可以交叉交流,并在需要时代替你。
3.  提前停止——停止一个看起来没有成功机会或者已经达到饱和点的项目。
4.  打包您的可交付成果,确保它们已经过测试并准备好投入生产。
5.  如果可能的话,试着在项目中期制作一个“婴儿”产品,让你的数据工程师在完成项目的同时准备一个解决方案。
6.  有些时候,公司里的其他人会有一个想法,而你会有冲突或有义务去做。建议 A/B 测试可以调和利益相关者的竞争性本质,允许你测试两个想法或间接说服对方他们的想法的时间和精力太昂贵。
7.  当利益相关者要求某个指标时,比如准确性,询问[这是否真的是适合他们的指标](/why-business-product-should-always-define-kpis-goals-for-data-science-450404392990)。
8.  当有人问你在一个新的未定义项目中能达到什么样的成功水平时,告诉他们需要一个一到两周的 POC 来给他们一个答案。

## 追求知识

1.  始终处于当前研究的顶端( [TDS](https://towardsdatascience.com) 、 [Arxiv Sanity、](http://www.arxiv-sanity.com/) [ML review](https://www.facebook.com/groups/mlreview/) 、 [Ruder.io](http://ruder.io/) )
2.  始终将新技术和研究整合到现有项目中,这可以为您和您的团队积累经验,或者,创建简短的 POC 以验证新的研究想法。
3.  维护一个知识库([我的有 250 页长](https://docs.google.com/document/d/1wvtcwc8LOb3PZI9huQOD7UjqUoY98N5r3aQsWKNAlzk/edit))以便当你需要学习旧的东西时有 O(1)的时间复杂度。好的链接应该被总结和保存,第二次在谷歌上搜索同样的东西是浪费时间,它很容易缩短你的工作。
4.  让你的团队有时间获取知识。阅读新的研究不是浪费开发时间,它让我们在工作中做得更好。允许这种情况发生在项目的每一步。如果我们不掌握先进的研究、新的方法和想法,我们就会在专业上停滞不前。
5.  当一种新的研究方法证明了自己时,所有团队成员都应该了解它。
6.  在[媒体、](https://medium.com/@cohenori) [TDS](https://towardsdatascience.com) 或[学术渠道](https://scholar.google.co.il/citations?user=xYU1eqQAAAAJ&hl=en)上发布您的结果,并且始终将基于代码的文章与 [Github 资源库](https://github.com/orico)一起发布。

## 尝试新事物

1.  深入了解产品管理,这将使你成为一名更好的数据科学家,尤其是当你正在开发产品的新功能时。
2.  协作是关键!对与其他公司或团队的外部和内部协作持开放态度。合作能在短时间内丰富你的经验,并有助于积极的工作关系。合作加强了你作为领导者的地位。
3.  试着向前看,看看你的公司正在走向何方,如果这对你有意义,试着成为第一批沿着这条道路前进的人。
4.  不断地向你的朋友咨询研究的想法和方法,有人有不同的角度,比你知道的更多。
5.  通过参加他们的会议、与他们共进午餐或召开联合团队会议,与公司的其他团队保持联系。
6.  在指导上投入时间,这可以通过建立一个实习项目来实现。辅导提高了经常被忽视的教学技能。

我要感谢我的同事 Samuel Jefroykin 和 Yoav Talmi 提供的宝贵意见。

Ori Cohen 博士拥有计算机科学博士学位,专注于机器学习。他领导着 Zencity.io 的研究团队,试图积极影响市民的生活。

# 用你新获得的壳技能打动旁观者

> 原文:<https://towardsdatascience.com/impress-onlookers-with-your-newly-acquired-shell-skills-a02effb420c2?source=collection_archive---------9----------------------->

## 数据科学家的 10 分钟外壳/终端技能

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9c0c743a46167247aa0f507e0570e12c.png)

Photo by [Adam Littman Davis](https://unsplash.com/@adamlittmandavis?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

我敢打赌,我们大多数人都见过有人坐在咖啡馆里对着黑/绿屏幕乱砍一气。

每当这种情况发生时,我第一个想到的就是——“这看起来太酷了。”

没有图形用户界面。这就像你在玩你的操作系统的内部。

***你要去的地方是和汇编语言一样接近的地方。***

[外壳命令](https://amzn.to/2YkjHbS)功能强大。它们看起来也很酷。

所以我想给他们一个尝试。我意识到,它们也可能是我数据科学工作流程的重要组成部分。

***这篇文章是关于我在使用 shell/terminal 时发现的最有用的命令,主要关注数据科学。***

# 您何时会使用 shell/terminal 进行数据分析?

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f5c36a8ee34e1d9bb046735e8bb409c6.png)

有一件事我们都认为是理所当然的——您不会一直拥有 Python。

可能是新公司的 Linux 服务器没有安装 python。

或者您想对大文件进行一些检查,而不真正将它们加载到内存中。

考虑这样一种情况,当您的笔记本电脑/服务器上有一个 6 GB 管道分隔的文件,并且您想要找出某一特定列中不同值的计数。

你可能有不止一种方法可以做到这一点。您可以将该文件放入数据库并运行 SQL 命令,或者您可以编写一个 Python/Perl 脚本。

但是如果服务器上没有安装 SQL/Python 呢?或者,如果你想在黑屏上看起来很酷呢?

无论如何, ***无论你做什么,都不会比这个更简单/耗时更少:***

cat data.txt | cut -d "|" -f 1 | sort -u | wc -l

30


这将比你用 Perl/Python 脚本做的任何事情运行得更快。

现在,让我们稍微违背这个命令。这个命令说:

*   使用 **cat** 命令将文件内容打印/流式输出到标准输出。
*   使用|命令将流内容从我们的 cat 命令传输到下一个命令 **cut*****cut** 命令中,通过参数 **-d** 指定分隔符“|”(注意管道周围的分号,因为我们不想将管道用作流),并通过参数 **-f.** 选择第一列
*   将流内容传输到对输入进行排序的**排序**命令。它采用参数 **-u** 来指定我们需要唯一的值。
*   通过管道将输出传递给 wc -l 命令,该命令计算输入中的行数。

***也许你还不明白。但是不要担心,我保证你在文章结束时会明白的。*** 我还会在本帖结束前尝试解释比上述命令更高级的概念。

现在,我在工作中广泛使用 shell 命令。作为一名数据科学家,我将根据我在日常工作中几乎每天都会遇到的用例来解释每个命令的用法。

我使用来自 Lahman Baseball 数据库的 Salaries.csv 数据来说明不同的 shell 函数。你可能想要[下载数据](https://www.kaggle.com/freshrenzo/lahmanbaseballdatabase)来配合你自己的文章。

# 从基本命令开始

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b59fa1f9629ffc27160134021cb607a9.png)

Think of every command as a color in your palette

每当试图学习一门新语言时,从基础开始总是有帮助的。shell 是一种新语言。我们将逐一讲解一些基本命令。

## 1.猫:

有很多时候你需要看到你的数据。一种方法是在记事本中打开 txt/CSV 文件。对于小文件来说,这可能是最好的方法。

但是大数据是个问题。有时文件会非常大,以至于你无法在 sublime 或任何其他软件工具中打开它们,在那里我们可以使用 cat 命令。

你可能需要等一会儿。gif 文件来显示。

cat salaries.csv


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/af2efbca157e6be8f61939983f8ed743.png)

## 2.头部和尾部:

现在你可能会问我为什么要在终端上打印整个文件?一般不会。但我只想告诉你关于猫的命令。

对于用例,当您只需要数据的顶部/底部 n 行时,您通常会使用 [head](https://en.wikipedia.org/wiki/Head_%28Unix%29) / [tail](https://en.wikipedia.org/wiki/Tail_%28Unix%29) 命令。你可以如下使用它们。

head Salaries.csv
tail Salaries.csv
head -n 3 Salaries.csv
tail -n 3 Salaries.csv


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/77ba135f4e6d821553ea2e293ca9b5e3.png)

请注意这里的 shell 命令的结构:

CommandName [-arg1name] [arg1value] [-arg2name] [arg2value] filename


它是`CommandName`,后跟几个`argnames``argvalues`,最后是文件名。通常,shell 命令有很多参数。您可以通过使用`man`命令来查看命令支持的所有参数的列表。你可以把`man`看作是帮助。

man cat


## 3.wc:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/53760e8677d84df60c6f861cef1aa1a2.png)

Count the Lines

[wc](https://en.wikipedia.org/wiki/Wc_%28Unix%29) 是一个相当有用的 shell 实用程序/命令,它让我们**计算给定文件中的行数(-l)****字数(-w)****字符(-c)**

wc -l Salaries.csv
wc -w Salaries.csv
wc -c Salaries.csv


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/44e5c0c3e8dc7a3239d5ef465163acd5.png)

## 4.grep:

有时,您可能希望在文件中查找特定的行。或者您可能希望打印文件中包含特定单词的所有行。

或者你可能想看看 2000 年球队的薪水。

grep 是你的朋友。

在本例中,我们打印了文件中包含“2000,BAL”的所有行。

grep "2000,BAL" Salaries.csv| head


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/97f95800e68fcd25cd25f0c0ae3f0978.png)

你也可以在 grep 中使用正则表达式。

# 管道——这使得外壳很有用

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1b9d28f59da0b965bcb626a14df211a4.png)

既然我们现在知道了 shell 的基本命令,我现在可以谈谈 Shell 用法的基本概念之一— [**管道**](https://en.wikipedia.org/wiki/Pipeline_%28Unix%29) 。

如果不使用这个概念,您将无法利用 shell 提供的全部功能。

这个想法很简单。

还记得我们之前如何使用 head 命令查看文件的前几行吗?

现在,您也可以编写如下的`head`命令:

cat Salaries.csv | head


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6c37ae23b58007d281208508f328fc0d.png)

***我的建议:*** *把命令里的“|”读成“把数据传到”*

所以我会把上面的命令理解为:

*cat* (打印)整个数据流,**将数据传递给** *head* ,这样它就可以只给我前几行。

你知道管道的作用吗?

它为我们提供了一种连续使用基本命令的方法。有许多命令都是相对基本的,它让我们可以按顺序使用这些基本命令来做一些相当重要的事情。

现在让我告诉你几个不那么基本的命令,然后我会向你展示我们如何**链接**它们来完成相当高级的任务。

# 一些中间命令

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c5a21dab76272d7076e3608b799df445.png)

## 1.排序:

你可能想在特定的列上对你的数据集进行排序。`sort`是你的朋友。

假设您想找出数据集中任何球员的前 10 名最高工资。我们可以如下使用排序。

sort -t "," -k 5 -r -n Salaries.csv | head -10


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9f57ec5138687cc58141ec61b4e321a2.png)

所以这个命令中确实有很多选项。让我们一个一个地看。

*   **-t** :使用哪个分隔符?","
*   **-k** :按哪一列排序?5
*   **-n** :如果要数值排序。如果您希望进行字母排序,请不要使用此选项。
*   **-r** :我想降序排序。默认情况下,升序排序。

然后显然是管道——或者把数据传递给`head`指挥部。

## 2.剪切:

此命令允许您从数据中选择特定的列。有时,您可能希望只查看数据中的某些列。

例如,您可能只想查看年份、团队和薪水,而不想查看其他列。[切割](https://en.wikipedia.org/wiki/Cut_(Unix))是要使用的命令。

cut -d "," -f 1,2,5 Salaries.csv | head


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/64066304f88458336967544ac9d3ee07.png)

这些选项包括:

*   **-d** :使用哪个分隔符?","
*   **-f** :剪切哪一列/哪些列?1,2,5

然后,显然是管道——或者将数据传递给`head`命令。

## 3.uniq:

[uniq](https://en.wikipedia.org/wiki/Uniq) 有一点棘手,因为你可能想在排序中使用这个命令。

此命令删除连续的重复项。比如:1,1,2 会转换成 1,2。

所以结合 sort,它可以用来获得数据中的不同值。

例如,如果我想在数据中找出十个不同的团队,我会使用:

cat Salaries.csv| cut -d "," -f 2 | sort | uniq | head


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/374b8b97c3c4e371b2cbb3303ab79197.png)

该命令也可以与参数 **-c** 一起使用,以计算这些不同值的出现次数。

类似于**的东西算不同的**。

cat Salaries.csv | cut -d "," -f 2 | sort | uniq -c | head


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5627485d2c0ae485cbbf7a629d83d065.png)

# 其他一些实用程序命令

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/0ea8708eb6e7cf6647e16e8a32326d46.png)

这里有一些其他的命令行工具,你可以不用深入细节就可以使用,因为细节很难。 ***就把这个帖子收藏起来吧。***

## 1.更改文件中的分隔符:

有时您可能需要更改文件中的分隔符,因为某个应用程序可能需要特定的分隔符才能工作。Excel 需要“,”作为分隔符。

**寻找并替换魔法。**:您可能想使用`[tr](https://en.wikipedia.org/wiki/Tr_%28Unix%29)`命令将文件中的某些字符替换为其他字符。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8ab4a85b3f682408f207ff954fc4b497.png)

## 2.文件中一列的总和:

使用 [awk](https://en.wikipedia.org/wiki/AWK) 命令,您可以找到文件中一列的总和。除以行数(`wc -l`),就可以得到平均值。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a7f6899a8293ff804b4f62d55f53fcdc.png)

awk 是一个强大的命令,它本身就是一门完整的语言。请务必查看 awk 的 wiki 页面,其中有很多关于 awk 的好的用例。

## 3.在目录中查找满足特定条件的文件:

有时,您需要在包含大量文件的目录中找到一个文件。您可以使用 find 命令来完成此操作。假设您想要**找到所有的。当前工作目录中的 txt 文件**即**以**开头。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3d109085889a9bba290fad048c083add.png)

去找**所有人。以 A 或 B 开头的 txt 文件**我们可以使用 regex。

# 最后>和>>

有时,您希望通过命令行实用程序(Shell 命令/ Python 脚本)获得的数据不显示在 stdout 上,而是存储在文本文件中。

你可以使用 **" > "** 操作符。例如,您可以在将上一个示例中的分隔符替换到另一个名为 newdata.txt 的文件中后存储该文件,如下所示:

cat data.txt | tr ',' '|' > newdata.txt


开始的时候,我经常搞不清 **"|"** (管道)和 **" > "** (to_file)操作。

记住的一个方法是,当你想写一些东西到一个文件时,你应该只使用**>****“|”不能用于写入文件。**另一个你应该知道的操作是**>>**操作。它类似于 **" > "** ,但它附加到一个现有的文件,而不是替换文件和重写。

# 结论

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/50e4913608a23047316abe7b44696d09.png)

这只是冰山一角。

虽然我不是 shell 使用方面的专家,但是这些命令在很大程度上减少了我的工作量。

试着将它们融入你的工作流程。我通常在 jupyter 笔记本中使用它们(如果您以`!`开始命令,您可以在 jupyter 代码块中编写 shell 命令)。永远记住:

> 技工要完善他的工作,必须先磨利他的工具。——孔子

所以,现在给一些人留下深刻印象。

如果你想了解更多关于命令行的知识,我想你会的,Coursera 上有[UNIX 工作台](https://www.coursera.org/learn/unix?ranMID=40328&ranEAID=lVarvwc5BD0&ranSiteID=lVarvwc5BD0-EK0XnncSGKDui6jU1GFilw&siteID=lVarvwc5BD0-EK0XnncSGKDui6jU1GFilw&utm_content=2&utm_medium=partners&utm_source=linkshare&utm_campaign=lVarvwc5BD0)课程,你可以试试。

我以后也会写更多这样的帖子。让我知道你对这个系列的看法。在 [**媒体**](https://medium.com/@rahul_agarwal) 关注我或者订阅我的 [**博客**](http://eepurl.com/dbQnuX) 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter [@mlwhiz](https://twitter.com/MLWhiz) 联系到我。

# 通过使用 pandas 库和 Python 提高数据质量

> 原文:<https://towardsdatascience.com/improve-data-quality-by-using-the-pandas-library-and-python-34fda752a6b5?source=collection_archive---------15----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/999f5cbc5395b1dd1204d5c3a86968c3.png)

*数据质量*是一个具有多个维度的宽泛概念。我在[的另一篇介绍性文章](/data-demystified-data-quality-d8c699b678a2)中详细介绍了这一信息。本教程探索了一个真实的例子。我们确定我们想要改进什么,创建代码来实现我们的目标,并以一些关于现实生活中可能发生的事情的评论结束。要继续学习,您需要对 [Python](https://www.python.org/) 有一个基本的了解。

# 熊猫图书馆

Python 数据分析库( [pandas](https://pandas.pydata.org/) )是一个开源的、BSD 许可的库,它为 Python 编程语言提供了高性能、易于使用的数据结构和数据分析工具。

您可以通过在命令行中输入以下代码来安装 pandas:python 3-m pip install—upgrade pandas。

pandas 中有两种主要的数据结构:

*   **系列。**可以包含任何类型数据的单个列。
*   **数据帧。**具有行和命名列的关系数据表。

数据帧包含一个或多个系列以及每个系列的名称。数据帧是通常用于数据操作的抽象或复杂性管理器。

# 系列结构

系列就像是字典和列表的混合体。物品按顺序存放,并贴上标签,以便您可以检索。序列列表中的第一项是特殊索引,它很像一个字典键。第二项是你的实际数据。需要注意的是,每个数据列都有自己的索引标签。您可以通过使用。名称属性。这部分结构不同于字典,它对于合并多列数据很有用。

这个简单的例子向您展示了一个系列是什么样子的:

import pandas as pd carbs = [‘pizza’, ‘hamburger‘, ‘rice’]
pd.Series(carbs)
0 ‘pizza’
1 ‘hamburger’
2 ‘rice’dType: object


我们还可以创建带有标签属性的系列:

foods = pd.Series( [‘pizza’, ‘hamburger’, ‘rice’], index=[‘Italy’, ‘USA’, ‘Japan’]Italy ‘pizza’
USA ‘hamburger’
Japan ‘rice’dType: object


# 查询系列

您可以通过索引位置或索引标签来查询序列。如果不为系列指定索引,则位置和标签具有相同的值。要按数字位置进行查询,请使用 iloc 属性。

foods.iloc[2]
‘rice’


要通过索引标签进行查询,请使用 loc 属性。

foods.loc[‘USA’]
‘hamburger’


请记住,一个键可以返回多个结果。这个例子展示了基础知识。还有许多其他系列主题,如矢量化、内存管理等。但我们不会在本文中深入探讨。

# 数据帧结构

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3592d2a1a17978734fa3619368cec9ee.png)

数据框架是熊猫图书馆的主要结构。它是您在数据分析和清理任务中工作的主要对象。

从概念上讲,DataFrame 是一个二维序列对象。它有一个索引和多列内容,每一列都有标签。但是列和行之间的区别只是概念上的。将 DataFrame 想象成一个双轴标签数组。

您可以使用**系列**创建如下数据帧表:

purchase_1 = pd.Series({ ‘Name’: ‘John’, ‘Ordered’:’Pizza’, ‘Cost’: 11 })
purchase_2 = pd.Series({ ‘Name’: ‘Mary’, ‘Ordered’:’Brioche’, ‘Cost’: 21.20 })
purchase_3 = pd.Series({ ‘Name’: ‘Timothy’, ‘Ordered’:’Steak’, ‘Cost’: 30.00 })df = pd.DataFrame([purchase_1, purchase_2, purchase_3], index=[‘Restaurant 1’, ‘Restaurant 1’, ‘Restaurant 2’])+--------------+-------+---------+---------+
| | Cost | Ordered | Name |
+--------------+-------+---------+---------+
| Restaurant 1 | 11 | Pizza | John |
| Restaurant 1 | 21.20 | Brioche | Mary |
| Restaurant 2 | 30.00 | Steak | Timothy |
+--------------+-------+---------+---------+


和 Series 一样,我们可以通过使用 **iloc****loc** 属性来提取数据。数据帧是二维的。因此,当我们向 loc 传递单个值时,如果只有一行要返回,那么索引操作符将返回一个序列。

让我们查询这个数据帧。

df.loc[‘Restaurant 2’]Cost 30.00
Ordered ‘Steak’
Name ‘Timothy’


该函数返回一个 Series 类型的对象。

pandas DataFrame 的一个强大特性是,您可以基于多个轴快速选择数据。因为 iloc 和 loc 用于行选择,pandas 开发人员直接在数据帧上为列选择保留了索引操作符。在数据帧中,列总是有一个名称。所以这个选择总是基于标签的。

例如,我们可以用以下代码重写所有餐馆 1 成本的查询:

df.loc[‘Restaurant 1’][‘Cost’]Restaurant 1 11
Restaurant 1 21.20Name: Cost, dType: float64


# 表演时间到了。

现在我们处理一个简单但常见的数据问题:缺少值。在[数据去神秘化——数据质量](/data-demystified-data-quality-d8c699b678a2),中,我解释了为什么完整性是评估数据质量时要考虑的因素之一。缺失数据还可能与另外两个方面有关:缺乏准确性或一致性。还有很多东西需要学习,但是我想直接跳到一个例子,并随着我们的进行引入新的概念。

我们可以从任何来源读取大型数据集。一些例子是关系数据库、文件和 NoSQL 数据库。这个库示例展示了一组与关系数据库交互的方法:

import pandas.io.sql as psql


注意 **connect****read_sql** 是关键方法。

为了简单起见,我们将使用 CSV 文件。假设我们有一个存储在 logs.csv 中的日志文件,该日志每隔 100 毫秒存储一次鼠标指针的位置。如果鼠标没有变化,算法会存储一个空值,但会向该行添加一个新条目。为什么?因为如果信息没有改变,通过网络发送这些信息是没有效率的。

我们的目标是用正确的坐标存储 CSV 文件中的所有行。如下表所示,我们可以用以下代码存储这些行:

df = pd.read_csv(‘logs.csv’)
df+----+-----------+---------+---------+-----+-----+
| | timestamp | page | user | x | y |
+----+-----------+---------+---------+-----+-----+
| 0 | 169971476 | landing | admin | 744 | 220 |
| 1 | 169971576 | landing | admin | NaN | NaN |
| 2 | 169971591 | profile | maryb | 321 | 774 |
| 3 | 169971691 | profile | maryb | NaN | NaN |
| 4 | 169972003 | landing | joshf | 432 | 553 |
| 5 | 169971776 | landing | admin | 722 | 459 |
| 6 | 169971876 | landing | admin | NaN | NaN |
| 7 | 169971891 | profile | maryb | 221 | 333 |
| 8 | 169971976 | landing | admin | NaN | NaN |
| 9 | 169971991 | profile | maryb | NaN | NaN |
| 10 | 169972003 | landing | johnive | 312 | 3 |
| 11 | 169971791 | profile | maryb | NaN | NaN |
| 12 | 169971676 | landing | admin | NaN | NaN |
+----+-----------+---------+---------+-----+-----+


当我们检查数据时,我们发现了多个问题。有许多空值,并且文件不是按时间戳排序的。这个问题在高度并行的系统中很常见。

可以处理空数据的一个函数是 fillna。更多信息请输入 df.fillna?在命令行中。使用这种方法有许多选项:

*   一种选择是传入单个*标量*值,将所有丢失的数据都变成一个值。但是这种改变不是我们想要的。
*   另一个选择是传递一个*方法*参数。两个常见的值是 ffill 和 bfill。ffill 向前填充单元格。它使用前一行中的值更新单元格中的 NaN 值。为了使此更新有意义,您的数据需要按顺序排序。但是传统的数据库管理系统通常不能保证你从中提取的数据的顺序。

所以,我们先把数据整理一下。我们可以按索引或值排序。在这个例子中,时间戳是索引,我们对*索引*字段进行排序:

df = df.set_index(‘timestamp’)
df = df.sort_index()


我们创建了下表:

+-----------+---------+---------+-----+-----+
| | page | user | x | y |
+-----------+---------+---------+-----+-----+
| time | | | | |
| 169971476 | landing | admin | 744 | 220 |
| 169971576 | landing | admin | NaN | NaN |
| 169971591 | profile | maryb | 321 | 774 |
| 169971676 | landing | admin | NaN | NaN |
| 169971691 | profile | maryb | NaN | NaN |
| 169971776 | landing | admin | 722 | 459 |
| 169971791 | profile | maryb | NaN | NaN |
| 169971876 | landing | admin | NaN | NaN |
| 169971891 | profile | maryb | 221 | 333 |
| 169971976 | landing | admin | NaN | NaN |
| 169971991 | profile | maryb | NaN | NaN |
| 169972003 | landing | johnive | 312 | 3 |
| 169972003 | landing | joshf | 432 | 553 |
+-----------+---------+---------+-----+-----+


如你所见,还有一个问题。我们的时间戳不是唯一的。两个用户可能同时与平台交互。

让我们重置索引,并使用时间戳和用户名创建一个复合索引:

df = df.reset_index()
df = df.set_index([‘timestamp’, ‘user’])
df


我们创建了下表:

+-----------+---------+---------+-----+-----+
| | | page | x | y |
+-----------+---------+---------+-----+-----+
| time | user | | | |
| 169971476 | admin | landing | 744 | 220 |
| 169971576 | admin | landing | NaN | NaN |
| 169971676 | admin | landing | NaN | NaN |
| 169971776 | admin | landing | 722 | 459 |
| 169971876 | admin | landing | NaN | NaN |
| 169971976 | admin | landing | NaN | NaN |
| 169971591 | maryb | profile | 321 | 774 |
| 169971691 | maryb | profile | NaN | NaN |
| 169971791 | maryb | profile | NaN | NaN |
| 169971891 | maryb | profile | 221 | 333 |
| 169971991 | maryb | profile | NaN | NaN |
| 169972003 | johnive | landing | 312 | 3 |
| | joshf | landing | 432 | 553 |
+-----------+---------+---------+-----+-----+


现在我们可以用 **ffill** 来填充缺失的数据:

df = df.fillna(method='ffill')


下表显示了结果:

+-----------+---------+---------+-----+-----+
| | | page | x | y |
+-----------+---------+---------+-----+-----+
| time | user | | | |
| 169971476 | admin | landing | 744 | 220 |
| 169971576 | admin | landing | 744 | 220 |
| 169971676 | admin | landing | 744 | 220 |
| 169971776 | admin | landing | 722 | 459 |
| 169971876 | admin | landing | 722 | 459 |
| 169971976 | admin | landing | 722 | 459 |
| 169971591 | maryb | profile | 321 | 774 |
| 169971691 | maryb | profile | 321 | 774 |
| 169971791 | maryb | profile | 321 | 774 |
| 169971891 | maryb | profile | 221 | 333 |
| 169971991 | maryb | profile | 221 | 333 |
| 169972003 | johnive | landing | 312 | 3 |
| | joshf | landing | 432 | 553 |
+-----------+---------+---------+-----+-----+


# 熊猫大战 PostgreSQL

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8d8dc98d0bd99f0b87fb20b91567adbd.png)

熊猫胜过 PostgreSQL。对于大型数据集,它的运行速度要快 5 到 10 倍。PostgreSQL 唯一表现更好的时候是在小数据集上,通常少于一千行。在 pandas 中选择列是高效的,时间为 O(1)。这是因为数据帧存储在内存中。

出于同样的原因,pandas 也有局限性,仍然需要 SQL。熊猫的数据存储在内存中。所以很难加载大于系统内存一半的 CSV 文件。数据集通常包含数百列,这为超过一百万行的数据集创建了大约 10 GB 的文件大小。

PostgreSQL 和 pandas 是两种不同的工具,具有重叠的功能。创建 PostgreSQL 和其他基于 SQL 的语言是为了管理数据库。它们使用户能够轻松地访问和检索数据,尤其是跨多个表的数据。

*   运行 PostgreSQL 的服务器将所有数据集存储为系统中的表。对于用户来说,将所需的表传输到他们的系统,然后使用 pandas 在客户端执行像 join 和 group 这样的任务是不现实的。
*   熊猫的专长是数据处理和复杂的数据分析操作。

这两种工具在技术市场上并不竞争。相反,它们增加了数据科学计算堆栈中可用的工具范围。

# 额外小费

pandas 团队最近引入了一种方法,用与数据帧长度相同的序列来填充缺失值。使用这种新方法,如果需要的话,很容易得到缺失的值。

# 参考

Fox,D. (2018),[用 pandas 和 PostgreSQL 操纵数据:哪个更好?](https://blog.thedataincubator.com/2018/01/pandas-vs-postgresql/)、*数据孵化器*。

熊猫(2019), [Python 数据分析库](https://pandas.pydata.org/)。

# 通过尝试不同的方法来改进你的 ML 模型

> 原文:<https://towardsdatascience.com/improve-your-ml-model-by-trying-different-approaches-582f4dda7eee?source=collection_archive---------18----------------------->

## 基于机器学习的二手车价格预测

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a7a531e5c6206f1f3239d4a8a3f7c42c.png)

Photo by [Jen Theodore](https://unsplash.com/@jentheodore?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

在这篇文章中,我们将看看我最近完成的项目,在这个项目中,我根据许多因素预测了二手车的价格。我在 [Kaggle](https://www.kaggle.com/avikasliwal/used-cars-price-prediction) 上找到了数据集。

这个项目是特殊的,因为我尝试了许多不同的东西,然后在笔记本上完成,作为存储库的一部分。我会解释我所想的每一步,以及结果如何。包含代码的存储库如下:

 [## kb22/二手车价格预测

### 此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/kb22/Used-Car-Price-Prediction) 

# 太久了,不会读

这篇文章的关键是:

1.  创建新特征可能会有帮助,例如我从`Name`创建了特征`Manufacturer`2.  尝试不同的方法来处理同一列。当直接使用`Year`栏时会产生不好的结果,所以我使用了从它派生出来的每辆车的年龄,这要有用得多。`New_Price`首先填充了基于`Manufacturer`的平均值,但是没有用,所以我在第二次迭代中删除了这个列。
3.  看起来不相关的栏目应该被删除。我掉了`Index``Location``Name``New_Price`4.  创建虚拟数据需要处理测试数据中缺失的列。
5.  摆弄 ML 模型的参数,因为它可能是有用的。当我将值设置为 100 时,RandomForestRegressor 中的参数`n_estimators`改进了`r2_score`。我也尝试了 1000,但它只是花了很长时间没有任何明显的改善。

如果你还想要完整的细节,请继续阅读!

# 导入库

我将导入`datetime`库来处理`Year`列。`numpy``pandas`库帮助我处理数据集。`matplotlib``seaborn`有助于绘图,我在这个项目中没有做太多。最后,我从`sklearn`导入了一些东西,尤其是度量和模型。

# 读取数据集

原始 Kaggle 数据集有两个文件:`train-data.csv``test-data.csv`。然而,文件`test-data.csv`的最终输出标签没有给出,因此,我将永远无法测试我的模型。因此,我决定只使用`train-data.csv`,并在`data`文件夹中将其重命名为`dataset.csv`。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/da89b5e7c187adde1c33e937d23c653f.png)

dataset.csv (Part 1)

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/57e7bdbe3c30ca0207969127f9f53a1d.png)

dataset.csv (Part 2)

然后,我将数据集分成 70%的训练数据和 30%的测试数据。

我输出训练数据信息,看看数据是什么样的。我们发现有些列像`Mileage``Engine``Power``Seats`有一些空值,而`New_Price`的大部分值都丢失了。为了更好地理解每一列真正代表了什么,我们可以看一下有数据描述的 Kaggle 仪表板。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/810ba70c275b75d060ad85fcd309307d.png)

Columns description

数据集现在已经加载,我们知道每一列的含义。现在是做一些探索性分析的时候了。请注意,我将始终使用培训部分,然后仅基于培训部分转换测试部分。

# 探索性数据分析

在这里,我们将探究上面的每一个专栏,并讨论它们的相关性。

## 索引

数据集中的第一列未命名。它实际上只是每一行的索引,因此,我们可以安全地删除这一列。

## 名字

`Name`列定义了每辆车的名称。我认为汽车的名字可能不会有很大的影响,但汽车制造商可以。例如,如果一般人发现`Maruti`生产可靠的汽车,他们的转售价值应该更高。因此,我决定从每个`Name`中提取`Manufacturer`。每个`Name`的第一个字就是厂家。

让我们根据制造商绘制并查看每辆汽车的数量。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/cd2e6dc38b0ee618468b24c21b4de880.png)

Manufacturer plot

正如我们在上面的图中看到的,在整个训练数据中,马鲁蒂的汽车数量最多,兰博基尼的汽车数量最少。另外,我不需要`Name`列,所以我删除了它。

## 位置

我最初尝试使用`Location`,但它导致了许多热门专栏,对预测帮助没有多大贡献。这意味着销售地点对汽车最终转售价格的影响几乎可以忽略不计。因此,我决定放弃这个专栏。

## 年

我最初保留`Year`是为了定义模型的构造。但后来我意识到,影响转售价值的不是年份,而是车的年龄。因此,受 Kaggle 的启发,我决定通过从当前年份中减去年份来用车龄替换`Year`## 燃料类型、变速器和所有者类型

所有这些列都是分类列。因此,我将为这些列中的每一列创建虚拟列,并将其用于预测。

## 公里驱动

数据输出显示列中存在的高值。我们应该调整数据,否则像`Kilometers_Driven`这样的列会比其他列对预测产生更大的影响。

## 英里数

`Mileage`定义汽车的行驶里程。然而,里程单位因发动机类型而异,例如,有些是每千克,有些是每升,但在这种情况下,我们将认为它们是等效的,只从这一列中提取数字。

正如我们之前检查的那样,`Mileage`列有一些缺失值,所以让我们检查它们并用该列的平均值更新空值。

## 发动机、动力和座椅

`Engine`值是在 CC 中定义的,所以我需要从数据中删除 CC。同样,`Power`有 bhp,我把 bhp 去掉。此外,由于这三个值都有缺失值,我将再次用平均值替换它们,就像我对`Mileage`所做的那样。

我使用`pd.to_numeric()`来处理空值,并且在从字符串转换为数字(int 或 float)时不会产生错误。

## 新价格

该列中的大多数值都丢失了。我最初决定把它们装满。我会根据制造商填写平均值。例如,对于福特,我会取所有存在的值,取它们的平均值,然后用该平均值替换福特 New_Price 的所有空值。然而,这仍然遗漏了一些空值。然后,我会用该列中所有值的平均值来填充这些空值。测试数据也是如此。

然而,这种方法并不真正成功。我试着对它运行随机森林回归器,结果是非常小的`r2_score`值。接下来,我决定简单地删除该列,这样`r2_score`的值会显著提高。

# 数据处理

这里,我将使用`pd.get_dummies`为所有分类变量创建虚拟列。

然而,由于测试数据中缺少所有类型,很可能会有缺失的列。我们用一个例子来理解一下。例如在列`Transmission`中,训练数据包括`Manual``Automatic`,因此虚拟对象将类似于`Transmission_Manual``Transmission_Automatic`。但是如果测试数据只有`Manual`值而没有`Automatic`值呢?在这种情况下,假人只会导致`Transmission_Manual`。这将使测试数据集比训练数据少一列,预测将不起作用。为了处理这个问题,我们在测试数据中创建缺失的列,并用零填充它们。最后,我们对测试数据进行排序,就像训练数据一样。

最后,我会缩放数据。

# 训练和预测

我将创建一个线性回归和随机森林模型来训练数据,并比较`r2_score`值以选择最佳选择。

我得到线性回归的`r2_score``0.70`,随机森林为`0.88`。因此,随机森林在测试数据上表现得非常好。

# 结论

在这篇文章中,我们看到了如何处理现实生活中的机器学习问题,以及我们如何根据它们的相关性和它们给出的信息来调整功能。

您可能还喜欢:

[](/how-i-used-python-and-r-to-analyze-and-predict-medical-appointment-show-ups-cd290cd3fad0) [## 我是如何使用 Python 和 R 来分析和预测医疗预约的!

### 一个 R 和 Python 共存的世界

towardsdatascience.com](/how-i-used-python-and-r-to-analyze-and-predict-medical-appointment-show-ups-cd290cd3fad0) [](/seaborn-lets-make-plotting-fun-4951b89a0c07) [## seaborn——让绘图变得有趣

### Python 中的 Seaborn 库简介

towardsdatascience.com](/seaborn-lets-make-plotting-fun-4951b89a0c07) [](/using-deep-learning-to-save-lives-by-ensuring-drivers-attention-e9ab39c03d07) [## 使用深度学习通过确保驾驶员的注意力来拯救生命

### 现实生活中的卷积神经网络

towardsdatascience.com](/using-deep-learning-to-save-lives-by-ensuring-drivers-attention-e9ab39c03d07) [](/plotting-business-locations-on-maps-using-multiple-plotting-libraries-in-python-45a00ea770af) [## 使用 Python 中的多个绘图库在地图上绘制商业位置

### 比较地图打印库

towardsdatascience.com](/plotting-business-locations-on-maps-using-multiple-plotting-libraries-in-python-45a00ea770af) 

请随意分享你的想法和想法。我很想收到你的来信!

# 通过使用 Sacred 管理您的机器学习实验来改进您的工作流程

> 原文:<https://towardsdatascience.com/improve-your-workflow-by-managing-your-machine-learning-experiments-using-sacred-d51dd2b0047e?source=collection_archive---------6----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/cae568bb476cf773dc1384786d0cd05b.png)

Me building experiments before using Sacred (Thanks [Nicolas](https://unsplash.com/@nicolasthomas) for the pick)

作为一名数据科学家,模型调优是我最不喜欢的任务。我 ***讨厌*** 它。我想这是因为管理实验总是会变得非常混乱。在寻找帮助我的工具时,我看到很多人提到[神圣的](https://github.com/IDSIA/sacred),所以我决定试一试。

在这篇文章中,我们将看到**如何使用神圣和全面的**来管理我们的实验。剧透警告:这个工具很棒,现在做实验真的很有趣。

# 神圣是如何工作的?

我们在模型训练脚本中使用神圣的装饰者。就是这样!该工具会自动存储每次运行的实验信息。今天,我们将使用 MongoDB 存储信息,并使用 Omniboard 工具将其可视化。好了,我们开始吧。

# 使用神圣的

这里有一个逐步指南:

1.  创造一个实验
2.  定义实验的主要功能
3.  添加配置参数
4.  添加其他指标
5.  进行实验

## 1 —创建一个实验

首先我们需要创建一个实验。很简单:

from sacred import Experiment****ex = Experiment("our_experiment")


搞定了。

## 2 —定义实验的主要功能

`run`方法运行实验的主要功能。当我们运行 Python 脚本时,`@ex.automain`装饰器定义*并且*运行实验的主要功能。它相当于:

from sacred import Experimentex = Experiment("our_experiment")@ex.main
def run():
pass

if name == 'main':
ex.run_commandline()


让我们用`@ex.automain`来代替:

from sacred import Experimentex = Experiment("our_experiment")@ex.automain
def run():
pass


## 3-添加配置参数

每次运行时,配置参数也会存储在数据库中。设置的方式有很多:通过[配置范围](https://sacred.readthedocs.io/en/latest/configuration.html#config-scopes)、[字典](https://sacred.readthedocs.io/en/latest/configuration.html#config-dictionaries)、[配置文件](https://sacred.readthedocs.io/en/latest/configuration.html#config-files)。让我们坚持这里的配置范围。

我们将使用这个[在线零售数据集](https://archive.ics.uci.edu/ml/datasets/online+retail)并使用 scikit-learn 的[时间序列交叉验证器](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.TimeSeriesSplit.html)来拆分数据。该模型将预测订单是否会被取消。让我们定义`criterion`参数:

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import TimeSeriesSplit
import pandas as pd
from sacred import Experiment ex = Experiment('online_retail_tree') @ex.config
def cfg():
criterion = "entropy"
@ex.automain
def run(criterion):
dateparse = lambda x: pd.datetime.strptime(x, '%d/%m/%Y %H:%M') df = pd.read_csv("Online Retail.csv", parse_dates["InvoiceDate"], date_parser=dateparse, decimal=",") df = df.sort_values(by="InvoiceDate") df["canceled"] = df["InvoiceNo"].apply(lambda x: x[0] == "C") X = df.loc[:,["Quantity","UnitPrice"]]
y = df.loc[:, ["canceled"]] ts_split = TimeSeriesSplit(n_splits=10)

clf = DecisionTreeClassifier(criterion=criterion)  

for train_index, test_index in ts_split.split(X):        
    X_train = X.iloc[train_index]        
    y_train = y.iloc[train_index]                 X_test = X.iloc[test_index]        
    y_test = y.iloc[test_index]                 clf.fit(X_train, y_train.values.ravel())         
    y_pred = clf.predict(X_test)

## 4 —添加其他指标

神圣收集关于实验的信息,但我们通常也想测量其他东西。在我们的例子中,我想知道**每次分割中取消订单的数量**。我们可以为此使用 Metrics API。

> 神圣支持使用 Metrics API 跟踪数字序列(例如 int、float)。`_run.log_scalar(metric_name, value, step)`方法采用一个度量名称(例如“training.loss”)、测量值和获取该值的迭代步骤。如果未指定步长,则会为每个度量设置一个自动递增 1 的计数器。— [指标 API](https://sacred.readthedocs.io/en/latest/collected_information.html#metrics-api)

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import TimeSeriesSplit
import pandas as pd
from sacred import Experimentex = Experiment('online_retail_tree')@ex.config
def cfg():
criterion = "entropy"@ex.automain
def run(criterion):
dateparse = lambda x: pd.datetime.strptime(x, '%d/%m/%Y %H:%M') df = pd.read_csv("Online Retail.csv", parse_dates["InvoiceDate"], date_parser=dateparse, decimal=",") df = df.sort_values(by="InvoiceDate") df["canceled"] = df["InvoiceNo"].apply(lambda x: x[0] == "C") X = df.loc[:,["Quantity","UnitPrice"]]
y = df.loc[:, ["canceled"]] ts_split = TimeSeriesSplit(n_splits=10)

clf = DecisionTreeClassifier(criterion=criterion)  

for train_index, test_index in ts_split.split(X):        
    X_train = X.iloc[train_index]        
    y_train = y.iloc[train_index] X_test = X.iloc[test_index]        
    y_test = y.iloc[test_index] clf.fit(X_train, y_train.values.ravel())         
    y_pred = clf.predict(X_test)5Running the experiment true_cancel_count = y_test["canceled"].value_counts().tolist()[1]  

   pred_cancel_count = y_pred.tolist().count(True)  

   train_cancel_count = y_train["canceled"].value_counts().tolist()[1] **ex.log_scalar("true_cancel_count", true_cancel_count)        
   ex.log_scalar("pred_cancel_count", pred_cancel_count)        
   ex.log_scalar("train_cancel_orders", train_cancel_count)**

## 5 —运行实验

我们将使用 MongoDB Observer 来存储关于实验的信息:

> 神圣通过为你的实验提供一个*观察者界面*来帮助你。通过附加一个观察器,您可以收集关于运行的所有信息,即使它还在运行。— [观察实验](https://sacred.readthedocs.io/en/latest/observers.html#observing-an-experiment)

为了将数据保存到名为 my_database 的 mongo 数据库中,我们只需运行`python3 my_experiment.py -m my_database`。

现在有了关于实验的数据,但我们需要将它可视化。为此,我们将使用[综合](https://github.com/vivekratnavel/omniboard)。

# 使用 OMNIBOARD

Omniboard 是用 React,Node.js,Express 和 Bootstrap 写的一个神圣的仪表盘。

要安装它,运行`npm install -g omniboard`,并开始我们运行`omniboard -m hostname:port:database`,在我们的例子中:`omniboard -m localhost:27017:my_database`。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ed1c6a004643cb30f4e74bc6456da600.png)

Omniboard listing our experiments

我们可以看到一个实验是否失败,实验持续时间,添加注释等等。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5dac6654c5eed8f59a5bad644824f505.png)

Detailed view of an experiment

detail 视图显示了我们跟踪的指标的图表,我们还可以查看命令行输出、源代码(awesome)和其他实验细节。

# 那又怎样?

神圣是一个伟大的工具,因为**现在我们不必担心保存我们的实验结果**。一切都被自动存储,我们可以回去分析任何实验。

这个工具被设计成**只引入最小的开销**,在我看来这就是它的伟大之处。

这里的主要信息是:**给神圣一个尝试**!我可以说我现在的工作流程因为它好了很多。🙂

为了同样的目的,你使用另一个工具吗?我也想听听其他替代方案。感谢您的阅读!

# 改进深度神经网络

> 原文:<https://towardsdatascience.com/improving-deep-neural-networks-b5984e29e336?source=collection_archive---------22----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b15e89225858b4419cfefa87943b4b83.png)

深度神经网络是自然语言处理、计算机视觉、语音合成等复杂任务的解决方案。提高他们的表现和理解他们如何工作一样重要。要了解它们是如何工作的,你可以参考我以前的帖子。在这篇文章中,我将解释与改善神经网络相关的各种术语和方法。

# 偏差和方差

偏差和方差是解释网络在训练集和测试集上表现如何的两个基本术语。让我们用一个 2 类问题来简单直观地理解偏差和方差。蓝线表示由神经网络计算的决策边界。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/fa8f332c59f019c9965bf5ddea30efb4.png)

1.  最左图显示神经网络存在**偏高的问题。**在这种情况下,网络已经学习了一个简单的假设,因此不能根据训练数据进行适当的训练。因此,它不能区分不同类别的示例,并且 ***在*** 的训练集和测试集上都表现不佳。我们也可以说这个网络不适合。
2.  最右边的图显示神经网络存在**方差高的问题。在这种情况下,网络已经学习了一个非常复杂的假设,因此不能概括。因此, ***在训练数据上表现出色,而在测试数据*** 上表现不佳。我们也可以说网络**过度拟合。****
3.  中心图显示了一个 ***【恰到好处】*** 的神经网络。它已经学习了理想假设,这有助于网络过滤掉异常,并对数据进行归纳。我们的目标应该是实现这样的网络类型。

# 训练食谱

既然我们知道什么样的神经网络是可取的;让我们看看如何实现我们的目标。这些步骤首先解决偏差问题,然后解决方差问题。

我们应该问的第一个问题是“是否存在高偏差?”如果答案是**是**,那么我们应该尝试以下步骤:

*   培养一个更大的网络。它包括增加隐含层的数目和隐含层中神经元的数目。
*   长时间训练网络。可能的情况是,完整的训练尚未完成,将需要更多的迭代。
*   尝试不同的优化算法。这些算法包括 Adam、Momentum、AdaDelta 等。
*   反复执行上述步骤,直到偏差问题得到解决,然后进入第二个问题。

如果答案是**否,**说明我们已经克服了偏倚问题,是时候关注方差问题了。我们现在应该问的第二个问题是“方差高吗?”如果答案是**是的,**那么我们应该尝试以下步骤:

*   收集更多的训练数据。随着我们收集更多的数据,我们将获得更多的数据变化,从较少变化的数据中习得的假设的复杂性将被打破。
*   试试正规化。我将在下一节谈到它。
*   反复执行上述步骤,直到方差问题得到解决。

如果答案是**否,**说明我们已经克服了方差问题,现在我们的神经网络是 ***【刚刚好】*** 。

# 正规化

正则化是一种逻辑技术,有助于减少神经网络中的过拟合。当我们将正则化加入到我们的网络中时,我们添加了一个新的正则化项,并且损失函数被修改。修改后的成本函数 **J** 的数学公式为:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4f751502079d6a1021bd4b8239ed3658.png)

带有*****的第二项称为正则化项。术语 ***||W||*** 通称为 ***弗罗贝纽斯范数*** (矩阵中元素的平方和)。随着正则化的引入,*****成为新的超参数,可以对其进行修改以提高神经网络的性能。上述正则化也被称为 ***L-2 正则化。***

之前,我们使用以下更新规则来更新权重:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/323316e96a2f9cea6f9bdeb81f4f7578.png)

由于在包括正则化的修改的成本函数 ***J,*** 中有新的正则化项,我们将以如下方式更新权重:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/06e0ef9ff34bc93e2806c5747aa4915c.png)

这里我们可以看到权重值减少了一个小于 1 的小数值。因此,我们也将这类正则化称为 ***权重衰减。*** 衰减值取决于学习率*****和正则项***λ。***

## 为什么正规化行得通?

训练神经网络的最终目标是最小化成本函数 ***J*** 以及正则化项。现在我们知道了什么是正则化,让我们试着理解它为什么有效。

第一个直觉是,如果我们增加***λ、*** 的值,那么 ***Frobenius 范数*** 就变小了,权重值就变得接近 0。这种方法主要清除某些神经元,使网络变得很浅。可以认为是将学习复杂假设的深层网络转换成学习简单假设的浅层网络。我们知道,简单假设导致复杂特征减少,过拟合就会减少,我们就会得到一个 ***【恰到好处】*** 的神经网络。

另一种直觉可以从应用正则化时神经元的激活方式中获得。为此,让我们考虑 ***tanh(x)*** 激活。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f5fa08f81255ef5034ea4aac1c96d7d4.png)

如果我们增加*****的值,那么 ***Frobenius 范数*** 变小,即权重 ***W*** 变小。因此,该层的输出将变小,并将位于激活函数的蓝色区域。我们可以看到,蓝色区域的激活几乎是线性的,网络将表现得类似于浅层网络,即网络将不学习复杂的假设(将避免尖锐的曲线),并且过拟合将最终减少,并且我们将获得一个 ***【恰到好处】*** 神经网络。

因此,*****的值过小将导致过拟合,因为 ***Frobenius 范数*** 将会很大,并且神经元将不会被清除,并且层的输出将不会在线性区域中。类似地,过大的*****值将导致欠拟合。因此,找到*****的理想值是提高神经网络性能的一项至关重要的任务。

# 辍学正规化

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/0facf481ce1fe4a7b85275f47802aa2f.png)

丢弃正则化是另一种正则化技术,其中我们丢弃某些神经元以及它们在神经网络中的连接。概率 ***keep_prob*** 决定了将要丢弃的神经元。在神经元被移除之后,网络在剩余的神经元上被训练。重要的是要注意,在测试时间/推断时间期间,所有的神经元都被考虑用于确定输出。让我们借助一个例子来理解这个概念:

Define the probablity that a neuron stays.

keep_prob = 0.5# Create a probability mask for a layer eg. layer 2. The mask should # have same dimensions as the weight matrix so that the connections # can be removed.
d2 = np.random.rand(a2.shape[0],a2.shape[1]) < keep_prob# Obtain the new output matrix.
a2 = np.multiply(a2,d2)# Since few neurons are removed, we need to boost the weights of # remaining neurons to avoid weight imbalance during test time.
a2 = a2/keep_prob


由于我们首先丢弃概率为 ***keep_prob*** 的神经元,然后用 ***keep_prob*** 提升剩余的神经元,这种类型的丢弃称为 ***反向丢弃。***

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/5f52526c48bfb3d651b0d5fd7a3e9a93.png)

dropout 之间的直觉是,它禁止神经元只依赖于某些特征,因此,权重是分散的。可能的情况是,神经元变得依赖于某些输入特征来确定输出。在 dropout 正则化的帮助下,对于训练过程中的不同训练样本,特定神经元每次只获得少量特征作为输入。最终,权重分布在所有输入中,网络使用所有输入特征来确定输出,而不依赖于任何一个特征,从而使网络更加健壮。它也被称为***L2 正则化的自适应形式。***

我们也可以为每一层单独设置***【keep _ prob】****。由于被丢弃的神经元数量与 ***keep_prob*** 成反比;建立***keep _ prob****的一般标准是,密集连接应该具有相对较少的***keep _ prob****以便丢弃更多的神经元,反之亦然。***

***另一个直觉是,随着退出正规化,深层网络在训练阶段模仿浅层网络的工作。这进而导致减少过拟合,我们获得一个 ***【恰到好处】*** 神经网络。***

# **提前停止**

**早期停止是一种训练方法,在这种方法中,我们在较早的阶段停止训练神经网络,以防止它过度拟合。我们跟踪 ***train_loss*** 和 ***dev_loss*** 来确定何时停止训练。**

**![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ee80a7b9f18e1afc14440a15787de38f.png)**

**刚好 ***dev_loss*** 开始超调;我们停止训练过程。这种方法论被称为*。但是,由于以下两个原因,早期停止不是训练网络的推荐方法:***

1.  ***当我们停止训练过程时,损失不是最小的。***
2.  ***我们正试图减少训练不当的网络上的过度拟合。***

***过早停止会使事情变得复杂,我们无法获得 ***【恰到好处】*** 神经网络。***

# **参考**

1.  **[维基百科—激活功能](https://en.wikipedia.org/wiki/Activation_function)**
2.  **[Coursera——深度学习课程 2](https://www.coursera.org/learn/deep-neural-network/home/welcome)**

***我想感谢读者阅读这个故事。如果你有任何问题或疑问,请在下面的评论区提问。我将非常乐意回答这些问题并帮助你。如果你喜欢这个故事,请关注我,以便在我发布新故事时获得定期更新。我欢迎任何能改进我的故事的建议。***

# 用数据科学改进 ERP 数据

> 原文:<https://towardsdatascience.com/improving-erp-data-with-data-science-9c7cc00bc4bf?source=collection_archive---------15----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/57e68a852048f5293876ff9bbf2a7c71.png)

企业资源规划(ERP)数据有助于公司在专业平台的帮助下管理其日常运营,这些平台从多个流中收集信息,并允许公司获得实时反馈,以做出更好的决策。

企业可以通过雇佣数据科学家来提高他们的 ERP 使用率,这些数据科学家知道如何理解来自 ERP 界面的信息,并使用它来推动有利可图的行动。

# 实现更好的需求预测

数据科学家对如何识别历史数据中的模式有着透彻的理解。考虑到 ERP 平台通常包含有关销售随时间波动的信息,数据科学家可以更深入地挖掘,以发现有助于公司确定多快订购更多产品以及客户最想要哪些产品的趋势。

一家公司雇佣的数据科学家可以评估每年、每月和每周的季节性因素,并为企业领导人提供从防晒霜到雪铲等各种产品的库存指导。此外,记住其他一些可能影响顾客需求的事情也很重要。

如果一个名人带着一个随处可见的钱包在颁奖典礼的红地毯上漫步,这种知名度可能会让消费者想要购买它。或者,如果一位受人尊敬的思想领袖发布了一条关于某个产品的推文,这种提及也可以刺激需求。ERP 软件提供公司需要的硬数据,数据科学家通过确定让人们想要产品的明显和不太明显的因素来帮助连接这些点。

在零售业中很容易看到这种优势,但这种优势也扩展到了制造业和客户服务领域。例如,对含有难以获得的成分的消费品的需求增加可能会导致公司或其供应链合作伙伴扩大其网络以采购该商品或寻找替代方法来配制该产品。

或者,购买新发布的智能手机的人数迅速上升,这可能需要品牌的客户支持团队成员在处理关于该技术产品的大量问题之前进行额外的培训。一旦企业依靠数据科学家来更好地理解需求相关模式,他们应该能够更好地预测和满足不断变化的需求。

# 帮助公司对解决问题更有信心

企业领导经常会遇到这样的情况,需要他们评估各种选项,并针对给定的场景做出最合适的选择。这通常始于公司代表选择 ERP 软件。例如,[他们评估](https://www.neosystemscorp.com/industry-expertise/non-profit-organizations/hosting-software/)是现场还是基于云的 ERP 解决方案更好,然后得出结论,答案取决于企业的需求。

上一节讨论了在数据科学家的帮助下预测未来需求如何帮助企业取得成功。如果公司依靠数据科学家在规范性分析领域提供帮助,或者在解决已知问题时找出最佳方法,他们也可以表现出色。这是因为获得必要的洞察力来进行规定性分析需要[关注数据的数量和质量](https://www.zdnet.com/article/getting-your-corporate-data-ready-for-prescriptive-analytics-data-quantity-and-quality-in-equal-measures/)。

幸运的是,对于已经在使用 ERP 软件的公司来说,他们需要的大部分或全部数据都在这个平台上。然而,数据科学家通过评估数据来确保数据没有错误或重复记录,如果在分析开始前不从数据库中删除,这些错误或重复记录可能会扭曲结果。

毕马威开展了一项 CEO 调查,发现 [67%的受访者不相信](https://home.kpmg/xx/en/home/insights/2019/04/dont-doubt-the-data.html)过去几年从数据分析或计算机驱动模型中得出的结论。他们说,他们未能根据数据显示采取行动,因为这与他们的直觉或经验相矛盾。如果领导人怀疑数据库中包含错误,可能会导致不正确的结论,他们会感到更加怀疑。

让数据科学家在仔细检查数据之前仔细准备数据,并不能保证解决公司领导层对可用信息缺乏信心的问题。但是数据专家会清理数据以减少不准确的结果。这意味着,如果数据科学家首先处理 ERP 中的信息,并检查其问题和有用性,公司高管就可以更权威地对信息采取行动。

# 协助从多个 ERP 工具中编译数据

当一家跨国公司在全球范围内使用多个 ERP 系统,并需要将信息整合到一个平台时,从 ERP 界面处理公司数据变得异常复杂。全球最大的啤酒品牌百威英博就是如此。

该品牌以前在其全球子公司中使用近 30 个单独的 ERP 平台,但现在正在过渡到一个单一的标准化系统,该系统将在未来五年或更短时间内主要在云中运行。在过去的一年半中,该品牌的 80 名工程师团队[参与了 30 个数据项目](https://www.datanami.com/2019/04/11/from-big-beer-to-big-data-inside-ab-inbevs-digital-transformation/),所有这些都是该公司数字化转型的因素。

当公司处于类似的情况下,他们希望开始使用一个 ERP 解决方案,而不是几十个或更多,数据科学家可以缓解否则可能是一个棘手的过渡。

然而,由于分析师预测[对数据科学家的需求将会增加](https://searchbusinessanalytics.techtarget.com/feature/Demand-for-data-scientists-is-booming-and-will-increase),公司领导人应该立即做出招聘决定,并向候选人提供有吸引力的雇佣条件。

# 数据科学家和 ERP 工具:实用配对

这一概述强调了数据科学家的专业知识如何改善公司使用 ERP 的方式。此外,它表明了为什么公司领导人越来越多地将让数据科学家加入他们的团队视为一项明智的投资。

*图像由* [*Rawpixel*](https://www.pexels.com/photo/person-using-ballpoint-pen-1451448/) 组成

# 用数据改善精神卫生保健

> 原文:<https://towardsdatascience.com/improving-mental-health-care-with-data-84489f69d8c9?source=collection_archive---------26----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/da2ef7fd33599c14f1fea4f85852bc0d.png)

photo by [Clément Falize](https://unsplash.com/@centelm)

五月是心理健康宣传月。这是一年中我们(额外)被鼓励向为最弱势人群之一服务的非营利组织捐款的时候。是时候强调围绕心理健康、消除污名和庆祝改善生活的创新的话题了。本着这个月的精神,这篇博文将概述美国精神卫生保健系统面临的挑战,这些挑战是从公开报道和我自己的职业经历中总结出来的。我还将探索技术专家和数据科学家如何寻求创建实用的数据驱动解决方案来解决这些复杂问题的例子。

# 全国精神疾病联盟:数字

*   在美国,大约五分之一的成年人(4660 万人)在特定年份患有精神疾病。
*   在美国,大约每 25 个成年人中就有 1 人(1120 万)在给定的一年中经历过严重的精神疾病,这些疾病严重干扰或限制了一种或多种主要的生活活动。
*   估计有 26%住在收容所的无家可归的成年人患有严重的精神疾病,估计有 46%患有严重的精神疾病和/或物质使用障碍。
*   大约 20%的州囚犯和 21%的地方监狱囚犯有精神健康状况的“近期病史”。
*   非裔美国人和西班牙裔美国人使用心理健康服务的比率分别是白种美国人的一半和亚裔美国人的三分之一。

美国被认为是“去机构化”运动的领导者。从 20 世纪 60 年代开始,这一运动受到这样一种观点的启发,即每个精神疾病患者在小社区比在大医院能得到更好的照顾。在财政激励和新药物协议的推动下,美国决策者迅速同意并关闭了大多数国营精神病医院。

美国比任何其他西方国家都更大幅度地减少医院。1955 年至 1994 年间,大约有 487,000 名精神病患者从州立医院出院。目前,约有 220 万患有严重精神疾病的人根本没有接受任何精神治疗。大约 20 万精神分裂症或躁郁症患者无家可归。

基于社区的护理的想法在理论上是非常美好的,因为它的目标是给病人更多的自主权,让他们融入社会。不幸的是,它从未得到充分实施,尤其是在后勤上不可行的小城镇或农村社区。医院关闭了,但是社区诊所没有取代它们。这导致了目前美国精神卫生保健的危机。

如此迫切需要的治疗、稳定和庇护失去了,最需要的人找到了其他公共机构,主要是监狱。无法得到疾病治疗的人在监狱、收容所或街头游荡。他们挤满了急诊室,有时故意让自己生病,等待医院的床位开放,并希望得到一个干净的淋浴和一顿热饭。有些人变得暴力,但更多时候他们是暴力的受害者。

其余的国家精神病医院现在资金不足,人员不足,员工工资低,人员流动率高。环境压力大,拥挤不堪,有时还很危险。这造成了令人难以置信的低质量的护理和不断的创伤循环。T2 的医院简直是人满为患,每 10 万人只有 12 张病床。根据[治疗倡导中心](https://www.treatmentadvocacycenter.org/)的报告,“去机构化:失败的历史”,这与 1850 年的比率相同。

私营精神病医院也跟不上患者的需求,这使得医院管理者可以挑选他们想要治疗的患者,并拒绝接收他们认为在他们的项目中“不成功”的严重精神疾病患者。是的,没错——私立医院拒绝给病得太重的病人治疗是合法的。

除了没有病床、缺乏社区资源以及持续的耻辱和歧视之外,护理协调也是一个突出的问题。医院、精神病医生、初级保健医生和其他专家通常不相互交流或共享关键信息。这可归因于过时的记录管理系统、确保患者信息隐私的低效方法(HIPAA)以及医务人员和病例管理的频繁变动。临床医生依靠自我报告的信息或部分医疗记录来做出关键决定。

在目前的状态下,美国精神卫生保健系统往往无法防止可避免的悲剧和不公正。这些后果不仅影响精神疾病患者,还会在家庭、社区、学校、工作场所和社会中产生反响。为了做出有意义的改变,精神卫生保健必须进入 21 世纪。尽管如此,还是有一些好消息——专注于自动化、数据科学和精神健康护理交叉领域的科学研究和创新公司正在增长。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/78ac4f4b7ba6869d31383e6a9c158298.png)

photo by Ron Smith

## 哥伦比亚大学精神病学研究部:蛋白石中心

***O***优化与 ***P*** *针对精神分裂症患者的个性化干预* ***A*** *横着****L****if espan。*

> “开发和测试精神障碍循证治疗的临床研究环境与大规模实施这些干预措施的现实世界临床实践环境之间存在巨大差距。”— [蛋白石中心](https://www.columbiapsychiatry.org/research/research-centers/optimizing-and-personalizing-interventions-people-schizophrenia-across)

美国大约有 280 万精神分裂症患者,其中 40%将得不到治疗。研究表明,早期干预,包括药物治疗,可以改变这种疾病的性质,并大大改善患者的长期结果。抗精神病药物是治疗精神分裂症的重要组成部分。早期的经历会对患者对药物治疗的态度产生持久的影响,精神病的首次发作是优化治疗的关键时刻。

OPAL 是一个开发、适应和检查干预措施的平台,这些干预措施解决了精神分裂症治疗和服务提供中的重要问题。他们利用心理健康数据科学以及生物统计学的专业知识来开发机器学习精确模型和数据分析。即将开展的一个项目专注于通过智能手机数据进行药物管理。

开出尽可能好的药物和剂量是一项挑战。这个问题的一个促成因素是缺乏关于药物如何治疗症状、副作用以及患者相应的行为、认知和情绪体验的准确信息。精神病医生通常依赖病人对过去一个月感觉的回忆。这是有问题的,因为被诊断患有精神分裂症的人容易出现记忆困难和认知偏差。

该项目将使用智能手机应用程序从首次经历精神病发作的患者中收集实时症状和当前患者功能数据。这些输入将允许临床团队利用相关和及时的数据做出更好的治疗决策。其目的是在疾病的早期阶段用尽可能好的信息进行治疗,以产生持久的终身影响。

## 阈值项目:自动化患者记录和预测需求

[Data Kind](https://www.datakind.org/) 是一家非营利组织,汇集了志愿数据科学家和社会变革组织,以“解决教育、贫困、健康、人权、环境和城市领域的关键人道主义问题。”

在 Data Kind 志愿者和芝加哥非营利组织 [Thresholds](https://www.datakind.org/projects/de-siloing-data-to-help-improve-the-lives-of-those-suffering-from-mental-illness) 的共同努力下,他们致力于收集多个平台的患者数据,并使用预测分析来识别可能需要早期干预的高风险患者。如果无法获得重要和最新的患者数据,卫生保健提供者很难就患者需要的护理和援助做出合理的决策。

该团队首先创建了一个数据仓库,其中包含从 Thresholds 的内部数据库、伊利诺伊州医疗保健和家庭服务部以及库克县监狱中提取的原始数据。他们建立了一个自动报告系统和一个仪表板,员工可以使用它来快速了解患者的需求和护理质量。这种自动化为组织节省了重要的时间和资源,因为收集和处理这些信息通常是手动完成的。新工具允许工作人员以易于理解的格式可视化数据,识别新趋势,并在特定患者中进行筛选,以更好地定制他们的护理。

他们还利用来自匿名数据流的患者信息,对 2013 年至 2015 年接受阈值治疗的近 4000 名患者进行了预测。这些信息包括病例管理文件、医疗数据以及认知、健康和康复服务的治疗数据。通过这些数据来源,他们能够开发一个系统来标记需要立即干预的高危患者。

## Kaiser Permanent:分析电子健康记录预测自杀风险

评估自杀风险的传统方法包括临床评估和问卷调查。这些方法被发现远不如数据驱动模型准确。来自 Kaiser Permanent 的研究人员观察了 2009 年至 2015 年间近 300 万名心理健康和初级保健医生的患者。为了建立一个回归模型,他们从电子健康记录中提取了数据,包括过去的自杀企图、精神健康或物质使用诊断、医疗诊断、精神药物治疗、住院或急诊护理以及抑郁问卷。

T2 的 eam 发现,在就诊后的 90 天里,预测风险最高的 1%的患者中自杀企图和死亡的发生率是预测风险最低的一半的患者的 200 倍。该研究还显示,因精神健康问题去看医生的患者风险得分在前 5%,占自杀企图的 43%和自杀死亡的 48%。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c125ca5b484d4c806950d7182fa09abc.png)

photo by Hillie Chan

# 使用自动编码器提高 PewDiePie 的相机质量

> 原文:<https://towardsdatascience.com/improving-pewdiepies-camera-quality-with-autoencoders-583635de1cde?source=collection_archive---------23----------------------->

## 让我们来看看如何通过自动编码器将深度学习用于图像超分辨率。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/bfb553177ce8df6f4d6d2b6b56f2f97e.png)

Comparison of the 480p input (left) to an Autoencoder trained for the task of image super-resolution, with it’s higher quality output at the same resolution (right).

最近,我一直在阅读各种图像超分辨率技术,这些技术利用深度学习来提高图像清晰度。使用像 [GANs](https://medium.com/@jonathan_hui/gan-super-resolution-gan-srgan-b471da7270ec) 和[自动编码器](https://arxiv.org/pdf/1606.08921.pdf)这样的技术来完成这项任务,已经取得了一些令人印象深刻的成果。可以有把握地推测,如今大多数智能手机相机和其他图像处理软件都利用这种人工智能来“[增强](https://knowyourmeme.com/memes/zoom-and-enhance)图像。

在这篇文章中,我想探索和详细说明自动编码器对于这项任务的有效性,并在最近的 PewDiePie 的[视频中展示一些结果。](https://www.youtube.com/watch?v=pUFumN5UsiE&t=29s)

## 为什么是派迪派?

如果你最近一直在关注订阅量最大的 YouTuber,你就会知道他面临着很多批评和嘲笑,因为尽管他使用了昂贵的摄影器材来录制视频,但他的视频质量很低。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c6d691886ba65e76644c51dc5e95d87e.png)

这让我认为,这将是玩超分辨率人工智能算法的完美用例,并看看我们可以用它们实现多少更好的视频质量。

## 什么是图像超分辨率?

低分辨率(LR)模糊图像可以被放大以输出更清晰、更详细的高分辨率(SR)图像的技术被称为单图像超分辨率。目的是恢复图像中由于相机质量差或照明条件差而丢失的对象信息。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/587927581015f2565bfa5df52a34ab53.png)

An example of image super resolution using Neural Networks (ESRGAN). [[Source](https://www.dsogaming.com/news/max-payne-gets-an-amazing-hd-texture-pack-using-esrgan-and-is-available-for-download/)]

卷积神经网络(CNN)已被证明在这类任务中相当出色,尤其是与更传统的插值技术相比。由于能够学习常见物体的形状和纹理,CNN 在恢复信息方面非常有效,否则这些信息甚至可能不会出现在 LR 图像中。因此,让我们看看如何训练一个基于 CNN 的自动编码器来完成这项任务。

## 收集培训数据

首先,我们来看看我们的训练数据。我们将使用 Pewds 的一对低分辨率-高分辨率(LR-HR)图像来训练我们的自动编码器网络。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c3fdd9478f4a7a0d232d694d1050e4c2.png)

Generating training data

收集这种类型的数据相当容易,即使这是监督学习。我们只需要高分辨率的图像,通过对图像进行简单的缩小和放大操作,很容易生成低分辨率的图像,如上图所示。这给了我们用于网络训练的输入输出对。

## 自动编码器架构

自动编码器网络包含两个主要模块——编码器**和 T2 解码器**。下图显示了整个编码器-解码器网络设置。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/b96d104987ddf17d8b5ec0bacdd23d7c.png)

LR -> Encoder -> Encoding -> Decoder -> SR

**编码器**的任务是接收 LR 图像,并找到该图像的高级表示,称为编码。为此,它使用各种卷积层。输出编码包含图像中各种对象的形状和纹理信息,并且比输入图像的尺寸小得多。然而,人类并不能真正理解这种编码,而只是这种特定网络能够理解的一种表示。

**解码器**的任务是进行编码并创建更高分辨率的图像。为此,它使用各种上采样模块,并从编码器的早期卷积层获得帮助,以恢复图像中可能在转换为编码时丢失的一些信息。这在上图中用上方的箭头表示。请将此视为解码器在平滑和锐化接收到的信息时向编码器询问原始图像的具体细节。

最后,我使用的特定网络将图像放大到与输入图像相同的分辨率,但质量更清晰,像素细节更多。如果感兴趣,你也可以尝试超越 LR 分辨率。

## 结果

我使用生成的图像和地面实况之间的基本 MSE 损失度量来训练网络。这当然不是你可以用来比较图像的最佳损失度量,所以在这方面还有很大的改进空间。

无论如何,即使使用 MSE,我也能得到相当不错的结果,这让我相信基于 CNN 的自动编码器对这项任务非常有效。以下是 LR 输入和 SR 输出之间的一些示例比较。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/72e34b4119f48e926c8e9fe1389be0f3.png)

Left: input to autoencoder. Right: output of autoencoder. Both images are 480x480.

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4b234d9576e53c83ff846d43d218b845.png)

Left: input to autoencoder. Right: output of autoencoder. Both images are 480x480.

更多视频格式的结果,请查看我的 [YouTube 频道](http://youtube.com/c/DeepGamingAI)下面嵌入的视频。

## 结论

虽然来自自动编码器的结果相当不错,但在实践中它们并不十分先进。还有各种其他基于 GAN 的方法用于训练图像生成器,产生看起来更真实的输出。总之,与 GAN 的发生器-鉴频器设置相比,基于 MSE 的损耗,甚至我们在这里可以用于纯自动编码器的任何其它损耗,都是不利的。

在任何情况下,这肯定是非常令人印象深刻的,我们可以用人工智能实现这些天,所以它值得关注最新的研究,如果你对图像超分辨率感兴趣!

感谢您的阅读。如果你喜欢这篇文章,你可以在[媒体](https://medium.com/@chintan.t93)、 [GitHub](https://github.com/ChintanTrivedi) 上关注我的更多作品,或者订阅我的 [YouTube 频道](http://youtube.com/c/DeepGamingAI)。

# 利用语义搜索和自然语言处理改进栈溢出搜索算法

> 原文:<https://towardsdatascience.com/improving-the-stack-overflow-search-algorithm-using-semantic-search-and-nlp-a23e20091d4c?source=collection_archive---------7----------------------->

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/bd7fb40df97c743479510524867018e9.png)

如果你是一个曾经尝试过编写一段代码的人,你肯定会遇到**栈溢出**(这很有名)。对于那些生活在岩石下的人来说,**栈溢出**为程序员提供了一个最大的 QA 平台。用户提出问题/疑问,他们的同伴试图以最有帮助的方式提供解决方案。答案越好,得到的票数就越高,这也提高了用户的声誉。

鉴于它的受欢迎程度,可以肯定地说,那里有大量的数据。然而,这种巨大的信息量也使得人们很难找到自己想要的解决方案。对于编程老手和其他有经验的专业人士来说,这并不是什么大问题,因为他们知道获得适当答案所需的正确关键字。然而,对于一个初级程序员来说,这是一个很大的问题。例如,如果他需要学习使用 Python 的*‘如何制作服务器’*,他不太可能在搜索框中使用术语*‘Django’*或*‘Flask’*。因此,这可能会威胁用户使用该平台。

因此,一个最佳的搜索引擎是必要的导航通过这个烂摊子。然而,就目前的情况来看,Stack Overflow 的搜索引擎也有一些自身的缺陷。让我举个例子来说明:

> 假设我是 NodeJS 的初学者,我想运行我的应用程序。因此,我转到 Stack Overflow 并键入以下内容:*‘Node—如何运行 Node app . js?’*。这是我得到的:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8da0b247b33586b19bf35aeea86d230e.png)

> **但是**确实存在*节点——如何运行 app.js 的结果:*

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/58b49f583095b5778102e28eda848706.png)

> 理想情况下,它应该返回两个查询的结果,但是没有。

休斯敦,我们有麻烦了 

***但你问,何必呢?*** 栈溢出的主要收入来源是通过**广告收入**。因此,他们的目标是最大限度地提高用户参与度,以推动更多的广告,从而赚更多的钱。由于他们的搜索引擎的次优性能,用户将很难通过他们的网站清除他的疑虑,因此将决定使用更复杂的搜索引擎,如谷歌。

当谷歌建议使用 Stackoverflow 之外的资源时,问题就出现了。对于每一个离开他们网站的用户来说,他们损失了他们本可以赚到的钱。

# 一个可能的解决方案

我们的目标是让平台真正理解用户试图搜索的内容,然后基于此返回最相似的结果。

自 20 世纪问世以来,自然语言处理(NLP)已经走过了漫长的道路。由于快速的处理器和复杂的模型架构,人工智能的这个子领域在过去几年中已经被证明工作得非常好,因此在解决各种语言理解任务方面具有巨大的潜力。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/789f63542f1c9a4176130c711286a420.png)

Sneak Peek into of the final result

(要观看动画版本,点击[这里](https://s3.gifyu.com/images/demo6e6ebf7bfc9642ae.gif)

该解决方案分为两个子任务:

1.  ***标签预测:*** 给定用户查询,我们希望预测给定查询最好属于哪些标签
2.  ***信息检索:*** 基于用户查询,返回与用户查询最相似的现有问题

给你一个鸟瞰图,解决方案的流程如下:

*   从 Google BigQuery 收集 Stackoverflow 问题/答案数据
*   预处理和标准化收集的数据
*   仅过滤掉最常见的标签(使用了 500 个标签)
*   使用 Word2Vec 训练单词嵌入
*   使用 LSTM 模型训练标签分类器(*提示:您不能使用二进制交叉熵损失来训练它。阅读更多了解原因*
*   使用经过训练的单词嵌入来为我们数据库中的所有问题创建句子嵌入
*   将查询与每个句子进行比较,并使用基于余弦距离的度量对语义相似的结果进行排序。
*   使用 ReactJS 和 Flask 创建 web 应用程序来部署训练好的模型

对于有流程图癖的人来说,这里有:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/0025b73d08906e3aca80cf9fad9f8390.png)

The Brain

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7b9ebfb9ebad134aa112a43bc0f77e68.png)

The web app architecture

不要太花哨,对吗?如果您熟悉这些概念中的每一个,请随意直接进入代码(它也有很好的文档记录*codegasm*)。

[](https://github.com/agrawal-rohit/stackoverflow-semantic-search) [## agr awal-rohit/stack overflow-语义搜索

### Team Maverick 的 IBM Hack Challenge Stack overflow 条目为……提供了最大的学习资源之一

github.com](https://github.com/agrawal-rohit/stackoverflow-semantic-search) 

宝贝程序员们,请继续阅读:)

> **小旁注:**我不会在文章中解释每一行代码(repo 中的 jupyter 笔记本已经考虑到了这一点)。相反,我会专注于关键的结果和它们背后的直觉

## 1.数据收集

为了理解数据并从中学习,我需要收集 Stack Overflow 上发布的问题和答案。因此,我需要以下内容:

*   标题
*   问题主体
*   这个问题的答案
*   为每个答案投票

> 由于关于堆栈溢出和更好的健全性检查的大量数据,我将数据限制为仅与“Python”相关的问题。然而,整个过程对于其他主题也是可重复的

**Google BigQuery** 数据集包括堆栈溢出内容的档案,包括帖子、投票、标签和徽章。该数据集被更新以反映互联网档案上的堆栈溢出内容,并且也可通过堆栈交换数据浏览器获得。关于数据集的更多信息在 [Kaggle Stackoverflow 数据集](https://www.kaggle.com/stackoverflow/stackoverflow)中给出

我们的任务所需的数据可以通过以下 SQL 查询来收集:

SELECT q.id, q.title, q.body, q.tags, a.body as answers, a.score FROM 'bigquery-public-data.stackoverflow.posts_questions' AS q INNER JOIN 'bigquery-public-data.stackoverflow.posts_answers' AS a ON q.id = a.parent_id WHERE q.tags LIKE '%python%' LIMIT 500000


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ff8cbc808582b2bbb497cddeb6071165.png)

Raw Data from Google BigQuery

该查询连接两个表(*stack overflow . posts _ questions*和*stack overflow . posts _ answers*)并收集与`python`相关的 500000 个问题所需的数据。因此,每行包含一个问题和一个答案。 *(* ***注:*** *可能存在问题相同但答案唯一的行)。*

## 2.数据预处理和标准化

数据预处理 101 —检查缺失值:

df.isna().sum()
--------------id 0
title 0
body 0
tags 0
answers 0
score 0
dtype: int64


正如我之前提到的,我们的数据集可能包含具有相同问题但唯一答案的行。我们希望将所有这些不同的行合并为一行,同时汇总每个答案的投票并合并所有答案。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3883b625a5063c21178ab4ef12fbad27.png)

Data after combing rows with identical questions

Max score before: 5440
Max score after: 9730


现在我们终于准备好了原始数据,我们可以继续清理和预处理这些原始文本数据了。我实现了基本的文本处理,包括以下步骤:

1.  将原始文本转换为令牌
2.  将令牌转换为小写
3.  删除标点符号
4.  删除停用词

> **注意:**我跳过了删除数字数据,因为我觉得这会删除宝贵的上下文信息。
> 
> 我还跳过了**‘词干化/词汇化’**这一步,因为我不想改变我们语料库中使用的特定领域术语,以免丢失宝贵的信息

如果您仔细观察数据集,您会发现问题和答案的原始文本是与 HTML 标记一起给出的,它最初是用 HTML 标记显示在 StackOverflow 上的。这些通常指的是`p`标签*、*`*h1-h6*`*、*标签和*、**、*标签。因为我只需要每篇文章的文本部分,所以我执行了以下步骤:

*   我通过组合标题、问题主体和所有答案(稍后将用于训练 Word2Vec 嵌入)构建了一个名为“post_corpus”的新特性列
*   我把标题加在问题正文的前面
*   我跳过了“代码”部分,因为它们没有为我们的任务提供有用的信息
*   我为每个问题构造了 URL,在问题 id 后面附加了“【https://stackoverflow.com/questions/】T2
*   我使用开源的**文本块库**为情感构建了两个特征

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/db0348e8ad4f816a1f8832b7492a6500.png)

Preprocessed Data

每篇文章都有不同数量的标签。为了缩小更精确模型的选择范围,我决定用 **20 个最常见的标签。**计划仅过滤包含至少一个 most_common_tags 的数据

['python', 'python-3.x', 'django', 'pandas', 'python-2.7', 'numpy', 'list', 'matplotlib', 'dictionary', 'regex', 'dataframe', 'tkinter', 'string', 'csv', 'flask', 'arrays', 'tensorflow', 'json', 'beautifulsoup', 'selenium']


好了,最后一个快速枯燥的数据处理步骤,然后我们开始有趣的事情:)

*   我为“processed_title”创建了一个单独的列,因为我想保留原始标题,因为我想在应用程序中提供原始标题
*   我还标准化了数字“分数”

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6dcbe4b2afa536ccb1e35271149eb845.png)

Preprocessed and Normalized Data

## 3.仅过滤掉最常见的标签

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/dc642efb67872cd3368c668b68b6248e.png)

尽管我们在数据处理步骤中确实过滤掉了许多标签,但是仍然存在许多 ***【杂散】*** 标签,与其他标签成千上万次的出现相比,这些标签可能只出现一次或两次。这增加了地面真实数据的维度,这对于我们的模型是不期望的。

因此,我们根据出现的次数提取前 500 个标签。(*考虑到我们有大约 140,000 个数据点,500 个标签似乎是一个很好的实验数字*

最后,我们修改了标签数据,使其只包含这 500 个标签中的一个标签,以获得更好的模型准确性

## 4.使用 Word2Vec 训练单词嵌入

为了让我们的模型理解原始文本数据,我们需要对它进行矢量化。单词包和 TF-IDF 是非常常见的矢量化方法。然而,由于我将使用人工神经网络作为我的模型(LSTM),BOW 和 TFIDF 的稀疏特性会造成问题。**因此,我决定选择单词嵌入**,这是密集的向量表示,因此非常适合我们的神经网络。

人们在 StackOverflow 上交谈的方式是非常技术性的,他们使用非常特定的词汇,所以使用预先训练的单词嵌入不是一个好主意(尽管谷歌有很多好的嵌入),因为他们是在简单的英语文本(如莎士比亚)上训练的,无法理解我们词汇表中单词之间的关系。因此,我决定使用 Word2Vec 从头开始训练一个单词嵌入模型。

我们数据集中的列`post_corpus`在这里开始发光。由于 Word2Vec 是一个无监督的模型,只需要一个语料库进行训练,我们需要为它提供尽可能多的文本,以便它理解词汇表。因此,我们使用`post_corpus`来训练 Word2Vec,因为它是一篇文章的标题、问题和所有答案的组合。

训练成功后,我们得到以下结果:

Terms most similar to "django"
[('flask', 0.5827779173851013), ('project', 0.5168731212615967), ('mezzanine', 0.5122816562652588), ('wagtail', 0.5001770257949829), ('drf', 0.4827461242675781), ('framework', 0.48031285405158997), ('cms', 0.47275760769844055), ('admin', 0.467496395111084), ('database', 0.4659809470176697), ('app', 0.46219539642333984)]

Terms most similar to "api"
[('apis', 0.6121899485588074), ('webservice', 0.5226354598999023), ('service', 0.49891555309295654), ('framework', 0.4883273243904114), ('postman', 0.47500693798065186), ('webhook', 0.4574393630027771), ('rpc', 0.4385871887207031), ('oauth2', 0.41829735040664673), ('twilio', 0.4138619303703308), ('application', 0.4100519120693207)]

Terms most similar to "gunicorn"
[('uwsgi', 0.5529206991195679), ('nginx', 0.5103358030319214), ('000080', 0.4971828758716583), ('supervisord', 0.4751521050930023), ('arbiterpy', 0.4701758027076721), ('iis', 0.46567484736442566), ('apache2', 0.45948249101638794), ('web1', 0.45084959268569946), ('fastcgi', 0.43996310234069824), ('supervisor', 0.43604230880737305)]

Terms most similar to "server"
[('webserver', 0.5781407356262207), ('servers', 0.48877859115600586), ('application', 0.488214373588562), ('app', 0.4767988622188568), ('vps', 0.4679219126701355), ('client', 0.46672070026397705), ('localhost', 0.46468669176101685), ('service', 0.457424521446228), ('apache', 0.4540043771266937), ('nginx', 0.4490607976913452)]


很酷,对吧?

## 5.使用 LSTM 模型训练标签分类器

这一部分处理我们的第一个子任务:

***“给定用户查询,我们希望预测给定查询最好属于哪个标签”***

准备用于训练模型的数据包括:

1.  对地面真实数据进行一次性编码
2.  分成训练集和测试集
3.  标记化和填充
4.  创建嵌入矩阵

(我将在这里包含代码,但是对于每个部分的详细解释,请参考存储库中的 [jupyter 笔记本](https://github.com/agrawal-rohit/stackoverflow-semantic-search/blob/master/Tag%20Classifier.ipynb))

为解决手头的子任务而创建的模型在嵌入层之后立即使用了 LSTM 层,因为它们在处理顺序数据和文本数据方面很熟练。随后添加密集图层,并去除正则化以构建稳健的模型

**秘方——损失函数:**由于我们在这里处理的是多标签分类问题,**我们不能使用二进制交叉熵损失**来训练模型。这是因为二进制交叉熵损失会推动你的模型预测一个或两个包含在地面真相中的标签,而不会因为遗漏了其他标签而惩罚它。

因此,我分别对每个类使用日志损失,然后根据类的数量计算其平均值。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/081b81df23186b9dcda81bc5343d5568.png)

The loss function used

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ceef0342109f96ca9cad10571b413b72.png)

Model Performance

然后,我们可以借助下面的函数获得任何句子的标签:

Test Case: selecting n1d array nd array numpy

Predicted: [('arrays', 'numpy', 'python')]
Ground Truth: [('numpy', 'python')] Test Case: taking info file

Predicted: [('python',)]
Ground Truth: [('python', 'python-2.6', 'python-2.7')] Test Case: python find txt continue causing fault

Predicted: [('python',)]
Ground Truth: [('python', 'python-3.x')] Test Case: fabric rsync read error connection reset peer 104

Predicted: [('django', 'python')]
Ground Truth: [('django', 'python', 'windows')] Test Case: fllter pandas dataframe multiple columns

Predicted: [('dataframe', 'pandas', 'python')]
Ground Truth: [('pandas', 'python')]


目前看来已经足够好了😃。完成这个子任务后,进入下一个任务

## 6.使用经过训练的单词嵌入来为我们数据库中的所有问题创建句子嵌入

子任务 2 要求如下:

***“基于用户查询,返回与用户查询最相似的现有问题”***

要比较两个句子有多相似,我们可以找到它们之间的‘距离’。为了能够计算这样的距离,句子必须属于相同的向量空间。这是通过**句子嵌入**完成的。我也使用过的最流行的距离度量之一是**余弦距离**。余弦距离越小,两个向量之间的相似度越高

为了计算整个句子的嵌入,我定义了以下函数,该函数对每个有效标记的嵌入进行平均,并用于计算数据库中所有问题的句子嵌入:

## 7.将查询与每个句子进行比较,并使用基于余弦距离的度量对语义相似的结果进行排序

尽管余弦距离本身就足以为我们提供这个特定任务的良好结果,但我决定定义一个自定义的相似性度量。其给出如下:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/abed72a043bb6ba478f382bb8c755b71.png)

*其中* ***q*** *=用户查询和* ***t*** *=已有问题*

*   它将余弦距离视为基本度量
*   它根据帖子在 StackOverflow 上获得的用户投票来考虑帖子的受欢迎程度
*   它考虑了人们所作出的反应的总体情绪。积极的情绪意味着答案是有帮助的,因此是一篇好文章

运行以下代码片段可以向您展示运行中的算法:

对于用户查询**“组合列表列表”,**我们得到:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ebb334821a6e67278b8c2d84bfd515ae.png)

Query Results

web 应用程序只是通过用户界面翻译这些结果

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/2320c78cbba3f2ee3d562a41d30ae408.png)

在这篇文章中,我不会讨论我是如何创建 web 应用程序的,你可以在资源库中查看代码。如果你有任何疑问或建设性的反馈(讨厌有毒的人可以去吸阿迪..),欢迎在下方随意留下回应。我很乐意收到你的来信😄

直到那时,再见~

[](https://github.com/agrawal-rohit) [## agrawal-rohit —概述

### 在 GitHub 上注册您自己的个人资料,这是托管代码、管理项目和与 40…

github.com](https://github.com/agrawal-rohit)

# 在移动设备上使用人工智能改善用户体验

> 原文:<https://towardsdatascience.com/improving-user-experience-with-ai-on-mobile-ede5c567f703?source=collection_archive---------20----------------------->

对于许多用户来说,他们的移动设备是他们接触网络世界的首选界面。设备智能并不是什么新鲜事——想想智能助理、预测文本——但这些系统往往涉及简单的预测模型或基于规则的系统。虽然深度神经网络是当前图像和视频分析的最先进技术,但它们复杂的结构带来了沉重的计算负担,而且许多繁重的工作通常都是在云中完成的。当任务可以在后台执行时,这很好,但实时沉浸式用户体验需要比往返于数据中心更快的响应时间。

> 即使在世界上最先进的地区,移动网络覆盖也不是无处不在。

除了延迟和传输时间之外,应用程序必须能够容忍较差的数据连接,并在不可用时从容地失败。如果支持人工智能的功能对于保持一致的性能和行为至关重要,那么除了在用户硬件上运行,可能没有其他选择,因为即使是有线连接也有停机时间。

令人欣慰的是,功能越来越强的智能手机——通常带有专用加速器——正在为设备上更大的智能打开大门。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9fe1b06259784b6d1984b853252d3f53.png)

# 多快才算够快?

当提供对用户交互的响应时,显然越快越好。尽管应尽可能减少任何延迟,但在运行复杂操作和提供响应时,我们应考虑三种不同的时间框架:

*   **在 0.1 秒内**系统感觉像是在瞬间响应,因此不需要特殊的机制来管理用户的注意力。这一类别的一个例子是在屏幕上拖动鼠标光标,或者观看视频的实时更新。
*   **在 1.0 秒内**系统感觉反应灵敏,用户能够将动作与反应联系起来,尽管他们会注意到延迟。想象一下点击一个按钮,然后等待事情发生。
*   **在 10 秒钟内**用户可以保持专注于手头的任务,但是你需要让他们参与进来——在更长的时间里,用户可能会想转换任务,做些别的事情。

一般来说,一个“不确定”的进度指示器对于几秒钟的等待时间就足够了——它显示某事正在发生,但不显示完成的时间。超过 5 秒左右,如果用户知道他们还要等待多长时间,他们会更舒服。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3f03db9450ca374e5f6f8345ef5cffb9.png)

For delays of *2–5 seconds, an indeterminate progress indicator* (L) *is sufficient; for 5+ seconds, a determinate progress indicator (R) is a better choice*

我们如何使用这些信息来确保我们的人工智能有利于用户体验?首先,用户认知链的中断必须被最小化,这样用户界面才会有反应。必须考虑推理时间,长时间运行的操作应该作为后台任务运行,这样用户就不用等待响应了。

举个例子,把一个人脸探测器应用到一幅图像上。如果实时运行,结果可以用来检查对象在拍照前是否睁开了眼睛。在这种情况下,一切都在等待人工智能,它给系统带来了延迟,所以它必须尽可能快地运行。或者,面部探测器可以在拍照后用来帮助标记朋友——在这种情况下,它可以作为后台任务运行,一旦他们准备好,就会提供建议。这样,用户就不用等待人工智能,他们的认知链也不会中断。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4eacc28a843ebea19b4c2b0553652eae.png)

上面的例子可以通过云服务来运行,例如[谷歌云视觉 API](https://cloud.google.com/vision/) 或[亚马逊认知](https://aws.amazon.com/rekognition/)——响应时间通常不到一秒。作为后台操作,这没什么问题,如果不需要经常发生,作为对用户工作流的中断,这也是可以接受的。但是如果:

*   你有大量的数据?
*   你想要一个真正的,身临其境的实时产品?
*   你想要在任何情况下都可靠?

为了提供最佳的用户体验,有必要在用户设备上运行推理:要么在应用程序内,要么作为嵌入在网页中的客户端代码(例如 [TensorFlow.js](https://www.tensorflow.org/js) )。

# 设备上计算

我们在这里真正讨论的用例是什么,在移动硬件上运行这些用例有多实际?计算机视觉应用是要求最高的,但也是最令人兴奋的。相机可以成为与世界互动的手段和获取信息的方式,例如通过图像搜索。深度神经网络已经迅速成为图像分析任务的首选工具,例如对象检测、图像分类或特征提取。

大多数常见的网络架构使用卷积层堆栈从图像中提取特征。添加层和更复杂的结构通常可以提高性能,但代价是增加计算要求和/或执行时间,以及内存和存储要求。

令人欣慰的是,一些较新的神经网络体系结构是专门为此应用而设计的。 [MobileNets](https://ai.googleblog.com/2017/06/mobilenets-open-source-models-for.html) 是一系列网络,旨在有效利用嵌入式或移动设备等受限平台上的有限资源。至关重要的是,通过控制网络的规模和复杂性,可以在精度和速度之间进行权衡,以适应应用要求:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e3f105efa132950af84a99b14b943211.png)

该图显示,根据我们的优先级,我们可以选择具有广泛性能特征的神经网络模型。MobileNets 在对付像 Inception 这样的重量级模型时表现得相当好,运行速度也快得多。模型文件的大小也小了很多——如果您希望定期将更新的模型推送到用户设备上,这是非常重要的。

量化是在受限硬件上获得良好性能的技巧之一。神经网络模型可以被压缩和简化,就像图像可以被压缩成 JPEG 文件一样。当我们这样做时,不仅神经网络变得小了很多,而且它也运行得更快了。不幸的是,目前的移动 GPU 技术对量化模型的支持有限,因此它们最终只能在 CPU 上运行。不过,随着硬件的发展,这种情况可能很快就会改变。

选择具有不同执行时间和精度的模型意味着我们可以选择一个适合用户工作流的模型。但是,要注意运行你的应用程序的各种硬件,尤其是 Android。遗留设备可能需要更长的时间,所以在 UI 中找到一个合适的方法来处理任何潜在的长时间运行的操作。

这就是目前人工智能和移动设备的全部内容。在下一篇文章中,我们将关注*人在回路中*以及用户交互如何帮助保持人工智能模型的新鲜和最新。

> [Rupert Thomas](https://twitter.com/rupertthomas) 是一名技术顾问,专门研究机器学习、机器视觉和数据驱动产品。[@ Rupert 托马斯](https://twitter.com/rupertthomas)
> 
> *本文原载于*[*black lab . ai*](http://www.blacklab.ai)

# 参考

1.  [用户界面响应时间—史蒂夫·亨蒂](https://medium.com/@slhenty/ui-response-times-acec744f3157)
2.  [响应时间:3 个重要限制—雅各布·尼尔森](https://www.nngroup.com/articles/response-times-3-important-limits/)
3.  [TFLite 图像分类模型性能](https://www.tensorflow.org/lite/models)
4.  [材料设计—进度指标](https://material.io/design/components/progress-indicators.html)
5.  [比较五大计算机视觉 API](https://goberoi.com/comparing-the-top-five-computer-vision-apis-98e3e3d7c647?gi=73ec7eb3a6a7)

# 使用蒙特卡罗模拟和概率锥改进你的算法交易

> 原文:<https://towardsdatascience.com/improving-your-algo-trading-by-using-monte-carlo-simulation-and-probability-cones-abacde033adf?source=collection_archive---------2----------------------->

## 使用统计技术来提高你交易成功的几率

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ac06551b2044bb26cea297cfa454aea4.png)

我对将统计工具应用于现实世界的介绍并不好。我在一家中型航空航天公司负责质量保证。虽然我们在工厂车间广泛使用统计过程控制(SPC ),但我们现在决定使用一些先进的统计工具,如实验设计,来纠正棘手的制造污染问题。

我把任务交给了我的博士统计学家。在回顾了这个项目之后(在进行任何实验之前),他回来问我“现在我理解了这个项目,你想向你的老板(首席执行官)提出什么结论?无论你选择什么结论,我都可以从实验和统计的角度来证明。”

我还以为。使用统计学不是为了找到答案,而是为了支持一个“宠物”答案,任何宠物答案。这让我畏缩。不出所料,我把这个项目交给了一个希望实验推动结论的人,而不是相反。

这些天来,我喜欢用统计数据来证明一个信念,而不是引导我走上一条明智的道路。

我是一个算法交易者,统计工具对我帮助很大。在这篇文章中,我将介绍如何使用蒙特卡罗模拟和概率锥来更有效地交易。

在我开始讨论之前,先提醒几句。首先,我绝不是统计学专家。除了参加一些本科和研究生水平的统计学课程,我对统计学的许多方面一无所知。我绝对不是蒙特卡洛分析或概率锥的专家。

我擅长的是作为日常实践者使用这些工具。我可能在做一些纯粹主义者会嗤之以鼻的事情,但这对我来说没问题。最后,我知道这些工具,以及我如何使用它们,对我的交易有很大帮助。交易利润说话,他们告诉我,我做的事情是对的——也许只是理论上不对。

此外,这里显示的所有交易结果都是假设的。过去的表现不代表未来的结果,你应该只用你能承受损失的钱来交易。交易风险很大。

抛开这些免责声明,让我们来谈谈这些工具,以及我如何在我的算法交易中使用它们。

**什么是蒙特卡洛分析?**

抛一枚硬币,你知道它正面着地的几率是 50%。假设你每出现一个正面就赢 1.25 美元,每出现一个反面就输 1 美元。你有 10 美元的资金,如果跌到 6 美元,你就会退出。那是你的毁灭点。问题是,这种情况发生的几率有多大?

对于这样一个简单的例子,你可以在维基百科上找到一个近似结果的理论方程:[https://en.wikipedia.org/wiki/Risk_of_ruin](https://en.wikipedia.org/wiki/Risk_of_ruin)

但是,如果情况更复杂呢?如果有各种各样的可能结果,而不是一个双头硬币,硬币有 25 个面,所有被选中的概率都不同,会怎么样?在这种情况下,理论计算变得更加困难,甚至不可能。

进入蒙特卡洛分析。蒙特卡罗分析利用计算机模拟来解决问题、计算概率等,而无需求解理论方程。这在理论上的答案甚至不可能得到的情况下尤其有用。

蒙特卡洛分析被广泛应用于各种领域,包括一些你可能想象不到的领域。在 20 世纪 40 年代,蒙特卡罗模拟实际上被用于第一颗原子弹的研制。我在交易中使用它,这是一种更温和的方法(虽然交易账户有时会爆炸!).

当在交易中使用时,蒙特卡罗可以帮助建立许多重要性能指标的概率:

破产的风险

最大和中值下降

年回报率

回流/提取比率

有了这些信息,交易者可以在策略选择、头寸规模、资本部署和分配方面做出更明智的决策。

**如何在交易中使用蒙特卡洛**

在典型的形式中,蒙特卡罗分析采用假设回溯测试产生的所有交易,并随机选择一笔又一笔交易来产生一条权益曲线。这个想法是,通过一个适当设计的回溯测试,对未来表现的最佳估计来自于使用过去的交易(稍后,我将讨论为什么这可能不成立的许多原因)。

这方面的一个例子如图 1 所示。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/76c0b9476999b2fe9efaad599be516fa.png)

*Figure 1- Hypothetical Backtest Curve, With Multiple Possible Future Paths*

深蓝色的粗曲线是假设的回溯测试,而细曲线显示了权益曲线未来可能走的一些路径。未来曲线是基于从回溯测试曲线中随机选择的交易。(**侧** **注:**在本例中,采用了一种称为“置换取样”的方法。基于随机选择过程,回溯测试中的每笔交易都可以选择多次。有些交易可能根本就不选。这导致期末权益价值的范围很广。如果使用“无替换抽样”,那么最终所有的权益曲线将收敛到一个共同的终点,因为每个回溯测试交易使用一次,而且只有一次。

当蒙特卡洛运行时,会生成成千上万条潜在的未来曲线。然后可以对这些结果进行分析,为未来的表现建立概率。

我通常是这样考虑蒙特卡洛的:当你执行历史回溯测试时,在你运行蒙特卡洛分析之前,你会得到一条发生了什么的权益曲线,如图 2 中的权益曲线。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c4908e054318e982956b367e406264e5.png)

*Figure 2- Hypothetical Backtest Curve*

毫无疑问——这就是实际发生的情况。但是,如果事情略有不同呢?举例来说,如果交易在回溯测试中以不同的顺序出现会怎样?

在这种情况下,图 3 所示的任何权益曲线(路径)都可能发生。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/efaac6439f67406fb7338bb14efe1031.png)

Figure 3- Slightly Altered History Leads To Different Possible Equity Curves

当然,许多其他未显示的路径也可能发生。因此,通过使用蒙特卡洛分析,并结合结果,我们可以得出某些事件发生的概率。

**使用蒙特卡洛的优势**

对我来说,蒙特卡洛分析的最大优势是它改变了我对 T2 算法交易的看法。当我开始思考交易中的概率时,蒙特卡洛强迫你这么做,我发现自己做出了更好的决定。例如,我不再认为“市场肯定会下跌”。相反,我想“市场可能会下跌,但如果不会,我会安全吗?”

以典型的交易者为例,在我们的交易生涯中,我们都曾有过这样或那样的经历。你在周一开始交易一个新的策略,一个历史上表现很好的策略。但是在连续 4 次实时亏损后,你就放弃了这个系统,因为在回溯测试中你只有 3 次连续亏损。然后你继续下一个策略,永无止境地追求完美。当然,在你退出后不久,你原来的方法就从 4 个失败者那里恢复了。不幸的是,你没有享受到康复的乐趣!

如果你通过蒙特卡洛模拟运行你的系统,也许它会显示 40%的机会连续 4 次失败。然后,当 4 个失败者真的发生时,你会感到沮丧,但你可能没有放弃这个策略。毕竟,你知道有 40%的可能性会出现这么多连续的输家。

这样蒙特卡洛才能真正帮助你理解自己的交易策略。虽然我在我的 algo 交易中使用它,但它可以被任何交易者使用,只要他或她有有效和稳定的交易历史。然而,要求有效的交易历史也导致该技术的一些严重缺点。

**蒙特卡洛的弊端**

使用蒙特卡罗进行 algo 交易策略分析存在相当多的危险。第一个缺点是历史结果需要稳定。我说的“稳定”不是指实际的交易结果,而是指交易方法。坚持用相同的系统或方法交易的交易者有稳定的方法。一个交易者周一尝试 algo 交易,周二随机猜测,周三订单流交易,没有稳定的方法。

如果你不断调整你的交易方法,你的历史交易将毫无意义。对于有效的蒙特卡罗分析,历史结果应该是一致的;整个回溯测试只有一种策略,或者一种方法。

一个相关的概念是如果市场发生重大变化。当市场发生“阶跃”变化时,蒙特卡洛分析不再有效。这方面的一个例子是瑞士央行 2015 年的行动。2015 年 1 月 15 日,这家瑞士银行取消了它在 2011 年确立的与瑞士法郎挂钩的所谓“挂钩”政策。这种挂钩将瑞士法郎的价值与欧元挂钩。

随着联系汇率突然取消,市场反应激烈,再也没有回到以前的状态。因此,考虑到 2015 年市场的结构性变化,对 2011 年至 2015 年的历史结果使用蒙特卡洛毫无意义。人们不能合理地预期过去 2011 年至 2015 年期间进行的交易会持续到 2015 年及以后。市场已经发生了根本性的变化。

蒙特卡罗的另一个可能的缺点是交易的序列相关性。序列相关性是交易历史的一个特征,其中当前交易结果依赖于(相关于)先前的交易结果。标准的蒙特卡罗分析假设每笔交易都独立于前一笔交易。我的经验表明,对于许多交易系统来说,这通常是正确的(或者实际上是正确的)。

所以,如果你有一个具有序列相关性的策略(不管是不是特别内置的),蒙特卡罗结果将是错误的。一个简单的均线交叉系统就是这样的例子,信号根据之前交易的盈亏而变化。下面给出了串行相关策略的伪代码。

**非序列相关策略**

*如果收盘穿越 10 日均线,那么买入*

*如果收盘价低于 10 日均线,那么卖空*

**串行相关策略**

*如果收盘穿越 10 日均线,则*

*如果之前的交易有利可图,则卖空*

*如果之前的交易没有盈利,那么买入*

*如果收盘价低于 10 日均线,则*

*如果之前的交易有利可图,那么买入*

*如果之前的交易无利可图,则卖空*

序列相关系统将包含一个历史,其中交易[i]的结果依赖于交易[i-1]的结果。当进行传统的蒙特卡罗分析时,这种重要的依赖性将会消失。幸运的是,在这种情况下,有一些方法既可以检测序列相关性,又可以随后用改进的蒙特卡罗分析来处理它(超出了本文的范围)。

蒙特卡洛的最后一个缺点是古老的计算机编程格言“垃圾进,垃圾出”除了在这种情况下,它更像是“杰作进,杰作出。”

这是什么意思?简而言之,如果你的回溯测试看起来很棒,那可能是因为曲线拟合、过度优化、事后诸葛亮等等。在这种情况下,回溯测试杰作将产生一个很好的蒙特卡洛结果——破产的可能性很小,提款概率很小等等。

在这种情况下,蒙特卡洛模拟实际上会让你过于自信,并导致你做出一些糟糕的决定。所以,如果结果看起来好得不真实,你应该小心。在大多数情况下,他们可能是!

**从一个示例案例开始**

市场上有许多免费的和商业的蒙特卡罗模拟器,都有不同的功能和特性。一个很好的免费模拟器可以从 [TickQuest](http://www.tickquest.com/?page_id=70) 获得。这个特殊的模拟器有一些可视化结果的好方法。

另一个免费的模拟器是我为微软 Excel 创建的,可以在我网站的[计算器](https://kjtradingsystems.com/calculators.html)页面上找到。Excel 版本的好处是,如果你可以用 Excel 宏语言编程,你可以很容易地扩展模拟器的功能。这使得它非常适合想要增加头寸规模和其他功能的自己动手的交易者。

我将使用我的免费 Excel 蒙特卡洛模拟器作为下面的例子。

首先,在运行蒙特卡洛分析之前,你必须对交易进行历史回溯测试。这是由您使用的交易平台为您选择的策略和工具生成的。交易结果可在策略绩效报告中找到。如前所述,关键是交易结果不要过度优化或曲线拟合,因为这将给出过于乐观的模拟结果。

交易显示在图 4 的权益曲线中,前 10 笔交易显示在图 5 中。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f6ec53dedf4c4097d5b78d42549623f3.png)

Figure 4- Sample Equity Curve

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/af00dc6ac12fe771aba816ea7a2fa291.png)

Figure 5 — First 10 Trades For Sample Equity Curve (From Strategy Backtest)

这些交易代表大约一年的交易结果,有 150 笔交易,19,000 美元的利润和大约 7,000 美元的最大亏损。

有几点需要注意:首先,这里使用的交易结果不一定代表一个好的或坏的策略——它仅仅是一个例子。第二,可靠的蒙特卡罗分析通常包括 5-10 年的回溯测试结果。这个样本策略只有一年。

要运行模拟器,需要以下数字,如图 6 所示:

**A** —回溯测试的交易结果

**B** —模拟的起始权益(模拟器还将运行 10 个额外的起始权益值,从您输入的值开始递增)

**C** —退出股权点——如果在模拟过程中股权下降到低于该金额,模拟运行将停止,并被视为“破产”的情况很多时候,该值被设置为交易交易所的最低要求保证金,因为这是账户中启动新交易所需的最低金额。

**D** —一年的平均交易次数。模拟器运行了 1 年,进行了许多交易。

**E** —系统名称标识符

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/eaeb85421b4f4a8f3f197f14acc0ffef.png)

Figure 6- Inputs for Monte Carlo Simulation

一旦输入了所有需要的值,用户点击“计算”按钮,模拟开始。模拟器为 11 个不断增长的股票价值中的每一个运行 2500 个案例。结果显示在图 7 f 部分的表格中

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d66008bb9a91dae22dd2f16d2b3a7c5f.png)

Figure 7- Monte Carlo Output Results

**蒙特卡洛结果**

黄色表格包含蒙特卡洛模拟的结果:

**G** — Ruin:如果你用这个系统交易一年,一年时间内跌破退出点权益(C)的概率是多少?这就是破产的风险百分比。

**H** —中值下降:基于 2,500 次模拟运行,您有 50%的机会在第一年中获得高于所示值的最大下降。您希望这个数字尽可能低。请记住,即使有这个提款值,你仍然有 50%的机会,你的提款实际上会更高。相反,你也有 50%的机会,你的最大提款将会降低。

**I** —中间利润:基于 2500 次模拟运行,您有 50%的机会在第一年获得高于所示值的最大利润。您希望这个数字尽可能高。请记住,由于这是一个中间利润值,你的利润实际上很有可能会更低或更高。

**J** —中值回报:基于 2500 次模拟运行,你有 50%的机会在第一年获得高于所示数值的最大百分比回报。您希望这个数字尽可能高。同样,更高或更低的值都有 50%的可能性。

**K** —收益/DD 比率:收益对提取比率。与 Calmar 比率密切相关,Calmar 比率将回报和下降合并为一个指标。return/dd 值越高通常越好。不过要小心——如果 return/dd 太高,这可能意味着过度拟合。如果价值太低,你为给定回报所要承受的风险就会太高,这个策略就不值得交易。

L — Prob > 0:如果你用这种策略交易一整年,那么这一年盈利的可能性。

敏锐的读者会注意到,对于提款、利润和回报,给出了 2,500 次模拟运行的中值。这显然忽略了一些最糟糕的情况,许多交易者对此更感兴趣。电子表格是完全解锁的,因此可以修改这些值来反映任何所需的百分比。例如,第 95 百分位的提款通常很受欢迎。

假设蒙特卡洛结果是可接受的,交易者现在可以决定过渡到实时交易(模拟或用真钱)。这种现场表演可以通过使用概率锥来测量和跟踪。

**什么是概率锥?**

在制造业中,生产优质零件的最佳方式之一是在工厂车间利用统计过程控制(SPC)。SPC 帮助生产团队监控制造过程,并在不良零件生产出来之前采取措施。

在交易中,SPC 技术可以用来监控交易系统的性能。一种方法是使用控制图。图 8 显示了一个例子。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9de396f4114f8fa9a1b7d58f1926a7e1.png)

Figure 8- Statistical Process Control Chart

对于这种方法,记录每个交易结果,如果满足某些条件(例如,如果一个零件[交易]超出或低于 3 sigma 水平),则流程(策略)被视为失控,可能需要采取措施。在交易中,这可能就像关闭策略一样简单。

不过,使用控制图来监控交易系统的表现有一些问题。一个问题是,对于“失控”的情况有许多规则,并不是所有的规则都适用于大多数交易系统中的非序列相关交易。我的经验是,控制图可能有用,但并不理想。

监控实时交易表现的一个更好的方法是使用概率锥,也称为累积图。图 9 显示了一个示例图表。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/f4e593fe8e40bcf98503eee2a4a421d4.png)

Figure 9- Sample Probability Cone Chart

在此图表中,绘制了以下值:

回溯测试权益曲线(黑线)

回测的平均性能(灰线)

在策略开发结束时,策略进入实时交易阶段:

上部概率圆锥带(绿色实线和虚线)

低概率锥形带(实线和红色虚线)

实际交易,真钱还是模拟(蓝线)

如果实时股票曲线高于或低于绿色和红色定义的波段,很多时候停止交易是明智的,直到交易系统回到正常区域-在红色和绿色虚线之间。

**如何在交易中使用概率锥**

概率锥是监控交易系统实时表现的一种相对简单的方法。如果你有很多交易系统要监控,这是很理想的,对于多样化的算法交易者来说经常是这样。

开始分析只需要 4 个数字:

**M**——回溯测试中每笔交易的平均利润

**N** —交易回溯测试结果的标准差

**O** —内带阈值,表示为平均值以上的标准差

**P** —外带阈值,表示为平均值以下的标准偏差

一旦建立了分析,当交易实时结束时,每个单独的交易被添加到 Q 列。蓝色曲线描绘了这些交易。

图 10 显示了一个例子。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c17071b1d884048268a00944be015134.png)

Figure 10 — Inputs For Probability Cones

因为概率锥分析是蒙特卡洛分析的自然延伸,所以我在蒙特卡洛工作簿中为它提供了一个单独的工作表。

**使用概率锥的优势**

使用概率锥的最大好处是对结果没有隐瞒。如果与回溯测试相比,您的实时策略表现不佳,这一点很明显(参见图 11)。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/ab929d2ca01d005923ac62f7150ff42d.png)

Figure 11- When Cone Levels Are Crossed, Strategy Should Be Stopped

概率圆锥图帮助交易者做出公正的决定。例如,这可能有助于决定何时停止交易,这通常是一件情绪激动的事情(谁喜欢放弃他们用血汗和眼泪创造的策略?).

概率圆锥图的另一个优点是它实现简单,易于理解。如果股票曲线在上限和下限之间,交易系统很可能运行正常。如果权益曲线超过上限,谨慎是有保证的,因为这种良好的表现比预期好得多。诚然,这是一件好事,但市场发生变化了吗?系统会很快开始表现不佳,回到它的长周期平均水平吗?

如果权益曲线低于下限,也许系统坏了,或者市场变了。停止交易这种策略可能是合适的。

**概率锥的缺点**

即使这些圆锥是一个很好的工具,也有一些缺点。首先,对于具有非正态分布结果的策略,圆锥可能是不准确的。在这种情况下,建议使用回溯测试交易结果通过蒙特卡洛模拟生成上下曲线,而不是仅使用平均值和标准差。这种方法将提供更精确的波段。

该工具的第二个缺点是决定上下波段值。是否应该使用 1 标准差?在这种情况下,波段将更接近平均值,由于正常波动,策略可能会过早关闭。另一方面,如果使用了 3 个标准差波段,在现场交易突破其中一个波段之前,可能要交易很多次。这可能意味着一项失败的战略会损失大量资金。

概率锥的最后一个缺点是,正如蒙特卡罗分析一样,分析的效用是后验测试结果的直接函数。在后验测试结果过拟合或过优化的情况下,圆锥不会有很大帮助。一个过度优化的系统最终会跌破下限,但前提是交易者在交易一个不应该交易的系统时出现不必要的亏损。

**样本案例**

继续使用之前在蒙特卡洛分析中显示的相同交易系统,我们可以使用概率锥分析来监控我们的实时交易表现。

要进行这种分析,唯一需要的额外数字是实时交易结果(图 10 中的 Q)和内外带值(图 10 中的 O 和 P)。这些都输入到电子表格中,如图所示。

内带和外带西格玛值以标准差的数量输入,给出了基于正态曲线的概率:

1 标准偏差= 68%的实时权益曲线应落在上下内带内

2 标准差= 95%的实时权益曲线应落在上下外带内

图 11 显示了一个实时交易结果的示例。在这种特殊情况下,策略性能明显下降。许多交易者会考虑在下方的红色实线被突破时关闭策略。更保守的交易者会在虚线红线水平关闭策略。

但是,如果发生了这样的事件,仍然应该跟踪策略。如果策略表现后来有所改善,那么交易者可以考虑恢复交易策略。

**结论**

统计工具,如蒙特卡洛分析和概率锥,可以为交易者提供有用的交易系统信息。通过正确使用这些工具,交易者可以避免交易一个糟糕的策略,也可以知道什么时候停止交易一个表现不佳的系统。这些工具让交易者更容易控制(没有双关语的意思!)的交易。

虽然这些工具很有用,但请注意它们只是工具。交易者必须仍然负责,由交易者决定每次分析的结论是否恰当,是否应该遵循。盲目地遵循这一点(或任何分析)可能是危险的。我个人发现蒙特卡罗和概率锥都是有用的,但我知道它们的局限性和缺点。总的来说,我觉得这些工具让我成为更好的交易者,这是真正的终极考验。

# 10 分钟内:为数据专业人员提供美味汤和硒的网络刮擦

> 原文:<https://towardsdatascience.com/in-10-minutes-web-scraping-with-beautiful-soup-and-selenium-for-data-professionals-8de169d36319?source=collection_archive---------1----------------------->

## 分析权威指南

## 使用 BS4 和 Selenium 快速从维基百科和电子商务中提取关键信息

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/70ae4ea1e9e5fdcbe927dc3de5686a35.png)

WebScraping — Free Image

# 介绍

**网络抓取**是从网站和在线内容中提取有价值信息的过程。这是一种提取信息和接收数据集以供进一步分析的免费方法。在这个信息实际上高度相关的时代,我相信网络抓取提取替代数据的需求是巨大的,尤其是对我这个数据专业人员来说。

**本书的目标**是让你了解使用快速和肮脏的 Python 代码搜集任何公开可用信息的几种方法。只需花 10 分钟来阅读这篇文章——或者更好的是,投稿。然后你可以快速浏览一下你的第一个网络抓取工具的代码。

**在这篇文章**中,我们将学习如何从维基百科和电子商务(Lazada)中抓取数据。我们将清理、处理数据,并将数据保存到*中。csv* 文件。我们会用美汤和硒作为我们主要的网页抓取库。

# 什么是美汤和硒

## 美味的汤

Beautiful Soup 将 HTML 解析成机器可读的树格式,以便快速提取 DOM 元素。它允许提取特定段落和具有特定 HTML ID/Class/XPATH 的表格元素。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/76edecd824aeeeb9ed8c49cb45910b95.png)

Parsing of DOM elements compared to Tree Dir Folder

每当我需要一个快速和肮脏的方法来提取网上信息。我将永远把 BS 作为我的第一步。通常我会在不到 10 分钟的时间内提取 15 行代码。

[](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) [## 美丽的汤文档-美丽的汤 4.4.0 文档

### 美汤 4 是通过 PyPi 发布的,如果不能用系统打包器安装,可以安装…

www.crummy.com](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) 

## 硒

Selenium 是一款旨在实现 Web 浏览器自动化的工具。质量保证(QA)工程师通常使用它来自动测试 Selenium 浏览器应用程序。

此外,由于这些自动化功能,它对 web scrape 非常有用:

1.  单击特定的表单按钮
2.  在文本字段中输入信息
3.  提取浏览器 HTML 代码的 DOM 元素

[](https://www.seleniumhq.org/) [## Selenium - Web 浏览器自动化

### Selenium 得到了一些最大的浏览器供应商的支持,这些供应商已经(或正在)采取措施使 Selenium 成为一个…

www.seleniumhq.org](https://www.seleniumhq.org/) 

# 编写你的第一个网络抓取工具

(Github 在本文末尾)

# 美味的汤

## 问题陈述

假设你是联合国大使,打算访问世界各地的城市,讨论关于气候变化的京都议定书的状况。你需要计划你的旅行,但是你不知道每个国家的首都。因此,你谷歌了一下,在维基百科上找到了这个链接。

 [## 国家首都列表-维基百科

### 这是一个国家首都的列表,包括领土和属地的首都,非主权国家包括…

en.wikipedia.org](https://en.wikipedia.org/wiki/List_of_national_capitals) 

在这个链接中,有一个表格将每个国家映射到首都。你会发现这很好,但你不会止步于此。作为一名数据科学家和联合国大使,您希望从维基百科中提取表格,并将其转储到您的数据应用程序中。你接受了挑战,用 Python 和 BeautifulSoup 编写了一些脚本。

## 步伐

我们将利用以下步骤:

1.  **Pip 安装**[**beautiful soup**](https://pypi.org/project/beautifulsoup4/)**4、Pip 安装请求**。请求将从 URL 获取 HTML 元素,这将成为 BS 解析的输入。
2.  **检查表格引用的是哪个 DOM 元素**。右击鼠标并点击*检查元件*。Chrome 浏览器的快捷键是 CTRL+I (inspect)。
3.  **点击左上角的检查按钮**突出显示您想要提取的元素。现在您知道了元素是 HTML 文档中的一个表格元素。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/28fbf0c8c2104eceebde32e5cdb1ac68.png)

National Capitals Elements Wikipedia

4.**在您的请求中添加标题和 URL**。这将在维基百科链接中创建一个请求。标题对于欺骗您的请求很有用,这样它看起来就像来自合法的浏览器。

对于维基百科来说,这可能无关紧要,因为所有的信息都是开源的,可以公开获得。但对于其他一些网站,如金融交易网站(SGX),它可能会阻止没有合法标题的请求。

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36'}
url = "https://en.wikipedia.org/wiki/List_of_national_capitals"
r = requests.get(url, headers=headers)


5.**启动 BS 和列表元素**提取表格中的所有行

soup = BeautifulSoup(r.content, "html.parser")
table = soup.find_all('table')[1]
rows = table.find_all('tr')
row_list = list()


6.**遍历表**中的所有行,遍历每个单元格,将其添加到 rows 和 row_list 中

for tr in rows:
td = tr.find_all('td')
row = [i.text for i in td]
row_list.append(row)


7.**创建熊猫数据框架并将数据导出到 csv**

df_bs = pd.DataFrame(row_list,columns=['City','Country','Notes'])
df_bs.set_index('Country',inplace=True)
df_bs.to_csv('beautifulsoup.csv')


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/c9f332ba5096ad04778f5e887f625124.png)

Result of web scraping in csv

> 恭喜你!只需 7 个步骤和 15 行代码,你就成为了一名专业的 web scraper

## 美丽的汤的局限性

到目前为止,BS 为我们成功地进行了网络搜集。但是我发现根据问题的不同有一些限制:

1.  请求过早地接受 html 响应,而不等待 Javascript 的异步调用来呈现浏览器。这意味着它不能获得 Javascript 异步调用(AJAX 等)生成的最新 DOM 元素。
2.  在线零售商,如亚马逊或 Lazada 在网站上安装了反机器人软件,可能会阻止你的爬虫。这些零售商将关闭任何来自 Beautiful Soup 的请求,因为它知道这些请求不是来自合法的浏览器。

> **注**
> 
> 如果我们在 Lazada 和 Amazon 等电子商务网站上运行 Beautiful Soup,我们会遇到这种连接错误,这是由他们的反垃圾软件阻止机器人发出 http 请求造成的。
> 
> https connection pool(host = '[www . Amazon . com '](http://www.amazon.com'),port=443):超过 url 的最大重试次数:/(由 SSLError 引起(SSLError(1,'[SSL:CERTIFICATE _ VERIFY _ FAILED]证书验证失败(_ssl.c:833)'),))

解决这个问题的一个方法是使用客户端浏览器,并自动化我们的浏览行为。我们可以通过使用硒来实现这一点。

硒万岁!!

# 

## 问题陈述

假设您正在创建价格波动模型来分析 Lazada 和 Amazon 等电子商务提供商。如果没有网络抓取工具,你需要雇人手动浏览大量的产品页面,并把价格一个一个地复制粘贴到 Excelsheet 中。这个过程是非常重复的,特别是如果你想每天/每小时收集数据点。这也将是一个非常耗时的过程,因为它涉及许多手动点击和浏览来复制信息。

> 如果我告诉你,你可以自动化这个过程:
> 
> 通过让 Selenium 为您进行产品探索和点击。
> 
> 通过让 Selenium 打开你的谷歌 Chrome 浏览器来模仿合法用户的浏览行为。
> 
> 让 Selenium 将所有信息抽取到列表和 csv 文件中。

你很幸运,因为你所需要做的就是写一个简单的 Selenium 脚本,然后你就可以在睡个好觉的同时运行 web 抓取程序了。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/07a53f119bfe8054a24bc0df7d9a8465.png)

Extracting Lazada Information and Products are time consuming and repetitive

## 安装

1.  **皮普安装硒**。
2.  **安装硒浏览器**。请参考此链接确定您最喜欢的浏览器(Chrome、Firefox、IE 等)。将它放在与项目相同的目录中。如果你不确定使用哪一个,可以从下面的 Github 链接下载。
3.  **包括这些导入**

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException


4.**通过插入可执行路径和 url 驱动 Selenium Chrome 浏览器**。在我的例子中,我使用相对路径来查找位于与我的脚本相同的目录中的 chromedriver.exe。

driver = webdriver.Chrome(executable_path='chromedriver')
driver.get('https://www.lazada.sg/#')


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/2e634f50426bf291714e0d129c17efc8.png)

Selenium Running Chrome and Extract Lazada and Redmart Data

5.**等待页面加载并找到元素**。这就是 Selenium 与 Requests 和 BS 的不同之处。您可以指示页面等待,直到呈现出某个 DOM 元素。之后,它会继续运行它的网络抓取逻辑。

您可以停止等待,直到满足预期条件(EC)以通过 ID*“Level _ 1 _ Category _ No1”进行查找。*如果已经过了 30 秒没有找到该元素,则通过 *TimeoutException* 关闭浏览器。

timeout = 30
try:
WebDriverWait(driver, timeout).until(EC.visibility_of_element_located((By.ID, "Level_1_Category_No1")))
except TimeoutException:
driver.quit()


恭喜你。我们已经设置了 Selenium 来使用我们的 Chrome 浏览器。现在我们已经准备好自动化信息提取了。

## 信息提取

让我们从 Lazada 网站中识别几个属性,并提取它们的 DOM 元素。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/61133eeefb82c87c0a8c6bb19211a7b2.png)

Extracting the DOM Elements via ID, Class, and XPATH Attributes

1.  **find_element by ID** 返回相关的类别列表。

category_element = driver.find_element(By.ID,'Level_1_Category_No1').text;

result -- Electronic Devices as the first category listing


2.**获取无序列表 xpath** (ul)并提取每个列表项的值(li)。您可以检查元素,右键单击并选择 copy > XPATH 来轻松地生成相关的 XPATH。请随意打开以下链接了解更多详情。

[](https://www.softwaretestinghelp.com/locate-elements-in-chrome-ie-selenium-tutorial-7/) [## 如何在 Chrome 和 IE 浏览器中定位元素以构建 Selenium 脚本- Selenium 教程…

### 这是我们 Selenium 在线培训系列的教程#7。如果您想查看本系列的所有 Selenium 教程…

www.softwaretestinghelp.com](https://www.softwaretestinghelp.com/locate-elements-in-chrome-ie-selenium-tutorial-7/) 

list_category_elements = driver.find_element(By.XPATH,'//*[@id="J_icms-5000498-1511516689962"]/div/ul')
links = list_category_elements.find_elements(By.CLASS_NAME,"lzd-site-menu-root-item")
for i in range(len(links)):
print("element in list ",links[i].text)

result


## 点击和操作

1.  **自动行动**。假设你想从 Lazada 主页浏览 Redmart,你可以模仿点击 *ActionChains 对象。*

element = driver.find_elements_by_class_name('J_ChannelsLink')[1]
webdriver.ActionChains(driver).move_to_element(element).click(element).perform()


## 从 Redmart 提取所有产品列表

1.  **创建产品标题列表**。我们可以提取并打印它们如下

product_titles = driver.find_elements_by_class_name('title')
for title in product_titles:
print(title.text)


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/cd1e7e81ff0821e9654976dc6b8b9c7b.png)![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8ae595588cb166d5f1d8dca8e446f8ef.png)

Redmart Best Seller Title Extractions

2.**提取产品名称、包装尺寸、价格和等级**。我们将打开几个列表来包含每一项,并将它们转储到一个数据帧中。

product_containers = driver.find_elements_by_class_name('product_container')

for container in product_containers: product_titles.append(container.find_element_by_class_name('title').text)
pack_sizes.append(container.find_element_by_class_name('pack_size').text) product_prices.append(container.find_element_by_class_name('product_price').text)
rating_counts.append(container.find_element_by_class_name('ratings_count').text)

data = {'product_title': product_titles, 'pack_size': pack_sizes,'product_price': product_prices, 'rating_count': rating_counts}


3.**将信息**转储到熊猫数据帧和 csv 中

df_product = pd.DataFrame.from_dict(data)
df_product.to_csv('product_info.csv')


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a32565037916ee9e390e0b06674a1da5.png)

CSV Dump for each of the product in Best Seller Redmart

> 恭喜你。你已经有效地扩展了你的技能,提取任何网上找到的信息!

# 目的、Github 代码和您的贡献

这个概念证明(POC)的目的是作为我自己的项目的一部分创建的。这个应用程序的目标是使用 web 抓取工具来提取任何公共可用的信息,而不需要太多的成本和人力。

在这个 POC 中,我使用 Python 作为脚本语言,[*B*](https://www.mathworks.com/matlabcentral/answers/155126-how-does-the-vision-cascadeobjectdetector-detect-left-and-right-eyes-separately-it-is-constantly-de)*eautiful Soup 和 Selenium library* 提取必要的信息。

Github Python 代码位于下面。

[](https://github.com/VincentTatan/Web-Scraping) [## Vincent tatan/网页抓取

### 美汤硒网刮。为 VincentTatan/Web 抓取开发做出贡献,创建一个…

github.com](https://github.com/VincentTatan/Web-Scraping) 

您可以随意克隆这个库,并在有时间的时候贡献自己的一份力量。

# 美汤和股票投资

代替今天关于 python 和 web 抓取的主题。你也可以看看我的另一篇关于为有抱负的投资者搜集信息的文章。您应该尝试通过这个演示来指导您编写快速而肮脏的 Python 代码,以便收集、分析和可视化股票。

[](/value-investing-dashboard-with-python-beautiful-soup-and-dash-python-43002f6a97ca) [## 价值投资仪表盘,配有 Python Beautiful Soup 和 Dash Python

### 价值投资的 Web 抓取与快速 Dash 可视化概述

towardsdatascience.com](/value-investing-dashboard-with-python-beautiful-soup-and-dash-python-43002f6a97ca) 

希望从这篇相关的出版物中,您可以学习如何收集关键信息并开发有用的应用程序。如果你喜欢,请阅读并联系我。

## 最后…

咻…就是这样,关于我的想法,我把它写成了文字。我真的希望这对你们来说是一个伟大的阅读。因此,我希望我的想法可以成为你发展和创新的灵感来源。

请**在下面评论**出来建议和反馈。

快乐编码:)

# 关于作者

Vincent Tatan 是一名数据和技术爱好者,拥有在 Visa Inc .和 Lazada 实施微服务架构、数据工程和分析管道项目[的相关工作经验。](https://bit.ly/2I8jkWV.)

Vincent 是土生土长的印度尼西亚人,在解决问题方面成绩斐然,擅长全栈开发、数据分析和战略规划。

他一直积极咨询 SMU BI & Analytics Club,指导来自不同背景的有抱负的数据科学家和工程师,并为企业开发他们的产品开放他的专业知识。

请通过 [**LinkedIn**](http://www.linkedin.com/in/vincenttatan/) **,**[**Medium**](https://medium.com/@vincentkernn)**或** [**Youtube 频道**](https://www.youtube.com/user/vincelance1/videos) 联系文森特

**免责声明**

**本免责声明告知读者,文中表达的观点、想法和意见仅属于作者,不一定属于作者的雇主、组织、委员会或其他团体或个人****参考文献是从列表中挑选的,与其他作品的任何相似之处纯属巧合**

这篇文章纯粹是作者的个人项目,与任何其他隐藏的目的无关。

# 12 分钟:熊猫和 Scikit 的股票分析-学习

> 原文:<https://towardsdatascience.com/in-12-minutes-stocks-analysis-with-pandas-and-scikit-learn-a8d8a7b50ee7?source=collection_archive---------0----------------------->

## 使用 Python 快速分析、可视化和预测股票价格

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/245adbd90d8a36954ed6461e4abc490f.png)

Predicting Stocks with Data Analysis

一天,我的一个朋友告诉我,财务自由的关键是投资股票。虽然在市场繁荣时期这是非常正确的,但在今天兼职交易股票仍然是一个有吸引力的选择。鉴于网上交易平台的便捷性,有许多自我价值投资者或家庭主妇交易者。甚至有成功的故事和广告吹嘘“*快速致富计划*”,学习如何投资股票,回报率高达 40%甚至更多。如今,投资已经成为职业人士的福音。

**现在的问题是:**哪些股票?你如何分析股票?与竞争对手相比,这只股票的回报和风险如何?

本书的目的是让你了解一种使用快速而肮脏的 Python 代码来分析股票的方法。只需花 12 分钟来阅读这篇文章——或者更好的是,投稿。然后,你可以快速浏览一下,编写你的第一份财务分析。

**为了开始学习和分析股票**,我们将从快速浏览历史股票价格开始。这将通过从熊猫网络数据阅读器和雅虎财经中提取最新的股票数据来完成。然后,我们将尝试通过探索性分析来查看数据,例如关联热图、matplotlib 可视化以及使用线性分析和 K 近邻(KNN)的预测分析。

# 正在加载 YahooFinance 数据集

[Pandas web 数据阅读器](https://pandas-datareader.readthedocs.io/en/latest/)是 Pandas 库的扩展,用于与最新的金融数据进行通信。这将包括以下来源:雅虎财经、谷歌财经、英格玛等。

我们将使用以下代码提取苹果股票价格:

import pandas as pd
import datetime
import pandas_datareader.data as web
from pandas import Series, DataFrame

start = datetime.datetime(2010, 1, 1)
end = datetime.datetime(2017, 1, 11)

df = web.DataReader("AAPL", 'yahoo', start, end)
df.tail()


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/6563f2af47d7c7e54cf5ac2e96b351bc.png)

Stocks Prices from Yahoo Finance

这段代码将提取从 2010 年 1 月到 2017 年 1 月的 7 年数据。如果你认为有必要,可以随意调整开始和结束日期。在接下来的分析中,我们将使用收盘价,它表示股票在一天结束时的最终交易价格。

# 探索股票的滚动平均和收益率

在这个分析中,我们使用两个关键指标来分析股票:滚动平均值和回报率。

## 滚动平均(移动平均)——确定趋势

滚动平均/移动平均(MA)通过创建不断更新的[平均价格](https://www.investopedia.com/terms/a/averageprice.asp)来平滑价格数据。这有助于减少价格图表中的“噪音”。此外,这种移动平均线可以作为“阻力”,这意味着从股票的下跌趋势和上涨趋势中,你可以预计它将跟随趋势,不太可能偏离其阻力点。

[](https://www.investopedia.com/articles/active-trading/052014/how-use-moving-average-buy-stocks.asp) [## 如何用均线买股票

### 移动平均线(MA)是一个简单的技术分析工具,它通过创建一个持续的…

www.investopedia.com](https://www.investopedia.com/articles/active-trading/052014/how-use-moving-average-buy-stocks.asp) 

让我们开始计算滚动平均值:

close_px = df['Adj Close']
mavg = close_px.rolling(window=100).mean()


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/064502ee4a5a09b0bb1ac3b24e92ecc2.png)

The Last 10 Moving Average

这将计算股票收盘价的最后 100 个窗口(100 天)的移动平均值,并取每个窗口移动平均值的平均值。正如你所看到的,移动平均线在窗口内稳步上升,并不跟随股价图的锯齿状线。

为了更好的理解,让我们用 Matplotlib 把它画出来。我们将移动平均线与股票价格图重叠。

%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib import style

# Adjusting the size of matplotlib
import matplotlib as mpl
mpl.rc('figure', figsize=(8, 7))
mpl.version

# Adjusting the style of matplotlib
style.use('ggplot')

close_px.plot(label='AAPL')
mavg.plot(label='mavg')
plt.legend()


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/262a93be03b56d4118d9c3ae0b55e073.png)

Apple Stocks Price with The Moving Average (mavg)

移动平均线使线变得平滑,显示股票价格的上升或下降趋势。

在这张图表中,移动平均线显示了股价上涨或下跌的上升趋势。从逻辑上讲,你应该在股票下跌时买入,在股票上涨时卖出。

## 回报偏差——确定风险和回报

> 预期**回报**衡量投资**回报**的概率分布的平均值或期望值。投资组合的预期**回报**的计算方法是将每项资产的权重乘以其预期**回报**,然后将每项投资的价值相加——Investopedia。

下面是你可以参考的公式:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/9b1da95ca3d0163de060241b8f2653b9.png)

Formula for Returns

基于这个公式,我们可以将我们的回报绘制如下。

rets = close_px / close_px.shift(1) - 1rets.plot(label='return')


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/7c02814ba188564778af50ef01025b87.png)

Plotting the Return Rate

从逻辑上讲,我们理想的股票回报应该尽可能的高且稳定。如果你是风险厌恶者(像我一样),你可能会想避开这类股票,因为你看到了 2013 年 10%的跌幅。这个决定很大程度上取决于你对股票的总体看法和对竞争对手的分析。

# 分析竞争对手的股票

在这一部分,我们将分析一家公司相对于其竞争对手的表现。让我们假设我们对科技公司感兴趣,并想比较一下*大公司:*苹果、通用电气、谷歌、IBM 和微软。

dfcomp = web.DataReader(['AAPL', 'GE', 'GOOG', 'IBM', 'MSFT'],'yahoo',start=start,end=end)['Adj Close']


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/2208e6d42e3b3b5ad5cd157f176cc024.png)

Stocks Price for Apple, General Electrics, Google, IBM, and Microsoft

这将返回一个光滑的雅虎财经股票收盘价表。整洁!!

## 相关性分析——一个竞争对手会影响其他竞争对手吗?

我们可以通过运行熊猫的百分比变化和相关函数来分析竞争。百分比变化将发现多少价格变化相比,前一天的定义回报。了解相关性将有助于我们了解回报是否受到其他股票回报的影响

retscomp = dfcomp.pct_change()

corr = retscomp.corr()


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/a7720d20ababf4f66e64daf3ac84d142.png)

让我们用散点图把苹果和通用电气画出来,看看它们的回报分布。

plt.scatter(retscomp.AAPL, retscomp.GE)
plt.xlabel(‘Returns AAPL’)
plt.ylabel(‘Returns GE’)


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/817fe440825aa977595ac62b0d9b1006.png)

Scatter Plot of GE and AAPL

我们可以看到,通用电气的回报和苹果的回报之间存在轻微的正相关关系。似乎在大多数情况下,苹果的回报越高,通用电气的回报也越高。

让我们通过绘制 scatter_matrix 来进一步改进我们的分析,以可视化竞争股票之间可能的相关性。在对角点,我们将运行核密度估计(KDE)。KDE 是一个基本的数据平滑问题,根据有限的数据样本对总体进行推断。它有助于生成总体分布的估计值。

[](https://en.wikipedia.org/wiki/Kernel_density_estimation) [## 核密度估计-维基百科

### 在统计学中,核密度估计(KDE)是一种估计概率密度函数的非参数方法

en.wikipedia.org](https://en.wikipedia.org/wiki/Kernel_density_estimation) 

pd.scatter_matrix(retscomp, diagonal='kde', figsize=(10, 10));


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/8877c98f34181019d77fcef797def923.png)

KDE Plots and Scatter Matrix

从这里我们可以看到大多数股票之间近似正相关的分布。

为了证明正相关,我们将使用热图来可视化竞争股票之间的相关范围。请注意,颜色越浅,两只股票的相关性越强。

plt.imshow(corr, cmap='hot', interpolation='none')
plt.colorbar()
plt.xticks(range(len(corr)), corr.columns)
plt.yticks(range(len(corr)), corr.columns);


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/e6c9fd9193e9ee4f020b75ae03b42364.png)

Heatmap of Correlations among competing stocks

从散点图和热图中,我们可以发现竞争股票之间有很大的相关性。然而,这可能不会显示因果关系,可能只是显示技术行业的趋势,而不是显示竞争股票如何相互影响。

## 股票回报率和风险

除了相关性,我们还分析每只股票的风险和回报。在这种情况下,我们提取回报率的平均值(回报率)和回报率的标准差(风险)。

plt.scatter(retscomp.mean(), retscomp.std())
plt.xlabel('Expected returns')
plt.ylabel('Risk')
for label, x, y in zip(retscomp.columns, retscomp.mean(), retscomp.std()):
plt.annotate(
label,
xy = (x, y), xytext = (20, -20),
textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/3d5b7e72049647e1e40c48f725dd602f.png)

Quick Scatter Plot among Stocks Risk and Returns

现在你可以看到这张简单的竞争股票的风险和回报对比图。从逻辑上来说,你想最小化风险,最大化回报。因此,你需要为你的风险回报承受能力画一条线(红线)。然后,你可以创建规则,买入红线以下的股票(MSFT、通用电气和 IBM),卖出红线以上的股票(AAPL 和谷歌)。这条红线展示了你的期望值阈值和你的买入/卖出决策基线。

# 预测股票价格

## 特征工程

我们将使用这三种机器学习模型来预测我们的股票:简单线性分析、二次判别分析(QDA)和 K 近邻(KNN)。但是首先,让我们设计一些特征:高/低百分比和百分比变化。

dfreg = df.loc[:,[‘Adj Close’,’Volume’]]
dfreg[‘HL_PCT’] = (df[‘High’] — df[‘Low’]) / df[‘Close’] * 100.0
dfreg[‘PCT_change’] = (df[‘Close’] — df[‘Open’]) / df[‘Open’] * 100.0


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/4190f1fab1383034c84dd6e9b81c1beb.png)

The end Data Frame Produced

## 预处理和交叉验证

在将数据放入预测模型之前,我们将使用以下步骤清理和处理数据:

1.  *丢弃缺失值*
2.  *在这里分离标签,我们要预测 AdjClose*
3.  *缩放 X,这样每个人都可以有相同的线性回归分布*
4.  *最后,我们希望找到 X 年末和 X 年初(训练)的数据序列,用于模型生成和评估*
5.  *分离标签并将其识别为 y*
6.  *通过交叉验证训练测试分割分离模型的训练和测试*

请参考下面的准备代码。

Drop missing value

dfreg.fillna(value=-99999, inplace=True)# We want to separate 1 percent of the data to forecast
forecast_out = int(math.ceil(0.01 * len(dfreg)))# Separating the label here, we want to predict the AdjClose
forecast_col = 'Adj Close'
dfreg['label'] = dfreg[forecast_col].shift(-forecast_out)
X = np.array(dfreg.drop(['label'], 1))# Scale the X so that everyone can have the same distribution for linear regression
X = preprocessing.scale(X)# Finally We want to find Data Series of late X and early X (train) for model generation and evaluation
X_lately = X[-forecast_out:]
X = X[:-forecast_out]# Separate label and identify it as y
y = np.array(dfreg['label'])
y = y[:-forecast_out]


## 模型生成——预测乐趣的开始

但是首先,让我们为我们的 Scikit-Learn 插入以下导入:

from sklearn.linear_model import LinearRegression
from sklearn.neighbors import KNeighborsRegressor

from sklearn.linear_model import Ridge
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline


## 简单线性分析和二次判别分析

简单的线性分析显示了两个或多个变量之间的线性关系。当我们在两个变量之间画这个关系时,我们得到一条直线。二次判别分析类似于简单的线性分析,只是该模型允许多项式(例如:x 的平方)并会产生曲线。

给定自变量(x)作为输入,线性回归预测因变量(y)作为输出。在绘图过程中,这将给我们一条直线,如下所示:

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/321526fbb4d26ac18c93fe900373fff9.png)

Simple Linear Regression

这是一个惊人的出版物,它展示了一个非常全面的线性回归审查。请参考下面的链接查看。

[](/a-beginners-guide-to-linear-regression-in-python-with-scikit-learn-83a8f7ae2b4f) [## 用 Scikit 学习 Python 线性回归的初学者指南

### 有两种类型的监督机器学习算法:回归和分类。前者预测…

towardsdatascience.com](/a-beginners-guide-to-linear-regression-in-python-with-scikit-learn-83a8f7ae2b4f) 

我们将即插即用现有的 Scikit-Learn 库,并通过选择我们的 X 和 y 训练集来训练模型。代码如下所示。

# Linear regression
clfreg = LinearRegression(n_jobs=-1)
clfreg.fit(X_train, y_train)# Quadratic Regression 2
clfpoly2 = make_pipeline(PolynomialFeatures(2), Ridge())
clfpoly2.fit(X_train, y_train)

# Quadratic Regression 3
clfpoly3 = make_pipeline(PolynomialFeatures(3), Ridge())
clfpoly3.fit(X_train, y_train)


## k 最近邻(KNN)

该 KNN 使用特征相似度来预测数据点的值。这确保了分配的新点与数据集中的点相似。为了找出相似性,我们将提取点来释放最小距离(例如:欧几里德距离)。

![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/d30c776a5654c1d1f071479d9d812a15.png)

KNN Model Visualization where you would group the questioned element in k number of elements

请参考此链接,了解有关该模型的更多详细信息。这对提高你的理解能力真的很有用。

[](https://www.analyticsvidhya.com/blog/2018/03/introduction-k-neighbours-algorithm-clustering/) [## k 近邻介绍:简化(用 Python 实现)

### 注意:这篇文章最初发表于 2014 年 10 月 10 日,更新于 2018 年 3 月 27 日

www.analyticsvidhya.com](https://www.analyticsvidhya.com/blog/2018/03/introduction-k-neighbours-algorithm-clustering/) 

# KNN Regression
clfknn = KNeighborsRegressor(n_neighbors=2)
clfknn.fit(X_train, y_train)


## 估价

一种简单快速且肮脏的评估方法是在每个训练好的模型中使用评分方法。评分法用测试数据集的 y 值来计算 self.predict(X)的平均准确度。

confidencereg = clfreg.score(X_test, y_test)
confidencepoly2 = clfpoly2.score(X_test,y_test)
confidencepoly3 = clfpoly3.score(X_test,y_test)
confidenceknn = clfknn.score(X_test, y_test)# results
('The linear regression confidence is ', 0.96399641826551985)
('The quadratic regression 2 confidence is ', 0.96492624557970319)
('The quadratic regression 3 confidence is ', 0.9652082834532858)
('The knn regression confidence is ', 0.92844658034790639)


这显示了大多数模型的巨大准确性得分(> 0.95)。然而,这并不意味着我们可以盲目地放置我们的股票。仍然有许多问题需要考虑,特别是不同的公司,随着时间的推移有不同的价格轨迹。

为了进行健全性测试,让我们打印一些股票预测。

forecast_set = clf.predict(X_lately)
dfreg['Forecast'] = np.nan#result
(array([ 115.44941187, 115.20206522, 116.78688393, 116.70244946,
116.58503739, 115.98769407, 116.54315699, 117.40012338,
117.21473053, 116.57244657, 116.048717 , 116.26444966,
115.78374093, 116.50647805, 117.92064806, 118.75581186,
118.82688731, 119.51873699]), 0.96234891774075604, 18)


# 绘制预测图

基于预测,我们将使用现有的历史数据来可视化绘图。这将有助于我们直观地看到模型如何预测未来的股票定价。

last_date = dfreg.iloc[-1].name
last_unix = last_date
next_unix = last_unix + datetime.timedelta(days=1)

for i in forecast_set:
next_date = next_unix
next_unix += datetime.timedelta(days=1)
dfreg.loc[next_date] = [np.nan for _ in range(len(dfreg.columns)-1)]+[i]dfreg['Adj Close'].tail(500).plot()
dfreg['Forecast'].tail(500).plot()
plt.legend(loc=4)
plt.xlabel('Date')
plt.ylabel('Price')
plt.show()


![](https://gitcode.net/OpenDocCN/towardsdatascience-blog-zh-2019/-/raw/master/docs/img/1c654809725e7311cbb353a664d34c23.png)

Predictions Displayed in Plot

我们可以看到蓝色展示了基于回归的股票价格预测。该预测预测,经济低迷不会持续太久,然后就会复苏。因此,我们可以在下跌时买入股票,在上涨时卖出。

# 未来的改进/挑战

为了进一步分析股票,这里有一些关于你如何做贡献的想法。这些想法将有助于对股票进行更全面的分析。如果需要更多的澄清,请随时告诉我。

*   分析经济定性因素,如新闻(新闻来源和情感分析)
*   分析某个国家的 HPI、公司来源之间的经济不平等等经济数量因素

# 目的、Github 代码和您的贡献

本概念证明(POC)是作为我目前管理的投资方项目的一部分而创建的。这个应用程序的目标是帮助您快速检索和显示关于某个公司股票价格的正确的金融见解,并预测其价值。

在 POC 中,我使用 Pandas- Web Datareader 来查找股票价格,使用 Scikit-Learn 来预测和生成机器学习模型,最后使用 Python 作为脚本语言。Github Python 笔记本代码位于下面。

[](https://github.com/VincentTatan/PythonAnalytics/blob/master/Youtube/Lesson%203%20%20Basic%20Python%20for%20Data%20Analytics%20%28Stocks%20Prediction%29.ipynb) [## Python Analytics/第 3 课用于数据分析的基本 Python(股票预测)。主机上的 ipynb

### 这是一个存放我的 Kaggle 和 iPython 笔记本的地方——python analytics/第三课基础…

github.com](https://github.com/VincentTatan/PythonAnalytics/blob/master/Youtube/Lesson%203%20%20Basic%20Python%20for%20Data%20Analytics%20%28Stocks%20Prediction%29.ipynb) 

您可以随意克隆这个库,并在有时间的时候贡献自己的一份力量。

# 价值投资

代替今天关于股票分析的话题。你也可以访问我的价值投资出版物,在那里我谈到了搜集股票金融信息,并将其显示在一个易于阅读的仪表板上,该仪表板根据[价值投资方法](https://www.investopedia.com/university/stockpicking/stockpicking3.asp)处理股票估值。请访问并投稿:)。

[](/value-investing-dashboard-with-python-beautiful-soup-and-dash-python-43002f6a97ca) [## 价值投资仪表盘,配有 Python Beautiful Soup 和 Dash Python

### 价值投资的 Web 抓取与快速 Dash 可视化概述

towardsdatascience.com](/value-investing-dashboard-with-python-beautiful-soup-and-dash-python-43002f6a97ca) 

***来自《走向数据科学》编辑的提示:*** *虽然我们允许独立作者根据我们的* [*规则和指导方针*](/questions-96667b06af5) *发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的* [*读者术语*](/readers-terms-b5d780a700a4) *。*

## 感谢

我想感谢我的会计和金融朋友们,他们给了我关于这本书的建设性反馈。我真的很高兴得知你从我的出版物中获得了很多价值。

## 最后…向我伸出手

咻…就是这样,关于我的想法,我把它写成了文字。我真的希望这对你们来说是一个伟大的阅读。因此,我希望我的想法可以成为你发展和创新的灵感来源。

请通过我的 [**LinkedIn**](http://www.linkedin.com/in/vincenttatan/) 联系我,订阅我的 [**Youtube 频道**](https://www.youtube.com/user/vincelance1/videos)

如果你喜欢,请给我**掌声**。

**下面评论**出来建议和反馈。

快乐编码:)

**免责声明:本免责声明告知读者,文中表达的观点、想法和意见仅属于作者,不一定属于作者的雇主、组织、委员会或其他团体或个人**。**参考文献从列表中挑选,与其他作品的任何相似之处纯属巧合**

**本文纯粹是作者的个人项目,绝无任何其他不可告人的目的。**
posted @   绝不原创的飞龙  阅读(28)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示