基于购买历史的用户细分
一个用例,说明我们如何使用机器学习,根据用户的购买力来确定不同产品的目标用户。
介绍
这一分析的目标是使用折扣应用程序,根据他们获得的交易确定不同的用户群,以便为他们重新提供类似于他们过去获得的优惠。
机器学习算法 K-means 用于根据用户的购买行为识别用户群。这是算法提取内容的三维图。
3D image of clusters produced by K-Means, by Muffaddal
术语:
在深入分析之前,让我们定义一些正在使用的关键字。
**交易收益:**当用户使用 app 获得折扣时。
**花费:**用户购买物品时支付的折扣价。
**保存:**用户通过 app 保存的金额。
**品牌:**提供折扣的商家如必胜客、格力诺
**交易:**提供给不同店铺和品牌用户的折扣。
分析
数据集
使用 JQL 从 Mixpanel 中提取行为数据集。该分析使用了以下内容
Mixpanel Data Set, by Muffaddal
userId: 用户的唯一 id
save amount:用户在交易受益
上节省的金额 spentAmount :用户在交易受益
brandName :交易受益的品牌
count :用户受益的交易数量
使用上述数据集averagesavenamount,为每个用户计算 averageSavedAmount 和dealavaillcount,如下所示
Average Deal Availed Data set, by Muffaddal
机器学习— K-means 聚类 K-mean 算法的第一步是找到最佳数量的聚类进行分割。为此有许多方法,其中之一是使用类内平方和(wcss)的肘方法。
WCSS for up-to 10 clusters, by Muffaddal
基于肘方法,使用 4、5 和 6 个聚类来探索片段,并挑选 4 个聚类作为给定数据集的最佳聚类。
R code for K-Means clustering
如果你想了解更多关于用户聚类和用户细分的知识,我会推荐 数据营 和Coursera上的这些课程。
K-means 提取了哪些片段?
以下是四个已确定细分市场的平均统计数据:
Average stats of each segment
Segments Characteristics
Graphical Representation of Segments Characteristics, by Muffaddal
细分市场 1 和 2 中的用户是高付费用户,细分市场 1 中的用户在每笔交易中也节省了同样高的费用(可能有买一送一的优惠)。然而,这些用户利用的交易数量少于 2(即分别为 1.3 和 1.4)。
另一方面,细分市场 3 和细分市场 4 的用户花费较少,因此储蓄也较少。然而,在所有 4 个细分市场中,细分市场 4 的用户拥有最大的每用户交易收益比率(平均每个用户收益超过 9 笔交易)。这是转变最多的一批用户。
每个细分市场的用户总数和交易数量是多少?
这是用户总数和每个细分市场用户的交易量。
Number of users in segments, by Muffaddal
Number of deals availed, by Muffaddal
57%的用户属于细分市场 3,只有 3%的用户来自转化率最高的细分市场(即细分市场 4)。
总体用户支出是多少?
这是各细分市场的支出分布情况
Spending of users in each segment, by Muffaddal
来自细分市场 4 的一些用户(细分市场 4 中的黄点)与细分市场 1 和 2 类似,但细分市场 3(包括 57%的用户)根本不喜欢高消费交易和/或品牌。
每个细分市场用户首选的品牌类型?
让我们看看这些细分市场用户利用什么类型的品牌来了解他们之间的区别。
Brands users availed, by Muffaddal
细分市场 1 的用户利用了汉堡、比萨饼和欢乐时光的组合,细分市场 2 的用户利用了比萨饼,而细分市场 3 的用户更喜欢汉堡包。而细分 4 用户(大多数转化用户)更喜欢果汁和其他类型的品牌。
每个细分市场都有哪些品牌?。
以下是这些细分用户使用过的十大品牌。
Top 10 Brands Availed by Each Segments, by Muffaddal
看看这些品牌,我们可以理解这些细分市场用户更喜欢什么类型的品牌和交易。第 1 和第 2 部分用户(高付费用户)使用了优质品牌,如 Sajjad、kababi、carbon、California 等,而第 3 和第 4 部分用户(低付费用户)大多选择了中低档品牌。
如何应用这些结果?
根据不同的用户群,我们可以:
1-定向广告针对每个细分市场的个性化广告会提高转化率,因为用户更有可能转化为特定品牌和优惠。因此,举例来说,先向付费能力较高的用户展示 Sajjad 的广告,然后再向付费能力较低的用户展示。
2- In-app 推荐
优化应用,在应用内推荐每个细分市场用户更感兴趣的交易和折扣。
摘要
总之,通过数据和适当的努力,我们能够识别用户及其喜好的有趣信息,并能够根据用户的偏好制定如何吸引用户的策略。
相似读数
使用 BigQuery ML 中的 RFM 分析和 Data Studio 中的可视化进行用户细分。
towardsdatascience.com](/rfm-analysis-using-bigquery-ml-bfaa51b83086) [## 基于项目的推荐系统综合指南
本指南将详细介绍基于项目的推荐系统是如何工作的,以及如何在实际工作中实现它…
towardsdatascience.com](/comprehensive-guide-on-item-based-recommendation-systems-d67e40e2b75d) [## 找到类似的产品推荐给用户
在 R 中使用 recommenderlab 获得类似的产品推荐
towardsdatascience.com](/find-similar-products-to-recommend-to-users-8c2f4308c2e4)
使用一般化的翻译向量来处理拼写错误和词汇外(OOV)单词,如缩写
Photo by Andrea Sonda on Unsplash
介绍
在这篇文章中,我将分享一种管理拼写错误和缩写的新方法。这个想法不是我自己的,但我认为它真的很有趣,并决定在这里测试和展示我自己的成果。
这个想法来自艾德·拉什顿,他来自一个快速人工智能论坛的帖子,是我在做自己的研究时偶然发现的。我强烈建议你阅读他的初步测试。
我采取了额外的步骤来测量将 Ed 的方法应用于下游自然语言处理(NLP)任务的效果,以查看它是否会提高分类准确性。
像使用外部数据源来创建一个广义的转换向量或测试缩写/OOV 词的方法是我自己的。
但是在我开始之前,了解什么是单词嵌入以及它们为什么重要是很重要的。如果您需要快速复习,请花 3-5 分钟通读关于词汇外(OOV)单词嵌入系列的 第一部分。
文章链接还谈到了为 OOV 单词生成单词嵌入,比如新加坡英语。这篇文章实际上是我关于如何最好地使用新加坡式英语的研究的延伸。
回忆一下,我们开始吧。
这种方法的基本原理来自于单词嵌入如何与另一个交互。这种“互动”的经典词语类比例子如下:
Figure 1 — Word Analogy “Equation”
直觉上,这个英语中的“等式”应该对你有意义。在向量空间中,数学将是这样的:
Figure 2 — Word Analogy Example in Vector Space — Source
为了向您展示这是真实的情况,我已经使用来自斯坦福的预训练单词嵌入运行了一些代码。这些单词嵌入在维基百科 2014 + Gigaword 上进行训练,以获得 60 亿个标记和 40 万个独特的词汇单词。
由于每个单词都表示在一个 100 维的空间中(即 100 个数字),为了可视化的目的,我应用了 T-分布式随机邻居嵌入(T-SNE)将维度减少到只有 2。
下面的图 3 是感兴趣的单词和数学方程的可视化,帮助你更好地理解单词之间的关系。
Figure 3 — Word Analogy Equation
正如您所看到的,经过适当训练的单词嵌入可以真实地表示单词之间的关系。模型生成的数字向量不仅仅是随机的。这些数字确实有一定的意义。
你可能不知道,我上面提到的是平移向量的实现。
平移向量是一种将坐标平面中的点/图形从一个位置移动到另一个位置的变换。
这是一个翻译向量,我将使用它来将拼写错误/缩写的单词移向最能解释这些单词意思的单词。
“等一下…你是说有一个翻译向量可以将拼写错误的单词移动到向量空间中相应的正确拼写上吗?”
答案是肯定的。
最重要的是,这个翻译工具甚至可以翻译缩写或 OOV 单词。这将使这些单词更接近于最能代表缩写或 OOV 单词真正含义的单词。
那么广义翻译向量是如何创建的呢?
这一系列的测试是由斯坦福大学使用手套单词嵌入法进行的。
在这一部分,我将首先分享处理拼写错误单词的实验。然后,我将转向我所做的处理缩写或 OOV 单词的实验。在此之后,我将试图解释为什么我认为这个翻译向量是有效的。最后测试这种方法对下游 NLP 任务的影响。
处理拼写错误的单词
为了处理拼写错误的单词,我最初认为拼写错误的单词的正确拼写应该出现在拼写错误的单词附近。
令我惊讶的是,我错了。事实完全不是这样。
以下是一些拼写错误的单词及其在向量空间中最接近的邻居的输出。
Input word: becuase
Closest 10:
becuase 1.0
becasue 0.768174409866333
beause 0.740034282207489
beacuse 0.7367663979530334
becaue 0.7192652225494385
athough 0.6518071889877319
althought 0.6410444378852844
becuse 0.6402466893196106
inspite 0.631598711013794
beleive 0.6224651336669922Input word: athough
Closest 10:
athough 0.9999999403953552
altough 0.7992535829544067
althought 0.7640241980552673
eventhough 0.7555050849914551
“ 0.7399924993515015
addding 0.7239811420440674
lthough 0.7079077363014221
surmising 0.6986074447631836
howver 0.6851125359535217
aknowledged 0.6843773126602173Input word: aknowledged
Closest 10:
aknowledged 1.0
ackowledged 0.8641712665557861
inisted 0.8378102779388428
admited 0.8242745399475098
annonced 0.81769859790802
avowing 0.7911248803138733
testifed 0.7896023392677307
addding 0.7784746885299683
sasid 0.7712235450744629
acknowleges 0.7595445513725281
注意在上面所有的例子中,前 10 个邻居中没有一个是正确拼写的单词?
我开始在越来越多拼错的单词上运行最近邻,直到一个模式出现,我得出结论…
所有拼写错误似乎都在向量空间中被分组在一起。
注意:这里着重强调了“似乎”这个词。因为我真的不确定。
如果我粗略地把它画出来,它可能看起来像这样:
Figure 4 — Misspelled words location in vector space
下一步是创建一个翻译向量,使拼写错误的单词嵌入更接近正确的拼写,如:
Figure 5 — Translation of misspelled words to correctly spelled words
过程是这样的:
- 运行余弦距离得到最近的 10 个单词拼写错误的选择。
- 对于 10 个最接近的单词中的每一个,取每个单词的单词向量,并将其从正确拼写的单词的单词向量中减去。
- 在步骤 2 中计算所有这些单词向量的平均值。这成为步骤 1 中所选单词的翻译向量。
- 测试平移向量。
STEP 1:
Input word: becuase
Closest 10:
becuase 1.0
becasue 0.768174409866333
beause 0.740034282207489
beacuse 0.7367663979530334
becaue 0.7192652225494385
athough 0.6518071889877319
althought 0.6410444378852844
becuse 0.6402466893196106
inspite 0.631598711013794
beleive 0.6224651336669922STEP 2:
sum_vec = ((glove["because"]-glove["becuase"]) + (glove["because"]-glove["becasue"]) +
(glove["because"]-glove["belive"]) + (glove["because"]-glove["beause"]) +
(glove["because"]-glove["becaue"]) + (glove["because"]-glove["beleive"]) +
(glove["because"]-glove["becuse"]) + (glove["because"]-glove["wont"]) +
(glove["because"]-glove["inspite"]) + (glove["because"]-glove["beleive"])
)STEP 3:
translation_vec = sum_vec / 10STEP 4:
real_word = glove["becuase"] + translation_vecClosest 10:
because 0.9533640742301941
but 0.8868525624275208
though 0.8666126728057861
even 0.8508625030517578
when 0.8380306363105774
if 0.8379863500595093
so 0.8338960409164429
although 0.8258169293403625
that 0.8221235871315002
. 0.8172339797019958
看看上面第 4 步的结果。注意平移向量是如何工作的?单词“becuase”的拼写错误被推到了正确的拼写“因为”。
既然我们知道处理拼写错误的翻译向量是可能的…
现在的问题是:
我们能为所有拼错的单词创建一个通用的翻译向量吗?
是的,你可以。
创建广义翻译向量
我先从维基百科上拿了一个经常拼错的英文单词列表——https://en . Wikipedia . org/wiki/Commonly _ misselled _ English _ words。
总共有 257 个拼错的单词。
接下来,我按照上面提到的步骤(步骤 1 到 4)运行每个单词。在 257 个单词中,只有 101 个出现在 GloVe 中。因此,计算了 101 个平移向量。
下一步很简单,要得到广义的翻译向量,只需得到所有 101 个翻译向量的平均值。
现在,在看不见的拼写错误的单词上测试广义翻译向量。即不在“经常拼写错误的英语单词”列表中的单词。
以下是一些结果:
TEST 1:
real_wd = word2vec["altough"] + generalised_translation_vector
Closest 10:
although 0.6854726149933246
though 0.6850398829597103
fact 0.6601790765388513
however 0.6519905808301287
moreover 0.6505953960788824
unfortunately 0.6351817153852294
why 0.6347064566357319
neither 0.6276211965351607
because 0.626889292147095
there 0.6217807488951306TEST 2:
real_wd = word2vec["belive"] + generalised_translation_vector
Closest 10:
belive 0.7508078651443635
believe 0.6821138617649115
we 0.6761371769103022
think 0.6593009947423304
i 0.6531635268562578
suppose 0.6463823815449183
know 0.643466951434791
why 0.6394517724397308
n't 0.6282966846577815
there 0.6273096464496348TEST 3:
real_wd = word2vec["howver"] + generalised_translation_vector
Closest 10:
moreover 0.6818620293021886
nevertheless 0.6726130620400201
neither 0.6667918863182073
unfortunately 0.6568077159269134
though 0.6563466579691621
indeed 0.6555591633099542
nor 0.6473033198348439
noting 0.6457127023810979
fact 0.6423381172434424
however 0.639381512943384
如你所见,仅仅在 101 个平移向量上,广义平移向量的表现并不太差。
然而,由于它只在 101 个翻译向量上建模,它在单词“howver”上表现不佳。如果我们对更多的平移向量进行平均,这应该很容易纠正。
这个一般化的翻译向量在缩写的 OOV 单词上表现如何?
为了测试这一点,我键入了一个缩写“ftw”来寻找它的最近邻居**,而没有**应用广义翻译向量。
结果就是这样。
Closest 10:
ftw 1.0
ftg 0.6485665440559387
ccts 0.6331672072410583
srw 0.6109601855278015
efts 0.6108307242393494
cmtc 0.6050553321838379
tfts 0.6022316217422485
okl 0.6015480756759644
jrtc 0.597512423992157
cacs 0.5950496196746826
如您所见,所有缩写似乎都被分组到了同一个向量空间中。这还没有真正的价值。
让我们应用广义平移向量,看看会发生什么。
real_wd = word2vec["ftw"] + generalised_translation_vectorClosest 10:
ftw 0.6879674996316458
training 0.5672708687073991
wing 0.5443954733951136
) 0.5178717182506045
fighter 0.4847256601149461
flying 0.4701913180805779
tactical 0.4680302804591241
combat 0.4674059145693783
squadrons 0.4593665765485848
foot 0.459181622011263
注意到这里有什么有趣的吗?如果你用谷歌搜索“ftw 战斗”,你会发现“ftw”代表“飞行训练联队”。
Figure 6 — Google search results for “ftw combat”
这表明广义翻译向量甚至对缩写也起作用,而不仅仅局限于拼写错误。
它设法将“ftw”的缩写翻译成它在文本中真正代表的意思。即军字。
现在你已经看到了结果,如果你像我一样,你会问自己这怎么可能。下一部分是我对我认为正在发生的事情的假设。
为什么我认为广义翻译向量有效
这一段纯属假设。我不认为这些是真的。我在这里所说的一切都仅仅是基于对结果的回顾和对我认为正在发生的事情的推断。
回想一下上面的图 4 和图 5。
我认为正在发生的事情大概是这样的:
Figure 7 — Why Generalised Translation Vector works
首先,根据我的测试,本地化的翻译向量似乎工作得最好,即更好的准确性。
本地化的翻译向量指的是具有缩写或拼写错误的单词的聚类的向量。
但我认为广义平移向量是可行的,因为它只是所有局部平移向量的平均值。它只是将蓝色圆圈中的所有东西推回到橙色圆圈中。
这是基于这样的假设:所有拼错的**、缩写或 OOV 单词都聚集在蓝色圆圈中。**
因为每个拼写错误的单词、缩写词或 OOV 单词都在一起,所以拥有一个通用的翻译向量只会将这些单词推向真正代表它们实际意思的单词。
重要提示:
- 翻译向量只对它被训练的单词起作用。我曾试图从 GloVe 中提取一个通用的翻译向量,并尝试将其应用于一个完全不同的数据集,但没有成功。
- 为了纠正拼写错误,正确拼写的单词必须首先存在于语料库中。
看到目前为止的结果,你认为模型学到了什么?我的假设有意义吗?你的假设是什么?
广义平移向量的应用
说了这么多,做了这么多,你可能想知道的下一个问题是:
“那又怎样?我能用这些知识做什么?”
在这一部分,我将分享两组代码在一个简单的多分类评论毒性任务中运行的结果。即有毒、剧毒、淫秽、威胁、侮辱或人身攻击。
以下是训练集的大致情况:
Figure 8 — Toxic comments data set
训练集被分成 127,656 个训练样本和 31,915 个验证样本。
我用二元交叉熵损失函数和带有 Keras 的 Adam 优化器训练了一个简单的双向 LSTM 模型。
在第一种情况下,我使用了 GloVe 中预先训练的单词嵌入,而没有使用中的广义翻译向量。
结果如下:
Figure 9 — Validation Loss and Accuracy
在由 153164 个样本组成的测试集上,模型精度为: 93.7687%
使用上面相同的配置,我将 GloVe 单词嵌入改为我应用了广义翻译向量的嵌入。
为了确保我只翻译需要翻译的向量,我从20 新闻组数据集的现有词汇表中运行了 GloVe 嵌入。
我只翻译了没有出现在 61118 个正确拼写单词的词汇列表中的向量。
结果如下:
Figure 10 — Validation loss and accuracy after applying Generalised Translation Vector
在上面的同一个测试集上,模型精度为: 93.8267%
精确度的差异只有 0.058%。
从这个实验来看,对拼写错误或 OOV 单词应用广义翻译向量是否有助于提高任何下游 NLP 任务的准确性,这是不确定的。
然而,凭直觉,我相信它确实有帮助。也许不是这个任务本身,而是其他 NLP 任务?
快速小结
- 我发现 fast.ai 上的一个帖子很有趣,于是决定测试一下某人(Ed Rushton)处理拼写错误的新颖方法。
- 我进一步测试了这种方法在缩写/OOV 单词上的应用,并得出结论:它对这些单词也有效。
- 我进一步研究了它是否有助于提高下游 NLP 任务(如分类)的准确性,发现我的实验没有结论。
结尾注释
我确实发现这个练习非常有趣,并且很可能在将来我的其他 NLP 项目中使用它。
所有的赞扬和感谢都归于埃德·拉什顿,因为他提出了这样一种新颖的方法。
我将来想尝试的是:
与其创建一个通用的翻译向量,不如根据一个单词属于哪个簇来运行本地化的翻译向量。
例如,如果单词是拼写错误,运行本地(拼写错误)翻译向量。如果单词是缩写,运行本地(缩写)翻译向量。
我坚信这种本地化的方法是使这种方法更强大的下一步。
我希望我在这方面的实验能帮助你更深入地了解单词嵌入是如何工作的,也许还能激发你的兴趣,让你自己做测试。
下次再见,朋友们!
如果你正在寻找 NLP 数据集,点击这里查看我创建的精选列表!😃
LinkedIn 简介:蒂莫西·谭
运用生成性对抗网络创造新颖的艺术形象
学习使用小的、不一致的和定制的数据集捕捉艺术家的风格
在这个项目中,我使用了一个生成性对抗网络(GAN)架构来生成新的艺术图像,这些图像捕捉了印度艺术家 Raja Ravi Varma[1848–1906]和 Sattiraju Lakshmi Narayana[1933–2014]的风格。(链接到源代码的 Github Repo)。
**简介:**这个项目的目标是理解生成对立网络(GAN)架构,通过使用 GAN 来生成新的艺术图像,捕捉给定艺术家的风格。生成对抗网络(GAN)架构是由伊恩·古德菲勒(链接到论文)博士在 2014 年提出的。GANs 由发生器和鉴别器神经网络组成。生成器神经网络将随机噪声作为输入,并生成图像作为输出,而鉴别器神经网络将图像作为输入,并生成概率值作为输出。由鉴别器评估的概率值指示输入图像是训练集的一部分的概率。发生器的目的是用它产生的图像“欺骗”鉴别器,而鉴别器的目的是正确地“找到”发生器产生的图像。竞争网络的这种对抗性、零和性质导致生成器越来越多地产生在概率上更有可能属于训练集的图像。下面给出了 GAN 的示例架构。
**其他作品:**当我看到英伟达科学家在 2017 年发表的一篇题为“无监督图像到图像翻译网络”的论文时,我被介绍到了 GAN 架构。他们使用 GAN(耦合 GAN)架构的变体来训练模型,这些模型可以有效地获取(I)白天拍摄的照片的输入图像,并在晚上产生照片的令人信服的输出图像,(ii)动物,并产生变形为不同动物的动物的令人信服的输出图像,(iii)个体,并产生添加了特征(改变发型,添加附件)的个体的令人信服的输出图像。下面是他们论文中的一个例子。对于每一对图像,左边的图像是输入,右边的图像是输出。
为了进一步理解这个模型,我找到了伯克利科学家在 2017 年发表的一篇题为‘使用循环一致的对抗网络进行不成对的图像到图像的翻译’的论文。他们还使用 GAN(循环 GAN)架构的变体来训练模型,这些模型可以有效地获取(I)照片的输入图像,并以各种画家的风格产生照片的令人信服的输出图像,(ii)在夏天拍摄的照片,并在冬天产生照片的令人信服的输出图像。下面是他们论文中的一个例子。
到目前为止讨论的 GAN 模型本质上是将输入图像转换成具有一些期望特征的修改的输出图像。我想看看甘的建筑是否可以用来创造新的艺术形象,捕捉特定艺术家的风格。我随后在脸书找到了一个 2017 年由几个人独立完成的研究项目,名为‘GANGogh:用 GANs 创造艺术’。他们使用甘建筑来(I)了解各种艺术家的风格,然后(ii)创造一种新的应用学习的风格,以产生新的艺术。
**我的贡献:**我希望我通过这个项目的主要贡献是为(I)时间紧迫,(ii)处理能力不足,(iii)希望使用小型自定义数据集,以及(iv)制作新颖、印象主义的艺术图像(捕捉给定艺术家的风格)的开发人员提供一种了解 GAN 架构的方法。时间和处理能力对我来说是一个很大的限制,因为我不得不在一个很慢的虚拟机上很晚才开始我的项目工作。因此,我对大幅减少训练一个模型的时间很感兴趣。我通过使用一个非常小的定制数据集(大约 200 张图片)做到了这一点。然而,与这种选择相关的权衡是,生成器或鉴别器更有可能“压倒”另一个(即,生成器学习速度比鉴别器快得多,或者鉴别器学习速度比生成器快得多)。这使输出图像退化为噪声。我通过引入条件反向传播来解决这个问题。当高于某个阈值时,与网络相关的损失被反向传播。通过分析模型产生的损失,我发现这是有效的。这种方法允许生成新颖的印象主义图像,其用相对少的训练时间和数据集有效地捕捉给定艺术家的风格。注意,小数据集导致生成的图像本质上是印象式的。然而,这是可以的,因为我们通过一个新的印象派图像实现了捕捉艺术家风格的目标,并大大降低了处理成本。这个小数据集也让我们能够在没有太多作品的情况下,捕捉较小的地区性艺术家的风格。我使用 cifar10 模型进行基准测试。由于 cifar10 数据集包含 60,000 幅图像,处理时间明显更长,因此生成的图像印象不深,因此它是一个很好的对比。
结果:
**讨论:**我们可以看到产生的图像本质上是印象派的。Ravi Varma 模型和 Bapu 模型在以艺术家的风格产生新颖的印象主义图像方面特别有效。组合模型显然具有较差的印象质量。我们可以推断这是可能的,因为鉴别器在这种情况下可以学习得更快,因为在非常小的数据集(~400 张图像)中有两种截然不同的风格。这一推论得到了上面给出的损失图的支持。注意发生器和鉴频器损耗如何在对应于组合模型的图中的一点处彼此产生显著偏差。尽管有条件反向传播,这种情况仍然存在。显然,当我们试图以不止一位艺术家的风格创作出新颖的印象派作品时,我们需要更多的数据。考虑 cifar10 基准测试示例。我们可以看到,尽管有 10 个不同的类别标签,但输出图像的印象要差得多。这是因为数据集的规模要大得多(约 60,000 张图像)。然而,我们要考虑的关键指标是上面给出的每次迭代的训练时间。请注意,Cifar10 模型的训练时间比其他模型要长得多。因此,我们能够(I)大幅减少训练时间,(ii)使用小型定制数据集,以及(iii)以特定艺术家的风格创建新颖的印象派图像。
写于 2018 年 4 月 25 日
使用先进的“智能”分析提高循环化学工艺的盈利能力
**目的:**针对典型的涉及循环过程的化工行业,通过优化可控参数来提高产量,从而增加利润。
背景
我认为,分析将对化学工业的许多领域产生重大影响,主要是在制造绩效方面。化学工业已经在 IT 系统和基础设施方面进行了投资,这些系统和基础设施可以高速生成和跟踪大量数据。然而,他们缺乏利用这种潜在智能的远见和能力。借助市场上更便宜、更先进的分析工具,人们可以利用机器学习&可视化来优化工厂参数,以提高其盈利能力。
高级分析可以帮助他们了解化学过程中发生的事情,这可能是许多化学工程师不知道的。这反过来有助于他们克服各种瓶颈,打破流程监控和运作中的一些刻板印象(传统思维)。
在本文中,我将谈论三个主要的智能和高级分析技巧,它们帮助我们创建了一个稳定的模型,该模型反过来被行业用来实现利润最大化。
- 改变时间序列数据的建模——有时数据表现出一种内在趋势(如收益率持续下降),这使得模型学习这些趋势非常困难。因此,我们在超时测试数据中观察到非常差的性能。为了克服这一点,我们预测了产量的变化,而不是产量的绝对值。这些值的变化有些稳定,因此模型相对容易学习。
- 智能特征工程 —特征工程是任何预测模型中最重要的一步。这是真正的数据科学家花费大部分精力的地方。在行业专家和基础数学的帮助下,我们创建了一组智能(但不是直观的)特征,这些特征被证明在预测产量方面非常重要。此外,同时帮助化学工程师了解工厂的功能。
- 在解决基于时间序列的建模时可以派上用场的特殊或非传统技术 -在建立预测模型期间,我们需要多次执行特定的分析,以帮助我们理解数据和过渡过程。在这一节中,我将讨论一些非传统的方法或技术,这些方法或技术可能有助于理解数据,从而有助于构建一个稳定而稳健的模型。
让我们深入研究第一部分,即改变建模,并了解它如何优于传统的时间序列建模。
改变建模
对于涉及数据趋势的情况,在没有任何能够捕捉该趋势的功能的情况下,训练模型变得极其困难。趋势中的每日特征将变成模型从未见过的值,因此增加了任何 ML 模型中的噪声和不准确性。为了解决这种情况,数据科学家通常会创建一个合成变量来捕捉趋势,如一年中的月份、经过的时间或简单的行号。在涉及衰减属性或未知速率的自回归属性的情况下,这种策略往往会失败。为了克服这个趋势问题,我们引入了变化建模。我们预测给定时间间隔内产量的变化。利用变化建模,我们对 x 和 y 特征相对于时间进行求导,以平滑趋势。这种方法使我们能够显著提高模型的预测能力。
△ P(time = t) = P(time = t) - P(time = t-1)P is the distribution which is dependent on time.
请注意,离群值处理和缺失值插补现在应该应用于这些衍生产品。
A graph showing a declining yield of a plant over the course of 2 years. It is called as ‘non-stationary’ behavior i.e. changing mean & variance which is not ideal for the time series modeling.
当我们对这种趋势求导时,结果看起来更稳定,更适合时间序列建模。
Constant mean and variance over time and mitigate the noises due to any reasons in data collection.
智能特征工程
我将谈论三种不同于传统的广泛特征-
- **由于建模变化而定义发生变化的特性:**当你对 x 和 y 求导时,特性会发生一些疯狂的事情。
通过研究二元关系和咨询行业专家,很多时候数据科学家需要创建一些特征转换。例如,一个特征的对数,乘以二,取一的平方等等。现在,根据变更建模,这种转换将会完全改变。这是变化-
y = log (x) || △y = △x / x
y = x² || △y = x △x
y = p X q || △y = p △q + q △p
y = 1 / x || △y = -△x / x²
2.**从商业和数据科学的角度来看,其他一些很酷的功能可能会有所帮助:**一些功能,如变化变量的滞后,采用二次微分来捕捉变化率以及绝对变量的滞后。输入所有这些变量有时会让您对模型性能感到惊讶。然而,在时间序列建模中,数据泄漏是一个非常严重的问题。
数据泄漏是指来自训练数据集之外的信息被用于创建模型。这些额外的信息可以让模型学习或知道一些它本来不知道的东西,从而使正在构建的模式的估计性能无效。屡试不爽的防止数据泄露的方法是问问你自己
如果在您希望使用模型进行预测时,任何其他特性的值实际上不可用,则该特性会给您的模型带来泄漏
3.**利用高级算法获取创新特征,特别是针对时间序列建模:**在特征工程自动编码模块中总是有新的进步,这些模块可以捕获时间序列数据的特殊特征。其中一个模块是“ tsfresh ”,它在 Python 中可用。
自动计算大量时间序列特征。此外,该软件包包含评估回归或分类任务的这些特征的解释能力和重要性的方法。要详细了解该包的工作和实现,请参考下一页。
需要注意的一点是:在使用这样的包时,企业很难解释这个特性及其在现实世界中的重要性。因此,当预测不是模型构建的唯一目的,而是涉及到预测的驱动因素时,我们不应该使用这样的库。
pip install tsfreshfrom tsfresh.examples.robot_execution_failures import download_robot_execution_failures, load_robot_execution_failuresdownload_robot_execution_failures()
timeseries, y = load_robot_execution_failures()
智能或非传统技术,在解决基于时间序列的建模时可以派上用场
在这里,我们将讨论我在各种时间序列问题中学习和实现的一些技术。这些技术是非传统的,很难在网上找到任何有用的内容。然而,在回答涉及化学过程的复杂问题时,尤其是循环问题时,它们被证明是超级方便的。
- 脉冲响应函数:了解当另一个不同的变量发生变化时,一个变量发生变化所需的时间。根据这一分析,您可以回答以下类型的问题—
a .如果我对温度稍作改变,稳定产量需要多长时间?
b .系统意识到氯含量变化的影响需要多长时间?
The y-axis shows the change in selectivity given a change in chlorine level is initiated at t= 0 hours. The x-axis shows the time from the change in chlorine levels. Grey region is the confidence interval of changes recorded in selectivity at t = T hours after the change in chlorines. This graph shows that the selectivity levels effect recorded after 8 hours of the change in chlorine and it finally stabilized after 12 hours.
在 R 中,我们有一个库“VARS”,它有一个函数 irf (脉冲反应函数),做的工作和上面提到的一样。下面是所用代码( R,tidyverse )的图示—
library(vars)# p represents the lag order. This have 17 orders of all lag variables.
m.var <- df.reg %>%
VAR(p = 17, type = "const") irf.var.cum.ccf <- irf(m.var,
n.ahead = 12, # No of Steps
runs = 1000, #Runs for the bootstrapping
impulse = "d_ccf", #Variable which changes
response = "d_S44" #Variable wohse effect is recorded)# Generates the plot
irf.var.cum.ccf %>%
plot()
**2。基础扩展:**它是一种技术,使我们能够通过在线性模型中保持其他变量的长期影响来捕捉一个变量的近期影响。在时间序列模型中,当您希望一个变量的系数捕获更近期的样本和来自长期样本的其他系数时。你也可以尝试其他传统技术——
- 对样本集进行加权,以便最近的时间段具有更高的权重(可能会导致整体预测能力的损失)
- 创造特征或试图理解为什么这种积极和消极的行为会随着时间的推移而改变(非常困难且依赖于数据)
- 改变训练周期的长度(可能不会产生期望的结果,如系数趋于零等。)
有时,一个 X 变量对 Y 的影响随着时间的推移而变化。例如,在 6 个月中,它对 Y 变量有积极的影响,而在接下来的 4 个月中,这种影响是消极的。你应该确保其他变量必须与 Y 变量有稳定的关系。
一个简单的线性模型应该是这样的—
𝑦(𝑡)=𝛽𝑋(𝑡)+𝜖
Where y(t) is some output (yield) that changes over time, t
可以有许多其他时变信号,但为了简单起见,我们假设只有一个:X(t)。你在尝试根据某个有误差的线性模型,学习 X(t)和 Y(t)之间的关系,ε。这种关系由系数β来描述。
**复杂:**根据你使用的数据周期,β值会发生变化,这表明 X 和 y 之间的关系实际上可能会随着时间的推移而变化。
**解析:**在这种情况下,我们需要引入一个叫做“指标函数”的新函数。指示器函数是一个简单的函数,当满足某些条件时为“1”,否则为“0”。
Mathematical representations of the equations mentioned to the right of the image
让我们把一月到六月的月份集合称为“A”。我们可以用一个指标函数来描述这一点,如右图所示。
类似地,我们可以创建一个类似的函数来描述 7 月到 12 月这几个月的集合,称这些集合为“B”。
现在,使用这些指标函数,我们可以通过重写我们的方程来说明随时间变化的关系(β)。
为了在实践中实现这一点,您将按照前面的描述设计特性,创建 X 的两个副本,并在适当的时间将值清零。
然后,您可以像往常一样拟合模型。
**新的复杂因素:**你的回归模型中不仅仅只有一个单一特征。你的回归方程实际上更像这样(尽管更复杂):
𝑦=𝛽_1*𝑋_1(𝑡) + 𝛽_2*𝑋_2(𝑡) + 𝛽_3*𝑓(𝑋_1(𝑡), 𝑋_2(𝑡)) + 𝜖
它被简化为只有两个独立变量,假设 x1 是我们目前讨论的变量。X_2 是植物发出的其他信号,f(X_1,X_2)是你根据 X_1 和 X_2 的相互作用设计的特征。
如果我们实现上面建议的更改,并将 X_1 的影响分成两个特性,您将得到:
𝑦(𝑡) = 𝛽_𝐴1*(𝑋_1(𝑡)∗𝕀_𝐴(𝑡)) + 𝛽_𝐵1*(𝑋_1(𝑡)∗𝕀_𝐵 (𝑡)) + 𝛽_2*𝑋_2(𝑡) +
𝛽_3*𝑓(𝑋_1(𝑡),𝑋_2(𝑡)) + 𝜖
“如果我们相信 X_1 和 y 之间的关系随时间变化,我们是否也需要重新评估 X_1 和 X_2 随时间变化的关系?”
**新决心:**答案是,要看你自己搞清楚是否有必要改变这一点。没有快速的答案,但是你可以尝试一些事情:
- 仅更改单个有问题的特征(X _ 1)-保持其他工程特征不变
- 改变你单一的有问题的特性(x1)和一些包含 x1 的影响更大的工程特性
- 改变所有依赖于 X_1 的特性
所有这些方法都是完全合理的,可能会也可能不会提高你的模型的拟合度。当然,你的解释会随着你采取的方法而改变。
如果你只实现了 X_1 上描述的单基函数,你实际上是在说:“我们相信 X_1 对收益率的影响会随着时间而变化——我们可以证明这一点。然而,受 X_1 影响的其它过程,例如 f(X_1,X_2),具有随时间的恒定关系,并且它们与产量的关系不随时间改变。”
你需要运用你对数据和过程的了解来判断这样的结论是否合理。
**3。分位数回归:**这种技术并不常用,但它比传统的线性回归有自己的优势。相对于普通的最小二乘回归,分位数回归的一个优点是,分位数回归估计对响应测量中的异常值更稳健。
分位数回归已由多位统计学家提出,并被用作在变量的均值之间没有关系或只有弱关系的情况下发现变量之间更有用的预测关系的方法。
Python 中的分位数回归实现
# Quantile regression package
import statsmodels.formula.api as smf# Building the formula
formula = 'Conversion_Change ~ ' + ' + '.join(X_columns)# Training the model
mod = smf.quantreg(formula, df_train)
res = mod.fit(q=.5)# Evaluation metrics on test dataset
r2_test = r2_score(y_test, res.predict(df_test))
参考
[1]https://en . Wikipedia . org/wiki/Quantile _ regression # Advantages _ and _ applications
[2]https://web.stanford.edu/~hastie/Papers/ESLII.pdf
[3]https://en.wikipedia.org/wiki/Indicator_function
[4]https://machine learning mastery . com/data-leakage-machine-learning/
https://tsfresh.readthedocs.io/en/latest/
善用人工智能
如何用人工智能帮助发展中国家
最近,我看到了几篇文章,阐述了人工智能如何通过消除对重复性劳动密集型制造角色的需求来威胁发展中国家。工厂自动化可能会导致较贫穷国家的失业率上升,从而扰乱当地经济并引发其他社会问题。人工智能对发展中国家来说是个巨大的威胁吗?
Photo by bill wegener on Unsplash
人们无法否认人工智能改变生活和重塑人类生活方式的潜力。在美国等发达国家,人工智能在过去十年里迅速接管了大多数人的生活。从搜索引擎到自动驾驶汽车,人工智能通过提供半自动到全自动的高性价比解决方案,影响并颠覆了许多传统行业。以广告业为例,通过采用计算广告,广告变得越来越个性化。基于实时竞价(RTB)的显示广告允许公司直接瞄准并购买用户,而不是购买广告关键词或广告视图。所有这些复杂的广告系统最终归结为简单的 ML 技术,如梯度推进决策树和因式分解机。
如果人工智能如此强大,那么它怎么可能除了伤害发展中国家之外什么都不做?事实是,人工智能也可以被恰当地利用来帮助那些不幸的人。
总部位于加州的初创公司 Zipline 正在对人工智能产生积极影响,它发明了一种全国无人机送货系统,将血液和药物运送到卢旺达的偏远医疗中心,卢旺达是一个遭受贫困和疾病蹂躏的东非内陆国家。Zipline 新改进的空中机器人能够从一个交付中心每天交付 500 多件货物。配备自动化物流系统和尖端的计算机视觉技术,一架单索无人机可以在接到订单后不到 10 分钟内发射。目前,该公司正在将其项目扩展到坦桑尼亚,在那里,抗蛇毒、狂犬病疫苗和其他重要药物通过其无人机交付。除了 Zipline,Matternet 也是另一家总部位于加州的无人机创业公司,于 2017 年与瑞士邮政合作。他们的无人机送货系统已经成功地在瑞士的实验室和医院之间运送医疗用品。
Photo by Jason Blackeye on Unsplash
除了医疗产品,许多发展中国家都急需安全的食物来源。微软在 Telengana、Maharashtra、Karnataka 和 Madhya Pradesh 等印度小村庄的数字农业项目被证明是成功的。微软设计了一款基于 Cortana Intelligence Suite 的播种应用程序,该程序结合了机器学习和商业智能,可以通知农民最佳播种日期。农民不需要大量投资,因为他们需要的只是一部能够接收来自微软应用程序的短信的手机。该应用程序通过预测理想的播种日期极大地帮助了农民,从而提高了作物产量。它还允许农民通过准确预测虫害和其他潜在风险(如季风)来提前计划。
Photo by Dose Media on Unsplash
也许人工智能可以帮助发展中国家的最重要的方面是提高教育质量。许多发展中国家的孩子,比如贫穷的 8 岁中国男孩在严寒中步行近 5 公里去上学,并不容易获得教育。Thirdspace Learning、Duolingo 和 Carnegie Learning 等公司正在开发 1 对 1 人工智能辅导软件,提供个性化的即时教育。随着 Quizlet、Newton 和 Thinkster Math 等教育技术公司获得越来越多的百万美元投资,在不久的将来,人工智能有望被用于为第三世界国家的农村地区提供教育资源。
Photo by Andy Kelly on Unsplash
自从著名计算机科学家约翰·麦卡锡在 1956 年创造了“人工智能”这个术语以来,人工智能每秒钟都在进化和改变着我们的生活。虽然许多人已经利用人工智能发明了最先进和高利润的技术,但很少有人考虑过在发展中国家产生影响。人工智能可以通过哪些方式让世界变得更好?
吴恩达你怎么看?
使用人工智能来确定具象艺术还是抽象艺术在今天更受欢迎
虽然智人在大约 10 万年前就有抽象思维的能力,但人类大脑花了更长的时间才发明了 T2 抽象画。直到 20 世纪初,像瓦西里·康丁斯基、卡齐米尔·马列维奇和希尔玛·阿夫·克林特这样的艺术家才创作出与现实世界毫无关联的抽象作品。抽象很快成为推动艺术创作的指路明灯,这一趋势在很大程度上延续至今。
但是抽象艺术到底有多受收藏家和艺术爱好者的欢迎呢?为了尝试回答这个问题,我们收集了去年 12 月 112,600 个 Instagram 帖子的数据库,这些帖子的地理位置和/或标签显示用户在迈阿密海滩举办巴塞尔艺术展期间在迈阿密。剔除自拍和其他无关图片后,产生了大约 74,760 张图片,这代表了 Instagram 用户亲自看到的所有艺术作品的集体视觉记录,他们也选择了与粉丝分享。基于我们早期的作品,我们然后通过一个为艺术设计和优化的人工智能工具来运行这些图像,以便按照流派(例如,抽象、具象)将艺术分为几大类,并识别出 10 种最常见的艺术作品。这些算法是由纽约的科技初创公司 Artrendex 开发的,Ahmed Elgammal 是该公司的创始人兼首席执行官。一些令人惊讶的结果出现了。
当今最流行的艺术表现方式是什么?
虽然抽象仍然流行,但它对艺术爱好者的相对重要性似乎在下降。在去年 12 月所有在 Instagram 上分享照片的迈阿密博览会参观者中,抽象艺术作品仅占帖子总数的 36%,低于去年的 52%。相比之下,去年 12 月的作品数量从 30%上升到 36%。第三个最受欢迎的类别是以某种方式涉及风景或室内的艺术作品,占 18%。主要基于文本的艺术品占 9%,而只有 1%的图像代表特定的物体——例如,一把螺丝刀或一双鞋。
我们将迈阿密的帖子与 Instagram 帖子的更大数据集进行了比较,这些帖子是我们在过去 18 个月里从其他顶级艺术博览会收集的。在过去的一年里,Instagram 用户对抽象艺术的兴趣有所下降,取而代之的是对外形、风景、内部装饰和基于文本的艺术的兴趣日益增长。虽然因果关系很难确定,但我们的感觉是,艺术家试图在抽象中创新,从而在市场上脱颖而出已经变得越来越困难。在拥挤的艺术市场中,调整更传统的比喻可能是一种更保险的脱颖而出的方式。
对这种变化的一个可能的解释是,在过去几年里,画廊和博物馆明显转向展示女性艺术家和有色人种艺术家的作品。这种艺术的一个显著特征是它倾向于表现和肖像。最近的例子包括在现代艺术博物馆举办的查尔斯·怀特回顾展;泰特现代美术馆和布鲁克林博物馆举办的“国家的灵魂:黑人权力时代的艺术”中的许多艺术家;恩迪卡·阿库尼里·克罗斯比和达纳·史高斯的画廊展览。这些艺术家中的许多人都以将与他们社区相关的人和地方的图像“画入画面”而闻名。抽象根本无法表达他们的艺术意图。正在展出的艺术家的这种转变——在可预见的未来很可能会继续——表明抽象艺术在艺术爱好者中可能会越来越不受重视。
2018 迈阿密艺术周期间最受欢迎的艺术作品有哪些?
当我们看到 10 件最具 Instagrammed 化的艺术作品时,对抽象的兴趣下降变得更加明显,其中只有一件是抽象的。
#1 — KAWS X Campana (2018) by KAWS and Fernando and Humberto Campana
这是一个天上人间的混搭。费南多和温贝托·坎帕纳——以用填充玩具装饰沙发、椅子和长凳而闻名的巴西设计师和兄弟——与布鲁克林的艺术家 KAWS 合作,创造了一系列限量版的椅子和沙发。每一件物品上都有 75 到 120 个由 KAWS 制作的填充玩具。
#2 — Positive Vibes (2018) by Jack Pierson
在从事各种媒体工作的同时, Jack Pierson 最出名的作品是用来自垃圾场的不匹配字母拼出令人回味的短语的雕塑。去年 12 月,三家不同的画廊展出了他的单词雕塑,但公平的参观者显然更喜欢张贴“积极情绪”的图像,而不是拼出“富家子弟忧郁”或“想要更少”的雕塑。
#3 — American Power (2017) by Tristan Eaton
特里斯坦·伊顿的喷漆肖像美国力量中描绘了 10 英尺高的大胆女性形象。虽然这位洛杉矶艺术家在 2017 年安装了这件作品,作为 Wynwood Walls 计划的一部分,但它在一年后继续吸引人们的注意,成为 2018 年迈阿密艺术博览会期间第三大被安装的作品。
#4 — We Belong Here (2018) by Tavares Strachan
出生于巴哈马群岛,拥有耶鲁大学艺术硕士学位,塔瓦雷斯·斯特拉坎以其充满概念的大型装置作品而闻名。在迈阿密,他为 Faena Festival 创作了一个霓虹灯雕塑,Faena Festival 是一个新的艺术节,与迈阿密海滩的巴塞尔艺术博览会同时举行。就像杰克·皮尔逊一样,“我们属于这里”这句精辟的话既可以被解释为宣示性的陈述,也可以被解释为间接的问题。
#5 — Hello Beautiful (2018) by Queen Andrea
安德里亚女王是纽约的美术家、壁画家和平面设计师。她是少数几个以男性为主的女性涂鸦艺术家之一。她的欢乐壁画是排名第五的艺术作品。
#6 — Untitled (Yellow, Orange, Yellow, Light Orange) (1955) by Mark Rothko
在迈阿密海滩巴塞尔艺术博览会上出售的最昂贵的艺术品是马克·罗斯科 1955 年的一幅画,要价 5000 万美元。这个价格尤其引人注目,因为四年前画廊在苏富比以 3660 万美元买下了这幅画。
#7 — Large Fancy Room Filled With Crap (2018) by David Shrigley
在迈阿密海滩巴塞尔艺术博览会的所有展位中,有一件由大卫·施莱格利创作的霓虹灯作品,上面写着“堆满垃圾的大房间”施莱格里以讽刺性的雕塑、绘画和视频闻名,他的作品经常出现在大型艺术博览会上。在最近伦敦的 Frieze 艺术博览会上,他的蓝色霓虹雕塑“我的作品很糟糕,我是一个非常坏的人”是博览会上最受欢迎的作品。
#8 — Smooth Egg with Bow (Magenta/Orange) (1994–2009) by Jeff Koons
杰弗·昆斯的*带蝴蝶结的光滑蛋(洋红色/橙色)*几乎有 7 英尺高,出自他广受好评的“庆典”系列。这座雕塑有五个不同颜色组合的独特版本(蓝色/洋红色、洋红色/紫色、洋红色/橙色、红色/黄色和银色/红色),其中一个于 2016 年 5 月在佳士得以 740 万美元的价格售出。据报道,提供这件特殊作品的画廊要价约为 1000 万美元。
#9 — Sora Versailles (2018) by Miya Ando
凭借这幅迷人而空灵的作品,陈美雅·安藤通过在建筑的各个侧面描绘日落和日出,改变了建筑的外观。从海滩木板路到邻近的街道,这是一个令人难忘的地方。
#10 — Silence = Death (1988) by Keith Haring
Lévy Gorvy 将其在迈阿密海滩巴塞尔艺术博览会上的展台改造成了向基斯·哈林曼哈顿下城流行商店的致敬。这幅画是艺术家被诊断出患有艾滋病的那一年的作品。这幅画描绘了一些人在一个粉红色的三角形主题中表现出“视而不见,听而不见,说而不闻”的行为,这个主题因艾滋病活动家团体“行动起来”而闻名。
道格·伍德汉姆是艺术信托顾问的管理合伙人,这是一家总部位于纽约的公司,专注于向收藏家和机构提供与艺术相关的金融建议。在他职业生涯的早期,道格是佳士得美洲区总裁,也是麦肯锡公司的合伙人。他也是畅销书今日艺术收藏:给每个热爱艺术的人的市场洞察的作者(2017)。
艾哈迈德·埃尔加马尔是罗格斯大学艺术和人工智能实验室的主任,也是 Artrendex 的创始人兼首席执行官。
用人工智能预测罗斯科画作的拍卖价格
马克·罗斯科悬浮在单色区域中的彩色悬浮矩形是 20 世纪最容易辨认的画作之一。在高度受限的形式下,他创作出了令人惊讶的多样化作品,为世界各地的收藏家和博物馆所垂涎。他在艺术史经典中的广泛声望和稳固地位,加上拥有手段和欲望拥有它的人数的快速增长,使他的作品变成了极其昂贵的“战利品艺术”。自 2010 年以来,拍卖会上的买家已经在他的画作上花费了总计 11 亿美元。
罗斯科作品的相对一致性,特别是与毕加索和沃霍尔等其他艺术界偶像相比,使他成为使用人工智能工具开发预测模型以估计拍卖价格的理想候选人。我们在下面解释我们是如何开发这个模型的,使用了世界上亿万富翁的数量和他们控制的财富等变量。然后,我们使用该模型预测将出现在 5 月 16 日苏富比当代艺术晚间拍卖会上的三件罗斯科作品的销售价格。但首先,简单介绍一下罗斯科市场。
耶鲁辍学生
罗斯科是来自拉托维亚的移民,1913 年末他十岁时来到爱丽丝岛。他的家人定居在俄勒冈州的波特兰,他在那里上高中,之后他在耶鲁大学学习了两年,然后辍学。他于 1923 年搬到纽约,并在那里一直呆到 1970 年去世。
学者们倾向于把他的职业生涯分为三个时期。在早年(1924-1939)期间,他经常画神话主题或受超现实主义启发的作品,其中很少有特别杰出或有趣的。在过渡的年(1940–1950),他从表现转向探索色彩和形式的并置如何被用来创造有趣的空间关系。他举世闻名的大部分画作都是在他晚年创作的,学者们称之为“经典时期”(1951-1970)。
在这第三个也是最重要的时期,罗斯科作品不多。华盛顿国家美术馆于 1998 年出版了一份他所有帆布和硬纸板作品的目录清单,其中仅包括这一时期的 386 件作品。这意味着平均每年只创作 20 幅画。
罗斯科还在纸上创作了许多作品,他认为这些作品是成熟的绘画,而不是素描。艺术家的儿子克里斯托弗·罗斯科(Christopher Rothko)写道,罗斯科坚持认为,他所有的纸上作品“……都要装在支架上,呈现出来时要无垫、无框、无釉。换句话说,他们应该像绘画一样被对待,没有任何东西阻碍我们的观点和方法。据我所知,我父亲在世时展出或出售的所有罗斯科的经典纸质作品都是装裱的,而不是装裱的,有些作品比其他作品更成功,但这种一致性清楚地表明了我父亲的愿望。”国家美术馆目前正在收集这位艺术家的纸质作品目录,预计将于 2022 年面世。因为纸更便宜,更容易使用,这位艺术家在纸上创作的经典画作可能比在画布上创作的更多,尽管准确的数字要到目录出版后才能清楚。
他的纸上作品和画布作品都会定期出现在拍卖会上。罗斯科的作品也私下出售,主要是通过佩斯画廊,自 1978 年以来一直代表艺术家的财产。
罗斯科价格预测模型
想象一下,站在一幅罗斯科作品前,认真地看着它。你会很快注意到矩形的数量,它们的颜色,以及它们与它们所绘制的单色场相比如何。这些是这幅画容易测量的方面。但罗斯科作品还有许多其他难以用语言表达的品质,更不用说量化了,这些品质有助于它的情感之美,比如矩形的边缘如何融入基色,绘画的亮度,以及颜色和形式并置创造的不寻常的空间关系。我们的眼睛看到这些信息,并将其传输到我们的大脑,引发情绪反应。
人工智能现在使机器能够在某些方面像人类一样看待世界,并允许它们将这些知识用于各种任务,包括驾驶自动驾驶汽车和使用视频监控系统监控时代广场的人们。计算机视觉的革命在很大程度上归功于一种叫做卷积神经网络(CNN)的模式识别算法。CNN 观察数字图像中的像素并从中寻找模式,而不需要机器先被告知要寻找什么。换句话说,这种技术提取图像本身的潜在特征,包括难以预先指定的特征。我们使用这种方法来分析罗斯科画作的数字图像,生成可用于预测销售价格的信息。
为了建立我们的模型,我们创建了一个数据库,包含了自 2000 年以来拍卖的这位艺术家的所有经典时期和晚期过渡时期的作品,总共有 118 件。该数据库不仅包括从 ArtNet 收集的全包销售价格(即,锤子价格加上买家溢价)和对象描述符(例如,尺寸、绘画制作日期、销售日期、画布或纸张上的绘画),还包括我们从网络上获取的每件作品的数字图像。作为数字图像的潜在替代品,我们还对每幅画的形式属性进行了“手动评分”:色块的数量、艺术家可能用来分隔这些色块的水平条纹的数量、画中的主色以及背景色。这四个变量通常会被鉴定人用来比较画作。除了这些“供给”变量,我们还收集了艺术品“需求”的各种衡量标准,如全球财富的增长、各种股票指数的增长,以及福布斯亿万富翁指数中亿万富翁的总财富和总数。然后,我们使用这些数据开发了一个模型来预测拍卖价格。
我们创建的模型惊人的准确,只有 5.5%的预测误差。这意味着,在我们数据库中的所有画作中,实际销售价格和预测销售价格之间的差异平均只有 5.5%。让这个表现最好的模型如此有趣的是,它的预测仅仅基于数字图像加上五个变量:绘画高度和宽度,是纸上还是画布上的作品,世界上亿万富翁的数量,以及他们控制的财富。我们数据库中的其他变量似乎都与价格无关,包括这幅画的制作日期。我们还将计算机生成的模型与我们自己的评估进行了比较,用上面提到的四个手动评分变量代替了数字图像。有了这些手动评分的变量,预测误差飙升至 20 %,作为一个模型,这是非常不够的。这种差异生动地提醒我们,机器可以比人的眼睛更敏锐地“观察”一幅画。
在将模型投入使用之前,对其进行一些一般性的观察。首先,亿万富翁的数量和他们控制的财富是解释销售价格的最重要的需求变量。其次,规模很重要。在其他条件不变的情况下,作品越大,越有价值。第三,在所有其他因素保持不变的情况下,纸上绘画相对于画布上的绘画有很大的折扣。最后,与深色的棕色和灰色相比,挂在墙上的鲜艳的橙色和紫色画作更容易打开买家的钱包。
5 月拍卖成交价预测
这让我们看到了马克·罗斯科的三幅作品,它们将在 5 月 16 日的苏富比当代艺术晚间拍卖会上拍卖。
旧金山现代艺术博物馆(SFMOMA)收藏了七幅罗斯科的作品,正在取消一幅 1960 年的未命名的古典时期画作。在宣布出售的新闻稿中,博物馆表示,它打算使用出售所得来购买作品,以帮助他们的收藏多样化。像今天的许多博物馆一样,SFMOMA 希望购买女性、有色人种和其他被忽视或边缘化群体的作品。
Untitled (1960), Oil on canvas, 69 x 50 1/8 inches
在通过我们的算法运行这幅画后,该模型预测它将卖到 4230 万美元(锤子价加上买家溢价),接近苏富比拍卖估计的低端。这仍然是一笔令人震惊的巨款,将会给贪婪的 SFMOMA 策展人带来快乐。苏富比的专家可能认为这件作品会卖出更高的价格,因为博物馆拍卖的艺术品往往在拍卖会上卖出高价。但是这种可能性在我们的模型中是无法解释的。
为了好玩,我们还玩了模型,看看 SFMOMA 画作的变化会如何影响其价值。如果颜色比目前的棕色勃艮第更偏向橙色,预计售价将跃升至 6650 万美元,比现有作品高出近 60%。如果这是一幅纸上作品,它的价值将降至 2030 万美元,这反映了收藏家们长期以来对画布上的画作比对纸上画作的偏好。
两幅 1969 年的经典纸质画作也将于今年 5 月在苏富比拍卖。两幅作品中较大的一幅名为*《无题(红色和酒红色盖过蓝色)】*,的预售估价为 900 万美元至 1200 万美元,或 1050 万美元至 1390 万美元(含买方溢价)。我们的人工智能模型预测这幅画的售价将达到 1660 万美元,高于拍卖估价的上限,这将使它成为该艺术家在拍卖中出售的第二昂贵的纸上作品。如果这幅画的一切都是一样的,除了它是在画布上,模型预测它会卖到 3340 万美元,几乎是它的纸质复制品的两倍。
Untitled (Red and Burgundy Over Blue), 1969, Oil on paper mounted on panel, 48 x 40 1/2 inches
第二幅纸上作品,*无题(红上红),*较小,但以其明亮的红色调色板而闻名。苏富比估计它将以 700 万美元到 1000 万美元之间的价格售出,或 820 万美元到 1170 万美元(含买方溢价)。鉴于其诱人的配色方案,我们的模型预测它的售价将达到 1370 万美元,也高于拍卖估价的上限。两幅作品都以高于拍卖估价的价格出售的前景,不仅反映了作品的内在质量,也反映了拍卖行长期以来的做法,即试图将估价保持在尽可能低的水平,以吸引更多的竞标者。
Untitled (Red on Red), 1969, Oil on paper mounted on canvas, 38 3/4 x 25 inches
马克·罗斯科是 20 世纪最受喜爱的艺术家之一。因为他的成熟作品属于受限制的视觉词汇,罗斯科画作的数字图像可以用来创建可靠的价格预测模型。我们急切地等待着即将到来的苏富比拍卖会的结果,看看这个模型表现如何。
本文发表于 2019 年 5 月 7 日《Artsy》杂志。原文发表于 2019 年 5 月 3 日https://dougwoodham.com。*
— — — — — — — — — — — — — — — — —
本文由道格·伍德汉姆和德文·刘撰写。
道格是纽约艺术信托顾问公司的管理合伙人,该公司专注于为收藏家和机构提供与艺术相关的金融建议。在他职业生涯的早期,道格是佳士得美洲区总裁,也是麦肯锡公司的合伙人。他也是畅销书今日艺术收藏:给每个热爱艺术的人的市场洞察 (2017)的作者。
Devin 是一名软件工程师,专门研究将人工智能应用于未来的工作。他目前正在湾区人工智能初创公司 Cresta 为大型企业公司实现重复性工作职能的自动化。他刚刚开始收集,并对探索人工智能和艺术的交叉感到兴奋。
利用气流和火花处理美国移民数据
Photo by Matthew Smith on Unsplash
为了促进从 DevOps 工程师到数据工程师的转变,我完成了 Udacity 数据工程纳米学位。
我完成的最后一个项目涉及结合美国移民数据、世界气温数据和美国城市人口数据。使用这些数据集,以及一些简单的连接和聚合,我能够确定到达美国城市的平均年龄和性别。
然后将这些数据与每个城市的温度数据相结合,这样就可以将到达人数与天气趋势联系起来。人口统计数据还可以说明参与者的平均年龄和城市之间是否存在关系。或者,可以重新利用这些数据,看看到达者的种族和城市/州的人口统计数据之间存在什么关系。
在这篇文章中,我将解释我完成这个项目的步骤。我发现“逆向工程”解决方案非常有效。明确定义最终结果有助于确保我采取的每一步都有助于最终目标,并且没有浪费时间。
然后,我将讨论整个项目中出现的一些挑战。在 2015 年的 Macbook Pro 上处理 7gb 的数据集是不可能的。利用 AWS EMR 和气流提供动力,创建高效的管道。最后,如果有第二次机会(和更多时间),我将讨论性能改进,这将极大地提高代码的可伸缩性和运行时间。
数据第一,代码第二
在编写任何代码之前,我首先回顾了数据集,并明确定义了最终的数据结构应该是什么样子。为此,我首先回顾了三个数据集的模式以及它们应该在哪里连接。
在这里,我能够绘制一个模式来定义数据集之间的关系。从软件的角度来看,这是定义我如何结合数据来理解美国城市移民模式的关键。
在定义了数据集之间的关系之后,最终的数据结构被明确地定义了。下面的字典实际上并没有在项目中实现。然而,它使我能够为数据创建一个层次结构,并在项目结束时定义数据的结构。对于每个州,应该有一个每月到达的汇总,一些关于人的年龄和性别以及平均温度的平均值。
我花了大约 35%的时间来理解数据、创建模式和定义最终结果。这使我能够为这个项目创建一个清晰的目标,这个项目的实现将完全围绕这个目标。我现在将讨论为实现该项目而创建的步骤。
创建管道
定义了成功的最终结果后,我接着开发软件来汇总数据。数据集的大小(7gb)使得在本地执行部署不可行。因此,我利用了 AWS EMR,它为执行 Spark 作业提供了一个预配置的主从集群。
为了编排和协调管道,我使用了 Apache Airflow。Airflow 提供了一个 web-ui 和图表,记录了哪些功能或步骤需要在连续功能之前执行,以及哪些功能可以同时运行。
例如,在任何 Spark 作业触发之前,需要从 s3 下载数据集并解压缩。使用 Airflow 记录这种依赖性,如果下游任务失败(从 s3 同步文件),那么依赖的上游任务将不会被调用。这提高了管道的稳定性,防止失控代码被执行并导致意外问题。
提取
提取步骤相当简单,包括将 zip 文件从 S3 存储桶同步到主 EMR 节点上的挂载目录(文件系统指向不同的服务器)。一旦文件成功同步,更复杂的工作就开始了。
负荷
数据集成功下载到服务器后,我就可以开始实现管道了。数组样式的符号用于说明城市/温度任务和移民数据聚合可以并且理想情况下应该同时执行。
温度和人口统计数据加载
回到最终结果,需要确定美国城市每月的平均温度。然后,这个平均值必须与每个城市的人口统计数据相结合。
由于移民数据来自 2015 年事实核查因此,只选择尽可能接近今年的温度数据是有意义的,并在相同的加载步骤下将其与人口数据相结合。
移民和人口统计数据同时加载。虽然这打破了单一的责任,数据集的连接是简单的。在数据清理方面也没有预先的工作,所以将这些数据集的加载分组到一个任务中是有意义的。
最后一步记录数据应该如何保存到磁盘。Partition by 确保数据按照指定的列以降序排序并保存到磁盘。如果您知道将通过查询这些列来选择数据,这将显著提高未来的读取性能。
Binary Search (LogN) can be applied when data sorted is sorted into buckets. More performant hash searches can be applied if uniqueness of buckets is guaranteed.
移民数据加载
汇总移民数据更加复杂,原因有二:
- 数据集要大得多,而且分布在几个文件上,需要一个额外的库来加载。
- 需要对数据集进行汇总和转换,以确定移民的平均年龄和性别。
为了解决这个问题,我使用了一种接口输出的方法。在这里,首先定义函数的最终结果,然后定义它们的输入。一旦这些都清楚了,你就可以把中间部分,或者说代码,作为实现细节来对待,这些细节必须对输出有所贡献。
我从工作中的一位资深朋友那里学会了将代码定义为一系列清晰的函数/对象。它极大地提高了我的生产率和代码质量。这也非常符合 TDD 的工作风格,在这种风格下,每个功能都应该有一个可以清楚评估的特定输出。
这种方法使我能够定义从磁盘文件加载数据所需完成的确切步骤,并根据数据创建一个统一的数据帧。
从这个数据框架中,我创建了代表每个需求的子集:
- 每个州移民的平均年龄
- 每个州所有女性移民的数量
- 每个州的移民总数
使用女性和所有移民数据框架,我可以通过连接女性和所有移民数据框架,并使用女性计数/所有移民计数创建一个新列来确定性别分布。
该数据框架随后与年龄数据框架相结合,以创建一个包含每个州所有抵达者的平均年龄和性别分布的数据集。
最终加入
在管道的这一点上,我已经连接了温度和人口统计数据。移民数据按州汇总,确定了移民的平均年龄和男女比例。
从这一点来看,所有需要的是一个结合了温度、人口统计和移民数据的综合集合。由于所有的数据集都是按照州来划分的,所以加载数据集并通过州代码将它们连接起来既简单又高效。
这些代码行完成后,我创建了一个数据结构,它标识了以下内容:
- 每个州移民的平均年龄
- 各州移民的平均性别
- 每个日历月每个州/城市的平均温度
- 每个城市/州的人口统计数据
满足要求!
转学?
我不明白的一件事是如何处理这些数据!在当前状态下,它位于 EMR 集群上,实际上没有任何商业价值,也不能用于任何下游流程。
由于时间限制,我把这一部分漏掉了。Udacity 课程每月 300 英镑,所以我自然想完成它。
正是因为这个原因,您还会看到零单元测试,可以说是将代码呈现为非生产就绪。
尽管如此,该软件实现了最终目标:证明我在数据工程领域的熟练程度。它很好地完成了这项任务,在完成课程的几周内,我就能在 Sainsbury’s 获得一份数据工程师的工作,在那里我将学习所有这些东西是如何在规模上实际使用的。
结束语
在本文中,我展示了如何通过首先定义确切的最终目标来分解一个(相当)复杂的软件需求。这有助于确保我随后提交的每一段代码都有助于相同的最终目标。通过显式定义每个函数的接口和输出,我能够将注意力从函数逻辑的实现细节上移开。
最终的结果是,每一行代码都有助于一个产生清晰输出的功能,这个功能在最终目标的实现中有一个清晰的角色。
除非我能想到更好的方法来思考复杂系统,否则我会坚持:
- 在计划任何软件之前,明确定义最终结果
- 明确规划软件以创造最终结果
- 清楚地将功能输入和输出定义为软件的构件
*要查看所有代码,并运行管道 请单击此处。 *
利用蚁群和遗传进化优化拼车出行时长
城市交通正在经历一场快速而重大的变革。自从互联网和智能手机诞生以来,我们的联系越来越紧密,并且能够规划和优化我们的日常通勤。与此同时,大量数据被收集并用于提高现有交通系统的效率。优步和 Lyft 等实时拼车公司正在利用这些数据改革出租车行业,为更加互联和集中控制的交通结构奠定基础,并建立拼车等创新系统。
在这个项目中,我解决了出租车的行程时间优化问题。这可以被框定为旅行推销员问题,一个众所周知的计算机科学问题。目标是找到访问一组位置的最短路径。对于这个问题,需要优化技术来智能地搜索解空间,找到接近最优的解。更具体地说,我首先使用机器学习来预测每一对接送地点之间的旅行时间。然后我使用进化算法,即蚁群和遗传算法,为数据集中的车辆找到最佳旅行路线。
问题描述
资料组
我使用的数据是纽约市出租车和豪华轿车委员会的出行记录数据,可以通过以下网址访问:https://www1 . NYC . gov/site/TLC/about/TLC-Trip-Record-data . page .我有 2016 年黄色出租车、绿色出租车和出租车辆的月度数据。该数据集有近 150 万条出行记录,具有以下 11 个属性:
- id —每次行程的唯一标识符
- vendor_id —表示与行程记录相关的供应商的代码
- 拾取日期时间 —血糖仪启用的日期和时间
- dropoff_datetime —血糖仪脱离的日期和时间
- 乘客计数 —车内乘客数量(驾驶员输入值)
- pickup_longitude —电表接合的经度
- pickup_latitude —仪表接合的纬度
- dropoff_longitude —电表脱离的经度
- dropoff_latitude —仪表脱离的纬度
- store_and_fwd_flag —该标志表示在发送给供应商之前,行程记录是否保存在车辆存储器中,因为车辆没有连接到服务器:Y =存储和转发,N =不是存储和转发行程
- trip_duration —以秒为单位的行程持续时间(也是目标变量)
我进行了简单的数据预处理技术,如消除重复、检查纬度和经度界限、删除明显的异常值、将数据字段转换为合理的单位等。为我的实验获取一个干净的数据集。
数据可视化
这个项目的一个重要组成部分是可视化数据,并找出下一步用于机器学习模型的最佳特征。取货时间是我首先关注的一个特性。
图 1 是一天中不同小时的取件时间分布。可以看出,最受欢迎的接送时间是下午 6 点到 10 点,超过 70,000 次。另一方面,最不活跃的接车时间是凌晨 2 点到 6 点,不到 35,000 次。
图 2 是一周中工作日的取件时间分布。似乎周五是最受欢迎的打车日,有近 220,000 次出行,而周日则是另一端,约 165,000 次。
图 3 是图 1 和图 2 结果的拾取时间热图。最活跃的接送时间是从周四到周日的下午 6 点到 9 点。最不活跃的接送时间是从周三到周日的下午 2 点到 5 点。
我研究的下一个特征是旅行持续时间。
图 4 是按分钟计算的出行持续时间分布。我观察到分布严重左倾,超过 75%的行程在 3 到 12 分钟之间。超过 10,000 次的行程持续 5 到 7 分钟。
图 5 显示了按分钟与按纬度和经度划分的旅行持续时间分布的比较。经度的分布也非常左偏,峰值大约在 1 公里处。按纬度分布更为正态分布,峰值在 0 公里处。
图 6 是一天中不同时段的出行时长热图。最长的旅行通常发生在周三至周五的下午 2 点至 4 点。最短的行程发生在周一和周二的上午 8 点到 9 点。
我还对取车和下车地点感兴趣。
我绘制了接送位置的空间密度,如图 7 所示。这看起来有点像你从太空中看到的图像,曼哈顿和两个机场(LGA 和 JFK)“点亮”得很清楚。
我进一步在图 8 的地图上展示了典型的旅行。洋红色圆圈是上车地点,绿色圆圈是下车地点,青色箭头线是行程长度。我可以看到接送地点的不均匀分布,因为曼哈顿以外(皇后区和布鲁克林区)有更多的接送地点。
机器学习
我的下一步计划是建立一个机器学习模型来预测接送地点之间的旅行时间。有了数据和目标,简单的线性回归就不够强大了。在庞大的数据集中有一些随机异常值,并且可能有一些分类特征,我决定使用梯度提升树,它可以轻松捕捉非线性关系,适应复杂性,并处理分类特征。使用的输入要素有:乘客计数、接送经度、接送纬度、接送经度、接送纬度和商店和转发标志。输出目标是 trip_duration。
我通过 XGBoost 实现了这个模型,XGBoost 是一个优化的分布式梯度增强库,旨在高效、灵活和可移植。这个模型很容易建立,但很难微调和解释。我使用均方根对数误差作为评估指标,因为它降低了误差幅度。根据这一指标,我选择了不同的超参数并比较了结果。我为我的 XGBoost 模型使用的最终参数是:{ fbooster = GB tree;目标=线性;learning _ rate = 0.05max _ depth = 14 子样本= 0.9;colsample _ bytree = 0.7colsample _ bylevel = 0.7 无声= 1;feval = rmsleg} 。
我们获得的平均绝对误差为 4.83。XGBoost 模型被保存为 pickle 文件,然后将被用作下一步的输入:优化。
提议的解决方案
因为这个问题涉及最小化旅行时间,同时还要访问每个地点,所以它类似于旅行推销员问题(TSP)。旅行商问题是一个组合 NP-hard 优化问题。这意味着这个问题没有多项式时间的解。添加的位置越多,可能的解决方案就越多。解决这个问题的强力方法包括检查每个可能的位置组合。如果我要评估每条可能的路径,其中 n 代表位置的数量,那么它的运行时间如下:O(n)=[(1/2)(n-1)!]
考虑到这个运行时间,一旦我开始向问题定义添加更多的位置,解决方案空间很快变得难以处理。因此,我使用元启发式直接搜索解空间。我不会遍历每一条可能的路径,而是会生成可能的路径,并以一种有指导的随机方式搜索它们。
蚁群优化
蚁群优化(ACO)算法是一种生物启发的元启发式算法,它以模拟蚂蚁搜索可能路径的方式来搜索解决方案空间。蚂蚁在它们的行进路线上留下信息素,这取决于路线的质量。由于我试图最小化旅行成本,我将使我的信息素质量τ等同于更低的旅行时间。完整图中的每条边都有一个对应的逆旅行时间成本 eta 和信息素 tau 。
每一代都有一定数量的蚂蚁随机出现在图中的起点。然后,每只蚂蚁通过遍历该图来构建解决方案。它通过以加权概率选择下一个位置来实现。计算从位置 I 到位置 j 的概率的公式是:
其中τ表示 n 乘 n 信息素矩阵,并且η表示 n 乘 n 逆行进时间成本矩阵。信息素矩阵中的所有值首先被初始化为 1/n。我发现用 1 初始化信息素矩阵对我的结果几乎没有影响。相应的指数 alph a 和β用于控制信息素和旅行时间成本在两个节点间概率计算中的影响。在分母中,我有这些值的总和,其中 h 表示蚂蚁可以访问的所有可能的位置。这些是特定蚂蚁还没有访问过的节点。将这些项加在一起,计算从节点 I 到节点 j 的加权概率。
每只蚂蚁生成相应的解后,更新信息素矩阵。如何做到这一点取决于所采用的策略。在这个解决方案中,我通过首先将它乘以 p (剩余系数)来更新每个信息素边缘。这代表了信息素“蒸发”或降低其影响的速率。然后,我们添加到信息素边缘 q/c ,其中 q 代表信息素强度,而 C 代表生成路径的总成本。因为行驶时间成本是分母,所以行驶时间较长的路径被选中的概率较低。这个过程重复 g 次,其中 g 代表世代数。
遗传进化
遗传进化(GE)是另一种生物启发的元启发式方法,它从进化过程中采取步骤。它利用连续世代的变异、交叉和选择功能。这些代构成了解决方案的群体。该优化算法遵循以下步骤:
- 创建一组路径。
- 使突变
- 交叉
- 确定适合度(行驶时间)
- 为下一代选择父代
- 重复步骤 2
通过随机生成 n 条路径来创建初始群体。变异和交叉操作基于变异率 m 和交叉率 c 。这两个值都在 0 和 1 之间。当遍历当前种群中的每条路径时,我随机选择一条不同的路径并对其进行变异。这种变异是通过遍历路径中的每个位置,并随机与前一个索引的位置进行交换来完成的。这种随机交换由变异因子 m 加权。
在我创造了突变体之后,我开始杂交。我遍历当前路径和变异路径中的每个索引,并根据交叉率 c:
行程路径中的顺序问题。仅仅在这里结束我的跨界行动是不够的。如上图所示,位置 1 和 12 出现了不止一次。因此,我需要删除重复的。然后,我找到丢失的位置,将它们打乱,并添加到路径中:
一旦我有了最终的后代路径,我就可以评估它与当前路径的适合度。如果它的旅行时间更短,那么它将被选择作为下一代的父路线,取代当前路线。这个过程重复 g 次,其中 g 代表世代数。
实验结果
在我对每种优化算法的试运行中,我发现蚁群优化比遗传进化表现得更好。这是意料之中的,因为蚁群优化算法是专门为解决旅行推销员问题而设计的。对于两种算法的每次试验,我都使用了 15 个不同的位置。
ACO 结果
对于蚁群优化的试验,我使用了以下值: alpha = 1.0,beta = 10.0,p = 0.5,q = 10.0 ,同时我改变了蚂蚁的数量和世代数 g。
下图是用 10 只蚂蚁和 g = 100 生成的。从每代平均成本图中可以看出,ACO 没有陷入局部最小值。它继续探索其他可能的解决办法。这从平均成本的巨大差异中可以明显看出。
通用电气结果
对于遗传进化优化的试验,我使用了以下值:突变率 m= 0.5,交叉率 c = 0.7 同时我改变了群体 p 的大小和世代数 g。从结果中,我可以看到世代越多,群体越大,算法找到的解决方案越好。然而,相比蚁群优化,这种解决方案仍然是劣势。
讨论
实验结果表明,蚁群算法是优化我们的问题的较好算法,该问题类似于旅行商问题。无论我在我的遗传进化程序中使用哪个参数作为种群 p 、突变率 m 或交叉率 s ,它都无法找到成本像 ACO 一样低的路径。我认为这是由多种因素造成的。
首先,考虑两种算法中的解路径是如何生成的。在蚁群中,旅行时间成本 n_ij 是蚂蚁做出的每个决定的考虑因素。这是因为在概率计算中使用了逆传播时间矩阵来确定蚂蚁接下来应该访问哪个位置。遗传进化仅在应用了它的变异和交叉操作之后评估成本。旅行费用对遗传进化的随机成分没有影响。突变和交叉是随机进行的,尽管受到交叉和突变率的影响,但不考虑这些变化是否会给我们带来更低的值。只有在选择阶段,我才会检查后代是否有更好的价值。
这可以解释为什么蚁群不仅表现得更好,而且表现得如此显著,以至于它的第一代产生的结果比遗传进化快了一百多分钟。另一个要考虑的因素是我如何实现我的变异和交叉操作。可能有更好的方法来实现它们,在选择之前也考虑路径的成本。
看到蚁群每一代的平均成本是很有趣的。它向我展示了算法没有陷入局部最小值。相反,它仍在寻找各种其他途径,没有一条比它找到的更好。由于蚂蚁的决定是基于加权概率,这是有意义的。将此与遗传进化的平均成本图进行比较,可以告诉我们该算法可能如何收敛。我从这条曲线上看到的趋势是一个下降的斜率,看起来很快就会变平。
结论
虽然旅行推销员问题本身可能很古老,但它在优步和 Lyft 等现代服务中的应用让我想起了它的相关性和丑陋的阶乘运行时间。随着生物启发优化算法的最新进展,我仍然可以找到可行的解决方案,而不需要多项式时间的解决方案。
在这个问题领域中,遗传进化优化还有进一步的工作要做。挑战在于找到一种更有效的方法,将路径成本纳入变异和交叉操作。但正如这个项目的结果所表明的,我可以肯定地说,蚁群优化确实是为了解决这类问题而产生的。
**注:**你可以从这个 GitHub repo 中查看该项目的完整代码:【https://github.com/khanhnamle1994/trip-optimizer
— —
如果你喜欢这个作品,你可以在 GitHub 上找到我自己的代码,在https://jameskle.com/上找到更多我的写作和项目。也可以在 推特*上关注我直接发邮件给我 或者 在 LinkedIn 上找我 。*
利用人工智能进行糖尿病再入院预测
医院再入院预测仍然是一个高度鼓励的研究领域,主要是因为医疗保险和医疗补助服务中心(CMS)的再入院减少计划。总体目标是通过识别导致再次住院的关键风险因素,减少早期再次住院的人数。这在重症监护室(ICU)中尤其重要,在 ICU 中,由于患者病情恶化,患者再次入院会增加死亡的可能性。传统方法使用简单的逻辑回归或其他线性分类方法来识别提供高预测准确性的关键特征。
Figure 1: Readmission in USA
然而,这些方法是不够的,因为它们不能捕捉不同特征之间的复杂模式。在本文中,我们提出了一个混合进化模拟退火 LASSO 逻辑回归(ESALOR)模型,以准确预测医院再入院率和识别重要的危险因素。提出的模型结合了进化模拟退火法(如下图所示)和 Lasso 的稀疏逻辑回归模型。ESALOR 模型在公开可用的糖尿病再入院数据集上进行测试,结果表明,与包括支持向量机(SVM)、决策树、朴素贝叶斯和逻辑回归在内的传统分类方法相比,所提出的模型提供了更好的结果。
Figure 2: Coupling ES and SA.
考虑到所提供的信息,建议的模型可以总结为以下步骤:
步骤 1 特征选择:使用过滤器和包装器特征选择方法的组合来选择特征的最佳子集。
第二步公式化:确定问题的套索-逻辑回归公式化。
第三步初始化:采用进化策略算法初始化模拟退火模型。
步骤 4 优化级别:使用基于混合进化策略的模拟退火方法来优化 LASSO 模型的参数(系数)。我们优化了所提出模型的参数。
第五步确定解决方案:我们通过比较所有解决方案找到最优方案。
步骤 6 预测:使用具有最佳系数的 LASSO 模型预测新患者的再次入院。
Table 1: Comparison of ESALOR model with traditional classifiers with testing data.
结果(如上表所示)通过观察再入院的性能指标进行比较,我们的模型用于做出更好的预测。在比较四种方法时,我们的方法也显示出比文献中其他方法更好的结果。更具体地,对于 SVM、ANN、LR 和 NB 的结果,如在表 2 中看到的,对于测试水平,预测准确度为大约 74 %。大多数方法的精度和召回值都小于 0.7。与此同时,这些方法的 F 值(需要大于 0.8)被建立在 0.65 左右。因此,当使用诸如 SVM、人工神经网络、LR 和 NB 等优秀方法时,预测性能不足以用于再入院。
然而,我们提出的模型的性能远远优于其他方法,如 F-measure。这意味着所提出的模型适用于不平衡数据,因为没有针对每个子类的不平衡学习。因此,提出的模型在预测再入院率方面表现更好。
结论
随着医疗保险和医疗补助中心(CMS)引入报销罚款,医院对降低再住院率产生了强烈的兴趣。在这项研究中,我们提出了一个混合分类框架,称为进化模拟退火 LASSO 逻辑回归(ESALOR ),以改善糖尿病患者再入院的分类。ESALOR 模型可以帮助医疗服务提供者识别导致糖尿病患者再次住院的关键风险因素。通过使用确定的风险因素,医生可以制定新的策略来降低糖尿病患者的再住院率和护理成本。
使用人工智能方法在扑克中获胜
这篇文章最初写于 2015 年,回顾了当时扑克研究的最新水平以及脑机接口技术如何影响它。
Victoria Peak, Hong Kong. Ori Cohen.
在扑克中获胜的概念很简单,理论上,你所要做的就是获得获胜的一手牌;价值最高的五张牌的组合。但由于其多种形式和多种动态,在实际操作中,扑克是一种依赖于偶然性的复杂游戏,需要对策略的深刻理解;有些是数学上的,有些是基于个人经验。
使用人工智能(AI)解决游戏是一种常见的做法。游戏不允许随机性,遵循预定义的规则,并使用一个相对简单的因素来衡量性能和胜算(例如,在国际象棋中,你通过拿下国王来获胜,在跳棋中,你通过锁定对手或抓住他的所有棋子来获胜),这些游戏是人工智能的经典测试平台。这些游戏可以在计算机上完美地定义[1],因此完全可以通过使用数学公式、统计方法、机器学习方法(ML)或策略和启发式方法来解决。用今天的 CPU 处理术语来说,它并不昂贵,而且相对容易完成。像国际象棋和跳棋这样的游戏已经被成熟的人工智能软件完全解决了,这些软件能够像人类大师甚至更高的水平进行游戏。通过利用人工智能编程建立一个所有动作的深度树,他们能够以很高的速度遍历树,并选择最佳的动作来获胜。相比之下,像扑克这样的游戏引入了运气的元素,或者换句话说,当你或你的对手从一副牌中抽出一张牌时,这张牌会提高还是阻碍你获胜的机会是未知的。因此,扑克是一种比那些不涉及随机元素的游戏更难解决的游戏,并且不能通过使用适用于非随机游戏的完全相同的技术来解决。
几项有影响力的研究集中在赢得扑克游戏的不同方法上。在这篇综述中,我们将介绍这些方面。通常,在扑克中获胜可以通过模拟对手并利用他们的弱点,通过使用学习专家策略并实时应用它们的算法,或者通过“读取”对手的想法来确定对手是否在虚张声势,所有这些方法都是为了在扑克中获胜而研究的。
扑克是一个不完美信息游戏,有竞争对手,有风险管理,有成功概率,有欺骗。不像在国际象棋中忽略对手建模是无关紧要的,在扑克中承认他们是非常有价值的,因此许多努力被投入到对手建模中[4,5,6,7,8]。有几种方法可以预测敌方可能采取的行动:1。专家系统——为了硬连接我们自己的或固定的策略,这种方法通常作为基线测量是好的。2.试探法——一种解决问题的方法,其结果是决策的近似值,而不是最佳值。3.统计学——根据对手的记录预测对手的行为。但是,这种方法容易受到不断改变下注习惯的对手的影响。4.神经网络(NN)——一种通用系统,能够预测对手的下一步行动,基于 ML 方法,并大致受我们大脑生物学的启发。神经网络相对容易创建,准确,并且明显优于前三种,但我们无法从它们那里获得学习信息(图 1a)。一般来说,NN 接收大量输入(我们下一步行动的可能性)并处理它,直到选择一个输出(下一步行动)。5.决策树(DT)-是经典 ML 中的另一种方法,可以对对手的未来行动进行分类,方法是在每个树节点(图 1b)提出一个问题,然后沿着树向下爬到拥有最终决策的末端叶子。DT 不像 NN 那样健壮,但是是人类可读的,并且获得相似的结果。
Figure 1: a (left) A Neural Network predicting an opponent future action. b (right) A subset of a decision tree model. [4]
Loki [4]和 Poki [5]是两个扑克程序,旨在观察对手,模拟他们的行为,并动态适应他们的游戏,以利用他们薄弱的游戏模式。这种“技能”在现实世界中提供了巨大的好处,因为它可以增强玩家发现虚张声势或从游戏中理解对手意图的自然能力。对手建模程序旨在检测经常弃牌和不经常弃牌的玩家,他们的游戏有多被动或激进,他们根据手中的牌下注或加注的行为,以及他们对动态策略的适应程度。洛基和波基在击败强大的扑克玩家方面无疑是一个进步,但它们肯定有其局限性,因为人类玩家也擅长对手建模,并可以实时改变他们的策略。然而,艾伯塔小组一直在研究扑克,最近宣布,他们首次创建了一个名为 Cepheus [9,10]的计算机程序,解决了“单挑限制德州扑克”(HULHE)。这个高度复杂的游戏有超过 10 个⁴决策点,挑战人工智能研究超过十年。实现仙王座需要 68 天,使用 4800 个 CPU 的高性能计算机集群,加上数据压缩和最先进的计算算法。呼和是一个需要人类玩家使用欺骗和虚张声势的游戏,显然不是机器式的特点;仙王座能够在不欺骗人类玩家的情况下和他们进行比赛,并且不让他们知道他们是在和一台机器比赛。
另一种使用人工智能在扑克中获胜的方法是通过脑电图(EEG)检测虚张声势。脑电图是一种从大脑读取电信号的方法,通常使用一个基于电极的帽子,戴在一个人的头上,如图 2 所示。测量隐蔽的人类状态[11],可以用 EEG 来执行,EEG 提供被注册为生理特征的健壮信号,并且可以通过 ML 方法来分类。虚张声势是一种故意误导游戏中其他对手的行为,是一项复杂的任务,需要有预谋的风险评估、虚假意图的行为和持续的跟进,尤其是在保持镇静方面。人工智能方法被用来分类玩家是否在虚张声势,这种方法可以帮助玩家通过了解对手的心理状态并抵消其隐藏的意图来赢得扑克比赛。经验结果表明,平均有 81.4%的概率可以检测到虚张声势。换句话说,在 200 毫秒的时间框架内,10 个人中有 8 个人可以持续检测到虚张声势。时间足够短,以赢得大多数使用诈唬或其他隐蔽状态作为策略工具的游戏。脑电图也可以记录额外的改善,如果眼球运动或肌肉紧张将被考虑在内,这两者都可以用脑电图记录。
Figure 2: an electrode array used to read electric signals from a person’s brain [from wikipedia]
已经有的消费者解决方案用于读取 EEG 大脑信号。虽然脑电图已经使用了 20 多年,但消费产品仍处于起步阶段。我假设脑电图设备将会进一步小型化,让非技术人员也能使用,并进行微调,以高精度读取房间内特定的大脑模式。自动诈唬分析方法也将得到改进,从而可以在锦标赛和私人高赌注游戏中秘密使用这种技术。然而,即使有这些进步,总有办法检测或阻止新技术无线工作,并防止扑克玩家拥有不公平的优势。虽然扑克在许多方面仍然是一种具有挑战性的游戏,但过去的经验告诉我们,随着研究和硬件的进步,人工智能的未来可以在我们的有生之年解决其他扑克变种。
参考资料:
[1] S .罗素和 p .诺维格。人工智能:现代方法。普伦蒂斯霍尔,1995 年。
[2] M .坎贝尔、A. J .霍恩和 F . h .徐。深蓝色。人工智能,134(1–2):57 { 83,2002}。
[3] J. Schaeffer、J. Culberson、N . Treloar、B. Knight、P. Lu 和 D. Szafron。世界锦标赛口径跳棋计划。人工智能,53(2–3):273 { 290,1992}。
[4] 戴维森。扑克中的对手建模:在敌对和不确定的环境中学习和行动(2002)
[5] D .比林斯,A .戴维森,j .谢弗,d .萨弗朗。扑克的挑战。人工智能,2002 年第 134 期,201–240 页。
[6] A .戴维森、d .比林斯、j .谢弗和 d .萨夫龙。改进了扑克中的对手建模。国际人工智能会议(ICAI,2000 年),第 1467 页{1473,2000}。
【7】比林斯、达瑟等,《对手建模在 扑克 》AAAI/IAAI。1998.
[8]f . sou they,m . p . Bowling,b . Larson,c . Piccione,n . Burch,Billings d .,& Rayner,C. (2012 年)。贝叶斯的虚张声势:扑克中的对手建模。 arXiv 预印本 arXiv:1207.1411 。
[9] Tammelin,Oskari 等人,“解决德州扑克的单挑限制。”
迈克尔·鲍林、尼尔·伯奇、迈克尔·约翰逊和奥斯卡里·塔梅林。单挑限注德州扑克 扑克 解决了。科学,347(6218):145–149,2015。
[11]Jessika Reiss land、Christian Kothe、Sabine Jatzev、Matti Gä rtner、Sebastian Welke 和 Thorsten O. Zander。BCI 检测故意隐藏的用户状态——或者:我们能检测出游戏中的虚张声势吗?
Ori Cohen 博士拥有计算机科学博士学位,专注于机器学习和脑机接口(BCI)。他领导着 Zencity.io 的研究团队,试图积极影响市民的生活。
利用人工智能创造人、车和猫
我们如何利用生成性对抗网络制作超现实的图像
None of the people in these images are real, they’ve just been generated by a neural network! Source.
想想你平常的一天是什么样的。除非你整天锁在房间里看《网飞》或者睡觉,否则当你去你想去的地方时,你很可能会经过很多人。有些人长头发,有些人短头发,有些人大鼻子,有些人小眼睛。
关键是,我们多久会停下来思考一下我们每天所看到的不同特征。你有没有想过,“是什么让一张脸变成了一张脸?”它是有两只眼睛、一个鼻子、一张嘴和一些头发的东西吗?如果是这样,难道我们不能编写一个超级简单的计算机程序,通过组合这些特征来生成新的面孔吗?
不完全是,我们遗漏了很多细节。比如皱纹、阴影和微笑。当我们被要求描述一张脸的特征时,我们可能通常不会想到的东西,但为了让它看起来真实,这些东西必须存在。
Something is off but I can’t put my finger on it… Source.
那么,如果它不只是告诉神经网络将两只眼睛、一个鼻子、一张嘴和一些头发放在一个大肉球上,并希望它看起来合理,那么我们如何才能真正生成人脸呢?
猫捉老鼠的游戏
首先,让我们花一点时间来了解生成性敌对网络(GANs)是如何工作的。
GAN 实际上由两个神经网络组成,一个生成器和一个鉴别器。生成器的工作是根据它所知道的生成新数据,鉴别器的工作是查看生成的数据是否合法。因此,在我们的例子中,生成器会尝试创建新的人脸图像,鉴别器会尽最大努力确定人脸的真假。
假设我们在和一家美术馆打交道。制造者是试图创作假艺术品并出售的人,鉴别者是试图鉴别艺术品真假的馆长。一开始,他们都不擅长自己的工作,但他们都从经验中学习。随着时间的推移,伪造者慢慢变得更擅长根据接受与否伪造艺术品,策展人也变得更擅长辨别真伪。
这基本上是一个生成性对抗网络如何训练的,生成器接受一个随机数,并根据输入吐出一个图像。鉴别器评估发生器的输出,并试图预测图像是否真实。如果猜测正确,网络会将其考虑在内,并更新它们的权重。如果它猜错了,也会发生同样的事情。
最终,目标是让这两个网络达到这样一个点,即生成器非常擅长生成假货,以至于鉴别器将始终徘徊在 50%左右的置信度。
然而,在训练 GAN 时需要注意的一点是,当一方过于擅长自己的工作时,可能会出现问题,因为另一方将无法学到任何东西。如果馆长能够正确地猜测每一件艺术品,伪造者将无法知道它做错了什么。如果伪造者做得太好,策展人总是会被骗,也不会学到东西。
绘制概率分布图
好吧,这很酷,对吧?你可以训练两个相互竞争的神经网络,让它们相互竞争,最终你会得到一个生成模型,它在创建可信的图像方面做得非常棒。但是让我们更深入地了解一下这实际上是如何工作的。
生成式对抗网络实际上做的是映射数据的概率分布。
这到底是什么意思?
我们可以把图片想象成一个高维概率分布的样本。每当你拍照时,你都是在从像素的概率分布中取样。基本上存在产生一些像素排列的概率或可能性,GAN 基于数据绘制概率分布。
对于我们的例子,基本上是学习什么使一张脸成为一张脸。眼睛、鼻子和嘴巴等不同的特征在这个概率分布中有一个表示。因此,改变输入到模型中的噪声将改变对应于这些数字的图像的一些质量。通过从这个分布中采样,我们可以得到一个模型,根据它所知道的图像某一部分中像素的概率来生成全新的图像。
使用 DCGAN 生成新的人脸
An image from the DCGAN paper. Source.
DCGAN 基本上是常规 GAN 的改进版本,但有一些重要的变化:
- 最大池函数被步长卷积取代,让网络学习自己的空间下采样和上采样。
- 去除卷积特征之上的全连接层。一个例子是全局平均池,它经常增加模型的稳定性,但损害收敛速度。最佳解决方案是将最高卷积特征直接连接到发生器和鉴别器的输入和输出。
- 通过将输入标准化为零均值和单位方差,使用批量标准化来稳定学习。这有助于渐变在更深的模型中流动,但不应该应用于所有层。当 batchnorm 不应用于生成器输出层和鉴别器输入层时,可以避免模型不稳定。
- ReLU 激活在发生器中用于所有层,除了使用 Tanh 的输出。据观察,这有助于模型更快地学习并覆盖训练分布的颜色空间。
- LeakyReLU 激活用于所有层的鉴别器中。
如果您对实现 DCGAN 感兴趣,有一个很棒的 PyTorch 教程,它使用了 CelebFaces 属性数据集(CelebA),这是一个包含超过 200,000 张名人脸部照片的数据集。
以下是数据集中的一些图像示例,这些图像被调整为 64x64,以便于训练:
这两个模型的结构如下:
Generator(
(main): Sequential(
(0): ConvTranspose2d(100, 512, kernel_size=(4, 4), stride=(1, 1), bias=False)
(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace)
(3): ConvTranspose2d(512, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace)
(6): ConvTranspose2d(256, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(7): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(8): ReLU(inplace)
(9): ConvTranspose2d(128, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(10): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(11): ReLU(inplace)
(12): ConvTranspose2d(64, 3, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(13): Tanh()
)
)Discriminator(
(main): Sequential(
(0): Conv2d(3, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(1): LeakyReLU(negative_slope=0.2, inplace)
(2): Conv2d(64, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(4): LeakyReLU(negative_slope=0.2, inplace)
(5): Conv2d(128, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(6): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(7): LeakyReLU(negative_slope=0.2, inplace)
(8): Conv2d(256, 512, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
(9): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(10): LeakyReLU(negative_slope=0.2, inplace)
(11): Conv2d(512, 1, kernel_size=(4, 4), stride=(1, 1), bias=False)
(12): Sigmoid()
)
)
那么现在发生了什么,我们已经在一堆人脸上训练了一个神经网络,结果一定很好,对吗?这取决于你对好的定义。
老实说,如果你不仔细看,有些看起来可能是真的脸。不过,其他人看起来像是直接从噩梦中走出来的。
不会是这个吧?一定有更好的方法让假人看起来像真的。英伟达的一些研究人员可能已经找到了秘方。
Nvidia 的 StyleGAN
结果公布后,英伟达用于生成新图像的生成对抗模型在新闻中得到了大量炒作和报道,这是有充分理由的。大多数照片都非常逼真,几乎无法与真实照片区分开来。
“These people are not real — they were produced by our generator that allows control over different aspects of the image.” Source.
老实说,这个模型得出的结果相当疯狂。如果我不是一名高中生,我肯定会尝试自己训练这个模型,但在它真正开始产生可识别的图片之前,我可能已经 40 岁了。他们毫不夸张地推荐一款配有 8 个特斯拉 V100 GPUs 的 NVIDIA DGX-1。因此,除非你手头有 15 万美元的闲钱,或者有一个企业级深度学习系统,否则你可能也不走运。
但是它实际上是如何工作的呢?
关于 StyleGAN 的论文提出了一个重要的问题。即使 GAN 产生的图像的分辨率和质量越来越好,我们仍然很难解释这些机器到底在做什么。它仍然像一个黑匣子。我们也不理解潜在空间,特征到变量的映射,没有定量的方法来比较生成器。
通过从经典的风格转移中获取灵感,我们的目标是以一种允许我们看到图像合成过程的方式重新创建生成器,并让我们调整每层图像的风格以操纵不同的功能。
在高层次上,Nvidia 的 StyleGAN 做了一些类似的事情,它在没有任何人类帮助的情况下学习图像的不同方面,在训练模型后,可以在不同层次上组合这些风格,以获得具有粗糙、中等和精细风格的最终图像。
看看这个恶心的造型吧!
这张图片展示了一些混合的风格:
生成模型的未来
Nvidia 的 StyleGAN 是生成式对抗网络的一个重大突破。网络生成的一些图像与实际照片几乎无法区分。但是 GANs 有哪些实际应用呢?
- AI 为视频生成图形
- 甘斯超分辨率
- 用于文本到图像生成的 GANs】
mediu
感谢阅读!如果您喜欢,请:
- 在 LinkedIn 上添加我,关注我的媒体,了解我的旅程
- 在我的个人网站查看我的一些其他项目
- 留下一些反馈或者给我发邮件(alex@alexyu.ca)
- 与你的网络分享这篇文章
利用人工神经网络分析总统演讲
深入分析
大多数分类任务都是为了区分不同层次的独特性而设计的,但是如果我们已经知道了不同之处,还想寻找相似之处呢?
在大多数分类任务中,总的目标是简单地最大化一些准确度的度量,无论是 F1 分数、平衡准确度等。在这些情况下,我们寻求理解错误的唯一目的是为了在将来最小化它们的频率。总的来说,我们希望将数据集分成尽可能清晰和不同的组。但是如果我们想反其道而行之呢?如果我们已经有了非常清晰的数据,但我们想了解它们是如何组合在一起的,该怎么办?在这种情况下,我们从误差中获得的信息可能比从预测的准确度中获得的信息更多。
考虑两个著名的,但非常独特的电影制作人:昆汀·塔伦蒂诺和韦斯·安德森。为了简单起见,让我们说前者的电影可能被描述为暴力,,而后者将被描述为*古怪。*有了这些知识,看看你是否能正确识别这些电影对白的作者:
- 如果你在梦里开枪打我,你最好醒来道歉
- “我爱你,但你不知道你在说什么。”
- “在我们像一群疯子一样互相攻击,把自己撕成碎片之前,让我们先打开麻袋,看看里面究竟是什么。这甚至可能不值得麻烦。”
在这里,我们看到前两个引号非常容易识别。第一个来自塔伦蒂诺经典落水狗,第二个来自安德森的月出王国。然而,第三部更具挑战性,因为它既有点暴力又有点古怪。我的妻子是这两个编剧兼导演的超级粉丝,她还没有看过这部电影,猜测它来自塔伦蒂诺。事实上,它来自安德森的最新电影《狗之岛》。有趣的是,虽然前两个引语很容易看出它们之间的区别,但第三个引语突出了它们的一些相似之处。
给出一系列这样的引用,你很可能会犯更多的错误。但这些错误实际上可以帮助我们更好地理解两个截然不同的人有什么共同点,尽管乍一看可能并不明显。
在今天的政治气候中,分歧的领域是明显的,我们都可以非常清楚地确定争论的焦点。真正的挑战在于找到共同点,并找到合作的机会。这是深度学习算法可以帮助我们完成的任务吗?这就是我们要努力解决的问题。
我们将采用与任何其他文本分类任务基本相同的方式来完成这项任务,真正的区别在于我们稍后如何解释结果。语法实验室储存了从华盛顿到奥巴马的总统演讲语料库,以及唐纳德·特朗普和希拉里·克林顿在 2016 年总统竞选期间的辩论和演讲的文字记录。所有工作都是使用 Jupyter 实验室和相关库在 Python 中完成的。
首先,我们将利用 2016 年的竞选数据建立和训练一个网络,然后看看这种方法在其他总统比较中的适用程度。由于大多数演讲将涵盖广泛的主题,我们希望能够在我们的预测误差中识别出明确的主题,因此每篇演讲被分成 50-100 个单词的部分,并保存到带有适当标签的数据帧中。
预处理
由于这不是本次分析的主要重点,我将快速强调一些关键步骤。如果你想更深入地了解这个话题,我鼓励你看看这篇的博文,它对我帮助很大。简而言之,大多数预处理包括以下步骤:
- 去除标签:所有的演讲都以一致的方式格式化,日期、标题、以及除了预定演讲者之外的其他人所说的话的标签都被包含在 *< >中。*在保存到数据帧之前,所有这些文本都从样本中移除,并且不包括在每个样本的字数中。
- **扩展缩略:**像“不会”和“应该”这样的词被识别出来,并用完整的词“不会”和“应该”代替一个标准的收缩列表和它们的对应物被用来完成这项任务。
- **删除特殊字符:**撇号、连字符等。
- **文本词汇化:**获取单词变体的基本形式(即 running = > run,cats = > cat,等等)。).
- **删除停用词:**使用了自然语言工具包(nltk)中的标准英语停用词列表,删除了单词 no 和 not ,因为它们会改变周围单词的解释。
- **标记化:**将字符串转换为单个单词的列表。
- 创造二元模型:许多单词作为短语的一部分比它们本身有更多的含义。对于专有名词来说尤其如此,比如*美国,乔治·华盛顿,等。但是它对像核武器这样的术语同样重要。*我们不是将所有的单词转换成二元模型,而是只希望转换那些有一定规律性的短语。幸运的是,Gensim 库有一个工具可以让这变得非常简单,这个工具叫做短语。请参见下面的代码来查看实现。
*Output:
Maximum Sample Word Count: 88
Sample:
maggie elizabeth walk stage lot folk hang window glad get good view also exciting* ***two_week*** *leave* ***consequential_election*** *lifetime*
数据不平衡
事实证明,特朗普花在竞选演讲上的时间比克林顿多得多,导致数据严重失衡。如下图所示,特朗普语料库的样本量是克林顿的近 4 倍。
如果用这种状态下的数据训练一个模型,它可以学会 100%的时间简单猜测特朗普,并达到 80%的准确率,这将是相当误导的。为了解释这一点,必须从特朗普的语料库中抽取一部分样本,其规模相当于克林顿的语料库。
使用手套矢量化
从这里开始,我们可以使用斯坦福大学的单词表示全局向量来将单词转换成向量。使用 100 维的向量来表示语料库中的每个单词,然后链接到每个样本中的每个单词。这可以通过下面的代码块来完成。
W2vVectorizer 类将在以后为基准目的训练模型时调用。
标杆管理
为了有一个有效的方法来衡量神经网络的性能,必须建立一个使用传统机器学习方法的基准。在这个项目中,使用了支持向量机、对数回归和随机森林。
Output:*[('Random Forest', 0.7851123595505618),
('Support Vector Machine', 0.7202247191011235),
('Logistic Regression', 0.7789325842696628)]*
从这里,我们可以看到一个随机森林模型获得了 78.5%的最高准确率。出于这个项目的目的,我们并不真正关心错误偏向哪个方向,因为数据集已经平衡,所以没有理由担心模型被不适当地偏向以获得异常高的准确性分数。
网络建设
因此,我们对数据进行了预处理、清理、平衡和标记,我们有了一个基准。现在是时候卷起袖子准备好玩的东西了!为了分析这些数据,我们将尝试递归和卷积神经网络(RNN 和 CNN 的),每种网络都首先需要创建一个嵌入层,它可以有效地将我们的样本转换为向量序列集。
现在,与其简单地创建一个 RNN 和 CNN 来进行分析,不如我们可以实现网格搜索来找到性能最佳的模型,这不是很好吗?不幸的是,没有理想的方法来实现一个 SKLearn 管道而不丢失以后可能是无价的信息,所以我们将从头开始创建这个网格搜索。我们首先从卷积网络开始。
构建卷积神经网络
首先:CNN 通常用于图像处理任务,所以你可能想知道为什么我们在这里应用它。据报道,CNN 实际上也很擅长 NLP 任务。我们将简单地使用一维层作为解释序列的方式,而不是使用三维层。当词库作为向量被收集时,网络可以识别紧密相连的词之间的共性。理论上,这应该允许我们的网络有效地识别语音模式。稍后将详细介绍。
目前,我们需要一个可以构建、训练和评分一个 CNN 的函数。它将使用默认参数和固定架构进行设置,该架构已被多个来源确定为 NLP 任务的有效起始架构。总共有 10 层,包括嵌入层。
需要注意的一点是,默认设置是经历 100 个时期。考虑到我们正计划实现网格搜索,这似乎有点极端。然而,提前停止已经在耐心水平为 5 的情况下实现。换句话说,如果损失函数在连续 5 个时期后没有产生改进的结果,训练将停止,并且记录结果。
除了模型、历史和结果,还将提供处理时间,以便我们可以跟踪完成每一步的时间。
CNN 网格搜索
从这里开始,只需要为我们的超参数定义网格并记录结果。
你可能想知道为什么要尝试;除了语法在这里。嗯,整个笔记本允许选择任何字长的样本序列。考虑到这一点,举例来说,试图从 20 个单词中汇集 35 个单词将会导致错误。因此,考虑到给定源数据,某些超参数集可能是无效的。
另一项值得注意的是,我们的模型被保存,并在网格搜索的每次迭代中被覆盖。这样做的原因是有 72 个网格要搜索,我们不想浪费内存保存每一个。取而代之的是,结果被存储,并且模型将使用最高性能的参数被再次创建。这将使我们能够更好地了解最佳表现模型的培训进度和历史,并使我们能够更有效地将结果与 RNN 进行比较。
构建递归神经网络
从这里开始,我们将使用与上面相同的方法构建一个带有网格搜索的递归神经网络。一个关键的区别是,RNN 氏症可以使用两种不同类型的神经元:长短期记忆(LSTM)或门控循环单位(GRU)。这些选项会影响网络本身的架构,但这可以通过一个简单的条件语句来说明。
从这里开始,RNN 和 CNN 网络之间唯一真正的区别是网格本身。
可视化结果
一旦我们的 RNN 和 CNN 网络经过训练和测试,我们就可以开始看结果了。具体来说,我们希望比较基准测试、表现最佳的 RNN 和表现最佳的 CNN 之间的准确度分数。
从这里,我们可以看到我们的递归神经网络优于卷积神经网络,并且大大优于基准。通过将模型保存到一个名为 *best_model,*的变量中,并对其调用 predict 方法,我们可以开始更详细地研究结果,从创建混淆矩阵开始。这里需要做的就是调用顶层模型的 predict 方法,并将其传递给一个函数,该函数将为我们创建可视化效果。
Output:
Confusion matrix, without normalization
F1 Score: 93.08%
在网络做出的 1,780 个预测中,有 123 个是不准确的,第一类和第二类误差相当均衡。由于我们并不真正关心错误类型的平衡,F1 分数被用作衡量性能的主要指标。从这里,我们可以从结果中创建一些单词云,以了解我们的网络在哪里、为什么以及如何出错,希望它能揭示我们两位候选人的共同点。
字云可视化
从这些结果中创建词云的关键是确保我们的原始样本与每一步的转换保持紧密结合。例如,参见下面的代码,它说明了原始文本样本是如何通过排序和训练/测试分割保持完整的:
这里的关键是文本样本和 bigram 数据被添加到 dataframe 的最后两列,即第 21 行和第 22 行。然而,只有向量被传递到嵌入中,如第 34 行所示。因此,我们可以稍后从测试集的模型中调用 predict 方法,我们的原始文本数据将被绑定到同一个索引。
此时,只需将字符串列表转换成由逗号分隔的单个单词字符串。在这个实例中,我们有三个不同的字符串:一个用于每个候选项(p1_cloud & p2_cloud),一个用于错误数据(error_cloud)。从这里开始,你所要做的就是找到并下载你想要的矢量图像,然后使用下面的代码创建你想要的形状的单词云:
关于为每个候选人的词云选择词,我选择关注它们之间使用频率差异最大的词。换句话说,像美国这样的短语对任何总统候选人来说都会被频繁使用,而且不会突出任何独特性。候选词之间使用差异最大的词被使用。
对于错误,由于目标正好相反(突出相似之处),使用了简单的频率计数,因为说话者的身份不太重要。
以下几对总统也完成了上述所有步骤,准确性和词云结果如下:
综合来看,我们可以看到我们的模型达到了 84.3%到 94.3%之间的平均准确率。这可能是由于模型性能的不一致性,但也可能是由于每对模型之间不同程度的相似性和差异。换句话说,林肯和华盛顿的准确率较低,表明他们比特朗普和克林顿有更多的共同点。相反,西奥多·罗斯福和安德鲁·杰克逊之间的差异很可能大于特朗普和克林顿。
需要说明的是,这些仅仅是第一印象,还需要进一步的调查来确认事实是否如此。目前,我们将继续关注特朗普和克林顿。
解读结果
不出所料,结果突出了这两位候选人之间的明显区别。一方面,我们有克林顿,她努力吸引妇女和年轻人,并花了很大力气强调她的执政经验。另一方面是特朗普,他的竞选活动似乎主要侧重于直接攻击克林顿。尽管他确实提到了移民、监管和贸易,但它们在他的词汇索引中的重要性远没有人们想象的那么明显。
通过查看与预测误差相关的单词 cloud,我们希望能够找到一些共同的主题。不幸的是,它并没有像预期的那样工作,尽管通过搜索术语机会的错误确实产生了一些有希望的结果。看看希拉里·克林顿的下面这段话:
但是你们的政府可以做一些常识性的事情,给美国人更多的成功机会。我们为什么不做呢?因为强大的特殊利益集团和将意识形态置于政治进步之前的倾向导致了国会的僵局。当你看到什么都没做时,你怎么能不沮丧,甚至生气呢?许多人觉得没有人站在他们一边,没有人支持他们,这在美国是不应该的。
我们的网络将此错误归类为特朗普的话,这表明特朗普和克林顿都同意,代表们没有有效地代表或代表他们选区的最佳利益:政府已经崩溃,需要修复。
因此,可能是我们的网络仅仅需要更多的改进,但也可能是错误云这个词需要不同的编译。可能两者都有一点,需要一些时间来解决,特别是在网络优化方面。幸运的是,有一项在这方面向前推进的战略。
下一步:模型细化
我们想找出是否存在一组特定的超参数来最大限度地提高测试精度。为了进行这样的分析,我们需要数据。为了实现这一点,随机选择了 500 对总统,对其进行了基准测试,并使用 2 个神经网络(1 个 CNN 和 1 个 RNN)和随机选择的超参数集进行了测试。所有的结果和数据都保存在一个数据框架中(其子集可以在下面找到),并进行初步的探索性分析。
我首先关注的是样本大小对准确性的影响,因为阶级不平衡是一个大问题。正如我们在上面所看到的,与詹姆斯·加菲尔德的所有比较只选择了 86 个样本,这是因为他唯一有记录的演讲是他的就职演说,在他就任总统仅 100 天后就被暗杀了。从这些分析中无法得出有意义的结果。从下面可以看出,要得到有意义的结果,至少需要 500 个样本。任何低于这个数字的结果都会变化很大,平均准确率接近随机水平。
然而,要清楚的是,某些结果产生 0%的准确度分数的事实导致了对代码中的错误的怀疑,该错误还没有被识别。这种影响似乎范围有限,不会对总体结论产生重大影响,但我确实认为,为了透明起见,这一点值得一提。这将在未来的更新中解决。
看一看网络架构,我们还可以探究所选不同模型的有效性。在这种情况下,循环网络被细分为长短期记忆(LSTM)模型和门控循环单元(GRU)模型。
在这里,可以观察到递归网络大大优于卷积网络,尽管后者在大多数情况下确实取得了最好的成绩。这可能是因为这些网络具有工作得非常好的特定超参数集,或者当存在某些样本特征时,它们通常工作得更好。无论哪种方式,都绝对是值得进一步探索的东西。
从更长远的角度来看,理想的做法是采用贝叶斯方法来构建网络,更新架构,并根据每一组新的结果以增量和编程的方式调整参数。实际上,这是一种训练机器制造机器的方法。但那将是另一天的挑战。
结论
从目前的观察来看,这个项目的目标在原则上似乎是合理的,我们有一个模型构建方法可以帮助我们实现这个目标。不幸的是,该方法目前的有效性仍然需要大量的手动搜索来找到共同的主题,但进一步调整模型,我们可以提高准确性,从而缩小我们的 spotlight 搜索的焦点。
然而,当收集随机选择的 500 位总统的数据时,当准确性达到足够的水平时(定义为分数超过 90%或网络优于基准时),错误数据会继续被跟踪。由此,可以创造出最后一个词云,人们可能会将其解读为反映了美国总统政治历史上的共同主题。尽管需要做更多的工作来弄清楚我们要去哪里,但反思我们去过哪里总是一个好的做法。
参考
可以在 Github 上找到这个项目的存储库以及所有相关的 Jupyter 笔记本。
使用 Azure 认知服务对特朗普的推文进行情感分析
一个关于如何使用 Azure 认知服务(文本分析 API)的广泛教程,通过 Databricks (Python,Scala)执行情感分析
Photo by Con Karampelas on Unsplash
第一部分——提取推文
情感可以在任何地方表现出来,比如评论、新闻、现实生活中的对话、新闻等等。通过采用机器学习方法来准确识别情感极性的能力开启了一系列可以为企业带来巨大价值的业务用例。如果机器可以自动确定情感,而不是人类通过分析内容来推断情感,这是一个低效率的过程,需要大量的成本和时间来评估;企业可以利用这种洞察力来调整他们的战略(例如,对于一家零售公司,他们可以加快定制营销,以降低流失风险并限制负面口碑的影响,这可以是一个反馈循环,以重新审视产品/服务并改进它,正如比尔·盖茨曾经说过的一句名言:“你最不满意的客户是你最大的学习来源”)
考虑到这种情况,如果必须建立大规模执行情感学习的能力,一种选择是使用传统的机器学习方法来建立分类器,该分类器预测输入(可以是从其原始形式转换成机器学习算法可理解的形式(包括单词包或 TF/IDF 或任何其他表示,例如 word2vec)的文本)是否属于离散的二进制类别(肯定或否定)。人们可以使用传统的监督机器学习算法,如朴素贝叶斯、逻辑回归、SVM、决策树或基于集成的随机森林来完成任务,并且可以基于所选的评估度量来实现相对较好的性能水平。或者,人们可以探索像多层感知器这样的深度学习方法,以实现类似的目标。但不管你的数据科学团队有多先进或完善,除非你是微软或谷歌或类似的公司,否则在性能和效率方面,与大公司(如微软)使用的方法竞争并不容易。云服务的一个优点是,它们基于数十年的研发投资,提供即时消费的分析服务,如 Azure Cognitive Services 或 AWS intensive。人们可以将这些服务用于情感分析用例,以快速实现价值。在我的上一篇文章中,我们探讨了 Azure 认知服务在内容审核中的使用,而这篇文章是关于使用 Azure 认知服务套件中的另一个服务进行情感分析!
为了让事情变得有趣,我将演示如何使用 Azure 认知服务对唐纳德·特朗普发布的推文进行情感分析。我不确定你,但许多人可能会先入为主,有偏见地认为他的推文确实带有“特定极性”。这项练习将努力验证这一假设,并分析他最近的推文,看看他们有什么情绪。
该员额将由两部分组成。在第一部分中,我将演示如何使用 Python 检索数据(本例中是 Trump 的 tweet ),在下一部分中,我将重点介绍如何使用 Scala 和 Databricks (Spark)以可扩展的方式分析 tweet。同样,代码实现不会是产品级的,只是为了证明其功能。
让我们从第一部分开始,即数据提取。为此,您将需要以下内容:
- Python(我用的是 Python 3.5)
- 开发环境(IDE 或笔记本。我正在使用数据块)
工作流看起来会像这样:
提取推文- >执行一些处理- >在文件系统中持久化 - >在 Spark 中读取推文- >与 Azure 认知服务集成- >生成情感预测- >执行分析
粗体部分将是这篇文章的范围。其余的将在第二部分讨论。我们开始吧,好吗?
如果你还没有注册社区版的 Databricks,你可以访问下面的链接。注册后,您必须在使用笔记本电脑之前启动一个集群。有了 community edition,可用的集群非常小,但对我们来说已经足够了。要创建集群,请单击左侧菜单上的“集群”,然后单击“+创建集群”按钮:
它将为您提供创建集群的选项。为群集指定您选择的名称。参数的默认值应该没问题。完成后,单击“创建集群”。安装群集需要几分钟时间。
该群集将安装最少的软件包。为了提取推文,我们将使用 tweepy。要使用它,您首先必须在集群中安装它。为此,单击 Workspace -> Users。
单击您的电子邮件 id,然后右键单击级联部分->创建->库
然后在该部分中,选择 PyPI,在包区域中写入“tweepy ”,并单击“创建”
完成后,点击 Databricks 主页中的“新建笔记本”:
给你的笔记本命名,选择 Python,点击“创建”
完成后,您就可以使用笔记本了。如果你以前用过 Jupyter 笔记本,UX 看起来会有些相似。
现在,随着环境的初始化和供应,需要满足另一个依赖性:为了能够与 Twitter 集成,您需要创建一个 Twitter 应用程序。我不会深入讨论这个步骤的细节,但是这个链接提供了一步一步的操作步骤。一旦你注册了一个 Twitter 应用,你需要以下四个相关的凭证:
API 密钥
API 密钥
访问令牌
访问令牌秘密
现在我们已经准备好实际编码了!在我们进行的过程中,我会尽力解释这些代码。
让我们从导入所需的模块和初始化所需的变量开始。
from tweepy import OAuthHandler
from tweepy import API
from tweepy import Cursorconsumer_key = "" #twitter app’s API Key
consumer_secret = "" #twitter app’s API secret Key
access_token = "" #twitter app’s Access token
access_token_secret = "" #twitter app’s access token secret
使用 twitter 应用程序时的身份验证机制是 OAuth,tweepy 的 API 使得使用 OAuthHandler 类来执行身份验证变得很方便,在 OAuth handler 类中,您可以指定与 Twitter 应用程序相关的凭据。然后用 tweepy。API 是 Twitter 为其余步骤提供的包装 API:
auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
auth_api = API(auth)
tweepy 返回的对象。API 类提供了许多可以用来提取 tweets 的方法。在这篇文章中,我们将使用的是 user_timeline()函数,它允许我们指定 Twitter 句柄、推文数量:
trump_tweets = auth_api.user_timeline(screen_name = ‘realDonaldTrump’, count = 600, include_rts = False, tweet_mode = ‘extended’)
许多参数是不言自明的。具体来说,将 include_rts 设置为 False 会将 retweets 从帐户中排除,而 tweet_mode 作为 extended 会提供 tweets 的完整文本,否则会被截断。trump_tweets 是一个 tweepy.models.ResultSet 类型的对象。它就像一个可遍历的 iterable,其中的每个元素都包含属性 full_text,该属性包含所需的 tweets 文本。因此,让我们使用 Python 的列表理解来完成这项任务,如下所示:
final_tweets = [each_tweet.full_text for each_tweet in trump_tweets]
以下是我试图提取时的推文。您的可能会有所不同。
现在让我们以文本文件的形式保存这个列表,这样我们可以在管道的第二阶段使用它们。因为我们将在第 2 部分的 Databricks 中使用 Spark 分析 tweets,所以在这种情况下使用分布式文件系统或对象存储是有意义的。这就是 Databricks DBFS (Databricks 文件系统)让事情变得更简单的地方。这个主题本身需要大量的理解,但在这个阶段,知道 DBFS 也是一个分布式文件系统就足够了,它根据云环境物理化在对象存储上(Blob 代表 Azure,S3 代表 AWS)。您还可以在 DBFS 挂载您的对象存储,并可以访问其名称空间下的对象存储。最后,您还可以使用本地文件系统 API(例如 Python 的)在 DBFS 上进行读/写(由 FUSE mount 提供)。因此:
with open(‘/dbfs/FileStore/tables/trump_tweets.txt’, ‘w’) as f:
for item in final_tweets:
f.write(“%s\n” % item)
您可以通过多种方式验证数据是否已成功写入。其中一种方法是再次读取该文件,以确保它已被正确写入:
read_tweets = []
with open(‘/dbfs/FileStore/tables/trump_tweets.txt’,’r’) as f:
read_tweets.append(f.read())
下面是一个输出示例:
这篇博文的第一部分到此结束,其中重点介绍了使用 Python(通过 tweepy 模块)从特定用户提取 tweets 的过程,以及使用 Databricks 笔记本的配置步骤。
第二部分—面向情感分析的 Azure 认知服务集成
在您从指定的 twitter 句柄(本例中为 @realDonaldTrump )中提取所需的一组推文之后,这个分析管道的下一部分是与 Azure 认知服务集成,以获得情绪预测。我们将在数据块中使用 Spark 来实现大规模处理(有一些警告)。如前所述,Azure 认知服务是一套服务,对于推文的情感分析,我们将使用 Azure 文本分析 API 。此外,为了扩大这篇文章的影响,增加你的技能,我将演示你如何在使用 Scala 时做到这一点!所以让我们开始吧。
依赖性管理:
首先,你需要注意一些依赖关系:
**1。Azure 认知服务中的文本分析 API—**如果你有 Azure 订阅(免费试用也适用于本例),你需要在 Azure 认知服务中提供文本分析 API。这个过程应该类似于我之前的帖子,在那里我演示了如何使用 Azure Cognitive Services 的内容审核服务。在提供了文本分析 API 之后,您需要获取以下详细信息:
文本分析 API 端点
API 认证密钥
一旦完成,您的文本分析 API 就可以从基于 REST 的客户机上使用了,它是用您选择的语言编写的(在这里是 Scala)。
2。Scala 库— 我们将依靠几个 Scala 库来完成这项工作。具体来说,我们将需要以下几个:
scalaj (向 Azure 文本分析 API 发送 REST 调用)
spray json (解析 Azure 文本分析 API 的 json 响应,我们将使用这些响应进行后续处理)
由于我们使用数据块,因此为您的环境管理这些依赖项的过程将是相似的。也就是说,您必须创建一个库,并将其附加到您启动的集群。对于 JVM 语言,maven 通常是您可以找到许多此类依赖项的首选存储库。要在 Databricks 中管理这些库,您必须为它们提供 maven 存储库坐标(由(group id:artifact id:Version)组成)。当您指定这些 maven 存储库坐标时,依赖关系管理(就像 Databricks 中使用的那样)能够在 maven 存储库中找到这些坐标,下载并在您的环境中安装/供应它们。下面举例说明如何在 Databricks 中指定 Spray Json 库的 maven 坐标:
您必须为 scalaj 库做同样的事情。
现在来看实施部分,监督您将要实施的工作流程总是有帮助的,因此我们的工作流程将由以下步骤组成:
阅读来自 DBFS 的推文- >删除推文文件中仅包含 URL 的任何行(因为它们不会包含任何情绪信号)- >以 Azure Text Analytics API 端点所需的 REST 调用的形式格式化每个推文行- >将 REST 调用发送到 Azure Text Analytics API 端点- >处理分析洞察的结果
有了这个工作流,让我们来考虑每个步骤的实现。作为一个好的实践,我们将首先创建一些帮助函数,它们将帮助我们执行上面提到的许多任务。
Scala 函数将 tweets 数据格式化为 REST POST 调用格式:
创建一个 Databricks 笔记本,选择 Scala 作为语言,并在一个单元格中编写以下代码:
def requestFormatter(givenTweet:String):String={
s"""{
"documents":[
{
"language":"en",
"id":1,
"text":"${givenTweet}"
}
]
}"""
}
让我们了解一下这段代码中发生了什么:
1。我们创建了一个名为 requestFormatter 的函数,它接受一个 String 类型的参数(givenTweet)。
2。该函数返回字符串
3。该函数根据 Azure Text Analytics API 的要求创建一个 Json,该 Json 由一个键-值对组成,键为“文档”,值为由语言、id 和文本字段组成的对象列表。这些字段不言自明。列表中的 id 字段应该是唯一的。在这种情况下,文本是实际数据(tweet)将嵌入的字段。此外,因为 documents 是一个列表,所以您可以有多个语言、id 和文本字段的对象,并且您可以在一个 REST 调用中发送多达 5000 个对象。然而为了简单起见,我只是在一个 REST POST 调用中发送一个对象。
Scala 函数发送 REST POST 调用:
在另一个单元格中,键入以下代码:
def sendPostRequest(textAnalyticsUrl:String,subscriptionKey:String,requestBody:String):String={
import scalaj.http.Http
Thread.sleep(3000)
val result = Http(textAnalyticsUrl).postData(requestBody)
.header("Content-Type", "application/json")
.header("Ocp-Apim-Subscription-Key", subscriptionKey).asString
result.body
}
下面是我们在这个函数中所做的:
1。函数 sendPostRequest 接受三个参数(textAnalyticsUrl 表示 Azure 文本分析 API 端点 URI,subscriptionKey 表示您之前检索的将用于 REST 调用身份验证的密钥,requestBody 是将作为 REST 调用的一部分发送的数据
2。我们为这个实现引入了 3 秒的延迟,这样 Azure 就不会阻塞我们的请求。有更好的方法来解决这个限制。
3。然后,我们发送一个 REST POST 调用,指定 URI、标头(“Content-Type”、“application/json”、“Ocp-Apim-Subscription-Key”、subscriptionKey),并用我们将通过前面的函数获得的 json 填充请求体。
4。最后,我们从这个函数中以字符串形式返回 REST 响应的结果,其形式如下:
{
“documents”:[{“id”:”1",”score”:0.85717505216598511}],
“errors”:[]
}
其中 documents 对象包含一个列表,特别是对应于文档 id 的分数。返回的分数从 0 到 1 不等,它是调用 Azure Text Analytics API 后的预测结果。接近 0 的值代表消极情绪,接近 1 的值代表积极情绪。
Scala 函数移除 Tweets 中的 HTTP 行函数:
该函数用于删除 tweets 文件中可能存在的 HTTP 行。
def removeHttpLines(textLine:String):Boolean={
import scala.util.matching.Regex
val pattern = "^http".r
pattern.findFirstIn(textLine) match {
case Some(x)=>false
case _ => true
}
}
1.该函数需要一个参数(字符串类型的 textLine)并返回布尔值(true 或 false)。
2。它利用正则表达式并在文本文件中寻找一个特定的模式,其中一行以“http”开始。它确实可以进一步细化,但为了简单起见,让我们使用它。
3。然后,它试图在文本文件中找到该模式。在这里,Scala 的模式匹配结构用于匹配两种可能性:如果找到匹配,即 Some(x ),那么返回值将为 false,否则将返回 true。我们返回这些值的原因将很快变得显而易见。
现在有了这些函数,让我们实现剩下的逻辑,有趣的是,由于 Scala 是一种函数式编程语言,它可以用一行代码来表示:
val tweetsSentimentsRdd = sc.textFile("/FileStore/tables/trump_tweets.txt").filter(removeHttpLines).map(x=>requestFormatter(x)).map(y=>sendPostRequest(url,subscriptionKey,y))
让我们来破译这里发生了什么:
1。首先,我们使用 SparkContext (sc) textFile 函数,该函数用于从文本文件中读取数据(通常来自 HDFS,在本例中是实现其接口的 DBFS)。它接受字符串形式的文件路径,这就是我们指定 tweets 文件的位置。此函数返回字符串类型的 RDD,其中每个元素对应于文件中的每一行。下一步是过滤掉任何只包含 http URLs 的行。这就是我们使用 Spark 的滤镜变换的地方。在它的参数中,我们传递了一个函数(再次感谢函数式编程),特别是 removeHttpLines,它将对数据的每一行进行操作,并将只返回那些从该函数中产生 true 的行(即,在它们的开头没有 http)。
3。下一部分转换过滤文本的每一行(即删除 http 行),并(使用 requestFormatter 函数)将每条 tweet 转换为所需的 Json 字符串,格式如下:
{
“documents”:[
{
“language”:”en”,
“id”:1,
“text”:”tweet text will come here”
}
]
}
3.接下来的部分使用函数 sendPostRequest 调用 Azure 文本分析 API 端点
在执行时,由于 Spark 的懒惰执行模型,不会发生任何执行。由于数据很小并且是 PoC 设置,因此使用“收集”操作是安全的(但是在生产设置中尽量避免这种情况,因为它会将 Spark 的所有分布式执行器节点的数据返回到驱动程序,从而导致内存溢出问题)。
val tweetsSentimentList = tweetsSentimentsRdd.collect()
现在我们有了 Scala 集合形式的响应。列表中的每个元素都是一个字符串(Json ),由来自 Azure Text Analytics API 的响应组成,在当前状态下,我们对此无能为力。如果要回答几个问题像:
分数的最大值和最小值是多少?
这条推文语料库的平均情感分是多少?
本语料库中特朗普最积极的推文有哪些?
为了回答这些分析问题(以及许多其他问题),可以对这种形式的数据进行的一种处理是将现有的 Json 字符串转换为针对这种处理进行了优化的 Scala case 类。有很多方法可以做到这一点,但是我求助于使用 spray json 库来做到这一点:
为此,首先我们必须为 Json 创建一个解析器。这包括创建表示 Json 结构的 case 类,如下所示:
case class ResponseBody(id:String, score:Double)
case class AzureTextAnalyticsResponse(documents: List[ResponseBody], errors: List[String])
然后使用 spray json 构造来指定 json 的结构,包括 key 的值以及不同的部分如何相互嵌入
object ResponseJsonUtility extends java.io.Serializable {
import spray.json._
import DefaultJsonProtocol._object MyJsonProtocol extends DefaultJsonProtocol {
implicit val responseBodyFormat = jsonFormat(ResponseBody,"id","score") //this represents the inner document object of the Json
implicit val responseFormat = jsonFormat(AzureTextAnalyticsResponse,"documents","errors") //this represents the outer key-value pairs of the Json
}//and lastly, a function to parse the Json (string) needs to be written which after parsing the Json string returns data in the form of case class object.import MyJsonProtocol._
import spray.json._
def parser(givenJson:String):AzureTextAnalyticsResponse = {
givenJson.parseJson.convertTo[AzureTextAnalyticsResponse]
}
}
现在创建了这些函数和对象,剩下的就是在 Scala 集合中使用它们来获得想要的结果:
val tweetsSentimentScore = tweetsSentimentList.filter(eachResponse=>eachResponse.contains(“documents”)).map(eachResponse=>ResponseJsonUtility.parser(eachResponse)).map(parsedResponse=>parsedResponse.documents(0).score)
到现在为止,upstated 的表达对你来说应该很熟悉了,但是这里仍然是对步骤的分解理解。首先,我们将执行过滤,只考虑 Json
2 中具有“documents”部分的元素。然后我们解析每个 Json 字符串并转换成 AzureTextAnalyticsResponse 案例类
3。然后,我们只需访问每个解析后的 Json 对象的分数,就可以得到一个只包含情感分数的列表
一旦我们有了这个,那么做进一步的分析就变得方便了,例如我们可以计算平均情绪得分如下:
(tweetsSentimentScore.sum)/(tweetsSentimentScore.length)
分数结果是 0.629,这意味着被分析的推文平均有轻微的正面情绪:-)
同样,我们可以获得特朗普推文的最大情绪得分:
tweetsSentimentScore.max
结果是 0.99,这意味着相当多的推文有相当高的积极度:-)
因此,总之,我们可以使用这种方法来做一些分析,以解决不同的问题。此外,这是一个非常基本的实现,有很多增强的机会,所以我们很想知道你用这些基础知识做什么。如果你很难理解 Scala 和 Spark 的一些概念,可以看看我最近的由 Apress 出版的《大数据分析的 Scala 编程》一书。
提高价格弹性准确性的贝叶斯建模
使用贝叶斯方法提高价格弹性,以包装消费品行业为例
介绍
一般来说,贝叶斯数据分析(BDA)和贝叶斯推理对我个人来说,在现实世界中理解和应用总是令人生畏。如果你对它不熟悉,或者想更新一下,我找到了这本很棒的书,它把所有的东西都联系在了一起。
使用 Python 进行贝叶斯分析——第二版,作者 Osvaldo Martin。
也许和我一样,你可能摆弄过文本分析的潜在狄利克雷分配,但从未真正理解它背后的概率主题建模。或者你可能看过一个教程,用抛硬币或其他一些我们在现实世界中无法应用的基本例子来解释先验和后验概率。
因此,我设定了一个目标,在业余时间花两周时间研读 BDA,并通过一个相对真实的例子来分享我所学到的东西;至少在我的行业——消费品包装。
动机
站在一家消费品公司的立场上,我们意识到大量资金被投入到支付给零售商如沃尔玛、Wholefoods 和其他杂货连锁店的促销、传单和折扣上。因此,这些投资获得我们期望的投资回报率是至关重要的。估算投资回报率的一个重要工具是弹性系数,这是一个价格变化对需求影响程度的比率。此外,预测或估计价格变动后的需求是准确了解促销投资回报率的基础。
组织通常在类别、细分市场(价格促销组)或单个 SKU 级别具有这些弹性系数。然而,就准确性而言,最好的是——你猜对了——在 SKU 级别,因为每个产品在一个细分市场中的表现略有不同。
目标和假设
因此,没有进一步的拖延,我们的目标将是获得一个特定产品的弹性系数在 SKU 水平使用 BDA,当我们所有的是:
1.弹性系数 a t 分段水平
2.加拿大一个省内多家商店的产品销售额和销售量。
因此,我们将使用我们对细分层次弹性的先验知识以及我们观察到的销售金额和数量来估算 SKU 层次的弹性值。
第一步:清洁
将数据加载到数据框中并进行标准数据输入。
计算产品的单位价格,因为我们以后需要用它来计算弹性。
接下来,我们将使用贝叶斯线性回归来获得 SKU 水平的弹性值,但首先我们需要将 PPU 和销售量转换成对数空间。这是因为一旦因变量和自变量都转换成对数-对数,弹性就是对数 PPU 的系数。很酷吧?
关于为什么双对数模型是描述需求弹性的最合理模型,有很强的微观经济学论据。潜在需求曲线描述了最像经济学家假设的需求行为。它确保需求不会随着价格的上涨而降到零以下,另一方面,需求会随着价格的下降而呈指数增长。[2]
移除一些额外的异常值。
第二步:贝叶斯广义线性模型
现在我们终于可以使用广义线性模型(GLM)“from _ formula”函数来创建贝叶斯线性模型了。这个函数的好处在于,它在“~”方面遵循与 R 相同的语法。我不得不将 log_PPU 改为 x,因为在我的 pymc3 版本中有一个错误,独立变量必须被称为 x。比我更聪明的人可能知道一个修复方法,但我只是跟着它走。
通过使用 family 属性,我们可以将可能性的分布,或者换句话说,观察数据的建议形状更改为非正态分布,但是对于此示例,让它保持正态分布。例如,将其转换为二项式会导致逻辑回归。
然后,我们从该模型中采样 4000 次,每个内核在 4 个内核中进行 500 步老化,这相当于 18,000 个样本。把烧伤想象成向一块软木板投掷飞镖,你最初投掷的飞镖很糟糕,几乎没有在木板上出现,但是经过几次尝试后,你会变得更好,并开始在同一区域持续击中它们。你最初几次扔得太差,不能代表你的真正技术,所以你把飞镖从板上拿下来,没人知道!
我们可以根据对数数量和对数 PPU 的散点图绘制 16,000 条回归线。
Trace Plot — x is our coefficient of the PPU, since in the previous step we renamed PPU to x.
上面的轨迹图表示模型的核密度估计和收敛。基本上,由于我们运行 4 个独立的马尔可夫链,3 个折线图中的 4 条彩色线越接近相同的模式,我们的模型就越有代表性(没有大的漂移或其他奇怪的模式)。
我们关心的是轨迹图中 PPU (x)值的分布,它实际上是我们运行的 18,000 次回归的 x 系数,如您所见,它的平均值为-2.66。
步骤 3:贝叶斯建模
现在你可能想知道为什么不做一个常规的 OLS 回归,如果这就是我们到目前为止所做的。原因是现在我们有一个可能的弹性值的分布,平均值为 2.66,标准偏差约为 0.067。因此,没有什么可以阻止我们从这个新的正态分布中进行采样,以获得尽可能多的弹性值!
在这一点上,我们还没有将我们的先验知识结合到这个模型中,即在细分水平上的弹性是什么。所以,让我们现在就开始吧!
我决定使用 pymc3 处理得很好的坚果采样做一个简单的贝叶斯推断。我们的观测数据样本现在将是我们从 GLM 获得的弹性值,我们在分段水平的弹性先验信念将在我们的模型参数中表示。
一行一行地走。
**第 1 行:**出现次数是我们从正态分布中取样的观察值。这些参数来自我们从 GLM 得到的分布。通常,观察值是实际的数据点,而不是分布。然而,我们有点创造性,使用了上面讨论过的 GLM 分布。我还将负 2.66 翻转为正,因为弹性通常表示为正数。
第 4 行: prior_mu 表示我们在段级别被给定的弹性值,具体是参数 mu=2.2。我选择 sigma 或方差为 0.01 的正态分布,只是因为我没有更好的方差估计。值得注意的是,prior_mu 的平均值和 sigma 也可以是分布本身。当这种情况发生时,它被称为有自己参数的超先验。所以,我们可以很快进入一个海龟一直到的情况。
第 5 行: prior_sig 表示我们的先验信念有多大的方差。为此,我选择了一个逆伽马分布,因为它不可能是负的,而且分布大多在 0 到 0.5 之间。这很有帮助,因为我不希望我们先前的信念 2.2 有太大的波动。
**第 6 行:**这是橡胶接触路面的地方,我们将观察结果与先前的信念联系起来。我再次选择了正态分布,并使用了参数观察到的,它有一个非常简单的作用,它允许我们将数据输入到我们的模型中。
**第 10 行:**之后,我们在 2 个核心上采样 3000 次,并丢弃前 500 个样本以说明老化期(总共 7000 个)。
就结果的可视化而言,首先我们有一个迹线图,它在左边显示了核密度估计,这是基于观察到的和先前的数据的弹性条件的可能值的分布。
请注意, prior_mu 值是我们的弹性系数,它既不是 2.2 也不是 2.66,而是在中间的某个位置。这清楚地显示了我们先前的和我们观察到的数据点对模型的影响。尝试用增加观察数据的出现次数,看看这个分布如何变化!
第四步:视觉化
Plot_join 基本上和 trace plot 是一样的,只是它们不是两个独立的图表,而是组合在一起的。但是它看起来真的很酷吗?
plot_posterior 给出了平均值和 94%的最高概率分布(HPD ),也就是说,我们讨论的参数弹性在 94%的时间里都在此范围内。
结论
通过 GLM 对该特定产品的弹性进行建模的对数-对数方法似乎是合适的,因为它在细分水平提供的弹性范围内(在 2.2 和 2.6 之间)。老实说,这是最让我吃惊的!
然而,给定足够的观察值,我们将很快看到观察到的弹性值优先于分段水平值。在我们的案例中,我们有超过 2000 个跨越多年的销售点交易,因此如果我们将观察到的发生次数从 500 次增加到 2000 次,我们会看到 2.6 是平均值模型值。
https://github.com/mattbitter/W2_BayesianGLM
参考
[1]伊利亚·卡佐夫,动态定价算法指南 (2019),网络
[2]丹尼尔·吕 Data,U 回归食品:利用销售数据确定价格弹性 (2018),网络
[3]戴夫·贾尔斯,计量经济学学生 MCMC 第四部分 (2014),网络
[4]威尔·科尔森,用贝叶斯推理估计概率 (2018),Web GitHub
[5] Will Koehrsen,Python 中的贝叶斯线性回归:使用机器学习预测学生成绩第 2 部分 (2018),网络媒体
[6]埃罗·卡雷拉,黑客的概率编程和贝叶斯方法 (2018),Web GitHub
使用 BERT 和 CNN 在 Reddit 上检测俄罗斯巨魔
这篇文章旨在对我和杰夫·吴在斯坦福大学的 CS 224N 期末项目做一个高层次的概述。对我们工作的技术细节感兴趣的人可以得到文件和海报。
背景和数据集
当谈到解决俄罗斯巨魔的问题时,一个社交媒体网站似乎被排除在对话之外:Reddit。Reddit 拥有许多政治留言板,如 r/politics 和 r/The_Donald ,这使得它特别容易受到政治干预,但标记的 troll 数据数量极其有限。唯一的来源是 Reddit 2018 年 4 月的透明度报告,其中包括与互联网研究机构关联的 944 个账户。其中一些帐户是多产的,有数百条评论和数万个 Reddit 因果点,表明这些 trolls 在被 Reddit“淘汰”之前已经深深地嵌入了 Reddit 文化。
目前的技术水平
Brandon Punturo 在 1 月份发布了一篇很棒的文章,该文章探索了传统机器学习技术在透明报告数据集上的使用,以及使用 Google BigQuery 获得的 Reddit 评论选集。他使用 AUC 作为性能指标来衡量他的分类器有多准确,并对假阳性和假阴性进行惩罚。他的分类器使用随机森林分类器成功实现了 0.74 的 AUC 分数,这是一个令人印象深刻的壮举。他考虑了每条评论的元数据,包括发布时间、发布的子编辑、评论收到的投票以及评论正文。
除了评论本身,这些额外的元数据有助于理解用户的上下文,但他的方法没有利用自然语言处理的深度学习的最新研究。通过单独查看评论,您可以使用这些方法来理解隐藏在巨魔和非巨魔评论中的潜在信息,并使用这些信息对它们进行分类。
神经架构
与传统的机器学习或统计技术相比,神经网络已被证明在特定的语言任务上取得了优异的性能。在基本水平上,这些网络通过使用由权重连接的隐藏神经元来发挥作用,权重代表神经元之间的连接强度。每次对样本评论训练神经层时,预测和真实输出之间的差异会通过称为反向传播的过程导致权重的更新。反向传播与 ReLU 或 sigmoid 函数等非线性层一起构成了神经网络的主干,并提供了在同一 Reddit 数据集上实现最先进(SOTA)性能的机会。
针对这个问题,我们设计了一个包含四个主要组件的神经架构:
- BERT 预训练嵌入层
- 神经中间层
- 脱落层
- 分类层
嵌入层给出了每个单词的张量表示以及它们在 n 维空间中的相互关系。神经中间层接受这些嵌入,并将其传递到神经网络的隐藏层,而退出层在训练期间保留中间层内的一定百分比的神经元,以防止过度拟合。然后,这些内容的张量输出被整形,并通过分类层产生逻辑,这些逻辑表明一个评论成为巨魔的可能性有多大。
1.伯特嵌入层
来自数据集的每个 Reddit 评论首先通过 BERT 层运行,以创建句子的嵌入表示。单词嵌入是给定词汇表中的单词或短语到相应的实数稀疏向量的映射,表示该单词与 vocab 中所有其他单词的关系。10 月,谷歌发布了一份关于变形金刚双向编码器表示的白皮书,这是一种新的单词嵌入类型,它共同取决于句子中单词的左右上下文。当用作神经架构中的嵌入层时,这种语言模型表示已被证明在问答数据集小队上实现了最先进的性能,并且也开始应用于其他 NLP 任务。
BERT 对这个数据集特别感兴趣的一个主要原因是因为我们正在处理这样一个小数据集(大约 14000 个 troll 和非 troll 评论),很难仅从这个语料库建立一个语言模型。通过使用 BERT 产生的单词嵌入,我们可以将 Google 获得的未标记数据训练的预训练模型与根据我们的标记数据训练的下游神经层相结合。这个过程被称为迁移学习,并且已经被证明在大量的 NLP 应用上实现了 SOTA 性能。
我们将比较各种中间神经层和 BERT 与普通迁移学习的性能改善,这意味着没有中间神经层。
2.中
对于神经网络的中间层,有许多不同的可行选择。将其中的每一个与 Puntoro 的随机森林模型和带有 BERT 和分类器的香草迁移学习的基准进行比较,可以展示每一个的有效性。
http://www.wildml.com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/
传统的神经网络具有前馈结构,本质上从头开始考虑每个新的输入,而不考虑先前的输入。递归神经网络连接了隐藏状态,每当对输入张量做出决定时,隐藏状态就会更新,从而创建一个反馈回路,使过去的决定影响未来的决定。这种保留先前样本信息的特性使得 rnn,尤其是长短期记忆网络成为该架构中间层的良好选择。LSTMs 是 rnn 的类型,其具有额外的隐藏单元来维持长上下文中的信息,解决消失梯度问题。
http://www.wildml.com/2015/11/understanding-convolutional-neural-networks-for-nlp/
卷积神经网络执行类似的任务,但它是通过对每个评论进行操作并将它们卷积成低维向量来完成的,这些低维向量通过使用过滤器来捕获关于存储在每个评论中的 n 元语法关系的信息。然后,这些卷积通过最大汇集层,以压缩来自卷积的信息,从而从每个卷积中捕获最重要的信号。通常,已知 CNN 比 LSTMs 更擅长分类任务,因为它们能够更有效地捕捉单词之间的短期和长期依赖性。部分原因是因为 rnn 倾向于将太多的权重放在输入的最后状态,这对于分类来说是不理想的。
https://www.aaai.org/ocs/index.php/AAAI/AAAI15/paper/view/9745/9552
最后,还有第三种类型的模型架构,称为递归卷积神经网络,旨在利用两种架构的优势,并且在从单词的左右上下文中捕捉含义时特别有效。这种类型的模型是在 2015 年推出的,不如前两个模型出名,但它代表了我们中间层的第三个有趣的选项。
3.脱落层
丢弃层的目的是在向前和向后训练过程中忽略随机选择的神经元。这通过忽略神经元之间的一些连接来限制神经元之间的相互依赖,从而减少对训练数据的过度拟合。在传统的机器学习术语中,这相当于损失函数的正则化。
4.分类层
这最后一层获取 dropout 层的输出,并将其重新整形为大小为 batch_size x 2 的 logits 张量,其中每个评论被赋予被分类为 troll(列 1)或非 troll(列 2)的未标准化的可能性。为了使这些分数正常化,我们使用 Softmax 函数来获得总和为 1 的概率。使用交叉熵损失的反向传播使用这些逻辑来执行,并且相应地更新网络中的权重。
结果
不同类型的模型表现明显好于预期,我们对每个中间层模型的开发 AUC 分数明显优于随机森林分类器和 BERT 基线。
我们执行了随机超参数搜索,以优化 RCNN 中隐藏单元的数量、每个样本的填充/截断注释长度以及退出率。我们发现了优化的超参数,使我们能够用 RCNN 实现 0.846 的测试 AUC,用 CNN 和 3 的波束大小实现 0.843 的测试 AUC。
尽管这个模型在我们的数据集上是准确的,但还是有几个值得注意的失效模式。其中之一是,某些包含像“希拉里”这样带有政治意味的词语的简短评论往往会产生更多的误报。通过观察几个带有这些触发词的较短输入句子,以及几个带有其他翻转词的较长句子,我们注意到假阳性和假阴性经常出现在单个神经元上。
值得注意的是,上面和我们的论文中执行的输出分析是在测试集上完成的,这不是最佳实践。虽然我们使用测试数据纯粹是为了理解我们模型的定性故障模式,而不是以任何方式调整权重,但是通常最好完全不要管它,而是在开发集上执行这个分析。
结论
这个项目的一个主要目标是改进最先进的 Reddit 检测,这是我们通过多种类型的神经网络成功实现的。然而,这仍然是在一个非常有限的数据集上完成的,并且这将无法扩展其分类巨魔的能力的可能性相当高。我们的希望是,Reddit 今年 4 月发布另一份透明度报告,以便其他研究人员可以建立类似的模型,进一步解决 Reddit 上的俄罗斯巨魔问题。自然语言处理,即使有迁移学习技术,也只能达到现有的标记数据的质量——现在 Reddit 基本上是一个数据沙漠。
在那之前,有大量有趣的子主题可供阅读(风险自负)。
使用卷积神经网络生成和声
探讨了主观质量的数据表示和时间分辨率以及生成笔记的负对数似然性。
使用神经网络(NN)生成音乐已经在数据科学方面讨论过几次,但通常是在使用递归神经网络(RNNs)和一些卷积神经网络(CNN)生成序列的背景下。这篇文章是关于一种使用卷积来产生和声的方法,这种方法可以用四种乐器在任何给定的时间产生一个音高。
Transposition of BWV 364 using Music21, Image by MuseScore
使用卷积神经网络的主要优势是,像图像识别一样,音乐在时间(主题/主题)和音高(变调)下是不变的。因此,当数据被组织为表示时间和音高的矩阵时,卷积是寻找音乐中的模式(如和弦进行或节奏)的理想操作。具体来说,对于这个项目,时间被组织成离散的时间,其基础是以特定频率对给定乐器(声音)的音高进行采样。正如我们很快会看到的,频率的选择对模型的表现有影响。
这个项目最终确定了八分音符离散时间尺度和 128 个半音音高矢量。midi 文件功能。对于数据集来说,163 首巴赫合唱曲是基于对有四个声部和 4:4 拍号的合唱曲的音乐 21 语料库的分析而选择的。这种数据表示和模型架构首先由谷歌人工智能团队完成,他们还发表了一篇关于他们技术的有趣论文。这个项目使用了许多这样的技术,但是是用 Keras 和 Music21 实现的。
使用 CNN 的基本思想是为不同的模式(节奏、和弦等)使用几个过滤器。)来生成每个离散时间步长的所有可能音高的概率分布。通过从未知音符重复采样并生成新的概率分布,可以从无输入或部分输入中生成一段音乐。
数据准备
Music21 的语料库处理 musicXML 格式的音乐文件,因此需要构建一个助手类,以便将这些文件转换成表示钢琴卷首的 numpy 数组(在 github 存储库中的 utils.py 中可以找到)。我建立的另一个方法是通过从音高(半音阶有 12 个音符)中增加或减去音程[1,11]上的一个数字,将钢琴卷转置为随机键。这样,通过从巴赫合唱曲之一中随机选择 4 个小节,并将其转换为随机键,就可以生成一批输入。
Piano Roll for a Single Voice as Input
然后,四个钢琴卷帘窗(女高音、女低音、男高音和男低音各一个)与四个遮罩矩阵堆叠在一起,这四个遮罩矩阵表示包含每个声部的已知音高的时间步长。然后,通过获取一批巴赫合唱曲并删除该批中每首作品的相同音符来训练该模型。然后,定制损失函数最小化擦除值的正确音高的负对数似然的总和(除以擦除音符的总数,以避免对具有更多擦除音符的批次或具有不同排序的批次进行更重的加权)。
在 Keras 中实现这一点需要使用自定义的生成器来批量生成输入,以及自定义的损失函数,这使得模型有点难以保存和加载。幸运的是,一旦一个模型被训练。json 和. h5 文件可以加载一个模型用于推理目的。
模型架构
该模型使用了 64 个卷积层和 128 个滤波器。他们最终能够使用扩张卷积来节省计算能力。因为我必须在没有大量 GPU 的单台计算机上训练这个模型,所以我使用的架构是 20 个卷积层和 64 个 5x5 过滤器。和原论文一样,每两层使用 BatchNormalization 和 skip connections 。对于卷积层,ReLU 激活与填充一起使用,以在时间和音高方面保持输入的原始大小。
Iterated Model Architecture
最后一层是卷积层,输出四个通道并使用 softmax 激活。这样,输出可以被训练成四个声部,其概率分布在每个时间步长的 128 个音高上。然后,通过对与输入中被擦除音符的实际音符相对应的概率的负对数求和来计算损失。
使用吉布斯采样生成音乐
一些论文研究了音乐生成的不同采样和重采样方法。Bach2Bach 的架构使用伪吉布斯采样程序来重写部分生成的乐谱。Coconet 的论文研究了不同的技术,发现创建最佳生成音乐样本的技术是使用退火概率从被擦除或未知的音符中采样。这个退火概率的公式很容易理解,它是:α_n = max(α_min,n(α_ max-α_ min)/BN,其中α值表示输入中被擦除的音符在下一次采样迭代中被擦除的概率。b 表示采样应在α_min 以上发生的步数,N 是总步数,通常设置为声部数(4)乘以时间步数(32)。
吉布斯采样的工作方式以及它如此有效的原因与概率分布收敛于一段连贯的音乐有关。如果我们将大部分被擦除的乐谱(或随机噪声)输入到模型中,概率分布通常会分布在几个音高上,因为每个音高取决于它之前和之后的内容,以及其他声部中发生的事情。实际上,我们试图在没有足够的其他变量背景的情况下建立一个联合概率分布模型。
因此,我们从概率分布中采样,以获得每个未知时间步长的音高,然后以概率α_n 再次擦除所有这些音高。这样,在吉布斯采样开始时发生的块采样使音乐不会简单地停留在同一音符上。随着过程的进行,越来越少的音符被重新采样,这使得被擦除音符的概率分布收敛于音乐上连贯的音高。
时间分辨率的影响:
使用负对数似然的度量,可以看出较高的时间分辨率有利于音乐质量。例如,为了训练网络,当使用十六分音符分辨率时,最小损失函数是 0.168,或者相对于被擦除的音符大约 85%的平均概率。四分之一音符分辨率的最佳损失函数是 0.487,平均概率约为 61%。然而,十六分音符分辨率可以通过在其自身声音中高度加权当前时间步长之前和之后的音高来获得更好的成功,因为在十六分音符分辨率中,四分音符代表四个时间步长。一个更好的度量是看吉布斯抽样程序是否减少了平均负对数似然。
TOP: 1/16th resolution, melody input. MID: 1/8th resolution, melody input. BOT: 1/8th resolution, random input.
对于经过训练的模型,1/16 音符分辨率似乎是过拟合的,因为它在训练数据上表现得非常好,并且可以在那里实现低 NLL,但是 NLL 在 Gibbs 采样过程中不收敛。最佳行为表现在八分音符分辨率,其中一段旋律被输入到模型中,而其他声音未知。
GitHub 和参考资料
该项目的代码库和音乐样本可以在下面的 GitHub 库中找到。
参考资料:
[1]库斯伯特和阿里萨。music21:计算机辅助音乐学和符号音乐数据工具包。2010.在国际音乐信息检索学会的会议录中。
[2] G .哈杰雷斯、f .帕切特和 f .尼尔森。DeepBach:巴赫合唱曲生成的可操纵模型。2010.在第 34 届机器学习国际会议论文集。
[3] C .黄,t .库伊曼斯,a .罗伯茨,等艾尔。卷积对位法。2017.第 18 届国际音乐信息检索学会会议论文集。
使用卷积神经网络预测肺炎
细胞神经网络及其应用简介。
这篇博客文章将从卷积神经网络的简要介绍和概述开始,然后过渡到应用这一新知识,通过 x 射线图像预测肺炎,准确率超过 92%。虽然这样的精度没有什么好兴奋的,但对于这样一个简单的卷积神经网络来说,这是一个值得尊敬的结果。
当需要显示代码示例时,代码将首先显示,然后在每个代码示例下面会有一个关于代码的解释。
数据集 : 肺炎 x 光数据集
中枢神经系统和视觉皮层的简史
卷积神经网络(CNN)或 ConvNets 是通常用于图像和音频识别和分类的神经网络。CNN 来源于动物大脑的视觉皮层。研究表明,猴子和猫的视觉皮层有神经元对视野的小子域做出反应。每个神经元负责视野的一小部分,称为感受野。视觉皮层中的所有神经元将一起覆盖整个视觉空间 (Hubel,1968) 。
人类大脑的视觉皮层是由具有相似功能的多列神经元组成的。这些神经元列的阵列构成了所谓的模块(神经科学挑战,2016) 。每个模块只能够对视野的一小部分做出反应,因此,视觉皮层由许多这些模块组成,以覆盖整个区域。虽然这并不完全是我们的卷积神经网络的功能,但它与动物的视觉皮层有明显的相似之处。
CNN 简介
像所有常见的神经网络一样,CNN 拥有可调权重和偏差的神经元。正常的神经网络是完全连接的,这意味着每个神经元都连接到上一层的每个神经元。CNN 并不像普通的神经网络那样完全连接,因为它的计算量太大,而且根本不需要达到预期的效果。当处理具有大输入大小的图像数据时,使用完全连接的神经网络不是非常有效。
为了想象大量的参数,想想我们的胸部 x 光图像。这些图像的输入形状为 64x64x3,或 64 宽,64 高,有 3 个颜色通道。如果使用完全连接的神经网络,这将意味着单个隐藏层中的单个神经元将由 12,288 个连接组成(64 x 64 x 3 = 12,288) (CS231n,2018) 。这是只有一个完全连接的神经元。想象一下在一个有许多神经元的神经网络中所有权重的数量!很容易理解为什么完全连接的神经网络不是分类图像的最有效的方法。这就是 CNN 派上用场的地方,除了 CNN 的架构实际上包括一些完全连接的层。
CNN 架构简介
像所有的神经网络一样,CNN 有一个输入和输出层,有许多隐藏层,它们将应用一个激活函数,通常是 ReLu。一个 CNN 设计将包括三个主要层:卷积层、池层和全连接层。下面将介绍每一层:
卷积层
卷积层负责从输入数据中寻找和提取特征。卷积层使用过滤器,也称为内核,用于这一特征提取过程。由于 CNN 没有完全连接,神经元只连接到输入空间的预定子区域。这个区域的大小被称为过滤器的大小,或感受领域。神经元的感受野就是它接收输入的空间。
对于本例,我们将使用大小为 3x3 的过滤器。我们只设置感受野的宽度和高度,因为过滤器的深度必须与输入的深度相同,并且是自动设置的。在我们的例子中,我们的输入有 3 个颜色通道。因此,输入的深度是 3。这意味着这个卷积层中的每个神经元将有 27 个权重(3x3x3 = 27)。
卷积层通过在输入空间滑动这些滤波器来卷积输入,同时计算权重和输入的点积。过滤器内的像素将被转换成代表整个感受野的单一值。
汇集层
汇集层,也称为下采样层,通常位于神经网络的卷积层之后。汇集层的作用是减少输入的空间维度。这将导致参数数量的减少,也将有助于我们的模型泛化,避免过度拟合。这篇博文将使用最常用的池层类型 max pooling 。还有其他版本的池层,如平均池,但这篇文章的重点是最大池。
Max Pooling: 卷积层会在输入的某个区域中找到一个特定的特征,并为其分配一个较高的激活值。然后,池图层将缩小该区域并创建一个新的制图表达。最大池层通过使用每个子区域中的最大值来创建原始区域的抽象。
最大池将覆盖每个子区域,应用最大过滤器,从每个子区域提取最高值,并创建一个维度减少的抽象。
下面的例子显示了一个 4x4 矩阵作为我们的输入。我们将使用 2x2 滤波器来扫描输入矩阵,我们还将使用步长 2。2x2 池大小或过滤器将决定我们缩小空间维度的数量。对于 2x2 的池大小,我们每次将缩小一半。扫描输入矩阵时,步幅将决定移动的步数。例如,步长为 2 时,我们将从红色的 2x2 到绿色的 2x2 扫描输入矩阵,依此类推。被扫描的区域每次将移动两个街区。
全连接层
像正常的神经网络一样,CNN 的全连接层中的每个神经元都连接到前一层中的每个神经元。完全连接的层负责在特征提取后对数据进行分类。全连接层将查看由卷积层或池层创建的高级功能的激活图,然后确定哪些功能与每个类相关联。
对于我们的数据集,我们有两类:肺炎和正常。完全连接的图层将查看先前图层找到的要素,然后确定哪些要素最有助于预测图像所属的类别。
肺炎简介
仅在美国,每年就有大约一百万人会因肺炎而去医院就诊。在这 100 万人中,每年约有 5 万人死于肺炎 (CDC,2017) 。
肺炎是一种传染性炎症疾病,影响所有年龄段人群的肺部,通常由病毒或细菌感染引起。肺炎会影响肺部的一侧或两侧,并导致肺泡(气囊)充满液体、细菌、微生物和脓液 (NIH,2018) 。
肺炎有多种诊断方法,一种常见的确诊方法是通过胸部 x 光检查。胸部 x 光是确定一个人是否患有肺炎的最好的测试,也是最准确的。虽然检测肺炎至关重要,但有时可能是一项艰巨的任务。肺炎通常在 X 射线中模糊地显示出来,也可能与当地的其他疾病混合在一起。
数据准备和分析
代码的第一部分将专门用于准备数据。这一部分更多的是关于模型的实际构建,而不是细节。我将这个数据准备和分析部分的所有代码,不包括视觉效果,放在一个名为 pneumonia_dataset 的单独文件中,以便稍后导入到应用 CNN 预测肺炎部分。从这个文件导入数据集将在本节的开头解释。
import os
import numpy **as** np
import matplotlib.pyplot **as** plt
from glob import glob
from keras.preprocessing.image import ImageDataGenerator
前几行是导入准备和可视化数据所需的库。
path **=** "./chest_xray"
dirs **=** os**.**listdir(path)
**print**(dirs)
输出:
Output:
['.DS_Store', 'test', 'train', 'val']
这里我们设置了 chest_xray 文件夹的路径,以备后用。然后,我们从 chest_xray 文件夹中打印出目录。请注意,该文件夹分为三个子文件夹:测试、训练和 val 或验证。每个文件夹都包含我们将需要用于培训和测试的胸部 x 光图像。
train_folder **=** path **+** '/train/'
test_folder **=** path **+** '/test/'
val_folder **=** path **+** '/val/'
train_dirs **=** os**.**listdir(train_folder)
**print**(train_dirs)
输出:
Output:
['.DS_Store', 'PNEUMONIA', 'NORMAL']
接下来,我们将为每个文件夹设置路径。我们可以使用之前设置的“path”变量,并将其与每个子文件夹的名称连接起来。然后,我们将希望看到培训文件夹的内容。为了查看目录,我们将对培训文件夹使用listdir()
功能,然后打印结果。
train_normal **=** train_folder **+** 'NORMAL/'
train_pneu **=** train_folder **+** 'PNEUMONIA/'
然后,我们可以使用我们的培训文件夹,并设置每个类的路径。在这种情况下,我们有两个类别:正常的图像和肺炎的图像。如果我们想要可视化具体为“正常”或“肺炎”的图像,那么我们将创建一个包含这些图像的路径的变量,以供以后参考。
pneu_images **=** glob(train_pneu **+** "*.jpeg")
normal_images **=** glob(train_normal **+** "*.jpeg")
现在,我们已经将培训文件夹分为“正常”和“肺炎”,我们可以从每个类中提取所有图像。这个数据集中的图像都是 jpeg 图像,所以对于每个路径,我们将在末尾添加.jpeg
,以确保我们提取图像。
**def** **show_imgs**(num_of_imgs):
**for** img **in** range(num_of_imgs):
pneu_pic **=** np**.**asarray(plt**.**imread(pneu_images[img]))
normal_pic **=** np**.**asarray(plt**.**imread(normal_images[img]))
fig **=** plt**.**figure(figsize**=** (15,10))
normal_plot **=** fig**.**add_subplot(1,2,1)
plt**.**imshow(normal_pic, cmap**=**'gray')
normal_plot**.**set_title('Normal')
plt**.**axis('off')
pneu_plot **=** fig**.**add_subplot(1, 2, 2)
plt**.**imshow(pneu_pic, cmap**=**'gray')
pneu_plot**.**set_title('Pneumonia')
plt**.**axis('off')
plt**.**show()
我们将创建一个名为show_imgs()
的函数来可视化我们训练集中的胸部 X 射线图像。该函数将采用一个参数来指定要显示多少幅图像(num_of_imgs
)。然后,我们将使用一个范围为“num_of_imgs”的 for 循环来显示指定的图像数量。
我们将并排显示正常图像和肺炎图像,因此我们将添加两个子图:一个用于正常,一个用于肺炎。这些图像的颜色映射将是“灰色”。如果你想改变颜色图,去 Matplotlb 的颜色图参考页面。
对于显示的每个图像,我们将通过设置每个子图的标题将其标记为“正常”或“肺炎”。
show_imgs(3)
我们可以这样使用我们的show_imgs()
函数。我们将调用这个函数,并给它一个参数:我们希望显示的两个类的图像数量。
train_datagen **=** ImageDataGenerator(rescale **=** 1**/**255,
shear_range **=** 0.2,
zoom_range **=** 0.2,
horizontal_flip **=** True,
rotation_range **=** 40,
width_shift_range **=** 0.2,
height_shift_range **=** 0.2)
这被称为图像预处理,或数据增强。我们将使用 Keras 的ImageDataGenerator()
类进行数据扩充。数据扩充有助于我们扩大训练数据集。训练数据越多,种类越多越好。随着更多的训练数据和轻微操纵的数据,过度拟合变得不那么成问题,因为我们的模型必须更一般化。
- 第一步是重新调整我们的数据。重新缩放图像是一种常见的做法,因为大多数图像的 RGB 值范围为 0–255。这些值对于大多数模型来说太高,无法处理,但是通过将这些值乘以 1/255,我们可以将每个 RGB 值压缩到 0–1 之间的值。这对于我们的模型来说更容易处理。
- 接下来我们有
shear_range
,它将随机应用剪切映射,或剪切变换到数据。数值“0.2”是剪切强度或剪切角度。 zoom_range
也被设置为“0.2”。这是为了随机放大图像。horizontal_flip
设置为“真”,因为我们想随机翻转数据集中的一半图像。rotation_range
是图像可以随机旋转的度数。width_shift_range
和height_shift_range
是随机平移图像的范围。
test_datagen **=** ImageDataGenerator(rescale **=** 1**/**255)
这是我们重新调整测试集的地方。测试集不需要应用于训练数据的所有相同变换。只有训练数据可以被操纵以避免过度拟合。测试集必须是原始图像,以便在真实的、经过最小程度处理的图像上准确预测肺炎。
training_set **=** train_datagen**.**flow_from_directory(train_folder,
target_size**=** (64, 64),
batch_size **=** 32,
class_mode **=** 'binary')
val_set **=** test_datagen**.**flow_from_directory(val_folder,
target_size**=**(64, 64),
batch_size **=** 32,
class_mode **=**'binary')
test_set **=** test_datagen**.**flow_from_directory(test_folder,
target_size**=** (64, 64),
batch_size **=** 32,
class_mode **=** 'binary')
输出:
Found 5216 images belonging to 2 classes.
Found 16 images belonging to 2 classes.
Found 624 images belonging to 2 classes.
现在,我们将采用我们的测试、训练和验证文件夹的路径,并使用来自 Keras 的flow_from_directory()
生成批量扩充数据。
- 第一个参数是要提取的目录。
- 第二个参数是目标尺寸,即调整大小后图像的尺寸。
- 第三个参数是“class_mode”,设置为“binary”。这将返回 1D 二进制标签。由于只有两个类,该数据集需要二进制分类。
现在我们已经准备好了数据,我们可以继续构建模型,训练它,然后测试它,并以准确度分数的形式获得我们的结果。
应用细胞神经网络预测肺炎
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, BatchNormalization, Dropout
import pneumonia_dataset
Keras 是一个运行在 TensorFlow 之上的高级 python 神经网络库。Keras 能够快速有效地实现和实验深度学习和机器学习算法,同时仍然非常有效。Keras 将是我们这篇博文选择的深度学习库,因此我们将导入一些所需的层和模型,以使我们的卷积神经网络功能良好。
最后一个导入语句是我之前在数据准备和分析部分提到的肺炎 _ 数据集文件。
training_set, test_set, val_set **=** pneumonia_dataset**.**load_data()
输出:
Training Set:
Found 5216 images belonging to 2 classes.
Validation Set:
Found 16 images belonging to 2 classes.
Test Set:
Found 624 images belonging to 2 classes.
pneumonia_dataset 文件将返回一个训练集、测试集和一个验证集,我们将对它们进行适当的命名。这将返回我们的数据如何在每个集合中分割的摘要,包括每个集合中的图像数量以及这些图像将适合多少个类别。
model **=** Sequential()
model**.**add(Conv2D(32, (3, 3), activation**=**'relu', input_shape**=**(64, 64, 3), padding**=**'same'))
model**.**add(MaxPooling2D(pool_size**=**(2, 2)))
model**.**add(Conv2D(32, (3, 3), activation**=**'relu', padding**=**'same'))
model**.**add(MaxPooling2D(pool_size**=**(2, 2)))
model**.**add(Conv2D(64, (3, 3), activation**=**'relu', padding**=**'same'))
model**.**add(MaxPooling2D(pool_size**=**(2, 2)))
model**.**add(Flatten())
model**.**add(Dense(128, activation **=** 'relu'))
model**.**add(Dropout(0.5))
model**.**add(Dense(1, activation **=** 'sigmoid'))
这是令人兴奋的部分。
- 首先,我们使用 Keras 的“顺序”模型创建我们的模型。这个模型是层的线性堆叠,这意味着我们将逐层创建我们的模型。
- **第一个卷积层:**第一个卷积层是我们的输入层。
- 第一个参数是在层中使用的卷积滤波器的数量,设置为“32”。这也是这一层中神经元或节点的数量。
- 第二个参数是过滤器的大小,或感受野。想象一下,我们正在创建一个大小为(3,3)的窗口,或者宽度为 3,高度为 3,我们的卷积层被限制在任何给定的时间进行查看。
- 我们将设置的第三个参数是激活函数。我们的非线性激活函数是 ReLu,或校正线性单位。ReLu 功能是
*f(x) = max(0, x)*
。因此,所有负值都转换为零,而所有正值保持不变。ReLu 是最流行的激活函数之一,因为它减少了消失梯度问题,并且计算成本更低。这并不意味着 ReLu 函数是完美的,但是它将完成大多数应用程序的工作。 - 第四个参数是输入形状。这个参数只需要在第一个卷积层中指定。在第一层之后,我们的模型可以处理剩下的部分。输入形状只是将被馈送到 CNN 的图像的形状。我们的输入图像的形状将是(64,64,3)(宽度,高度,深度)。
- 最后一个参数是填充,设置为“same”。这将填充输入,使输出具有与初始输入相同的长度。
- **第一个最大池层:**该模型的最大池层只有一个参数。
- **第二卷积和最大池层:**第二卷积层和最大池层将与上面的前几层相同。第二卷积层将不需要指定输入大小。
- **第三卷积层:**在第三卷积层,第一个参数会被改变。在前两个卷积层中,该层中的滤波器或神经元的数量被设置为“32”,但是对于第三层,它将被设置为“64”。除了这一点变化之外,其他一切都将保持不变。
- **第三个最大池层:**第三个最大池层将与前两个最大池层相同。
- **展平:**展平是将多维数据转换为全连接层的可用数据所必需的。为了让全连接层工作,我们需要将卷积层的输出转换为 1D 向量。我们的卷积层将使用 2D 数据(图像)。在将它送入分类器之前,必须将其整形或展平为一维。
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= max_pooling2d_16 (MaxPooling (None, 6, 6, 64) 0 _________________________________________________________________ flatten_5 (Flatten) (None, 2304) 0 _________________________________________________________________
- Dense — ReLu: 密集层是完全连接的层,意味着每个神经元都连接到前几层的所有神经元。我们将使用 128 个节点。这也意味着完全连接的层的输出大小为 128。对于这个完全连接的层,将使用 ReLu 激活功能。
- Dropout: Dropout 用于正则化我们的模型并减少过度拟合。丢弃将暂时“丢弃”完全连接的层中的随机节点。节点的这种丢失将导致由未被丢失的节点组成的变薄的神经网络。由于没有特定的节点是 100%可靠的,因此丢弃减少了过度拟合,并有助于模型一般化。“. 5”表示某个节点被丢弃的概率为 50%。要阅读更多关于辍学的内容,请查阅本文。
- Dense — Sigmoid: 我们最终的全连接层将使用 sigmoid 函数。我们的问题包括两类:肺炎和正常。这是一个二元分类问题,其中 sigmoid 可用于返回介于 0 和 1 之间的概率。如果这是一个多类分类,乙状结肠激活功能将不会是选择的武器。然而,对于这个简单的模型,sigmoid 函数工作得很好。sigmoid 函数可以定义为:
model**.**compile(optimizer**=**'adam', loss**=**'binary_crossentropy', metrics**=**['accuracy'])
我们现在可以使用 Keras 中的 compile 方法来配置模型。
- 第一个参数是优化器,它将被设置为“adam”。亚当优化器是目前深度学习中最流行的算法之一。《Adam:一种随机优化的方法》的作者表示,Adam 结合了另外两种流行的优化器的优点:RMSProp 和 AdaGrad。你可以在 Adam 论文的第 6.3 节中读到关于 CNN 的 Adam 的有效性。
- 第二个参数是损失函数。这个模型将使用二元交叉熵损失函数。我们的模型将进行二元分类,因此我们可以将此损失函数写成如下所示,其中“y”为 0 或 1,表示类别标签是否是正确的分类,其中“p”是模型的预测概率:
- 最后一个参数是度量函数,它将判断模型的性能。在这种情况下,我们希望返回精度。
model_train **=** model**.**fit_generator(training_set,
steps_per_epoch **=** 200,
epochs **=** 5,
validation_data **=** val_set,
validation_steps **=** 100)
输出:
Epoch 1/5
200/200 [==============================] - 139s 697ms/step - loss: 0.2614 - acc: 0.8877 - val_loss: 0.5523 - val_acc: 0.8125
Epoch 2/5
200/200 [==============================] - 124s 618ms/step - loss: 0.2703 - acc: 0.8811 - val_loss: 0.5808 - val_acc: 0.8125
Epoch 3/5
200/200 [==============================] - 124s 618ms/step - loss: 0.2448 - acc: 0.8984 - val_loss: 0.7902 - val_acc: 0.8125
Epoch 4/5
200/200 [==============================] - 121s 607ms/step - loss: 0.2444 - acc: 0.8955 - val_loss: 0.8172 - val_acc: 0.7500
Epoch 5/5
200/200 [==============================] - 119s 597ms/step - loss: 0.2177 - acc: 0.9092 - val_loss: 0.8556 - val_acc: 0.6250
现在是训练模型的时候了!这将使用 Keras 的fit_generator()
方法来完成。这将根据从训练集生成的批数据来训练模型。
- 第一个参数是每个时期的步数。这将被设置为 200。每个时期的步骤将告诉模型在结束特定时期之前从发生器产生的样本批次的总数。
- 第二个参数是历元的数量,或训练迭代。Keras 文档指出,一个历元被定义为对所提供的全部数据的迭代,如 steps_per_epoch 所定义的。
- 第三个参数是模型将使用的验证数据。该模型不会根据验证数据进行训练,但这将有助于测量每个时期结束时的损失。
- 最后一个论点是验证步骤。我们的验证数据来自一个生成器(见上面的代码),所以必须设置从生成器生成的样本批次数,类似于每个时期的步骤数。
test_accuracy **=** model**.**evaluate_generator(test_set,steps**=**624)
**print**('Testing Accuracy: {:.2f}%'**.**format(test_accuracy[1] ***** 100))
输出:
Testing Accuracy: 90.22%
既然已经对模型进行了训练,那么是时候根据测试数据来评估模型的准确性了。这将通过使用 Keras 的evaluate_generator()
方法来完成。该评估将返回测试集丢失和准确性结果。
- 与拟合生成器一样,评估生成器的第一个参数是从中提取样本的文件夹。因为我们正在测试模型的准确性,所以将使用测试集。
- 第二个参数是在完成之前从生成器中提取的样本批次数。
然后,我们可以打印精度,并将其缩短为仅显示两位小数。精确度将作为 0-1 之间的值返回,因此我们将它乘以 100 以获得百分比。
之后,模型就完成了!我们已经在从胸部 x 光图像预测肺炎方面取得了一些成功!
所有东西放在一起(20 个时代)
Output:
Found 5216 images belonging to 2 classes.
Found 16 images belonging to 2 classes.
Found 624 images belonging to 2 classes.
Epoch 1/20
200/200 [==============================] - 142s 708ms/step - loss: 0.5141 - acc: 0.7369 - val_loss: 0.6429 - val_acc: 0.6250
Epoch 2/20
200/200 [==============================] - 137s 683ms/step - loss: 0.4034 - acc: 0.8058 - val_loss: 0.6182 - val_acc: 0.7500
Epoch 3/20
200/200 [==============================] - 134s 670ms/step - loss: 0.3334 - acc: 0.8483 - val_loss: 0.6855 - val_acc: 0.6875
Epoch 4/20
200/200 [==============================] - 129s 644ms/step - loss: 0.3337 - acc: 0.8516 - val_loss: 0.8377 - val_acc: 0.6875
Epoch 5/20
200/200 [==============================] - 139s 696ms/step - loss: 0.3012 - acc: 0.8672 - val_loss: 0.6252 - val_acc: 0.8750
Epoch 6/20
200/200 [==============================] - 132s 662ms/step - loss: 0.2719 - acc: 0.8808 - val_loss: 0.6599 - val_acc: 0.6875
Epoch 7/20
200/200 [==============================] - 125s 627ms/step - loss: 0.2503 - acc: 0.8969 - val_loss: 0.6470 - val_acc: 0.7500
Epoch 8/20
200/200 [==============================] - 128s 638ms/step - loss: 0.2347 - acc: 0.9016 - val_loss: 0.8703 - val_acc: 0.6875
Epoch 9/20
200/200 [==============================] - 131s 656ms/step - loss: 0.2337 - acc: 0.9075 - val_loss: 0.6313 - val_acc: 0.6875
Epoch 10/20
200/200 [==============================] - 124s 619ms/step - loss: 0.2159 - acc: 0.9133 - val_loss: 0.7781 - val_acc: 0.7500
Epoch 11/20
200/200 [==============================] - 129s 647ms/step - loss: 0.1962 - acc: 0.9228 - val_loss: 0.6118 - val_acc: 0.8125
Epoch 12/20
200/200 [==============================] - 127s 634ms/step - loss: 0.1826 - acc: 0.9306 - val_loss: 0.5831 - val_acc: 0.8125
Epoch 13/20
200/200 [==============================] - 128s 638ms/step - loss: 0.2071 - acc: 0.9178 - val_loss: 0.4661 - val_acc: 0.8125
Epoch 14/20
200/200 [==============================] - 124s 619ms/step - loss: 0.1902 - acc: 0.9234 - val_loss: 0.6944 - val_acc: 0.7500
Epoch 15/20
200/200 [==============================] - 128s 638ms/step - loss: 0.1763 - acc: 0.9281 - val_loss: 0.6350 - val_acc: 0.6875
Epoch 16/20
200/200 [==============================] - 139s 696ms/step - loss: 0.1727 - acc: 0.9337 - val_loss: 0.4813 - val_acc: 0.8750
Epoch 17/20
200/200 [==============================] - 145s 724ms/step - loss: 0.1689 - acc: 0.9334 - val_loss: 0.3188 - val_acc: 0.7500
Epoch 18/20
200/200 [==============================] - 133s 664ms/step - loss: 0.1650 - acc: 0.9366 - val_loss: 0.4164 - val_acc: 0.8750
Epoch 19/20
200/200 [==============================] - 132s 661ms/step - loss: 0.1755 - acc: 0.9316 - val_loss: 0.5974 - val_acc: 0.8125
Epoch 20/20
200/200 [==============================] - 132s 662ms/step - loss: 0.1616 - acc: 0.9395 - val_loss: 0.4295 - val_acc: 0.8750
Testing Accuracy: 92.13%
结论
卷积神经网络在测试集上取得了 92.13%的准确率。你可以自己决定这是否应该被称为“成功”。对于一个简单的模型,我认为这是非常合理的。